diff --git a/docs/active-work.md b/docs/active-work.md index 8b9fb8a..dc01df9 100644 --- a/docs/active-work.md +++ b/docs/active-work.md @@ -14,13 +14,16 @@ backlog. 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` @ `d400f30` (Lean 4 Stage 3b #170 atop Stage 3a - #167, the bottom-panel 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, and the minimap blank-slab fix #159; - protocol v20). The previous snapshot named `d152120`; the recovery - check below accepts it or anything newer. + `githubsucks/main` @ `a27f646` (Lean 4 Stage 4a #179 atop bottom-panel + Stage 2A #177, the bottom-panel Stage 2 framing #175, terminal + configuration Stage 1 #173, Lean 4 Stage 3b #170, Stage 3a #167, the + CRDT undo repro #157, the inline-math landed-doc refresh #172, the + bottom-panel 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, and the minimap blank-slab fix #159; protocol v20). The + previous snapshot named `d152120`; the recovery check below accepts it + or anything newer. - On the transfer source, `origin/main` named a release mirror at `d3fa632` and lagged badly. On the current destination, `origin` names the canonical URL. This difference is why all recovery begins by @@ -143,7 +146,7 @@ If it does not, stop and repair the remote/fetch configuration. to recur; the next occurrence carries its own evidence under whoever's PR, and a Stage B framing follows then. -## Lean 4 lane (Arc 8) — Stages 1, 2, 3a, 3b MERGED; Stage 4a IN REVIEW +## Lean 4 lane (Arc 8) — Stages 1, 2, 3a, 3b, 4a MERGED; 4b is next - **Stages 1, 2, 3a and 3b are MERGED** — #160 (`main` @ `0827dd1`), #161 (`46a1b8f`), #167 (`6f348c9`), #170 (`d400f30`). Their full @@ -159,9 +162,12 @@ If it does not, stop and repair the remote/fetch configuration. (`main` @ `d400f30`), 2026-07-26. Both were integrated against a main that had advanced 50 commits mid-review; the only conflict either time was this ledger's own lane headings, resolved by keeping both sides. -- Worktree `../pmacs-lean-stage4`, branched off `main` @ `d400f30`. - Framing-only so far: `docs/lean4-mode-framing.md` **revision 8**. No - code. Awaiting user approval before implementation, per the workflow. +- **Stage 4a merged as #179** (`main` @ `a27f646`, 2026-07-26) — the + typed-edit consumer chain. Worktree `../pmacs-lean-stage4`, branched + off `main` @ `d400f30`; retained, carrying nothing unmerged. + `docs/lean4-mode-framing.md` **revision 8** remains the approved + framing. **Stage 4b (the Lean-specific half) is framed and not + started.** - **Round 6 review found five P1s, four of them internal to rev 6** — facts about pmacs the revision asserted without checking, while its external (upstream) facts held. Fixed in rev 7: Stage 4a's footprint @@ -458,68 +464,109 @@ If it does not, stop and repair the remote/fetch configuration. resolve *to*, and `pmacs .` should route into it rather than growing a second directory surface. -## GPU terminal input lane — IN REVIEW +## The CRDT half of the test corpus is dark in CI — NEEDS A LANE -- Portable branch: `githubsucks/gpu-terminal-input`, worktree - `../pmacs-gui-term-input`, based on `githubsucks/main` @ `46a1b8f`. -- Approved framing: `docs/gpu-terminal-input-framing.md` revision 2, - committed as the branch's first commit (`9a0df21`). Bug fix, not a - feature; **no protocol change (stays v20)**. -- Reported as "text input within the terminal doesn't work on GUI, this is - fine in TUI". Root cause: the dispatcher applied **both** terminal-layout - syncs to **every** attached frontend, and a semantic session satisfies both - conditions (a `term_sizes` entry from `AttachRequest` *and* a terminal - declaration). Its PTY was resized twice per tick forever — grid arm installs - the TUI placement size, semantic arm installs the declared content - rectangle, each arm's idempotence guard seeing only what the other just - wrote — so the child took a `SIGWINCH` storm at tick cadence. -- **The fix is a split, not a guard.** The grid arm is also the only per-tick - controller-liveness release a semantic frontend gets, and - `sync_semantic_terminal_layout` cannot take that over: the buffer-follow - snapshot clears the viewport declaration (`on_buffer_snapshot_sent`), so - that arm stops running in exactly the switch-away case that needs the - release. `sync_terminal_layout` is therefore split into a - frontend-kind-neutral half (panel reconcile + liveness) and a grid-only - geometry half, with the loop body extracted to - `sync_terminal_layouts_for_tick` so the exclusivity is structural and tests - drive the real thing. -- **Trap for anyone touching this again:** the release at the "no - `window_placements` entry" arm reads like liveness and is grid geometry. A - semantic frontend has no placement entry at all, so moving it into the - neutral half releases a GPU controller every tick. -- Bite-verified against **two** pre-images, because the naive guard fixes the - storm and introduces the leak: +- **No branch, no framing yet.** Found while gating #166, then measured + properly during the vterm as-framed audit. Deliberately kept out of #166 so + a CI change would not arrive after review approval. +- **Root cause:** `.github/workflows/ci.yml` never enables the `crdt` feature + anywhere — zero hits across the workflow directory. The `test` job runs + `cargo test --all-targets --no-default-features --features luajit|lua54`. + Every `#[cfg(feature = "crdt")]` test is therefore **not compiled** in CI, + not merely skipped. +- **Measured, `--list` under CI's exact flags versus the same flags plus + `crdt`: 3,024 vs 3,288 — 264 tests dark.** Per target: - | pin | `main` | naive guard | the split | - |---|---|---|---| - | settle (acc 2+3) | FAIL | pass | pass | - | controller release (acc 6) | pass | FAIL | pass | - | grid still resizes (acc 5) | pass | pass | pass | + | dark | CI | full | target | + |---:|---:|---:|---| + | 177 | 1,832 | 2,009 | **the library itself** (`src/lib.rs`) | + | 21 | 15 | 36 | `m5_5_acceptance` | + | 13 | 1 | 14 | `gpu_invocation_acceptance` | + | 13 | 1 | 14 | `gpu_initial_target_acceptance` | + | 8 | 0 | 8 | `m10_11_acceptance` | + | 6 | 0 | 6 | `auto_pair_crdt_acceptance` | + | 6 | 0 | 6 | `m10_2_perf` | + | 4 | 5 | 9 | `vterm_stage3_acceptance` | + | 4 | 0 | 4 | `m10_10_perf` | + | 3 | 0 | 3 | `compile_mode_crdt_acceptance` | + | 2 | 22 | 24 | `theme_faces_acceptance` | + | 2 | 0 | 2 | `m11_5_semantic_acceptance` | + | 1 | 9 | 10 | `vterm_stage1_acceptance` | + | 1 | 7 | 8 | `statusline_segments_acceptance` | + | 1 | 10 | 11 | `gpu_font_acceptance` | + | 1 | 0 | 1 | `auto_indent_crdt_acceptance` | + | 1 | 0 | 1 | `m10_11_perf` | -- Real-path evidence: a quiet child trapping `SIGWINCH` reports **144 frames - in 4 s and `WINCH 1..12` on screen** against the pre-fix tree, versus a - settled screen with the fix. -- **Deliberately out of scope, named:** interactive-shell echo on a raw-mode - PTY (Q#GT5 — reproduces in-process too, so it is not the GUI/TUI - asymmetry), and a geometry change appearing to clear the visible screen - (reproduces pre-fix; why acceptance 4 latches its observation across - frames). -- Verification on this branch: `cargo fmt --check` clean; strict workspace - Clippy clean; 1,829 default + 2,006 CRDT library tests; vterm Stage 1/2/3 - 10 / 6 / 9 CRDT; bottom-panel Stage 1 46; M4 121; required GPU 155; - **isolated-config workspace sweep 3,177 across 92 suites, zero failures**; - `git diff --check` clean. Gates were run against the committed tree. +- **The single worst line is the library.** `cargo test --lib --features crdt` + is a REQUIRED local gate in `CLAUDE.md`, and CI has never run it. 177 + library tests — the whole CRDT half — are developer-machine-only. +- **Ten suites run zero or one test in CI**, including `gpu_initial_target` + (#148's entire acceptance, 1/14), `gpu_invocation` (#141's, 1/14), and + `a37`, the Vterm Stage 3 real-daemon/real-PTY/real-wgpu path that #135 + built specifically because "a decoded-message fixture would prove none of + the three fit together". +- **⚠ `a37` will report green in the new job without running, unless the + job builds `pmacs-gpu` AND sets `PMACS_REQUIRE_GPU=1`.** Measured + 2026-07-26 while gating #173. `a37_real_daemon_real_pty_and_headless_gpu_ + render_one_terminal_session` derives its sibling binary path from + `CARGO_BIN_EXE_pmacs`, and on a missing binary it `eprintln!`s a skip and + **returns `ok`**. A fresh worktree running + `cargo test --features crdt --test vterm_stage3_acceptance` reports **9/9 + in 0.17 s having never run it**; a real run takes ~4 s. Only + `PMACS_REQUIRE_GPU=1` promotes that skip to a failure, and `CLAUDE.md` + applies that flag to `cargo test -p pmacs-gpu` — a **different package**, + so the required local gate does not cover a37 either. The `gpu-render` + job already sets the flag, which is what makes fix-shape part 2 sound; + state it as a **requirement** of that job rather than inheriting it by + luck, because a `crdt` leg added to the plain `test` job would run a37 + vacuously. +- **`a37` is also load-sensitive, which changes how to read the expected + first-run failures.** It passed at `d152120` and failed at that *same + commit* twenty minutes later, with a second agent saturating the machine + with `rustc` in between; it then failed identically on `d152120`, + `04c5ad1`, and the #173 merge commit, which is how #173 established the + failure was not its own. The signature is `last_frame_text` all spaces + with `rendered_nonuniform_frames` nonzero — frames arrive, content does + not. `pmacs-gpu`'s own suite flaked the same way under the same load + (201/202, then 202/202 on immediate rerun). **So a red a37 on the first + CI run is ambiguous by construction**: before treating it as a real + failure, run the same command on the merge base, and prefer serialized + execution for this suite over retry-until-green. +- **Sort deliberate from accidental before proposing a fix.** Some of the 264 + are perf suites that are `#[ignore]`d by default and belong to their own + jobs (`m10_2_perf` 6, `m10_11_perf` 1). `m10_10_perf` has **no** `#[ignore]` + and no CI job naming it, so it looks accidental. This classification is not + finished and is the lane's first task. +- **Fix shape, two parts** (the flag combination is verified to work: + `--no-default-features --features luajit,crdt` lists 10 vterm Stage 1 tests + versus 9 without): + 1. a `crdt` leg on the `test` job for the non-GPU suites and the library; + 2. the GPU-requiring `crdt` suites onto the existing `gpu-render` job, which + already has lavapipe and `PMACS_REQUIRE_GPU=1` — + `vterm_stage3_acceptance`, `gpu_invocation_acceptance`, + `gpu_initial_target_acceptance`, `gpu_font_acceptance`. +- **Expect first-run failures, and budget for them.** These would execute in + CI for the first time ever: real PTY timing on CI runners, wgpu under + lavapipe, and daemon-socket tests at unfamiliar concurrency. Start + ubuntu-only and decide about macOS from evidence. A red first run is the + lane working, not the lane failing. +- Mitigating fact, verified rather than assumed: #166's three unit pins are + **not** `crdt`-gated and do run under CI's exact flags, including the + controller-release pin whose only job is catching the plausible wrong fix. -## Terminal config + copy mode arc — Stage 1 IN REVIEW +## Terminal config + copy mode arc — Stage 1 MERGED; Stage 2 is next - Approved framing: `docs/terminal-config-and-copy-mode-framing.md` **revision 4** (four review rounds), committed as the first commit of Stage 1's branch. Two stages, two branches, two PRs; **no protocol change**. -- **Stage 1 = `githubsucks/terminal-config`**, worktree - `../pmacs-terminal-config`, based on `githubsucks/main` @ `d152120` - and merged up to `c93f9ee` during review round 1. Profiles, - scrollback, escape key, and the `C-c t` opening binding. +- **Stage 1 MERGED as #173** (`main` @ `cf54270`, 2026-07-26, one review + round, all twelve checks green). Branch `githubsucks/terminal-config` + and worktree `../pmacs-terminal-config` retained. Profiles, scrollback, + a per-terminal configurable escape key, and the `C-c t` opening + binding; no protocol change. Main was integrated **twice** during the + single review round (`ccf29e3`, then `c93f9ee` after the first merge + left the PR conflicting) — see the no-CI-while-conflicting fact below. - **Stage 2 = `terminal-copy-mode`, not started.** Branch it off `main` after Stage 1 merges: no dependency, but both edit `builtin/runtime/terminal.lua`. @@ -604,22 +651,34 @@ If it does not, stop and repair the remote/fetch configuration. - `pmacs-gpu` itself failed 201/202 once under the same load and passed 202/202 on immediate rerun. -## Bottom-panel lane (Arc 7) — Stage 1 + framing MERGED; Stage 2A IN REVIEW +## Bottom-panel lane (Arc 7) — Stages 1, 2A + framing MERGED; 2B is next -Stage 1 and the Stage 2 framing are on `main`. **Stage 2A is -implemented and in review.** +Stage 1, the Stage 2 framing, and Stage 2A are all on `main`. **Stage 2B +has not started.** -- **Stage 2A — portable branch `githubsucks/bottom-panel-stage2a`**, - worktree `../pmacs-bp-stage2a`, **canonical `main` @ `cf54270` - integrated** (review round 1, finding 4 — the terminal-config lane - #173 also changes `src/editor.rs`, so gates were rerun on the merge - result, not the old combination). Five commits: the classified census - routing, the painter extraction + acceptance, the lane record, then - the round-1, round-2 and round-3 review fixes. **No protocol change; no behavior - change for any frontend today** — with `panel_capable = false` for - semantic sessions, `primary_document_window` returns `view.active` - in every existing configuration, so this is seam adoption that - becomes load-bearing in 2B. +- **Stage 2A MERGED as #177** (`main` @ `0a3fcd1`, 2026-07-26, all twelve + checks green at `8424172`, three review rounds). Branch + `githubsucks/bottom-panel-stage2a` and worktree `../pmacs-bp-stage2a` + are retained and carry nothing unmerged. Five commits: the classified + census routing, the painter extraction + acceptance, the lane record, + then the round-1, round-2 and round-3 review fixes. **No protocol + change; no behavior change for any frontend today** — with + `panel_capable = false` for semantic sessions, + `primary_document_window` returns `view.active` in every existing + configuration, so this is seam adoption that becomes load-bearing in + 2B. +- **Stage 2B is approved and unstarted.** It branches from `main`, **not + stacked on 2A**, per the framing §9. Scope: protocol v21, the daemon + panel projection, the GPU band, and the negotiated `panel_capable` + flip. `docs/bottom-panel-stage2-framing.md` §7.2 carries its five + acceptance criteria (A2B-1..5) plus the reassertion of parent + criterion 52, and §8 records **no open items**, so 2B needs no further + framing round. Its sharpest trap is §5.3's three-boundary split: the + GPU `text_area_bottom` is `status_band_top`, + `geometry_capacity_bottom` and `document_text_bottom` at once, and a + blanket rewrite moves the status chrome along with the document while + still satisfying an "everything moved" assertion — hence A2B-4's + contrast form. - Verification on the merge result: `cargo fmt --check` clean; strict workspace Clippy clean; **1,832 default + 2,015 CRDT** library tests; `bottom_panel_stage2a_acceptance` **17**; bottom-panel Stage 1 46; @@ -778,6 +837,23 @@ git worktree add --track \ ## Closed since the last snapshot +- **GPU terminal input (the double terminal-layout sync) — MERGED as #166** + (`main` @ `b889873`, 2026-07-25, one review round, all twelve checks green + after a macOS PTY-timing rerun). The dispatcher applied **both** + terminal-layout syncs to **every** attached frontend; a semantic session + satisfies both conditions, so its PTY was resized twice per tick forever and + the child took a `SIGWINCH` storm that made a GPU terminal untypable while + output still flowed. `sync_terminal_layout` is now split into a + frontend-kind-neutral half (panel reconcile + controller liveness) and a + grid-only geometry half, with the loop body extracted to + `sync_terminal_layouts_for_tick` so the exclusivity is structural. No + protocol change (v20). Durable lessons are in `docs/agent-handoff.md` §5; + the framing (`docs/gpu-terminal-input-framing.md` rev 2) carries three + falsified hypotheses, the two-pre-image bite matrix, and two named + out-of-scope items (Q#GT5 interactive-shell echo on a raw PTY, which + reproduces in-process and so is not the GUI/TUI asymmetry; and a geometry + change appearing to clear the visible screen, which reproduces pre-fix). + Branch `gpu-terminal-input` and worktree `../pmacs-gui-term-input` retained. - **Inline-math slice — MERGED as #158** (`main` @ `5aa9044`, 2026-07-25). Detect → parse → layout → draw for `$…$`, entirely inside `pmacs-gpu`, no protocol change. Verified by the user's manual pass on diff --git a/docs/agent-handoff.md b/docs/agent-handoff.md index 66ccc25..45ee353 100644 --- a/docs/agent-handoff.md +++ b/docs/agent-handoff.md @@ -1,9 +1,18 @@ # Agent handoff — cross-machine continuity -**Last updated: 2026-07-26, after Lean 4 stages 3a and 3b (#167, #170) -landed — pmacs' first Lean language server — following the inline-math -slice (#158), the first mathematical typesetting in pmacs, and find-file (#162), -the dired arc's Stage 0, and COHERENCE.md (#163), Lean 4 Stage 1 (#160), the +**Last updated: 2026-07-26, after Lean 4 Stage 4a (#179) — the typed-edit +consumer chain — and bottom-panel Stage 2A (#177), the classified census +routing that makes every Projection-class consumer ask +`primary_document_window`; following the bottom-panel Stage 2 framing +(#175), terminal configuration Stage 1 (#173) — profiles, scrollback, a +per-terminal configurable escape key, and the `C-c t` opening binding — +Lean 4 stages 3a and 3b (#167, #170), pmacs' first Lean language server; +the GPU terminal input fix (#166), the double terminal-layout sync that +made a GPU terminal untypable; the CRDT undo repro (#157), the +inline-math landed-doc refresh (#172), the inline-math slice (#158), the +first mathematical typesetting in pmacs; dired Stage 1 (#165), Lean 4 +Stage 2 (#161), the dired framing pair (#163/#164), find-file (#162) — +the dired arc's Stage 0 — COHERENCE.md (#163), Lean 4 Stage 1 (#160), the minimap blank-slab fix (#159), bottom-panel Stage 1 (#155), the inline-math re-scout (#154), the vterm PTY-flake fix (#153), and the GPU initial-target doc refresh (#152); and before that GPU @@ -28,13 +37,17 @@ commands, read `docs/active-work.md` immediately after this file. ## 1. Where the project stands (2026-07-26) -- `main` @ `d400f30` (Lean 4 Stage 3b #170 atop Stage 3a #167, the - bottom-panel 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**. The bullets below describe the arcs in - their own terms; this line is the head-of-`main` anchor. +- `main` @ `a27f646` (Lean 4 Stage 4a #179 atop bottom-panel Stage 2A + #177, the bottom-panel Stage 2 framing #175, terminal configuration + Stage 1 #173, Lean 4 Stage 3b #170, Stage 3a #167, the CRDT undo repro + #157, the inline-math landed-doc refresh #172, the bottom-panel + 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; + v21 arrives with Stage 2B. 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 @@ -758,6 +771,44 @@ commands, read `docs/active-work.md` immediately after this file. DAP, 8 GPU splits, plus the `.ipynb` arc (its JSON-grammar prerequisite shipped in #123). +- **GPU terminal input LANDED — #166** (`main` @ `b889873`; + `docs/gpu-terminal-input-framing.md` rev 2; one review round). The + dispatcher applied **both** terminal-layout syncs to **every** attached + frontend each tick. A semantic session satisfies both conditions — a + `term_sizes` entry from `AttachRequest` *and* a terminal declaration — so + its PTY was resized twice per tick forever: the grid arm installed the TUI + placement size, the semantic arm the declared content rectangle, each arm's + `old_size == size` guard seeing only what the other had just written. The + child took a `SIGWINCH` storm at tick cadence, which made typing into a GPU + terminal impossible while output kept flowing. TUI was structurally + unaffected. + - `EditorInstance::sync_terminal_layout` is split into + `sync_terminal_controller_liveness` (frontend-kind **neutral**: panel + reconcile + release of a controller whose window moved away — reads only + views/windows/controller, never a grid size) and + `sync_terminal_grid_geometry` (**grid only**: TUI placement + resize). + `sync_terminal_layout` survives as the composition, so `editor::run` and + `LOCAL` are byte-identical. + - `daemon::sync_terminal_layouts_for_tick` is the extracted loop body: + liveness for every frontend once per tick, then **exactly one** geometry + arm keyed on `semantic_states` membership — the same fact session + establishment uses, so the arms cannot both fire. + - **The trap, kept in a comment:** the release on a missing + `window_placements` entry reads like liveness and is grid geometry. A + semantic frontend has no placement entry at all, so moving it into the + neutral half would release a GPU controller every tick. + - Why not the one-line guard: the grid arm was also the **only** per-tick + controller-liveness release a semantic frontend got, and + `sync_semantic_terminal_layout` cannot take it over — the buffer-follow + snapshot clears the viewport declaration, so that arm stops running in + exactly the switch-away case that needs the release. + - No protocol change (v20). Gates: 1,829 default + 2,006 CRDT library + tests; vterm Stage 1/2/3 10/6/9 CRDT; bottom-panel 46; M4 121; required + GPU 155; isolated-config workspace sweep 3,177 across 92 suites. + - **Known gap, its own lane:** CI never enables `crdt`, so the Stage 3 + real-path acceptance (including `a37`) is not compiled there. #166's unit + pins are not `crdt`-gated and do run. See `docs/active-work.md`. + ## 2. How we work (the part that must not drift) The user is expert and reviews deeply — they falsify framings and find @@ -884,6 +935,34 @@ final variant — its own round-trip cannot detect a discriminant shift. ## 5. Hard-won ops lessons +- **A test that skips on a missing precondition reports `ok`, and a gate log + cannot tell that apart from a pass.** `vterm_stage3_acceptance::a37` — the + only acceptance driving a real daemon, a real PTY and a real wgpu render + together — derives `pmacs-gpu` from `CARGO_BIN_EXE_pmacs` and, when that + binary is absent from the target directory, prints a skip and returns. + A fresh worktree reports the suite 9/9 **in 0.17 s having never run it**; + a real run takes ~4 s. `PMACS_REQUIRE_GPU=1` is what promotes the skip to + a failure, and the standing gate list applies that flag to + `cargo test -p pmacs-gpu`, a *different package*. Two habits follow: + build the workspace before believing any suite that reaches for a sibling + binary, and **judge such a suite by its elapsed time**, not its verdict. +- **Before attributing a red test to your branch, run it on the merge base.** + `a37` failed on the #173 branch, which looked like a regression; it failed + identically on the PR's own base and on two intermediate commits, and had + *passed* on that same base twenty minutes earlier. The variable was machine + load from a second agent compiling continuously. Load-sensitive tests make + both verdicts uninformative in isolation, so the base-commit run is the + cheapest way to tell a regression from weather — and it is much cheaper + than the bisect it replaces. +- **A daemon-side fix is not deployed until the daemon is restarted from a + tree that contains it.** #166's reporter rebuilt and saw no change: the + running daemon had been started from a shared checkout still on a pre-fix + branch, and `pmacs --gpu` attaches to whatever process already owns the + socket. Rebuilding a binary does nothing to a running process. When + validating a daemon-side fix by hand, check the running process's binary + path and start time against the tree you think you fixed — + `ps -eo pid,lstart,args | grep '[p]macs --daemon'` — before concluding the + fix failed. - **Two operations that must be alternatives are not made alternatives by being adjacent.** The dispatcher applied its grid and semantic terminal-layout syncs to every attached frontend; a semantic session diff --git a/docs/gpu-terminal-input-framing.md b/docs/gpu-terminal-input-framing.md index 0bbccef..aa1bea4 100644 --- a/docs/gpu-terminal-input-framing.md +++ b/docs/gpu-terminal-input-framing.md @@ -81,7 +81,11 @@ character: | | frames for a static screen | typed `Z` ever visible at the prompt | |---|---|---| | `main` today | **730** in a 20 s window | **no** | -| with the guard | **2** | (see Q#GT5 — a separate question) | +| with the fix | **2** | yes | + +Bet B2 is **scored TRUE**: with the fix deployed, the reporter confirmed +typing into a GPU terminal works. The earlier caveat here pointed at Q#GT5, +which is now retracted — see "Deferred (named)". The TUI is unaffected: a grid session has no semantic terminal declaration, so only one arm ever runs for it. This is a **frontend-kind** defect, which is @@ -281,11 +285,12 @@ change. Stays v20. snapshot that signals the switch-away). Hence the split in Q#GT1. Recorded rather than deleted: the failure mode is one a reviewer or a future simplification will re-propose. -- **B2.** The user's reported symptom is this defect. *Partially scored: the - storm is proven and GUI-only, and its shape (line editor unusable, output - still flowing) matches the report. Not fully scored until the user, or an - acceptance running the **user's own shell**, confirms typing works after the - fix. Q#GT5 is the reason this bet is stated rather than assumed.* +- **B2 — SCORED TRUE 2026-07-25.** "The user's reported symptom is this + defect." Confirmed in real use after the fix was deployed: typing into a GPU + terminal works. The confirmation needed a daemon **restart** built from a + tree containing the fix — the first attempt reported no change because a + pre-fix daemon still owned the socket, which is worth remembering whenever a + daemon-side fix is being validated by hand. - **B3.** No other pair of per-frontend-kind daemon operations is applied as siblings rather than alternatives. *Scored by an explicit audit of the dispatcher's per-frontend loop during implementation — this defect's shape @@ -294,7 +299,14 @@ change. Stays v20. ## Deferred (named) -- Interactive-shell echo on a raw-mode PTY (Q#GT5) — its own scout. +- ~~Interactive-shell echo on a raw-mode PTY (Q#GT5)~~ — **RETRACTED + 2026-07-25.** The observation behind it (a `bash --norc -i` fixture not + echoing typed characters) does not reproduce in real use: with the fix + deployed, typing into a GPU terminal echoes normally. The fixture was almost + certainly measuring its own timing — polling a published screen snapshot + before readline had finished initialising — not a product behaviour. Recorded + as retracted rather than deleted so nobody re-derives it from the framing's + earlier revision and spends a scout on it. - **A geometry change appears to clear the visible screen.** Observed while building acceptance 4: after the probe's deliberate 25×92 → 20×71 resize, the next frame's visible grid is entirely blank even though the content diff --git a/docs/vterm-framing.md b/docs/vterm-framing.md index b1124c0..7d4ca02 100644 --- a/docs/vterm-framing.md +++ b/docs/vterm-framing.md @@ -1674,6 +1674,64 @@ GPU assertions remain in `pmacs-protocol` and `pmacs-gpu` respectively. - **37:** one real-daemon/real-PTY/headless-wgpu acceptance path; it is not replaced by a decoded-message fixture. +### 0.12 As-framed audit, 2026-07-25 (after #166) + +Prompted by a GPU terminal input defect that shipped in Stage 3 and was fixed +in #166. The arc is structurally complete — all 37 criteria have +implementations, and every test named in the Stage 2 verification map exists — +but the audit found two gaps worth recording against the criteria themselves. + +**Criterion 22's "without thrash" was never pinned.** The criterion reads +"unchanged, zero, passive, and failed resize cases preserve prior geometry +*without thrash*". The word appears nowhere in `src/` or `tests/`. The suite +pinned the four enumerated single-arm cases and never the cross-arm +interaction — which is exactly where the thrash lived: the daemon applied +both the grid and the semantic terminal-layout sync to every attached +frontend, so a semantic session's PTY was resized twice per tick forever. +Criterion 31's "only the exact durable controller changes PTY geometry" was +violated in the same event, in spirit rather than letter: the controller was +the right frontend, but the geometry came from the grid projection. #166 adds +the settle pins; the gap was open from #135 (2026-07-22) until then. + +**Why the Stage 3 suite could not see it.** Of its nine tests, only three +drive a real daemon; the other six construct `EditorState` directly and never +execute the dispatcher loop where the defect lived. `a31`, which is about two +semantic frontends sharing one session, therefore passes on the broken tree. +The same structural blindness explains why `bottom_panel_stage1_acceptance` +was unaffected. A criterion about *dispatcher* behavior needs a test that +runs the dispatcher. + +**Four of the nine Stage 3 tests do not run in CI at all**, because they are +`#[cfg(feature = "crdt")]` and the workflow never enables that feature: +`a37`, the two added by #166, and +`terminal_mode_keeps_reporting_presence_so_peers_drop_the_stale_caret` — which +is Stage 3 review round 1's own regression guard. Stage 1's +`read_only_empty_crdt_bootstrap_is_immutable_against_remote_content`, the CRDT +half of criterion 14, is dark for the same reason. Stage 2 is fully covered +(6/6). This is not a vterm problem: 264 tests workspace-wide are dark, +including 177 in the library. It has its own lane in `docs/active-work.md`. + +**And `a37` is darker still than that count implies: it reports `ok` without +running whenever `pmacs-gpu` is absent from the same target directory** +(measured 2026-07-26 while gating #173). It derives the sibling binary from +`CARGO_BIN_EXE_pmacs` and, finding nothing, prints a skip notice and returns. +A fresh worktree reports the suite 9/9 in 0.17 s having executed the arc's +only real-daemon/real-PTY/real-wgpu path zero times; a genuine run takes +about four seconds. `PMACS_REQUIRE_GPU=1` is the only thing that turns that +skip into a failure, and the standing gate list applies that flag to +`cargo test -p pmacs-gpu`, a different package. So the audit's claim that +"only 3 of 9 Stage 3 tests drive a real daemon" was itself optimistic — +**on a target directory without the frontend binary the honest number is 2**, +and nothing in the gate log says so. It is also load-sensitive: it passed and +then failed at the same commit twenty minutes apart under machine +contention. Criterion 22's unpinned "without thrash" and this are the arc's +two standing verification gaps. + +**Not audited:** §11's blanket claim that "deferral means graceful ignore or +documented absence, never escape leakage, panic, unbounded allocation, or +child leak". That covers roughly twenty deferred items and none were +spot-checked. It remains an unproven claim rather than a known gap. + ## 10. Gates and bite verification Every PR runs the standing full gates from `AGENTS.md`, sequentially, plus its