docs: give the tree lane its entry, and move Tree off ✗

Three updates, one of which was a broken cross-reference of my own
making.

THE DAEMON-LEAK ENTRY POINTED AT A LANE THAT DID NOT EXIST. It said the
unclassified failure was "recorded in the tree lane below"; this branch
had no tree lane. A pointer to nothing is worse than no pointer — it
reads as though the record exists and sends the next reader looking. The
tree lane is added, and since it now sits ABOVE that entry the direction
is corrected too, with a second pointer to the framing §6a where the
occurrence is recorded in full.

The lane carries branch, base, framing revision, every commit, the gate
table with both sweeps and their exact reconciliations, the bite
verification for both behavioural claims, the held-PR state and the
recovery command. It also names what is NOT in scope, because the four
unadopted §14 consumers and dired's `i` will otherwise read as omissions
from this stage rather than as later ones.

COHERENCE.md §14: Tree moves ✗ -> ◐, implemented with ONE consumer. Not
✓, and the row says why: the LSP outline is the only adopter, dired's
`i` remains the deferral in its §13, and the other four named consumers
have not adopted. The organising fact goes in the section rather than
only in the framing — folding is LOCAL PROJECTION STATE, NOT A REFRESH
PROTOCOL, which is why a consumer with no `on_refresh` can fold at all.
The §0 scorecard row moves with the body; a grade table disagreeing with
its own section is the defect this document keeps correcting in others.

The framing's status moves from "approved" to implemented-and-gated,
held for PR review, and four durable facts go to the handoff §1: folding
as projection state; identity being consumer-supplied and compared by
equality, with `line:col` chosen because the `::` parent chain collides
on overloads; `has_children` having to read the full row array rather
than the rendered subset, since a collapsed node's children are absent
from it by construction and the bug would look like fold working and
unfold silently not; and that a bite which passes validates the pair
rather than the test.

The daemon leak stays a separate reap-ledger candidate. It is not tree
scope, it predates this work, and folding it in would make a lane
responsible for a leak it did not cause.

Verified: fmt, diff-check, listview 21/21, --lib 1896/0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Levi Neuwirth 2026-08-05 16:50:29 +02:00
parent 8f64c3b2a1
commit 38e94dc33f
No known key found for this signature in database
4 changed files with 128 additions and 13 deletions

View File

