docs: sync the durable records to landed main @ 6bee09d

PR #184 (bottom-panel Stage 2B-1) merged, but the four documents that
new work is supposed to start from still described it as open. Advance
every canonical anchor and close the one obligation that was blocking a
lane removal.

docs/agent-handoff.md
- §1's head-of-main anchor moves 7fd646d -> 6bee09d.
- State schema support and production advertisement as two separate
  facts: SUPPORTED is now v6..=v21, the server-first Hello still says
  v20, and #184 landed only the first.
- New §1 bullet for Stage 2B-1 carrying its durable substrate: the
  server-first incompatibility argument, the shared wire_grid boundary
  and why per-axis caps are a parameter, authoritative Absent, and the
  panel_epoch / geometry_epoch split.
- New §1 bullet for the PTY terminate diagnostic (#176), plus two §5
  ops lessons: a drain that ticks is not an observation, and how to
  prove a child exited without waitid or unsafe.

docs/active-work.md
- Canonical base and the recovery floor both advance to 6bee09d.
- Remove the #176 lane. It was retained only because rule 4 requires
  its facts to reach the handoff first; that move is in this commit, so
  the lane goes.
- Rewrite the bottom-panel lane as 2B-1 MERGED with 2B-2 next, branching
  fresh from landed main rather than stacking.
- Annotate the documentation lane with measured staleness (1 ahead, 320
  behind) without deleting it, since nothing has decided its fate.

docs/bottom-panel-stage2-framing.md
- Status header records 2A and 2B-1 as merged and 2B-2 as next. No
  revision bump: the header is landed state, and no design decision in
  the document changed.

COHERENCE.md
- §16 names #184 as the PR that landed the reserved v21 family.

No runtime code, no protocol change, no gate suite implicated.
This commit is contained in:
Levi Neuwirth 2026-07-28 16:28:21 -04:00
parent 6bee09dc98
commit e05ac819b5
4 changed files with 266 additions and 259 deletions

View File

@ -1343,10 +1343,10 @@ its asks are already practiced.**
- Versioned protocol schema `SUPPORTED=[6..=21]` with deliberate - Versioned protocol schema `SUPPORTED=[6..=21]` with deliberate
encoding-breaking bumps, both-frontends support required per bump, encoding-breaking bumps, both-frontends support required per bump,
and byte-pin discipline for appended variants (handoff §4). The v21 and byte-pin discipline for appended variants (handoff §4). The v21
bottom-panel family is reserved but dark in Stage 2B-1: because bottom-panel family landed with Stage 2B-1 (#184) and is reserved but
`Hello` is server-first, the production daemon still advertises v20 dark: because `Hello` is server-first, the production daemon still
so shipped v20 clients remain attachable; compatible v21 activation advertises v20 so shipped v20 clients remain attachable; compatible
belongs to Stage 2B-3. v21 activation belongs to Stage 2B-3.
- Two genuine frontends share the conceptual model; CRDT concurrent - Two genuine frontends share the conceptual model; CRDT concurrent
editing with presence across them; remote attach + reconnect. editing with presence across them; remote attach + reconnect.
- **Graceful per-frontend degradation is practiced, not aspirational**: - **Graceful per-frontend degradation is practiced, not aspirational**:

View File

@ -5,14 +5,16 @@ landed on `main`. Read it after `docs/agent-handoff.md`. Remove completed
entries when their PR merges; do not let this become a second permanent entries when their PR merges; do not let this become a second permanent
backlog. backlog.
**One lane below is retained past its merge, and says so at its own **No lane below is retained past its merge.** The PTY terminate
head**: the PTY terminate diagnostic (#176), because no landed-doc PR diagnostic (#176) was the last one — retained because rule 4 removes a
owns moving its facts to `docs/agent-handoff.md` yet, and rule 4 removes merged lane only *after* its durable facts reach
a lane only *after* that move. Every other merged lane has been removed — `docs/agent-handoff.md`, and that absorption was unowned. This snapshot
the Lean 4 and GPU-terminal-input headers this paragraph used to owns it: #176's facts are now in the handoff (§1's arc bullet and §5's
disclaim are gone, as are the inline-math (#172), dired (#169), and two ops lessons about ticking observers and proving child exit), so its
terminal config + copy mode lanes — the last of these was #180's work, lane is gone. The Lean 4, GPU-terminal-input, inline-math (#172), dired
folded into #182 so two open PRs would stop re-conflicting in this file. (#169), and terminal config + copy mode lanes were removed the same way
— the last of these was #180's work, folded into #182 so two open PRs
would stop re-conflicting in this file.
**Trust the canonical-base line below over any lane header**: if a PR **Trust the canonical-base line below over any lane header**: if a PR
number appears in `git log --first-parent githubsucks/main`, it has number appears in `git log --first-parent githubsucks/main`, it has
@ -27,11 +29,14 @@ landed regardless of what a lane says.
machine-local: `origin` may name this canonical URL, a release mirror, machine-local: `origin` may name this canonical URL, a release mirror,
or something else, and therefore has no authority by name alone. or something else, and therefore has no authority by name alone.
- Canonical base at this snapshot: - Canonical base at this snapshot:
`githubsucks/main` @ `7fd646d` (Journey/GPU directory-target ratchet `githubsucks/main` @ `6bee09d` (bottom-panel Stage 2B-1 #184, atop the
#183, atop Journey Stage 1a #182 and the previously recorded landed Journey/GPU directory-target ratchet #183, Journey Stage 1a #182 and
work; protocol v20). The previous snapshot named `c2d56ff`, and **the 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 recovery floor advances with it**: the check below now requires
`7fd646d` or newer, so a tree at `c2d56ff` no longer passes. That is `6bee09d` or newer, so a tree at `7fd646d` no longer passes. That is
deliberate — the floor moves with the base, because a check that deliberate — the floor moves with the base, because a check that
accepts an older commit than the declared base passes on a tree the accepts an older commit than the declared base passes on a tree the
rest of this file does not describe. rest of this file does not describe.
@ -70,106 +75,13 @@ git worktree list
git status --short --branch git status --short --branch
``` ```
The `git log` command must expose `7fd646d` — the base named above — or a The `git log` command must expose `6bee09d` — the base named above — or a
newer intentional main. Keep this threshold and the canonical-base line in 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 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 declares canonical will pass on a tree the rest of this file does not
describe. describe.
If it does not, stop and repair the remote/fetch configuration. If it does not, stop and repair the remote/fetch configuration.
## PTY terminate diagnostic lane — MERGED (PR #176)
> **Lane retained deliberately, and it is the next one to close.** #176
> merged into `main` @ `bf8878f` (2026-07-26); rule 4 below removes a
> merged lane, but only after its durable facts reach
> `docs/agent-handoff.md`. **That absorption is unowned** — no landed-doc
> PR exists for #176 — so removing the lane now would delete the record
> instead of moving it. Whoever opens that PR removes this section.
- Portable branch: `githubsucks/pty-terminate-eperm`; worktree
`../pmacs-math-slice`. **PR #176**, base `main`, based on `ccf29e3`
with `c93f9ee` (#175) merged in.
- Approved framing: `docs/process-signal-tolerance-framing.md`
**revision 4**, after three review rounds.
- **Diagnostic only. No disposition change.** Every call that failed
before still fails, with no state transition and no reap-ledger
arming. `src/process.rs` is the only source file touched.
- **Why nothing is fixed:** revisions 13 each proposed a *tolerance*
rule and all three were rejected as unsound in the same way — each
concluded something about a process from something that was not about
that process. Rev 1 from an errno alone (EPERM means the caller lacks
permission, not that the id was recycled); rev 2 from `try_wait`,
which observes the spawned **leader** while a PTY signal targets
`-tcgetpgrp(...)`, entities that diverge exactly when job control has
moved the terminal; rev 3 from group-directed **ESRCH**, which proves
only that the selected foreground group vanished.
- **Two facts that killed the original argument.** `group = true` is
*rejected* for PTY mode at spawn (`src/process.rs:1428-1429`), so the
reap ledger never applies to the PTY path at all; and the ledger
comment (`:1075`) says EPERM "cannot happen for our own children" and
drops the entry for **bounded growth** — not a ruling that EPERM means
dead.
- **The CI evidence never established the child had exited.** The probe's
last source statement is a file write and CPython teardown does not
synchronise with it, so no tolerance rule could even be shown to fix
the symptom. That is the whole reason the lane is diagnostic.
- What ships: a failing `kill` now reports five separate facts — target
source, target kind/value, spawn-time group, errno, and the leader's
real `try_wait` state. The test seam injects the **kill result only**,
never the observation, so the real `ChildHandle::try_wait` runs against
the real child.
- **Not "strictly additive".** `try_wait` reaps and caches, so an exited
child may be reaped earlier than otherwise. Safe because
`portable-pty` 0.9.0 returns a `std::process::Child` on Unix and
delegates `try_wait` to it, so `poll_one` still sees the cached
status — pinned by an exactly-one-terminal-event test rather than
assumed.
- Round-1 review fixes: the exited-child tests no longer use a fixed
sleep as proof of exit (nix's `waitid` is unavailable on macOS and
`libc::waitid` needs `unsafe`, which the crate forbids), instead
driving the production diagnostic in a bounded loop until it observes
the exit; and every assertion is now exact message equality built from
the kernel-assigned pid, since the substring forms would have accepted
a hardcoded target or a wrong exit code.
- Bites, all verified rather than assumed: tolerating the failure fails
the disposition test; stubbing the leader observation fails three
tests including the one-event pin; a hardcoded target fails four; a
wrong exit code fails two.
- **The sweep found a real defect in these tests, not a flake.**
`observing_the_leader_does_not_consume_the_exit_event` failed with
"process ProcessId(26) is not running": the pid helper drained for
`Started`, and **`drain_until` ticks**. A tick can observe an
immediately-exiting child and move the record out of `Running`, after
which `signal` never reaches the diagnostic at all, so the bounded
loop spun to its limit. It passed standalone because the drain
returned on `Started` before `poll_one` saw the exit; only load lost
the race. Fast-exiting children now read the pid straight from the
supervisor record (no tick), and the loop fails fast if the record
left `Running`. **Verified under matched load: 0/15 with all 16 cores
saturated, while the old ticking helper fails 1/10 — the fix is
load-bearing.**
- Verification: fmt, `git diff --check`, strict workspace clippy clean;
lib 1,838 + CRDT 2,015 (both +6, exactly the new tests); GPU 202; M4
121; bottom-panel 46; compile-mode 67; vterm 9/6/5; **isolated-config
`--no-fail-fast` sweep 3,258 across 93 suites, zero failures**.
Earlier sweeps on this branch showed two failures and then one; the
totals reconcile (3,256/2 → 3,257/1 → 3,258/0, same test count). The
two that were genuinely unrelated —
`read_dir_supersede_cancels_in_flight_predecessor` (known
pre-existing) and
`headless_snapshot_round_trip_summary_restores_the_minimap` — are
load-contention flakes; the second is structurally unreachable from
this diff, since `pmacs-gpu` depends on `pmacs-protocol` and never on
`pmacs`.
- **Parked, each with its reason:** all tolerance rules (need the
evidence this PR produces); `terminate` idempotence for an
already-reaped process (independent fix, different failure, one
feature per PR); and `signal_target`'s read-then-kill of `tcgetpgrp`
— still the most likely real fix site.
- **The lane closes when this merges.** It does not wait for the flake
to recur; the next occurrence carries its own evidence under whoever's
PR, and a Stage B framing follows then.
## The CRDT half of the test corpus is dark in CI — NEEDS A LANE ## The CRDT half of the test corpus is dark in CI — NEEDS A LANE
- **No branch, no framing yet.** Found while gating #166, then measured - **No branch, no framing yet.** Found while gating #166, then measured
@ -305,132 +217,84 @@ If it does not, stop and repair the remote/fetch configuration.
never been enforced. Any CI job that compiles the `crdt` targets has to never been enforced. Any CI job that compiles the `crdt` targets has to
fix them first or it will be red on arrival. fix them first or it will be red on arrival.
## Bottom-panel lane (Arc 7) — 2B-1 REGATED; PR #184 OPEN FOR REVIEW ## Bottom-panel lane (Arc 7) — 2B-1 MERGED; 2B-2 IS THE NEXT SLICE
Stage 1, the Stage 2 framing, and Stage 2A are on `main`. Framing Stage 1, the Stage 2 framing, Stage 2A, and **Stage 2B-1 are all on
revision 5's three-way split of 2B was explicitly approved on `main`**. Framing revision 5's three-way split of 2B was explicitly
2026-07-27; revision 6 records PR #184's review correction. **Stage approved on 2026-07-27; revision 6 records PR #184's review correction.
2B-1 is implemented and integrated with canonical `main` @ `7fd646d`. Nothing in this arc is in flight. **2B-2 — the daemon panel projection
Review round 2's four findings are corrected at `ab7c207`; the and epoch machine — is the next slice, and it branches fresh from
gate-found GPU/PTY probe barrier is corrected and the complete suite is `githubsucks/main` @ `6bee09d` or newer. Do not stack it on the 2B-1
green at `9e20175`. The follow-up fixture-specific probe correction is branch.**
committed and proportionally regated at `9c79ce1`. PR #184 is open and
must not merge before user review.**
- **Stage 2B-1 branch:** `bottom-panel-stage2b`, based on - **Stage 2B-1 MERGED as #184** (`main` @ `6bee09d`, 2026-07-28; all
`githubsucks/main` @ `7fd646d` by merge because review had begun. twelve checks green on the reviewed head `5539b6e`; two review rounds
Recovery: `git fetch githubsucks && git checkout plus a gate-found follow-up). Branch
bottom-panel-stage2b`. Everything described through the integration `githubsucks/bottom-panel-stage2b` and worktree `../pmacs-bp-stage2b`
and gate checkpoint is committed and pushed; nothing depends on a are retained and carry nothing unmerged. Durable facts — the
worktree or `/tmp`. PR #184: schema-support-versus-advertisement split, the shared `wire_grid`
<https://github.com/levineuwirth/pmacs/pull/184>. boundary, authoritative `Absent`, and the two epochs — are in
- **Ships only the reserved v21 wire layer:** the four wire shapes, `docs/agent-handoff.md` §1 per rule 3, not here.
schema version, shared cell-grid validator, and accepted-version - **What 2B-1 deliberately did not do**, because 2B-2 and 2B-3 must not
ladder move. The production daemon continues advertising v20 because re-litigate it: no producer, no consumer, no capability change.
its `Hello` is server-first; v21 activation belongs to 2B-3. This `panel_capable` is still `false` for every semantic session, so the
slice has no producer, consumer, or capability change; journey grade is unchanged and every shipped v20 client remains
`panel_capable` stays `false`, so it changes no user-visible journey attachable.
grade and existing v20 clients remain attachable. - **2B-3 inherits a hard constraint from 2B-1's review**: it owns a
- **Review round 1 closed:** two P1s and one P2, all corrected at *compatibility-preserving* v21 activation mechanism and may **not**
`9b364ad`: `PanelFrame` now identifies its buffer, the transport simply change the unsolicited `Hello` to 21. The handshake is
ratchet covers the actual attach path rather than a detached codec server-first, so that one-line change locks out every shipped v20
assertion, and shared grid bounds have one validator. frontend before it can even send an `AttachRequest`.
- **Review round 2 found four issues, corrected at `ab7c207`:** the - **Two review rounds, and what each cost.** Round 1: `PanelFrame`
server-first `Hello` made the advertised v20↔v21 compatibility needed an explicit `buffer_id`, the transport ratchet had to drive the
one-way; `COHERENCE.md` and `docs/agent-handoff.md` still named only real attach path rather than a detached codec assertion, and shared
v20 schema support; framing §9 named a nonexistent aggregate 2B grid bounds needed one validator. Round 2: the server-first `Hello`
suite instead of the three exact 2B slice suites; and the panel plus made the advertised v20↔v21 compatibility one-way; `COHERENCE.md` and
copied terminal "one byte over" fixtures were actually two bytes the handoff still named only v20 schema support; framing §9 named a
over. The correction keeps production advertisement at v20, adds a nonexistent aggregate 2B suite instead of the three exact slice
real-daemon existing-v20-client acceptance, updates all three durable suites; and the panel plus copied-terminal "one byte over" fixtures
records, names the exact slice suites, and asserts both rejecting were actually two bytes over.
fixtures are exactly `limit + 1`. - **The full gate — not review — found two version-ladder omissions and
- **The full gate exposed and corrected a contradiction in Vterm Stage one probe contradiction.** The statusline and Vterm Stage 3 ladders
3's headless probe at `9e20175`.** Its loop exited as soon as resize still pinned v20 and rejected v21. Separately, Vterm Stage 3's
plus two nonuniform composites were observed, while its acceptance headless probe exited its loop as soon as resize plus two nonuniform
later required the PTY child's `VTERMROW` output in the final frame. composites were observed, while its acceptance later required the PTY
The v20-compatible handshake made that scheduling race deterministic: child's `VTERMROW` output in the final frame; the v20-compatible
terminal mode, five frames, and resize all succeeded, but the report handshake made that scheduling race deterministic, so the report
sampled a blank frame. The probe now waits for the exact child-output sampled a blank frame. The probe now waits for the exact child-output
observation its acceptance asserts. The formerly failing exact observation its acceptance asserts.
GPU/PTY test passes, and the full nine-test Stage 3 target passes. - **The probe fix then leaked its own fixture, and that is the reusable
- **Follow-up review corrected the probe barrier's fixture leak at lesson.** The generic runner hard-coded the *producer* fixture's
`9c79ce1`.** The generic runner hard-coded the producer fixture's
`VTERMROW` breadcrumb, so the CAT input fixture could satisfy every `VTERMROW` breadcrumb, so the CAT input fixture could satisfy every
assertion but never satisfy the loop exit and waited out the assertion yet never satisfy the loop exit — it waited out the
20-second safety deadline. Producer probes now name their required 20-second safety deadline and passed on the deadline. Producer probes
frame text while input probes finish on the latched echo. The report now name their own required frame text while input probes finish on
exposes `completion_observed`, and both paths assert it, so a the latched echo, and the report exposes `completion_observed` which
deadline-driven pass cannot hide the stall again. **both** paths assert, so a deadline-driven pass cannot hide a stall
- **The full gate found and corrected two 2B-1 omissions:** the again.
statusline version ladder still pinned v20/rejected v21, and Vterm - **Final verification on the reviewed head:** `cargo fmt --check`;
Stage 3 pinned v20 both structurally and in its real headless probe. strict workspace Clippy; library **1,849 passed + 3 ignored** default
Those ratchets now expect v21 and, where applicable, reject v22. and **2,034 passed + 4 ignored** CRDT; bottom-panel Stage 1 / 2A /
- **Pre-integration green evidence at `b9123c2`:** formatting and strict 2B-1 **46 / 17 / 16**; folding Stage 2 **48**; GPU font **11**;
workspace Clippy; library **1,849 passed + 3 ignored default** and statusline **8 CRDT**; m11_5 semantic **2 CRDT**; GPU initial target
**2,034 passed + 4 ignored CRDT**; bottom-panel Stage 1 / 2A / 2B-1 and invocation **15 / 15 CRDT**; the handshake consumers m5_5 / m5_7 /
**46 / 17 / 15**; folding Stage 2 **48**; GPU font **11**; statusline mode-system wiring **36 / 7 / 1 CRDT**; Vterm Stages 1 / 2 / 3
**8 CRDT**; m11_5 semantic **2 CRDT**; Vterm Stages 1 / 2 / 3 **10 / 6 / 9 CRDT**, including the required real daemon + real PTY +
**10 / 6 / 9 CRDT**, with Stage 3's real daemon + PTY + wgpu probe real wgpu probe; M4 **121 passed + 3 ignored + 1 filtered**; required
required and green; M4 **121 passed + 3 ignored + 1 filtered**; GPU **202/202**; the isolated-config one-invocation full workspace
required GPU **202**; and the isolated-config, one-invocation full sweep; and `git diff --check`.
workspace sweep green on rerun. Its first pass hit the known - Retained as classification rather than erased: the first
completion-before-supersede race in required-GPU pass was **201/202** on
`m8_1_acceptance::read_dir_supersede_cancels_in_flight_predecessor`;
the exact pin, its full 10-test target, and the complete workspace
rerun all passed.
- **The former deterministic red is resolved on `main`.** PR #183
corrected `gpu_initial_target_acceptance` through the public
`pmacs --gpu .` path, consumed the asynchronous dired snapshot, and
retained the managed daemon before the wait so failure cleanup remains
effective. The code integration auto-composed.
- **The previous complete post-integration gate was green at `c8895a8`:**
formatting; strict workspace Clippy; library **1,849 passed + 3
ignored default** and **2,034 passed + 4 ignored CRDT**; bottom-panel
Stage 1 / 2A / 2B-1 **46 / 17 / 15**; folding Stage 2 **48**; GPU font
**11**; statusline **8 CRDT**; m11_5 semantic **2 CRDT**; GPU initial
target and invocation **15 / 15 CRDT**; Vterm Stages 1 / 2 / 3
**10 / 6 / 9 CRDT**, including the required real daemon + PTY + wgpu
probe; M4 **121 passed + 3 ignored + 1 filtered**; required GPU
**202/202**; the isolated-config, one-invocation full workspace sweep;
and `git diff --check`.
- The first required-GPU pass was **201/202** on
`a_fraction_draws_rule_pixels_between_its_operand_rows`, a rendering `a_fraction_draws_rule_pixels_between_its_operand_rows`, a rendering
test structurally outside this lane's protocol-only GPU diff. The test structurally outside a protocol-only diff, which passed
exact test passed immediately in isolation with one test thread, and immediately in single-threaded isolation and **202/202** on the
the mandatory complete rerun passed **202/202**. This is retained as mandatory complete rerun. Separately, library and Vterm attempts
classified gate evidence, not erased as a clean first pass. *inside the restricted tool sandbox* produced `Operation not
- **The corrected review-round-2 head is fully green at `9e20175`:** permitted` failures in socket-based attach tests; the authoritative
formatting; strict workspace Clippy; library **1,849 passed + 3 outside-sandbox reruns passed.
ignored default** and **2,034 passed + 4 ignored CRDT**; bottom-panel - **Ordering for the rest of the arc is fixed:** 2B-2 branches from
Stage 1 / 2A / 2B-1 **46 / 17 / 16**; folding Stage 2 **48**; GPU landed `main`; 2B-3 branches only after 2B-2 lands; Stage 3 (the
font **11**; statusline **8 CRDT**; m11_5 semantic **2 CRDT**; GPU adopter default flip) last. Each slice starts fresh from landed main.
initial target and invocation **15 / 15 CRDT**; the handshake
consumers m5_5 / m5_7 / mode-system wiring **36 / 7 / 1 CRDT**
(the release-only m5 perf test remains ignored by its standing
contract); Vterm Stages 1 / 2 / 3 **10 / 6 / 9 CRDT**, including the
required real daemon + PTY + wgpu probe; M4 **121 passed + 3 ignored
+ 1 filtered**; required GPU **202/202**; the isolated-config,
one-invocation full workspace sweep; and `git diff --check`.
- An initial default-library attempt inside the restricted tool
sandbox produced three `Operation not permitted` failures in
socket-based attach tests. The authoritative outside-sandbox rerun
passed all **1,849 + 3 ignored**, and the matching CRDT run passed.
This is retained as environment classification, not presented as a
clean first attempt.
- **The fixture-specific follow-up is proportionally green at
`9c79ce1`:** formatting and strict workspace Clippy; protocol
**17/17**; bottom-panel Stage 2B-1 **16/16**; Vterm Stage 3 **9/9
CRDT** with the real daemon + PTY + required wgpu probe in **5.72 s**;
the formerly stalled CAT path **1/1 in 0.32 s**; required GPU
**202/202**; and `git diff --check`. The first Stage 2B-1 and Vterm
attempts inside the restricted tool sandbox reproduced the classified
Unix-socket `Operation not permitted` denial; their authoritative
outside-sandbox reruns passed.
- **Next ordering is fixed:** 2B-2 branches from `main` only after 2B-1
lands; 2B-3 branches only after 2B-2 lands. The daemon epoch machine
belongs to 2B-2; the GPU band and negotiated capability flip belong
to 2B-3.
- **Stage 2A MERGED as #177** (`main` @ `0a3fcd1`, 2026-07-26, all twelve - **Stage 2A MERGED as #177** (`main` @ `0a3fcd1`, 2026-07-26, all twelve
checks green at `8424172`, three review rounds). Branch checks green at `8424172`, three review rounds). Branch
@ -597,7 +461,21 @@ git worktree add --track \
githubsucks/kill-ring-browser githubsucks/kill-ring-browser
``` ```
## Documentation lane ## Documentation lane — STALE, AND ITS DISPOSITION IS UNDECIDED
> **Measured 2026-07-28, not inferred:** `githubsucks/handoff-2026-07-20`
> is at `c11d7e7`, **1 commit ahead of `main` and 320 behind**. Its
> whole diff against `main` is four documentation files
> (`docs/active-work.md`, `docs/agent-handoff.md`,
> `docs/roadmap-2026-07.md`, `docs/vterm-framing.md`), every one of
> which has been rewritten repeatedly since by the landed-doc PRs
> #156/#168/#169/#172/#180. Rule 4 removes a lane on merge *or
> abandonment*, and this one looks abandoned in substance — but "looks
> abandoned" is not the same as a decision, and no PR was ever opened
> for it. **This snapshot deliberately annotates rather than deletes:
> whoever confirms the branch carries nothing unique removes the
> section.** The bullets below are its original claims, preserved as
> written and now unverified.
- Portable branch: `githubsucks/handoff-2026-07-20` - Portable branch: `githubsucks/handoff-2026-07-20`
- Carries synchronized `AGENTS.md` / `CLAUDE.md`, this ledger, the - Carries synchronized `AGENTS.md` / `CLAUDE.md`, this ledger, the

View File

@ -1,7 +1,9 @@
# Agent handoff — cross-machine continuity # Agent handoff — cross-machine continuity
**Last updated: 2026-07-28, during bottom-panel Stage 2B-1 PR #184 **Last updated: 2026-07-28, after bottom-panel Stage 2B-1 (#184) merged;
review; the canonical landed base remains the Journey/GPU the canonical landed base is that merge — 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), directory-target ratchet (#183), following Journey Stage 1a (#182),
which made directory which made directory
startup one coherent local/daemon/GPU path and incorporated the terminal startup one coherent local/daemon/GPU path and incorporated the terminal
@ -47,8 +49,9 @@ commands, read `docs/active-work.md` immediately after this file.
## 1. Where the project stands (2026-07-28) ## 1. Where the project stands (2026-07-28)
- `main` @ `7fd646d` (Journey/GPU directory-target ratchet #183, atop - `main` @ `6bee09d` (bottom-panel Stage 2B-1 #184, atop the Journey/GPU
Journey Stage 1a #182, incorporating terminal configuration + copy 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 mode landed docs #180, Lean 4 Stage 4b #181, the dired Stage 1 landed
docs #169 and the PTY-terminate diagnostic #176, terminal copy mode docs #169 and the PTY-terminate diagnostic #176, terminal copy mode
#178, the GPU-terminal-input landed docs #168, Lean 4 Stage 4a #178, the GPU-terminal-input landed docs #168, Lean 4 Stage 4a
@ -59,12 +62,15 @@ commands, read `docs/active-work.md` immediately after this file.
landed-doc refresh #156, the inline-math slice #158, dired Stage 1 landed-doc refresh #156, the inline-math slice #158, dired Stage 1
#165, the GPU terminal input fix #166, Lean 4 Stage 2 #161, the dired #165, the GPU terminal input fix #166, Lean 4 Stage 2 #161, the dired
framing #164, COHERENCE.md #163, find-file #162, Lean 4 Stage 1 #160, framing #164, COHERENCE.md #163, find-file #162, Lean 4 Stage 1 #160,
minimap blank-slab #159, bottom-panel Stage 1 #155). Protocol unchanged minimap blank-slab #159, bottom-panel Stage 1 #155).
at **v20** — bottom-panel Stage 2A deliberately carries no wire change. **Protocol schema support is now `v6..=v21`, while the production
The in-review Stage 2B-1 reserves the v21 schema but keeps the server-first `Hello` still advertises v20.** Those are two different
server-first production `Hello` at v20; compatible activation belongs facts and #184 landed only the first: the v21 bottom-panel wire family
to Stage 2B-3. The bullets below describe the arcs in their own terms; exists, is gated in both directions, and has no producer, no consumer,
this line is the head-of-`main` anchor. and no capability behind it. Compatible v21 activation and the
production advertisement move belong to Stage 2B-3. The bullets below
describe the arcs in their own terms; this line is the head-of-`main`
anchor.
- **`COHERENCE.md` is now required reading and a required framing input - **`COHERENCE.md` is now required reading and a required framing input
#163.** It carries the product-coherence thesis, an audited #163.** It carries the product-coherence thesis, an audited
scorecard, per-concern gaps, and §20's priority order, and it is the scorecard, per-concern gaps, and §20's priority order, and it is the
@ -163,6 +169,44 @@ commands, read `docs/active-work.md` immediately after this file.
raw echoed `Ctrl-X` is invisible; and such probes must **count raw echoed `Ctrl-X` is invisible; and such probes must **count
occurrences rather than test presence**, because a single-character occurrences rather than test presence**, because a single-character
probe collides with the child's own banner text. probe collides with the child's own banner text.
- **PTY terminate diagnostic LANDED — #176** (merge `bf8878f`,
2026-07-26, one review round; `docs/process-signal-tolerance-framing.md`
rev 4, after three framing rounds). **Diagnostic only — no disposition
changed.** Every call that failed before still fails, with no state
transition and no reap-ledger arming; `src/process.rs` is the only
source file touched. It exists because the `terminate` EPERM flake is
real and nothing yet knows *why*.
- **Why three tolerance rules were all rejected: each concluded
something about a process from something that was not about that
process.** Rev 1 reasoned from an errno alone (EPERM means the caller
lacks permission, not that the id was recycled); rev 2 from
`try_wait`, which observes the spawned **leader** while a PTY signal
targets `-tcgetpgrp(...)` — entities that diverge exactly when job
control has moved the terminal; rev 3 from group-directed **ESRCH**,
which proves only that the selected foreground group vanished. This
is the reusable shape, not a Unix trivium.
- **Two facts that killed the original argument.** `group = true` is
*rejected* for PTY mode at spawn, so the reap ledger never applies to
the PTY path at all; and the ledger's own comment saying EPERM
"cannot happen for our own children" drops the entry for **bounded
growth**, not as a ruling that EPERM means dead. A comment stating a
belief is not the same as code enforcing it.
- What ships: a failing `kill` now reports five separate facts —
target source, target kind/value, spawn-time group, errno, and the
leader's real `try_wait` state. The test seam injects the **kill
result only**, never the observation, so the real
`ChildHandle::try_wait` runs against the real child.
- **It is not "strictly additive".** `try_wait` reaps and caches, so an
exited child may be reaped earlier than before. That is safe only
because `portable-pty` 0.9.0 returns a `std::process::Child` on Unix
and delegates `try_wait` to it, so `poll_one` still sees the cached
status — pinned by an exactly-one-terminal-event test rather than
assumed.
- **Still open, and still the most likely real fix site:**
`signal_target`'s read-then-kill of `tcgetpgrp`. All tolerance rules
remain parked pending the evidence this diagnostic produces, as does
`terminate` idempotence for an already-reaped process (a different
failure, so a different PR).
- **Lean 4 arc (Arc 8) — stages 1, 2, 3a, 3b, 4a, 4b ALL LANDED** - **Lean 4 arc (Arc 8) — stages 1, 2, 3a, 3b, 4a, 4b ALL LANDED**
(`docs/lean4-mode-framing.md`; #160, #161, #167, #170, #179, #181). pmacs edits Lean 4: `arborium-lean` highlighting, a (`docs/lean4-mode-framing.md`; #160, #161, #167, #170, #179, #181). pmacs edits Lean 4: `arborium-lean` highlighting, a
`lean4` major mode, `⟨⟩ ⦃⦄ ⟮⟯` pairs, and a `lake serve` language `lean4` major mode, `⟨⟩ ⦃⦄ ⟮⟯` pairs, and a `lake serve` language
@ -471,19 +515,20 @@ commands, read `docs/active-work.md` immediately after this file.
`bottom_panel_stage1_acceptance` 46; kill ring 30; compile 67; M4 121; `bottom_panel_stage1_acceptance` 46; kill ring 30; compile 67; M4 121;
required GPU 152; initial-target 14 CRDT; all three vterm suites; folding required GPU 152; initial-target 14 CRDT; all three vterm suites; folding
Stage 2 48. All 12 CI checks green at merge. Stage 2 48. All 12 CI checks green at merge.
- **Stage 2 (the GPU panel band) is FRAMED** - **Stage 2 (the GPU panel band) is FRAMED, and its first two slices
`docs/bottom-panel-stage2-framing.md` rev 6, four framing review have LANDED** — `docs/bottom-panel-stage2-framing.md` rev 6, four
rounds, no open framing items; the rev-5 implementation split was framing review rounds, no open framing items; the rev-5
explicitly approved 2026-07-27 and rev 6 records PR #184's implementation split was explicitly approved 2026-07-27 and rev 6
server-first compatibility and gate correction. It reserves records PR #184's server-first compatibility and gate correction.
protocol **v21** and ships as four serial It reserves protocol **v21** and ships as four serial
implementation slices: **2A** classified census routing + implementation slices: **2A** classified census routing +
per-window painter extraction (no wire change), **2B-1** the wire, per-window painter extraction (no wire change, #177), **2B-1** the
**2B-2** the daemon projection and epoch machine, then **2B-3** the wire (#184), **2B-2** the daemon projection and epoch machine,
GPU band, compatible v21 activation, and negotiated then **2B-3** the GPU band, compatible v21 activation, and the
`panel_capable` flip. Production attachment remains v20 through negotiated `panel_capable` flip. Production attachment remains v20
2B-1 and 2B-2. Parent acceptance 3755 remains authoritative. through 2B-2. Parent acceptance 3755 remains authoritative.
Stage 3 is the adopter default flip. Stage 3 is the adopter default flip. **2B-2 is the next slice, and
it branches from `6bee09d` or newer.**
- **The §1.3 census is CLASSIFIED, not uniformly redirected.** Only the - **The §1.3 census is CLASSIFIED, not uniformly redirected.** Only the
Projection class (#1#12, #21#22) routes through Projection class (#1#12, #21#22) routes through
`primary_document_window`; focus/input (#13#15, #23), focus chrome `primary_document_window`; focus/input (#13#15, #23), focus chrome
@ -491,6 +536,64 @@ commands, read `docs/active-work.md` immediately after this file.
authorities. Rerouting them breaks remote-op validation and authorities. Rerouting them breaks remote-op validation and
application, `DispatchIdle`, presence, focused application, `DispatchIdle`, presence, focused
search/menu/completion routing, and terminal bell ownership. search/menu/completion routing, and terminal bell ownership.
- **Bottom panel Stage 2B-1 (the reserved v21 wire) LANDED — #184**
(merge `6bee09d`, 2026-07-28, two review rounds plus a gate-found
follow-up; all 12 checks green on reviewed head `5539b6e`). It adds
no producer, no consumer, and no capability: `panel_capable` is still
`false` for every semantic session, so nothing about it is
user-visible. What it establishes is durable:
- **Schema support and production advertisement are separate facts.**
`SUPPORTED` is now `6..=21`; the daemon's unsolicited `Hello` still
says 20. This is not a hedge — **the handshake is server-first**, so
a shipped v20 frontend rejects a `Hello { protocol_version: 21 }`
*before* it can send an `AttachRequest`. Bumping the advertised
version is therefore an incompatible act on its own, independent of
whether any new message is ever sent. A real-daemon acceptance
emulates that exact rejection point and then requires the
attachment to reach its initial grid. **2B-3 must ship a
compatibility-preserving activation mechanism; it may not simply
change the unsolicited `Hello` to 21.**
- **One shared grid validator, split along a stated boundary**
(`pmacs-protocol/src/wire_grid.rs`). Shared: checked area, the
visible-cell bound (262,144), cell count, cursor bounds, glyph
legality, wide-continuation topology, the 8 MiB aggregate
glyph-byte budget, and the attachment rejection. Terminal-only: the
512 per-axis PTY caps, title/process metadata, selection spans, and
the `at_bottom == (scroll_offset == 0)` coupling. Per-axis caps are
a `WireGridLimits` **parameter**, not a constant, because a panel
does not inherit them — a 4K surface at a small font is
legitimately wider than 512 columns, and the *area* bound is what
keeps the encoding inside the transport budget. The attachment
rejection is deliberately shared: panels render no attachments
either, so classifying it terminal-only would let a panel ship a
cell no frontend can paint.
- **`PanelFramePayload::Absent` is authoritative, and silence is
not.** The receiver retains its last valid frame, so a close *or* a
hide must send `Absent` explicitly or a stale band stays on screen
indefinitely. Validation is likewise atomic — a bad frame is
rejected whole and the previous valid frame is retained.
- **Two epochs, answering two different questions.** `panel_epoch` is
opaque and monotonic per frontend: stable across ordinary frames of
one continuously present window/buffer, and moved on buffer
replacement, new side-window creation, and every `Absent`
`Present` transition — which is what stops a stale `PanelPointer`
from addressing a reopened panel as if it were the old one (Q#BP16).
`geometry_epoch` answers a *frontend* declaration and moves whenever
the frontend declares new effective cell geometry, **including a
font or scale change that leaves `CellSize` identical** — exactly
the case daemon-side value dedup cannot see (Q#BP2S1).
- `PanelFrame` carries an explicit `buffer_id` (review round 1) and
its `focused` bit is presentation and focus-chrome routing only
(Q#BP14b) — the *keys* decision remains `DispatchIdle` (Q#BP14a).
- The frontend half is `FrontendEvent::{FrontendCellGeometry,
PanelResizeRows, PanelPointer}`, gated in both directions, with each
extended enum byte-pinned on its own previous final variant so the
v6v20 encodings are provably unchanged.
- **A version bump is not done until every ratchet that pins the old
version moves.** The full gate — not review — found that the
statusline and Vterm Stage 3 ladders still pinned v20 and rejected
v21, in both structural and real-headless-probe form. Grep for the
outgoing version across `tests/` before calling a bump complete.
- **GPU initial target LANDED — #148** - **GPU initial target LANDED — #148**
(`docs/gpu-initial-target-framing.md` rev 3; merge `0dd16a5`; two review (`docs/gpu-initial-target-framing.md` rev 3; merge `0dd16a5`; two review
rounds). `pmacs --gpu [--socket NAME|PATH] FILE` transports exact Unix path rounds). `pmacs --gpu [--socket NAME|PATH] FILE` transports exact Unix path
@ -1295,6 +1398,29 @@ round-trip cannot detect a discriminant shift.
echo instrument for the opposite reason people assume: termios `ECHO` is echo instrument for the opposite reason people assume: termios `ECHO` is
*off* in raw mode, so nothing double-echoes and one keystroke yields exactly *off* in raw mode, so nothing double-echoes and one keystroke yields exactly
one cell. one cell.
- **Draining the event stream to learn a pid also TICKS, and a tick
reaps.** #176's
`observing_the_leader_does_not_consume_the_exit_event` failed under
load with "process ProcessId(26) is not running": its helper drained
for `Started` to read the pid, `drain_until` ticks while it drains, and
a tick can observe an immediately-exiting child and move the record out
of `Running` — after which `signal` never reaches the code under test
at all. It passed standalone only because the drain returned on
`Started` before `poll_one` saw the exit. Read the pid **straight from
the supervisor record**, which does not tick, and fail fast if the
record has left `Running`. **Verified load-bearing under matched load:
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.
- **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
`#![forbid(unsafe_code)]` rules out. What works is driving the
production diagnostic in a **bounded loop until it observes the
exit**. Relatedly, #176's round-1 review replaced every substring
assertion with exact message equality built from the kernel-assigned
pid — the substring forms would have accepted a hardcoded target or a
wrong exit code.
- **The checkout may be shared with the user.** Check `git status` for - **The checkout may be shared with the user.** Check `git status` for
foreign uncommitted work before any stash/checkout/branch surgery; foreign uncommitted work before any stash/checkout/branch surgery;

View File

@ -1,13 +1,16 @@
# Bottom panel Stage 2 — the GPU panel band (framing) # Bottom panel Stage 2 — the GPU panel band (framing)
**Revision 6 — PR #184 review correction; the underlying Stage 2 **Revision 6 — PR #184 review correction; the underlying Stage 2
framing remains APPROVED 2026-07-27. 2A is merged and 2B-1 is under framing remains APPROVED 2026-07-27. 2A (#177) and 2B-1 (#184) are both
review. Ground truth: canonical `main` @ `7fd646d`, protocol v20 on merged, and 2B-2 is the next slice. Ground truth: canonical `main` @
`main`; `bottom-panel-stage2b` reserves the v21 schema while its `6bee09d`, where protocol schema support is `v6..=v21` while the
server-first production handshake continues to advertise v20.** production server-first handshake still deliberately advertises v20.**
Revisions 14 were pre-implementation; rev 5 recorded the three-way Revisions 14 were pre-implementation; rev 5 recorded the three-way
slice of Stage 2B after its first slice was already built; rev 6 slice of Stage 2B after its first slice was already built; rev 6
corrects that slice's mixed-version and gate contracts. corrects that slice's mixed-version and gate contracts. **No revision
bump accompanies 2B-1's merge** — the status sentence and ground-truth
anchor above are landed-state facts, and no design decision in this
document changed when #184 landed.
Stage 1 (#155, merge `e745068`) gave pmacs window placement, window Stage 1 (#155, merge `e745068`) gave pmacs window placement, window
parameters, TUI side windows, the divider, and the adopter `display` parameters, TUI side windows, the divider, and the adopter `display`