docs: one normative home for the crdt sweep's build precondition

The durable half of this lane is a boundary question, not the missing
line. `scripts/gate`'s header names handoff section 3 as the owner of
its reasoning, and this precondition lived in section 5's hazard
register --- a coherent cause for the omission rather than mere
oversight. A requirement the script was never told to encode is one it
will keep not encoding.

So section 3 gains it NORMATIVELY: the build joins the protocol-bump
block as a third line, with its own load-bearing bullet covering the
mechanism (pmacs-gpu has no tests/ directory, so cargo never uplifts
its bin), the measurement that makes it conditional, and why it was
latent until per-worktree target directories stopped hiding it.

Section 5 keeps the INCIDENT and its signature, which is history rather
than contract, and now says so: twelve
`gpu_invocation_acceptance::crdt::*` failures on a target directory
with no `debug/pmacs-gpu`, first seen on PR #228's first gate run.
Recast so that seeing the signature again reads as "the script was
bypassed", not "the requirement moved".

The script's header keeps citing section 3 and ONLY section 3. Citing
both would split one executable contract across two homes and weaken
the script's only clean boundary at the same time as Q#GR-4 declines to
build any automated check for prose drift. A boundary that is neither
enforced nor singular is not a boundary.

The ledger records Q#GR-1's observed answer rather than the question:
both sweeps run alone from the same cold disposable target with
`debug/pmacs-gpu` asserted absent beforehand --- default exit 0 with
the binary still absent afterwards, crdt exit 101 with exactly twelve
failures --- plus the silent-skip finding, which is the part nobody was
looking for: a54 reported `ok` in that cold crdt sweep because its only
non-spawning path is its skip branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai
This commit is contained in:
Levi Neuwirth 2026-08-09 16:39:35 +02:00
parent f55ce54627
commit 898a98120c
No known key found for this signature in database
2 changed files with 105 additions and 21 deletions

View File

@ -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)

View File

@ -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