From 4b8ff2afaa8f3006c27ca53c7dae3dcf17379900 Mon Sep 17 00:00:00 2001 From: REPPL <77722411+REPPL@users.noreply.github.com> Date: Wed, 30 Sep 2026 23:38:26 +0100 Subject: [PATCH 1/8] docs: bring the user-facing pages current for v0.12.0 The v0.12.0 docs-currency review and the surface cross-check found pages and help that no longer say what the binary does; each now says what is. - upgrade guide: a run's state file is rewritten at schema version 8 (the version state.go writes), from version 1, the version v0.11.1 wrote. - build: the `key` check admits an issue id (the issue-keyed lane), and a refusal exits 3 on a locked run state as well as on a held intent. - history separation: its sentence names the store it resolves (a missing store created, a legacy corpus moved) and its refusal outside a git checkout; a Long help keeps the exit 1 on a finding. - guard: the default-word delete the guard blocks since 62d1ab56f leaves the unseen list, and the argument hint reads `check [--command ...]`, since check refuses a positional. - update and version: the network is reached only by a command whose job includes the call; the pages name each such path (launch --fetch-baseline, delegating verbs routed to a provider, ahoy connect and credential, site setup, the forge calls) in place of an "only" claim. - ahoy counts five changing sub-verbs, credential --home included; prepare-this-repo describes ADRs under timestamp ids; drain gains its argument hint and input line; the README sample board shows the Now / Next / Later block, taken from the built binary in a throwaway managed repository. The two help sentences are pinned by help_truth_test.go in both directions (the sentence, and the behaviour it names); the generated reference and the surface snapshot are regenerated. Assisted-by: Claude:claude-opus-5-5 --- .abcd/development/release/surface.json | 2 +- README.md | 6 +++ commands/ahoy.md | 9 ++-- commands/build.md | 9 ++-- commands/drain.md | 3 ++ commands/guard.md | 7 ++- commands/prepare-this-repo.md | 5 +- commands/update.md | 6 ++- commands/version.md | 14 ++++-- docs/how-to/upgrade-to-v0.12.0.md | 9 ++-- docs/reference/cli/commands.md | 9 +++- internal/core/surface/sentences.go | 4 +- internal/surface/cli/help_truth_test.go | 67 +++++++++++++++++++++++++ internal/surface/cli/history.go | 6 ++- internal/surface/cli/update.go | 2 +- 15 files changed, 127 insertions(+), 31 deletions(-) create mode 100644 internal/surface/cli/help_truth_test.go diff --git a/.abcd/development/release/surface.json b/.abcd/development/release/surface.json index fdc4f9435..056dc092c 100644 --- a/.abcd/development/release/surface.json +++ b/.abcd/development/release/surface.json @@ -1418,7 +1418,7 @@ { "path": "abcd history separation", "hidden": false, - "sentence": "Report whether any retained transcript held both a reading and the ledger of one run: Writes nothing; never refuses, exiting 1 naming each such transcript.", + "sentence": "Report whether a retained transcript held both a reading and one run's ledger: Writes a missing store or a legacy corpus move; refuses outside a git checkout.", "flags": [] }, { diff --git a/README.md b/README.md index 65892ba2b..cdceaa68b 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,12 @@ abcd — ~/code/your-repo record: true work tiers: [development work work.local] presence: abcd-managed · your-repo · main · itd 0 · iss 0 + status: Now 0 · Next 0 · Later 0 + Now: + (none) + Next: + (none) + Later: 0 intents ``` diff --git a/commands/ahoy.md b/commands/ahoy.md index 2c021905a..ce83e4a08 100644 --- a/commands/ahoy.md +++ b/commands/ahoy.md @@ -13,10 +13,11 @@ harness-invoked row that `install` wires, is in the agents-and-hosts block of Run abcd's install/update engine for the current repo and present the result. Bare invocation, its `--dry-run`, `--remote` and `--providers` modes, and the -`doctor` sub-verb perform **zero writes**; `install`, `uninstall`, `remote apply` -and `connect` are the four that change something, and each says so before it -runs — `remote apply` is the only one that changes state outside this machine, -and it asks before it does. +`doctor` sub-verb perform **zero writes**; five change something. `install`, +`uninstall`, `remote apply` and `connect` each say so before they run — +`remote apply` is the only one that changes state outside this machine, and it +asks before it does — and `credential --home` writes the chosen home only after +the credential's verification call succeeds. A mode is a flag on the bare verb, one at a time; a distinct action is a sub-verb. diff --git a/commands/build.md b/commands/build.md index bf9261d5b..7c90e80c6 100644 --- a/commands/build.md +++ b/commands/build.md @@ -46,8 +46,9 @@ hand-back. For an intent with no run in progress, the checks run first, and every one must pass: -- `key` — the argument is an intent id. An issue id is refused: the issue key - is not built yet. +- `key` — the argument is an intent id or an issue id (`iss-N`, by shape), and + anything else is refused; an issue id is checked as the issue-keyed lane + above. - `ready` — the intent is READY: planned, its criteria written, its spec linked and written (the same gate `/abcd:intent` reports). - `open_questions` — no open question under `## Open Questions`: every list @@ -74,8 +75,8 @@ pass: cannot be read (a worktree git will not answer for, a ledger holding one id twice) and an unreadable claim count as holding it: what they hold is unknown. -A refusal writes nothing. It exits 2, or 3 when a peer holds the intent (back -off and take other work). Under `--json` the refusal comes as its own document +A refusal writes nothing. It exits 2, or 3 when a peer holds the intent or the +run state is locked (back off and take other work). Under `--json` the refusal comes as its own document before the error envelope: `refusal.stage`, `refusal.check`, `refusal.reason`, `refusal.remedy` and every check's row in `refusal.checks`. Tell the user the check, the reason and the remedy, and do not work around it: an open question diff --git a/commands/drain.md b/commands/drain.md index abb2b7f4c..1e6c2f5c6 100644 --- a/commands/drain.md +++ b/commands/drain.md @@ -1,6 +1,7 @@ --- name: drain description: "Fix the issues needing no decision, one lane at a time, and hand the rest back: Writes its state and user-visible drafts; refuses without the rule's record." +argument-hint: "[--dry-run] [--max ] [--pace /] [--sub-agents ] [--fix-rounds ]" block: agents --- @@ -216,3 +217,5 @@ too, you are in a source checkout of this repo, where — and only there — binary on `PATH`, run `ahoy install` through whichever rung just resolved: `"${CLAUDE_PLUGIN_ROOT}/abcd" ahoy install`, `abcd ahoy install`, or `go run ./cmd/abcd ahoy install` in a source checkout. + +**User input:** $ARGUMENTS diff --git a/commands/guard.md b/commands/guard.md index 154e67159..014fa4578 100644 --- a/commands/guard.md +++ b/commands/guard.md @@ -1,7 +1,7 @@ --- name: guard description: "Judge a shell command against the hazard registry before it runs: Writes nothing; refuses a hazard through check or hook, and an unknown sub-verb." -argument-hint: "[check | hook]" +argument-hint: "[check [--command ] | hook]" block: agents --- @@ -387,9 +387,8 @@ since rm refuses a last segment `..`. Quoted, `'/**'` and `"~/.?"/*` block as What an allow still does not see is a hazard that never reaches command position at all: a delete target printed whole by a substitution (`rm -rf $(echo /)`), read by its known text the way `rm -rf $(find …)` names its targets every day, -or spelled any other way than the words above, a default's own word included -(`rm -rf ${DIR:-$HOME}`), as is a `..` after a symlink, which the path is read -past lexically, or after a segment holding a variable (`/tmp/$X/../*`) or a +or spelled any other way than the words above, as is a `..` after a symlink, +which the path is read past lexically, or after a segment holding a variable (`/tmp/$X/../*`) or a `~user` home (`~root/../../*`); one launched through a known wrapper carrying a value-taking flag the guard does not name (`sudo -u bob ` is seen; the bundled short form `sudo -Hu bob ` reaches only the warn, not the entry that names it), one diff --git a/commands/prepare-this-repo.md b/commands/prepare-this-repo.md index 91e82ad56..d6359042b 100644 --- a/commands/prepare-this-repo.md +++ b/commands/prepare-this-repo.md @@ -48,7 +48,8 @@ Read from `$ABCD`, delegating heavy reading to subagents where available: constraints, evidence, surfaces, internals, delivery, glossary). - `.abcd/development/principles/` — one principle per file, plus the three-rung promotion ladder in its README. -- `.abcd/development/decisions/adrs/` — MADR, sequential `NNNN`. Session +- `.abcd/development/decisions/adrs/` — MADR, one `-.md` per + decision under a timestamp id (`adr-`). Session decisions live in `work/DECISIONS.md`; architecture-shaping ones graduate. - `.abcd/development/intents/` — lifecycle by directory (`drafts/` → `planned/` → `shipped/` → `superseded/`). @@ -208,7 +209,7 @@ the conventions read as the repo's own. Adapt wording to the repo; keep the substance: - Three-tier working state: `.abcd/development/` (durable record: ADRs in - `decisions/adrs/` using MADR + `NNNN`, dated plans and research notes), + `decisions/adrs/` using MADR under timestamp ids, dated plans and research notes), `.abcd/work/` (committed: `CONTEXT.md` orientation, `DECISIONS.md` append-only one-line decision log), `.abcd/.work.local/` (gitignored: `NEXT.md` handover, `scratch/`, `logs/` — runtime artefacts go here, never diff --git a/commands/update.md b/commands/update.md index 6107662be..8d0f43e61 100644 --- a/commands/update.md +++ b/commands/update.md @@ -13,8 +13,10 @@ tag), verifies the platform binary against the same release's `checksums.txt`, and swaps the PATH copy atomically, printing a receipt that opens with `abcd updated from to ` and names the path, origin and digest. abcd never checks for or -applies updates on its own — this verb is the only command that reaches the -release origin, and only when invoked. +applies updates on its own — this verb reaches the release origin only when +invoked, as does the one other flag that reaches it, `--fetch-baseline` on +`launch` and `launch ship`, which downloads a released plugin archive to +compare against. The same line announces a swap the plugin bootstrap makes. When a hook that discards its output made the swap, the next session start shows the line once, diff --git a/commands/version.md b/commands/version.md index e5595d602..b933c0cb5 100644 --- a/commands/version.md +++ b/commands/version.md @@ -52,10 +52,16 @@ for a binary the update verb can swap, the host's plugin update for a plugin-root binary, or the package manager's own command for a Homebrew install — chosen by the same on-disk classification `abcd update` dispatches on. Relay it verbatim rather than paraphrasing; it is the one line the user -types next. abcd never fetches implicitly (adr-38): the network is only ever -touched by a verb whose documented job is that fetch — `update --check`, -`update`, `docs cite refresh`, and `memory ingest `; every other path -reads only what is on disk. +types next. abcd never fetches implicitly (adr-38): the network is touched +only when the caller runs a command whose documented job includes a remote +call. The release origin is reached by `update --check`, `update`, and +`launch --dry-run --fetch-baseline` or `launch ship --fetch-baseline`; a cited +source by `docs cite refresh`; a URL by `memory ingest `; a provider's +verification call by `ahoy connect` and `ahoy credential --home`; a +model provider by a delegating verb routed to one (`reading ingest --dispatch` +among them); the site host and GitHub by `site setup`; and GitHub, through `gh` +or `git`, by `ahoy --remote`, `ahoy remote apply` and the implement loop's +landing. **Binary resolution.** Run `"${CLAUDE_PLUGIN_ROOT}/abcd"` — a plugin install provisions the binary into the plugin root, so this is the rung that fires for a diff --git a/docs/how-to/upgrade-to-v0.12.0.md b/docs/how-to/upgrade-to-v0.12.0.md index 8d5463be0..ec5d42cff 100644 --- a/docs/how-to/upgrade-to-v0.12.0.md +++ b/docs/how-to/upgrade-to-v0.12.0.md @@ -34,10 +34,11 @@ says ` may take the review stage`, and an operand outside them is refused as an `unknown stage`. A run started with an older abcd carries on. Its state file (schema version 1, -2 or 3) is read as it stands, each `step` taken as the lane's `stage`, and the -read writes nothing; the run's next `abcd implement step` or `receipt` writes -the file at schema version 4. An older abcd cannot read a version-4 file, so -finish a run with the abcd that is going to keep driving it. +the version v0.11.1 writes) is read as it stands, each `step` taken as the +lane's `stage`, and the read writes nothing; the run's next `abcd implement +step` or `receipt` writes the file at schema version 8. An older abcd cannot +read a version-8 file, so finish a run with the abcd that is going to keep +driving it. ## Replace the removed command spellings diff --git a/docs/reference/cli/commands.md b/docs/reference/cli/commands.md index 5676e858e..6c6cbed1e 100644 --- a/docs/reference/cli/commands.md +++ b/docs/reference/cli/commands.md @@ -1387,10 +1387,15 @@ abcd history reconstruct 0123abcd-session #### `abcd history separation` -Report whether any retained transcript held both a reading and the ledger of one run: Writes nothing; never refuses, exiting 1 naming each such transcript. +Report whether a retained transcript held both a reading and one run's ledger: Writes a missing store or a legacy corpus move; refuses outside a git checkout. **Usage:** `abcd history separation` +Report whether any retained transcript held both a reading and the ledger of one run, from +record metadata alone. The store is resolved as every history read resolves it: a missing +store is created and a legacy corpus moved into it. A transcript that held both is a finding: +each is named and the verb exits 1. Outside a git checkout with a commit it refuses. + #### `abcd history show` Show one stored transcript's metadata and redacted body: Writes only a missing store and a legacy corpus moved into it; refuses an id the store does not hold. @@ -3292,6 +3297,6 @@ install's shape, and swaps nothing. **Flags:** ``` - --check fetch the latest release once and compare it with this binary, swapping nothing (the only network touch besides the update itself; abcd never fetches implicitly — adr-38); names its source and the command that takes the update + --check fetch the latest release once and compare it with this binary, swapping nothing (it reaches the network only when invoked; abcd never fetches implicitly — adr-38); names its source and the command that takes the update --yes skip the TTY confirmation of a freshly resolved tag ``` diff --git a/internal/core/surface/sentences.go b/internal/core/surface/sentences.go index 1e7dde5dd..6d3a6aa1d 100644 --- a/internal/core/surface/sentences.go +++ b/internal/core/surface/sentences.go @@ -159,8 +159,8 @@ var sentences = map[string]string{ "Writes a missing store, and the repaired records only with --apply; refuses outside a git checkout.", "abcd history reconstruct": "Render one session and its sub-agents as one artefact plus telemetry: " + "Writes both files into --out; refuses an --out that is not an existing directory.", - "abcd history separation": "Report whether any retained transcript held both a reading and the ledger of one run: " + - "Writes nothing; never refuses, exiting 1 naming each such transcript.", + "abcd history separation": "Report whether a retained transcript held both a reading and one run's ledger: " + + "Writes a missing store or a legacy corpus move; refuses outside a git checkout.", "abcd history show": "Show one stored transcript's metadata and redacted body: " + "Writes only a missing store and a legacy corpus moved into it; refuses an id the store does not hold.", "abcd history staged": "List the ended transcripts not yet redacted into the store: " + diff --git a/internal/surface/cli/help_truth_test.go b/internal/surface/cli/help_truth_test.go new file mode 100644 index 000000000..6a0b7ae96 --- /dev/null +++ b/internal/surface/cli/help_truth_test.go @@ -0,0 +1,67 @@ +package cli + +import ( + "bytes" + "strings" + "testing" +) + +// help_truth_test.go — help sentences held to what the verb does, in both +// directions: the sentence says it, and the verb does it. + +// TestHistorySeparationHelpNamesItsWritesAndRefusal: `history separation` +// resolves the store as every history read does (a missing store is created, a +// legacy corpus moved into it) and refuses outside a git checkout, so its help +// may claim neither that it writes nothing nor that it never refuses. +func TestHistorySeparationHelpNamesItsWritesAndRefusal(t *testing.T) { + t.Setenv("HOME", t.TempDir()) + t.Chdir(t.TempDir()) + + var stdout, stderr bytes.Buffer + if code := Run([]string{"history", "separation", "--help"}, &stdout, &stderr); code != 0 { + t.Fatalf("history separation --help exited %d: %s", code, stderr.String()) + } + help := stdout.String() + for _, claim := range []string{"Writes nothing", "never refuses"} { + if strings.Contains(help, claim) { + t.Errorf("history separation --help claims %q, which the verb does not hold:\n%s", claim, help) + } + } + for _, want := range []string{"Writes a missing store or a legacy corpus move", "refuses outside a git checkout"} { + if !strings.Contains(help, want) { + t.Errorf("history separation --help does not say %q:\n%s", want, help) + } + } + + stdout.Reset() + stderr.Reset() + if code := Run([]string{"history", "separation"}, &stdout, &stderr); code == 0 { + t.Fatalf("history separation outside a git checkout exited 0; the help says it refuses there\nstdout: %s", stdout.String()) + } +} + +// TestUpdateCheckHelpClaimsNoMonopolyOnTheNetwork: `update --check` is not the +// only network touch besides the update itself (`launch --fetch-baseline` +// downloads a released plugin archive), so its flag help says only that it +// reaches the network when invoked. +func TestUpdateCheckHelpClaimsNoMonopolyOnTheNetwork(t *testing.T) { + var stdout, stderr bytes.Buffer + if code := Run([]string{"update", "--help"}, &stdout, &stderr); code != 0 { + t.Fatalf("update --help exited %d: %s", code, stderr.String()) + } + help := stdout.String() + if strings.Contains(help, "the only network touch") { + t.Errorf("update --help claims --check is the only network touch:\n%s", help) + } + if !strings.Contains(help, "it reaches the network only when invoked") { + t.Errorf("update --help does not say --check reaches the network only when invoked:\n%s", help) + } + + stdout.Reset() + if code := Run([]string{"launch", "--help"}, &stdout, &stderr); code != 0 { + t.Fatalf("launch --help exited %d: %s", code, stderr.String()) + } + if !strings.Contains(stdout.String(), "--fetch-baseline") { + t.Fatalf("launch no longer carries --fetch-baseline; the network sentences in update --help and commands/version.md name it") + } +} diff --git a/internal/surface/cli/history.go b/internal/surface/cli/history.go index 3a7ec96b5..01e520290 100644 --- a/internal/surface/cli/history.go +++ b/internal/surface/cli/history.go @@ -166,7 +166,11 @@ func newHistoryCommand(asJSON *bool) *cobra.Command { historyCmd.AddCommand(&cobra.Command{ Use: "separation", Short: "Report whether any retained transcript held both a reading and the ledger of one run", - Args: cobra.NoArgs, + Long: "Report whether any retained transcript held both a reading and the ledger of one run, from\n" + + "record metadata alone. The store is resolved as every history read resolves it: a missing\n" + + "store is created and a legacy corpus moved into it. A transcript that held both is a finding:\n" + + "each is named and the verb exits 1. Outside a git checkout with a commit it refuses.", + Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { repoRoot, rootSHA, err := historyStore(cmd) if err != nil { diff --git a/internal/surface/cli/update.go b/internal/surface/cli/update.go index 26439a30e..e9255c485 100644 --- a/internal/surface/cli/update.go +++ b/internal/surface/cli/update.go @@ -106,7 +106,7 @@ func newUpdateCommand(asJSON *bool) *cobra.Command { }, } cmd.Flags().BoolVar(&yes, "yes", false, "skip the TTY confirmation of a freshly resolved tag") - cmd.Flags().BoolVar(&check, "check", false, "fetch the latest release once and compare it with this binary, swapping nothing (the only network touch besides the update itself; abcd never fetches implicitly — adr-38); names its source and the command that takes the update") + cmd.Flags().BoolVar(&check, "check", false, "fetch the latest release once and compare it with this binary, swapping nothing (it reaches the network only when invoked; abcd never fetches implicitly — adr-38); names its source and the command that takes the update") cmd.MarkFlagsMutuallyExclusive("check", "yes") return cmd } From e8d5d006051244142c7dd4a9829cebe767aeec06 Mon Sep 17 00:00:00 2001 From: REPPL <77722411+REPPL@users.noreply.github.com> Date: Wed, 30 Sep 2026 23:50:54 +0100 Subject: [PATCH 2/8] docs: drop the guard brief's claim that a default's word goes unseen The guard blocks `rm -rf ${DIR:-$HOME}` and `${X[0]]-$HOME}` as rm-rf-root-or-home since 62d1ab56f and 598f47756, and the chapter's own reading of a default already says so. The v0.12.0 docs review held on the stale clause in the list of what an allow does not see; this removes it, matching the same fix to commands/guard.md in 4b8ff2afa. Assisted-by: Claude:claude-opus-5-5 --- .abcd/development/brief/04-surfaces/17-guard.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.abcd/development/brief/04-surfaces/17-guard.md b/.abcd/development/brief/04-surfaces/17-guard.md index 17e516597..81aff8f77 100644 --- a/.abcd/development/brief/04-surfaces/17-guard.md +++ b/.abcd/development/brief/04-surfaces/17-guard.md @@ -447,11 +447,9 @@ message or a branch name is spelled every day; a delete target printed whole by substitution (`rm -rf $(echo /)`), which is read by its known text because that is how an everyday delete names what it removes (`rm -rf $(find . -name '*.pyc')`); a target spelled any other way than the words above (`rm -rf -"$DIR"/*` with `DIR` unset, `rm -rf /?*`), a default's own word, which bash -prints only when the variable is unset (`rm -rf ${DIR:-$HOME}`, and -`${X[0]]-$HOME}`, which the bash 3.2 of macOS reads as a default after the -subscript), a `..` after a symlink, which is read past lexically (a link to -the root under a named directory), or after a segment holding a variable, +"$DIR"/*` with `DIR` unset, `rm -rf /?*`), a `..` after a symlink, which is +read past lexically (a link to the root under a named directory), or after +a segment holding a variable, which is not folded (`/tmp/$X/../../*` is the root with `X` unset), a `..` past the home followed by a glob other than `*` (`~/../?*`, as `/?*`), a relative `..` that stays inside the working directory (`x/../*`, the From 4d634c4f0baf4d23fde0c76b811e0619ee927d48 Mon Sep 17 00:00:00 2001 From: REPPL <77722411+REPPL@users.noreply.github.com> Date: Wed, 30 Sep 2026 23:55:10 +0100 Subject: [PATCH 3/8] docs: bring the rest of the guard brief current with the shipped guard The v0.12.0 re-review held on the tail of the same list: an alternative nested more than three deep and a `$PWD` substring that prints the root both block as rm-rf-root-or-home since iss-2609290426544292, and the chapter's own reading of a substring already says so. The release cross-check named three more claims in the chapter the shipped guard contradicts: only `guard check` speaks JSON, the hook answering by exit code and stderr alone; the `matches` list names every entry tripped, the one that fired included; and a hazard the guard reads in code rather than from the registry is enforced but not taught. Refs: iss-2609290426544292 Assisted-by: Claude:claude-opus-5-5 --- .../development/brief/04-surfaces/17-guard.md | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/.abcd/development/brief/04-surfaces/17-guard.md b/.abcd/development/brief/04-surfaces/17-guard.md index 81aff8f77..807613f5b 100644 --- a/.abcd/development/brief/04-surfaces/17-guard.md +++ b/.abcd/development/brief/04-surfaces/17-guard.md @@ -65,12 +65,14 @@ the hook: it is blocked (`command-unparsable`), not let through, because a line the guard misreads may be one bash runs, and a pass would carry every hazard in it past the guard. On the check it exits 2, like the rest. -Either verb also speaks JSON, and that is the form the plugin page uses: a -verdict, and with it the entry that fired, its tier, why the command is -dangerous, and the safe successor. A `matches` list carries any further entries -the same line tripped, so a command hazardous in two ways reports both rather -than only the first; the rendered form says the same thing on an `also matched:` -line. +The check also speaks JSON (`guard check --json`), and that is the form the +plugin page uses: a verdict, and with it the entry that fired, its tier, why the +command is dangerous, and the safe successor. A `matches` list names every entry +the same line tripped, the one that fired included, so a command hazardous in +two ways reports both rather than only the first; the rendered form says the +same thing on an `also matched:` line. The hook answers the host by its exit +code and its message on stderr alone, and writes nothing on stdout, with or +without `--json`. ## Taught before it is refused @@ -82,7 +84,11 @@ the safe successor, recalled by the commands the registry names (`rm`, work injects those rules before the agent acts, so a host without hook support is still taught the safe form and a host with hooks is taught it before the guard would have to refuse. An entry added to the registry is taught and enforced from -the same release, with no second edit. The registry taught is the one the guard +the same release, with no second edit. A hazard the guard reads in code rather +than from the registry, such as `git-stash-shared-stack` (a bare `git stash` in +a checkout with more than one worktree) or `interpreter-reads-stream` (a shell +handed its script through a pipe, as in `cat x | sh`), is enforced but not +taught. The registry taught is the one the guard enforces in the repository: an entry the repository adds in its `.abcd/guard.json` is taught by the same generator as the bundled ones, its rule marked `(repo)` after its entry id, and a guard file the guard refuses is @@ -448,16 +454,13 @@ substitution (`rm -rf $(echo /)`), which is read by its known text because that is how an everyday delete names what it removes (`rm -rf $(find . -name '*.pyc')`); a target spelled any other way than the words above (`rm -rf "$DIR"/*` with `DIR` unset, `rm -rf /?*`), a `..` after a symlink, which is -read past lexically (a link to the root under a named directory), or after -a segment holding a variable, -which is not folded (`/tmp/$X/../../*` is the root with `X` unset), a `..` -past the home followed by a glob other than `*` (`~/../?*`, as `/?*`), a -relative `..` that stays inside the working directory (`x/../*`, the -directory `*` names), a `..` after a `~user` home, whose depth is not known -(`~root/../../*`), an -alternative nested more than three deep, and a substring of `$PWD` that -prints the root (`${PWD:0:1}`), which warns as `$PWD` does; one behind a wrapper flag the per-wrapper -table does not name; a REST +read past lexically (a link to the root under a named directory), or after a +segment holding a variable, which is not folded (`/tmp/$X/../../*` is the root +with `X` unset), a `..` past the home followed by a glob other than `*` +(`~/../?*`, as `/?*`), a relative `..` that stays inside the working directory +(`x/../*`, the directory `*` names), and a `..` after a `~user` home, whose +depth is not known (`~root/../../*`); one behind a wrapper flag the +per-wrapper table does not name; a REST path an entry names by its root segment when the host serves that API under a prefix; an IFS the shell already holds when the line starts, or gains during the line through a name the guard does not read (a sourced file, a nameref set before From c8ddb042553c44cf798bced12007eb9bb5a30968 Mon Sep 17 00:00:00 2001 From: REPPL <77722411+REPPL@users.noreply.github.com> Date: Thu, 1 Oct 2026 00:15:09 +0100 Subject: [PATCH 4/8] docs: name the trailing-dot fold only where the guard makes it The v0.12.0 re-review read the guard chapter whole and held on one more sentence: `rm -rf ../.` is allowed, and the fold of a trailing `.` after a `..` warns only past a first segment (`./../.`). This applies the reviewer's drafted replacement through `docs fidelity --apply`, which flags the sentence for the product thinker's review in .abcd/work/brief-review-flags.json. Assisted-by: Claude:claude-opus-5-5 --- .abcd/development/brief/04-surfaces/17-guard.md | 2 +- .abcd/work/brief-review-flags.json | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 .abcd/work/brief-review-flags.json diff --git a/.abcd/development/brief/04-surfaces/17-guard.md b/.abcd/development/brief/04-surfaces/17-guard.md index 807613f5b..d7cb11a32 100644 --- a/.abcd/development/brief/04-surfaces/17-guard.md +++ b/.abcd/development/brief/04-surfaces/17-guard.md @@ -423,7 +423,7 @@ directory is folded the same way: a `..` past `$PWD` or `${PWD}`, or past the start of a relative path, is the directory above it, so `$PWD/../*`, `./../*` and `x/../../*` warn as `../*` does, and `$PWD/x/../*` as `$PWD/*`; a relative path whose `..` stays inside the working directory is compared as -written. A trailing `.` after such a `..` (`../.`) warns too, though rm +written. A trailing `.` after such a `..` (`./../.`) warns too, though rm refuses it. Each target is also read the way its glob can expand: a run of `*` is one `*`, which is what every shell without globstar expands `**` to (with globstar it matches more), so `/**`, `~/**` and `~/../**` block as diff --git a/.abcd/work/brief-review-flags.json b/.abcd/work/brief-review-flags.json new file mode 100644 index 000000000..20778f35f --- /dev/null +++ b/.abcd/work/brief-review-flags.json @@ -0,0 +1,13 @@ +{ + "schema_version": 1, + "flags": [ + { + "chapter": "17-guard.md", + "sentence": "written. A trailing `.` after such a `..` (`../.`) warns too, though rm", + "replacement": "written. A trailing `.` after such a `..` (`./../.`) warns too, though rm", + "evidence": "Probes at 4d634c4f0 via guard check on stdin (scratch binary): `rm -rf ../.` ALLOWS (exit 0), and so do `rm -rf ../../.`, `rm -rf ./.`, `rm -rf /.`; while `rm -rf ./../.`, `rm -rf $PWD/../.` and `rm -rf x/../../.` WARN on rm-rf-working-directory (exit 0) and `rm -rf ..`, `rm -rf ../` warn. The chapter's own example `../.` is the one form that allows. internal/core/guard/match.go:883-885 (foldParents comment) claims a trailing `.` is folded, and no test in internal/core/guard/*_test.go names `../.`; the sentence entered the chapter in 4ef5013bd (2026-09-29), an ancestor of a76d7f52b, so it is pre-existing and outside every delta reviewed since. Every other probed claim in the chapter holds: only `guard check` speaks JSON (`guard hook --json` writes nothing on stdout and answers by exit 2/1/0 and stderr), `matches` lists every entry tripped with the fired one first (`[\"git-push-force\",\"git-clean\"]`, rendered `also matched: git-clean`), `git-stash-shared-stack` and `interpreter-reads-stream` fire (stash.go, payload.go) and are absent from `rules SHELL` (17 registry entries, none of those ids), the verdict table, `command-unparsable` on the hook, `git pus? --force`, `r[[:lower:]] -rf /`, `git clea[!n] -fd`, `rm $(true) -rf *`, `mkdir -p foo/{a,b}` (allow), `git push {--force,} origin main`, `${HOME%/*}`, `~/../*/*`, `/**`, `~/.?/*`, `~/.[a-z]/*`, `~/.?` (allow), `'/**'`, `${X:+$HOME}`, `IFS=x; rm -rf ${U:-x/x}`, `IFS=Uv; rm -rf $HOME/x`, `${X:-$'\\x2f'}`, `$!/`, `${PWD:0:1}` (block), `cat x | sh`, `pkill -u`, `kill $(pgrep make)`, `cd /tmp \u0026\u0026 rm -rf x`, `pushd /tmp; rm -rf x`, `core.hooksPath`, a same-line git alias, and the whole unseen list at lines 449-490 (`$(echo /)`, `\"$DIR\"/*`, `/?*`, `/tmp/$X/../../*`, `~/../?*`, `x/../*`, `~root/../../*`, `ps | grep | xargs kill`, `p=$(pgrep make); kill $p`, `python -c`, `$(cat msg.txt)`, `$(date)` all allow).", + "commit": "4d634c4f0baf4d23fde0c76b811e0619ee927d48", + "applied": "2026-09-30T23:00:13Z" + } + ] +} From fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9 Mon Sep 17 00:00:00 2001 From: REPPL <77722411+REPPL@users.noreply.github.com> Date: Thu, 1 Oct 2026 00:15:10 +0100 Subject: [PATCH 5/8] chore: cut v0.12.0 Assisted-by: Claude:claude-opus-5-5 --- .abcd/development/releases/0.11.1.md | 45 +++++++++++++++ .claude-plugin/marketplace.json | 4 +- CHANGELOG.md | 85 ++++++++++++++++++++++++++++ RELEASE.md | 44 +++++++------- 4 files changed, 153 insertions(+), 25 deletions(-) create mode 100644 .abcd/development/releases/0.11.1.md diff --git a/.abcd/development/releases/0.11.1.md b/.abcd/development/releases/0.11.1.md new file mode 100644 index 000000000..dfe485863 --- /dev/null +++ b/.abcd/development/releases/0.11.1.md @@ -0,0 +1,45 @@ +# Release 0.11.1 (2026-09-28) + +abcd makes sure the right person is the author of record before a single commit lands. `abcd ahoy` checks the identity a commit would actually carry, author and committer, whatever git config or environment produced it, against the identity the repository pins; when they diverge it proposes the pinned (or global) identity and asks before writing repo-local config, and with no one to ask it reports and writes nothing. (itd-131) + +> "A sandbox `Test User` override authored 54 commits before anyone noticed — we had to rewrite history and force-push to unpick it," said Alice, who maintains the repo. "Now `ahoy` catches a wrong identity before the first commit, and it asks me rather than guessing." (itd-131) + +A repository abcd manages declares what it ships, and the release flow follows the declaration. A Go application or a macOS app with its own tag-driven workflow declares its artefact kind once, `launch --dry-run` and `launch ship` run against it with the changelog-driven gate, the deferral read and the derived version, and `launch scaffold` lays the gate beside the release workflow the repository already has and leaves that workflow as it was. (itd-2609150819432059) + +One verb sets up a managed repository's site: `abcd site setup` writes the composition, the render-then-deploy workflow and the environments and prints the step left, and with a hosting credential configured it creates and routes the host and reports the address. The site is abcd's own page set, rendered from that repository's record. (itd-2609061543533170) + +> "The explorer, the graph, the timeline: I had them for abcd and wanted them for every repository abcd manages," said a product thinker looking at the record browser. "Now one verb writes the workflow and the environments, and when I have given abcd a hosting credential it creates and routes the host too. Any managed repo's site looks like abcd's, with its own record in it." (itd-2609061543533170) + +A new issue, or a draft intent filed as quoted text, is matched against the record at filing: a likely double is linked and named, and never dropped. (itd-2609212137116617) + +> "I filed the same finding twice a month apart and nobody noticed until a consistency pass," said a technical facilitator. "Now the capture tells me at filing that it looks like iss-N, writes the link, and leaves it to me to confirm. Nothing is refused: a wrong match is a link I remove, not a finding I lost." (itd-2609212137116617) + +The status-line badge always reads one of three states, `abcd-managed`, `waiting on the product thinker` or `waiting on the technical facilitator`; an agent's question to the human is refused until the mode says who is being asked, and the next human answer resets it. (itd-2609212130146198) + +> "The badge was set by whichever agent remembered," said a product thinker who had watched it read managed while an agent waited on them. "Now an agent cannot ask me anything until it has said which of us it is asking, and the moment I answer the badge goes back. It is the one signal I have that something is waiting; now it is true." (itd-2609212130146198) + +Consult any source freely and cite only by deliberate human choice: `abcd source` keeps a local-only corpus of material you are not free to name and an append-only ledger of what influenced which decision, citation needs the source's permission and your own flip of the ledger line, and `abcd source cite-check` clears text before it is shared, reporting offenders by key alone. (itd-76) + +> "I could never let an agent near my working papers before, because one helpful footnote could burn a collaborator's trust," said Alice, a researcher-developer. "Now it reads everything, records what influenced what, and cites nothing. When the paper behind a decision is finally published, I flip one flag — and the whole influence trail is already written." (itd-76) + +Every shipped intent owes a fidelity review, and abcd now says which ones are still owed: bare `abcd intent audit` lists each with its receipt and the command that re-emits the request, `abcd intent` carries the count, and `abcd intent audit --owed` hands a host the owed requests oldest first, leaving them owed when no reviewer is reachable. Nothing refuses on the debt. (itd-2609150819445595, itd-53) + +> "I asked what was outstanding and got a list of eight, with the command to re-emit each one," said Iris, a technical facilitator paying down a run's review debt. "Last week the same question was a grep through the decision log." (itd-2609150819445595) + +Intents that ship as one piece of work plan as a bundle: one shared spec, both records moving to `planned/` together and shipping together when the spec closes, with `abcd intent reclassify` to change a record's kind or supersede it. One glossary page now maps the record families (intent, spec, step, bundle, issue, release, status) and how each moves, with phase, milestone and roadmap marked superseded. (itd-34, itd-2609211913453478) + +> "I kept asking which word to use, and every answer named a different document," said a product thinker who had just approved bundles and wondered whether phases still meant anything. "Now there is one page: intent, spec, step, bundle, issue, release, status. Phase and milestone are on it too, marked superseded, with what replaced them. I read it in five minutes." (itd-2609211913453478) + +A review names the commit it read, and the bare `abcd` board shows how far the default branch has moved since, flagging one past twenty commits. `abcd intent consistency` checks the brief and the intents against each other and files each contradiction as an issue, quoting both ends. (itd-28, itd-48) + +When a capability could use a program you have not installed, `abcd ahoy install` explains it first: what the program is, whether this capability needs it, what already works without it and the exact install step. It installs only on an explicit yes, and a no leaves the capability on its native default and says so. (itd-63) + +Also in this release: + +- An admission and a surprise are written by a verb, and the order the design fixes is a refusal (itd-2609020625400194) +- A reframe occasioned by a reading is recorded as a reframe, joined to what occasioned it, without carrying the construal it replaced (itd-2609020625402518) +- The scribe's context is assembled and its output is ingested by a verb, and the record can show that no session held both a reading and the ledger (itd-2609020625402599) +- A principle carries typed claims, its reference, its comparison and its evidence, its statement is readable cold, and it inherits only what held (itd-2609020625405170) +- abcd lab mechanises the lab conventions three hand-run experiments proved (itd-2609212137128014) + +The line-by-line record of this release is its section in CHANGELOG.md. diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index f7bf5392f..52296b9a8 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -10,9 +10,9 @@ "description": "Host-agnostic configuration layer for development — a single Go binary, usable as a plugin in compatible agent harnesses.", "name": "abcd", "source": { - "sha256": "dd9cc57407c738bbe8b442ef26b575986be720963f4cd5aeade9e6c5f3a9a750", + "sha256": "47d04d8f11c2e3bea513dddbbccc88f5522957aca793828fff42389d29e49418", "source": "archive", - "url": "https://github.com/intentdriven/abcd/releases/download/v0.11.1/abcd-plugin-v0.11.1.zip" + "url": "https://github.com/intentdriven/abcd/releases/download/v0.12.0/abcd-plugin-v0.12.0.zip" } } ] diff --git a/CHANGELOG.md b/CHANGELOG.md index da8d639d1..3a1a5f131 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,91 @@ some carry a **Breaking** heading. ## [Unreleased] +## [0.12.0] - 2026-09-30 + +These notes list what was added and what was fixed; changes to earlier behaviour are not claimed until the composer can see the previous release. + +### Added + +- **Breaking: the build loop names a lane's stages `stage`, not `step`.** A spec's pieces keep the word step; what a lane goes through (`worktree`, `brief`, `implement`, `validate`, `land`) is a stage in every JSON field that carries one: `performed` becomes `performed_stage` and `step` becomes `stage` in `abcd implement step --json` and `abcd implement receipt --json`, a loop refusal's `refusal.step` becomes `refusal.stage`, a lane's `lane.step` under `status.now` in `abcd --json` becomes `lane.stage`, and `abcd implement check --json` and the refusal it logs carry `stage`, with an operand outside its five refused as an `unknown stage`. The run state file moves to schema version 8: a run begun on v0.11.1 (schema version 1) is read as it stands and rewritten at version 8 by its next `implement step` or `receipt`, which an older abcd cannot read, so finish a run with the abcd that will keep driving it. A script, hook or host reading any of the old fields stops finding them; update it from the table in docs/how-to/upgrade-to-v0.12.0.md. (iss-2609291313276243, iss-2609292359485570) +- **Breaking: the command spellings kept for one release are gone.** `abcd ahoy dry-run`, `abcd ahoy identity-check`, `abcd version` (with `abcd version --check`), `abcd docs lint` and `abcd site check` are unknown commands, refused with exit 2; use `abcd ahoy --dry-run`, `abcd ahoy --identity`, `abcd --version`, `abcd update --check`, `abcd lint docs` and `abcd lint site`. Bare `abcd identity` and bare `abcd ahoy remote` now list their sub-verbs and exit 0 instead of naming a replacement; for the reports they gave, use `abcd lint identity` and `abcd ahoy --remote`. Search scripts, hooks and CI workflows for the old spellings; docs/how-to/upgrade-to-v0.12.0.md lists every replacement. (iss-2609251324599468) +- **A role can run through a command-line harness.** The machine's configuration enables a shipped runner with `runner.` (the claude CLI, always launched with its bare flag so a target repository's hooks and servers do not run, or opencode) and routes a role to it with `roles..runner`; a role left unset runs on the host as before, and a repository that declares `runner.*` is refused. The runner gets the same brief, inputs and output contract as the host sub-agent, its answer is validated the same way and its transcript lands in abcd's own store. A runner's model route off its provider's allowlist is refused before anything launches, a harness binary or PATH directory another account can write is refused, and a model the claude harness reports outside a bounded plain shape counts as an unparsable answer, so it never reaches the run state. An absent, refusing or failing runner hands the role back to the host, each fallback writes a receipt naming the role, the runner, the reason and the route that ran, and the run summary counts fallbacks per runner and per role. So far the runners are proven against stand-in harnesses only: no real claude or opencode binary has yet run a role, and the fallback for a run with no host session is built in the core but not yet reachable from a surface. (itd-2609201916056194, iss-2609301557141123, iss-2609301557191251) +- **An OpenAI-compatible API adapter.** `oracle.api.` takes a `base_url`, a `key` given by name and a `models` allowlist, and a role or judgement pointed at `/` runs over that protocol with the same prompt, inputs and output contract as the host sub-agent, its transcript captured into the same store and the provider, the model asked for and the model reported recorded per call; `abcd ahoy connect` sets a provider up. A model not on its provider's list is refused when the configuration is read, before any call. The allowlist alone decides: abcd bundles no vendor denylist, and an `oracle.denylist` entry the configuration writes still refuses a listed model it matches. With no provider configured nothing changes and no network call is made. (itd-2609081951381895, iss-2609300110451242) +- **One credential store for every external key.** `abcd ahoy credential ` explains what a credential unlocks and what works without it, and stores it in the home named with `--home`: `external` (an environment variable, or a field of another tool's configuration file, of which abcd keeps only the pointer), `abcd` (the owner-only `~/.abcd/credentials.json`) or `keychain` (the platform keychain, which the explanation recommends); the value is read from standard input, and nothing is asked interactively. The API adapter and the site setup resolve keys by name through the store, and a name that resolves to nothing is refused naming the command that stores it. The `abcd` home refuses to write inside a git working tree, including through a home directory that is itself a symlink into a checkout, and the store reads and writes its index through the one `~/.abcd` it opened. The keychain home is so far exercised in tests against a stand-in, not a live keychain. (itd-2609221017023290, iss-2609290259108077, iss-2609290300313698) +- **The status board shows Now, Next and Later.** Bare `abcd` and the site's Status page compute the block from the record and store nothing: Now lists every intent whose lane the build's state file shows started, with its lane state, and names the head of `abcd build next`'s pick order as next up; Next lists the planned intents the readiness gate reports READY, in pick order; Later gives the planned intents that are not READY, with the failing check, then drafts. An intent in a lane is listed under Now only. The text board gives Later as a count, while `abcd --json` and the site keep its rows. The next-up head passes the record checks `abcd build next` runs (open questions, the claim sections, `blocked_by`, the spec's steps), though not its peers check. A managed repository's `site-src/ui.json` written before the block's labels existed keeps building: `abcd site setup` and `abcd site build` add each missing label with abcd's default words and name it on stderr. (itd-2609212103568351, iss-2609292011569133, iss-2609291803334904) +- **An intent can name the release it must land by.** `abcd intent plan --target ` or `abcd intent target ` writes `target_release` on a planned intent, and record lint refuses it on a shipped or superseded one. `abcd launch --dry-run` and the release cut list every targeted intent not yet shipped, in text, in the receipt and in `--json`, and proceed; at the cut, each target the release passes becomes `next`, and the status board marks a targeted intent with its target. (itd-2609212103572513) +- **A cut release gets a retrospective.** `abcd reflect ` (`/abcd:reflect`) runs an interview seeded by the intents the tag shipped, read the way the release cut reads them, with their audit notes and the release's changelog section, and writes `.abcd/development/retrospectives//README.md`. A shipped intent with no audit notes is named and `abcd intent audit ` offered first; a tag that shipped no intent is refused. A packed lifeboat carries every retrospective, and embarking from one shows the predecessor lessons most like the new voyage's brief. A retrospective written while an embark runs makes the embark fail loudly rather than being replaced. (itd-24, iss-2609301245517138) +- **A coherence pre-pass before the planning interview.** `abcd intent prepass ` assembles the brief's invariants, the principles and a one-line index of every other intent beside a draft for the host to judge, and `--findings-json` writes the resulting questions into the planning brief under the local tier: each invariant the draft appears to conflict with, quoting both lines; each sibling it overlaps, with the four answers (keep both, bundle, supersede, refine) and any recommendation given in prose, never as a marked option; and each concern it cannot anchor to a named record, marked unanchored. The draft and its siblings are left unchanged. (itd-42) +- **The brief must describe what ships.** In a repository that carries a brief, `abcd spec close` refuses to move an intent to shipped, and the release cut refuses over every intent shipped since the last tag, while the brief lags a surface: a deterministic layer refuses, with no oracle, any verb, sub-verb or agent no brief chapter names, and a host-delegated layer refuses on a confirmed false sentence and fails closed when no reviewer answers. `abcd docs fidelity` runs the gate, `--report` only reports, `--apply` writes the reviewer's drafted brief edits and flags each for review, `--autonomous` does the same for an unattended run, and `abcd docs fidelity record --verdict-json` records a verdict. No backlog file exempts a surface, a recorded verdict that names a false brief sentence cannot let the change through, and a drafted sentence or replacement spanning lines or over 2048 bytes is refused. (itd-60, iss-2609301251469172) +- **A dependency bump can land without a person re-authoring it.** `abcd launch scaffold --dependency-reauthor` writes a workflow that re-authors a declared bot's bump as the repository owner when its diff touches only one declared ecosystem's manifest and lock file, names the bot and the workflow in the message with `Assisted-by: None`, updates the pull request and records each re-authoring; any other diff, bot or ecosystem is left alone and the run says which test it failed. The attribution gate is unchanged and still refuses the bot's original commit. The workflow is proven offline so far: the first live bump waits on the repository's GitHub App and its secrets. (itd-2609221842494980) +- **Session URLs and tool footers are kept out of committed text and the build loop's posts.** A live agent-session URL and a tool's generated-with footer are refused by `abcd lint`'s privacy rule in any committed file, by record-lint's `harness_leak` rule in the record and the docs, and by `abcd lint outbound`, which judges a commit message or any text given to it. The build loop strips either shape from the pull-request title and body it posts. Nothing scrubs other posts, such as a hand-opened pull request, an issue or a comment, so re-read and strip those after creating them. (itd-152) +- **abcd names the product thinker or the technical facilitator, never the maintainer.** The command pages, rules, brief, principles, docs and rendered text say which of the two roles they mean, and docs-lint's banned-token list refuses the word maintainer. (itd-2609212137129937) +- **The rules loader teaches the shell hazards before shell work.** A SHELL domain is built on every rules load from the hazard registry the guard enforces, one lesson per entry and one recall term per command head; a repository's own `.abcd/guard.json` entries are taught marked `(repo)`, and a `guard.json` the guard refuses is named on stderr and never taught. A repository entry's `why` and `successor` are capped at 1,024 bytes, so one entry cannot crowd the other domains out of the injection budget; under a disabled registry each lesson opens `Hazard (guard off)` rather than claiming a refusal; and an override that withholds lessons names the repository's own among them. (iss-151, iss-2609300756163382, iss-2609300916451435, iss-2609300916459279, iss-2609300916465620) +- **An armed gitleaks reaches every scan.** Capture, history, memory, the launch scan, the privacy lint, `disembark pack` and the other write paths report what an opted-in gitleaks finds, not the history capture alone. With gitleaks armed but not installed, the launch scan and `pack` fail closed, the privacy lint errors, and the write paths write on the native scanner and name the gap in their receipt, `abcd implement record --transcript` included. (iss-2608291814575788, iss-2609301307566557) +- **The implement run log counts agents and says what it cannot see.** `abcd implement log` counts the agents a session's own `agent_start` and `agent_end` lines declare alive, refuses an `agent_start` past the session's ceiling, and takes a `ceiling_overrun` event; `abcd implement check` reports `agents_alive`, and `abcd implement report` counts overruns and their minutes per mode and session. `implement log` refuses a `lane_close`, `agent_start` or `agent_end` missing a field the report needs, and the report names lines lacking a required field (`missing_fields`) and events whose lines stop more than six hours before the run's last line (`coverage`). An agent started outside the log stays invisible to the count. (iss-2609240646542516, iss-2609240646549900, iss-2609240646555891) +- `abcd hook prompt-router --json` writes `{text, injected, active}`, naming the full active-domain set on every prompt, so a client that snapshots injected rules can drop a domain that left the set; the kill switch is an empty list, and a domain that leaves and returns is injected again. (iss-2608261550580260) +- A stored transcript records its route in `source_kind` (`native` or `import`) and the tool that produced it in a new `source_tool`, so an imported transcript keeps its source harness; records written before the split read under both labels without a rewrite. (iss-2608230752354928) +- `abcd build --session ` claims the intent in the shared run state when it creates the run, so another checkout building the same intent is refused at its peers check from the start; a build without `--session` holds no claim and says so. (iss-2609252050506863) +- `abcd launch manifests --tree public|dev [--root ]` runs the manifest lockstep check over a named tree, read-only, exiting 0 when consistent, 1 on drift and 2 when unreadable. (iss-2609261423222935) +- The filing-time match against the record runs on every route that files an issue: `abcd inbox promote`, the intent consistency pass, the reading ingest and the promote of a reading item, as well as `abcd capture`. (iss-2609281911024185) +- `abcd ahoy remote apply` and `abcd site setup` explain a missing gh and offer its Homebrew install, run only on a yes typed at a terminal; `--yes`, a piped answer and a run with no terminal decline with the command to run, and `abcd ahoy --remote` never installs. (iss-2609281911024838) +- `abcd capture wontfix --duplicates ` writes the typed `duplicates` link, checked for shape, self-reference and existence before anything is written. (iss-2609291118049254) +- record-lint's `stale_edge` rule flags a planned or draft intent whose `builds_on` or `blocked_by` names a superseded intent, naming the successor its chain ends at, and `edge_cycle` flags a `builds_on`/`blocked_by` cycle naming every record on it; both warn. (iss-2609300903497125) +- A committed `.githooks/prepare-commit-msg` writes the `Assisted-by:` trailer from `git config abcd.assistedBy` when git prepares a message, so a plain `git revert`, a cherry-pick, an amend or a squash reaches the attribution gate with its trailer; with the key unset it writes nothing, and it never writes `None`. (iss-2609251125591539) +- The prefer-sota principle, and the bundled OPINIONS rule that points at it, say a remedy proposed for an issue or chosen in an autonomous run cites its grounds, including a primary-source state-of-the-art check where the fix depends on outside practice. (iss-2609292159470796) +- The ready-intent and open-spec next moves say that closing the spec ships the intent when no other open spec names it. (iss-2609100508566033) + +### Fixed + +- **`abcd guard` blocks a recursive delete of the root or the home.** The bundled registry's `rm-rf-root-or-home` blocks `rm -rf` of `/`, `/*`, `~`, `$HOME` and `${HOME}` and their slash and star forms, and `rm-rf-working-directory` warns on `*`, `.`, `..`, `./*`, `../*` and `.*`, where a bare `rm -rf /` was allowed. The compare reads the spellings a shell resolves to the same place, bare and through `sh -c` or `bash -c`: repeated separators and `/./` segments, a `..` folded after the root, the home, `$PWD` or a relative start, a run of `*` as one star, a dot-led glob segment that can match `..` (bracket expressions included), trailing-slash globs such as `/*/` and `~/*/`, and a separator run before `$HOME`. (iss-2609282105242542, iss-2609290625482831, iss-2609290745243990, iss-2609290925320493, iss-2609290925333487, iss-2609290925346181, iss-2609290929129725, iss-2609291233390280, iss-2609300057462186) +- The root-or-home rule reads a variable operand as the set of texts it can print: its written spelling (`$HOME`, `"$HOME"`, `${HOME}`, a backslash-newline inside the name, a brace group), a default's or alternative's word however it is quoted (ANSI-C and locale strings included), a trim, replacement or substring that can leave only `/` or the home, indirect, positional and special parameters such as `$!`, and an expansion that can print nothing beside a root, so `rm -rf ${DIR:-$HOME}`, `rm -rf ${X%%*}/` and `rm -rf $!/` block while `${DIR%/}`, `${f%.txt}` and `${p##*/}` stay allowed. (iss-2609290321312087, iss-2609290419119456, iss-2609290426544292, iss-2609292320015665, iss-2609300009506126, iss-2609300009581165, iss-2609300057304812, iss-2609300057311045, iss-2609300057326778, iss-2609300057467536, iss-2609300651133651) +- A line that assigns `IFS`, directly or through a name built from an expansion in any place bash assigns through (`export`, `declare`, `read`, `printf -v`, `eval`, arithmetic and the rest), makes the root-or-home rule treat unquoted defaults, alternatives, trims, replacements and `$HOME` or `$PWD` as split, so `IFS=x; rm -rf ${U:-x/x}` blocks. (iss-2609300057318410, iss-2609300651115290, iss-2609300726507446, iss-2609300812525892) +- The root-or-home rule no longer blocks everyday clean lines: a positional slice such as `rm -rf "${@:2}"` reads as the parameters' value, and a colon default such as `rm -rf "${1:-build}"/*` is read without an empty value it cannot print, while `${@:-w}` and `${*:-w}` keep the empty value their parameter-count test allows. (iss-2609300651122268, iss-2609300651127327, iss-2609300726419415) +- A command name, subcommand or flag spelled with a bracket expression the guard cannot decide, such as `r[[:lower:]] -rf /` or `git clea[[:lower:]] -fd`, is compared with that span read as a star, so it blocks or warns as its expansion would. (iss-2609291233468970) +- The shell guard reads more of what bash runs: a parameter expansion is an unknown word, so a dash glued to a variable (`git push --$X`) or a variable in command position blocks as its command-substitution twin does; kill-by-search follows a search fed into `xargs kill` through an unquoted here-document or an inherited pipe; a here-document a substitution opens and never reads refuses the line; and a pending here-document beside an unterminated substitution no longer panics the tokenizer. (iss-2609251824244354, iss-2609270036253187, iss-2609290521415701, iss-2609290625381759) +- The bundled guard registry blocks `abcd source ledger --flip`, leaving the flip to a public citation to the person. (iss-2609252007448074) +- The guard's command page and hook help state that it adjudicates only the shell and question tool calls the hook manifest hands it, so a hazardous call through any other tool is neither checked nor warned about. (iss-2609091955574760) +- **A refusal no longer repeats a value a host payload chose.** The ideate recorder, lifeboat review, intent audit, the reading ingest, the intent consistency ingest, scribe, release, the implement loop's lane receipt and the memory page ingest describe a refused value by its length or redact it through the canonical scanner instead of quoting it; the memory writer seals the secret in a page filename it refuses; and the owed-audit listing withholds a dead-letter reason's tokens that name the local tier. (iss-2609090951295881, iss-2609290033521472, iss-2609290043245353, iss-2609290144116254, iss-2609290218032954, iss-2609290300462829, iss-2609290300464268, iss-2609290411321963, iss-2609252038344132) +- The secret scanner finds a token glued behind a letter, a digit or an underscore, in the percent-decoded and JSON-unescaped views too, so the launch scan, every store-before-commit redactor and refusal redaction seal it; a sweep that cannot be built fails those paths closed. (iss-2609290541525428, iss-2609290551363398, iss-2609290743362554) +- `abcd launch ship --changelog-json` scans the rendered changelog section and release page with the canonical scanner and refuses a secret, a key, or the caller's own home or identity with reason `privacy`, naming the kind and the line but never the matched text. (iss-2609290405381338) +- The payload byte scan reads more document metadata for a person's name: EXIF and TIFF person tags (Artist, Copyright, XPAuthor, CameraOwnerName) and a Canon MakerNote's owner name, IPTC person datasets and their text-keyed siblings, and PDF text strings written in hex or with octal escapes, so a short single-token name there is kept as a finding rather than dropped as chance. (iss-2609261659051539, iss-2609261831352258, iss-2609291653241690) +- The scanner no longer masks the repository owner's handle in an `owner/repo` slug that names a sibling repository on GitHub; the owner alone and other owners stay findings. (iss-2609291409053602) +- The privacy lint reads an escaped Windows home path at any escaping depth, record-lint's `harness_leak` rule reads the issue ledger, and Homebrew's Linux prefix reads as a system account rather than a person's home. (iss-2608301306580014, iss-2609290845269642) +- The public banlist gates the plugin surfaces the shipped artefact carries (`commands/`, `agents/` and `hooks/`), as it gates the README and `docs/`. (iss-2609261457358637) +- A custom secret pattern whose boundary-free form cannot compile no longer turns the scanner's junction search into a per-byte walk for the whole pattern set. (iss-191) +- **Output no longer prints a checkout's absolute path.** The status board and `abcd --json`'s `dir`, `abcd peers`, the capture verbs and the other surfaces show a path under the home directory home-relative and one outside it by its directory name, and the board's first line masks escape sequences and bidi controls in the checkout's name. (iss-2609251823560369, iss-2609281329007423, iss-2609281613094952, iss-2609281736483740) +- **Every file abcd trusts in `~/.abcd` is reached through the directory it judged.** A symlinked `~/.abcd` is refused by the machine credential store, the PATH-entry and cache-attestation records, the hook shims and the history registry, as the rules loader already refused it; each level below the home is opened by descriptor, and one every account can write or another account owns is refused; the status-line settings are read through the same check; the history registry loads and writes under the lock it took; and lock files are created owner-only. (iss-2609260958587561, iss-2609281017573862, iss-2609281129171021, iss-2609281310017733, iss-2609290656480443, iss-2609290656491358, iss-2609291246244867) +- Two abcd processes on one machine no longer make one refuse its own `~/.abcd` configuration as swapped: a file atomically renamed into place between the check and the read is judged afresh, up to eight times. (iss-2609290518278152, iss-2609291157309818) +- The append primitive refuses a symlink planted between its check and its open, the implement run state refuses a symlinked log and reads a claim whose session or lane is not a name as unreadable, and every lock descriptor is close-on-exec, so a child that outlives its parent no longer keeps a lock held. (iss-2609281229109140, iss-2609230720193756, iss-2609300109005165) +- ahoy's rewrites of `.abcd/config.json`, the `.gitignore` block and the agent-instructions marker block, and the release cut's CHANGELOG writes, run under a file lock; the store locks move onto shared primitives that still exclude an older binary, and the history store's lock gives up after two minutes instead of waiting without end. (iss-127, iss-129) +- The update notice is shown once across any number of concurrent session starts. (iss-2609300939590291) +- Transcript records are written owner-only (0600) under an owner-only chain, a records directory or legacy record left wider is narrowed, and a records directory another account owns is refused naming that account, without write wording on a read verb. (iss-2609012029343438, iss-2609291610432030, iss-2609291731336469) +- A symlinked `.abcd`, `.abcd/development` or `specs/` is refused rather than followed by the spec store, the ADR mint lock and scribe's run directory; the bare reading render lists its stages through the one root it opened; and the drain rule refuses a linked decision store. (iss-2609012037137250, iss-2609012043432648, iss-2609300841466575) +- `abcd update` creates its staging file exclusively and without following links, so a symlink planted at `.abcd.new` is removed, never written through. (iss-2609300055241043) +- `abcd ahoy install` on a cold cache writes no PATH entry a plugin update would strand and names the install one-liner to run first; it removes abcd-owned dangling PATH entries once its target works, never an unowned one; and a stale binary refuses before any write, the `--bin-dir` writability probe included. (iss-2609100506263330, iss-2609280932480608, iss-2609291942529461) +- After an update abcd says `abcd updated from X to Y` once, from the installer, `abcd update` or, for a swap the hook made unseen, the next session start; `abcd --version` and bare `ahoy` note when the session's plugin root differs from the running binary's. (iss-2609291942520919, iss-2609020113012227) +- ahoy's config gaps name the flag that answers them (`--visibility`, `--docs-target`, `--oracle-backend`, `--scan-deep`), a `--yes` run says up front that values are still asked, every JSON list renders empty as `[]` rather than `null`, an existing `.abcd/rules.json` is kept rather than replaced by the skeleton, and the drain-rule offer is asked only at a terminal, so a piped answer stream no longer shifts. (iss-2609120447486547, iss-2609120447487070, iss-2609281931185016, iss-2609300711394491) +- Consent questions no longer read standard input redirected from `/dev/null` as a terminal, and a gitleaks or trufflehog that PATH resolves inside the checkout no longer counts as installed. (iss-2609300905174086, iss-2609300905225841) +- The hook shims refuse a PATH candidate whose file is world-writable, and every salvage hook entry that runs the bootstrap declares a status message; the every-prompt entry (UserPromptSubmit) also declares a 120-second timeout, while the before-command (PreToolUse) and before-compaction (PreCompact) entries declare none and take the host's default. (iss-2609020352438590, iss-323) +- A repository route in `.abcd/config.json` with a malformed name or value is skipped with one sanitised diagnostic instead of taking every provider command down; `ahoy connect`, `ahoy credential` and bare `ahoy` name each skipped route; a route whose agent's role setting does not point at the routed connection is refused naming `oracle.roles.`; and an API answer that reports no model is refused, so every recorded call names what answered. (iss-2609300929557796, iss-2609300805090515, iss-2609291925582287, iss-2609300805371434) +- `abcd drain` hands a deferred record back when the checkout holds no release tag or only one older than its `deferred_after`, naming `git fetch --tags`, and refuses a candidate record with a duplicated key or an id its filename contradicts. (iss-2609300711394709, iss-2609300711402515, iss-2609300841407812) +- The build loop's records commit names the model the lane's receipts report in its `Assisted-by:` trailer and runs the repository's hooks; a zero-padded issue key is refused; quoted text in a lane brief can no longer close its fence; and a handed-back run names its run directory as the way out. (iss-2609301046433372, iss-2609301128211767, iss-2609301128253254, iss-2609301303434847) +- The blocked pre-start check settles a blocker whose supersession chain ends at an accepted ADR or in `disciplines/`; every backoff in the run log carries its reason and measured minutes; and `abcd implement report` counts a session that joined up to a minute before a window's mode was set in that window. (iss-2609300751191426, iss-2609231206196407, iss-2609240646544930) +- Under `--json`, an unknown flag is answered with the error envelope on stdout at exit 2, and `abcd update --json` writes one document on a refusal. (iss-2609292352131344, iss-2609282105241960) +- `abcd help --agent` refuses naming `abcd --help --agent`, the people block reads the same under `--help` and `--help --agent`, and the CLI reference says the second form adds the agents-and-hosts verbs. (iss-2609251645374557, iss-2609251645376019, iss-2609251645376219) +- The routing lines name a verb once, never `abcd abcd`; `abcd reading ingest --route` gives the output read's own refusal; `abcd site`, `site build` and `lint site` find the checkout from a subdirectory; a re-run of `launch ship` between the cut and the tag gives the release-in-flight refusal; embark's walk refusal names the lifeboat path; and `abcd ideate record` tells a reframed verdict from a killed one. (iss-2609251606543515, iss-2609251606553359, iss-2609251750202525, iss-2609252117203691, iss-2609252004013212, iss-2609100508573400) +- `abcd capture disposition` encodes hidden runes in its grounds and exit condition; `capture defer` past the same anchor rewrites that cycle's deferral instead of adding a second; `capture list` ends each row with a one-line summary; `abcd intent audit`'s issue drift names the ledger it read; the early spec-close impact refusal names `abcd intent plan --impact`; and `abcd inbox` names the sender of a report it cannot read. (iss-2609251823551349, iss-2609251823555125, iss-2609240307549105, iss-2609251235119402, iss-2609240646522330, iss-2609240133234244) +- The admission ordering gate refuses a hand-placed marker with no matching run directory and manifest, the widening-run summary stands down on a contested or unreadable admission, and a `resolved:` or `deferred:` label mid-sentence in an open question no longer counts as settled. (iss-2609251842111593, iss-2609251842112266, iss-2609260932374727) +- **The record gates read what they claim.** Two ADR files claiming one id are refused and the resolver names both; a byte-order mark is read alike by every frontmatter reader; a quoted null in `superseded_by` is a string on the lifeboat path and an empty collection there is no successor; a disposition whose item contradicts its directory is a blocker; a markdown-named link at a store root is reported; a non-markdown file in a lint config's `roots` is a configuration error; the three-tier layout check finds `NEXT.md`, `scratch/` and `logs/` in any case and at the `.abcd/` root, and `NEXT.md` at any depth of a committed tier; and no configured path may reach into `.git`. (iss-2609301000153822, iss-2608221126066379, iss-2608241347321758, iss-2608301744300631, iss-2608301203525338, iss-2609261208193041, iss-2609281045487620, iss-173, iss-2608291814578333) +- The plugin no longer lists `abcd:README` and `abcd:CHANGELOG` as agents, and record-lint's `agent_contract` defaults its prompt-version log to `.abcd/development/agents/CHANGELOG.md`, outside the directory a harness loads whole. (iss-110, iss-2609290630234596) +- The reading corpus's exclusion floor reads frontmatter to the same close as the canonical reader, a principle titled in setext form carries its title into a reading, and `abcd reading assemble` reports a run written outside the run directory as ingestable, with its ingest line. (iss-2609281627055603, iss-2609261140284421, iss-2609091648476051) +- The launch listing reads export attributes from the archived revision, as `git archive` does, and on a git too old to do so while the index differs it refuses with the remedy. (iss-2609260933592838) +- `abcd docs cite refresh` refuses a redirect from https down to plain http and queues the citation as blocked rather than broken. (iss-2609012037440084) +- Path redaction states its name boundary once, so the error scrub, the install receipt and the store redactors agree on a home path followed by `.`, `-old` or `_x`. (iss-2608292037564347) +- The bundled COMMITTING rules tell an agent to commit as the human, never a tool or bot identity, and to re-read and strip a session URL or generated-with footer from a pull request, issue or comment after creating it. (iss-2608210923437502) +- Command pages and help match the binary: the `disembark` hint lists `pack` and its other sub-verbs, `docs cite confirm --receipt` describes the receipt schema, bare `abcd lint` says it checks every target but outbound, `/abcd:decide` says it needs abcd 0.8.0 or later, the record dispatch says both id shapes resolve, the intent page says `grounds.redacted` is omitted when zero, the capture page states the resolve-on-the-carrying-branch convention and the rebased-series case of `capture reframe`, the ingest page carries the author-name conventions for a citation, and `prepare-this-repo` says the lint config `ahoy install` seeds is committed. (iss-2609240519413467, iss-2609240519418856, iss-2609282105240689, iss-2609061503374089, iss-2609120452369809, iss-2609151150180399, iss-2609190338070038, iss-2609261325441711, iss-2608210923438110, iss-2609240519427388) +- The terminology page describes the memory retrieval that shipped, the writing-style page names `harness_leak`'s own escape, the verification matrix uses the current audit and review names, and the brief names the twelve shipped verbs and agents it had no chapter for. (iss-2608221254560250, iss-2609020833531987, iss-2609231101102072, iss-2609300839021188) + ## [0.11.1] - 2026-09-28 These notes list what was added and what was fixed; changes to earlier behaviour are not claimed until the composer can see the previous release. diff --git a/RELEASE.md b/RELEASE.md index dfe485863..2d75e283e 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,45 +1,43 @@ -# Release 0.11.1 (2026-09-28) +# Release 0.12.0 (2026-09-30) -abcd makes sure the right person is the author of record before a single commit lands. `abcd ahoy` checks the identity a commit would actually carry, author and committer, whatever git config or environment produced it, against the identity the repository pins; when they diverge it proposes the pinned (or global) identity and asks before writing repo-local config, and with no one to ask it reports and writes nothing. (itd-131) +Any role can run through a command-line harness the operator names, with the same brief, contract and transcript store as the host's own sub-agent: `roles..runner` routes a role to the claude CLI or opencode runner the machine enabled, and where the runner is absent or fails the host takes the role, a receipt names the role, the runner, the reason and the route that ran, and the run summary counts fallbacks per runner and per role. The runners are proven against stand-in harnesses so far; no real claude or opencode binary has yet run a role. (itd-2609201916056194) -> "A sandbox `Test User` override authored 54 commits before anyone noticed — we had to rewrite history and force-push to unpick it," said Alice, who maintains the repo. "Now `ahoy` catches a wrong identity before the first commit, and it asks me rather than guessing." (itd-131) +> "My reviews were the scarcest thing in a run, and a second harness was sitting on the machine doing nothing," said a technical facilitator. (itd-2609201916056194) -A repository abcd manages declares what it ships, and the release flow follows the declaration. A Go application or a macOS app with its own tag-driven workflow declares its artefact kind once, `launch --dry-run` and `launch ship` run against it with the changelog-driven gate, the deferral read and the derived version, and `launch scaffold` lays the gate beside the release workflow the repository already has and leaves that workflow as it was. (itd-2609150819432059) +An OpenAI-compatible API adapter reaches a configured provider for the roles and judgements pointed at it, and serves only the models that provider's list allows: the adapter takes a base URL and a key name, a model left off the list is refused before any call, abcd bundles no vendor denylist, and the run record shows the model that actually answered. With no provider configured nothing changes. (itd-2609081951381895) -One verb sets up a managed repository's site: `abcd site setup` writes the composition, the render-then-deploy workflow and the environments and prints the step left, and with a hosting credential configured it creates and routes the host and reports the address. The site is abcd's own page set, rendered from that repository's record. (itd-2609061543533170) +> "I wanted one cheap decision model through OpenRouter, and I wanted to be certain nothing else of mine would ever go through it," said a product thinker configuring the first aggregator. (itd-2609081951381895) -> "The explorer, the graph, the timeline: I had them for abcd and wanted them for every repository abcd manages," said a product thinker looking at the record browser. "Now one verb writes the workflow and the environments, and when I have given abcd a hosting credential it creates and routes the host too. Any managed repo's site looks like abcd's, with its own record in it." (itd-2609061543533170) +One credential store, three homes, and every adapter reads through it: `abcd ahoy credential ` explains what a key unlocks and what works without it, then stores it where `--home` says, as a pointer to another tool's configuration or an environment variable, in the owner-only `~/.abcd/credentials.json`, or in the platform keychain, the home the explanation recommends. The abcd home refuses to write inside a git working tree. (itd-2609221017023290) -A new issue, or a draft intent filed as quoted text, is matched against the record at filing: a likely double is linked and named, and never dropped. (itd-2609212137116617) +Bare `abcd` and the site's Status page show Now, Next and Later, computed from the record and maintained by nobody: Now is what is in a lane and the head of the pick order, Next is every planned intent the readiness gate reports ready, and Later is the rest, a count on the text board and rows in `--json` and on the site. (itd-2609212103568351) -> "I filed the same finding twice a month apart and nobody noticed until a consistency pass," said a technical facilitator. "Now the capture tells me at filing that it looks like iss-N, writes the link, and leaves it to me to confirm. Nothing is refused: a wrong match is a link I remove, not a finding I lost." (itd-2609212137116617) +> "The phase documents told me what someone once thought would happen next; this tells me what is next," said a product thinker reading the board after retiring phases. (itd-2609212103568351) -The status-line badge always reads one of three states, `abcd-managed`, `waiting on the product thinker` or `waiting on the technical facilitator`; an agent's question to the human is refused until the mode says who is being asked, and the next human answer resets it. (itd-2609212130146198) +A change cannot call itself shipped while the brief lags the surface it delivered, and a release cannot be cut while an intent shipped since the last cut leaves its chapter behind: `abcd spec close` and the release cut refuse on a verb, sub-verb or agent no brief chapter names, and on a sentence a host-run reviewer confirms false, failing closed when no reviewer answers. `abcd docs fidelity` runs the same gate and can draft and apply the brief edit, flagged for review. (itd-60) -> "The badge was set by whichever agent remembered," said a product thinker who had watched it read managed while an agent waited on them. "Now an agent cannot ask me anything until it has said which of us it is asking, and the moment I answer the badge goes back. It is the one signal I have that something is waiting; now it is true." (itd-2609212130146198) +> "I read the verdict, not the source," said a product thinker shipping with abcd. (itd-60) -Consult any source freely and cite only by deliberate human choice: `abcd source` keeps a local-only corpus of material you are not free to name and an append-only ledger of what influenced which decision, citation needs the source's permission and your own flip of the ledger line, and `abcd source cite-check` clears text before it is shared, reporting offenders by key alone. (itd-76) +A cut release gets a retrospective: `abcd reflect ` runs an interview seeded by the intents the tag shipped, their audit notes and the release's changelog section, and writes `.abcd/development/retrospectives//README.md`, which a packed lifeboat carries with it. (itd-24) -> "I could never let an agent near my working papers before, because one helpful footnote could burn a collaborator's trust," said Alice, a researcher-developer. "Now it reads everything, records what influenced what, and cites nothing. When the paper behind a decision is finally published, I flip one flag — and the whole influence trail is already written." (itd-76) +> "abcd's brief and intents captured *what* I'd done," said Henry, a junior-developer persona. (itd-24) -Every shipped intent owes a fidelity review, and abcd now says which ones are still owed: bare `abcd intent audit` lists each with its receipt and the command that re-emits the request, `abcd intent` carries the count, and `abcd intent audit --owed` hands a host the owed requests oldest first, leaving them owed when no reviewer is reachable. Nothing refuses on the debt. (itd-2609150819445595, itd-53) +Before the planning interview, a coherence pre-pass reads a draft against the brief's invariants, the principles and a one-line index of every other intent: `abcd intent prepass ` writes the questions into the planning brief, each conflict quoting the invariant, each overlap with its four answers (keep both, bundle, supersede, refine), and any concern it cannot anchor asked as a question, never asserted as a conflict. (itd-42) -> "I asked what was outstanding and got a list of eight, with the command to re-emit each one," said Iris, a technical facilitator paying down a run's review debt. "Last week the same question was a grep through the decision log." (itd-2609150819445595) +> "I'd grill an intent and it would come out crisp — clear terms, testable acceptance — and still be quietly redundant with something I'd specced two months earlier," said Iris, product lead. (itd-42) -Intents that ship as one piece of work plan as a bundle: one shared spec, both records moving to `planned/` together and shipping together when the spec closes, with `abcd intent reclassify` to change a record's kind or supersede it. One glossary page now maps the record families (intent, spec, step, bundle, issue, release, status) and how each moves, with phase, milestone and roadmap marked superseded. (itd-34, itd-2609211913453478) +A bot-opened dependency bump whose diff is only a manifest and its lock file can be re-authored as the repository's owner, so it merges on its own: `abcd launch scaffold --dependency-reauthor` writes the workflow, the message names the bot and the workflow with `Assisted-by: None`, the attribution gate is untouched, and everything else is left alone. The workflow is proven offline; its first live bump waits on the repository's GitHub App. (itd-2609221842494980) -> "I kept asking which word to use, and every answer named a different document," said a product thinker who had just approved bundles and wondered whether phases still meant anything. "Now there is one page: intent, spec, step, bundle, issue, release, status. Phase and milestone are on it too, marked superseded, with what replaced them. I read it in five minutes." (itd-2609211913453478) +> "Every bump sat blocked with auto-merge armed, looking as though it wanted a review no reviewer could give," said a product thinker who had just landed one by hand at the end of a long day. (itd-2609221842494980) -A review names the commit it read, and the bare `abcd` board shows how far the default branch has moved since, flagging one past twenty commits. `abcd intent consistency` checks the brief and the intents against each other and files each contradiction as an issue, quoting both ends. (itd-28, itd-48) +A live agent-session URL and a tool's generated-with footer are kept out of committed text: `abcd lint`, record-lint and `abcd lint outbound` refuse either shape, and the build loop strips both from the pull-request title and body it posts. Other posts are not scrubbed, so a pull request, issue or comment opened by hand is re-read and stripped after it is created. (itd-152) -When a capability could use a program you have not installed, `abcd ahoy install` explains it first: what the program is, whether this capability needs it, what already works without it and the exact install step. It installs only on an explicit yes, and a no leaves the capability on its native default and says so. (itd-63) +Every place abcd writes names which of the two people it means, the product thinker or the technical facilitator, and the word maintainer leaves the vocabulary, refused by docs-lint. (itd-2609212137129937) + +> "Agents kept asking 'the maintainer' and I never knew if they meant me deciding what to build or me running the gates," said a product thinker. (itd-2609212137129937) Also in this release: -- An admission and a surprise are written by a verb, and the order the design fixes is a refusal (itd-2609020625400194) -- A reframe occasioned by a reading is recorded as a reframe, joined to what occasioned it, without carrying the construal it replaced (itd-2609020625402518) -- The scribe's context is assembled and its output is ingested by a verb, and the record can show that no session held both a reading and the ledger (itd-2609020625402599) -- A principle carries typed claims, its reference, its comparison and its evidence, its statement is readable cold, and it inherits only what held (itd-2609020625405170) -- abcd lab mechanises the lab conventions three hand-run experiments proved (itd-2609212137128014) +- An intent names the release it must land by, and the cut says whether it did (itd-2609212103572513) The line-by-line record of this release is its section in CHANGELOG.md. From 828ca629b806430909420c1d3d7d674666f96432 Mon Sep 17 00:00:00 2001 From: REPPL <77722411+REPPL@users.noreply.github.com> Date: Thu, 1 Oct 2026 00:15:30 +0100 Subject: [PATCH 6/8] chore: record the v0.12.0 release-gate receipts Assisted-by: Claude:claude-opus-5-5 --- .../docs-currency-reviewer.json | 223 ++++ .../iss35-brief-surface-crosscheck.json | 1063 +++++++++++++++++ 2 files changed, 1286 insertions(+) create mode 100644 .abcd/work/reviews/fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9/docs-currency-reviewer.json create mode 100644 .abcd/work/reviews/fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9/iss35-brief-surface-crosscheck.json diff --git a/.abcd/work/reviews/fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9/docs-currency-reviewer.json b/.abcd/work/reviews/fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9/docs-currency-reviewer.json new file mode 100644 index 000000000..10bd0cada --- /dev/null +++ b/.abcd/work/reviews/fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9/docs-currency-reviewer.json @@ -0,0 +1,223 @@ +{ + "subject": { + "digest": { + "gitCommit": "fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9" + } + }, + "verifier": { + "id": "docs-currency-reviewer@release" + }, + "timeVerified": "2026-09-30T23:15:30Z", + "verificationResult": "PROMOTE", + "judgeModel": "claude-fable-5-1", + "tier": "full", + "manifestHash": "sha256:62c165624c1e254075d752cb607b40375040a36eb854f57b635fe16c03106535", + "policy": { + "detector": "docs-currency-reviewer", + "version": "1", + "promptHash": "sha256:host-run-agent-harness-review-no-pinned-prompt", + "briefVersion": "0.12.0" + }, + "categories": { + "false-claim": 8, + "stale-record": 4, + "stale-count": 1, + "incomplete": 8, + "criterion-violation": 3 + }, + "_reviewProvenance": "Host-run docs-currency-reviewer (Fable 5.1, tier full) read the first roll b89784c4302dc68698714afbc708bb02ad78a52d, which differs from this content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9 only by 4b8ff2afa (the user-facing pages brought current: README.md, commands/ahoy.md, build.md, drain.md, guard.md, prepare-this-repo.md, update.md, version.md, docs/how-to/upgrade-to-v0.12.0.md, two CLI help sentences and their regenerated docs/reference/cli/commands.md, plus pinning tests), e8d5d0060, 4d634c4f0 and c8ddb0425 (the guard brief chapter 17-guard.md brought current after three docs-review HOLDs; the docs review of c8ddb0425 is PROMOTE), and the re-cut CHANGELOG, whose payload corrects dc-1 and dc-17. It found 24: four major (dc-1, dc-2, dc-5, dc-17), all fixed; eleven fixed in all; the thirteen remaining minors and nitpicks are deferred as one documentation record. Every finding carries its disposition.", + "failing": [ + { + "id": "dc-1", + "category": "false-claim", + "severity": "major", + "summary": "CHANGELOG.md:25: The breaking bullet says the run state file 'moves to schema version 4' and is 'rewritten at version 4'; the binary at this commit writes schema version 8 (versions 5-8 added validation, fix-round cap, landing and the runner record after the rename). v0.11.1 wrote version 1, so a v0.11 run is rewritten at 8, not 4.", + "disposition": "fixed", + "note": "Fixed in the re-cut CHANGELOG of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9 (the payload names schema version 8, internal/core/implement/loop/state.go:124); CHANGELOG.md:25." + }, + { + "id": "dc-2", + "category": "false-claim", + "severity": "major", + "summary": "docs/how-to/upgrade-to-v0.12.0.md:36-40: Same claim as dc-1 in the upgrade guide: 'the run's next abcd implement step or receipt writes the file at schema version 4' and 'An older abcd cannot read a version-4 file'. The next write is at schema version 8; a reader checking `schema_version` against this page will see 8.", + "disposition": "fixed", + "note": "Fixed in 4b8ff2afa (docs: bring the user-facing pages current for v0.12.0), an ancestor of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9; docs/how-to/upgrade-to-v0.12.0.md:37-41." + }, + { + "id": "dc-3", + "category": "false-claim", + "severity": "nitpick", + "summary": "CHANGELOG.md:37: 'docs-lint's banned-token list refuses the word maintainer' (and RELEASE.md:35 'refused by docs-lint'): the ban is a pattern in this repository's own `.abcd/docs-lint.json`, not a bundled docs-lint rule; no Go source carries the token, so a managed repository's `abcd lint docs` does not refuse it.", + "disposition": "deferred", + "note": "Captured as iss-2609302306281487 in this release's records commit, the one documentation record listing every deferred docs-currency minor and nitpick; fixed in the first lane after the tag." + }, + { + "id": "dc-4", + "category": "criterion-violation", + "severity": "nitpick", + "summary": "CHANGELOG.md:21: The section preamble says 'changes to earlier behaviour are not claimed until the composer can see the previous release', yet the two Breaking bullets (removed spellings, renamed JSON fields) are changes to earlier behaviour filed under `### Added`; the section has no `### Removed` or `### Changed` heading for a reader scanning for breakage.", + "disposition": "deferred", + "note": "Captured as iss-2609302306281487 in this release's records commit, the one documentation record listing every deferred docs-currency minor and nitpick; fixed in the first lane after the tag." + }, + { + "id": "dc-5", + "category": "false-claim", + "severity": "major", + "summary": "commands/build.md:49-50: The `key` check says an issue id is refused ('the issue key is not built yet'), contradicting the same page's lines 38-44 and the binary, which builds `build ` as an issue-keyed lane.", + "disposition": "fixed", + "note": "Fixed in 4b8ff2afa (docs: bring the user-facing pages current for v0.12.0), an ancestor of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9; commands/build.md:49-51." + }, + { + "id": "dc-6", + "category": "false-claim", + "severity": "nitpick", + "summary": "commands/ahoy.md:23-24: Page says a `status` argument is the bare detection pass; the binary has no `status` sub-verb and refuses any positional, so the word is a page-level convention the page does not mark as such.", + "disposition": "deferred", + "note": "Captured as iss-2609302306281487 in this release's records commit, the one documentation record listing every deferred docs-currency minor and nitpick; fixed in the first lane after the tag." + }, + { + "id": "dc-7", + "category": "stale-count", + "severity": "minor", + "summary": "commands/ahoy.md:15-19: 'install, uninstall, remote apply and connect are the four that change something' omits `ahoy credential --home ...`, which the page itself (lines 537-540) and the help say writes the chosen home.", + "disposition": "fixed", + "note": "Fixed in 4b8ff2afa (docs: bring the user-facing pages current for v0.12.0), an ancestor of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9; commands/ahoy.md:16-20." + }, + { + "id": "dc-8", + "category": "incomplete", + "severity": "nitpick", + "summary": "commands/ahoy.md:4: argument-hint omits the `credential` sub-verb documented at line 517.", + "disposition": "deferred", + "note": "Captured as iss-2609302306281487 in this release's records commit, the one documentation record listing every deferred docs-currency minor and nitpick; fixed in the first lane after the tag." + }, + { + "id": "dc-9", + "category": "incomplete", + "severity": "minor", + "summary": "commands/build.md:77-78: Exit 3 is described only for a peer holding the intent; the binary also exits 3 when the run state is locked.", + "disposition": "fixed", + "note": "Fixed in 4b8ff2afa (docs: bring the user-facing pages current for v0.12.0), an ancestor of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9; commands/build.md:78-79." + }, + { + "id": "dc-10", + "category": "incomplete", + "severity": "nitpick", + "summary": "commands/capture.md:4: argument-hint omits `mentions [--ref ]`, a sub-verb the binary has and the page documents at lines 289-292.", + "disposition": "deferred", + "note": "Captured as iss-2609302306281487 in this release's records commit, the one documentation record listing every deferred docs-currency minor and nitpick; fixed in the first lane after the tag." + }, + { + "id": "dc-11", + "category": "incomplete", + "severity": "nitpick", + "summary": "commands/capture.md:633-635: Says `widening_runs` is a key of the bare board's JSON; the top-level key is `reading_outstanding` (widening_runs sits nested inside it, omitempty).", + "disposition": "deferred", + "note": "Captured as iss-2609302306281487 in this release's records commit, the one documentation record listing every deferred docs-currency minor and nitpick; fixed in the first lane after the tag." + }, + { + "id": "dc-12", + "category": "incomplete", + "severity": "nitpick", + "summary": "commands/docs.md:4,75-118: `docs fidelity` takes a repeatable `--intent ` flag that the page and its argument-hint never mention.", + "disposition": "deferred", + "note": "Captured as iss-2609302306281487 in this release's records commit, the one documentation record listing every deferred docs-currency minor and nitpick; fixed in the first lane after the tag." + }, + { + "id": "dc-13", + "category": "incomplete", + "severity": "nitpick", + "summary": "commands/history.md:4: argument-hint spells `ingest [...]` without the required `--into ` the page (lines 261-266) and the binary require.", + "disposition": "deferred", + "note": "Captured as iss-2609302306281487 in this release's records commit, the one documentation record listing every deferred docs-currency minor and nitpick; fixed in the first lane after the tag." + }, + { + "id": "dc-14", + "category": "incomplete", + "severity": "nitpick", + "summary": "commands/implement.md:42-54: `implement join` also takes `--model` and `--reason`; the page documents only `--session`, `--role`, `--ceiling`.", + "disposition": "deferred", + "note": "Captured as iss-2609302306281487 in this release's records commit, the one documentation record listing every deferred docs-currency minor and nitpick; fixed in the first lane after the tag." + }, + { + "id": "dc-15", + "category": "criterion-violation", + "severity": "minor", + "summary": "commands/drain.md:1-5,219: The new page has no `argument-hint` in its frontmatter and no `**User input:** $ARGUMENTS` line, unlike every other command page, although the verb takes `--dry-run`, `--max`, `--pace`, `--sub-agents`, `--fix-rounds`.", + "disposition": "fixed", + "note": "Fixed in 4b8ff2afa (docs: bring the user-facing pages current for v0.12.0), an ancestor of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9; commands/drain.md:4,220-221." + }, + { + "id": "dc-16", + "category": "criterion-violation", + "severity": "nitpick", + "summary": "commands/ingest.md:4,119: Declares `argument-hint: ` but carries no `**User input:** $ARGUMENTS` line, so the argument is never handed to the page.", + "disposition": "deferred", + "note": "Captured as iss-2609302306281487 in this release's records commit, the one documentation record listing every deferred docs-currency minor and nitpick; fixed in the first lane after the tag." + }, + { + "id": "dc-17", + "category": "false-claim", + "severity": "major", + "summary": "CHANGELOG.md:84: 'every salvage hook entry that runs the bootstrap declares a 120-second timeout and a status message' is false for two of the three: only UserPromptSubmit declares 120; the PreToolUse and PreCompact salvage entries declare no timeout (the host's default) and the repository's own test pins them to none. The status-message half holds. (The resolved record iss-323's `resolution:` field repeats the same false claim.)", + "disposition": "fixed", + "note": "Fixed in the re-cut CHANGELOG of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9 (only UserPromptSubmit declares the 120-second timeout); CHANGELOG.md:84." + }, + { + "id": "dc-18", + "category": "false-claim", + "severity": "minor", + "summary": "commands/update.md:16-17: Claims `update` is the only command that reaches the release origin; `launch --dry-run --fetch-baseline` / `launch ship --fetch-baseline` fetch the tag's checksums.txt and plugin archive from the same origin, and hooks/bootstrap.sh downloads the release binary at session start.", + "disposition": "fixed", + "note": "Fixed in 4b8ff2afa (docs: bring the user-facing pages current for v0.12.0), an ancestor of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9; commands/update.md:16-19." + }, + { + "id": "dc-19", + "category": "false-claim", + "severity": "minor", + "summary": "commands/version.md:55-58: Enumerates the network-touching verbs as `update --check`, `update`, `docs cite refresh` and `memory ingest ` and says every other path reads only disk; the v0.12 binary also reaches the network on `launch --fetch-baseline`, `reading ingest --dispatch`, `ahoy connect` and `site setup`.", + "disposition": "fixed", + "note": "Fixed in 4b8ff2afa (docs: bring the user-facing pages current for v0.12.0), an ancestor of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9; commands/version.md:55-64." + }, + { + "id": "dc-20", + "category": "stale-record", + "severity": "minor", + "summary": "commands/prepare-this-repo.md:51,210-211: Describes the ADR store as 'MADR, sequential NNNN' and tells the target repo to file ADRs 'using MADR + NNNN'; ADRs now mint as `adr-` filed as `-.md`, only the legacy 0001-0058 keep ordinals.", + "disposition": "fixed", + "note": "Fixed in 4b8ff2afa (docs: bring the user-facing pages current for v0.12.0), an ancestor of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9; commands/prepare-this-repo.md:51-52,212." + }, + { + "id": "dc-21", + "category": "incomplete", + "severity": "nitpick", + "summary": "commands/launch.md:4: argument-hint lists dry-run, ship, archive, manifests and scaffold but omits the `receipts` sub-verb the binary exposes and the page documents at line 834.", + "disposition": "deferred", + "note": "Captured as iss-2609302306281487 in this release's records commit, the one documentation record listing every deferred docs-currency minor and nitpick; fixed in the first lane after the tag." + }, + { + "id": "dc-22", + "category": "stale-record", + "severity": "nitpick", + "summary": "commands/launch.md:1035: Refers to the project as 'abcd-cli'; the plugin manifest, README and every other page name it 'abcd'.", + "disposition": "deferred", + "note": "Captured as iss-2609302306281487 in this release's records commit, the one documentation record listing every deferred docs-currency minor and nitpick; fixed in the first lane after the tag." + }, + { + "id": "dc-23", + "category": "stale-record", + "severity": "minor", + "summary": "README.md:118-125: The sample bare `abcd` board omits the `status: Now N \u00b7 Next N \u00b7 Later N` line every abcd-managed checkout now renders (the sample shows `presence: abcd-managed ...`, so the line would follow); the example predates the Now/Next/Later block this release ships (itd-2609212103568351).", + "disposition": "fixed", + "note": "Fixed in 4b8ff2afa (docs: bring the user-facing pages current for v0.12.0), an ancestor of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9; README.md:126-131." + }, + { + "id": "dc-24", + "category": "stale-record", + "severity": "minor", + "summary": ".abcd/work/issues/resolved/iss-323-hook-salvage-entries-invoke-bootstrap-sh-with-no-timeout-bud.md:12: The resolved record's `resolution:` says every salvage entry (UserPromptSubmit, PreToolUse, PreCompact) declares a 120-second timeout; commit 6a40c898b (ruling CH1) later removed the 120 from PreToolUse and PreCompact, and the changelog line at CHANGELOG.md:84 was derived from this stale text (see dc-17).", + "disposition": "deferred", + "note": "Captured as iss-2609302306281487 in this release's records commit, the one documentation record listing every deferred docs-currency minor and nitpick; fixed in the first lane after the tag." + } + ] +} \ No newline at end of file diff --git a/.abcd/work/reviews/fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9/iss35-brief-surface-crosscheck.json b/.abcd/work/reviews/fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9/iss35-brief-surface-crosscheck.json new file mode 100644 index 000000000..4f82335ab --- /dev/null +++ b/.abcd/work/reviews/fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9/iss35-brief-surface-crosscheck.json @@ -0,0 +1,1063 @@ +{ + "subject": { + "digest": { + "gitCommit": "fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9" + } + }, + "verifier": { + "id": "iss35-brief-surface-crosscheck@release" + }, + "timeVerified": "2026-09-30T23:15:30Z", + "verificationResult": "PROMOTE", + "judgeModel": "claude-opus-5-5", + "tier": "full", + "manifestHash": "sha256:62c165624c1e254075d752cb607b40375040a36eb854f57b635fe16c03106535", + "policy": { + "detector": "iss35-brief-surface-crosscheck", + "version": "1", + "promptHash": "sha256:9a746004577ef2e42a0c3673f50c5c247724407714db0af1f310f6ab8cee1c9a", + "briefVersion": "0.12.0" + }, + "categories": { + "false-claim": 90, + "undocumented-surface": 8, + "fictional-layout": 7, + "criterion-violation": 6, + "stale-count": 18 + }, + "_reviewProvenance": "The manifest's forty-five pinned checkers (Opus 5.5, at most eight alive under the run's ceiling) ran tier full over the first roll b89784c4302dc68698714afbc708bb02ad78a52d, which differs from this content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9 only by the docs fix 4b8ff2afa, the guard chapter corrections e8d5d0060, 4d634c4f0 and c8ddb0425, and the re-cut CHANGELOG. Merged as the script's Merge phase does (where|claim[:60], first wins) into 129 unique findings, all valid at b89784c4 on an independent classification (Fable 5.1): 39 cycle, 87 standing, 3 user-facing, 4 behaviour. Eight are fixed before the content commit (the three user-facing and every 17-guard.md finding); x-025 and x-039/x-118 are captured; x-001 is design-record drift, the binary doing what v0.12.0's breaking change states; the rest of the design-record drift is deferred to the systematic brief pass iss-2609091956001547. Every failing entry carries a disposition.", + "failing": [ + { + "id": "x-001", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/01-ahoy.md:40-42 (abcd ahoy remote): claim: The four read-only modes are flags on the bare verb and 'the modes' former sub-verb spellings are unknown commands'. / reality: True for `ahoy dry-run`, `ahoy identity-check`, `ahoy providers` (each: unknown command, exit 2), but the remote report's former spelling `abcd ahoy remote` is still a live command: bare it prints the `ahoy remote` help and exits 0 (its short help says 'Writes nothing bare... refuses an unknown sub-verb'). The chapter never says what bare `ahoy remote` does, although its table lists `remote` as a shipped sub-verb. The shipped itd-2609212130136102 (ac-1) also records bare `ahoy remote` as markMoved, naming `--remote` and exiting 2. The binary does neither.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547; not a defect: bare `abcd ahoy remote` listing its sub-verbs and exiting 0 is the stated behaviour of v0.12.0's breaking change (CHANGELOG.md:26 under `### Added`, iss-2609251324599468), so the stale side is the shipped intent itd-2609212130136102's criterion ac-1 and 01-ahoy.md:40-42, not the binary." + }, + { + "id": "x-002", + "category": "fictional-layout", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/01-ahoy.md:213-270 (~/.abcd tree): claim: The ~/.abcd/ tree is the user-scope inventory ('the two are one list and must agree' with 05-internals/03-configuration.md). / reality: The tree leaves out three files abcd writes and reads in ~/.abcd/: `oracle-routing.json` (ahoy install's machine routing table, internal/core/ahoy/oracle_routing.go; the same chapter's gap table names ~/.abcd/oracle-routing.json), `statusline.json` (the status-line setting, internal/core/ahoy/statusline_detect.go) and `cache-attestation` (written by hooks/bootstrap.sh, read by internal/core/ahoy/cache_attestation.go; the same chapter's prose at ~line 280 names it). 03-configuration.md's own symlink paragraph lists all three as user-scope files.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: oracle_routing.go, statusline_detect.go and cache_attestation.go all exist at v0.11.1; the tree omitted them then too: stale prose." + }, + { + "id": "x-003", + "category": "undocumented-surface", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/01-ahoy.md:54-60 and :714-725 (abcd ahoy uninstall): claim: Uninstall removes the marker block, abcd's own PATH entry where it owns it, and the provenance record, and leaves `.abcd/` intact. / reality: Uninstall also rewrites the harness's settings.json. It restores the statusLine command that was there before install pointed it at abcd (internal/core/ahoy/apply.go:1633 `receipt.StatusLine = uninstallStatusLine()`, internal/core/ahoy/statusline_apply.go:271). commands/ahoy.md documents this ('`ahoy uninstall` restores the previous command'). The brief chapter never mentions this write in either uninstall description.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: uninstallStatusLine present in internal/core/ahoy at v0.11.1 and HEAD; chapter never mentions the settings.json restore: stale prose." + }, + { + "id": "x-004", + "category": "undocumented-surface", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/01-ahoy.md:687-693 (bare abcd ahoy status board): claim: The bare status board prints: folder kind, plugin-root status, root SHA, install mode, vintage and staleness, the superseded-root note, citation coverage, the gap count, and on a repo guard health and the banlist block with its reach. / reality: The shipped board (`bin/abcd-darwin-arm64 ahoy`) also prints a `statusline:` row (installed/foreign/no-harness; signals.statusline in the JSON) and a `provider:` row. The chapter's list of board contents leaves out the statusline row.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: `abcd ahoy` prints a statusline row now and the ahoy report carried statusline at v0.11.1: stale prose." + }, + { + "id": "x-005", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/03-embark.md:192: claim: Acceptance: when the unpack runs on a conflict-free target, \"the four record families land at their canonical locations under the target\". / reality: The unpack writes five record families: embarkFamilies in internal/core/lifeboat/embark_types.go:318 lists adrs, issues, intents, specs and retrospectives. The same chapter says \"The five record families\" at line 102, and commands/embark.md lists five (ADRs, issues, intents, specs, release retrospectives). The acceptance criterion's count is stale from before retrospectives were added (itd-24).", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: embarkFamilies gained retrospectives in the cycle (0 hits at v0.11.1, 5 at HEAD; itd-24 shipped in the cycle); acceptance count not updated: stale prose." + }, + { + "id": "x-006", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/03-embark.md:85: claim: \"The write runs under the target's issue-ledger lock (when it writes an issue) and then its intent store's lock, the order every writer holding both takes\"; the late-arrival example names only a capture or an intent mint. / reality: The write takes three locks: the ledger lock, then the intent store's lock, then the spec store's lock (intent.WithLedgerThenMintLock in internal/core/intent/ledgerlock.go:93-100, called from internal/core/lifeboat/embark.go:114; the comment at embark.go:102-107 says \"then its spec store's\"). A spec minted in the target between the plan and the write is also rejudged as a conflict. The brief leaves out the spec store's lock and the spec-mint case.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: WithLedgerThenMintLock with the spec-store lock exists at v0.11.1; brief omits it: stale prose." + }, + { + "id": "x-007", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/04-launch.md:466-472 (Bump-tier rule table) and :742-745 (acceptance: additive -> minor, breaking -> major): claim: Major = any shipped intent carries impact: breaking; Minor = no breaking and at least one additive; Patch = only fix. Acceptance: given an additive intent and no breaking, the tier is minor; given any breaking intent, the tier is major. / reality: The shipped policy (internal/core/changelog/version.go DeriveNext) has a pre-1.0 row the brief omits: from a 0.x base, breaking -> minor++ and additive -> patch++, and no input can derive 1.0.0. The reported tier is computed from the version delta (internal/core/launch/semver.go BumpTier; internal/surface/cli/ship.go:126), so on this 0.x repository an additive-only cut reports tier 'patch' and a breaking cut reports 'minor'. The brief's table and both acceptance criteria are false for every cut abcd currently makes.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: version.go pre-1.0 rows present at v0.11.1; brief's tier table and acceptance never had them: stale prose." + }, + { + "id": "x-008", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/04-launch.md:473-477: claim: At release, the cut gathers the intents shipped since the previous release and takes the highest-severity impact. A change not tied to any intent falls back to conventional-commit derivation. / reality: No conventional-commit derivation exists anywhere in internal/core/changelog, internal/core/release or internal/core/launch. changelog.Derive takes the maximum impact over every record that entered a terminal folder since the anchor tag (ShippedSince: intents and resolved issues alike), and a cut with no bump-driving record is refused as empty-cut (release/emit.go), never derived from commit messages.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: No 'conventional' derivation in changelog/release/launch at either ref: stale prose." + }, + { + "id": "x-009", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/04-launch.md:492 (refusal-kinds table, stale-intent row): claim: stale-intent is raised when an intent in planned/ has a spec that has closed. / reality: internal/core/release/emit.go:98-100 and staleRefusal: stale-intent fires only when an intent in planned/ has NO open spec left, i.e. every spec realising it has closed ('an intent whose every spec has closed is still in planned/'). A planned intent with one closed spec and another still open does not trip it.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: staleRefusal at v0.11.1 already fired only when every spec closed: stale prose." + }, + { + "id": "x-010", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/04-launch.md:57, :148, :640, :705: claim: itd-72 is a live, separately scheduled design target: 'the remaining release automation is separately scheduled (itd-70 retention, itd-72 publishing)'; 'Commit, tag and publish stay a design target (itd-72's publishing)'; the release commit message format is 'a full-cut design target (itd-72)'; abcd's own publishing automation stays a design target (itd-72). / reality: itd-72 is in .abcd/development/intents/superseded/ (superseded_by: adr-37, 2026-09-20): publishing moved into CI behind the changelog-driven gate (release.yml / auto-release.yml), and the record states every criterion is met in another shape or moot. Nothing schedules it; the brief cites a superseded intent as pending work.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: itd-72 in superseded/ at v0.11.1; brief cites it as pending: stale prose." + }, + { + "id": "x-011", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/05-intent.md:3: claim: Remaining backing intents sit in `intents/planned/` (itd-27 grill, itd-34 kinds, itd-50 audit loop) / reality: Only itd-50 is in planned/. itd-27 is in superseded/ (superseded_by: itd-94) and itd-34 is in shipped/ (.abcd/development/intents/superseded/itd-27-grill-skill-and-glossary.md, .abcd/development/intents/shipped/itd-34-three-intent-kinds.md)", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: itd-27 superseded and itd-34 shipped at v0.11.1: stale prose." + }, + { + "id": "x-012", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/05-intent.md:82: claim: bundle-member examples itd-20, itd-24, itd-63, itd-69 (bundle `spc-83-operator-surfaces`, in `planned/` \u2014 committed but unscheduled, named in no phase doc) / reality: None of the four is in planned/: itd-24, itd-63 and itd-69 are in shipped/, and itd-20 is in superseded/ (superseded_by: itd-121)", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: itd-20 superseded, itd-24 shipped in the cycle, itd-63/69 shipped at v0.11.1; already false then: stale prose." + }, + { + "id": "x-013", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/05-intent.md:309, :436: claim: The grill step is backed by itd-27, located in `intents/planned/` ('per itd-27, `intents/planned/`'; 'backing intent itd-27, `intents/planned/`') / reality: itd-27 is in intents/superseded/ (superseded_by: itd-94), so the grill has no planned backing intent. The later-phase marker on the grill stands; the location cited for its backing intent is wrong", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: itd-27 in superseded/ at v0.11.1: stale prose." + }, + { + "id": "x-014", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/05-intent.md:72, :177: claim: the canonical build order is the phase plan at `roadmap/phases/` / reality: .abcd/development/roadmap/phases/README.md opens 'Retired on 2026-09-21 (adr-2609212115255771): phases and milestones are no longer units of the record ... not maintained'. The shipped order is dependencies plus shelves: Now/Next/Later, and `abcd build next` picks the next intent. This chapter cites the same ADR itself at lines 73 and 93", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: roadmap/phases/README.md carried 'Retired on' at v0.11.1: stale prose." + }, + { + "id": "x-015", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/05-intent.md:151, :168, :492: claim: 'the first seven disciplines' follow the template and 'the seven written since (itd-190 onwards)' use `## The rule`; 'Fourteen disciplines are in the tree'; 'seven of the fourteen disciplines carry no [Acceptance Criteria] section' / reality: disciplines/ holds 15 records (the bare `abcd intent` status reports `disciplines 15`). Seven use `## Rule` (itd-1, 5, 37, 79, 81, 84, 140). Eight use `## The rule`/`## The gate` (itd-190, 191, 192, 193, 195, 196, 197, itd-2609251624540864), and those eight have no `## Acceptance Criteria`", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: disciplines/ held the same 15 records at v0.11.1 (16 tree entries incl. README); count of fourteen stale then: stale prose." + }, + { + "id": "x-016", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/05-intent.md:496: claim: stale_edge and edge_cycle stay at warn because 'this tree carries five findings': drafts itd-22 (`blocked_by`) and itd-33 (`builds_on`) name superseded itd-2, plus three mutual-builds_on cycles / reality: itd-22 and itd-33 no longer name itd-2 in any edge (itd-33: blocked_by [itd-121], builds_on [itd-2609201916151817, itd-22]; both bodies record that the itd-2 edge was dropped). So stale_edge has zero findings. A walk of builds_on+blocked_by finds only the three cycles, and in one of them itd-2609201916056194 is now in shipped/", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: itd-22/itd-33 edges identical at both refs; the itd-2 edge was already dropped: stale prose." + }, + { + "id": "x-017", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/05-intent.md:401-407, :420-422: claim: Scope Conditions: 'An absent section (no conditions AND no nullity) exits the gate non-zero, naming the field'. Grounds: 'Required at the readiness gate for a press-release intent'. Scope conditions are 'mandatory with an explicit nullity \u2014 enforced by the claim-recording-gradient discipline' / reality: In internal/core/intent/ready.go, scopeConditionsCheck and groundsCheck are built with `Advisory: true`, and Ready ignores advisory rows. A failing scope-conditions or grounds row never makes `abcd intent ready` exit 1. The chapter's own row at line 314 says these are advisory and never withhold readiness", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: ready.go Advisory: true rows unchanged since v0.11.1; chapter's own line 314 agrees: stale prose." + }, + { + "id": "x-018", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/05-intent.md:498: claim: `surface_history` entries are well-formed; 'Lint code `IL012` (severity: warn)'. The bullet is not marked (convention), and line 490 says each unmarked invariant names what holds it / reality: No IL012 exists in any Go source, in .abcd/record-lint.json or in 05-internals/06-lint.md. No non-test Go code reads `surface_history`, so nothing checks this invariant", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: IL012 absent from Go, record-lint.json and 06-lint.md at both refs: stale prose." + }, + { + "id": "x-019", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/05-intent.md:15, :508: claim: Every superseded file records `kind_at_supersession`; `kind_at_supersession` is (convention) and 'every record in `superseded/` carries it' / reality: Three of the 13 superseded records have no kind_at_supersession key: itd-17, itd-27 and itd-58", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: itd-17/27/58 lack kind_at_supersession at both refs: record convention not met, prose overclaims." + }, + { + "id": "x-020", + "category": "fictional-layout", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/05-intent.md:495: claim: Intents in `superseded/` with `kind_at_supersession: bundle-member` carry `bundle: null` AND `bundle_at_supersession: ` / reality: superseded/itd-20-top-level-abcd-dispatcher.md has kind_at_supersession: bundle-member, still carries `bundle: spc-83-operator-surfaces`, and has no bundle_at_supersession. Only itd-32 matches the stated shape", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: itd-20 superseded record unchanged since v0.11.1 with bundle still set: stale prose." + }, + { + "id": "x-021", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/05-intent.md:308: claim: 'A leading quote always creates \u2014 never falls through to bare render' / reality: `abcd intent \"\"` refuses at exit 2 with nothing created in two cases: a lone word with no space (internal/surface/cli/cli.go loneBareToken: 'a lone word is read as a sub-verb, never as a draft title'), and text near a sub-verb name (a did-you-mean refusal). The verb's help and commands/intent.md summarise it as 'refuses a lone word', but this chapter never mentions the refusal", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: loneBareToken refusal exists at v0.11.1; chapter never mentions it: stale prose." + }, + { + "id": "x-022", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/05-intent.md:91: claim: The existing ADR store is described as `.abcd/development/decisions/adrs/`, `NNNN-.md`, zero-padded / reality: ADRs now mint as `-.md` through the shared record-id seam (for example 2609301720596683-abcd-adds-a-missing-site-label-....md, and the adr-2609212115255771 this chapter links). The zero-padded NNNN names survive only as the legacy ordinals 0001-0058. The itd-44 diversion is marked later-phase, but this sentence describes the existing store", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: 20 stamped ADR filenames at v0.11.1 already; chapter still describes NNNN: stale prose." + }, + { + "id": "x-023", + "category": "criterion-violation", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/05-intent.md:559-593: claim: Unmarked present-tense description of the itd-50 audit-loop policy: an `audit_mode` frontmatter key with record-only/loop-to-acceptance, `audit_budget`, the UNACHIEVABLE rollup and replan block, and a verification receipt at `.abcd/.work.local/logs/audit/verify-/receipt.json` with offered/accepted/rejected_wrong_criteria states that 'the drainer stamps' / reality: itd-50 is still in planned/. No non-test Go code reads audit_mode or audit_budget, and nothing writes a verify- receipt or the rejected_wrong_criteria state. 05-internals/03-configuration.md marks the same feature '(staged: itd-50)', saying 'no validator reads them' and that the drainer layer 'does not exist'. This section carries no staged marker", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: itd-50 planned and audit_mode/audit_budget unread at both refs; section unmarked: stale prose." + }, + { + "id": "x-024", + "category": "undocumented-surface", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/06-capture.md:61-87 and :294-300 (fast path and its refusals): claim: The fast path `/abcd:capture \"\"` is described with its refusals: a missing remedy, the automatic filers' remedy value from a person, a found-at path that does not resolve or leaves the checkout, and malformed flag values. A short text is said only to skip the match (fewer than eight distinct terms files the record unlinked). No other refusal of the text itself is stated. / reality: The shipped verb also refuses a one-word text. `abcd capture frobnicate --remedy x` exits 2 with `unknown capture subcommand \"frobnicate\" (nothing captured \u2014 a lone word is read as a sub-verb, never as issue text; issue text must contain a space ...)` (internal/surface/cli/cli.go:4608). The verb's own one-line summary says it (`refuses a missing --remedy, a lone word or no checkout`, in commands/capture.md:3 and `abcd capture --help`). No brief chapter mentions the lone-word refusal: a grep of .abcd/development/brief for 'lone word' or 'must contain a space' finds nothing.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: 'must contain a space' refusal in cli.go at v0.11.1; brief chapter omits it: stale prose." + }, + { + "id": "x-025", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/06-capture.md:294-300: claim: Every refusal of a ledger verb's own input exits 2 with nothing written, including an id the ledger does not hold, on resolving, marking wontfix, promoting, deferring, linking and the capture write alike. / reality: The exit code matches, but in a checkout with no ledger, a refusal over an unknown id writes to the tree. This was run in a scratch git repo with no `.abcd/`. `capture resolve iss-999 note --impact fix`, `capture wontfix iss-999 because`, `capture link iss-999 --blocked-by iss-998`, `capture defer iss-999 --after v0.1.0 --reason r`, `capture promote iss-999` and `capture remedy iss-999 \"...\"` each exit 2. Each also leaves `.abcd/work/issues/.iss-alloc.lock` behind, creating the directory chain too (lock name from internal/core/capture/alloc.go:19). abcd's own .gitignore:48 ignores that lock, so the leftover is invisible in this repository. In another repository it shows up as an untracked file. Refusals caught before the lock is taken leave nothing: a missing --impact and the lone-word refusal both leave the tree empty.", + "disposition": "deferred", + "note": "Behaviour finding captured as iss-2609302305500526 in this release's records commit; fixed in the first lane after the tag. Probable defect: a ledger verb's refusal of an unknown id exits 2 but leaves .abcd/work/issues/.iss-alloc.lock and its directory chain (reproduced at b89784c4 in a bare git repository; alloc.go unchanged since v0.11.1)." + }, + { + "id": "x-026", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/07-memory.md:20: claim: The surface traces to itd-36, \"which sits in `intents/planned/`\". / reality: itd-36 is at .abcd/development/intents/shipped/itd-36-memory-unification.md, closed as delivered on 2026-09-21. No copy exists in intents/planned/. The same file's own References (line 160) links the shipped/ path, so the page contradicts itself.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: itd-36 in shipped/ at v0.11.1: stale prose." + }, + { + "id": "x-027", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/07-memory.md:151-154: claim: Tight coupling: itd-36 is structurally non-decomposable, because the sub-verbs need the schema, the schema needs the curator role, and the curator role needs the lint codes. A partial ship is not meaningful. / reality: The sub-verbs (bare, ingest, ask, lint) and all seven lint codes ship on the binary (abcd memory --help; internal/core/memory/lint.go defaultSeverities), yet the same page (lines 129-130) says the curator role on principle-distiller is not built. itd-36 was closed as shipped with three criteria split out into their own issues (iss-2609211905340006, iss-2609211905346507, iss-2609211905347458). So the surface did ship without the curator role, and ship partially, which the non-decomposability claim says cannot happen.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: itd-36 shipped 2026-09-21 with criteria split out; non-decomposability claim stale then: stale prose." + }, + { + "id": "x-028", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/08-abcd.md:264: claim: The design-target banner anchors the unbuilt board on \"itd-20, `intents/planned/`, `spec_id: null`\" (and line 327 says the dev-sync terminal state is \"recorded here and in itd-20\"). / reality: itd-20 is not planned: it lives at .abcd/development/intents/superseded/itd-20-top-level-abcd-dispatcher.md, and `abcd itd-20` reports \"(intent, superseded) ... superseded_by: itd-121\". The chapter's own Related-documentation link (line 341) already points into superseded/, so the banner contradicts both the record and the chapter.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: itd-20 superseded at v0.11.1: stale prose." + }, + { + "id": "x-029", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/08-abcd.md:266-269: claim: \"The shipped status path reads `.git`, `.abcd/development` and the three work tiers, and nothing else: no visibility, no disembark log, no dev-sync record, no logbook, no linked intents, no spec store, and no thresholds, walks or timeouts.\" / reality: The shipped bare board (`abcd`, `abcd --json`) also reads the mode file (statusline), sibling worktrees and branches (peers), .abcd/work/reviews/ with a threshold of 20 (`reviews.threshold: 20`), the oracle-routing files, the user inbox, and the intent and spec stores through the readiness gate (the `status` block's now/next/later with `failing_checks` such as spec_link/spec_body). The chapter's own 'What ships today' section documents all of these, so 'nothing else ... no linked intents, no spec store, no thresholds' is false for the shipped path.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: board_status.go does not exist at v0.11.1; the board's peers/mode/reviews/readiness reads landed in the cycle without the chapter: stale prose." + }, + { + "id": "x-030", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/08-abcd.md:269-270: claim: \"There is no alias routing either: `status` and `help` route to no render.\" (and line 336: \"Nothing routes them today.\") / reality: `abcd help` is routed: it prints the grouped verb list and exits 0 (verified; the chapter's own line 81 says so). Only `abcd status` is refused (`abcd: unknown command \"status\" for \"abcd\"`, exit 2). The accurate claim is that neither routes to the board, not that neither routes to any render.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: `abcd help` routing present at v0.11.1; chapter's own line 81 says so: stale prose." + }, + { + "id": "x-031", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/08-abcd.md:96-99: claim: `consult` and `ingest` \"run as host-side markdown over the sources corpus, and reach the binary only through the `source` verb\". / reality: commands/ingest.md:43-45 also instructs the agent to run `abcd mode product-thinker` / `abcd mode facilitator` (a write to .abcd/.work.local/mode) during a confidential ingest, so ingest reaches the binary through `mode` as well as `source`.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: commands/ingest.md gained the `abcd mode` step in the cycle (0 hits at v0.11.1): stale prose." + }, + { + "id": "x-032", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/10-docs.md:117-125: claim: Arming the lint's release-gate mode from a release is a design target: 'Nothing in the release machinery passes it. The release workflow's docs-currency step, CI's, and the docs-lint make target each run the lint in its plain mode, the scaffolded release template names the verb nowhere ... The promotion is reachable only by a human typing the flag.' / reality: The release workflow passes the flag: .github/workflows/release.yml:148 runs `go run ./cmd/abcd lint docs --release-gate` as its 'Docs-lint (docs-currency gate)' step. The scaffold renders that step from internal/core/launch/scaffold/substitutions.go:13-18 (abcdExtraGates: 'The docs lint runs with --release-gate here, and only here'), so the release-gate mode is already armed in the release. Only ci.yml:411 and Makefile:245 (docs-lint) run the plain mode.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: release.yml and scaffold substitutions carry --release-gate at v0.11.1: stale prose." + }, + { + "id": "x-033", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/10-docs.md:51-53: claim: The citation refresh 'fetches every cited URL once' and 'Each URL gets exactly one bounded attempt'. / reality: A cited URL with a current manual (human-confirmed) receipt is kept as it is and never requested. internal/core/cite/refresh.go:122 says 'A current MANUAL receipt is preserved verbatim and its URL is not even requested', and the result counts it under `preserved` (StatusPreserved), apart from `fetched`. So not every cited URL is fetched.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: refresh.go preserves manual receipts at v0.11.1: stale prose." + }, + { + "id": "x-034", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/10-docs.md:112-114: claim: 'The working verbs accept the docs-lint.json to load and the repo to work over; the bare citation parent only routes and takes neither.' / reality: Only `abcd docs cite confirm` and `abcd docs cite refresh` take --config/--root. The other working verbs under `abcd docs`, `abcd docs fidelity` (flags --apply, --autonomous, --intent, --report) and `abcd docs fidelity record` (--verdict-json), take neither, as this chapter's own generated appendix and `--help` show. The claim holds only when read as limited to the citation verbs.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: docfidelity.go absent at v0.11.1; the flag set landed in the cycle: stale prose (claim only true of cite verbs)." + }, + { + "id": "x-035", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/11-history.md:236-238: claim: The prompt-router entrypoint (UserPromptSubmit) drains one entry and at most half a megabyte per prompt. / reality: internal/surface/cli/cli.go:2076 sets livePromptDrainBudget = DrainBudget{MaxEntries: 1, MaxBytes: 512<<10}, but DrainBudget.exhausted (internal/core/history/staging.go:193-201) always admits the first entry whatever its size (attempted == 0 returns false). With MaxEntries 1 the byte cap therefore never binds: a prompt drains one staged transcript of any size (e.g. a multi-megabyte session), so 'at most half a megabyte per prompt' is not a bound the code enforces.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: DrainBudget.exhausted attempted==0 short-circuit is deliberate per its comment (a pass must make progress), unchanged since v0.11.1: prose overstates the byte cap, not a code defect." + }, + { + "id": "x-036", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/11-history.md:99: claim: The listing's text render ends with the same one line [the session-separation summary]. / reality: internal/surface/cli/history.go:127-136: when the listing is empty the text render prints 'abcd history \u2014 no transcripts stored for this repo' (or the named-session variant) and returns before the separation line is written, so an empty `abcd history list` does not end with the separation line (the 'unobserved' case the brief says it reports).", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: history.go empty-listing early return at v0.11.1: stale prose." + }, + { + "id": "x-037", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/11-history.md:333-335: claim: The corpus has three write paths that all redact: the explicit capture, the explicit drain, and the automatic session-start drain; the migration is a fourth. / reality: More shipped paths write redacted records into the store: `abcd history ingest` (internal/core/history/ingest.go:440 calls Capture), `abcd history capture --all`, the live per-prompt drain from `abcd hook prompt-router` (internal/surface/cli/cli.go:2108, described in this same chapter at line 236), and `abcd build`'s runner transcripts (internal/surface/cli/build.go:581/836 -> internal/core/runner/transcript.go:30 history.Capture); `history migrate --apply` also rewrites records. The count of three (plus one) is stale.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: ingest.go and the live prompt drain wrote records at v0.11.1 already (runner transcript added in cycle): count stale then." + }, + { + "id": "x-038", + "category": "false-claim", + "severity": "minor", + "summary": "abcd history separation (--help Short) vs .abcd/development/brief/04-surfaces/11-history.md:176-183: claim: Brief: every history verb reaches the store through one resolve seam that creates the store chain when absent and moves a legacy corpus into it (so read verbs are not side-effect-free). / reality: The brief matches the code (history.SessionSeparation -> List -> Resolve, internal/core/history/separation.go:62-63, history.go:460-461), but the shipped `abcd history separation --help` says 'Writes nothing; never refuses' \u2014 it writes a missing store / moves a legacy corpus like list/show/staged, and it refuses outside a git checkout via historyStore. The shipped surface and the brief disagree on this verb's side effects; the brief's side-effect paragraph also names only list, show and staged.", + "disposition": "fixed", + "note": "Fixed in 4b8ff2afa (docs: bring the user-facing pages current for v0.12.0), an ancestor of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9; internal/core/surface/sentences.go:162-163 and internal/surface/cli/history.go:169-173 (regenerated docs/reference/cli/commands.md:1390-1398)." + }, + { + "id": "x-039", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/12-version.md:147 (generated surface appendix; generator internal/core/surface/appendix.go:84 HostDelegatedSentence): claim: \"It ships as a host-delegated command page: the command tree registers no `abcd version` verb, so there are no flags and no sub-verbs to list.\" / reality: /abcd:version is not host-delegated: commands/version.md runs the binary's root flag (`abcd --version --json`), the root carries a `--version` bool flag (listed in 08-abcd.md's appendix), and .abcd/record-lint.json's host_delegated list is only consult, ingest, prepare-this-repo. The chapter's own prose (lines 8, 32, 78-79) says the surface is a root flag and names only consult/ingest/prepare-this-repo as host-delegated, and internal/surface/cli/staleusage.go:87 answers `version` as \"a root flag, not a verb\". The generator labels every shipped register row without a registered verb as host-delegated, so this appendix misclassifies the surface and its \"no flags\" wording hides the --version flag the chapter documents.", + "disposition": "deferred", + "note": "Behaviour finding captured as iss-2609302306003610 in this release's records commit; fixed in the first lane after the tag. Generator defect: HostDelegatedSentence (internal/core/surface/appendix.go, new in the cycle) labels every verb-less shipped register row host-delegated, so the generated 12-version.md appendix calls /abcd:version host-delegated." + }, + { + "id": "x-040", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/12-version.md:15-17: claim: \"For one release the retired verb answers with the flag, or with the check when asked for it, and exits non-zero.\" / reality: The retired verb does not answer with the flag's report or run the check. `abcd version` prints `unknown command \"version\"` and `abcd version --check` prints `unknown flag: --check`. Both then print the same fixed redirect line from staleusage.go:87 (\"`version` is a root flag, not a verb: run `abcd --version` (asking for a newer release is the update verb's --check); /abcd:version runs it\") and exit 2. The answer is the same whether or not --check is passed; nothing tells the two cases apart. The exit-non-zero half holds.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: Root-flag redirect in staleusage.go is new in the cycle; `abcd version --check` prints the same fixed line: brief written against a shape the code never had: stale prose." + }, + { + "id": "x-041", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/12-version.md:77-81: claim: The pages that document no verb, whose token gets a what-it-is line in place of a stale-binary remedy, are listed as the dispatcher page `abcd.md` and the host-delegated pages (`consult`, `ingest`, `prepare-this-repo`). / reality: internal/surface/cli/staleusage.go:81-88 pagesWithNoVerb has a fifth entry, `version`, which gets its own root-flag redirect line (checked: `abcd version` exits 2 with that line). The enumeration in this paragraph reads as complete but leaves out the one page this chapter is about.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: pagesWithNoVerb gained `version` in the cycle; enumeration not updated: stale prose." + }, + { + "id": "x-042", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/14-ingest.md:20-27: claim: Typing `abcd ingest` at the CLI gets a misdirecting second line: because commands/ingest.md exists, the binary adds its stale-surface note reading the page as proof a newer build carries the verb and telling the person to rebuild or update; the same holds for /abcd:consult and /abcd:prepare-this-repo, and the note 'should' instead say the command runs in the host agent. / reality: bin/abcd-darwin-arm64 ingest exits 2 with `abcd: unknown command \"ingest\" for \"abcd\"` followed by `abcd: `ingest` has no binary verb \u2014 it runs in the host agent; invoke it as /abcd:ingest` (internal/surface/cli/staleusage.go:85); consult and prepare-this-repo print the same host-agent note. No rebuild/update advice is emitted, so the paragraph describes a defect the shipped binary no longer has.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: 'has no binary verb' note present in staleusage.go at v0.11.1; chapter describes the pre-fix refusal: stale prose." + }, + { + "id": "x-043", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/15-prepare-this-repo.md:20-24: claim: Typing `abcd prepare-this-repo` at a shell is an unknown command, and 'today that refusal also blames a stale binary and asks for a rebuild', the wrong reading for a host-delegated surface. / reality: The shipped binary (bin/abcd-darwin-arm64 at b89784c4) refuses with exit 2: 'abcd: unknown command \"prepare-this-repo\" for \"abcd\"' followed by 'abcd: `prepare-this-repo` has no binary verb \u2014 it runs in the host agent; invoke it as /abcd:prepare-this-repo'. It does not mention staleness or a rebuild. internal/surface/cli/staleusage.go routes host-delegated pages (pagesWithNoVerb), and internal/surface/cli/staleusage_pageverb_test.go:55 asserts that a host-delegated page must not send the reader to rebuild or update. The 'today' defect the brief describes has already been fixed.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: Same host-agent note at v0.11.1; the rebuild advice was already gone: stale prose." + }, + { + "id": "x-044", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/16-lint.md:84-85: claim: `scanner.ScrubOutbound` is the rewrite direction and remains without a front door by design (spc-45 scopes a forge client out). / reality: ScrubOutbound is wired to a shipped verb: the implement loop's land stage (`abcd implement step`, driven by `abcd build`) calls it on the pull-request body and title before posting (internal/core/implement/loop/land.go:591,595) and again to strip a posted body through the forge (`gh pr edit`, land.go:647-657). A forge client and a scrub front door both exist.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: implement/loop/land.go (ScrubOutbound front door) is new in the cycle: stale prose." + }, + { + "id": "x-045", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/16-lint.md:77-82: claim: Four surfaces judge the harness-leak class; `abcd lint outbound` is the fourth, and it is the only one that judges text BEFORE it is public. / reality: Other shipped paths also judge outbound text before it is published: `abcd launch ship`'s ingest runs scanner.CheckOutbound over the changelog section and the release page (internal/core/release/ingest.go:410,417,515-516), and the implement loop's land stage scrubs/checks PR title and body before and after posting (internal/core/implement/loop/land.go:591-595,644-665). The count of four and the 'only one before public' claim are both stale.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: release/ingest.go CheckOutbound existed at v0.11.1 so the count of four was already stale; land.go adds more in the cycle: stale prose." + }, + { + "id": "x-046", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/16-lint.md:146 (v1 rule set, privacy-hygiene severity): claim: privacy-hygiene severity is `error`, with only network-identifier findings mapped from a scanner warn/info landing as `warn`; the two not-read findings (file over the 4 MiB cap, file that could not be opened) are listed without a severity exception. / reality: Both not-read findings are emitted at warn, not error: over-cap at internal/core/repolint/rule_privacy.go:194-199 and open-failure at rule_privacy.go:202-207 (Severity: SeverityWarn). The severity column omits these two warn cases.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: rule_privacy.go SeverityWarn for not-read findings at v0.11.1: stale prose." + }, + { + "id": "x-047", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/17-guard.md:68: claim: \"Either verb also speaks JSON, and that is the form the plugin page uses: a verdict, and with it the entry that fired, its tier, why ... and the safe successor.\" (applies to both check and hook) / reality: Only `abcd guard check --json` emits a JSON decision. `abcd guard hook --json` (and `abcd --json guard hook`) writes nothing to stdout for allow, warn or block. It keeps the prose message on stderr and exits 0/1/2. Checked with bin/abcd-darwin-arm64 on block, warn and allow payloads. The hook code has no JSON path, and the only JSON test is TestGuardCheckJSON in internal/surface/cli/guard_verb_test.go.", + "disposition": "fixed", + "note": "Fixed in 4d634c4f0 (docs: bring the rest of the guard brief current with the shipped guard), an ancestor of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9; .abcd/development/brief/04-surfaces/17-guard.md:68-75 (only `guard check` speaks JSON; the hook answers by exit code and stderr)." + }, + { + "id": "x-048", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/17-guard.md:70-71: claim: \"A `matches` list carries any further entries the same line tripped\", meaning the entries beyond the one that fired / reality: `matches` lists every entry tripped, including the one that fired. `guard check --json` on a line chaining `git clean -fd` with a force push returns entry_id git-push-force and matches [\"git-push-force\",\"git-clean\"]. A single hit returns matches [\"git-push-force\"]. commands/guard.md describes it correctly as \"every entry the command tripped, blockers first\".", + "disposition": "fixed", + "note": "Fixed in 4d634c4f0 (docs: bring the rest of the guard brief current with the shipped guard), an ancestor of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9; .abcd/development/brief/04-surfaces/17-guard.md:70-72 (`matches` names every entry tripped, the one that fired included)." + }, + { + "id": "x-049", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/17-guard.md:77-86: claim: The SHELL domain teaches the registry the guard enforces, one rule per entry. \"a host with hooks is taught it before the guard would have to refuse\", and \"The registry taught is the one the guard enforces in the repository.\" / reality: `abcd rules SHELL` teaches only the 17 entries in internal/core/guard/defaults/guard.json. The guard also enforces hazard verdicts defined in code, outside that registry, and none of them are taught. Examples: `git-stash-shared-stack` warns on `git stash` / `git stash pop` (internal/core/guard/stash.go), and `interpreter-reads-stream` blocks `cat x | sh` (internal/core/guard/payload.go). Others include git-config-rewrite-unread, unrecognised-launcher and program-name-unknown. For these, an agent is refused or warned without having been taught first.", + "disposition": "fixed", + "note": "Fixed in 4d634c4f0 (docs: bring the rest of the guard brief current with the shipped guard), an ancestor of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9; .abcd/development/brief/04-surfaces/17-guard.md:87-91 (a hazard read in code is enforced but not taught)." + }, + { + "id": "x-050", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/17-guard.md:451-453: claim: An allow does not see \"a default's own word, which bash prints only when the variable is unset (`rm -rf ${DIR:-$HOME}`, and `${X[0]]-$HOME}` ...)\" / reality: Both are now blocked. `guard check` blocks `rm -rf ${DIR:-$HOME}`, `rm -rf \"${DIR:-$HOME}\"`, `rm -rf ${DIR-$HOME}` and `rm -rf ${X[0]]-$HOME}` as rm-rf-root-or-home (exit 1). This was fixed under iss-2609290426544292 (commit 62d1ab56f, TestDefaultWordsTheWrittenCompareReads in internal/core/guard/defaultword_test.go). The brief still lists it as a residual. commands/guard.md:390-391 carries the same stale residual.", + "disposition": "fixed", + "note": "Fixed in e8d5d0060 (docs: drop the guard brief's claim that a default's word goes unseen), .abcd/development/brief/04-surfaces/17-guard.md:456-463, and in 4b8ff2afa (docs: bring the user-facing pages current for v0.12.0), commands/guard.md:390-391; both ancestors of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9." + }, + { + "id": "x-051", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/17-guard.md:460: claim: An allow does not see \"an alternative nested more than three deep\" / reality: `rm -rf ${X:+${X:+${X:+${X:+$HOME}}}}` (four deep) is blocked as rm-rf-root-or-home (exit 1). This was fixed under iss-2609290426544292 (TestDeepAlternativesAndSubstringsTheWrittenCompareReads in internal/core/guard/defaultword_test.go).", + "disposition": "fixed", + "note": "Fixed in 4d634c4f0 (docs: bring the rest of the guard brief current with the shipped guard), an ancestor of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9; .abcd/development/brief/04-surfaces/17-guard.md:456-463 (the more-than-three-deep alternative left the unseen list)." + }, + { + "id": "x-052", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/17-guard.md:460-461: claim: An allow does not see \"a substring of `$PWD` that prints the root (`${PWD:0:1}`), which warns as `$PWD` does\" / reality: `rm -rf ${PWD:0:1}` is blocked as rm-rf-root-or-home (exit 1), not warned. The brief contradicts itself: line 355-356 already says a substring \"also reads as the root ... (`${X:1}`, `${PWD:0:1}`)\". This was fixed under iss-2609290426544292 (internal/core/guard/defaultword_test.go:147).", + "disposition": "fixed", + "note": "Fixed in 4d634c4f0 (docs: bring the rest of the guard brief current with the shipped guard), an ancestor of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9; .abcd/development/brief/04-surfaces/17-guard.md:456-463 (the `${PWD:0:1}` substring left the unseen list)." + }, + { + "id": "x-053", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/18-ideate.md:137-143: claim: If a second research store already exists somewhere below the checkout root, the run succeeds against the checkout's own store and names the stray one on the way past. / reality: strayStoreNotes (internal/surface/cli/cli.go:4368-4441, called from internal/surface/cli/ideate.go:124) walks only the directory chain from the working directory up to (not including) the checkout root; its own comment says 'A sweep of the whole checkout would find stray stores this walk cannot see'. A stray .abcd/development/research/notes anywhere else below the root (not an ancestor of cwd) is never named, so 'somewhere below the checkout root' overclaims the notice's reach.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: strayStoreNotes ancestor-only walk exists at v0.11.1: prose overclaims reach." + }, + { + "id": "x-054", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/18-ideate.md:148-149: claim: the decision log's read-modify-write runs under the same advisory lock the ledger allocators use. / reality: ideate takes its own lock file, .abcd/work/.decisions.lock (internal/core/ideate/ideate.go:64, record.go:179), via fsutil.WithFileLock. The capture allocator locks .abcd/work/issues/.iss-alloc.lock (internal/core/capture/alloc.go:19,215) and intent flocks the intents/ directory (internal/core/intent/create.go:656). It shares the flock primitive, not the lock, so a ledger allocation and an ideate append do not serialise against each other.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: .decisions.lock in internal/core/ideate at v0.11.1; separate from the ledger lock: stale prose." + }, + { + "id": "x-055", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/18-ideate.md:13-14: claim: No other verb requires it, nothing warns when it is skipped, and capture friction stays at one line. / reality: The shipped capture verb requires --remedy as well as the text. `abcd capture --help` reads 'refuses a missing --remedy, a lone word or no checkout' and '--remedy ... the proposed fix, one line (required)', and commands/capture.md:64 says 'A capture is one line of text plus one line of remedy'. Capture friction is two lines, not one.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: 'refuses a missing --remedy' absent at v0.11.1 and present at HEAD: --remedy became required in the cycle; ideate chapter not updated: stale prose." + }, + { + "id": "x-056", + "category": "criterion-violation", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/19-identity.md:33: claim: Sub-verbs table records `render` in the adr-40 bucket `audit` (reality against a recorded commitment, emitting MET / MET_WITH_CONCERNS / NOT_MET / INCONCLUSIVE). / reality: `abcd identity render` (internal/surface/cli/identity.go, internal/core/positioning/render.go) emits no findings and no audit verdict. It prints a unified diff per drifted surface, or 'nothing to propose', and exits 0. The comparison it proposes corrections for is bucketed `lint`: `abcd lint identity` is `lint` in 16-lint.md:51, and the `identity-positioning` rule is a lint rule. adr-40 (0040-review-audit-lint-are-three-verbs.md:113) reserves lint/review/audit for surfaces that produce findings, so the cell should read `\u2014` (a non-assessment proposal verb), or `lint` at most. It is legal vocabulary, so surface_coverage passes it. This is a review-grain cell, which the chapter's own note (lines 26-28) says the snapshot cannot check.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: identity render emits diffs, no verdict, at both refs; adr-40 bucket cell wrong: stale prose (review-grain)." + }, + { + "id": "x-057", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/21-update.md:9-14: claim: abcd never checks for or applies updates on its own; this verb, with its check, is the only **command** that reaches the release origin, and only when invoked (the next paragraph names hooks/bootstrap.sh as the only other code path). / reality: `abcd launch --dry-run --fetch-baseline` also reaches the release origin: internal/surface/cli/launch_deep.go builds update.NewReleaseAssets pinned to the plugin's own repository and downloads the baseline release's plugin archive and checksums.txt from https://github.com//releases/download// (internal/core/update/assets.go, internal/core/launch/parity.go). The flag is listed in `bin/abcd-darwin-arm64 launch --help`. It is opt-in, so the adr-38 'only when invoked' half holds, but the brief's 'only command' claim does not (and the `update --check` flag help repeats it: 'the only network touch besides the update itself').", + "disposition": "fixed", + "note": "Fixed in 4b8ff2afa (docs: bring the user-facing pages current for v0.12.0), an ancestor of content commit fecdbed575f9e8e2cb0b875491d9aa48e8dfa0f9; internal/surface/cli/update.go:109 (regenerated docs/reference/cli/commands.md:3300)." + }, + { + "id": "x-058", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/21-update.md:154-158: claim: A file swapped under either local proof: the receipt reports the old digest instead and reads `updated : an unpublished build -> `. / reality: internal/surface/cli/update.go:182-195 renders a swapped receipt through update.UpdatedLine, so it reads `abcd updated from an unpublished build to `, followed by ` path: ` and a ` replaced: sha256 \u2014 in no published release; ` line. The `updated : ... -> ` wording the brief quotes is not printed anywhere; the brief's own receipt table (line 139) and the 'An update says so once' section describe the current wording.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: UpdatedLine wording is new in the cycle (update.go at v0.11.1 used the `-> ` form the brief quotes): stale prose." + }, + { + "id": "x-059", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/22-site.md:21-22: claim: Bare `abcd lint` runs the same gates as its `site` rule, over a render in a temporary directory outside the repository. / reality: Bare `abcd lint` has no rule named `site`; the rule that renders into a temp dir and runs site.Check is `site-gates` (internal/core/repolint/rule_site.go RuleMeta ID \"site-gates\", as 16-lint.md:30 and :147 name it). `site` is the lint's sub-verb/target (`abcd lint site`), not a bare-lint rule.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: rule id 'site-gates' at v0.11.1: stale prose." + }, + { + "id": "x-060", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/24-decide.md:81-84: claim: `recordid.CanonADRID` and `recordid.ADRFileID` are the canonical pair, and only the citation resolver, the `abcd ` dispatch and `decide` itself call them. / reality: At b89784c4 the pair is also called outside those three: internal/core/lint/adridunique.go:52-54 (a record gate in internal/core/lint, the package the chapter says carries only local regexes), internal/core/drainrule/drainrule.go:186,220, internal/core/intent/startcheck.go:248,295, internal/core/intent/reclassify.go:454,459 and internal/core/implement/loop/brief.go:379-390. The 'only' enumeration is false, and so is the picture of lint as a reader that does not use the canonical pair.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: reclassify.go, implement/loop/brief.go and lifeboat already called CanonADRID/ADRFileID at v0.11.1 (adridunique/drainrule/startcheck added in cycle): 'only three callers' was stale then." + }, + { + "id": "x-061", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/27-implement.md:52-54 (and exit-code list :290-292): claim: Outside a checkout, or in a repository with no commit, every sub-verb refuses and nothing is created; exit 2 covers 'no checkout to key a run on'. / reality: `abcd implement load --site preflight --json` run from a directory outside any git repository exits 0 with status \"ok\" and run_log.logged=false: the load sub-verb runs its check and does not refuse (internal/core/implement/load.go logLoadWarning simply skips the run log when no root SHA resolves). Other sub-verbs (bare, report, status) do refuse at exit 2 there, so 'every sub-verb' is false for load.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: Reproduced: `implement load --site preflight --json` outside a checkout exits 0 with status ok; load.go's logLoadWarning skip exists at v0.11.1; the load check is designed to warn and never fail, so prose overclaims rather than a defect." + }, + { + "id": "x-062", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/30-inbox.md:146-149: claim: Exit codes are `0` done; `1` a failure after the capture is written (the promotion could not be recorded, or the report could not be moved), naming the capture; `2` refused, with nothing written. / reality: Exit 1 is also returned with nothing written and no capture named, by every inbox verb, whenever the inbox cannot be read for a reason that is not a refusal (internal/core/report/inbox.go peekInbox: \"cannot read the inbox: %w\"; the CLI's reportRefusal maps non-ErrRefused errors to exit 1). Tested with a scratch HOME whose ~/.abcd/inbox is mode 000: `abcd inbox`, `abcd inbox --json` and `abcd inbox promote ` (the last run in an abcd checkout) each exit 1 with `cannot read the inbox: lstat ~/.abcd/inbox/promoted: permission denied`. The list does not cover this, and it says exit 1 always names a capture. Other pre-capture failures inside Promote (os.OpenRoot, ensureInbox's `cannot create the inbox`, a lock error other than contention) exit 1 in the same way.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: 'cannot read the inbox' non-refusal exit 1 path at v0.11.1: prose exit-code list incomplete." + }, + { + "id": "x-063", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/30-inbox.md:61-64: claim: Run in any other repository [a promotion] is refused before anything is read or written. / reality: The promote front door (internal/surface/cli/report.go, `promote ` RunE) runs capture.LedgerRoot and then resolveMatch(ledger) before report.Promote makes its root-commit check. resolveMatch loads the layered match configuration (layered.Config: the repository's .abcd/config.json and the machine-level config.json), and can print loader notes to stderr. Those files are therefore read before the refusal. Nothing in the inbox or the ledger is touched first, and no output difference was seen: a scratch repository holding an invalid .abcd/config.json still got only the root-commit refusal, with exit 2. The claim is literally false at the code level but has no visible effect.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: resolveMatch call in report.go promote is new in the cycle; config read before the root-commit refusal with no visible effect: prose literally false, harmless." + }, + { + "id": "x-064", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/33-source.md:15-18: claim: The host-delegated pages /abcd:consult and /abcd:ingest carry the judgement and call these (abcd source) verbs for every write. / reality: commands/ingest.md directs two corpus writes that no abcd source verb makes: step 4 (commands/ingest.md:90-95) has the agent hand-repair text.md and commit it in the corpus repo, and says itself 'a hand repair to a stored file is the one write the verb does not make'; step 5 (commands/ingest.md:102-104) has the agent write summary.md/notes directly into the source's folder. No verb in `abcd source --help` (add, cite-check, declassify, init, ledger, sync-banlist) writes a derived artefact or a repaired text. commands/consult.md does route every write through the verbs, so the claim holds for consult only.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: commands/ingest.md hand-repair and summary steps at v0.11.1: stale prose." + }, + { + "id": "x-065", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/34-build.md:31-34: claim: The `next` sub-verb row note: 'naming a falsified pick in the run record (criterion 6) [is] not built'. / reality: It is built: internal/core/implement/loop/handback.go appends a `pick` record line 'the pick of is falsified: ... handed back as unachievable ...' for a run `build next` started; `abcd build next --help` says 'A lane handed back after its fix rounds falsifies the pick: the run record says so'. The same chapter's own fix-round section (lines 455-463) also says the pick line is written, so the chapter contradicts itself.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: handback.go and `build next` are new in the cycle; chapter's row note says not built while its own later section says written: stale prose." + }, + { + "id": "x-066", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/34-build.md:149-150: claim: 'Naming a falsified pick in the run record (criterion 6) waits on the unachievable verdict of itd-50.' / reality: The unachievable hand-back ships (ruling DR1; --fix-rounds flag, `handed-back` stage) and the falsified-pick record line ships with it (internal/core/implement/loop/handback.go:32-33; `abcd build next --help`). The claim is stale.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: Falsified-pick line ships with handback.go (cycle): stale prose." + }, + { + "id": "x-067", + "category": "undocumented-surface", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/34-build.md:395-400: claim: The receipt's fields are enumerated as `schema_version`, `run_id`, `lane`, `branch`, `commits`, `definition_of_done`, `report`, optional `model`, and optional `resolves`; 'no field the schema does not name'. / reality: The shipped receipt schema also carries an optional `handback` object (`kind`, `reason`, `home`; internal/core/implement/loop/receipt.go:73), which `abcd build --help` names for the issue-keyed lane ('A receipt carrying `handback` in its place ends the lane'). The field list in this chapter omits it; it is documented only in 35-drain.md:177.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: receipt.go `handback` object added in the cycle; field list not updated: stale prose." + }, + { + "id": "x-068", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/README.md:301: claim: `consult.md` and `ingest.md` invoke the binary nowhere at all and carry the workflow itself. / reality: Both command pages invoke the binary repeatedly: commands/consult.md runs `\"${CLAUDE_PLUGIN_ROOT}/abcd\" source --json` (line 14), `source ledger` (54), `source sync-banlist` (84) and `source cite-check` (87); commands/ingest.md runs `source --json` (14), `source add` (67) and `source sync-banlist` (101), and says the `abcd source add` verb does the deterministic half (line 10). They have no verb of their own, but they do call the binary.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: commands/consult.md and ingest.md call `abcd source` at v0.11.1: stale prose." + }, + { + "id": "x-069", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/README.md:351: claim: Three agents serve no verb, and no command page calls on them (ruthless-reviewer, security-reviewer, sota-researcher): the host agent invokes each directly and reads the report itself. / reality: ruthless-reviewer and security-reviewer are dispatched by a verb: the `abcd build` / `abcd implement step` loop's validate stage names them as its validators (internal/core/implement/loop/validate.go:71-72, RoleRuthless/RoleSecurity; `abcd build --help` text in internal/surface/cli/build.go:504) and parses their verdicts itself, and commands/build.md:262-263 calls on both. The 34-build.md chapter documents them (line 417). Only sota-researcher serves no verb and is called by no command page.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: validate.go RoleRuthless/RoleSecurity new in the cycle: stale prose." + }, + { + "id": "x-070", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/README.md:298: claim: Three commands back onto no verb of their own (`/abcd:consult`, `/abcd:ingest` and `/abcd:prepare-this-repo`), called the host-delegated commands. The generated-appendix section (line 103) gives only two cases for a chapter whose command the tree does not register: a staged design target, or one of these host-delegated commands. / reality: A fourth shipped command page also has no verb: /abcd:version. `abcd version` is refused as an unknown command, so the page runs the root `--version` flag. Its generated appendix (.abcd/development/brief/04-surfaces/12-version.md) says 'It ships as a host-delegated command page: the command tree registers no `abcd version` verb'. However, .abcd/record-lint.json surface_coverage.host_delegated lists only consult, ingest and prepare-this-repo, and the README names three. So the record contradicts itself on which commands are host-delegated, and the README's list misses version.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: `abcd version` verb retired to a root flag in the cycle (staleusage redirect new); README and record-lint host_delegated list disagree with the generated appendix: stale/inconsistent prose." + }, + { + "id": "x-071", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/02-constraints/04-naming.md:14: claim: `/abcd:ahoy`: the bare form and the read-only sub-verbs report; `install`, `uninstall` and `remote apply` are the write paths. / reality: `abcd ahoy --help` registers two more writing sub-verbs. `connect` writes its block under ~/.abcd/ and its key to the chosen home, and `credential` writes the chosen home with --home. The write-path list is incomplete.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: ahoy_credential.go is new in the cycle (connect existed); write-path list not updated: stale prose." + }, + { + "id": "x-072", + "category": "criterion-violation", + "severity": "minor", + "summary": ".abcd/development/brief/02-constraints/04-naming.md:54-58: claim: Every surface is either maritime-mapped or registered as exempt, so an exemption is a decision rather than an omission. The listed exempt surfaces are banlist, changelog, consult, decide, docs, guard, history, ideate, identity, ingest, lint, memory, prepare-this-repo, reading, rules, site, spec, update, version, plus intent, capture, grill, audit, reflect and bare /abcd. / reality: Shipped surfaces that appear in neither the maritime table nor any exemption list: `build`, `drain`, `implement`, `inbox`, `lab`, `mode`, `peers`, `report`, `scribe` and `source` (all present in commands/ and in `abcd --help`/`--help --agent`), and the CLI verb `statusline`. The file never mentions any of them.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: build, implement, inbox, lab, mode, peers, report, scribe, source pages exist at v0.11.1 and were unregistered then; drain added in cycle: stale prose." + }, + { + "id": "x-073", + "category": "criterion-violation", + "severity": "minor", + "summary": ".abcd/development/brief/02-constraints/04-naming.md:180: claim: `task_classes` is a closed enum {oracle_review, intent_audit, spec_planning, code_rescue, principle_distillation, lifeboat_packing, audit, lint, surface_render, cross_document_audit, cold_reading}, and this table is the source of truth. / reality: agents/intent-auditor.md declares `task_classes: [intent_audit, intent_consistency]`. `intent_consistency` is not in the closed enum.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: agents/intent-auditor.md declared intent_consistency on 2026-09-26 (35ee85348, before v0.11.1) and the naming enum was not extended; agentcontract.go checks presence not values: record inconsistency, not a code defect." + }, + { + "id": "x-074", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/02-constraints/04-naming.md:180: claim: the binary carries no `task_classes` schema and no cross-check test reads the field (iss-265) / reality: internal/core/lint/agentcontract.go:229-231 reads `capability_scope.task_classes` and raises a finding when it is missing or empty on an untrusted-input agent. The lint validates that the field is present but not its values, so 'nothing reads the field' is overstated.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: agentcontract.go reads task_classes at v0.11.1: prose overstated." + }, + { + "id": "x-075", + "category": "fictional-layout", + "severity": "minor", + "summary": ".abcd/development/brief/02-constraints/04-naming.md:220: claim: voyage/ is split by operation: `disembark/history.jsonl`, `embark/provenance.json`, `embark/from//` (row not marked staged) / reality: Only disembark/history.jsonl is written (internal/core/lifeboat/voyage.go). No Go code writes embark/provenance.json or embark/from//. 02-constraints/01-platform.md:23 and 04-surfaces/03-embark.md:241 describe both as a design target.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: voyage.go writes only disembark/history.jsonl at both refs: unmarked design target." + }, + { + "id": "x-076", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/02-constraints/04-naming.md:212: claim: `managed-repo`: has an ABCD marker block (or an in-tree `.abcd/`, or an `index.json` entry) and a `.git/` directory / reality: internal/core/ahoy/detect.go:162-169 classifies managed-repo on an index registration or a marker block alone. It says a bare `.abcd/` is explicitly NOT a managed signal (iss-88), and it does not require `.git`. Git presence only separates unmanaged-repo from unmanaged-folder, and `.git` may be a file.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: detect.go iss-88 rule (no bare .abcd/, no .git required) at v0.11.1: stale prose." + }, + { + "id": "x-077", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/02-constraints/04-naming.md:217: claim: `aliases`: array of prior names a repo has had, recorded in per-root-sha `meta.json` (row not marked staged) / reality: The meta.json that ahoy writes (internal/core/ahoy/apply.go:852-860) holds root_commit, name, github and corpus. No code writes or reads a repo `aliases` field there. The only `aliases` fields in Go belong to the rules domains, the glossary, record families and source metadata.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: No aliases in ahoy meta.json at either ref: fictional field." + }, + { + "id": "x-078", + "category": "fictional-layout", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/01-agents.md:46: claim: `agents/` also holds two plain docs, its README and its changelog, which carry no agent frontmatter; the loader globs agents/*.md and registers both as harness agents alongside the real prompt files; iss-110 tracks the mis-registration. / reality: agents/ holds only the sixteen prompt files plus a per-agent fixtures/ directory each; there is no agents/README.md or agents/CHANGELOG.md. Commit d5091dac6 moved both to .abcd/development/agents/ (README.md, CHANGELOG.md), record-lint's agent_contract reads the log from `changelog: .abcd/development/agents/CHANGELOG.md` in .abcd/record-lint.json, and iss-110 is in .abcd/work/issues/resolved/ (resolved_by d5091dac6). The mis-registration the paragraph describes no longer exists and nothing tracks it as open.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: d5091dac6 (2026-09-29, in cycle) moved agents/README+CHANGELOG to .abcd/development/agents/ and resolved iss-110; chapter not updated: stale prose." + }, + { + "id": "x-079", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/01-agents.md:148: claim: Concrete backends are opt-in adapters behind the same seam (a local model, a model CLI subprocess, a provider API, or a model over MCP), selected when an operator wants abcd to reach a model directly; the `oracle.backend` config key records the choice, defaulting to host-delegated; an unreachable adapter degrades to that default. / reality: The only shipped adapter is the API one (internal/adapter/openaiapi); no native, CLI-subprocess or MCP oracle adapter exists under internal/adapter/, and the paragraph does not mark them as design targets. The shipped selection is not oracle.backend: internal/core/oracle routes a step to a provider by `oracle.roles.` (or a `--route`), and nothing in internal/core/oracle reads oracle.backend. `ahoy install --oracle-backend` writes the key and ahoy's detect only checks that it is set. The degrade-on-unreachable half holds for the API adapter only (Route.FellBack in internal/core/oracle/dispatch.go). The chapter never mentions oracle.roles, the key that actually selects the backend.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: Only openaiapi adapter at both refs; oracle.backend not read by internal/core/oracle; oracle.roles unmentioned: stale prose." + }, + { + "id": "x-080", + "category": "undocumented-surface", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/03-configuration.md:3-8,18 (and :414-417): claim: `.abcd/config.json` has 'Nine keys plus a meta block ... That is the whole of the configuration surface the shipped binary consults'. The machine layer `~/.abcd/config.json` has only two readers, the provider adapter's `oracle` keys and the `match` keys, and 'every other config read resolves the repo-scope .abcd/config.json alone'. / reality: Two more layered readers of `.abcd/config.json` / `~/.abcd/config.json` are wired into the shipped `abcd build` / `abcd implement` loop. internal/core/runner/config.go reads `roles..runner`, `runner.` (with `.model`) and `runner.fallback_host`. internal/core/implement/loop/pace.go claims the `pace` namespace and reads `pace.work_minutes`, `pace.pause_minutes`, `pace.sub_agents` and `pace.fix_rounds` through layered.Load(layered.Config). Neither namespace appears in this chapter. Their only documentation is .abcd/development/brief/04-surfaces/34-build.md:161,299-329.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: runner/config.go and loop/pace.go are new in the cycle; configuration chapter does not name them: stale prose." + }, + { + "id": "x-081", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/03-configuration.md:87-90: claim: The OpenAI-compatible API adapter 'reads four keys under `oracle`' through the layered resolver. / reality: The oracle package reads five keys under `oracle`: `oracle.api`, `oracle.denylist`, `oracle.roles` and `oracle.judgements` (internal/core/oracle/config.go:59-62), plus `oracle.bundled_context_providers` (internal/core/oracle/selfcontained.go:36). The chapter describes the fifth key later, at :166-178, but the count still says four.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: selfcontained.go bundled_context_providers new in the cycle; count of four not updated: stale prose." + }, + { + "id": "x-082", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/03-configuration.md:245-248: claim: 'eight of the thirteen committed records carry it [schema_version], and five do not, the record-lint and docs-lint configuration among them ... on those five.' / reality: 15 configuration records are tracked at the .abcd/ root and in .abcd/config/ (14 JSON plus config/dependency-reauthor.conf). 8 carry schema_version: citations-baseline, config, positioning, prose-citations-baseline, rules, site-baseline, site, config/reading-presets. 7 do not: docs-lint, record-lint, config/artefact, config/identity, config/launch-payload, config/version-location, config/dependency-reauthor.conf. Counting JSON only, it is 8 of 14 with 6 unstamped. Neither count is thirteen/five: config/artefact.json (added 2026-09-26) and dependency-reauthor.conf (2026-09-29) came after the count was written (2026-09-09).", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: config/artefact.json existed at v0.11.1 so thirteen/five was already wrong; dependency-reauthor.conf added in cycle: stale count." + }, + { + "id": "x-083", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/03-configuration.md:366-370 (and :411 'the staged worktree store'): claim: The worktree store is a design target and unbuilt: 'No `worktree` verb exists in the shipped binary, and nothing in it creates or reads this store.' / reality: It is true that no `worktree` verb exists. The rest is false: the shipped build/implement loop creates and reads worktrees in the store. internal/core/implement/loop/lane.go:34 declares WorktreeStoreRel = \".abcd/worktrees\" and makes each lane's worktree at ~/.abcd/worktrees//- on branch build/-. `abcd implement step --help` (internal/surface/cli/build.go:497-499) states this. The ahoy chapter's tree (04-surfaces/01-ahoy.md:225-226, 'NOT BUILT') carries the same stale claim.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: WorktreeStoreRel in lane.go at v0.11.1: stale prose." + }, + { + "id": "x-084", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/03-configuration.md:429-431 (and :475): claim: The `sources/` corpus that /abcd:ingest and /abcd:consult read: 'abcd never creates that one, and both verbs say so and stop when it is absent'. At :475, 'the `sources/` corpus is the caller's to place'. / reality: The shipped `abcd source init` creates it: 'Create an empty sources corpus, a git repository with no remote' at ~/.abcd/sources by default, mode 0700, in one commit. Bare `abcd source` refuses with exit 3 'naming `abcd source init`'. The `source` verb and its sub-verbs (add, cite-check, declassify, init, ledger, sync-banlist) are not named in this chapter. 04-surfaces/01-ahoy.md:240-243 says the corpus is 'Created only by its explicit init', which contradicts this chapter, although the two are declared to be 'one list and must agree'.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: `abcd source init` existed at v0.11.1: stale prose, and 01-ahoy.md contradicts it." + }, + { + "id": "x-085", + "category": "undocumented-surface", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/03-configuration.md:409-436: claim: The user-scope inventory of `~/.abcd/` is stated to be the same list as the ahoy chapter's tree ('the two are one list and must agree'). / reality: The inventory omits user-scope files the binary reads and writes: `oracle-routing.json` (the machine layer of layered.OracleRouting, internal/core/layered/layered.go:113, written by `ahoy install`), `statusline.json` (internal/core/statusline/settings.go) and `cache-attestation` (internal/core/ahoy/cache_attestation.go, written by hooks/bootstrap.sh). These three appear only in the symlink-refusal list at :438-440, not in the inventory.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: Same three user-scope files existed at v0.11.1: stale inventory." + }, + { + "id": "x-086", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/03-configuration.md:221-227: claim: 'Owed-review draining (staged) ... No `run` seam ships, so nothing drains today.' / reality: Owed reviews can be drained today. The shipped `abcd intent audit --owed [--max ]` (internal/surface/cli/intent_drain.go, runOwedDrain, itd-53) lists the owed fidelity reviews oldest first and emits the head's request, so a host drains them by hand. The shipped autonomous-run loop (`abcd build` / `abcd implement`, internal/core/implement/loop, with pluggable runners in internal/core/runner) runs an intent-auditor at the validate stage of the lane that ships the intent. So 'nothing drains today' and 'No run seam ships' no longer match the shipped surface. Only the automatic drain at an iteration boundary remains unbuilt.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: runOwedDrain in intent_drain.go at v0.11.1: stale prose." + }, + { + "id": "x-087", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/03-configuration.md:855-857: claim: 'Only the memory package exists today, and its shipped front door takes a URL rather than a harvested directory.' / reality: `abcd memory ingest ` takes either a local file path or an https URL (help: 'Distil a local file or an https source into cited memory pages'). Saying it takes only a URL misstates the verb's argument.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: memory ingest 'Distil a local file or an https source' help at v0.11.1: stale prose." + }, + { + "id": "x-088", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/03-configuration.md:898-905: claim: `cmd/` holds 'the shipped entrypoint plus four build-time binaries': record-lint, scaffold-sync, abcd-gen-surface and abcd-gen-cli-ref ('The four are developer tooling'). / reality: `cmd/` holds six directories: abcd plus five build-time binaries. The tree omits `cmd/scaffold-render/`, which writes every profile of the scaffolded release workflows for CI's zizmor job (iss-2609251939472371).", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: cmd/scaffold-render/ absent at v0.11.1, present at HEAD: added in the cycle without the tree: stale prose." + }, + { + "id": "x-089", + "category": "fictional-layout", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/03-configuration.md:909-911: claim: internal/adapter/ shows only scanner/ and gitleaks/, with the comment 'The scanner is the one seam with a package today'. / reality: internal/adapter/ holds four packages: gitleaks, hosting (with cloudflare/), openaiapi and scanner. `hosting` calls itself 'the second seam under internal/adapter beside the scanners' (the `abcd site setup` provider seam). `openaiapi` is the OpenAI-compatible provider adapter this chapter describes at :85-192.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: internal/adapter/hosting and openaiapi exist at v0.11.1: stale layout." + }, + { + "id": "x-090", + "category": "fictional-layout", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/03-configuration.md:915-916: claim: `agents/.md` holds the host-delegated agent prompts, 'plus per-agent fixtures/, README.md and CHANGELOG.md'. / reality: The top-level agents/ holds only the 16 .md prompts and 16 /fixtures/ directories. No README.md or CHANGELOG.md is tracked there (git ls-files agents). They are at .abcd/development/agents/README.md and .abcd/development/agents/CHANGELOG.md.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: agents/README.md and CHANGELOG.md moved by d5091dac6 in the cycle: stale layout." + }, + { + "id": "x-091", + "category": "undocumented-surface", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/03-configuration.md:966-972: claim: The families under `.abcd/development/` are enumerated: brief with glossary, intents, principles, decisions, roadmap with phases and RFCs, plans, native spec store, cold-reading ledger, release surface declaration, release gate manifest, research, and persona roster. / reality: .abcd/development/ also holds `agents/` (the agent-surface README.md and CHANGELOG.md) and `releases/` (per-release pages 0.10.0.md, 0.11.0.md, 0.11.1.md plus README.md). Neither is in the enumeration.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: .abcd/development/releases/ exists at v0.11.1 and is not enumerated (agents/ added in cycle): stale enumeration." + }, + { + "id": "x-092", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/05-prompt-quality.md:27: claim: `agents/` sits outside both the record-lint and docs-lint roots, so the per-file rules do not reach it; only agent_contract walks the tree. / reality: docs-lint's per-file rules do reach agents/: .abcd/docs-lint.json lists \"agents\" in name_roots (line 12, the names/ banned-token gate run by lintNameRoots, internal/core/lint/lint.go:3253) and in links_resolve.extra_roots (line 286). The Makefile's docs-lint comment says the same: the link check walks 'the agent prompts'. The 'roots' arrays leave agents/ out, but per-file rules still run over it.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: docs-lint.json name_roots lists agents at v0.11.1: stale prose." + }, + { + "id": "x-093", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/05-prompt-quality.md:13-14, :56-57: claim: The unbumped-edit check needs a diff range 'which the continuous-integration caller supplies'; 'The range comes from the CI caller, never from the in-tree config'. / reality: The local gate arms it too. The Makefile's record-lint target runs `go run ./cmd/record-lint -agent-diff origin/main...HEAD` (Makefile:165), so every `make record-lint` and `make preflight` runs the diff half, not only CI (ci.yml:391). The brief names the CI caller as the only supplier.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: Makefile record-lint passes -agent-diff at v0.11.1: stale prose." + }, + { + "id": "x-094", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/05-prompt-quality.md:73-75: claim: Every shipped agent's `fixtures/` directory holds exactly one file, the injection canary. / reality: Two agents hold more than one fixture. agents/intent-auditor/fixtures/ has injection-canary.json and injection-canary-consistency.json. agents/release-changelog-composer/fixtures/ has injection-canary.json, injection-canary-press-release.json and no-forecast.json. no-forecast.json is not a canary: it pairs an input with an expected payload, and TestComposerFixtureExamplesIngest (internal/core/release/fixtures_test.go) runs that payload through the real ingest. That is a narrow per-agent version of the expected-output half the brief says 'does not exist'.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: Same five fixture files at v0.11.1 (two agents with more than one): stale prose." + }, + { + "id": "x-095", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/05-prompt-quality.md:75-77: claim: The harness lands with the first Pass-A agent's spec (the lifeboat pipeline), 'the point at which a second agent exists to generalise the runner over'. / reality: That point passed without the harness. The lifeboat pipeline's agents (principle-distiller, graveyard-interpreter, press-release-composer, lifeboat-reviewer) have shipped since 0.1.0 on 2026-07-16 (.abcd/development/agents/CHANGELOG.md:575), and 16 agents are in agents/. There is still no internal/core/prompttest. The brief still describes the landing condition as a future event, and it is stale.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: Lifeboat agents shipped since 0.1.0; no prompttest at either ref: stale prose." + }, + { + "id": "x-096", + "category": "undocumented-surface", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/05-prompt-quality.md:29-51: claim: agent_contract walks the tree 'skipping directories', and 'What it enforces on every invocation' lists five checks: declaration, prompt_version semver, capability_scope, canary, changelog entry. / reality: agent_contract also walks every subdirectory. It refuses any markdown file below the top level that is outside a fixtures/ directory as a misfiled prompt (misfiledAgentPrompts, internal/core/lint/agentcontract.go, iss-2608281948289198). The brief's enforcement list leaves this sixth refusal out. It is documented only at .abcd/development/agents/README.md:26.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: misfiledAgentPrompts in agentcontract.go at v0.11.1: enforcement list incomplete." + }, + { + "id": "x-097", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/05-prompt-quality.md:122-124: claim: On the self-improvement pre-flight: most prompts' changelog entries say the gate has not fired; 'the four review and research prompts say it nowhere'. / reality: Five prompts say it nowhere, not four. reflection-composer 0.1.0 (.abcd/development/agents/CHANGELOG.md:15-24, the only entry for that prompt) records 'Unmeasured, in the 0.x band' and never mentions the pre-flight. The prompts that do mention it are the four cold-reading definitions, release-changelog-composer, intent-auditor, scribe, principle-distiller, graveyard-interpreter, press-release-composer and lifeboat-reviewer (as lifeboat-oracle).", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: reflection-composer added in the cycle (15 prompts at v0.11.1, 16 at HEAD); count of four stale by the addition: stale prose." + }, + { + "id": "x-098", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/08-skills.md:74-75: claim: Five verbs have a Go verb and no command page: `changelog`, `completion`, `hook`, `rules`, and `spec`. / reality: The binary registers a sixth such verb, `statusline` (listed by `abcd --help --agent`, `abcd statusline --help` works), and there is no commands/statusline.md. The surfaces index's Operator-internal verbs table (.abcd/development/brief/04-surfaces/README.md:222-237) already lists six rows, statusline included.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: statusline verb registered at v0.11.1 with no command page: stale count." + }, + { + "id": "x-099", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/08-skills.md:76-77: claim: Three command pages carry no Go verb of their own name: the host-delegated three above (consult, ingest, prepare-this-repo). / reality: commands/version.md also has no Go verb of its own name: `abcd version` is not a registered verb (it falls through to the root help), and the page runs the root flag `abcd --version --json`. That makes four command pages without a same-named Go verb.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: version verb retired in the cycle; page without a same-named verb list not updated: stale count." + }, + { + "id": "x-100", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/08-skills.md:77-79: claim: Two of those three [consult, ingest, prepare-this-repo] call no part of the binary at all; `/abcd:prepare-this-repo` is the exception. / reality: commands/consult.md and commands/ingest.md both call the binary. Each first runs `\"${CLAUDE_PLUGIN_ROOT}/abcd\" source --json` and stops on exit 3. consult says every write goes through the `abcd source` verbs (e.g. `abcd source sync-banlist --refresh`, `abcd source ledger`), and ingest delegates storing to `abcd source add` and uses `abcd mode`. None of the three is binary-free.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: consult.md and ingest.md call `abcd source` at v0.11.1: stale prose." + }, + { + "id": "x-101", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/08-skills.md:19: claim: The release payload declares all four kinds [commands, skills, agents under agents/, hook entrypoints under hooks/]. / reality: .abcd/config/launch-payload.json includes `commands`, `agents` and `hooks` but no `skills`, and the same page says so at lines 113-115 (\"the include list still names commands, agents and hooks and no skills directory\"). Only the install-surface resolver (internal/core/launch/installsurface.go conventionRules/declarationKeys) knows the skills kind; the payload itself does not declare it.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: launch-payload.json has no skills entry at either ref; page contradicts itself: stale prose." + }, + { + "id": "x-102", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/06-delivery/01-build-sequence.md:33-36: claim: \"The scanner is the one seam standing\"; the oracle, history, spec and run seams are \"planned rather than present\". / reality: internal/adapter/ holds four packages, not one seam: scanner, gitleaks (the scanner's opt-in external backend), hosting (its package doc reads \"the provider seam `abcd site setup` routes a rendered site through ... It is the second seam under internal/adapter beside the scanners\"), and openaiapi (the OpenAI-compatible API adapter). The oracle seam also ships in working form: internal/core/oracle routes each host-delegated agent to the harness or to a configured provider (`abcd ahoy connect`, `ahoy credential`, `ahoy --providers`), and internal/core/runner ships command-line runners (claude.go, opencode.go) under the shipped intent itd-2609201916056194. Only the adapter/oracle/ path is absent, and that absence is all the index_drift gate checks.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: hosting/openaiapi and oracle routing exist at v0.11.1 (runner added in cycle): stale prose." + }, + { + "id": "x-103", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/06-delivery/01-build-sequence.md:52-56: claim: The read-only halves of ahoy are the bare invocation, `--dry-run`, `--identity`, `--remote` and `doctor`; \"Two further forms write: `uninstall` ... and `remote apply`.\" / reality: `abcd ahoy --help` lists more write forms than two besides install: `connect` (\"Writes its block under ~/.abcd/ and its key to the home chosen\") and `credential` (\"Writes the chosen home only with --home\"). It also has a read-only `--providers` mode, which the chapter's list of read-only halves leaves out.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: ahoy credential (and --providers) new in the cycle: stale enumeration." + }, + { + "id": "x-104", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/06-delivery/01-build-sequence.md:62: claim: \"`abcd launch --dry-run` previews the bundle read-only\". / reality: The verb's help says \"Writes only its pre-flight report, to the local tier\", and 04-surfaces/04-launch.md:672 agrees: \"Every preview ... writes a pre-flight report\". So the preview writes a file.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: launch --dry-run writes its pre-flight report at v0.11.1: stale prose." + }, + { + "id": "x-105", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/06-delivery/01-build-sequence.md:80-81: claim: memory: \"a vendor memory harvest is an opt-in, read-only source over it.\" The claim is not marked as a design target. / reality: No such surface ships. `abcd memory` has only `ask`, `ingest` (a local file or https URL) and `lint`. internal/core/memory has no code that reads vendor session memory, and 04-surfaces/07-memory.md never mentions a harvest or vendor memory.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: No vendor memory harvest in internal/core/memory at either ref: unmarked design target." + }, + { + "id": "x-106", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/06-delivery/01-build-sequence.md:85,90-91: claim: `/abcd:intent` cites itd-27, and \"`grill` is a design target (itd-27)\". / reality: itd-27 is in .abcd/development/intents/superseded/ (superseded_by: itd-94). itd-94 shipped the plan and readiness gate, not grill. `abcd intent grill` is not registered: it falls through to the intent group's own help. So `grill` is a superseded record, not a live design target.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: itd-27 superseded at v0.11.1; grill unregistered: stale prose." + }, + { + "id": "x-107", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/06-delivery/01-build-sequence.md:95-96: claim: \"Native, CLI, API and MCP adapters are opt-in\" for the oracle seam. The claim is not marked as staged. / reality: CLI and API routes do ship: internal/core/runner (claude, opencode) and internal/adapter/openaiapi, wired through `ahoy connect` and `ahoy credential`. No MCP oracle adapter exists: internal/core/oracle and internal/core/runner never mention MCP, and there is no adapter/oracle/ path. The sentence presents all four as available opt-ins without saying which exist.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: runner CLI routes (claude.go/opencode.go) landed in the cycle; MCP absent; sentence unqualified: stale prose." + }, + { + "id": "x-108", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/06-delivery/01-build-sequence.md:119-131: claim: Autonomous run seam: \"Nothing of this ships: the binary registers no `run` verb, the run adapter is on the planned-seams list, and the operator surface over it is itd-29, in `intents/planned/`.\" / reality: itd-29 is in .abcd/development/intents/superseded/, superseded by itd-2609201916151817 (planned), which re-landed the run on the `implement` verb. A native loop does ship. `abcd build` is \"Start the loop that takes one READY intent to delivered\" and is paced (--pace). `abcd build next` picks the readiest planned intent and gates on unsettled `blocked_by`. `abcd implement status|step|receipt` drive the loop, and `receipt` completes a stage \"once the receipt verifies\", which is the receipt-gated iteration this section calls design-only. The absence of a `run` verb and of adapter/run/ is accurate. The rest of the section is stale.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: itd-29 superseded at v0.11.1 and `build next`/validate/handback landed in the cycle: section stale." + }, + { + "id": "x-109", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/06-delivery/02-verification-matrix.md:35 (Oracle adapter degrade): claim: (staged) A wired adapter that is unreachable degrades to the host-delegated default rather than failing the run. No oracle adapter package exists, so there is nothing to make unreachable; `ahoy install --oracle-backend` records the choice ahead of the seam / reality: An oracle adapter package ships: internal/adapter/openaiapi (OpenAI-compatible provider client, itd-2609081951381895), dispatched through internal/core/oracle (Resolve/Dispatch, provider connections configured by `abcd ahoy connect`, selected per agent with `--route =[@]` on intent audit, launch ship, disembark press-release and others). The degrade is implemented and wired: openaiapi.ErrUnreachable -> Route.FellBack (internal/core/oracle/dispatch.go:93-101) moves the step to the harness, called from internal/surface/cli/dispatch.go:81. The row's 'no adapter package exists' is false, and its staged marker covers behaviour the binary carries.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: dispatch.go FellBack degrade is new in the cycle; matrix row still says no adapter package exists: stale prose." + }, + { + "id": "x-110", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/06-delivery/02-verification-matrix.md:51 (Launch documentation audit): claim: (staged) ... The gate appears in every launch report and reports itself unimplemented: nothing reads the docs tree at cut time and nothing prompts / reality: The documentation-audit gate is implemented: docAuditGate (internal/core/launch/gates.go:975-995) runs the docs-lint engine's findings over the configured doc roots, statuses ran / not_armed / not_measured, measured by the front door (internal/surface/cli/launch_preflight.go:56 docAuditPreflight) on both `launch --dry-run` (cli.go:421) and `launch ship` (ship.go:556). The docs tree IS read at cut time; only the interactive prompt half is absent. The matrix's own Launch preflight row (line 46) already says the documentation audit warns unless configured strict, contradicting this row.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: docAuditGate in gates.go at v0.11.1: stale prose." + }, + { + "id": "x-111", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/06-delivery/02-verification-matrix.md:53 (Intent capture): claim: Bare quoted text runs the interview and writes a draft with press-release content, a persona quote and acceptance criteria / reality: `abcd intent \"\"` runs no interview: it writes a draft whose `## Press Release` is the text as prose, with `## Why This Matters` seeded by a prompt and `## Acceptance Criteria` a placeholder (internal/core/intent/create.go:498-525); no persona quote is written. commands/intent.md:102-105 tells the host the Why This Matters and Acceptance Criteria sections are placeholders to be replaced 'via the planning interview', which runs later at planning, not at capture.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: create.go writes placeholder sections, no interview, at v0.11.1: stale prose." + }, + { + "id": "x-112", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/06-delivery/02-verification-matrix.md:57 (Intent help): claim: Bare `abcd intent` shows intents grouped by state with the next actions to take / reality: Bare `abcd intent` prints one line of per-state COUNTS (drafts/planned/shipped/disciplines/superseded/reviews owed), a spec open/closed count, one `link: itd-N -> spc-N` line per linked intent, and two generic routing hints (capture vs intent, ideate). It lists no intents grouped by state and no per-intent next action.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: Bare `abcd intent` prints counts and links (verified): stale prose." + }, + { + "id": "x-113", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/06-delivery/02-verification-matrix.md:71 (Capture migration): claim: (staged) promoting a pre-ledger flat issue list into the structured ledger ... The binary registers no migration verb / reality: The staged capability is indeed absent, but the literal statement is false: the binary registers `capture migrate` (back-link migration, documented one row up at line 69), `banlist migrate` and `history migrate`. The sentence should say no verb performs the flat-list migration.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: capture/banlist/history migrate verbs at v0.11.1: literal sentence false, capability absent." + }, + { + "id": "x-114", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/02-constraints/04-naming.md:99-101: claim: \"Several parents print usage with no state, two verbs refuse instead of rendering\". / reality: Bare, at least three verbs refuse instead of rendering: `abcd launch` (pass --dry-run), `abcd decide` (a quoted title is required) and `abcd build` (accepts 1 arg, received 0). Bare `abcd source` also refuses when there is no corpus, and bare `abcd report` refuses off a terminal. The enumeration this sentence defers to (04-surfaces/README.md \u00a7 Bare invocation) names all five.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: launch/decide/build refuse bare (verified exit 1/2/2); build had Args at v0.11.1: stale count." + }, + { + "id": "x-115", + "category": "criterion-violation", + "severity": "minor", + "summary": ".abcd/development/brief/02-constraints/04-naming.md:8-10,55-58: claim: Every surface is either maritime-mapped or 'exempt and says so on the record, so an exemption is a decision rather than an omission'. The exempt list is 'registered here so the exemption is on the record'. / reality: The binary registers the top-level verbs build, drain, implement, inbox, lab, mode, peers, report, scribe, source and statusline (see `abcd --help --agent`). None of them appears in the mapped table, the rationale exemptions or the exempt list, so the naming registry leaves them out.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: Same unregistered verbs as x-072, present at v0.11.1: stale registry." + }, + { + "id": "x-116", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/14-ingest.md:20-27: claim: Typing `abcd ingest` at the CLI 'gets a second line that misdirects': the binary adds its stale-surface note, which tells the person to rebuild or update. The page says 'every host-delegated page has the same shape' and that the note should instead say the command runs in the host agent. / reality: `abcd ingest` (and `abcd consult`) exits 2 with a second line that reads \"`ingest` has no binary verb \u2014 it runs in the host agent; invoke it as /abcd:ingest\". The binary already prints the corrected note, so the chapter describes the refusal as it used to be.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: Duplicate of x-042; host-agent note present at v0.11.1: stale prose." + }, + { + "id": "x-117", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/15-prepare-this-repo.md:20-24: claim: Typing `abcd prepare-this-repo` is an unknown command, and 'Today that refusal also blames a stale binary and asks for a rebuild'. / reality: `abcd prepare-this-repo` exits 2 with the second line \"`prepare-this-repo` has no binary verb \u2014 it runs in the host agent; invoke it as /abcd:prepare-this-repo\". Nothing blames a stale binary and nothing asks for a rebuild.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: Duplicate of x-043; present at v0.11.1: stale prose." + }, + { + "id": "x-118", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/12-version.md:147 (generated appendix): claim: 'It ships as a host-delegated command page: the command tree registers no `abcd version` verb'. / reality: /abcd:version is not host-delegated. commands/version.md runs the binary (`abcd --version --json`), and the binary refuses `abcd version` with \"`version` is a root flag, not a verb: run `abcd --version`\", which is a different message from the \"has no binary verb \u2014 it runs in the host agent\" note it prints for the host-delegated consult, ingest and prepare-this-repo. 04-surfaces/README.md:309-313 names exactly those three as the host-delegated commands, so the appendix contradicts both the binary and the register.", + "disposition": "deferred", + "note": "Behaviour finding captured as iss-2609302306003610 in this release's records commit; fixed in the first lane after the tag. Duplicate of x-039 (checker b00): the same generated appendix misclassification of /abcd:version." + }, + { + "id": "x-119", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/01-product/04-scope.md:17: claim: `/abcd:reflect` \u2014 release retrospective, a design target (itd-24, planned) / reality: reflect ships: commands/reflect.md exists, `abcd reflect` is registered (help's Release group), itd-24 sits in intents/shipped/, and the 04-surfaces/README.md register row 9 reads shipped.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: itd-24 moved planned/ -> shipped/ in the cycle; scope page still calls reflect a design target: stale prose." + }, + { + "id": "x-120", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/08-skills.md:74: claim: Five verbs have a Go verb and no command page: `changelog`, `completion`, `hook`, `rules`, and `spec`. / reality: Six: `statusline` is also a registered verb with no commands/statusline.md (listed in the help's agents block and in the 04-surfaces/README.md operator-internal table; 01-product/04-scope.md:19 also names six).", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: Duplicate of x-098: statusline verb at v0.11.1: stale count." + }, + { + "id": "x-121", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/08-skills.md:67,76; .abcd/development/brief/04-surfaces/README.md:298: claim: Three commands are host-delegated; three command pages carry no Go verb of their own name: consult, ingest, prepare-this-repo. / reality: commands/version.md is a fourth command page with no Go verb (`abcd version` -> unknown command; version is the root --version flag), and 04-surfaces/12-version.md's generated appendix calls it 'a host-delegated command page'. The record-lint surface_coverage host_delegated list still names only three, so the brief is inconsistent about the page's shape.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: Duplicate of x-070/x-099: version page verb-less since the cycle: stale/inconsistent prose." + }, + { + "id": "x-122", + "category": "criterion-violation", + "severity": "minor", + "summary": ".abcd/development/brief/02-constraints/04-naming.md:54: claim: Commands without a maritime cognate are exempt 'and says so on the record, so an exemption is a decision rather than an omission'; the exemption list is banlist, changelog, consult, decide, docs, guard, history, ideate, identity, ingest, lint, memory, prepare-this-repo, reading, rules, site, spec, update, version. / reality: Shipped command pages build, drain, implement, inbox, lab, mode, peers, report, scribe and source (and the verb statusline) appear neither in the metaphor table nor in any exemption, so their naming status is an omission.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: Duplicate of x-072/x-115: stale registry." + }, + { + "id": "x-123", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/glossary/core/surface.md:18: claim: Every user-facing command has two halves: the markdown file under commands/ and the transport package under internal/surface/ that formats what the core returns. / reality: The host-delegated command pages have no Go verb (commands/consult.md and commands/ingest.md call no part of the binary; version.md has no verb either), as 04-surfaces/README.md and 05-internals/08-skills.md themselves state.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: consult/ingest have no Go verb at v0.11.1 (they do call `abcd source`, so the reality wording overstates 'call no part'); glossary's two-halves claim stale." + }, + { + "id": "x-124", + "category": "fictional-layout", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/03-configuration.md:915: claim: Plugin tree: `agents/.md # host-delegated agent prompts, plus per-agent fixtures/, README.md and CHANGELOG.md` / reality: No agents/README.md or agents/CHANGELOG.md exists in the tree (git ls-files agents); both live under .abcd/development/agents/ since iss-110's resolution.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: Duplicate of x-090: moved by d5091dac6 in the cycle: stale layout." + }, + { + "id": "x-125", + "category": "stale-count", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/README.md:7: claim: 01-agents.md: \"The fifteen shipped agent prompts and the design roster still to be built\" / reality: Sixteen prompts ship in agents/ (the chapter itself says \"Sixteen agent prompts ship in `agents/` today\").", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: 15 prompts at v0.11.1 (17 entries minus README/CHANGELOG), 16 at HEAD after reflection-composer; index not bumped in the cycle: stale count." + }, + { + "id": "x-126", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/README.md:61: claim: The prompt files under `agents/` ... are checked in neither direction: nothing asserts that one has a row here, and nothing notices when one is added or removed (iss-110). / reality: `abcd docs fidelity` derives the shipped surfaces from the command tree AND every agents/.md (internal/core/docfidelity/docfidelity.go:131-187) and refuses a surface no brief chapter names; TestPluginAgentSurfaceRegistersOnlyAgents checks the agents/ top level. iss-110 is resolved and concerned the README/CHANGELOG mis-registration, not row coverage.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: docfidelity.go agents/ derivation new in the cycle; iss-110 resolved by d5091dac6 in the cycle: stale prose." + }, + { + "id": "x-127", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/04-surfaces/README.md:351: claim: Agents no verb dispatches: \"Three serve no verb, and no command page calls on them\" \u2014 ruthless-reviewer, security-reviewer, sota-researcher. / reality: `abcd build`'s validate stage dispatches ruthless-reviewer and security-reviewer as lane validators and parses their SHIP/FIX FIRST and APPROVE/BLOCK/NEEDS-INPUT verdicts (internal/core/implement/loop/validate.go:70-101, internal/surface/cli/build.go:504); commands/build.md:262 calls on both, and 04-surfaces/34-build.md:417 documents it. Only sota-researcher serves no verb.", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: Duplicate of x-069: validate.go new in the cycle: stale prose." + }, + { + "id": "x-128", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/01-agents.md:31: claim: Repo-workflow reviewers and researchers, dispatched by a human rather than by a verb: docs-currency-reviewer, ruthless-reviewer, security-reviewer, and sota-researcher. / reality: ruthless-reviewer and security-reviewer are dispatched by the `build` verb's validate stage (internal/core/implement/loop/validate.go RoleRuthless/RoleSecurity; commands/build.md:262); docs-currency-reviewer is the release gate's semantic reviewer (commands/launch.md:808, 04-surfaces/README.md:376).", + "disposition": "deferred", + "note": "Design-record drift (cycle), deferred to the systematic brief pass iss-2609091956001547: validate.go dispatch new in the cycle; docs-currency-reviewer as release-gate reviewer at v0.11.1: stale prose." + }, + { + "id": "x-129", + "category": "false-claim", + "severity": "minor", + "summary": ".abcd/development/brief/05-internals/08-skills.md:19: claim: \"The release payload declares all four kinds\" (commands, skills, agents, hooks). / reality: The release payload's include list (.abcd/config/launch-payload.json) names commands, agents and hooks and no skills directory. The same page says so itself at lines 112-114 (\"the include list still names commands, agents and hooks and no skills directory\"). Only the install-surface resolver (internal/core/launch/installsurface.go conventionRules/declarationKeys) recognises all four kinds; the payload does not declare skills.", + "disposition": "deferred", + "note": "Design-record drift (standing), deferred to the systematic brief pass iss-2609091956001547: Duplicate of x-101: stale prose." + } + ] +} \ No newline at end of file From 175f22f63a14573be038bcc5ab08085edd4ae017 Mon Sep 17 00:00:00 2001 From: REPPL <77722411+REPPL@users.noreply.github.com> Date: Thu, 1 Oct 2026 00:15:31 +0100 Subject: [PATCH 7/8] docs: record the v0.12.0 gate outcomes and the publish agenda line Eleven of the docs-currency gate's 24 findings, the four major ones among them, are fixed in 4b8ff2afa and the re-cut CHANGELOG; the thirteen remaining minors and nitpicks are captured as one documentation record. The cross-check's three user-facing findings and every finding on the guard chapter are fixed before the content commit. Its behaviour findings are captured with the two defects the docs reviews surfaced, as four minor records to fix in the first lane after the tag; x-001 is the stated behaviour of the breaking change, and it and the rest of the design-record drift are deferred to the systematic brief pass. The DECISIONS entry carries the run's agenda line, approve the publish step, under ruling A2 and the releases ruling of 2026-09-25T08:04:52Z. Refs: iss-2609302305500526 Refs: iss-2609302306003610 Refs: iss-2609302306019245 Refs: iss-2609302306153318 Refs: iss-2609302306281487 Refs: iss-2609091956001547 Assisted-by: Claude:claude-opus-5-5 --- .abcd/work/DECISIONS.md | 1 + ...s-refusal-of-an-id-the-ledger-does-not-hold.md | 15 +++++++++++++++ ...ce-appendix-generator-labels-abcd-version-a.md | 15 +++++++++++++++ ...arents-comment-internal-core-guard-match-go.md | 15 +++++++++++++++ ...ord-and-docs-fidelity-apply-disagree-on-the.md | 15 +++++++++++++++ ...-docs-currency-minors-deferred-past-the-tag.md | 15 +++++++++++++++ 6 files changed, 76 insertions(+) create mode 100644 .abcd/work/issues/open/iss-2609302305500526-a-ledger-verb-s-refusal-of-an-id-the-ledger-does-not-hold.md create mode 100644 .abcd/work/issues/open/iss-2609302306003610-the-surface-appendix-generator-labels-abcd-version-a.md create mode 100644 .abcd/work/issues/open/iss-2609302306019245-the-guard-s-foldparents-comment-internal-core-guard-match-go.md create mode 100644 .abcd/work/issues/open/iss-2609302306153318-docs-fidelity-record-and-docs-fidelity-apply-disagree-on-the.md create mode 100644 .abcd/work/issues/open/iss-2609302306281487-v0-12-0-docs-currency-minors-deferred-past-the-tag.md diff --git a/.abcd/work/DECISIONS.md b/.abcd/work/DECISIONS.md index 45e598384..1b64ae6c3 100644 --- a/.abcd/work/DECISIONS.md +++ b/.abcd/work/DECISIONS.md @@ -2625,3 +2625,4 @@ together (the script's header says why there is no escape hatch). - 2026-09-30 — An older site interface-string file keeps building: `abcd site setup` and `abcd site build` add to `site-src/ui.json` each label the allowlist declares and the file does not carry, with abcd's default words, name each on stderr, and change nothing else in it (the product thinker's ruling TG1 of 2026-09-30, relayed verbatim: "(b) ABCD ADDS THE MISSING LABELS: on the next site setup or site build, abcd adds only the missing required labels (with the default words); the project's own wording elsewhere in ui.json is never changed. No failure, no manual step; both intents stay impact: additive."). It is the one exception to "a file the repository owns once it exists is kept", recorded as adr-2609301720596683, which refines adr-47 and leaves decision 2's closed allowlist untouched: a blank declared label and an unknown key are still refused, and the site gate's own render never completes the file. itd-2609212103568351 and itd-2609212103572513 keep `impact: additive` (lane tgLabels of autonomous run A). - 2026-09-30 — A command-line runner admits a harness reached through a directory, or a binary, that is group-writable only when the group is the system administrator group (gid 0 anywhere, gid 80 `admin` on darwin) and other cannot write it; other-writable stays refused whatever the group, and every other group stays refused (lane runner2Land of autonomous run A, `internal/core/runner/proc.go` `adminGroupWritableOnly`). Reason: the runner2 re-verification (reverify-runner2) found that on a Homebrew Mac `/opt/homebrew/bin` is `drwxrwsr-x` group admin, so a harness installed there was refused with the `chmod go-w` message; members of the administrator group can already act as root, so that write grants them nothing new, and asking a person to strip Homebrew's own directory mode would break Homebrew. - 2026-09-30 — Narrowing the administrator-group exception in the entry above (lane fix-runnerAdmin of autonomous run A, `internal/core/runner/proc.go` `adminGroupWritableOnly`): a command-line runner admits a harness binary, or a directory it is reached through, that is group-writable (never other-writable) only on darwin and only when the group is gid 80 `admin`; gid 0 is refused on every OS, and gid 80 is refused off darwin. Reason: the entry above granted gid 0 on the premise that members of the administrator group can already act as root, which holds for darwin's admin group (its members may sudo by default) but not for Linux's gid 0 root group nor darwin's gid 0 wheel, whose membership does not by itself let someone act as root (the runner2Land review note). The Homebrew `/opt/homebrew/bin` case the exception exists for is group admin, so it stays admitted. +- 2026-09-30 — Release v0.12.0 is cut by autonomous run A, and the run's agenda line is: approve the publish step. Under ruling A2 of the product thinker's run A interview (2026-09-23 07:52Z: the run approves the release environment itself once every gate is green) and the product thinker's releases ruling of 2026-09-25T08:04:52Z ("cut additional releases if that makes sense, but bundle multiple intents for it"), the run approves the `release` environment's deployment of v0.12.0 only after the merge queue, the verify job and every other gate on the tagged commit report green, and stops with a handover instead if any does not. The cut: v0.12.0, impact breaking (three breaking records, iss-2609251324599468, iss-2609291313276243 and iss-2609292359485570, and five removed command spellings the release guard found and the records declare), 281 records since v0.11.1: eleven shipped intents, all additive, and 270 resolved or declined issues (171 fixes, nineteen additive, three breaking, 77 internal and outside the changelog); the release guard passed, and the findings guard passed with the one major carried past v0.11.1 on its recorded deferral (iss-2609281134544802). Content commit fecdbed5, on top of 4b8ff2afa, e8d5d006, 4d634c4f and c8ddb042, which the gates' findings required. Both semantic gates ran at tier full over the first roll b89784c4, which differs from the content commit only by those four commits and the re-cut CHANGELOG. The docs-currency-reviewer (Fable 5.1) found 24, four major (a schema version the CHANGELOG and the upgrade guide gave as 4 where the binary writes 8, a build page's key shape, and a timeout the CHANGELOG gave to three hook entries where only UserPromptSubmit declares it), all four fixed; eleven in all are fixed in 4b8ff2afa and the re-cut CHANGELOG, and the thirteen remaining minors and nitpicks are captured as one documentation record (iss-2609302306281487). The brief-surface cross-check (45 pinned checkers, Opus 5.5, at most eight alive) found 129, all valid at b89784c4 on an independent classification (Fable 5.1): 39 cycle, 87 standing, three user-facing and four behaviour. The three user-facing findings are fixed in 4b8ff2afa, and every finding on the guard chapter 17-guard.md in e8d5d006, 4d634c4f and c8ddb042, after three docs-review holds; the docs review of c8ddb042 is PROMOTE. One brief sentence (17-guard.md:426) was applied from the reviewer's draft and is flagged for the product thinker's review in .abcd/work/brief-review-flags.json. Captured as four records, all minor and all to be fixed in the first lane after the tag: a capture refusal that leaves .iss-alloc.lock behind (iss-2609302305500526, x-025), the appendix generator labelling /abcd:version host-delegated (iss-2609302306003610, x-039 and x-118), the guard's trailing-dot fold that its comment promises and `rm -rf ../.` does not make (iss-2609302306019245), and `docs fidelity` record and --apply disagreeing on a verdict's chapter shape (iss-2609302306153318). The behaviour finding x-001 is not a defect: bare `ahoy remote` listing its sub-verbs and exiting 0 is the stated behaviour of v0.12.0's breaking change, so the stale side is the shipped intent's criterion; it and the rest of the design-record drift go to the systematic brief pass iss-2609091956001547. Integration branch 24d, reviewed and ready, holds until the tag and falls into the next release. diff --git a/.abcd/work/issues/open/iss-2609302305500526-a-ledger-verb-s-refusal-of-an-id-the-ledger-does-not-hold.md b/.abcd/work/issues/open/iss-2609302305500526-a-ledger-verb-s-refusal-of-an-id-the-ledger-does-not-hold.md new file mode 100644 index 000000000..ddccb2449 --- /dev/null +++ b/.abcd/work/issues/open/iss-2609302305500526-a-ledger-verb-s-refusal-of-an-id-the-ledger-does-not-hold.md @@ -0,0 +1,15 @@ +--- +schema_version: 1 +id: "iss-2609302305500526" +slug: "a-ledger-verb-s-refusal-of-an-id-the-ledger-does-not-hold" +severity: "minor" +category: "bug" +source: "review-followup" +found_during: "v0.12.0 release gate crosscheck (autonomous run A)" +origin: researcher-authored +production_mode: hand-written +found_at: "internal/core/capture/alloc.go" +remedy: "Check the id against the ledger before the allocation lock is taken, or remove the lock and every directory the lock step created on a refusal; a test in a bare git repository runs each refusing verb and asserts git status --porcelain is empty afterwards." +--- + +A ledger verb's refusal of an id the ledger does not hold writes to the tree: in a git checkout with no ledger, capture resolve, wontfix, link, defer, promote and remedy over an id the ledger does not hold each exit 2 as the capture chapter promises (06-capture.md:294-300, 'nothing written') but leave .abcd/work/issues/.iss-alloc.lock behind, creating the directory chain (lock name internal/core/capture/alloc.go:19). abcd's own .gitignore hides it here; in any other repository it shows as an untracked file. Refusals caught before the lock is taken (a missing --impact, a lone word) leave the tree empty. Found by the v0.12.0 release-gate brief-surface cross-check (x-025, checker a05), reproduced by the classifier at b89784c4; standing since before v0.11.1. diff --git a/.abcd/work/issues/open/iss-2609302306003610-the-surface-appendix-generator-labels-abcd-version-a.md b/.abcd/work/issues/open/iss-2609302306003610-the-surface-appendix-generator-labels-abcd-version-a.md new file mode 100644 index 000000000..76ef311df --- /dev/null +++ b/.abcd/work/issues/open/iss-2609302306003610-the-surface-appendix-generator-labels-abcd-version-a.md @@ -0,0 +1,15 @@ +--- +schema_version: 1 +id: "iss-2609302306003610" +slug: "the-surface-appendix-generator-labels-abcd-version-a" +severity: "minor" +category: "bug" +source: "review-followup" +found_during: "v0.12.0 release gate crosscheck (autonomous run A)" +origin: researcher-authored +production_mode: hand-written +found_at: "internal/core/surface/appendix.go" +remedy: "Emit HostDelegatedSentence only for a row the host_delegated list names, and give a root-flag surface such as version its own sentence naming the flag; regenerate the 12-version.md appendix and pin both sentences with a generator test." +--- + +The surface appendix generator labels /abcd:version a host-delegated command page: HostDelegatedSentence (internal/core/surface/appendix.go:84) is emitted for every shipped register row with no registered verb, so the generated appendix of 12-version.md:147 says the command page is host-delegated and has no flags, while commands/version.md runs the binary's root --version flag and record-lint.json's host_delegated list holds only consult, ingest and prepare-this-repo. The generator, not the prose, is wrong, and it re-emits the error on every regeneration. Found by the v0.12.0 release-gate brief-surface cross-check (x-039, checker a11, and its duplicate x-118, checker b00); the generator is new in the v0.12.0 cycle. diff --git a/.abcd/work/issues/open/iss-2609302306019245-the-guard-s-foldparents-comment-internal-core-guard-match-go.md b/.abcd/work/issues/open/iss-2609302306019245-the-guard-s-foldparents-comment-internal-core-guard-match-go.md new file mode 100644 index 000000000..314238abf --- /dev/null +++ b/.abcd/work/issues/open/iss-2609302306019245-the-guard-s-foldparents-comment-internal-core-guard-match-go.md @@ -0,0 +1,15 @@ +--- +schema_version: 1 +id: "iss-2609302306019245" +slug: "the-guard-s-foldparents-comment-internal-core-guard-match-go" +severity: "minor" +category: "inconsistency" +source: "review-followup" +found_during: "v0.12.0 release gate docs review (autonomous run A)" +origin: researcher-authored +production_mode: hand-written +found_at: "internal/core/guard/match.go" +remedy: "Decide the reading once: either fold a trailing . after a leading .. so ../. warns like .. (and widen 17-guard.md:426 back), or narrow the comment to the forms that fold; in both cases add a guard test that names ../., ./../. and ../../. with their verdicts." +--- + +The guard's foldParents comment (internal/core/guard/match.go:883-885) says a trailing . after a .. is folded, but rm -rf ../. is allowed: the fold of a trailing . happens only past a first segment (./../., $PWD/../. and x/../../. warn on rm-rf-working-directory), while ../., ../../., ./. and /. all allow. Harmless in practice, since rm refuses a path whose last segment is . or .., but the comment promises a reading the code does not make and no test in internal/core/guard names ../. at all. Found by the v0.12.0 release-gate docs review of 4d634c4f0 (a HOLD on 17-guard.md:426, whose sentence c8ddb0425 narrowed to ./../.); pre-existing from 4ef5013bd. diff --git a/.abcd/work/issues/open/iss-2609302306153318-docs-fidelity-record-and-docs-fidelity-apply-disagree-on-the.md b/.abcd/work/issues/open/iss-2609302306153318-docs-fidelity-record-and-docs-fidelity-apply-disagree-on-the.md new file mode 100644 index 000000000..ac733fc50 --- /dev/null +++ b/.abcd/work/issues/open/iss-2609302306153318-docs-fidelity-record-and-docs-fidelity-apply-disagree-on-the.md @@ -0,0 +1,15 @@ +--- +schema_version: 1 +id: "iss-2609302306153318" +slug: "docs-fidelity-record-and-docs-fidelity-apply-disagree-on-the" +severity: "minor" +category: "bug" +source: "review-followup" +found_during: "v0.12.0 release gate docs review (autonomous run A)" +origin: researcher-authored +production_mode: hand-written +found_at: "internal/core/docfidelity/store.go" +remedy: "Validate every failing entry's chapter at record time with the same chapterNameRe Apply uses (or normalise a 04-surfaces/ prefix in both places), so record refuses what apply would refuse; a test records and applies a verdict in each shape." +--- + +docs fidelity record and docs fidelity --apply disagree on the shape of a verdict's chapter: record checks only that a failing entry's chapter is non-empty (internal/core/docfidelity/store.go:248-249), so it saved a HOLD naming "04-surfaces/17-guard.md", and --apply then refused that same verdict with "the edit's chapter ... is not a chapter file under .abcd/development/brief/04-surfaces" (Apply's one-component chapterNameRe, internal/core/docfidelity/apply.go:31,64). A verdict the recorder accepts cannot be applied, and the reviewer has to re-record it by hand. Found while applying the v0.12.0 release-gate docs review of 4d634c4f0 (the correction landed as c8ddb0425). diff --git a/.abcd/work/issues/open/iss-2609302306281487-v0-12-0-docs-currency-minors-deferred-past-the-tag.md b/.abcd/work/issues/open/iss-2609302306281487-v0-12-0-docs-currency-minors-deferred-past-the-tag.md new file mode 100644 index 000000000..4c54b1d84 --- /dev/null +++ b/.abcd/work/issues/open/iss-2609302306281487-v0-12-0-docs-currency-minors-deferred-past-the-tag.md @@ -0,0 +1,15 @@ +--- +schema_version: 1 +id: "iss-2609302306281487" +slug: "v0-12-0-docs-currency-minors-deferred-past-the-tag" +severity: "minor" +category: "documentation" +source: "review-followup" +found_during: "v0.12.0 release gate docs-currency review (autonomous run A)" +origin: researcher-authored +production_mode: hand-written +found_at: "commands" +remedy: "Correct each page line against the binary as its finding states (argument-hints, flag lists, the JSON key, the project name, the User input line), and correct dc-3/dc-4/dc-24 in the next release's records rather than editing the shipped v0.12.0 section; docs-lint and the plugin page tests stay green." +--- + +Thirteen v0.12.0 docs-currency findings are deferred past the tag, all minor or nitpick: dc-3 (CHANGELOG.md:37 and RELEASE.md:35 call a role-word ban a bundled docs-lint rule; it is a pattern in this repository's .abcd/docs-lint.json), dc-4 (CHANGELOG.md:21 preamble vs the two breaking bullets filed under Added), dc-6 (commands/ahoy.md:23-24 a status argument the binary refuses), dc-8 (commands/ahoy.md:4 argument-hint omits credential), dc-10 (commands/capture.md:4 argument-hint omits mentions), dc-11 (commands/capture.md:633-635 widening_runs sits under reading_outstanding), dc-12 (commands/docs.md:4,75-118 omit docs fidelity --intent), dc-13 (commands/history.md:4 ingest hint omits the required --into), dc-14 (commands/implement.md:42-54 omit join --model and --reason), dc-16 (commands/ingest.md:4,119 no User input line for its argument-hint), dc-21 (commands/launch.md:4 argument-hint omits receipts), dc-22 (commands/launch.md:1035 names the project abcd-cli), dc-24 (resolved iss-323's resolution says all three salvage entries declare the 120-second timeout; only UserPromptSubmit does since 6a40c898b). Found by the v0.12.0 release-gate docs-currency review (Fable 5.1, tier full) over b89784c4. From ce3261714ad7476d8807357a2632b7c2bf0e3be2 Mon Sep 17 00:00:00 2001 From: REPPL <77722411+REPPL@users.noreply.github.com> Date: Thu, 1 Oct 2026 00:23:39 +0100 Subject: [PATCH 8/8] docs: state the guard's JSON answer without spelling its flag in the prose The guard chapter's prose above its generated appendix named a verb and a flag, which the brief's shape rule keeps to the appendix alone. The sentences say the same thing without the spelling: the check answers in JSON when asked, and the hook writes nothing on stdout in either output form. Assisted-by: Claude:claude-opus-5-5 --- .abcd/development/brief/04-surfaces/17-guard.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.abcd/development/brief/04-surfaces/17-guard.md b/.abcd/development/brief/04-surfaces/17-guard.md index d7cb11a32..ad6ea914c 100644 --- a/.abcd/development/brief/04-surfaces/17-guard.md +++ b/.abcd/development/brief/04-surfaces/17-guard.md @@ -65,14 +65,13 @@ the hook: it is blocked (`command-unparsable`), not let through, because a line the guard misreads may be one bash runs, and a pass would carry every hazard in it past the guard. On the check it exits 2, like the rest. -The check also speaks JSON (`guard check --json`), and that is the form the -plugin page uses: a verdict, and with it the entry that fired, its tier, why the -command is dangerous, and the safe successor. A `matches` list names every entry -the same line tripped, the one that fired included, so a command hazardous in -two ways reports both rather than only the first; the rendered form says the -same thing on an `also matched:` line. The hook answers the host by its exit -code and its message on stderr alone, and writes nothing on stdout, with or -without `--json`. +The check also answers in JSON when asked, and that is the form the plugin page +uses: a verdict, and with it the entry that fired, its tier, why the command is +dangerous, and the safe successor. A `matches` list names every entry the same +line tripped, the one that fired included, so a command hazardous in two ways +reports both rather than only the first; the rendered form says the same thing +on an `also matched:` line. The hook answers the host by its exit code and its +message on stderr alone, and writes nothing on stdout in either output form. ## Taught before it is refused