From 502308d8e48325a139d578ef311b61ee6f85f9ae Mon Sep 17 00:00:00 2001 From: Levi Neuwirth Date: Wed, 12 Aug 2026 13:14:51 +0200 Subject: [PATCH 1/5] docs: absorb #236 and #237 --- the GUI arc anchor moves to d038f71 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docs only. No `src/`, no `pmacs-gpu/`, no 1a implementation. **The recovery procedure was RE-RUN, not SHA-swapped, and that is what licenses the rest of this commit.** Every documented step, from an empty directory, on git 2.55.0: clone the canonical URL (which names it `origin`, and `git remote get-url githubsucks` errors with `No such remote`, exactly as the section anticipates); add the alias; fetch; `git log -1 --oneline githubsucks/main` -> `d038f71`; confirm BOTH the old floor `9a26ac8` and the new `d038f71` are ancestors, so advancing the floor is valid rather than merely plausible; recover with the three-argument `git worktree add -b githubsucks/` form and confirm the upstream is actually set. The documented TRAP was reproduced too: the two-argument form succeeds and leaves `## HEAD (no branch)`, so that correction still holds on 2.55.0. **This discharges a debt rather than inheriting one.** The previous absorption advanced the base to `e67ad07` WITHOUT re-running the procedure and recorded that as an outstanding obligation. It is settled here, by the run above. Canonical base, recovery floor, the `git log` threshold and the last-exercised record all move to `d038f71` together --- a floor that accepts an older commit than the base it declares passes on a tree the rest of the file does not describe. **The GUI lane is REWRITTEN, not removed.** Rule 4 removes a lane when its ARC is done; the arc is Stage 1 as a whole and **five slices remain**. The lane now records 1-pre as merged, names 1a as next and NOT STARTED, and keeps the fact that 1a (v24 `TextInput`) and 1e (v25 `OpenTarget`) are the two protocol-bearing slices and are serialized. Open-PR and branch-recovery wording for 1-pre is gone --- a lane that still says "recover with `git checkout`" for a merged branch is how a reader ends up on a stale tip. The handoff anchor absorbs both merges, and §1 gains the arc bullet the anchor promises. Its durable facts are the ones that will bind future slices rather than the diff: a route carries the DECISION and only the body gives the EFFECT; a harness that re-implements what it tests witnesses its own copy; winit's `KeyEvent` is non-constructible outside winit and this will bind every GUI input slice; the sentinel is the success condition and the timeout only an error ceiling; four test defects that were all one shape --- witnessing an absence the harness had manufactured; and `cargo metadata`, not intuition, decides which CI job runs a member's unit tests. **One judgement beyond the stated scope, flagged rather than slipped in.** §1a's board had no GUI-arc row at all, which would have contradicted the anchor two sections above it. A row is added at the position `COHERENCE.md` §20 Q#GA5 gives it --- after Priority 1, running alongside P2-P5, interacting only at the P2 start gate --- and the P2 row now names that gate. The section's own dateline is corrected in the same breath: the table was written 2026-08-01 and claimed zero open PRs, so it now says which row is current and which are as-of that date. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai --- docs/active-work.md | 304 +++++++++++++++--------------------------- docs/agent-handoff.md | 82 +++++++++++- 2 files changed, 188 insertions(+), 198 deletions(-) diff --git a/docs/active-work.md b/docs/active-work.md index 870b8be..9f8a7ee 100644 --- a/docs/active-work.md +++ b/docs/active-work.md @@ -136,7 +136,11 @@ lesson, §1 for the two framings). are identical on every machine. Remote names are otherwise 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` @ `e67ad07`** — +- Canonical base at this snapshot: **`githubsucks/main` @ `d038f71`** — + **GUI Stage 1-pre #237**, the input seam (`App::window_event` from 655 + lines to four; no behaviour change, no wire change), atop `f8ad3e7` + **GUI arc Stage 0 #236**, the arc framing and its documentation sweep. + Beneath them `e67ad07`, the file-watcher arc absorption, atop `122b8e8` the file-watcher D3 **#235** (closes issue #233), atop `b867f64` git integration Stage 1 **#227**, atop `ae84d58` the LSP file-watcher @@ -173,7 +177,7 @@ lesson, §1 for the two framings). where they describe a stage as it landed** — only this current-state paragraph tracks the live range. **The recovery floor advances with the base**, so the check below - now requires **`e67ad07`** or newer; a tree at `db1bbe9` no longer + now requires **`d038f71`** or newer; a tree at `db1bbe9` no longer passes — it would lack the entire QoL arc, which this file and the handoff both describe as complete. That is deliberate — a check accepting an older commit than the declared base passes on a tree the rest of this file does not @@ -213,28 +217,40 @@ git worktree list git status --short --branch ``` -The `git log` command must expose `e67ad07` — the base named above — or a +The `git log` command must expose `d038f71` — 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. -**LAST EXERCISED AT `9a26ac8`, 2026-08-08** — re-run from an empty -directory rather than having its SHA swapped. **The advance to -`e67ad07` (2026-08-11) has NOT been re-exercised**, and by this -paragraph's own argument that is exactly when the exercise matters, so -it is recorded as an outstanding obligation rather than left to read as -though it had been done. The floor above and the check below are in -step at `e67ad07`; what is unverified is the *procedure* against that -base, not the SHA. That distinction is the -whole point of this paragraph: advancing the base is exactly when the -recovery commands are most likely to have rotted, and a swapped SHA -reads identically to a verified one. `git clone` the canonical URL, add -the `githubsucks` alias, `git fetch githubsucks --prune`, confirm -`9a26ac8` is an ancestor of `githubsucks/main`, and recover with the -three-argument `git worktree add -b githubsucks/` -form. All four steps ran clean. +**LAST EXERCISED AT `d038f71`, 2026-08-12**, from an empty directory +rather than by having its SHA swapped — **which also discharges the +outstanding obligation this paragraph carried at `e67ad07`**, where the +base advanced without the procedure being re-run. That debt is settled, +not inherited: the advance recorded here was exercised as part of making +it. + +Every documented step ran, in order, on git **2.55.0**: + +1. `git clone` the canonical URL into an empty directory. The clone + names it `origin`; **`git remote get-url githubsucks` errors with + `No such remote`**, exactly as the section above anticipates. +2. Add the alias, confirm the URL, `git fetch githubsucks --prune`. +3. `git log -1 --oneline githubsucks/main` → `d038f71`. +4. **The floor check, run against both floors**: `9a26ac8` (the old one) + and `d038f71` are each an ancestor of the tip, so advancing the floor + is valid rather than merely plausible. +5. The three-argument `git worktree add -b + githubsucks/` form → a real branch with its upstream set + (`## recovered-local...githubsucks/gui-stage1-pre`). +6. **The documented trap, reproduced rather than assumed**: the + two-argument form on a remote-only branch **succeeds** and leaves + `## HEAD (no branch)`. The correction below still holds on 2.55.0. + +That distinction is the whole point of this paragraph: advancing the +base is exactly when the recovery commands are most likely to have +rotted, and a swapped SHA reads identically to a verified one. **Correction, found by re-running it.** This file claimed the two-argument form fails for a remote-only branch with `fatal: invalid @@ -250,186 +266,88 @@ hazard in a shape that looks committed. **A documented error message that never appears is worse than no documentation**, because the reader waits for a signal that is not coming. -## GUI arc Stage 1 — 1-pre OPEN as PR #237 +## GUI arc Stage 1 — 1-pre MERGED as #237 (`d038f71`); 1a is next, NOT STARTED -**Written at the branch's first commit**, with the framing, as the arc's -§5 requires of every PR in it. +**The lane is rewritten, not removed.** Rule 4 removes a lane when its +ARC is done, and the arc is Stage 1 as a whole: **five slices remain**. -- **PR #237** — https://github.com/levineuwirth/pmacs/pull/237. -- **Branch `gui-stage1-pre`**, base `githubsucks/main` @ `f8ad3e7` (the - Stage 0 merge, #236). **`githubsucks/gui-stage1-pre` is the - authoritative tip** — the ref, not a SHA. Recover with - `git fetch githubsucks && git checkout gui-stage1-pre`. - **Framing `docs/gui-stage1-input-framing.md`, revision 11, APPROVED** - after **eight rejected revisions**. Revision 9 is the approved design; - revision 10 recorded a scope correction found against this - implementation and **also argued P2 was satisfied by classification - alone, which review overturned — revision 11 retracts it**. It is - Stage 1's framing for **all** slices and governs the later branches; - only Stage 0 was framed by the arc document itself. -- **Scope of THIS branch: 1-pre only — the input seam. No behaviour - change.** `App::window_event` was **655 lines** and is now **four** — - call `dispatch_window_event`, exit if it asks. The dispatch it calls - is one `route_event` call and one arm per route. Nothing below it - could be witnessed without a display, which is why the seam precedes - every other slice. -- **IMPLEMENTED in four commits, one per event family**, so each lands - with its own witnesses and mutations rather than as one 600-line - diff: `014110f` lifecycle (close / modifiers / resize), `7f0f9db` - redraw, `0705564` keyboard, `e955645` the four pointer arms. Review - round 1 added `f976dc1`, the P2 effect harness. -- **P2 HAS TWO HARNESSES, and the second was review round 1's blocker.** - The routing harness answers *where did this event go*; `EffectHarness` - answers *what did it do*. Classification alone could not satisfy P2 — - **a wheel route carries a delta, and whether that becomes a viewport - update, a panel event, a terminal event or nothing depends on - `State`.** The effect harness drives a real `AttachClient` over a - `socketpair` (real handshake, outbox, writer thread and encoder, so - the transcript is the wire), a real windowless `State`, and - `App::dispatch_window_event`. -- **`App::dispatch_window_event` is what made P2 reachable.** Left inside - `window_event`, the dispatch would force the harness to re-implement - it, and a harness that re-implements what it tests witnesses its own - copy. `window_event` is now **four lines**, so **P3 shrinks from a - 33-line match to a single `if`**. -- **Steps are delimited by a non-coalesceable sentinel key, not a - sleep** — otherwise "this step sent nothing" is undecidable without - waiting, and a fixed-duration wait against a writer thread is exactly - the core-count assumption behind PR #235's CI red. -- **The effect rows never skip**: a missing wgpu adapter is an assertion - failure. M21 confirms all **nine** effect rows fail loudly while the - **thirteen** GPU-free routing rows stay green. The assert is - **unconditional**, not `PMACS_REQUIRE_GPU`-gated, so no invocation - anywhere can turn a missing adapter into a quiet `ok`. -- **They execute in exactly ONE CI job, and that is checked rather than - assumed.** `cargo metadata` reports `workspace_default_members` as the - root `pmacs` package alone, so the `test` matrix and `crdt-test` — - both bare `cargo test --all-targets` — never compile `pmacs-gpu`'s - unit tests at all. Only **`gpu-render`** runs them, and it installs - lavapipe, proves the adapter with `vulkaninfo`, and sets - `PMACS_REQUIRE_GPU=1`. This is the handoff's "`gpu-render` runs a - DIFFERENT PACKAGE" fact showing up as a dependency: these rows live or - die with that one job. -- **Three manufactured absences, all found by running the rows**, and - each the same shape: the harness withheld something production - supplies, then witnessed its own omission. `resumed` sets the frontend - id and session version before any geometry flush (the resize row); - the fixture document was two lines and could not scroll; a headless - `State` has no attached buffer, so `scroll_by_lines` returned `None`. - A fourth was a vacuous assertion — `.all(|e| matches!(..))` over an - empty transcript is true — caught by the outbound-blind mutation. -- **The shape.** Deciding is `route_event(&WindowEvent) -> Route`, a - free function composing one decision function per family - (`route_lifecycle`, `route_keyboard` + `route_key_action`, - `route_pointer`). Performing stays on `App` in seven `apply_*` - methods. A route carries the **decision**, not the effect: a wheel - route holds a delta, and whether that becomes a viewport update, a - panel event, a terminal event or nothing depends on `State`. Effects - are witnessed separately — see the P2 bullet below. -- **Every moved body verified as the original, mechanically.** The - keyboard body is byte-identical modulo two named conversions; the four - pointer bodies were checked by re-running rustfmt on the pre-move text - at the new indent level and diffing, since de-indenting by 8 columns - lets rustfmt rejoin lines. **22 witnesses — 13 routing, 9 effect — and - 24 mutations, M1–M24.** Twenty-three fail their own rows; **M6 is the - P3 exception check and must stay green**. -- **P3 IS NOW MEASURED, NOT ASSUMED — and re-measured after the effect - harness landed.** Replacing `window_event`'s whole body with `let _ = - (event_loop, event);` — a GUI that responds to no input at all — - leaves **all 265 `pmacs-gpu` tests green** under `PMACS_REQUIRE_GPU=1` - at the current shape (it was 256 before the effect rows; the number is - re-run, not carried forward). That is the exception's true extent: - `ActiveEventLoop` cannot exist outside a live event loop, so **no** - headless test in the crate observes the delegation. What it covers is - now **one `if`**, not a 33-line match. -- **A SECOND ACCEPTED STRUCTURAL EXCEPTION, found here and winit's - rather than ours.** `KeyEvent` carries a `pub(crate) - platform_specific` field, so **no `WindowEvent::KeyboardInput` can be - constructed outside winit** and the keyboard family's routing arm - cannot be fed by a test. Bounded three ways: it does **not** extend to - the pointer families (`DeviceId::dummy()` exists for exactly this, and - all three pointer events are constructible — checked before writing - the exception down); the family's only real decision is factored into - `route_key_action(ElementState)` and witnessed directly; and what - stays unwitnessed is one pattern arm containing a match and a call. -- **The crate now has exactly ONE executable `event_loop.exit()`**, in - `window_event`. Bodies return an `EventOutcome` rather than taking an - `&ActiveEventLoop`, which is what keeps them reachable in principle. - **`EventOutcome` has TWO producers and they differ in kind**: a native - close (`LifecycleRoute::Exit`), which must always exit, and - `apply_keyboard`'s idle Escape, which is a local quit. **Stage 1a's A4 - removes the keyboard producer only**, leaving **one** `Exit` - producer — the native close. **One producer is not one variant**: - `EventOutcome` survives because `dispatch_window_event` must still - distinguish `Continue` from `Exit` on every event, and only the close - exits. A4 changes `apply_keyboard`'s signature, not the type. An - earlier revision of this bullet claimed the type would collapse and - should go with the Escape branch; that was wrong. -- **Slice order (each its own branch and PR):** `1-pre` → `1a`\* → `1b` - → `1c` → `1d` → `1e`\*. **`1a` and `1e` are protocol-bearing (v24 - `TextInput`, v25 `OpenTarget`/`OpenTargetResult`) and are - SERIALIZED.** 1c is **not** protocol-bearing under Q#S1-8. -- **Q#S1-7 obligation carried by THIS PR:** Meta/Super policy moves to - Stage 2, so the arc framing's §2.5 and the standing backlog are - amended here. Stage 1 keeps the deliberate OS reservation and adds no - island. -- **Gates:** `./scripts/gate --acceptance gpu_invocation_acceptance`. - That one invocation already runs `PMACS_REQUIRE_GPU=1 cargo test -p - pmacs-gpu` (step `gpu`) and the full `--workspace --no-fail-fast` - sweep in both feature configurations, so the framing §11 phrase "plus - touched input suites" is satisfied by the sweep rather than by a - hand-picked list. **No `--protocol`** — 1-pre changes no wire. -- **THE FIRST GATE RUN WENT RED ON A STRAY `/tmp/.git`, NOT ON THIS - BRANCH.** `m4` and the sweep failed - `m4_24_bare_string_glob_stays_relative` and - `m4_24_d3_fallback_base_is_the_smallest_attachment_dir` — two LSP - file-watcher tests — with every other target green. Established as - environmental three ways, in increasing strength: - - **Structurally impossible for this branch to cause.** The branch - changes seven files, five of them under `docs/`; **the whole - executable diff is inside the `pmacs-gpu` crate** - (`src/main.rs` and `src/attach.rs`), and `pmacs-gpu` is a workspace - **member but not a dependency** of the root package, so the - `m4_acceptance` binary never links it. - - **The marker is older than the session.** `/tmp/.git` is empty and - was created at 20:14 CEST, **3.5 h before** the gate run at 23:45; - `/tmp` held 8,920 entries. That is handoff §1's recorded hazard - exactly. - - **A discriminating pair compared on SIGNATURE, not test name**, same - binary and commit, one variable — run as **four literal `--exact` - invocations, one test each**, since `m4_24_` is a prefix matching - **18** tests. Contaminated: `0 passed; 1 failed` each, panicking at - `m4_acceptance.rs:5668:5` and `:6615:5` with `.received = ""`, - **matching the gate red's own signature**. Clean: `1 passed; 0 - failed` each, **zero panics**. The exact commands are in handoff - §1's hazard bullet. A rerun would have established only - intermittence; the pair establishes the cause. + after eight rejected revisions. It is Stage 1's framing for **all** + slices and governs every later branch; only Stage 0 was framed by the + arc document itself. Revision 9 is the approved design; 10 recorded a + scope correction found against the 1-pre implementation; **11 retracts + 10's claim that P2 was satisfied by route classification alone**, and + corrects the Stage 1a consequence 10 got wrong. +- **Slice order, each its own branch and PR:** ~~`1-pre`~~ → **`1a`**\* → + `1b` → `1c` → `1d` → `1e`\*. **`1a` and `1e` are the two + protocol-bearing slices — v24 `TextInput` and v25 + `OpenTarget`/`OpenTargetResult` — and they are SERIALIZED** against + each other and against every other wire change in the project. 1c is + **not** protocol-bearing, under Q#S1-8. +- **NEXT: 1a, and nothing of it exists yet** — no branch, no code. It + carries the **v24** `TextInput` variant, so it must run alone. + `PROTOCOL_VERSION` is **23** at this base, and + `ADVERTISED_PROTOCOL_VERSION` stays pinned at 20 and must not be + edited to chase it. Its nine contracts (A1–A9) and the Q#S1-9 + precedence rules are in the framing; **A4 deletes the idle-Escape + local quit**, which is the one 1-pre change 1a is expected to undo. - **`scripts/gate` isolates the target dir and five ambient roots but - NOT `TMPDIR`** — recorded in handoff §1, where the standing fix is - assigned to the gate lane rather than to this PR. +### What 1-pre landed, and the facts worth not re-deriving + +- **`App::window_event` went from 655 lines to four**: call + `dispatch_window_event`, exit if it asks. Deciding is + `route_event(&WindowEvent) -> Route`, composing one decision function + per family; performing is seven `apply_*` methods. **No behaviour + change, no wire change.** +- **A route carries the DECISION, not the effect.** A wheel route holds + a delta; whether that becomes a viewport update, a panel event, a + terminal event or nothing depends on `State`. This is why P2 needs a + second harness, and why revision 10's contrary argument was retracted. +- **Two harnesses.** `RoutingHarness` answers *where did this event go* + (13 rows, no GPU). `EffectHarness` answers *what did it do* (9 rows) — + a real `AttachClient` over a `socketpair` through the real handshake, + outbox, writer thread and encoder, a real windowless `State`, and the + production dispatch. **22 witnesses, 24 mutations M1–M24**; + twenty-three fail their own rows and **M6 is the P3 exception check, + which must stay green**. +- **`dispatch_window_event` is why P2 was reachable at all.** Left inside + `window_event`, the dispatch would force a harness to re-implement it, + and a harness that re-implements what it tests witnesses its own copy. +- **The sentinel is the success condition; the 30 s read ceiling is only + an error ceiling.** Steps are delimited by a non-coalesceable sentinel + key rather than a sleep, so absence is never inferred from duration — + but an unbounded blocking read would wedge the gate instead of + reddening it, and a hang looks like slowness until the job is killed. +- **TWO ACCEPTED STRUCTURAL EXCEPTIONS, both measured rather than + asserted.** **P3**: deleting `window_event`'s whole body leaves all + **265** `pmacs-gpu` tests green, so no headless test in the crate + observes the delegation — what it covers is now one `if`. **P1, + keyboard only, and winit's rather than ours**: `KeyEvent` carries a + `pub(crate) platform_specific` field, so **no + `WindowEvent::KeyboardInput` can be constructed outside winit**. It + does **not** reach the pointer families — `DeviceId::dummy()` exists + for exactly this and all three pointer events are constructible, + checked before the exception was written down. +- **`EventOutcome` survives A4, and one producer is not one variant.** + The crate has **exactly one** executable `event_loop.exit()`, in + `window_event`. A4 removes the keyboard `Exit` producer, leaving the + native close; the type stays because `dispatch_window_event` must + still distinguish `Continue` from `Exit` on every event. What A4 + changes is `apply_keyboard`'s signature. +- **The effect rows execute in exactly ONE CI job**, checked with `cargo + metadata`: `workspace_default_members` is the root `pmacs` package + alone, so the `test` matrix and `crdt-test` — both bare `cargo test + --all-targets` — never compile `pmacs-gpu`'s unit tests. Only + **`gpu-render`** runs them, with lavapipe, `vulkaninfo` and + `PMACS_REQUIRE_GPU=1`. The harness's adapter assert is + **unconditional**, so a missing adapter can never become a quiet `ok`. +- **A stray `/tmp/.git` reddened the first gate run and had nothing to do + with this branch.** Established on signature, not test name, by four + literal `--exact` invocations; the marker was left in place and an + isolated `TMPDIR` used instead. **`scripts/gate` does not isolate + `TMPDIR`** — recorded in `docs/agent-handoff.md` §1, where the + standing fix is assigned to the gate lane. - **The marker was left in place**: it is foreign, deleting it is - unnecessary, and the isolated `TMPDIR` is the correct remedy. It must - be **outside `/tmp` and outside every git worktree** — a child of - `/tmp` is not isolated, because `/tmp/.git` remains its ancestor. -- **GREEN under an isolated `TMPDIR`: all nine gates pass on the final - EXECUTABLE tree** (log `20260812T090034Z-2989598`, review round 2) — - executable, not final, because prose and doc comments changed after - it, as the sentence below records. fmt, clippy, - lib, lib-crdt, `gpu_invocation_acceptance`, **m4 168/0/3**, - `PMACS_REQUIRE_GPU=1 -p pmacs-gpu` (**265 tests, none filtered and - none skipped**, all nine effect rows included), the **117-target - `--workspace --no-fail-fast` sweep with zero failures anywhere** - (`m4_acceptance` running all 171 in it), and `diff-check`. Earlier - full-green runs at `20260811T215605Z-2664352` (round 1) and - `20260812T083735Z-2869707` (the P2 harness) are superseded by this - one. **What changed after it is doc comments and prose only** — the - `EventOutcome` correction below and this paragraph; `cargo fmt - --check`, `clippy -D warnings` and the 22 routing/effect rows were - re-run on the result. Stated rather than glossed, because "the gate - was green" and "the gate was green on exactly this tree" are - different claims. ## The GUI arc — Stage 0 MERGED as #236 (`f8ad3e7`) diff --git a/docs/agent-handoff.md b/docs/agent-handoff.md index 281aac7..64e3ed6 100644 --- a/docs/agent-handoff.md +++ b/docs/agent-handoff.md @@ -1,6 +1,15 @@ # Agent handoff — cross-machine continuity -**Last updated: 2026-08-11 (second pass, same day).** `main` is +**Last updated: 2026-08-12.** `main` is **`d038f71`** — **#237**, GUI +arc **Stage 1-pre**, the input seam: `App::window_event` goes from 655 +lines to four, deciding moves to a pure `route_event` and performing to +seven `apply_*` methods. **No behaviour change and no wire change** — +it is the seam the five behavioural slices land on, and **1a is next +and not started**. Beneath it `f8ad3e7` — **#236**, GUI arc **Stage +0**, the arc framing and its documentation sweep. **Both are absorbed +into §1 at this anchor.** + +Previously **2026-08-11 (second pass)**: `main` was **`122b8e8`** — **#235**, D3 of the LSP file watcher, which **closes issue #233 and completes that arc**: the watcher stops sleeping and walks once per scan, zero jobs at idle. Beneath it `b867f64` — git @@ -102,8 +111,66 @@ reads it the way you just did. For volatile branches, checkpoints, verification, and recovery commands, read `docs/active-work.md` immediately after this file. -## 1. Where the project stands (2026-08-11) +## 1. Where the project stands (2026-08-12) +- **GUI arc — Stage 0 MERGED as #236, Stage 1-pre MERGED as #237 + (2026-08-12). The arc is OPEN: five Stage 1 slices remain and 1a has + not started.** Stage 0 framed the arc + (`docs/gui-arc-framing.md`); Stage 1 is framed for **all** its slices + by `docs/gui-stage1-input-framing.md` (revision 11). 1-pre is the + input seam and changes **no behaviour and no wire**: + `App::window_event` went from 655 lines to four. Durable facts: + - **A route carries the DECISION; only running the body gives the + EFFECT.** A wheel route holds a delta, and whether that becomes a + viewport update, a panel event, a terminal event or nothing at all + depends on `State`. An approved evidence contract asked for + "outbound events **and** local effects", and a first implementation + argued route-classification covered both. It does not, and framing + revision 11 retracts the argument. **When a contract names two + things, satisfying one and arguing it implies the other is a + narrowing wearing the costume of a mechanism.** + - **A harness that re-implements the thing it tests witnesses its own + copy.** The dispatch had to leave `window_event` — which cannot be + driven, since `ActiveEventLoop` does not exist outside a live event + loop — and become `App::dispatch_window_event` before any effect + could be observed. That single extraction is what made the evidence + possible, and it shrank the untestable residue to one `if`. + - **Winit's `KeyEvent` cannot be constructed outside winit** — a + `pub(crate) platform_specific` field — so **no + `WindowEvent::KeyboardInput` can be built by a test**. This will + bind every future GUI input slice. It does **not** extend to the + pointer families: `DeviceId::dummy()` exists for exactly this + purpose and `CursorMoved` / `MouseInput` / `MouseWheel` are + constructible. Bound an exception by checking its edges before + writing it down. + - **The sentinel is the success condition; the timeout is only an + error ceiling**, and conflating them undoes the design. Absence is + decided by a non-coalesceable sentinel rather than a duration, so + the harness is insensitive to core count — but an unbounded blocking + read turns a downstream regression into a **wedged gate** instead of + a red one, and a hang reads as slowness until the job is killed. + - **Four defects in the tests themselves, all one shape: witnessing an + absence the harness had manufactured.** It skipped the post-connect + wiring `resumed` performs, so geometry was silently withheld; the + fixture was too short to scroll; a windowless `State` has no + attached buffer, so viewport sends were withheld; and + `.all(|e| matches!(..))` over an **empty** transcript is vacuously + true. **Before believing a green row, ask what the harness withheld + that production supplies.** + - **`cargo metadata` decides which CI job runs a member's unit + tests, not intuition.** `workspace_default_members` is the root + package alone, so every bare `cargo test --all-targets` skips + `pmacs-gpu` entirely; only `gpu-render` runs it. A GPU-dependent + assert is therefore **unconditional** rather than + `PMACS_REQUIRE_GPU`-gated, so a missing adapter can never become a + quiet `ok`. + - **Deliberately unbuilt here**: every behavioural change. 1a + (`TextInput`, **v24**, protocol-bearing) is next and serialized + against 1e (`OpenTarget`, **v25**); **A4 deletes 1-pre's + idle-Escape local quit**, which is the one thing 1-pre added that a + later slice removes. `EventOutcome` nevertheless **survives** A4: + the native close still returns `Exit`, and **one producer is not one + variant**. - **Git integration Stage 1 — MERGED as #227 (2026-08-11).** `*git-status*` (a `listview` panel over `git --no-optional-locks -C status --porcelain=v2 --branch -z`) and `*git-diff*` @@ -620,15 +687,20 @@ commands, read `docs/active-work.md` immediately after this file. **Read this before picking anything up.** It is the only place the remaining work is enumerated in one view; the per-arc bullets below give -the detail. Nothing here is in flight: **zero PRs are open** at this -anchor, so every item is startable. +the detail. **The table is current at `d038f71` (2026-08-12); the rows +beneath it that carry no GUI-arc mention date from 2026-08-01** and +were written before that arc existed. Zero PRs were open when this +section was first written; the GUI row is the only one refreshed since, +so treat the others as of that date and check `git log` before believing +any of them is still startable. #### Arc state, against `COHERENCE.md` §20's priority order | P | Arc | State | What is next | |---|---|---|---| | 1 | **Journey** | **Stage 1 COMPLETE** (1a #182/#183; 1b-1 #203, 1b-2 #204, 1b-3 #205) | Journey runs to step 10. The thin end is now steps **1** (install — that is P8), **11** (background work: visible but no ownership model, §9) and **12** (session restore: desktop-save is opt-in *and* a documented no-op under a daemon) | -| 2 | Workspace + location | Missing; model gap | The long-lead arc. Start before a fifth subsystem grows its own root convention — four have already diverged (§7) | +| 1.5 | **GUI arc (half A)** | **Stage 0 MERGED (#236); Stage 1-pre MERGED (#237)** | **`COHERENCE.md` §20 Q#GA5 slots half A immediately after Priority 1** and it runs alongside P2–P5, interacting only at P2 — *reaching Stage 4b is a P2 START GATE*. It is the product half of §16 and what that section's product subgrade is graded against. **Next: Stage 1a**, not started, protocol-bearing at **v24** and serialized against 1e's v25 | +| 2 | Workspace + location | Missing; model gap | The long-lead arc. Start before a fifth subsystem grows its own root convention — four have already diverged (§7). **Gated by the GUI arc reaching Stage 4b** (Q#GA5) | | 3 | Extension ownership | Missing; prerequisite-shaped | **`pmacs.hook.remove` does not exist.** That one bug-sized gap blocks §13's disable/uninstall, §10's trust classes, and package-scoped cancellation | | 4 | **Discovery** | **Stage 1 MERGED (#207)** | Stage 2 candidates, in rough dependency order: richer M-x rows (**protocol change** — `MinibufferPrompt.candidates` is `Vec`; `CompletionPopupRow` already proves the pattern), `Command` gaining title/category/aliases/flags/arg-schema (~147 definition sites), predicate evaluation, help-layer unification, and the help-prefix decision | | 5 | Workbench convergence | Partial; **Arc 7 COMPLETE** (#213) and **the tree primitive is implemented** (PR held) | The bottom panel is finished on both frontends and the adopter default is flipped. The tree primitive has landed on a held PR: §14's Tree moves ✗ → ◐ with the LSP outline as its one adopter. **Next: adoption** — dired's `i`, then DAP's variables view, which is why it was built first | From 08d970c40dd65298015101d09c0a8ed66dc20894 Mon Sep 17 00:00:00 2001 From: Levi Neuwirth Date: Wed, 12 Aug 2026 13:21:20 +0200 Subject: [PATCH 2/5] docs: give the absorption PR its own lane, with the gate result This file's standing rule is 'when a PR is opened, give it a lane', and the correction behind that rule --- #171 drifted 153 commits while invisible here --- applies to a docs PR as much as a code one. Written with the branch's own commit rather than after the fact, which is also what keeps a lane from re-conflicting on every other merge. Records the eight-stage gate result, states the docs-only scope as something verified with `git diff --name-only` rather than intended, and notes that the lane is REMOVED at merge: it describes a docs pass, not an arc, so rule 4 takes it outright instead of rewriting it. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai --- docs/active-work.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/docs/active-work.md b/docs/active-work.md index 9f8a7ee..dc13f0f 100644 --- a/docs/active-work.md +++ b/docs/active-work.md @@ -266,6 +266,43 @@ hazard in a shape that looks committed. **A documented error message that never appears is worse than no documentation**, because the reader waits for a signal that is not coming. +## Docs absorption of #236 and #237 — branch OPEN, docs only + +**Written with the branch's own commit**, because this file's standing +rule is *when a PR is opened, give it a lane* — and a lane recording an +absorption belongs in the absorption, not after it. #171 drifted 153 +commits while invisible here. + +- **Branch `docs-absorb-237`**, base `githubsucks/main` @ `d038f71` + exactly. **`githubsucks/docs-absorb-237` is the authoritative tip** — + the ref, not a SHA. +- **Scope: `docs/active-work.md` and `docs/agent-handoff.md` only.** No + `src/`, no `pmacs-gpu/`, **no Stage 1a implementation** — verified with + `git diff --name-only githubsucks/main`, which lists nothing outside + `docs/`. +- **The recovery procedure was RE-RUN from an empty directory on git + 2.55.0, not SHA-swapped**, and that is what licenses advancing the + base at all. It also **discharges the obligation left at `e67ad07`**, + where the base moved without the procedure being exercised. Details in + "Repository authority" above; the floor check was run against **both** + floors, and the documented two-argument worktree trap was reproduced + rather than assumed. +- **Gates: `./scripts/gate`, all eight stages green** (log + `20260812T111504Z-3265400`). No `--acceptance` and no `--protocol` — + docs only, so no suite is touched and no wire moves. That run covered + `502308d`; **the only later commit is this lane**, 34 lines of + markdown, with `git diff --check` and `cargo fmt --check` re-run clean + on the result. +- **One judgement recorded because it exceeded the requested scope and + was approved on review**: §1a's board carried no GUI-arc row, which + contradicted the anchor two sections above it. The row sits where + `COHERENCE.md` §20 Q#GA5 puts the arc — after Priority 1, alongside + P2–P5, interacting only at the **P2 start gate** — and the section's + dateline now says which row is current and which are as of + 2026-08-01. +- **This lane goes when the PR merges.** It describes a docs pass, not + an arc, so rule 4 removes it outright rather than rewriting it. + ## GUI arc Stage 1 — 1-pre MERGED as #237 (`d038f71`); 1a is next, NOT STARTED **The lane is rewritten, not removed.** Rule 4 removes a lane when its From 74054bb7ffd0da23611d48068dd9abf0bb083b5c Mon Sep 17 00:00:00 2001 From: Levi Neuwirth Date: Wed, 12 Aug 2026 13:23:05 +0200 Subject: [PATCH 3/5] docs: record PR #238 in the absorption lane The number goes in the moment the PR opens, per this file's own rule. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai --- docs/active-work.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/active-work.md b/docs/active-work.md index dc13f0f..e570cbf 100644 --- a/docs/active-work.md +++ b/docs/active-work.md @@ -266,13 +266,14 @@ hazard in a shape that looks committed. **A documented error message that never appears is worse than no documentation**, because the reader waits for a signal that is not coming. -## Docs absorption of #236 and #237 — branch OPEN, docs only +## Docs absorption of #236 and #237 — PR #238 OPEN, docs only **Written with the branch's own commit**, because this file's standing rule is *when a PR is opened, give it a lane* — and a lane recording an absorption belongs in the absorption, not after it. #171 drifted 153 commits while invisible here. +- **PR #238** — https://github.com/levineuwirth/pmacs/pull/238. - **Branch `docs-absorb-237`**, base `githubsucks/main` @ `d038f71` exactly. **`githubsucks/docs-absorb-237` is the authoritative tip** — the ref, not a SHA. From 6d6942e0688c61af7180f8fd49d579b2ee14cf7a Mon Sep 17 00:00:00 2001 From: Levi Neuwirth Date: Wed, 12 Aug 2026 13:32:40 +0200 Subject: [PATCH 4/5] docs: absorption review round 1 --- seven findings, two of them absorption holes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **The absorption was incomplete, and the two holes were Stage 0's.** `docs/agent-handoff.md` §6 still called Stage 0 "READY FOR PR (not yet opened)" and the ledger's Stage 0 lane still handed out branch-recovery instructions and called itself pre-PR --- for work that merged as #236. A merged lane that still says "checkout the branch" sends a reader to a tip that no longer moves. Both rewritten; the recovery lines are removed rather than updated, because there is nothing left to recover. **A LANE CANNOT REMOVE ITSELF AT MERGE, and saying so was wrong in a way that would have shipped.** GitHub merges the tree as it stands, so "removed at merge" would have landed the words *PR #238 OPEN* on `main` --- a lane advertising an open PR that closed in the same commit. It stays while the PR is under review, because an open PR without a lane is the #171 defect, and **a final pre-merge commit on this branch takes it out**. That obligation is now written into the lane itself. **Q#GA5 was recorded backwards.** The P2 row said P2 was "gated by the GUI arc reaching Stage 4b". The ruling is the reverse: **P2 is blocked by nothing and may start now**; when the arc reaches Stage 4b, P2 must already have started, and **no later GUI stage begins** until it has an approved framing and an opened lane. The gate is on STARTING P2, not on finishing it, and it binds the GUI arc rather than P2. Corrected in both the P2 row and the GUI row, which had inherited the same inversion. **`9a26ac8` was the previous last-EXERCISED anchor, not the previous declared FLOOR** --- that was `e67ad07`, and the two had drifted apart. Checking the exercised anchor in the floor's place verifies the wrong claim, so the check is re-run and re-stated against `e67ad07` and `d038f71`; `9a26ac8` is retained only under its own correct label. **1-pre did not ADD the idle-Escape local quit.** The docs said "no behaviour change" and then called the Escape quit a "1-pre change" and "the one thing 1-pre added" --- which contradict each other and the diff. It is **pre-existing behaviour that 1-pre preserved and isolated** behind an `EventOutcome` return; **1a removes it**. Fixed in both files. **§1a called the board current at `d038f71` while most of it dates from 2026-08-01**, and P5 still described #217 as a held PR although it had merged. The board is now labelled **MIXED-ANCHOR and explicitly not current as a whole**, with the drift named as evidence and a pointer to `git log --first-parent`; the P5 row is corrected. Refreshing the rest is a separate pass, deliberately not folded into a GUI absorption. **The exact-head accounting was wrong --- one commit and 34 lines, when it was two and 38 --- and the fix is to stop counting.** A count goes stale on the very next commit, including the one carrying the fix, which is how it broke in the first place. Both the lane and the PR body now state the standing property instead: every commit after the gated tree is markdown-only, checkable with `git diff --name-only 502308d..HEAD`. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai --- docs/active-work.md | 52 +++++++++++++++++++++++++++---------------- docs/agent-handoff.md | 34 +++++++++++++++++----------- 2 files changed, 54 insertions(+), 32 deletions(-) diff --git a/docs/active-work.md b/docs/active-work.md index e570cbf..f6ae35d 100644 --- a/docs/active-work.md +++ b/docs/active-work.md @@ -238,9 +238,13 @@ Every documented step ran, in order, on git **2.55.0**: `No such remote`**, exactly as the section above anticipates. 2. Add the alias, confirm the URL, `git fetch githubsucks --prune`. 3. `git log -1 --oneline githubsucks/main` → `d038f71`. -4. **The floor check, run against both floors**: `9a26ac8` (the old one) - and `d038f71` are each an ancestor of the tip, so advancing the floor - is valid rather than merely plausible. +4. **The floor check, run against the OLD DECLARED FLOOR and the new + one**: `e67ad07` and `d038f71` are each an ancestor of the tip, so + advancing the floor is valid rather than merely plausible. + *(`9a26ac8` is the previous last-EXERCISED anchor, which is a + different thing from the previous declared floor — the two had + drifted apart, and checking the exercised anchor in the floor's place + would have verified the wrong claim.)* 5. The three-argument `git worktree add -b githubsucks/` form → a real branch with its upstream set (`## recovered-local...githubsucks/gui-stage1-pre`). @@ -291,9 +295,13 @@ commits while invisible here. - **Gates: `./scripts/gate`, all eight stages green** (log `20260812T111504Z-3265400`). No `--acceptance` and no `--protocol` — docs only, so no suite is touched and no wire moves. That run covered - `502308d`; **the only later commit is this lane**, 34 lines of - markdown, with `git diff --check` and `cargo fmt --check` re-run clean - on the result. + `502308d`. **Every commit after it is markdown-only** — stated as a + standing property rather than a count, because a count goes stale on + the next commit, which is how the previous version of this sentence + came to say "one commit, 34 lines" when there were two and 38. Check + it with `git diff --name-only 502308d..HEAD`, which must list nothing + outside `*.md`; `git diff --check` and `cargo fmt --check` are clean + at HEAD. - **One judgement recorded because it exceeded the requested scope and was approved on review**: §1a's board carried no GUI-arc row, which contradicted the anchor two sections above it. The row sits where @@ -301,8 +309,14 @@ commits while invisible here. P2–P5, interacting only at the **P2 start gate** — and the section's dateline now says which row is current and which are as of 2026-08-01. -- **This lane goes when the PR merges.** It describes a docs pass, not - an arc, so rule 4 removes it outright rather than rewriting it. +- **THIS LANE MUST BE DELETED BY A FINAL PRE-MERGE COMMIT ON THIS + BRANCH, and cannot remove itself at merge.** GitHub merges the tree as + it stands, so "removed at merge" would land the words *PR #238 OPEN* + on `main` — a lane advertising an open PR that closed in the same + commit. It stays while the PR is under review, because an open PR + without a lane is the #171 defect; the last commit before merge takes + it out. Rule 4 removes it **outright** rather than rewriting it: it + describes a docs pass, not an arc. ## GUI arc Stage 1 — 1-pre MERGED as #237 (`d038f71`); 1a is next, NOT STARTED @@ -328,7 +342,10 @@ ARC is done, and the arc is Stage 1 as a whole: **five slices remain**. `ADVERTISED_PROTOCOL_VERSION` stays pinned at 20 and must not be edited to chase it. Its nine contracts (A1–A9) and the Q#S1-9 precedence rules are in the framing; **A4 deletes the idle-Escape - local quit**, which is the one 1-pre change 1a is expected to undo. + local quit**, which is **pre-existing behaviour, not something 1-pre + introduced** — 1-pre preserved it and moved it behind an + `EventOutcome` return, and 1a removes it. `EventOutcome` survives that + removal: the native close still returns `Exit`. ### What 1-pre landed, and the facts worth not re-deriving @@ -406,24 +423,21 @@ absorption" was too generous. Five stale lanes remain below, and two `COHERENCE.md` corrections had not been made at all. What is done here is listed at the commit that does it, not promised here. -- **Branch `gui-arc-stage0`**, base `githubsucks/main` @ `e67ad07` (the - file-watcher arc absorption) after the 2026-08-11 rebase; it was - branched at `0e4c58d`. **`githubsucks/gui-arc-stage0` is the - authoritative tip** — the ref, not a SHA. Recover with - `git fetch githubsucks && git checkout gui-arc-stage0`. +- **MERGED as #236 (`f8ad3e7`).** The branch was `gui-arc-stage0`, based + on `e67ad07` after the 2026-08-11 rebase and branched at `0e4c58d`. + **Recovery instructions are removed deliberately**: a merged lane that + still says "checkout the branch" sends a reader to a tip that no + longer moves. Its content is on `main`. - **Framing `docs/gui-arc-framing.md`, revision 3, APPROVED 2026-08-10** after two review rounds (two blocking findings each round, closed). It is **also the framing for Stage 0 itself**, which is docs-only; Stages 1–10 each require their own framing before their branch. -- **The park is over and the work is DONE.** The branch was parked at +- **The park is over and the work is MERGED.** The branch was parked at its first commit until #227 merged, because #227 was 72 `main` commits behind and touched the three files Stage 0's absorption rewrites. #227 merged (`b867f64`), #233's arc closed (#234, #235), this branch - rebased onto `e67ad07`, and the absorption ran. **Sixteen commits - above the base as of `30e2209`; ready for its PR.** *(Anchored to a - SHA deliberately: a bare running count goes stale on the next commit, - which is the staleness class this lane exists to retire.)* + rebased onto `e67ad07`, the absorption ran, and it landed as **#236**. - **What landed (docs only, no `src/`):** the absorption pass enumerated in the framing's §5 — five stale lanes, the authority/recovery anchor, `COHERENCE.md`'s `v6..=v21` → `v6..=v23`, diff --git a/docs/agent-handoff.md b/docs/agent-handoff.md index 64e3ed6..84e71e6 100644 --- a/docs/agent-handoff.md +++ b/docs/agent-handoff.md @@ -166,9 +166,11 @@ commands, read `docs/active-work.md` immediately after this file. quiet `ok`. - **Deliberately unbuilt here**: every behavioural change. 1a (`TextInput`, **v24**, protocol-bearing) is next and serialized - against 1e (`OpenTarget`, **v25**); **A4 deletes 1-pre's - idle-Escape local quit**, which is the one thing 1-pre added that a - later slice removes. `EventOutcome` nevertheless **survives** A4: + against 1e (`OpenTarget`, **v25**); **A4 deletes the idle-Escape + local quit**, which is **pre-existing behaviour that 1-pre preserved + and isolated rather than introduced** — the seam moved it behind an + `EventOutcome` return, and 1a is what removes it. `EventOutcome` + nevertheless **survives** A4: the native close still returns `Exit`, and **one producer is not one variant**. - **Git integration Stage 1 — MERGED as #227 (2026-08-11).** @@ -687,23 +689,27 @@ commands, read `docs/active-work.md` immediately after this file. **Read this before picking anything up.** It is the only place the remaining work is enumerated in one view; the per-arc bullets below give -the detail. **The table is current at `d038f71` (2026-08-12); the rows -beneath it that carry no GUI-arc mention date from 2026-08-01** and -were written before that arc existed. Zero PRs were open when this -section was first written; the GUI row is the only one refreshed since, -so treat the others as of that date and check `git log` before believing -any of them is still startable. +the detail. + +**THIS TABLE IS MIXED-ANCHOR AND IS NOT CURRENT AS A WHOLE.** The GUI +row is written at `d038f71` (2026-08-12); **every other row dates from +2026-08-01** and has not been re-audited since, including the original +claim that zero PRs were open. Rows are known to have drifted — P5 +called the tree primitive "PR held" when **#217 had already merged** — +so **check `git log --first-parent githubsucks/main` before believing +any row is still startable**. Refreshing the rest of the board is a +separate pass, deliberately not folded into a GUI absorption. #### Arc state, against `COHERENCE.md` §20's priority order | P | Arc | State | What is next | |---|---|---|---| | 1 | **Journey** | **Stage 1 COMPLETE** (1a #182/#183; 1b-1 #203, 1b-2 #204, 1b-3 #205) | Journey runs to step 10. The thin end is now steps **1** (install — that is P8), **11** (background work: visible but no ownership model, §9) and **12** (session restore: desktop-save is opt-in *and* a documented no-op under a daemon) | -| 1.5 | **GUI arc (half A)** | **Stage 0 MERGED (#236); Stage 1-pre MERGED (#237)** | **`COHERENCE.md` §20 Q#GA5 slots half A immediately after Priority 1** and it runs alongside P2–P5, interacting only at P2 — *reaching Stage 4b is a P2 START GATE*. It is the product half of §16 and what that section's product subgrade is graded against. **Next: Stage 1a**, not started, protocol-bearing at **v24** and serialized against 1e's v25 | -| 2 | Workspace + location | Missing; model gap | The long-lead arc. Start before a fifth subsystem grows its own root convention — four have already diverged (§7). **Gated by the GUI arc reaching Stage 4b** (Q#GA5) | +| 1.5 | **GUI arc (half A)** | **Stage 0 MERGED (#236); Stage 1-pre MERGED (#237)** | **`COHERENCE.md` §20 Q#GA5 slots half A immediately after Priority 1** and it runs alongside P2–P5, interacting only at Q#GA5's start gate — **reaching Stage 4b obliges P2 to have STARTED, and no later GUI stage begins until it has an approved framing and an opened lane. The constraint binds THIS arc, not P2**, which is free to start at any time. It is the product half of §16 and what that section's product subgrade is graded against. **Next: Stage 1a**, not started, protocol-bearing at **v24** and serialized against 1e's v25 | +| 2 | Workspace + location | Missing; model gap | The long-lead arc. Start before a fifth subsystem grows its own root convention — four have already diverged (§7). **P2 is blocked by nothing and may start now.** Q#GA5 runs the other way: when the GUI arc reaches Stage 4b, **P2 must already have started**, and no later GUI stage begins until it has an approved framing and an opened lane. **The gate is on STARTING P2, not on finishing it** | | 3 | Extension ownership | Missing; prerequisite-shaped | **`pmacs.hook.remove` does not exist.** That one bug-sized gap blocks §13's disable/uninstall, §10's trust classes, and package-scoped cancellation | | 4 | **Discovery** | **Stage 1 MERGED (#207)** | Stage 2 candidates, in rough dependency order: richer M-x rows (**protocol change** — `MinibufferPrompt.candidates` is `Vec`; `CompletionPopupRow` already proves the pattern), `Command` gaining title/category/aliases/flags/arg-schema (~147 definition sites), predicate evaluation, help-layer unification, and the help-prefix decision | -| 5 | Workbench convergence | Partial; **Arc 7 COMPLETE** (#213) and **the tree primitive is implemented** (PR held) | The bottom panel is finished on both frontends and the adopter default is flipped. The tree primitive has landed on a held PR: §14's Tree moves ✗ → ◐ with the LSP outline as its one adopter. **Next: adoption** — dired's `i`, then DAP's variables view, which is why it was built first | +| 5 | Workbench convergence | Partial; **Arc 7 COMPLETE** (#213) and **the tree primitive MERGED as #217** | The bottom panel is finished on both frontends and the adopter default is flipped. §14's Tree moves ✗ → ◐ with the LSP outline as its one adopter. *(This row said "PR held" until 2026-08-12; #217 is in the canonical base chain.)* **Next: adoption** — dired's `i`, then DAP's variables view, which is why it was built first | | 6 | Config productization | Foundation only | Value provenance, then layering, then adoption migration (**table-valued settings are the hard prerequisite** — `ConfigValue` is four scalars) | | 7 | Package lifecycle | Not started | Correctly sequenced after P3 | | 8 | **Distribution** | **Stage 1 SHIPPED (v1.1.0, #211)** | Binaries on tag, checksums, machine-checked glibc floor. **Journey step 1 now works and the "invisible until this exists" blocker is lifted.** Next is a *decision* about channels / update / signing, not a queued plan | @@ -3329,7 +3335,9 @@ servers. ## 6. Named deferrals (the standing backlog, consolidated) -**The GUI arc — OPEN, framing approved 2026-08-10, Stage 0 READY FOR PR (not yet opened).** +**The GUI arc — OPEN. Stage 0 MERGED as #236 and Stage 1-pre MERGED as +#237 (2026-08-12); Stage 1a is next and not started.** See §1's arc +bullet for what landed. `docs/gui-arc-framing.md` is the arc-level frame and is also Stage 0's own framing; Stages 1–10 each need their own before their branch. It opened from a daily-driver report: the TUI is daily-drivable, the GUI is From 549e225505a38e8dcedf136ab356c6ca56ebfa9d Mon Sep 17 00:00:00 2001 From: Levi Neuwirth Date: Wed, 12 Aug 2026 13:54:26 +0200 Subject: [PATCH 5/5] docs: remove the #238 lane --- the promised final pre-merge commit The lane recorded this PR while it was under review, because an open PR without a lane is the #171 defect: it drifted 153 commits while invisible in the ledger. Review is done, so the lane goes. **It had to go in a commit rather than "at merge".** GitHub merges the tree as it stands, so leaving it would have landed the words *PR #238 OPEN* on `main` --- a lane advertising an open PR that closed in the same commit, which is the exact staleness class this absorption exists to clear. Rule 4 takes it **outright** rather than rewriting it: a lane is rewritten when its ARC survives its PR, and this one describes a docs pass with nothing left behind it. Every reference to #238 and to the `docs-absorb-237` branch lived inside the lane, so the deletion is self-contained and leaves no dangling pointer. What the lane recorded that outlives it is already elsewhere: the recovery rehearsal and its floor checks are in "Repository authority", and the GUI arc's state is in the Stage 1 lane and the handoff anchor. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_016bqGA6s9tTUFzYpbeW3tai --- docs/active-work.md | 48 --------------------------------------------- 1 file changed, 48 deletions(-) diff --git a/docs/active-work.md b/docs/active-work.md index f6ae35d..cbed93f 100644 --- a/docs/active-work.md +++ b/docs/active-work.md @@ -270,54 +270,6 @@ hazard in a shape that looks committed. **A documented error message that never appears is worse than no documentation**, because the reader waits for a signal that is not coming. -## Docs absorption of #236 and #237 — PR #238 OPEN, docs only - -**Written with the branch's own commit**, because this file's standing -rule is *when a PR is opened, give it a lane* — and a lane recording an -absorption belongs in the absorption, not after it. #171 drifted 153 -commits while invisible here. - -- **PR #238** — https://github.com/levineuwirth/pmacs/pull/238. -- **Branch `docs-absorb-237`**, base `githubsucks/main` @ `d038f71` - exactly. **`githubsucks/docs-absorb-237` is the authoritative tip** — - the ref, not a SHA. -- **Scope: `docs/active-work.md` and `docs/agent-handoff.md` only.** No - `src/`, no `pmacs-gpu/`, **no Stage 1a implementation** — verified with - `git diff --name-only githubsucks/main`, which lists nothing outside - `docs/`. -- **The recovery procedure was RE-RUN from an empty directory on git - 2.55.0, not SHA-swapped**, and that is what licenses advancing the - base at all. It also **discharges the obligation left at `e67ad07`**, - where the base moved without the procedure being exercised. Details in - "Repository authority" above; the floor check was run against **both** - floors, and the documented two-argument worktree trap was reproduced - rather than assumed. -- **Gates: `./scripts/gate`, all eight stages green** (log - `20260812T111504Z-3265400`). No `--acceptance` and no `--protocol` — - docs only, so no suite is touched and no wire moves. That run covered - `502308d`. **Every commit after it is markdown-only** — stated as a - standing property rather than a count, because a count goes stale on - the next commit, which is how the previous version of this sentence - came to say "one commit, 34 lines" when there were two and 38. Check - it with `git diff --name-only 502308d..HEAD`, which must list nothing - outside `*.md`; `git diff --check` and `cargo fmt --check` are clean - at HEAD. -- **One judgement recorded because it exceeded the requested scope and - was approved on review**: §1a's board carried no GUI-arc row, which - contradicted the anchor two sections above it. The row sits where - `COHERENCE.md` §20 Q#GA5 puts the arc — after Priority 1, alongside - P2–P5, interacting only at the **P2 start gate** — and the section's - dateline now says which row is current and which are as of - 2026-08-01. -- **THIS LANE MUST BE DELETED BY A FINAL PRE-MERGE COMMIT ON THIS - BRANCH, and cannot remove itself at merge.** GitHub merges the tree as - it stands, so "removed at merge" would land the words *PR #238 OPEN* - on `main` — a lane advertising an open PR that closed in the same - commit. It stays while the PR is under review, because an open PR - without a lane is the #171 defect; the last commit before merge takes - it out. Rule 4 removes it **outright** rather than rewriting it: it - describes a docs pass, not an arc. - ## GUI arc Stage 1 — 1-pre MERGED as #237 (`d038f71`); 1a is next, NOT STARTED **The lane is rewritten, not removed.** Rule 4 removes a lane when its