@ -107,7 +107,7 @@ remain open to them.
| 11 | Config layering + provenance | **Partial (foundation only)** | Typed registry is right; 5 settings live in it; no value provenance |
| 12 | Profiles | **Missing** | One hardcoded default keymap; not a named concept |
| 13 | Package lifecycle UX | **Resolution without lifecycle** | Mature resolver/lockfile; init-only install; no uninstall/disable/search |
| 14 | Workbench primitives | **Partial (best trajectory)** | Listview is a real primitive but only **4** call sites, all LSP panels (`*lsp*` added post-audit by #204); buffer-list and search re-implement it; **the bottom panel is COMPLETE — both frontends, and Stage 3 flipped the adopter default so omission means the panel**. **Tree is still ✗ and is now the arc's successor** |
| 14 | Workbench primitives | **Partial (best trajectory)** | Listview is a real primitive but only **4** call sites, all LSP panels (`*lsp*` added post-audit by #204); buffer-list and search re-implement it; **the bottom panel is COMPLETE — both frontends, and Stage 3 flipped the adopter default so omission means the panel**. **Tree is implemented (◐) with the LSP outline as its one adopter; the remaining consumers, including dired's `i`, have not adopted** |
| 15 | Contextual affordances | **Weak** | Right-click menu only; code actions apply first-blindly; no git integration at all |
| 16 | Semantic frontend | **Strong** | v6..=v21 schema support; production attach remains v20 during the dark panel slice; degradation practiced |
| 17 | Distribution | **Partial** | **v1.1.0 ships prebuilt Linux/macOS binaries on tag** (#211) with checksums and a stated glibc floor. No channels, in-place update, rollback, signing, or package-manager distribution |
@ -1367,15 +1367,27 @@ Primitive-by-primitive against the list above:
(§9).
- **Help view** △ — exists twice (§5); needs unification, not
invention.
- **Tree** ✗ — none. The named future consumers (project files, symbol
hierarchy, package dependency graph, worker trees, git status) will
each need it; building it once *before* dired's directory view and
the workers tree harden their own conventions is exactly this
section's point. Dired Stage 1 (merged #165) landed **without** inventing
one: its listing is flat (Emacs parity), and the recursive
in-buffer case — `i` insert-subdirectory — is a named deferral in
`docs/dired-framing.md` §13, which is where a shared tree primitive
would land.
- **Tree** ◐ — **implemented, one consumer.** `listview` carries
optional `depth` and `id` on rows, primitive-owned collapse state, and
selection re-seated by id rather than by line; `TAB` toggles. Absent
`depth`/`id`, a row behaves exactly as before, which is what leaves
the flat consumers untouched (pinned by byte-identity coverage).
**The LSP outline is the only adopter**: it previously flattened a
genuine `DocumentSymbol` tree into indented strings, and now supplies
structure while keeping its rendered text.
The organising fact, worth carrying: **folding is local projection
state, not a refresh protocol.** Collapse only hides rows and never
changes a surviving row's depth, so the primitive re-renders from its
own array without calling the consumer — which is why the outline
works at all, having no `on_refresh`.
**Still one consumer, hence ◐ not ✓.** The named future consumers
(project files, package dependency graph, worker trees, git status)
have not adopted, and dired's recursive `i` insert-subdirectory — the
second real constraint source — remains the deferral in
`docs/dired-framing.md` §13. Dired Stage 1 (merged #165) landed
**without** inventing its own, which is what kept this possible.
- **Structured table / inspector / diff view** ✗ — none. (`describe.*`
tables are the inspector's data model without a view; the
wire-declared `ResourceOffer` family was reserved for diff/blame

View File

@ -161,6 +161,76 @@ form. All four steps ran clean. **The two-argument form still does not
work** for a remote-only branch (`fatal: invalid reference`), which is
why every lane below spells out the `-b` form.
## Tree primitive (P5) — IMPLEMENTED and GATED, PR HELD
**Held deliberately, not stalled.** The work is complete and green; the
PR is not open pending review of the documentation this lane records.
- **Branch `tree-primitive-framing`**, base `githubsucks/main` @
`12f2970`. **Unpushed** while held. Framing
`docs/tree-primitive-framing.md` **revision 5** — approved after four
review rounds, with Q#TR1TR4 decided.
- **Commits:** `61b1062` framing, `cf4ac1c` rev 2, `932b3ab` rev 3,
`5186bfd` rev 4 (carrying the `COHERENCE.md` §14 call-site
correction), `49a42ec` the primitive, `8f64c3b` byte-identity coverage
plus the verification record.
### What it ships
`listview` gains **optional** `depth` and `id` on rows; absent, a row
behaves exactly as before, which is what leaves the flat consumers
untouched. Collapse state is **primitive-owned**, keyed by
consumer-supplied id. Selection is re-seated **by id, not by line**.
`TAB` toggles; a leaf reports rather than silently doing nothing.
**The observation that made it cheap:** collapse only ever *hides* rows
and never changes a surviving row's depth, and consumers emit parents
before children, so descendants are a **contiguous run**. Folding is
therefore **local projection state, not a refresh protocol** — the
primitive re-renders from its own array without calling the consumer,
which is why the anchor consumer works at all: **the outline has no
`on_refresh`**.
The LSP outline adopts, supplying `depth` and `id = line:col`; its
`text` stays consumer-rendered per Q#TR4.
### Verification
| gate | result |
|---|---|
| luajit sweep | **3453 / 0** (= `main` 3450 + 3 listview tests) |
| crdt sweep, isolated ×2 | **3722 / 0** (= `main` 3718 + 4 tests) |
| `listview_acceptance` | 21 / 21 |
| `m4_acceptance` | 150 / 150 (basedpyright skipped) |
| `--lib` | 1896 / 0 |
| fmt · diff-check · clippy ±crdt | pass |
Both behavioural claims are **bite-verified**: disabling the ancestor
filter fails the fold test; an unconditional gutter fails the
byte-identity test.
**One unclassified occurrence** — the first crdt sweep reported 7
failures whose signatures were destroyed before being read. It is
recorded in the framing's §6a, **not** as a row in
`docs/ci-red-signatures.md`, because it has no normalized signature to
match. Two non-causal hypotheses are recorded there; neither is testable
now.
### Recovery, once pushed
```sh
git fetch githubsucks
git worktree add ../pmacs-tree \
-b tree-primitive-framing \
githubsucks/tree-primitive-framing
```
### Not in scope
dired's `i` insert-subdirectory (the second consumer, its own stage);
the other four §14 consumers; DAP's variables view; giving the outline a
refresh, which is LSP request-lifecycle work.
## Leaked daemons from `gpu_invocation_acceptance` — NEEDS A LANE
**Found 2026-08-05 while cleaning up after the tree-primitive work. No
@ -187,7 +257,8 @@ so **nothing in the existing ledger covers them**.
**Why it matters beyond tidiness.** Dozens of resident daemons were
present during every local sweep run this week, including the one that
produced the unclassified failure recorded in the tree lane below. That
produced the unclassified failure recorded in the **tree-primitive lane
above** (and, in full, in that lane's framing §6a). That
makes them a **rival explanation** to the shared-target-dir mechanism
for that occurrence, and neither can be tested against it now — the
signatures were not captured. A leak that quietly changes the

View File

@ -122,6 +122,36 @@ commands, read `docs/active-work.md` immediately after this file.
- **A capability fallback must strip the QUIT ACTION too**, not just
the side parameters — a quit action stranded on a document window
makes a later `q` try to restore a presentation that never happened.
- **The tree primitive ships — `listview` gained depth, collapse and
identity** (P5, §14's last missing workbench primitive; implemented,
PR held). Rows carry **optional** `depth` and `id`; absent, a row
behaves exactly as before, which is what leaves the flat consumers
untouched. The LSP outline is the one adopter. Durable facts:
- **Folding is local projection state, not a refresh protocol.**
Collapse only *hides* rows and never changes a surviving row's
depth, and consumers emit parents before children, so descendants
are a **contiguous run**. The primitive therefore re-renders from
its own array **without calling the consumer** — which is the only
reason the anchor consumer works, because **the outline has no
`on_refresh` at all**. A design requiring the consumer to re-supply
rows on every fold would have fitted no existing consumer.
- **Identity is consumer-supplied and compared by equality; the
primitive never derives one.** `item` is opaque by design. The
outline uses `line:col`, because the `::` parent chain collides on
overloads and same-named siblings — exactly where a stale expansion
would reattach to the wrong node. **Selection is re-seated by id,
not by line**, since a fold inserts or removes rows above the
cursor.
- **`has_children` must read the FULL row array, not the rendered
subset.** A collapsed node's children are absent from the rendered
map by construction, so asking the view would answer "no" for every
collapsed node and make expanding impossible — a self-sealing bug
that looks like fold working and unfold silently not.
- **A bite that passes validates the pair, not the test.** The first
byte-identity injection used `row.depth or 0`; flat rows have no
depth, so it changed nothing and the test "passed" against a
regression the flat path is immune to. Ask which defect you
injected before believing a green bite.
- **pmacs is installable without cloning — Distribution Stage 1, #211,
released as v1.1.0.** A `v*` tag builds `pmacs` and `pmacs-gpu` on
pinned `ubuntu-22.04` / `macos-15` and publishes a GitHub Release with
@ -226,7 +256,7 @@ anchor, so every item is startable.
| 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) |
| 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<String>`; `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** (Stage 3 merged, #213) | The bottom panel is finished on both frontends and the adopter default is flipped. **The tree primitive is now the arc's successor**`COHERENCE.md` §14 grades Tree ✗, and DAP's variables view is its next would-be inventor. Build it *before* dired's `i` and the worker tree invent two |
| 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 |
| 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 |

View File

@ -1,6 +1,8 @@
# Framing — the tree primitive
**Revision 5.** Status: **APPROVED; Q#TR1TR4 decided.** Scouted against
**Revision 5.** Status: **IMPLEMENTED and GATED; PR HELD for review.**
Q#TR1TR4 decided at approval. Both sweeps green and both behavioural
claims bite-verified — see §6a. Scouted against
`githubsucks/main` @ `12f2970`. Carries a correction to `COHERENCE.md`
§14 (revision 4, below).