docs: absorb #174 and advance the anchors to 0442d78

#174 merged while this PR was open, so the lane it had just been given
is already a merged lane. Rule 4 removes those rather than relabelling
them — but only once the durable facts are in the handoff, so do both
here in that order.

docs/agent-handoff.md
- §5 gains the lesson: a wait predicate WEAKER than the assertion it
  guards is a race on whichever platform loses it, and "wait until the
  file mentions X, then assert Y" races whenever Y is stricter than X.
- Two things that generalize past the fix ride with it: a race you
  cannot reproduce can still be bitten at one remove (an unsatisfiable
  predicate proves the wait is load-bearing; the old predicate still
  passing proves a local run cannot tell them apart), and the obvious
  fix is sometimes worse — the sibling m4_26 is deliberately left alone
  because closing it the easy way trades a precise assertion diff for a
  vague five-second hang.
- Header and §1 anchor advance to 0442d78, noting #174 is test-only and
  #184 remains the substantive change at that head.

docs/active-work.md
- Remove the #174 lane; the header paragraph now says where it went.
- Canonical base and recovery floor advance to 0442d78. The floor
  explicitly rejects 6bee09d as well as 7fd646d, per its own rule that a
  check accepting an older commit than the declared base passes on a
  tree the file does not describe.
- Bottom-panel lane: 2B-2 is IN FLIGHT, not merely "next" — branch,
  worktree, and the fact it is branched fresh rather than stacked. Its
  boundaries are restated because they are easy to overrun: production
  Hello stays v20, panel_capable stays false, and 2B-3 may not simply
  bump the unsolicited Hello.
- dired lane: the re-scout is under way on the existing branch, so #171
  keeps its three-round history and the product is a rev 5.
- Both lanes note that main advancing to 0442d78 changes nothing for
  them, since #174 is test-only.

The bottom-panel framing doc keeps its 6bee09d ground-truth line: that
is a scouting statement about what was actually read, and re-anchoring
it to a commit nobody re-scouted against would be a false claim.
This commit is contained in:
Levi Neuwirth 2026-07-28 17:04:17 -04:00
parent 0d6ede2cbb
commit 6fc7fee044
2 changed files with 67 additions and 78 deletions

View File

