From e05ac819b5feae1747ce25cd20ed4e3cfe2b9f12 Mon Sep 17 00:00:00 2001 From: Levi Neuwirth Date: Tue, 28 Jul 2026 16:28:21 -0400 Subject: [PATCH] docs: sync the durable records to landed main @ 6bee09d MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- COHERENCE.md | 8 +- docs/active-work.md | 334 +++++++++------------------- docs/agent-handoff.md | 170 ++++++++++++-- docs/bottom-panel-stage2-framing.md | 13 +- 4 files changed, 266 insertions(+), 259 deletions(-) diff --git a/COHERENCE.md b/COHERENCE.md index e997614..6d1e80f 100644 --- a/COHERENCE.md +++ b/COHERENCE.md @@ -1343,10 +1343,10 @@ its asks are already practiced.** - Versioned protocol schema `SUPPORTED=[6..=21]` with deliberate encoding-breaking bumps, both-frontends support required per bump, and byte-pin discipline for appended variants (handoff §4). The v21 - bottom-panel family is reserved but dark in Stage 2B-1: because - `Hello` is server-first, the production daemon still advertises v20 - so shipped v20 clients remain attachable; compatible v21 activation - belongs to Stage 2B-3. + bottom-panel family landed with Stage 2B-1 (#184) and is reserved but + dark: because `Hello` is server-first, the production daemon still + advertises v20 so shipped v20 clients remain attachable; compatible + v21 activation belongs to Stage 2B-3. - Two genuine frontends share the conceptual model; CRDT concurrent editing with presence across them; remote attach + reconnect. - **Graceful per-frontend degradation is practiced, not aspirational**: diff --git a/docs/active-work.md b/docs/active-work.md index 6a47763..19ed9d5 100644 --- a/docs/active-work.md +++ b/docs/active-work.md @@ -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 backlog. -**One lane below is retained past its merge, and says so at its own -head**: the PTY terminate diagnostic (#176), because no landed-doc PR -owns moving its facts to `docs/agent-handoff.md` yet, and rule 4 removes -a lane only *after* that move. Every other merged lane has been removed — -the Lean 4 and GPU-terminal-input headers this paragraph used to -disclaim are gone, as are the inline-math (#172), dired (#169), and -terminal config + copy mode lanes — the last of these was #180's work, -folded into #182 so two open PRs would stop re-conflicting in this file. +**No lane below is retained past its merge.** The PTY terminate +diagnostic (#176) was the last one — retained because rule 4 removes a +merged lane only *after* its durable facts reach +`docs/agent-handoff.md`, and that absorption was unowned. This snapshot +owns it: #176's facts are now in the handoff (§1's arc bullet and §5's +two ops lessons about ticking observers and proving child exit), so its +lane is gone. The Lean 4, GPU-terminal-input, inline-math (#172), dired +(#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 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, or something else, and therefore has no authority by name alone. - Canonical base at this snapshot: - `githubsucks/main` @ `7fd646d` (Journey/GPU directory-target ratchet - #183, atop Journey Stage 1a #182 and the previously recorded landed - work; protocol v20). The previous snapshot named `c2d56ff`, and **the + `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 + `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 - `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 accepts an older commit than the declared base passes on a tree the rest of this file does not describe. @@ -70,106 +75,13 @@ git worktree list 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 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 describe. 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 1–3 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 - **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 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 -revision 5's three-way split of 2B was explicitly approved on -2026-07-27; revision 6 records PR #184's review correction. **Stage -2B-1 is implemented and integrated with canonical `main` @ `7fd646d`. -Review round 2's four findings are corrected at `ab7c207`; the -gate-found GPU/PTY probe barrier is corrected and the complete suite is -green at `9e20175`. The follow-up fixture-specific probe correction is -committed and proportionally regated at `9c79ce1`. PR #184 is open and -must not merge before user review.** +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.** -- **Stage 2B-1 branch:** `bottom-panel-stage2b`, based on - `githubsucks/main` @ `7fd646d` by merge because review had begun. - Recovery: `git fetch githubsucks && git checkout - bottom-panel-stage2b`. Everything described through the integration - and gate checkpoint is committed and pushed; nothing depends on a - worktree or `/tmp`. PR #184: - . -- **Ships only the reserved v21 wire layer:** the four wire shapes, - schema version, shared cell-grid validator, and accepted-version - ladder move. The production daemon continues advertising v20 because - its `Hello` is server-first; v21 activation belongs to 2B-3. This - slice has no producer, consumer, or capability change; - `panel_capable` stays `false`, so it changes no user-visible journey - grade and existing v20 clients remain attachable. -- **Review round 1 closed:** two P1s and one P2, all corrected at - `9b364ad`: `PanelFrame` now identifies its buffer, the transport - ratchet covers the actual attach path rather than a detached codec - assertion, and shared grid bounds have one validator. -- **Review round 2 found four issues, corrected at `ab7c207`:** the - server-first `Hello` made the advertised v20↔v21 compatibility - one-way; `COHERENCE.md` and `docs/agent-handoff.md` still named only - v20 schema support; framing §9 named a nonexistent aggregate 2B - suite instead of the three exact 2B slice suites; and the panel plus - copied terminal "one byte over" fixtures were actually two bytes - over. The correction keeps production advertisement at v20, adds a - real-daemon existing-v20-client acceptance, updates all three durable - records, names the exact slice suites, and asserts both rejecting - fixtures are exactly `limit + 1`. -- **The full gate exposed and corrected a contradiction in Vterm Stage - 3's headless probe at `9e20175`.** Its loop exited as soon as resize - plus two nonuniform composites were observed, while its acceptance - later required the PTY child's `VTERMROW` output in the final frame. - The v20-compatible handshake made that scheduling race deterministic: - terminal mode, five frames, and resize all succeeded, but the report +- **Stage 2B-1 MERGED as #184** (`main` @ `6bee09d`, 2026-07-28; all + twelve checks green on the reviewed head `5539b6e`; two review rounds + plus a gate-found follow-up). Branch + `githubsucks/bottom-panel-stage2b` and worktree `../pmacs-bp-stage2b` + are retained and carry nothing unmerged. Durable facts — the + schema-support-versus-advertisement split, the shared `wire_grid` + boundary, authoritative `Absent`, and the two epochs — are in + `docs/agent-handoff.md` §1 per rule 3, not here. +- **What 2B-1 deliberately did not do**, because 2B-2 and 2B-3 must not + re-litigate it: no producer, no consumer, no capability change. + `panel_capable` is still `false` for every semantic session, so the + journey grade is unchanged and every shipped v20 client remains + attachable. +- **2B-3 inherits a hard constraint from 2B-1's review**: it owns a + *compatibility-preserving* v21 activation mechanism and may **not** + simply change the unsolicited `Hello` to 21. The handshake is + server-first, so that one-line change locks out every shipped v20 + frontend before it can even send an `AttachRequest`. +- **Two review rounds, and what each cost.** Round 1: `PanelFrame` + needed an explicit `buffer_id`, the transport ratchet had to drive the + real attach path rather than a detached codec assertion, and shared + grid bounds needed one validator. Round 2: the server-first `Hello` + made the advertised v20↔v21 compatibility one-way; `COHERENCE.md` and + the handoff still named only v20 schema support; framing §9 named a + nonexistent aggregate 2B suite instead of the three exact slice + suites; and the panel plus copied-terminal "one byte over" fixtures + were actually two bytes over. +- **The full gate — not review — found two version-ladder omissions and + one probe contradiction.** The statusline and Vterm Stage 3 ladders + still pinned v20 and rejected v21. Separately, Vterm Stage 3's + headless probe exited its loop as soon as resize plus two nonuniform + composites were observed, while its acceptance later required the PTY + child's `VTERMROW` output in the final frame; the v20-compatible + handshake made that scheduling race deterministic, so the report sampled a blank frame. The probe now waits for the exact child-output - observation its acceptance asserts. The formerly failing exact - GPU/PTY test passes, and the full nine-test Stage 3 target passes. -- **Follow-up review corrected the probe barrier's fixture leak at - `9c79ce1`.** The generic runner hard-coded the producer fixture's + observation its acceptance asserts. +- **The probe fix then leaked its own fixture, and that is the reusable + lesson.** The generic runner hard-coded the *producer* fixture's `VTERMROW` breadcrumb, so the CAT input fixture could satisfy every - assertion but never satisfy the loop exit and waited out the - 20-second safety deadline. Producer probes now name their required - frame text while input probes finish on the latched echo. The report - exposes `completion_observed`, and both paths assert it, so a - deadline-driven pass cannot hide the stall again. -- **The full gate found and corrected two 2B-1 omissions:** the - statusline version ladder still pinned v20/rejected v21, and Vterm - Stage 3 pinned v20 both structurally and in its real headless probe. - Those ratchets now expect v21 and, where applicable, reject v22. -- **Pre-integration green evidence at `b9123c2`:** formatting and 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**; Vterm Stages 1 / 2 / 3 - **10 / 6 / 9 CRDT**, with Stage 3's real daemon + PTY + wgpu probe - required and green; M4 **121 passed + 3 ignored + 1 filtered**; - required GPU **202**; and the isolated-config, one-invocation full - workspace sweep green on rerun. Its first pass hit the known - completion-before-supersede race in - `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 + assertion yet never satisfy the loop exit — it waited out the + 20-second safety deadline and passed on the deadline. Producer probes + now name their own required frame text while input probes finish on + the latched echo, and the report exposes `completion_observed` which + **both** paths assert, so a deadline-driven pass cannot hide a stall + again. +- **Final verification on the reviewed head:** `cargo fmt --check`; + 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 / 16**; folding Stage 2 **48**; GPU font **11**; + statusline **8 CRDT**; m11_5 semantic **2 CRDT**; GPU initial target + and invocation **15 / 15 CRDT**; the handshake consumers m5_5 / m5_7 / + mode-system wiring **36 / 7 / 1 CRDT**; Vterm Stages 1 / 2 / 3 + **10 / 6 / 9 CRDT**, including the required real daemon + real PTY + + real 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`. + - Retained as classification rather than erased: the first + required-GPU pass was **201/202** on `a_fraction_draws_rule_pixels_between_its_operand_rows`, a rendering - test structurally outside this lane's protocol-only GPU diff. The - exact test passed immediately in isolation with one test thread, and - the mandatory complete rerun passed **202/202**. This is retained as - classified gate evidence, not erased as a clean first pass. -- **The corrected review-round-2 head is fully green at `9e20175`:** - 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 / 16**; folding Stage 2 **48**; GPU - font **11**; statusline **8 CRDT**; m11_5 semantic **2 CRDT**; GPU - 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. + test structurally outside a protocol-only diff, which passed + immediately in single-threaded isolation and **202/202** on the + mandatory complete rerun. Separately, library and Vterm attempts + *inside the restricted tool sandbox* produced `Operation not + permitted` failures in socket-based attach tests; the authoritative + outside-sandbox reruns passed. +- **Ordering for the rest of the arc is fixed:** 2B-2 branches from + landed `main`; 2B-3 branches only after 2B-2 lands; Stage 3 (the + adopter default flip) last. Each slice starts fresh from landed main. - **Stage 2A MERGED as #177** (`main` @ `0a3fcd1`, 2026-07-26, all twelve checks green at `8424172`, three review rounds). Branch @@ -597,7 +461,21 @@ git worktree add --track \ 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` - Carries synchronized `AGENTS.md` / `CLAUDE.md`, this ledger, the diff --git a/docs/agent-handoff.md b/docs/agent-handoff.md index bc6f440..ea5319f 100644 --- a/docs/agent-handoff.md +++ b/docs/agent-handoff.md @@ -1,7 +1,9 @@ # Agent handoff — cross-machine continuity -**Last updated: 2026-07-28, during bottom-panel Stage 2B-1 PR #184 -review; the canonical landed base remains the Journey/GPU +**Last updated: 2026-07-28, after bottom-panel Stage 2B-1 (#184) merged; +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), which made directory 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) -- `main` @ `7fd646d` (Journey/GPU directory-target ratchet #183, atop - Journey Stage 1a #182, incorporating terminal configuration + copy +- `main` @ `6bee09d` (bottom-panel Stage 2B-1 #184, atop 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 docs #169 and the PTY-terminate diagnostic #176, terminal copy mode #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 #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, - minimap blank-slab #159, bottom-panel Stage 1 #155). Protocol unchanged - at **v20** — bottom-panel Stage 2A deliberately carries no wire change. - The in-review Stage 2B-1 reserves the v21 schema but keeps the - server-first production `Hello` at v20; compatible activation belongs - to Stage 2B-3. The bullets below describe the arcs in their own terms; - this line is the head-of-`main` anchor. + minimap blank-slab #159, bottom-panel Stage 1 #155). + **Protocol schema support is now `v6..=v21`, while the production + server-first `Hello` still advertises v20.** Those are two different + facts and #184 landed only the first: the v21 bottom-panel wire family + exists, is gated in both directions, and has no producer, no consumer, + 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 — #163.** It carries the product-coherence thesis, an audited 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 occurrences rather than test presence**, because a single-character 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** (`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 @@ -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; required GPU 152; initial-target 14 CRDT; all three vterm suites; folding Stage 2 48. All 12 CI checks green at merge. - - **Stage 2 (the GPU panel band) is FRAMED** — - `docs/bottom-panel-stage2-framing.md` rev 6, four framing review - rounds, no open framing items; the rev-5 implementation split was - explicitly approved 2026-07-27 and rev 6 records PR #184's - server-first compatibility and gate correction. It reserves - protocol **v21** and ships as four serial + - **Stage 2 (the GPU panel band) is FRAMED, and its first two slices + have LANDED** — `docs/bottom-panel-stage2-framing.md` rev 6, four + framing review rounds, no open framing items; the rev-5 + implementation split was explicitly approved 2026-07-27 and rev 6 + records PR #184's server-first compatibility and gate correction. + It reserves protocol **v21** and ships as four serial implementation slices: **2A** classified census routing + - per-window painter extraction (no wire change), **2B-1** the wire, - **2B-2** the daemon projection and epoch machine, then **2B-3** the - GPU band, compatible v21 activation, and negotiated - `panel_capable` flip. Production attachment remains v20 through - 2B-1 and 2B-2. Parent acceptance 37–55 remains authoritative. - Stage 3 is the adopter default flip. + per-window painter extraction (no wire change, #177), **2B-1** the + wire (#184), **2B-2** the daemon projection and epoch machine, + then **2B-3** the GPU band, compatible v21 activation, and the + negotiated `panel_capable` flip. Production attachment remains v20 + through 2B-2. Parent acceptance 37–55 remains authoritative. + 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 Projection class (#1–#12, #21–#22) routes through `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 application, `DispatchIdle`, presence, focused 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 + v6–v20 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** (`docs/gpu-initial-target-framing.md` rev 3; merge `0dd16a5`; two review 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 *off* in raw mode, so nothing double-echoes and one keystroke yields exactly 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 foreign uncommitted work before any stash/checkout/branch surgery; diff --git a/docs/bottom-panel-stage2-framing.md b/docs/bottom-panel-stage2-framing.md index 2384118..b3ce129 100644 --- a/docs/bottom-panel-stage2-framing.md +++ b/docs/bottom-panel-stage2-framing.md @@ -1,13 +1,16 @@ # Bottom panel Stage 2 — the GPU panel band (framing) **Revision 6 — PR #184 review correction; the underlying Stage 2 -framing remains APPROVED 2026-07-27. 2A is merged and 2B-1 is under -review. Ground truth: canonical `main` @ `7fd646d`, protocol v20 on -`main`; `bottom-panel-stage2b` reserves the v21 schema while its -server-first production handshake continues to advertise v20.** +framing remains APPROVED 2026-07-27. 2A (#177) and 2B-1 (#184) are both +merged, and 2B-2 is the next slice. Ground truth: canonical `main` @ +`6bee09d`, where protocol schema support is `v6..=v21` while the +production server-first handshake still deliberately advertises v20.** Revisions 1–4 were pre-implementation; rev 5 recorded the three-way 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 parameters, TUI side windows, the divider, and the adopter `display`