diff --git a/AGENTS.md b/AGENTS.md index 6dff9a5..5fe3d5c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -45,7 +45,8 @@ ambient local state. The repo is a private pnpm workspace shell (`@agentic-workf or makes a public SDK/provider/MCP stability promise. The real execution-host path is now selectable on macOS and proves an honest `weak` `process-group` posture at compose time; the current real GitHub Forge/GitHub Issues path includes blocked-PR surfacing, -held-merge replay safety, landing-path redaction, and origin-bearing work-source provenance. +held-merge replay safety, landing-path redaction, and origin-bearing work-source provenance — +held-merge and commit-status legs are unit-proven, with real-effect evidence pending a rerun. Strong no-phone-home evidence remains future work. EVRUN-partial is recorded; P11 also records a blocked EVRUN-full capture attempt where the narrow Codex app-server and real-host smokes passed outside the Codex sandbox, but the combined real GitHub path could not run without sandbox diff --git a/README.md b/README.md index 96fa43d..79b55d4 100644 --- a/README.md +++ b/README.md @@ -26,23 +26,24 @@ The current CLI surface is `jig setup`, `jig preview`, `jig run`, `jig inspect`, `jig export`. The private MCP surface lives in `@agentic-workflow-kit/jig-mcp` and exposes the settled operator-control verbs as source-checkout tool calls; it is not published and carries no stability -promise. +promise. `jig resume` remains a CLI/SDK recovery operation rather than an MCP operator-control +verb. Launch binds the track policy plus any configured work profile and repo-policy floors, snapshots them into the run record, and reconstructs the effective floor-merged policy basis on resume. The fixture-backed commands below are the supported local way to exercise the repo from a fresh -checkout. The package split is now implementation fact inside this private workspace; Codex -app-server transport work remains future implementation, not a shipped public API, while the real -execution-host path now exercises a local macOS process-group probe and reports an honest `weak` -containment posture. +checkout. The package split and the private Codex app-server transport are now implementation fact +inside this private workspace; neither creates a shipped public API. The real execution-host path +now exercises a local macOS process-group probe and reports an honest `weak` containment posture. Current evidence proves a scoped real-provider path with a scripted agent leg (`EVRUN-partial`). P11 also captured an EVRUN-full attempt: the narrow Codex app-server and real-host smokes pass outside the Codex sandbox, but the combined real GitHub path could not run without sandbox credentials and an integrity key. The current real GitHub Forge/GitHub Issues path also carries blocked-PR surfacing, held-merge replay safety, landing-path redaction, and -per-candidate origin-bearing provenance. `EVRUN-full`, remote execution, public package -publication, and a full Codex-driven agent leg remain future work; strong/no-phone-home -execution-host evidence remains in that later proof step. +per-candidate origin-bearing provenance — held-merge and commit-status legs are unit-proven, with +real-effect evidence pending a rerun. `EVRUN-full`, remote execution, public package publication, +and a full Codex-driven agent leg remain future work; strong/no-phone-home execution-host evidence +remains in that later proof step. ## Quick Start diff --git a/docs/README.md b/docs/README.md index a1f7c66..ebdfdee 100644 --- a/docs/README.md +++ b/docs/README.md @@ -24,7 +24,8 @@ scoped to **Jig the execution engine**. Current implementation truth includes a private setup command that emits validated owner configuration, plus a private real GitHub Forge/GitHub Issues path with blocked-PR surfacing, -held-merge replay safety, landing-path redaction, and origin-bearing candidate provenance; +held-merge replay safety, landing-path redaction, and origin-bearing candidate provenance — +held-merge and commit-status legs are unit-proven, with real-effect evidence pending a rerun; phase-table PR-number status updates still live in delivery docs. Preserve active design history in place: diff --git a/docs/delivery/target-state-implementation/README.md b/docs/delivery/target-state-implementation/README.md index 22bdafa..454e0ed 100644 --- a/docs/delivery/target-state-implementation/README.md +++ b/docs/delivery/target-state-implementation/README.md @@ -5,21 +5,24 @@ status: in progress # Target-state implementation — delivery track -**Status: in progress.** P01–P11 are merged, including P11's blocked EVRUN-full evidence record, and -P12 is open in PR #71 (see the [phase table](#phase-table)); the remaining phases are planned. Phase -statuses live in the phase table below and in each phase doc's frontmatter. +**Status: in progress.** P01–P12 are merged (see the [phase table](#phase-table)): P11 merged with a +blocked EVRUN-full evidence record, so the full-capture demonstration is still owed. P13 is +currently blocked pending the contract-owner freeze decision and the remaining evidence/remediation +closeout; P14 is planned. Phase statuses live in the phase table below and in each phase doc's +frontmatter. ## Overview -This track turns the current Jig implementation — a single private package with a fixture-backed -CLI (`jig preview`, `jig run`, `jig inspect`, `jig resume`) — into the target state described by -[`docs/product/`](../../product/README.md) and [`docs/design/`](../../design/README.md): the -three-package SDK/CLI/testkit shape of [ADR 0027](../../design/decisions/0027-packaging-sdk-boundary.md), -the real Codex app-server agent transport of -[ADR 0028](../../design/decisions/0028-codex-app-server-transport.md), proven execution-host -containment, the full owner-facing surface (guided setup, start, preview, watch, inspect, -ask-why, decide, stop, notices, export), and the EVRUN-full evidence that the whole real path -works. +This track documented the path from the historical baseline at PR #53 — a single private package +with a fixture-backed CLI centered on `jig preview`, `jig run`, `jig inspect`, and `jig resume` — +to the current multi-package private workspace and the remaining target-state gaps described by +[`docs/product/`](../../product/README.md) and [`docs/design/`](../../design/README.md). Phases +P01-P12 have already landed the package split of +[ADR 0027](../../design/decisions/0027-packaging-sdk-boundary.md), the private Codex app-server +transport of [ADR 0028](../../design/decisions/0028-codex-app-server-transport.md), the private +MCP adapter, execution-host proof work, and the owner-facing setup / observation / decision / +export surfaces. What remains is the honest closure work: EVRUN-full evidence, contract-freeze +readiness, and the final audit/docs posture. The track is fourteen phases, each scoped to one reviewable PR. The phase docs under [`phases/`](./phases/) carry the per-phase obligations; [`verification.md`](./verification.md) @@ -53,11 +56,14 @@ Verified against the repo after Phase 02 workspace split: - **Provider seams exist with mixed maturity inside `packages/jig-sdk`.** Four ports in `packages/jig-sdk/src/ports.ts`; the composition root `packages/jig-sdk/src/bootstrap.ts` selects drivers by name and fails closed on unknown names. Forge (`git`/`gh`-based GitHub - driver) and Work source (GitHub Issues importer) are **real and usable**. The Agent seam has a - `CodexAgent` wrapper but **no production `CodexAgentSession` transport** — `agent: 'codex'` is - unusable from the shipped CLI. The real Execution host is now selectable on macOS and exercises - a local `process-group` confinement probe that reports an honest proven `weak` posture at - compose time; stronger no-phone-home evidence remains open for P11. + driver) and Work source (GitHub Issues importer) are **real and usable**. The Agent seam now + includes the private production Codex app-server transport: `bootstrap.ts` composes + `createProductionCodexAgentSession`, and driver selection supports `agent: 'codex'`. The + remaining limitation is evidence, not absence of implementation: P11 still records only a + blocked EVRUN-full attempt, so the full real-effect proof for the combined Codex/GitHub path is + still owed. The real Execution host is now selectable on macOS and exercises a local + `process-group` confinement probe that reports an honest proven `weak` posture at compose time; + stronger no-phone-home evidence remains open for P11. - **Conformance and controlled doubles** now live in `packages/jig-testkit` (`packages/jig-testkit/src/provider-conformance.ts`, `packages/jig-testkit/tests/conformance/`), outside the production SDK dependency graph. @@ -83,8 +89,9 @@ Verified against the repo after Phase 02 workspace split: private coordination shell; no publish or stability promise is created. - **Driving** ([driving contract](../../design/contracts/driving.md)): CLI, MCP, and SDK adapters as thin realizations of one operator-control port carrying start, preview, watch, - inspect, ask-why, decide, and stop — one action, one control-plane call, SDK/operator-owned - records. + inspect, ask-why, notice acknowledge, notice snooze, decide, stop, and export — one action, + one control-plane call, SDK/operator-owned records. Resume remains on the SDK recovery surface, + not the operator-control port. - **Providers** ([providers contract](../../design/contracts/providers.md), [realization roadmap](../../design/contracts/provider-realization-roadmap.md)): a real Codex agent behind `AgentPort` over the owned stdio app-server (ADR 0028), an execution host with @@ -278,22 +285,22 @@ release posture`") ## Phase table -| ID | Phase | Status | Hard dependencies | Parallelization | -| --- | ------------------------------------------------------------------------------------------ | ------------------------------ | ----------------- | ----------------------------------------------------------------------- | -| P01 | [SDK boundary and operator-control surface](./phases/01-sdk-boundary-and-operator-port.md) | merged (#55) | — | First; everything else keys off this surface. | -| P02 | [Package split: jig-sdk, jig-cli, jig-testkit](./phases/02-package-split-workspace.md) | merged (#56, #58) | P01 | Sole occupant of its slot — it moves every source file. | -| P03 | [Codex app-server transport](./phases/03-codex-app-server-transport.md) | merged (#57, #58, #59, #60) | P01 | Parallel with P04–P10 after P02 (soft). | -| P04 | [Execution-host containment and substrate](./phases/04-execution-host-containment.md) | merged (#63) | — | Parallel with P03, P05–P10 after P02 (soft). | -| P05 | [Forge and work-source completion](./phases/05-forge-and-work-source-completion.md) | merged (#64) | — | Parallel with P03, P04, P06–P10 after P02 (soft). | -| P06 | [Owner configuration model](./phases/06-owner-configuration-model.md) | merged (#65) | — | Parallel with P03–P05, P08–P10 after P02 (soft). | -| P07 | [Guided setup](./phases/07-guided-setup.md) | merged (#66) | P06 | Parallel with anything not touching config templates. | -| P08 | [Watch, notices, ask-why](./phases/08-observation-surfaces.md) | merged (#67) | P01 | Parallel with P03–P06, P09, P10; coordinate record vocabulary with P09. | -| P09 | [Decide and stop](./phases/09-owner-decision-and-run-control.md) | merged (#68) | P01 | Parallel with P03–P06, P08, P10; coordinate record vocabulary with P08. | -| P10 | [Export: write-once audit record](./phases/10-export-audit-record.md) | merged (#69) | P01 | Parallel with P03–P09. | -| P11 | [EVRUN-full evidence](./phases/11-evrun-full-evidence.md) | merged (#70; blocked evidence) | P03, P04 | Sequential after both provider phases; benefits from P05. | -| P12 | [MCP driving adapter](./phases/12-mcp-adapter.md) | pr #71 | P02 | Parallel with P11; soft dependency on P08/P09 for verb coverage. | -| P13 | [Contract v0 freeze readiness](./phases/13-contract-freeze-readiness.md) | planned | P05, P07–P12 | Blocked: also requires a contract-owner freeze decision. | -| P14 | [Target-state audit, docs, release posture](./phases/14-docs-and-release-readiness.md) | planned | All other phases | Last; closes the track. | +| ID | Phase | Status | Hard dependencies | Parallelization | +| --- | ------------------------------------------------------------------------------------------ | ------------------------------ | ----------------- | ---------------------------------------------------------------------------- | +| P01 | [SDK boundary and operator-control surface](./phases/01-sdk-boundary-and-operator-port.md) | merged (#55) | — | First; everything else keys off this surface. | +| P02 | [Package split: jig-sdk, jig-cli, jig-testkit](./phases/02-package-split-workspace.md) | merged (#56, #58) | P01 | Sole occupant of its slot — it moves every source file. | +| P03 | [Codex app-server transport](./phases/03-codex-app-server-transport.md) | merged (#57, #58, #59, #60) | P01 | Parallel with P04–P10 after P02 (soft). | +| P04 | [Execution-host containment and substrate](./phases/04-execution-host-containment.md) | merged (#63) | — | Parallel with P03, P05–P10 after P02 (soft). | +| P05 | [Forge and work-source completion](./phases/05-forge-and-work-source-completion.md) | merged (#64) | — | Parallel with P03, P04, P06–P10 after P02 (soft). | +| P06 | [Owner configuration model](./phases/06-owner-configuration-model.md) | merged (#65) | — | Parallel with P03–P05, P08–P10 after P02 (soft). | +| P07 | [Guided setup](./phases/07-guided-setup.md) | merged (#66) | P06 | Parallel with anything not touching config templates. | +| P08 | [Watch, notices, ask-why](./phases/08-observation-surfaces.md) | merged (#67) | P01 | Parallel with P03–P06, P09, P10; coordinate record vocabulary with P09. | +| P09 | [Decide and stop](./phases/09-owner-decision-and-run-control.md) | merged (#68) | P01 | Parallel with P03–P06, P08, P10; coordinate record vocabulary with P08. | +| P10 | [Export: write-once audit record](./phases/10-export-audit-record.md) | merged (#69) | P01 | Parallel with P03–P09. | +| P11 | [EVRUN-full evidence](./phases/11-evrun-full-evidence.md) | merged (#70; blocked evidence) | P03, P04 | Sequential after both provider phases; benefits from P05. | +| P12 | [MCP driving adapter](./phases/12-mcp-adapter.md) | merged (#71) | P02 | Parallel with P11; soft dependency on P08/P09 for verb coverage. | +| P13 | [Contract v0 freeze readiness](./phases/13-contract-freeze-readiness.md) | blocked | P05, P07–P12 | Requires evidence/remediation closeout and a contract-owner freeze decision. | +| P14 | [Target-state audit, docs, release posture](./phases/14-docs-and-release-readiness.md) | planned | All other phases | Last; closes the track. | ## What can run in parallel @@ -338,10 +345,14 @@ boundary enforcement from P02 on, docs checks, and the definition of "delivered" Per the escalation rule (product owns what/why; design reconciles to product; delivery names conflicts rather than resolving them): -- **`MERGE-5` is promised but unproven.** The product guarantees blocked-PR surfacing; the - EVRUN-partial record explicitly does not claim `MERGE-5`, and only unit-level coverage - exercises the forge adapter's block-surfacing primitives — no end-to-end real-effect proof - exists. P05 owns closing or explicitly re-scoping this gap. +- **`MERGE-5` is partially proven; real-effect rerun is still owed.** The product guarantees + blocked-PR surfacing. Surfacing is now reachable from normal runner wiring, and the PR-creation + and comment legs were smoke-proven (`#64`). The commit-status write/read leg failed with an + HTTP 403, and held-merge posture was never observed against a protected target — the + EVRUN-partial record explicitly does not claim `MERGE-5` end to end. A real-effect rerun remains + required before the claim is fully proven; see the review record + `docs/archive/reviews/2026-07-06-p04-p12-target-state-review.md` for the observed failure + detail. - **GUARD-2 pause shape is an open design question** (distinct sub-state vs. reusing `parked`, raised in [`plan-intake.md`](../../design/core/plan-intake.md#open-questions); [`authorization.md`](../../design/core/authorization.md) explicitly declines to invent a new @@ -356,11 +367,9 @@ conflicts rather than resolving them): - **Owner-facing setup, notices, and export placement are settled for MCP.** ADR 0029 keeps setup as configuration rather than an operator-control verb; ADR 0030 places notice acknowledge/snooze as owner notice records; ADR 0032 places export on the operator port. -- **Resume placement is also unsettled at the driving boundary.** The shipped CLI has - `jig resume` and the SDK/package ADR expects a programmatic resume surface, but the active - driving contract does not include resume in the deliberate action set. P01 and P12 must route - whether resume is a driving action, recovery API, or CLI-only recovery surface before - exposing it as an operator-control port verb. +- **Resume placement is settled.** ADR 0033 places resume on the SDK recovery surface + (`JigRecoverySurface`), not the operator-control port. The shipped CLI's `jig resume` is a + recovery surface; MCP deliberately does not expose resume as an operator-control port verb. - **MCP adapter package placement** is settled by ADR 0033: MCP lives in a private `jig-mcp` adapter package that depends on `jig-sdk` and carries no publish or stability promise. - **ADR `applied` status does not mean implemented** — the @@ -369,16 +378,16 @@ conflicts rather than resolving them): ## Reference map -| Area | Read | -| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Product commitments (IDs) | [`product/jig.md`](../../product/jig.md), [`product/guarantees.md`](../../product/guarantees.md), [`product/concepts.md`](../../product/concepts.md), [`product/use-cases.md`](../../product/use-cases.md) | -| Driving boundary | [`design/contracts/driving.md`](../../design/contracts/driving.md) | -| Data contracts (v0) | [`design/contracts/execution-plan-contract-v0.md`](../../design/contracts/execution-plan-contract-v0.md), [`design/contracts/observability-records-contract-v0.md`](../../design/contracts/observability-records-contract-v0.md) | -| Provider seams | [`design/contracts/providers.md`](../../design/contracts/providers.md), [`design/contracts/provider-realization-roadmap.md`](../../design/contracts/provider-realization-roadmap.md) | -| Core lifecycle | [`design/core/`](../../design/core/README.md) (bootstrap, plan-intake, orchestration, authorization, records) | -| Domain model | [`design/domain/configuration-and-work.md`](../../design/domain/configuration-and-work.md), [`design/domain/runtime-and-observation.md`](../../design/domain/runtime-and-observation.md) | -| Security view | [`design/security-model.md`](../../design/security-model.md) | -| Packaging / transport / conformance decisions | [ADR 0027](../../design/decisions/0027-packaging-sdk-boundary.md), [ADR 0028](../../design/decisions/0028-codex-app-server-transport.md), [ADR 0026](../../design/decisions/0026-conformance-self-report-only.md) | -| Evidence gates | [`design/evidence/README.md`](../../design/evidence/README.md) | -| Current implementation | `src/` (ports, bootstrap, harness, authorization, records, projection, resume, providers, conformance), `tests/` (unit, integration, conformance, smoke, hermetic guard, `tests/fixtures/m5b-local-mvp/`), `scripts/`, `package.json`, `vitest.config.ts` | -| Historical provenance | [`docs/archive/delivery/`](../../archive/delivery/README.md) (M5b, M7 tracks — provenance only) | +| Area | Read | +| --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Product commitments (IDs) | [`product/jig.md`](../../product/jig.md), [`product/guarantees.md`](../../product/guarantees.md), [`product/concepts.md`](../../product/concepts.md), [`product/use-cases.md`](../../product/use-cases.md) | +| Driving boundary | [`design/contracts/driving.md`](../../design/contracts/driving.md) | +| Data contracts (v0) | [`design/contracts/execution-plan-contract-v0.md`](../../design/contracts/execution-plan-contract-v0.md), [`design/contracts/observability-records-contract-v0.md`](../../design/contracts/observability-records-contract-v0.md) | +| Provider seams | [`design/contracts/providers.md`](../../design/contracts/providers.md), [`design/contracts/provider-realization-roadmap.md`](../../design/contracts/provider-realization-roadmap.md) | +| Core lifecycle | [`design/core/`](../../design/core/README.md) (bootstrap, plan-intake, orchestration, authorization, records) | +| Domain model | [`design/domain/configuration-and-work.md`](../../design/domain/configuration-and-work.md), [`design/domain/runtime-and-observation.md`](../../design/domain/runtime-and-observation.md) | +| Security view | [`design/security-model.md`](../../design/security-model.md) | +| Packaging / transport / conformance decisions | [ADR 0027](../../design/decisions/0027-packaging-sdk-boundary.md), [ADR 0028](../../design/decisions/0028-codex-app-server-transport.md), [ADR 0026](../../design/decisions/0026-conformance-self-report-only.md) | +| Evidence gates | [`design/evidence/README.md`](../../design/evidence/README.md) | +| Current implementation | `packages/jig-sdk/src/` (ports, bootstrap, harness, authorization, records, projection, resume, providers), `packages/jig-cli/src/`, `packages/jig-mcp/src/`, `packages/jig-testkit/src/`, `tests/` (unit, integration, conformance, smoke, hermetic guard, `tests/fixtures/m5b-local-mvp/`), `scripts/`, `package.json`, `vitest.config.ts` | +| Historical provenance | [`docs/archive/delivery/`](../../archive/delivery/README.md) (M5b, M7 tracks — provenance only) | diff --git a/docs/delivery/target-state-implementation/phases/11-evrun-full-evidence.md b/docs/delivery/target-state-implementation/phases/11-evrun-full-evidence.md index f4274fd..47868dd 100644 --- a/docs/delivery/target-state-implementation/phases/11-evrun-full-evidence.md +++ b/docs/delivery/target-state-implementation/phases/11-evrun-full-evidence.md @@ -1,6 +1,6 @@ --- title: "Phase 11 - EVRUN-full evidence" -status: "pr #70 — blocked evidence record" +status: "merged (#70; blocked evidence)" --- # Phase 11 - EVRUN-full evidence @@ -92,12 +92,22 @@ gated on this evidence path. This phase is the proof step: it converts "implemen ## Acceptance Criteria +These criteria remain the bar for closing this phase. The per-AC disposition markers below +record honest current state as of the #70 merge; they do not lower the bar. + 1. A committed, dated EVRUN-full evidence record (or record set) exists under `docs/design/evidence/`, indexed, convention-complete (versions, hashes, Limitations, redaction statement, ID citations). + **Disposition at #70 merge: not met.** What was delivered instead is the blocked-attempt + record `docs/design/evidence/2026-07-06-evrun-full-capture-attempt.md`. A full capture + re-attempt is still owed before this criterion is met. 2. The record demonstrates: real Codex editing through the owned app-server transport; real, exercised confinement with honest strength; an adversarial no-phone-home observation; and multi-run idempotency against a real landed effect. + **Disposition at #70 merge: not met.** The combined EVRUN-full path could not run because + the sandbox GitHub and integrity prerequisites were absent; the blocked-attempt record + `docs/design/evidence/2026-07-06-evrun-full-capture-attempt.md` documents what was observed + instead. A full capture re-attempt remains required before this criterion is met. 3. Hosted/remote operation and Windows behavior are explicitly restated as out of scope in the Limitations section. 4. README/AGENTS/product status lines about EVRUN reflect the new boundary — no claim exceeds diff --git a/docs/delivery/target-state-implementation/phases/12-mcp-adapter.md b/docs/delivery/target-state-implementation/phases/12-mcp-adapter.md index db29cd8..63281e5 100644 --- a/docs/delivery/target-state-implementation/phases/12-mcp-adapter.md +++ b/docs/delivery/target-state-implementation/phases/12-mcp-adapter.md @@ -1,6 +1,6 @@ --- title: "Phase 12 - MCP driving adapter" -status: "pr #71" +status: "merged (#71)" --- # Phase 12 - MCP driving adapter diff --git a/docs/delivery/target-state-implementation/phases/13-contract-freeze-readiness.md b/docs/delivery/target-state-implementation/phases/13-contract-freeze-readiness.md index e68f259..bc702a6 100644 --- a/docs/delivery/target-state-implementation/phases/13-contract-freeze-readiness.md +++ b/docs/delivery/target-state-implementation/phases/13-contract-freeze-readiness.md @@ -1,6 +1,6 @@ --- title: "Phase 13 - Contract v0 freeze readiness" -status: planned +status: blocked --- # Phase 13 - Contract v0 freeze readiness @@ -76,8 +76,8 @@ consumer, which is why the owner decides and this phase only prepares. [ADR 0026](../../../design/decisions/0026-conformance-self-report-only.md) (verdict vocabulary constraints) - P11's evidence records; the golden files under `tests/fixtures/m5b-local-mvp/` -- Source of truth for shipped shapes: `src/plan-validator.ts`, `src/records.ts`, - `src/projection.ts` (post-P02 package locations) +- Source of truth for shipped shapes: `packages/jig-sdk/src/plan-validator.ts`, + `packages/jig-sdk/src/records.ts`, `packages/jig-sdk/src/projection.ts` ## Dependencies diff --git a/docs/delivery/target-state-implementation/verification.md b/docs/delivery/target-state-implementation/verification.md index 875b8f4..057284b 100644 --- a/docs/delivery/target-state-implementation/verification.md +++ b/docs/delivery/target-state-implementation/verification.md @@ -21,12 +21,27 @@ Gate integrity rules (from [`AGENTS.md`](../../../AGENTS.md)): - No skipped steps, no threshold adjustments, no widened exclusion lists. Coverage stays enforced at 90% (aim 95%) across whatever package layout exists after P02. +- **Coverage headroom.** A PR may merge only if its gate run reports branch coverage at or above + 90.5%. The enforced floor in `vitest.config.ts` stays 90 — the 0.5-point headroom absorbs + run-to-run coverage jitter so that a green PR cannot produce a red main. - After P02 the gate additionally enforces the ADR 0027 dependency matrix (see [package boundary checks](#package-boundary-checks)); later phases inherit that check. - A phase that must change gate mechanics (for example, P02 re-wiring `pnpm check` to fan out across workspace packages) changes the mechanics without reducing what is checked, and its PR review verifies exactly that. +## Review gate + +A PR merges only after the automatic hosted review has posted and all of its threads are +resolved. Merging ahead of the review is a recorded escalation in the PR, never silent (incident +class: `#68` merged three minutes before its review posted). + +## Post-merge watch + +After each squash-merge, the merger watches the main push `check` run to conclusion. A red main +run halts further merges until main is green again (incident class: three consecutive red main +runs went unnoticed). + ## Test lanes The four Vitest lanes in `vitest.config.ts` carry different proof and must not blur: @@ -146,8 +161,14 @@ From P02 onward: - Each phase PR flips its own phase-table row and phase-doc frontmatter status to merged with its own PR number — no follow-up PRs for status. Since the number does not exist until the PR is opened: open the PR first, then push a status commit citing the exact number to the same - branch before requesting review, so the squash-merge lands work and status together. The - track front page must never claim less progress than `main`. + branch before requesting review, so the squash-merge lands work and status together. +- **Status-flip rule.** The status commit writes `merged (#N)` _before_ the merge happens, and + this is the sanctioned convention: the squash-merge lands the work and the status atomically in + one commit. Writing an interim status such as `implemented (#N)` or `PR #N` and relying on a + later PR to flip it to `merged` is a rule violation, not a lighter-weight variant — it is the + observed daisy-chain failure mode where the tail row goes stale (the last phase never gets its + follow-up flip and the track front page under-reports `main`). The track front page must never + claim less progress than `main`. ## Reviewer inspection axes @@ -169,22 +190,30 @@ The owning sections above remain normative — this list restates them for a sin pass and is not itself mechanically enforced. 1. Full gate green locally, with the output shown as evidence, not asserted ([The gate](#the-gate)). -2. Goldens are byte-identical, or the change is an owned, declared records-contract change +2. The gate run's reported branch coverage is at or above 90.5%, the enforced-floor headroom + ([The gate](#the-gate)). +3. Goldens are byte-identical, or the change is an owned, declared records-contract change ([Golden-record discipline](#golden-record-discipline)). -3. For real-provider phases (P03, P04, P05, P11): a smoke transcript is in the PR body or a +4. For real-provider phases (P03, P04, P05, P11): a smoke transcript is in the PR body or a committed evidence record; a skipped run is a recorded escalation, not a silent "not run" ([Evidence records and the EVRUN gates](#evidence-records-and-the-evrun-gates)). -4. Smoke and evidence assertions are not satisfiable by a fail-closed refusal +5. Smoke and evidence assertions are not satisfiable by a fail-closed refusal ([Conformance and testkit posture](#conformance-and-testkit-posture)). -5. Any export-map widening names the consumer that needs it +6. Any export-map widening names the consumer that needs it ([Package boundary checks](#package-boundary-checks)). -6. The status flip lands in the same PR: open the PR first, then push a status commit citing - the exact PR number to the phase-table row and the phase-doc frontmatter +7. The status flip lands in the same PR: open the PR first, then push a status commit citing + the exact PR number to the phase-table row and the phase-doc frontmatter, writing `merged +(#N)` directly — never an interim `implemented (#N)`/`PR #N` left for a later PR to flip ([Docs checks](#docs-checks)). -7. Status-bearing docs (root `README.md`, `AGENTS.md`, `docs/README.md`, package descriptions, +8. Status-bearing docs (root `README.md`, `AGENTS.md`, `docs/README.md`, package descriptions, `skills/README.md` CLI surface list) are updated in the same PR ([Docs checks](#docs-checks)). -8. All review threads are resolved, the PR is squash-merged, and the worktree is cleaned up - after merge (`AGENTS.md`). +9. The automatic hosted review has posted and all review threads (including its own) are + resolved before merge; merging ahead of the review is a recorded escalation, never silent + ([Review gate](#review-gate)). +10. The PR is squash-merged and the worktree is cleaned up after merge (`AGENTS.md`). +11. After the squash-merge, the merger watches the main push `check` run to conclusion; a red + main run halts further merges until main is green again + ([Post-merge watch](#post-merge-watch)). ## Definition of delivered diff --git a/docs/design/contracts/driving.md b/docs/design/contracts/driving.md index 6c33a2a..3c6dda1 100644 --- a/docs/design/contracts/driving.md +++ b/docs/design/contracts/driving.md @@ -14,7 +14,8 @@ that action. The edge holds no run logic and imports no provider contracts — i ## Owns - The inbound driving interface jig is operated through. -- The deliberate driving actions: start, preview, watch, inspect, ask-why, decide, stop, export. +- The deliberate driving actions: start, preview, watch, inspect, ask-why, notice-ack, + notice-snooze, decide, stop, export. - The one-command / one-control-plane-call / SDK-owned-records invariant. - Keeping the edge free of run logic — orchestration, eligibility, and authorization stay in core. @@ -130,9 +131,13 @@ shipped public package promise. ## Driving actions at current altitude -The driving action set is: start, preview, watch, inspect, ask-why, decide, stop, and export. This -section stays at design altitude only. It names the deliberate actions the port carries without -freezing exact method signatures or adapter-specific representation. +The driving action set is: start, preview, watch, inspect, ask-why, notice acknowledge, notice +snooze, decide, stop, and export. [ADR 0030](../decisions/0030-observation-surface-placement.md) +places notice acknowledge and snooze as owner notice records on this same operator-control port. +ADR 0032 places export on the same port, and ADR 0033 keeps `resume` on the SDK recovery surface +rather than on the operator-control port or MCP adapter. This section stays at design altitude +only. It names the deliberate actions the port carries without freezing exact method signatures or +adapter-specific representation. ## Invocation into cited core surfaces @@ -198,12 +203,14 @@ available invariant number is `INV-019`. ## Reconciles to -- `docs/product/jig.md` — "Driving a run" (start, preview, watch, inspect, ask-why, decide, stop; - "You run Jig from a terminal, drive it as a tool from your own agent, or embed it in your own - software"); "Operator-initiated" (see "What Jig isn't (yet)"); "Product boundaries" for no public - package/export/stability promise today. +- `docs/product/jig.md` — "Driving a run" (start, preview, watch, inspect, ask-why, acknowledge or + snooze a notice, decide, stop; "You run Jig from a terminal, drive it as a tool from your own + agent, or embed it in your own software"); "Operator-initiated" (see "What Jig isn't (yet)"); + "Product boundaries" for no public package/export/stability promise today. - ADR 0032 — export is an operator-control action that writes a local audit artifact and records export audit events outside finalized run logs. +- ADR 0033 — `resume` is a recovery-surface operation and MCP lives in the private `jig-mcp` + adapter package; neither changes the operator-control port verb set. - ADR 0027 — the `jig-sdk` package boundary is distribution/dependency structure, while this document's SDK adapter remains a thin driving realization. - `SEE-1` — full run visibility, surfaced through inspect/ask-why on the operator boundary. diff --git a/scripts/check-delivery-foundation.mjs b/scripts/check-delivery-foundation.mjs index 94df0bf..9623888 100644 --- a/scripts/check-delivery-foundation.mjs +++ b/scripts/check-delivery-foundation.mjs @@ -1,4 +1,4 @@ -import { readFileSync } from 'node:fs'; +import { readdirSync, readFileSync } from 'node:fs'; import { resolve } from 'node:path'; const fixtureReadme = resolve('tests/fixtures/m5b-local-mvp/README.md'); @@ -32,3 +32,73 @@ if (missing.length > 0) { } console.log('Delivery foundation fixture conventions are present.'); + +// Cross-check that every target-state-implementation phase doc's frontmatter status matches +// its phase-table row status in the track README, so the two status surfaces cannot drift +// silently (a phase doc updated without its table row, or vice versa). +const trackReadmePath = resolve('docs/delivery/target-state-implementation/README.md'); +const trackReadmeText = readFileSync(trackReadmePath, 'utf8'); +const phaseDocsDirectory = resolve('docs/delivery/target-state-implementation/phases'); + +function normalizeStatus(status) { + return status.trim().toLowerCase().replace(/\s+/g, ' '); +} + +const phaseTableRowPattern = /^\|\s*(P\d+)\s*\|\s*\[.*?\]\((\.\/phases\/[^)]+)\)\s*\|\s*(.*?)\s*\|/gm; +const tableStatusByPhaseFile = new Map(); +for (const match of trackReadmeText.matchAll(phaseTableRowPattern)) { + const [, phaseId, relativePhasePath, status] = match; + const phaseDocPath = resolve('docs/delivery/target-state-implementation', relativePhasePath); + tableStatusByPhaseFile.set(phaseDocPath, { phaseId, status: normalizeStatus(status) }); +} + +if (tableStatusByPhaseFile.size === 0) { + console.error(`${trackReadmePath} phase table did not match the expected row pattern.`); + process.exit(1); +} + +const frontmatterPattern = /^---\n([\s\S]*?)\n---/; +const frontmatterStatusPattern = /^status:\s*"?(.*?)"?\s*$/m; +const statusMismatches = []; +const expectedPhaseDocPaths = new Set( + readdirSync(phaseDocsDirectory) + .filter((entry) => /^\d{2}-.*\.md$/.test(entry)) + .map((entry) => resolve(phaseDocsDirectory, entry)), +); + +for (const [phaseDocPath, { phaseId, status: tableStatus }] of tableStatusByPhaseFile) { + const phaseDocText = readFileSync(phaseDocPath, 'utf8'); + const frontmatterBlock = phaseDocText.match(frontmatterPattern)?.[1]; + if (!frontmatterBlock) { + statusMismatches.push(`${phaseId} (${phaseDocPath}): no frontmatter block found`); + continue; + } + const frontmatterMatch = frontmatterBlock.match(frontmatterStatusPattern); + if (!frontmatterMatch) { + statusMismatches.push(`${phaseId} (${phaseDocPath}): no frontmatter status found`); + continue; + } + const docStatus = normalizeStatus(frontmatterMatch[1]); + if (docStatus !== tableStatus) { + statusMismatches.push( + `${phaseId} (${phaseDocPath}): frontmatter status "${docStatus}" does not match ` + + `phase-table row status "${tableStatus}"`, + ); + } +} + +for (const phaseDocPath of expectedPhaseDocPaths) { + if (!tableStatusByPhaseFile.has(phaseDocPath)) { + statusMismatches.push(`${phaseDocPath}: phase doc is not represented in the track README table`); + } +} + +if (statusMismatches.length > 0) { + console.error('Phase status drift between the track README table and phase-doc frontmatter:'); + for (const mismatch of statusMismatches) { + console.error(`- ${mismatch}`); + } + process.exit(1); +} + +console.log('Phase-table and phase-doc frontmatter statuses agree.');