@ -21,11 +21,13 @@ number appears in `git log --first-parent githubsucks/main`, it has
landed regardless of what a lane says.
**Two open PRs had no lane here at all before this snapshot** — #174 and
#171 — and both now have one. An open PR is exactly the volatile work
this file exists to record, so its absence is a ledger defect rather
than a tidy omission: #171 drifted **153 commits** while invisible here,
and its still-green old CI run describes a tree nobody has looked at
since. When a PR is opened, give it a lane.
#171. An open PR is exactly the volatile work this file exists to
record, so its absence is a ledger defect rather than a tidy omission:
#171 drifted **153 commits** while invisible here, and its still-green
old CI run describes a tree nobody has looked at since. **When a PR is
opened, give it a lane.** #174 has since merged, so per rule 4 its lane
is gone again and its durable lesson is in `docs/agent-handoff.md` §5;
#171's lane is below.
## Repository authority
@ -36,14 +38,16 @@ since. When a PR is opened, give it a lane.
machine-local: `origin` may name this canonical URL, a release mirror,
or something else, and therefore has no authority by name alone.
- Canonical base at this snapshot:
`githubsucks/main` @ `6bee09d` (bottom-panel Stage 2B-1 #184, atop the
Journey/GPU directory-target ratchet #183, Journey Stage 1a #182 and
the previously recorded landed work). **Protocol schema support is
`githubsucks/main` @ `0442d78` (the M4 config-sink race fix #174, atop
bottom-panel Stage 2B-1 #184, the Journey/GPU directory-target ratchet
#183, Journey Stage 1a #182 and the previously recorded landed work).
**Protocol schema support is
`v6..=v21`; the production server-first `Hello` still advertises
v20** — two different facts, and #184 landed only the first. The
previous snapshot named `7fd646d`, and **the
recovery floor advances with it**: the check below now requires
`6bee09d` or newer, so a tree at `7fd646d` no longer passes. That is
`0442d78` or newer, so a tree at `7fd646d` — or at `6bee09d` — no
longer passes. That is
deliberate — the floor moves with the base, because a check that
accepts an older commit than the declared base passes on a tree the
rest of this file does not describe.
@ -82,7 +86,7 @@ git worktree list
git status --short --branch
```
The `git log` command must expose `6bee09d` — the base named above — or a
The `git log` command must expose `0442d78` — the base named above — or a
newer intentional main. Keep this threshold and the canonical-base line in
step: a recovery check that accepts an older commit than the base it
declares canonical will pass on a tree the rest of this file does not
@ -224,15 +228,24 @@ If it does not, stop and repair the remote/fetch configuration.
never been enforced. Any CI job that compiles the `crdt` targets has to
fix them first or it will be red on arrival.
## Bottom-panel lane (Arc 7) — 2B-1 MERGED; 2B-2 IS THE NEXT SLICE
## Bottom-panel lane (Arc 7) — 2B-1 MERGED; 2B-2 IN FLIGHT
Stage 1, the Stage 2 framing, Stage 2A, and **Stage 2B-1 are all on
`main`**. Framing revision 5's three-way split of 2B was explicitly
approved on 2026-07-27; revision 6 records PR #184's review correction.
Nothing in this arc is in flight. **2B-2 — the daemon panel projection
and epoch machine — is the next slice, and it branches fresh from
`githubsucks/main` @ `6bee09d` or newer. Do not stack it on the 2B-1
branch.**
**2B-2 — the daemon panel projection and epoch machine — is under way**
on branch `bottom-panel-stage2b2`, worktree `../pmacs-bp-stage2b2`,
branched fresh from `githubsucks/main` @ `6bee09d`. It is *not* stacked
on the 2B-1 branch, which is the rule for every slice in this arc. Note
that `main` has since advanced to `0442d78`; the only difference is the
test-only #174, so the slice's integration surface is unchanged.
**2B-2's boundaries, restated because they are easy to overrun:** the
production `Hello` stays at v20 and `panel_capable` stays `false`. The
slice is dark/test-only capability exactly as 2B-1 was. Compatible v21
activation, the GPU band, and the negotiated capability flip are all
2B-3's, and 2B-3 may **not** simply change the unsolicited `Hello` to
21.
- **Stage 2B-1 MERGED as #184** (`main` @ `6bee09d`, 2026-07-28; all
twelve checks green on the reviewed head `5539b6e`; two review rounds
@ -446,64 +459,6 @@ has **no branch and no framing yet**.
`FrontendView.fold_projection` to `true` for semantic frontends, which
Stage 2 deliberately left `false` (Q#FD21).
## M4 config-sink race lane — PR #174 OPEN, REVIVED AND REGATED
> **This ledger had no lane for #174 at all until this snapshot, and
> that is the defect worth naming.** An open PR is precisely the
> volatile work this file exists to record; two of them were invisible
> here (see the dired framing lane below), which is how one of them
> drifted 153 commits without anyone noticing.
- Portable branch: `githubsucks/fix-m4-sink-races`; worktree
`../pmacs-m4-sink-race`. **PR #174**, base `main`.
- **Revived 2026-07-28**: it was 130 commits behind, so canonical `main`
@ `6bee09d` was merged in at `302c21c` and the whole gate suite rerun.
The diff against `main` is unchanged at **25 lines in one file**
(`tests/m4_acceptance.rs`).
- **The fix is one predicate.**
`m4_5_initial_config_pushed_via_did_change_configuration` waited for
`contains("probe")` and then asserted `"probe":true` — six bytes
further on. The sink is JSONL written by a *separate process*, so the
test could read a half-written line; Linux wins that race reliably and
macOS/lua54 did not, reporting `{"rust":{"probe":`. It now waits for a
trailing newline, which is true only once a whole record has landed.
**Any "wait until the file mentions X, then assert Y about the file"
shape races whenever Y is stricter than X.**
- **The structural claim was re-verified against current `main`, not
inherited from the original scout.** `src/bin/pmacs_fake_lsp.rs` *did*
change upstream (Lean 4 stages 3b, `1e1be67` / `cdaea66`), so the "one
`writeln!` is the only writer" argument could have rotted. It has not:
the config sink is still a single `writeln!` at `:433` on a
`create+append` handle. `tests/m4_acceptance.rs` itself has **zero**
upstream commits since the merge base `ccf29e3`, which is why the
merge was clean.
- **The race cannot be falsified locally, but the wait can be — and was,
two ways.** Replacing the predicate with an unsatisfiable one fails
the test at `m4_acceptance.rs:317` with "async pump deadline
exceeded", proving `pump_async` asserts rather than falling through
and that the new predicate genuinely has to become true. Restoring the
*old* predicate leaves the test passing locally, which confirms rather
than assumes that a green local run cannot tell the two apart. Treat
the local suite as a regression check and the structural argument as
the reason.
- **The sibling weak predicate is deliberately left alone.** `m4_26`
(`:5487`) has the same shape, and the obvious fix makes it *worse*
waiting for the expected value turns a genuine `rootUri` regression
into a five-second timeout with a misleading message, trading a
precise diff for a vague hang. Closing it properly means giving that
sink a record terminator in the fake server, and it has never been
observed failing. The reasoning is a comment at the call site so the
next person does not repeat the first instinct.
- Gates on `302c21c`: fmt; strict workspace Clippy; library **1,849 + 3
ignored** default and **2,034 + 4 ignored** CRDT; m4 **121 passed + 3
ignored + 1 filtered** with basedpyright skipped; the two touched
tests run explicitly **2/2**; required GPU **202/202**;
`git diff --check`.
- **No ledger entry was added on the PR branch itself** — this file was
owned by the landed-state sync while #174 was revived, and a
drive-by lane there would have re-conflicted it for no benefit. This
is that entry.
## dired Stage 2 framing lane — PR #171 OPEN, STALE, DO NOT MERGE AS-IS
- Portable branch: `githubsucks/dired-stage2-framing` (head `ab42a79`,
@ -536,7 +491,11 @@ has **no branch and no framing yet**.
fan-out a rename transaction has to survive.
Re-scout against `6bee09d`, publish a new revision, and get explicit
framing approval before any implementation.
framing approval before any implementation. **The re-scout is under
way** on the existing branch, so PR #171 keeps its three-round
history; the product is a revision 5, not a new document. (`main` has
since advanced to `0442d78`, but the only difference is the test-only
#174, so no re-scout conclusion turns on it.)
- **The rename problem the framing must still answer**, restated because
it is the hard part: a rename is a transaction across **five** path
owners — the buffer path, the buffer name, the URI-keyed LSP stores

View File

@ -1,7 +1,9 @@
# Agent handoff — cross-machine continuity
**Last updated: 2026-07-28, after bottom-panel Stage 2B-1 (#184) merged;
the canonical landed base is that merge — the reserved protocol-v21
**Last updated: 2026-07-28, after the M4 config-sink race fix (#174) and
bottom-panel Stage 2B-1 (#184) merged; the canonical landed base is
`0442d78`. #174 is test-only. #184 is the substantive one — the reserved
protocol-v21
bottom-panel wire family, dark by construction, with the production
handshake deliberately still advertising v20 — following the Journey/GPU
directory-target ratchet (#183), following Journey Stage 1a (#182),
@ -49,7 +51,8 @@ commands, read `docs/active-work.md` immediately after this file.
## 1. Where the project stands (2026-07-28)
- `main` @ `6bee09d` (bottom-panel Stage 2B-1 #184, atop the Journey/GPU
- `main` @ `0442d78` (the M4 config-sink race fix #174 — test-only —
atop bottom-panel Stage 2B-1 #184, the Journey/GPU
directory-target ratchet #183, Journey Stage 1a #182, incorporating
terminal configuration + copy
mode landed docs #180, Lean 4 Stage 4b #181, the dired Stage 1 landed
@ -528,7 +531,7 @@ commands, read `docs/active-work.md` immediately after this file.
negotiated `panel_capable` flip. Production attachment remains v20
through 2B-2. Parent acceptance 3755 remains authoritative.
Stage 3 is the adopter default flip. **2B-2 is the next slice, and
it branches from `6bee09d` or newer.**
it branches from `0442d78` or newer.**
- **The §1.3 census is CLASSIFIED, not uniformly redirected.** Only the
Projection class (#1#12, #21#22) routes through
`primary_document_window`; focus/input (#13#15, #23), focus chrome
@ -1412,6 +1415,33 @@ round-trip cannot detect a discriminant shift.
0/15 failures with all 16 cores saturated versus 1/10 for the ticking
helper.** The general rule: an observation helper that advances the
system is not an observation.
- **A wait predicate that is WEAKER than the assertion it guards is a
race, on every platform that happens to lose it.** #174: the m4 config
sink test waited for `contains("probe")` and then asserted
`"probe":true` — six bytes further on. The sink is JSONL written by a
*separate process*, so the test could read a half-written line; Linux
won that race reliably and macOS/lua54 did not, reporting the
truncated `{"rust":{"probe":`. **Any "wait until the file mentions X,
then assert Y about the file" shape races whenever Y is stricter than
X.** The fix is to wait for the exact unit the assertion reads — here
a trailing newline, true only once a whole `writeln!` record has
landed, and still correct if the payload's field order or spelling
changes. Two things generalize beyond the fix:
- **A race you cannot reproduce can still be bitten at one remove.**
The failure needs a scheduler outcome Linux does not produce, so no
local run falsifies it. But `pump_async` *asserts* on its deadline,
so replacing the predicate with an unsatisfiable one proves the wait
is load-bearing rather than decorative — and restoring the *old*
predicate, which still passes locally, proves a green local run
cannot distinguish the two. Bite what you can reach and say plainly
which claim rests on structure instead of evidence.
- **The obvious fix is sometimes worse.** The sibling `m4_26` has the
same weak shape and was deliberately left alone: waiting for the
expected value would convert a genuine `rootUri` regression — what
its `assert_ne!`s exist to catch — into a five-second timeout with a
misleading "server didn't initialize?" message, trading a precise
assertion diff for a vague hang. Closing it properly needs a record
terminator in the fake server first.
- **Proving a child has exited is harder than it looks on this
codebase.** A fixed sleep is not proof; nix's `waitid` is unavailable
on macOS; and `libc::waitid` needs `unsafe`, which