From 513a7dfa58ffc87d7677a8c88f5da94764a9c27f Mon Sep 17 00:00:00 2001 From: Levi Neuwirth Date: Fri, 31 Jul 2026 18:28:35 -0400 Subject: [PATCH] docs(discovery): finalize Stage 1 framing review Correct the M-x prompt census: six of the eleven canonical commands need a second prompt, including describe-command. Make the apropos substring negative discriminate against fuzzy matching with a concrete non-contiguous fixture and a no-substring precondition. Update the help index mutation to the twelfth canonical command, and carry all three corrections into the active-work ledger. --- docs/active-work.md | 19 +++++--- ...discovery-stage1-command-family-framing.md | 44 ++++++++++++++----- 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/docs/active-work.md b/docs/active-work.md index 04805bd..7628388 100644 --- a/docs/active-work.md +++ b/docs/active-work.md @@ -380,14 +380,15 @@ which would have re-conflicted on every merge. githubsucks/journey-stage1b3-welcome ``` -## Discovery Stage 1 (P4) — FRAMING APPROVED (rev 5); implementation next +## Discovery Stage 1 (P4) — FRAMING APPROVED (rev 6); implementation next - **Branch `discovery-stage1-commands`**, worktree `../pmacs-p4-discovery`, based on `githubsucks/main` @ `54a092e`. **Framing only; no code, no - PR yet.** `docs/discovery-stage1-command-family-framing.md` revision 5, + PR yet.** `docs/discovery-stage1-command-family-framing.md` revision 6, three review rounds closed (round 1: two blocking, two major; round 2: two blocking, two major; round 3: two factual corrections; all - accepted), and **Q#D2 / Q#D3 decided by the user**. + accepted), Q#D2 / Q#D3 decided by the user, and the final review's + acceptance corrections applied. - **What it is.** `COHERENCE.md` §20 Priority 4 — "almost pure wiring, the best payoff-per-effort in this document". **Eleven commands under one `help.*` prefix**: nine new (describe-key/mode/hook/buffer, @@ -399,7 +400,10 @@ which would have re-conflicted on every merge. - **`apropos` matches by SUBSTRING, not fuzzy** (Q#D3). `fuzzy_score` is subsequence-based and descriptions are long sentences, so fuzzy would match nearly every command. Pinned by a - subsequence-that-is-not-a-substring finding nothing. + `test.apropos-subsequence-fixture` whose `qzjx` letters occur as `q z + j x`, only after asserting no registered name or description contains + `qzjx` as a substring; it must find nothing, whereas fuzzy finds the + fixture. - **It adds no Rust.** `pmacs.describe.*`, `pmacs.keymap.list()`, `pmacs.command.list()` and `pmacs.config.list()` already return everything needed, and `parse_completion_source` accepts a **Lua @@ -422,8 +426,11 @@ which would have re-conflicted on every merge. corrected, repeated one PR later. The path is dispatch `M-x` → `editor.execute-command` → assert the selected candidate **before** RET (`accept()` does `session.take()`) → accept → `invoke_interactive`. - Five of the nine commands open a **second** prompt the pins must drive - too; a pin that stops after the first RET has tested the palette. + Six of the eleven canonical commands (`help.describe-command`, + `help.describe-setting`, `help.describe-key`, `help.describe-hook`, + `help.where-is`, and `help.apropos`) open a **second** prompt the pins + must drive too; a pin that stops after the first RET has tested the + palette. - **One owner for `*help*` writes — NOT a one-site migration.** `src/help.rs` has semantic renderers for command/key/buffer/mode/ hook/view and **none for settings, lists or apropos**, and diff --git a/docs/discovery-stage1-command-family-framing.md b/docs/discovery-stage1-command-family-framing.md index 32349d1..fc6bd73 100644 --- a/docs/discovery-stage1-command-family-framing.md +++ b/docs/discovery-stage1-command-family-framing.md @@ -1,11 +1,28 @@ # Discovery Stage 1 — the describe/list command family -**Status: framing, rev 5 — Q#D2 and Q#D3 decided; ready for implementation approval.** +**Status: framing, rev 6 — final review corrections applied; ready for +implementation approval.** **Serves `COHERENCE.md` §5 (unify discoverability), §1.1 (substrate without surface), §20 Priority 4.** ## 0. Revision history +- rev 6 (2026-07-31) — final review corrections applied. + - **The second-prompt census now includes `help.describe-command`.** + Six of the eleven canonical commands take an argument, not five: + `describe-command`, `describe-setting`, `describe-key`, + `describe-hook`, `where-is`, and `apropos`. The full M-x driver must + accept each command's second prompt before it has tested the command. + - **The negative substring pin now has a discriminating fixture.** It + registers `test.apropos-subsequence-fixture` with a description whose + `qzjx` letters occur only as the non-contiguous sequence `q z j x`, then + first asserts that no registered command name or description contains + `qzjx` as a substring. `help.apropos qzjx` finding nothing therefore + fails under a fuzzy implementation rather than passing as an ordinary + no-match. + - **The index-property arithmetic follows the eleven-command family.** + Its targeted mutation is now adding a twelfth canonical command + without indexing it. - rev 5 (2026-07-31) — **Q#D2 and Q#D3 answered by the user**; no review findings at `1cc9d96`. - **Q#D2 → `help.*` is canonical, with two forwarders.** @@ -397,11 +414,11 @@ The pre-RET assertion is not decoration: `accept()` does `session.take()`, so afterwards nothing about the accepted value survives, and a selected candidate shadows typed text. -**Commands that take an argument open a SECOND prompt** (`where-is`, -`describe-key`, `describe-hook`, `describe-setting`, `apropos`). Those -pins drive that prompt too, and assert against it with the same -pre-accept discipline. A pin that stops after the first RET has tested -the palette, not the command. +**Six of the eleven canonical commands take an argument and open a SECOND +prompt** (`describe-command`, `describe-setting`, `describe-key`, +`describe-hook`, `where-is`, `apropos`). Those pins drive that prompt too, +and assert against it with the same pre-accept discipline. A pin that stops +after the first RET has tested the palette, not the command. ### 4.1 Pins @@ -418,11 +435,14 @@ the palette, not the command. 4. **N — `apropos` matches descriptions, not only names, and does so by substring.** Two assertions: a word appearing in exactly one command's *description* and no command *name* finds that command - (what distinguishes apropos from a name filter); and a - **subsequence that is not a substring** — letters present in order - but not contiguous — finds **nothing**. The second is what pins - Q#D3's decision rather than leaving matching semantics to whatever - the implementation reaches for. + (what distinguishes apropos from a name filter); and a deliberately + discriminating negative: register + `test.apropos-subsequence-fixture`, whose description's `qzjx` letters + occur only as the non-contiguous sequence `q z j x`, assert that **no** + registered command name or description contains `qzjx` as a substring, + then assert `help.apropos qzjx` finds **nothing**. A fuzzy implementation + finds the fixture, so this pins Q#D3's substring decision rather than + passing as an ordinary no-match. 5. **N — `describe-setting` completes, and a non-matching typo still reaches the existing error path.** Two assertions, because §3.2 has two outcomes: (a) typing a real setting's prefix makes it the @@ -432,7 +452,7 @@ the palette, not the command. *Rev 1 asserted a typo "cannot reach `on_accept`", which `resolve_accepted_value` contradicts.* 6. **N — `M-x help` lists the family.** A property over the family list, - so adding a tenth command without indexing it fails. + so adding a twelfth canonical command without indexing it fails. 7. **P — every command's `*help*` write goes through `_show_help`.** Replace that function with a counting stub, drive all **eleven** through §4.0's path, and assert the count equals eleven. Pins §3.4's