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 |