diff --git a/docs/active-work.md b/docs/active-work.md index 305bb99..05f1287 100644 --- a/docs/active-work.md +++ b/docs/active-work.md @@ -265,7 +265,7 @@ also removed: this branch's "R8 NEEDS A LANE" investigation block, and durable facts are in the retired registry row and the handoff §6 census. -## `scripts/gate --protocol` build step — BRANCHED, framing in review +## `scripts/gate --protocol` build step — IMPLEMENTED, no PR yet **Written with the lane's first commit**, per the standing correction from #171 and #215. @@ -275,15 +275,15 @@ from #171 and #215. authoritative tip** — the ref, not a SHA. Recover with `git fetch githubsucks && git checkout gate-protocol-build`. -- **Framing `docs/gate-protocol-build-framing.md`, revision 3**, in - review. Narrow by design: one missing step in one script, plus the - boundary question that let it go missing. No `src/`, no protocol, no - feature work. -- **The defect.** `--protocol` adds the CRDT workspace sweep, whose - documented precondition is `cargo build --workspace - --no-default-features --features luajit,crdt` (handoff §5:532-535). - The plan emitter (`scripts/gate:187-204`) has **no build step at - all** — read from the source, not inferred from the failure. +- **Framing `docs/gate-protocol-build-framing.md`, revision 3, + APPROVED and implemented.** Narrow by design: one missing step in one + script, plus the boundary question that let it go missing. No `src/`, + no protocol, no feature work. +- **The defect, as found.** `--protocol` adds the CRDT workspace sweep, + whose documented precondition is `cargo build --workspace + --no-default-features --features luajit,crdt` — documented in handoff + **§5** at the time, **§3** now. The plan emitter had **no build step + at all** — read from the source, not inferred from the failure. - **Why it was latent, and why that makes it urgent rather than tidy.** Before #225 every worktree shared one `CARGO_TARGET_DIR`, which almost always already held a `pmacs-gpu` binary, so the precondition @@ -308,14 +308,52 @@ authoritative tip** — the ref, not a SHA. Recover with build any automated check for prose drift. This entry recorded that superseded decision until now; a recovering machine reading the stale version would have rebuilt revision 1's wrong boundary. -- **Q#GR-1 must be settled by OBSERVATION before implementation** — - whether the default sweep needs the binary too. The entire defect is - a precondition nobody checked; establishing its replacement by - reading would repeat the error at one remove. +- **Q#GR-1 — SETTLED BY OBSERVATION, 2026-08-09, before any fix was + written.** On a **disposable** target directory (never a live lane's), + with `debug/pmacs-gpu` asserted **absent before each run** as a + recorded precondition, each sweep run **alone** from that same cold + state so neither could have built the binary for the other: + + | sweep | exit | result | `pmacs-gpu` after | + |---|---|---|---| + | default | **0** | green, 114 test targets | **still absent** | + | crdt | **101** | exactly **12** failures, all `gpu_invocation_acceptance::crdt::*`, all *"build pmacs-gpu before this acceptance suite"* | still absent | + + So framing §3's inference **holds** and §4's *"only under + `--protocol`"* is correct — the default sweep never builds the binary + and never needs it. **Mechanism, now established rather than + guessed:** `pmacs-gpu` has no `tests/` directory, so cargo never + uplifts its bin to `debug/pmacs-gpu`; only an explicit `cargo build` + produces it. + + **Found while doing it, and worse than the twelve:** + `bottom_panel_stage2b_gpu` a54 reported **`ok`** in that cold crdt + sweep. Its only path that does not spawn `pmacs-gpu` is its skip + branch, so a test whose whole purpose is real wgpu rendering passed + having rendered nothing. The missing build does not merely fail + twelve tests — it voids coverage in tests that report green. + (`vterm_stage3` a37 has the same shape by source read; cargo captures + passing tests' output, so the skip is invisible in the log.) +- **What landed.** A named `build-crdt` step emitted immediately before + `sweep-crdt` under `--protocol`, carrying the exact §5 invocation — + **not** folded into the sweep command, because `cargo build … && + cargo test …` reports a *build* failure under the name `sweep-crdt`. + Plus **`--self-test`** (Q#GR-5): a hardcoded three-line synthetic plan + — pass, fail-named-`build-crdt`, **pass sentinel** — driven through + the *real* runner loop, which is what makes attribution *and* + continuation observable at all. `PLAN_FILE` is deliberately **not** + injectable: that would turn the runner's `eval` into a general command + executor, the same defect this script's review caught in + `--acceptance`. - **Blocks PR #228 (discovery Stage 2).** That lane's `--protocol` result needs re-establishing on a fresh target dir under the repaired - script. Deliberately **not** folded into that feature branch. -- **Gates:** `scripts/gate --acceptance gate_script_acceptance`. + script. Deliberately **not** folded into that feature branch, and it + happens **after** this lands, not inside it. +- **Gates:** `scripts/gate --acceptance gate_script_acceptance`. Note + the recursion — this lane edits the script that runs its own gates, + so `--print-plan`, `--help` and `--self-test` were also checked by + hand after each edit: a change that breaks the script cannot be + reported honestly by the script. ## QoL arc retirement — PR #224 OPEN (docs only) diff --git a/docs/agent-handoff.md b/docs/agent-handoff.md index 19155ca..65e7374 100644 --- a/docs/agent-handoff.md +++ b/docs/agent-handoff.md @@ -529,10 +529,21 @@ someone forgot. which is why name-keyed lists are not trustworthy. - **`basedpyright` hangs forever** — always `cargo test --test m4_acceptance -- --skip basedpyright`. -- **The crdt sweep needs `cargo build --workspace` first**, or twelve - `gpu_invocation_acceptance` tests fail on a missing `pmacs-gpu` - binary. `cargo build --workspace --no-default-features --features - luajit,crdt` is the invocation that produces both binaries. +- **INCIDENT — the crdt sweep's missing build step. §3 now owns this + requirement; what stays here is the history and the signature.** + Signature: twelve `gpu_invocation_acceptance::crdt::*` failures, each + *"build pmacs-gpu before this acceptance suite"*, on a target + directory with no `debug/pmacs-gpu` in it. Seen on **PR #228's first + gate run** (2026-08-09) — the first `--protocol` run in a *fresh* + per-worktree target directory after #225. Latent for the whole life + of the shared `CARGO_TARGET_DIR`, which nearly always already held + the binary, so the precondition was met by accident. Reproduced + deliberately the same day on a disposable cold target: default sweep + exit 0, crdt sweep exit 101 with exactly those twelve. + **`scripts/gate --protocol` now runs the build as a named + `build-crdt` step**, so this signature appearing again means the + script was bypassed, not that the requirement moved. The invocation, + the measurement and the reasoning are in §3. - **A shared `CARGO_TARGET_DIR` makes concurrent sweeps unattributable.** Every worktree on this machine resolves to the same target directory, so `target/debug/pmacs` is a **shared mutable file**: a @@ -2298,15 +2309,50 @@ eight broken version assertions on CI. When the two disagree, **this list wins**. **Touching `PROTOCOL_VERSION` STRENGTHENS the sweep line. It does not -replace it:** +replace it — and the crdt sweep has a BUILD PRECONDITION:** ``` cargo test --workspace --no-fail-fast -- --skip basedpyright +cargo build --workspace --no-default-features --features luajit,crdt cargo test --workspace --features crdt --no-fail-fast -- --skip basedpyright ``` Every part is load-bearing: +- **The build before the crdt sweep is a PRECONDITION, not a courtesy, + and it is gate policy rather than an ops tip.** The crdt sweep spawns + `pmacs-gpu` as a *process*, and no `cargo test` run produces that + binary: `pmacs-gpu` has no `tests/` directory, so cargo never uplifts + its bin to `debug/pmacs-gpu`. Omit the build on a cold target + directory and twelve `gpu_invocation_acceptance::crdt::*` tests fail + on *"build pmacs-gpu before this acceptance suite"* — and, worse, + crdt tests that drive the real binary (`vterm_stage3` a37, + `bottom_panel_stage2b_gpu` a54) take their skip branch and report + **`ok`**, so the missing build also voids coverage *silently*. + `scripts/gate --protocol` emits it as its own named `build-crdt` + step, never folded into the sweep command, so a build failure is + attributed to the build rather than to the sweep. + + **Only the crdt sweep needs it, and that is MEASURED rather than + reasoned.** On 2026-08-09, on a disposable target directory with + `debug/pmacs-gpu` asserted **absent before each run** and each sweep + run alone from that cold state: the **default** sweep exited **0** + (114 test targets green) and left `debug/pmacs-gpu` **still absent** + — it never builds the binary and never needs it — while the **crdt** + sweep exited **101** with exactly those twelve failures. An + unconditional build would be a real cost paid for nothing on every + ordinary lane. + + **Why this was latent for years.** Before per-worktree target + directories (#225) every worktree on this machine shared one, which + nearly always already held a `pmacs-gpu` from some earlier build, so + the precondition was satisfied **by accident** on essentially every + run. The hazard is not the red gate — a red gate stops you. It is a + **green** `--protocol` run whose crdt sweep was decided by what + happened to be in the build directory rather than by the diff, which + is a gate reporting coverage it does not have. §5 keeps the incident + and its signature as history; **this section owns the requirement.** + - **`--workspace`, never `--tests`.** `--tests` selects 108 targets where `--workspace` selects 110, and the two it drops are **`pmacs_protocol` and `pmacs_gpu`**. On a protocol bump, dropping