From 4a0694e138037b19eb65d359e695650eb5ef7f2d Mon Sep 17 00:00:00 2001 From: REPPL <77722411+REPPL@users.noreply.github.com> Date: Tue, 28 Jul 2026 08:55:23 +0100 Subject: [PATCH 1/3] =?UTF-8?q?chore:=20ship=20itd-102/103/104=20=E2=80=94?= =?UTF-8?q?=20close=20spc-16/18/19?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ship flow for the three merged arcs (PRs #156/#157/#158): specs open->closed, intents planned->shipped. Fidelity-review receipts rcp-c09c73d6adc5 (itd-103), rcp-37a162874f75 (itd-104), rcp-52648dea351e (itd-102) are owed and tracked by the release gate. Assisted-by: Claude:claude-fable-5 --- ...-repo-says-the-same-thing-about-itself-everywhere-becaus.md | 3 ++- ...d-teaches-repo-agents-the-shell-commands-they-must-never.md | 3 ++- ...-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md | 3 ++- ...d-teaches-repo-agents-the-shell-commands-they-must-never.md | 0 ...-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md | 0 ...-repo-says-the-same-thing-about-itself-everywhere-becaus.md | 0 6 files changed, 6 insertions(+), 3 deletions(-) rename .abcd/development/intents/{planned => shipped}/itd-102-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md (97%) rename .abcd/development/intents/{planned => shipped}/itd-103-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md (97%) rename .abcd/development/intents/{planned => shipped}/itd-104-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md (98%) rename .abcd/development/specs/{open => closed}/spc-16-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md (100%) rename .abcd/development/specs/{open => closed}/spc-18-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md (100%) rename .abcd/development/specs/{open => closed}/spc-19-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md (100%) diff --git a/.abcd/development/intents/planned/itd-102-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md b/.abcd/development/intents/shipped/itd-102-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md similarity index 97% rename from .abcd/development/intents/planned/itd-102-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md rename to .abcd/development/intents/shipped/itd-102-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md index 05cbcce..cd32ef1 100644 --- a/.abcd/development/intents/planned/itd-102-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md +++ b/.abcd/development/intents/shipped/itd-102-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md @@ -39,4 +39,5 @@ impact: additive ## Audit Notes -_Empty. Populated by intent-fidelity-reviewer when intent moves to shipped/._ + +Fidelity review OWED (receipt rcp-52648dea351e). diff --git a/.abcd/development/intents/planned/itd-103-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md b/.abcd/development/intents/shipped/itd-103-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md similarity index 97% rename from .abcd/development/intents/planned/itd-103-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md rename to .abcd/development/intents/shipped/itd-103-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md index 6732e30..6fedf60 100644 --- a/.abcd/development/intents/planned/itd-103-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md +++ b/.abcd/development/intents/shipped/itd-103-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md @@ -39,4 +39,5 @@ impact: additive ## Audit Notes -_Empty. Populated by intent-fidelity-reviewer when intent moves to shipped/._ + +Fidelity review OWED (receipt rcp-c09c73d6adc5). diff --git a/.abcd/development/intents/planned/itd-104-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md b/.abcd/development/intents/shipped/itd-104-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md similarity index 98% rename from .abcd/development/intents/planned/itd-104-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md rename to .abcd/development/intents/shipped/itd-104-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md index 3af5963..8bcc14c 100644 --- a/.abcd/development/intents/planned/itd-104-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md +++ b/.abcd/development/intents/shipped/itd-104-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md @@ -39,4 +39,5 @@ impact: additive ## Audit Notes -_Empty. Populated by intent-fidelity-reviewer when intent moves to shipped/._ + +Fidelity review OWED (receipt rcp-37a162874f75). diff --git a/.abcd/development/specs/open/spc-16-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md b/.abcd/development/specs/closed/spc-16-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md similarity index 100% rename from .abcd/development/specs/open/spc-16-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md rename to .abcd/development/specs/closed/spc-16-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md diff --git a/.abcd/development/specs/open/spc-18-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md b/.abcd/development/specs/closed/spc-18-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md similarity index 100% rename from .abcd/development/specs/open/spc-18-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md rename to .abcd/development/specs/closed/spc-18-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md diff --git a/.abcd/development/specs/open/spc-19-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md b/.abcd/development/specs/closed/spc-19-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md similarity index 100% rename from .abcd/development/specs/open/spc-19-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md rename to .abcd/development/specs/closed/spc-19-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md From 1d915554de44bf6376c7769a43f6ab7c8f1eab28 Mon Sep 17 00:00:00 2001 From: REPPL <77722411+REPPL@users.noreply.github.com> Date: Tue, 28 Jul 2026 09:03:11 +0100 Subject: [PATCH 2/3] =?UTF-8?q?chore:=20cut=20v0.4.1=20=E2=80=94=20date=20?= =?UTF-8?q?the=20changelog,=20fix=20surface=20links=20post-ship?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Roll the [Unreleased] section into a dated 0.4.1 heading (the binary's one-time migration off hand-written changelogs; a derived cut refuses to fold hand-written prose) and repoint the guard/ideate/identity surface pages at the now-shipped intents and closed specs. Assisted-by: Claude:claude-fable-5 --- .abcd/development/brief/04-surfaces/17-guard.md | 4 ++-- .abcd/development/brief/04-surfaces/18-ideate.md | 4 ++-- .abcd/development/brief/04-surfaces/19-identity.md | 4 ++-- CHANGELOG.md | 2 ++ 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.abcd/development/brief/04-surfaces/17-guard.md b/.abcd/development/brief/04-surfaces/17-guard.md index cba0d1c..4f9bc51 100644 --- a/.abcd/development/brief/04-surfaces/17-guard.md +++ b/.abcd/development/brief/04-surfaces/17-guard.md @@ -99,6 +99,6 @@ promoted into the bundled defaults through the admission gate. ## References - Plugin command: [`commands/abcd/guard.md`](../../../../commands/abcd/guard.md) -- Spec: [`spc-16`](../../specs/open/spc-16-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md) -- Intent: [`itd-103`](../../intents/planned/itd-103-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md) +- Spec: [`spc-16`](../../specs/closed/spc-16-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md) +- Intent: [`itd-103`](../../intents/shipped/itd-103-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md) - Install/health surface: [`01-ahoy.md`](01-ahoy.md) diff --git a/.abcd/development/brief/04-surfaces/18-ideate.md b/.abcd/development/brief/04-surfaces/18-ideate.md index 1544bc6..8f4737a 100644 --- a/.abcd/development/brief/04-surfaces/18-ideate.md +++ b/.abcd/development/brief/04-surfaces/18-ideate.md @@ -93,6 +93,6 @@ later session trusts it. ## References - Plugin command: [`commands/abcd/ideate.md`](../../../../commands/abcd/ideate.md) -- Intent: [`itd-104`](../../intents/planned/itd-104-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md) -- Spec: [`spc-18`](../../specs/open/spc-18-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md) +- Intent: [`itd-104`](../../intents/shipped/itd-104-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md) +- Spec: [`spc-18`](../../specs/closed/spc-18-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md) - Routing-help neighbours: [`05-intent.md`](05-intent.md), [`06-capture.md`](06-capture.md) diff --git a/.abcd/development/brief/04-surfaces/19-identity.md b/.abcd/development/brief/04-surfaces/19-identity.md index e345529..30ac076 100644 --- a/.abcd/development/brief/04-surfaces/19-identity.md +++ b/.abcd/development/brief/04-surfaces/19-identity.md @@ -79,7 +79,7 @@ the recorded three-variant tagline drift this check exists to catch. ## References - Plugin command: [`commands/abcd/identity.md`](../../../../commands/abcd/identity.md) -- Spec: [`spc-19`](../../specs/open/spc-19-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md) -- Intent: [`itd-102`](../../intents/planned/itd-102-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md) +- Spec: [`spc-19`](../../specs/closed/spc-19-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md) +- Intent: [`itd-102`](../../intents/shipped/itd-102-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md) - Onboarding consumer: [`15-prepare-this-repo.md`](15-prepare-this-repo.md) - Conformance surface: [`16-audit.md`](16-audit.md) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24c4782..756e494 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ called out in a **Breaking** section. ## [Unreleased] +## [0.4.1] - 2026-07-28 + ### Added - **`abcd identity` — one canonical identity block, and every surface held to From b1dbe01902d4a5658cd4269a7e933f46306fa68b Mon Sep 17 00:00:00 2001 From: REPPL <77722411+REPPL@users.noreply.github.com> Date: Tue, 28 Jul 2026 09:12:22 +0100 Subject: [PATCH 3/3] chore: ingest fidelity verdicts for itd-102/103/104; capture iss-151 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ship-flow fidelity reviews (receipts rcp-52648dea351e, rcp-c09c73d6adc5, rcp-37a162874f75) ingested into the shipped intents' Audit Notes: - itd-102: 4 MET - itd-103: 3 MET, 1 MET_WITH_CONCERNS (working-tree override, iss-147) - itd-104: 3 MET, 1 MET_WITH_CONCERNS (adversarial fresh-context is prompt-enforced, not binary-provable — spec-consistent) iss-151 captures the itd-103 headline gap: only the guard plane shipped; the teaching plane (rules-loader safety domain) is unwired. Assisted-by: Claude:claude-fable-5 --- ...me-thing-about-itself-everywhere-becaus.md | 50 ++++++++++++++++- ...ents-the-shell-commands-they-must-never.md | 53 ++++++++++++++++++- ...-before-it-becomes-a-record-entry-resea.md | 50 ++++++++++++++++- ...one-of-its-two-promised-planes-the-exec.md | 11 ++++ 4 files changed, 158 insertions(+), 6 deletions(-) create mode 100644 .abcd/work/issues/open/iss-151-itd-103-shipped-only-one-of-its-two-promised-planes-the-exec.md diff --git a/.abcd/development/intents/shipped/itd-102-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md b/.abcd/development/intents/shipped/itd-102-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md index cd32ef1..0f372b5 100644 --- a/.abcd/development/intents/shipped/itd-102-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md +++ b/.abcd/development/intents/shipped/itd-102-your-repo-says-the-same-thing-about-itself-everywhere-becaus.md @@ -39,5 +39,51 @@ impact: additive ## Audit Notes - -Fidelity review OWED (receipt rcp-52648dea351e). + +Fidelity review — receipt rcp-52648dea351e (verifier abcd:intent-fidelity-reviewer claude-fable-5). + +Provenance: abcd:intent-fidelity-reviewer@claude-fable-5 · rubric_hash sha256:d401343707d6fa0f8fabad4c67380b1ec356ffd47f1b72a4e1b56ed320e25a4a · prompt_hash sha256:95792472ae74ca0469f69a51c618946e0d33cb1380032460099ed4b469d67e86 +Input attestations: diff:PR#158 feat/itd-102-repo-identity @ ca1459805dd4cc3d48adc39433bbd34b098736dd (base main): internal/core/positioning/, internal/core/audit/rule_positioning.go, internal/surface/cli/identity.go, commands/abcd/identity.md, commands/abcd/prepare-this-repo.md, .abcd/positioning.json, internal/fsutil os.Root containment@-; rubric:.abcd/.work.local/reviews/rcp-52648dea351e.request.md@sha256:d401343707d6fa0f8fabad4c67380b1ec356ffd47f1b72a4e1b56ed320e25a4a; + +Acceptance rollup: MET 4 · MET_WITH_CONCERNS 0 · NOT_MET 0 · INCONCLUSIVE 0 + +Per-criterion verdicts: +- ac-1 — MET: The onboarding interview (prepare-this-repo, detect-then-interview) calls `abcd identity init`, which writes the identity into a fixed-bullet markdown block and records its location in the repo's positioning registry — markdown is the single source of truth, the registry only points at it. + evidence: internal/core/positioning/init.go:159 — "fmt.Fprintf(&b, \"- **Title:** %s\\n\", title) … - **Tagline:** … - **Pitch:** (fixed bullet shape)" + evidence: internal/core/positioning/init.go:141 — "if err := writeConfig(r, DefaultConfig(loc)); err != nil — records where the block lives in ConfigRelPath" + evidence: commands/abcd/prepare-this-repo.md:118 — "Identity — detect first, interview only if there is nothing to detect … abcd identity init --title \"…\" --tagline \"…\" [--pitch \"…\"]" + evidence: internal/core/positioning/block.go:85 — "bulletRe = regexp.MustCompile(`^ {0,3}[-*]\\s+\\*\\*([A-Za-z]+):\\*\\*\\s*(.*)$`) — parses the fixed bullet shape back out" +- ac-2 — MET: checkSurface flags a diverged surface StatusDrifted; the audit rule emits a finding naming the file, the 1-based line, the exact drifted text and the canonical line; it is SeverityWarn by default and severityFor upgrades the whole family to SeverityError when the registry sets severity=blocker — both halves are test-enforced (TestPositioningDriftIsAWarnFindingNamingTheExactLine, TestPositioningSeverityUpgradesToBlocker) and passed. + evidence: internal/core/audit/rule_positioning.go:87 — "surface %q no longer carries the canonical %s — it says %q; the identity block (%s) says %q (File+Line set from s.File/s.Line)" + evidence: internal/core/audit/rule_positioning.go:107 — "func severityFor … if EqualFold(cfg.Severity, SeverityBlocker) { return SeverityError } default SeverityWarn" + evidence: cmd: go test -run 'TestPositioningSeverityUpgradesToBlocker' ./internal/core/audit/ (via full pkg run) — "ok github.com/REPPL/abcd-cli/internal/core/audit — AC2 second half: per-repo config upgrades the whole family to blocker" +- ac-3 — MET: The only re-render path is Propose, which returns unified diffs and performs no writes ('It performs no writes whatsoever'); the CLI `abcd identity render` writes nothing and no flag makes it, and the command doc states it plainly — a deliberate identity change is an edit to the block, never an autonomous rewrite. + evidence: internal/core/positioning/render.go:48 — "It performs no writes whatsoever." + evidence: internal/surface/cli/identity.go:51 — "Print the proposed correction for every drifted surface as a unified diff (writes nothing)" + evidence: commands/abcd/identity.md:43 — "prints a unified diff per drifted surface. It **writes nothing**, and no flag" +- ac-4 — MET: abcd-cli's own .abcd/positioning.json points the block at the brief product chapter's pre-existing 'Identity (canonical)' section in .abcd/development/brief/01-product/README.md, which PR#158 does not touch (its last change was the earlier iss-143 consolidation commit 48a3524, not this positioning work); and the iss-143 three-variant drift corpus is captured verbatim and caught — one-at-a-time and all-three-together tests pass. + evidence: .abcd/positioning.json:4 — "\"file\": \".abcd/development/brief/01-product/README.md\", \"heading\": \"Identity (canonical)\"" + evidence: cmd: gh pr diff 158 --name-only | grep 01-product — "NOT in PR diff — the brief Identity section is pointed at unchanged (last touched by 48a3524, not PR#158)" + evidence: internal/core/positioning/check_test.go:140 — "func TestCheckCatchesTheIss143DriftCorpus — the three real drifted variants (readme-strapline, manifest-description, conventions-opening) each caught StatusDrifted" + evidence: cmd: go test -run 'TestCheckCatchesTheIss143DriftCorpus|TestCheckCatchesAllThreeVariantsTogether' -v ./internal/core/positioning/ — "--- PASS: TestCheckCatchesTheIss143DriftCorpus / --- PASS: TestCheckCatchesAllThreeVariantsTogether (Drifted()==3)" + +Gap audit: +- honoured: + - One canonical markdown identity block is the single home; the config records only where it lives + evidence: internal/core/positioning/init.go:151 — "func blockSection … The single recorded home for how this project names itself" + evidence: .abcd/positioning.json:2 — "\"block\": { \"file\": …, \"heading\": \"Identity (canonical)\" }" + - Every registered surface is compared to the block on every audit; a mismatch names the exact drifted line and the canonical line + evidence: internal/core/audit/rule_positioning.go:87 — "it says %q; the identity block (%s) says %q" + evidence: internal/core/positioning/check.go:141 — "res.Status = StatusOK … if len(res.Missing) > 0 { res.Status = StatusDrifted }" + - The fix is a proposed diff or a deliberate recorded block change — never a silent extra variant, never a silent rewrite + evidence: internal/surface/cli/identity.go:164 — "%d proposed change(s), nothing written. Adopt what you agree with." + evidence: internal/core/positioning/init.go:91 — "ErrAlreadyAdopted … change the block there, or edit %s deliberately — re-running onboarding never repoints the canon" + - iss-143's three-variant tagline drift is the acceptance corpus and is caught + evidence: internal/core/positioning/check_test.go:55 — "The iss-143 acceptance corpus: the three real drifted variants the repo was carrying" + - Rule is wired into the production audit path (not dead scaffolding) + evidence: internal/core/audit/rules.go:12 — "identityPositioning{} — registered in DefaultRules()" + evidence: internal/surface/cli/cli.go:97 — "root.AddCommand(newIdentityCommand(&asJSON))" +- diverged: + - Onboarding is described as an install-or-prepare interview, but abcd currently onboards only via the prepare-this-repo bridge (host asks the questions); there is no separate install-time interview beyond the CLI `identity init` it drives — a narrower-than-worded but functionally complete path + evidence: internal/core/positioning/init.go:35 — "InitRequest is the onboarding interview's outcome. The host asks the questions (the prepare surface carries the wording); this is what it hands over." +- missing: (none) \ No newline at end of file diff --git a/.abcd/development/intents/shipped/itd-103-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md b/.abcd/development/intents/shipped/itd-103-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md index 6fedf60..268f39b 100644 --- a/.abcd/development/intents/shipped/itd-103-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md +++ b/.abcd/development/intents/shipped/itd-103-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md @@ -39,5 +39,54 @@ impact: additive ## Audit Notes - -Fidelity review OWED (receipt rcp-c09c73d6adc5). + +Fidelity review — receipt rcp-c09c73d6adc5 (verifier abcd:intent-fidelity-reviewer claude-fable-5). + +Provenance: abcd:intent-fidelity-reviewer@claude-fable-5 · rubric_hash sha256:e96fe6d7a3f6bfe3908171b52f5bd42de194298ead0093ffab6b377adc9dd3bc · prompt_hash sha256:f4de8b23c6b6c7a54133bf2042b6b89829c579412cf26f1f66a65c36d57aa6fe +Input attestations: diff:main..feat/itd-103-shell-hazard-registry (PR #156, merge 49cffa05): internal/core/guard/, internal/surface/cli/guard.go, internal/core/ahoy/guard_health.go, commands/abcd/guard.md, hooks/hooks.json@sha256:49cffa05e6216d9cbb29dc601961464781e6541d; rubric:.abcd/.work.local/reviews/rcp-c09c73d6adc5.request.md@sha256:e96fe6d7a3f6bfe3908171b52f5bd42de194298ead0093ffab6b377adc9dd3bc; + +Acceptance rollup: MET 3 · MET_WITH_CONCERNS 1 · NOT_MET 0 · INCONCLUSIVE 0 + +Per-criterion verdicts: +- ac-1 — MET: Every non-decision path in the hook adapter routes through one failOpen that exits 1 (non-zero, non-blocking) and prints 'NOT CHECKED — ... runs UNGUARDED'; the hooks.json wrapper catches even an unexpected exit and fails open loudly; and guard health is a first-class ahoy field wired into the status render — never a silent no-op, never a bricked session. + evidence: internal/surface/cli/guard.go:145 — "\"abcd guard: NOT CHECKED — \"+format+\". This command runs UNGUARDED.\\n\" ... return &exitError{Code: 1}" + evidence: hooks/hooks.json:13 — "[ $s -eq 0 ] || [ $s -eq 1 ] || [ $s -eq 2 ] || { echo \"abcd guard: FAILED TO RUN (exit $s) — shell commands run UNGUARDED ...\" >&2; exit 1; }" + evidence: internal/core/ahoy/detect.go:78 — "res.Guard = detectGuardHealth(abs, pluginRoot, pluginOK)" + evidence: internal/surface/cli/cli.go:1453 — "fmt.Fprintf(w, \" guard: %s\\n\", guardHealthLine(res.Guard))" +- ac-2 — MET_WITH_CONCERNS: A blocker refuses with the successor built into the block message and a warn passes with the warning surfaced, and the only disable route is the per-repo .abcd/guard.json config (no in-session flag or env bypass exists) — CONCERN: that override takes effect from the WORKING TREE before it is committed or reviewed (config.Load reads .abcd/guard.json off disk; iss-147 records this exactly), so it is reviewable-in-a-diff but the criterion's 'committed' qualifier is not actually enforced. + evidence: internal/core/guard/guard.go:300 — "return fmt.Sprintf(\"%s by the abcd guard (%s): %s Run instead: %s\", lead, e.ID, e.Why, e.Successor)" + evidence: internal/surface/cli/guard.go:198 — "case guard.VerdictBlock: ... fmt.Fprintln(cmd.ErrOrStderr(), termsafe.Sanitize(dec.Message)); return &exitError{Code: 2}" + evidence: internal/core/guard/config.go:34 — "data, err := fsutil.ReadGuarded(filepath.Join(repoRoot, \".abcd\", \"guard.json\"), maxGuardFileBytes)" + evidence: .abcd/work/issues/open/iss-147-guard-load-reads-abcd-guard-json-from-the-working-tree-so-a.md:4 — "guard-load-reads-abcd-guard-json-from-the-working-tree" +- ac-3 — MET: tokenize honours shell quoting and recognises operators outside quotes only, so a hazard inside a quoted argument stays one non-command token; matching runs in command position via commandOf/matchSegment; the cd-chain is enforced by AfterCD + precededByCD scanning earlier segments of the SAME chain across &&/;/||/| separators; and TestIncidentCaptureIsKnownGoodFixtureOne pins this repo's own quoted 'cd scratch && rm -rf *' capture as a known-good that must not fire. + evidence: internal/core/guard/tokenize.go:23 — "Operators and comments are recognised OUTSIDE quotes only, which is exactly what keeps a hazard named inside a quoted argument from ever reaching command position." + evidence: internal/core/guard/match.go:41 — "if matchSegment(p, s) && (p.AfterCD == nil || !*p.AfterCD || precededByCD(segs[:i], s.chain))" + evidence: internal/core/guard/match.go:51 — "func precededByCD(before []segment, chain int) bool { ... if cmd, _ := commandOf(s); cmd == \"cd\"" + evidence: internal/core/guard/fixtures_test.go:104 — "if !containsAll(first, \"capture\", \"cd scratch && rm -rf *\")" +- ac-4 — MET: The admission gate TestBundledEntriesPassAdmissionGate fails the build unless every bundled entry ships known-bad AND known-good fixtures, known-good is at least 40% of the corpus (10*good < 4*(good+bad)), and every known-good fires nothing (a declared 100% true-negative floor); the 6 shipped entries all clear it (e.g. rm-rf-after-cd-chain 8/17 good = 47%); and the eval / sh -c string-payload gap is documented, not silent, in the tokenizer, the CLI reference, and the surface brief. + evidence: internal/core/guard/fixtures_test.go:41 — "if 10*good < 4*(good+bad) { t.Fatalf(\"entry %s: known-good is %d of %d fixtures, below the 40%% floor\" ...)" + evidence: internal/core/guard/fixtures_test.go:66 — "if d.Verdict != VerdictAllow { t.Fatalf(\"known-good %q fired %v ...; the true-negative floor is 100%%\" ...)" + evidence: internal/core/guard/tokenize.go:26 — "v1 GAP (documented, not silent): ... A command string carried as a DATA argument — `sh -c ''`, `eval ''` ... its payload is never parsed" + evidence: .abcd/development/brief/04-surfaces/17-guard.md:86 — "a command string handed to an interpreter (`eval`, `sh -c`)" + +Gap audit: +- honoured: + - A deterministic guard, a core verb any harness hook can call, refuses a matching command and replies with the safe successor so the block itself is the lesson + evidence: internal/core/guard/guard.go:246 — "func (r Registry) Check(command string) (Decision, error)" + evidence: internal/surface/cli/guard.go:122 — "newGuardHookCommand builds `guard hook`: the adapter between a host's pre-tool-use hook payload and the core decision" + - Two tiers mirroring the docs-lint family: a blocker refuses, a warn passes with the warning attached + evidence: internal/core/guard/guard.go:19 — "TierBlocker = \"blocker\" ... TierWarn = \"warn\"" + evidence: internal/surface/cli/guard.go:200 — "case guard.VerdictWarn: fmt.Fprintln(cmd.ErrOrStderr(), termsafe.Sanitize(dec.Message)); return nil" + - Each entry ships a fixture that proves its guard fires, enforced as a build-time admission gate + evidence: internal/core/guard/fixtures_test.go:19 — "func TestBundledEntriesPassAdmissionGate" + evidence: internal/core/guard/defaults/guard.json:1 — "6 entries, each carrying known_bad + known_good fixtures" + - The known-good corpus is not optional: this repo's own incident-capture command must not be blocked + evidence: internal/core/guard/fixtures_test.go:95 — "func TestIncidentCaptureIsKnownGoodFixtureOne" +- diverged: + - The only escape is a COMMITTED per-repo config override — delivered as a per-repo .abcd/guard.json read from the working tree, so it activates before commit/review (reviewable in a diff, but 'committed' is not enforced) + evidence: internal/core/guard/config.go:34 — "fsutil.ReadGuarded(filepath.Join(repoRoot, \".abcd\", \"guard.json\") ...)" + evidence: internal/surface/cli/guard.go:275 — "the file is read from the working tree, so this can be true before anyone has reviewed the edit that made it true (iss-147)" +- missing: + - Press-release 'two planes': the teaching plane — the rules loader injecting the matched safety rules before shell-heavy work — is not wired in this delivery; only the execution-time guard plane ships (a guard/safety rules domain does not exist in internal/core/rules/) + evidence: .abcd/development/intents/shipped/itd-103-abcd-teaches-repo-agents-the-shell-commands-they-must-never.md:13 — "The rules loader injects the matched safety rules before shell-heavy work" + evidence: internal/core/rules/rules.go:401 — "no guard/safety/hazard domain is registered — the only `guard` here is the stemming short-token guard" \ No newline at end of file diff --git a/.abcd/development/intents/shipped/itd-104-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md b/.abcd/development/intents/shipped/itd-104-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md index 8bcc14c..15d4e73 100644 --- a/.abcd/development/intents/shipped/itd-104-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md +++ b/.abcd/development/intents/shipped/itd-104-abcd-gates-a-new-idea-before-it-becomes-a-record-entry-resea.md @@ -39,5 +39,51 @@ impact: additive ## Audit Notes - -Fidelity review OWED (receipt rcp-37a162874f75). + +Fidelity review — receipt rcp-37a162874f75 (verifier abcd:intent-fidelity-reviewer claude-fable-5). + +Provenance: abcd:intent-fidelity-reviewer@claude-fable-5 · rubric_hash sha256:1aa9117683cdc84ea4bcbae37c95edab738938331fdb6d39d5d00ea051db4141 · prompt_hash sha256:95792472ae74ca0469f69a51c618946e0d33cb1380032460099ed4b469d67e86 +Input attestations: diff:PR 157 main..e05a58ef44b970f7d8db65d7502675bf9a46c3d9: internal/core/ideate/ (ideate.go, record.go, render.go), internal/core/recordid/resolve.go, internal/surface/cli/ideate.go + cli.go ideate wiring, commands/abcd/ideate.md, routing help in commands/abcd/{intent,capture}.md@sha256:e05a58ef44b970f7d8db65d7502675bf9a46c3d9; rubric:.abcd/.work.local/reviews/rcp-37a162874f75.request.md@sha256:1aa9117683cdc84ea4bcbae37c95edab738938331fdb6d39d5d00ea051db4141; + +Acceptance rollup: MET 3 · MET_WITH_CONCERNS 1 · NOT_MET 0 · INCONCLUSIVE 0 + +Per-criterion verdicts: +- ac-1 — MET: The bare intent and capture status renders both print ideateRoutingRule (an optional pointer for a big, unproven idea) with no gate wording, and nothing in the ideate package is reachable from capture or intent-create; TestIdeateRoutingHintIsAPointerNotAGate enforces both facts and passes. + evidence: internal/surface/cli/cli.go:1255 — "const ideateRoutingRule = \" a big, unproven idea? `abcd ideate` runs the optional admission gauntlet and records the verdict either way\\n\"" + evidence: internal/surface/cli/cli.go:1119 — "fmt.Fprint(w, ideateRoutingRule) // bare `abcd intent` render; mirrored at cli.go:1746 for `abcd capture`" + evidence: internal/surface/cli/ideate_surface_test.go:177 — "for _, forbidden := range []string{\"must\", \"required\", \"before you\", \"warning\"} { ... presents ideate as a gate" +- ac-2 — MET_WITH_CONCERNS: The three legs and their required order are binary-enforced — legOrder is [research, record-grill, adversarial-review] and validate() refuses any leg out of position or carrying another leg's evidence — but the adversarial leg's defining fresh-context/off-policy/unknown-authorship property is delegated to the ideate.md prompt and is by design unverifiable at ingest (validateAdversarial only checks non-empty kill attempts and outcomes), so that debiasing property rests on prompt compliance, not on the recorded artefact. + evidence: internal/core/ideate/ideate.go:145 — "var legOrder = []LegKind{LegResearch, LegRecordGrill, LegAdversarialReview}" + evidence: internal/core/ideate/record.go:274 — "if leg.Kind != legOrder[i] { ... the legs run in order (%s), and the order is what each leg is looking at" + evidence: internal/core/ideate/record.go:367 — "The leg's fresh-context, off-policy, unknown-authorship conduct is the orchestrating prompt's obligation — the binary cannot observe how an agent was run" + evidence: commands/abcd/ideate.md:71 — "Strip every authorship signal before handing the artefact over ... This is the only measured debiasing effect in the whole protocol" +- ac-3 — MET: Record() writes the durable verdict for every registered outcome (survives/killed/reframed) and refuses a payload whose rejected-alternatives arrive empty by omission (the explicit no_rejected_alternatives marker is required), while graduation is gated on survival — Result.Graduates is verdict==survives and renderOutcome offers the draft-intent path only for survives, ideate minting no intent itself. + evidence: internal/core/ideate/record.go:405 — "if !p.NoRejectedAlternatives { ... the verdict records no rejected alternatives and does not say so explicitly — nothing was written" + evidence: internal/core/ideate/record.go:474 — "Graduates: v.verdict == VerdictSurvives," + evidence: internal/core/ideate/render.go:119 — "case VerdictSurvives: ... may graduate to a draft intent through\\nthe ordinary quoted-text create (`abcd intent \"\"`). Ideate mints no\\nintent itself" +- ac-4 — MET: resolveCitations builds one recordid.Resolver over the repository and refuses the whole verdict (CitationError, nothing written) if any grill hit cites an id that does not resolve; each hit is shape-checked against CitedIDRe first, and the resolved set is carried into the record as CitedRecords — the check-the-record-first gate, exercised green by the surface test that feeds an unresolvable itd-9999. + evidence: internal/core/ideate/record.go:454 — "if _, ok := r.Lookup(h.Record); !ok { unresolved = append(unresolved, h.Record); continue }" + evidence: internal/core/ideate/record.go:348 — "if !recordid.CitedIDRe.MatchString(h.Record) { ... which is not a record id (want adr-N, itd-N, iss-N, or spc-N)" + evidence: internal/core/recordid/resolve.go:76 — "func NewResolver(repoRoot string) (*Resolver, error)" + evidence: internal/surface/cli/ideate_surface_test.go:117 — "\"ideate\", \"record\", \"the-ideate-gate\", \"--verdict-json\", writeVerdict(t, ideateVerdictJSON(\"itd-9999\"))" + +Gap audit: +- honoured: + - Ideate is an optional verb named in the routing help, never a pre-capture gate + evidence: internal/surface/cli/cli.go:1255 — "a big, unproven idea? `abcd ideate` runs the optional admission gauntlet" + evidence: internal/core/ideate/ideate.go:19 — "NEVER A GATE. Nothing here is reachable from capture or intent-create." + - The record is written whether the idea survives or dies, and rejected alternatives cannot arrive silently empty + evidence: internal/core/ideate/render.go:123 — "case VerdictKilled: ... The idea is closed. Before proposing it again, read this record" + evidence: internal/core/ideate/record.go:405 — "the verdict records no rejected alternatives and does not say so explicitly — nothing was written" + - Every record-grill hit is cited by id and validated against the live repository, refusing the whole verdict on an unresolvable id + evidence: internal/core/ideate/record.go:460 — "if len(unresolved) > 0 { ... return nil, &CitationError{Unresolved: unresolved}" + - Only a survivor graduates; ideate mints no intent itself + evidence: internal/core/ideate/record.go:474 — "Graduates: v.verdict == VerdictSurvives," + - Wired on both planes: the abcd ideate verb (CLI) and the /abcd:ideate command surface + evidence: internal/surface/cli/cli.go:150 — "root.AddCommand(newIdeateCommand(&asJSON))" + evidence: commands/abcd/ideate.md:7 — "# `/abcd:ideate` — the idea-admission gauntlet" +- diverged: + - The adversarial leg's fresh-context/off-policy/unknown-authorship conduct is codified in the orchestrating prompt but not enforceable by the binary at ingest — the recorded artefact cannot prove the evaluator was a fresh, off-policy session + evidence: internal/core/ideate/record.go:367 — "the binary cannot observe how an agent was run, and pretending to check it would be theatre" + evidence: commands/abcd/ideate.md:66 — "The evaluator must not be the session that ran legs 1 and 2. Dispatch it as a separate agent with its own context." +- missing: (none) \ No newline at end of file diff --git a/.abcd/work/issues/open/iss-151-itd-103-shipped-only-one-of-its-two-promised-planes-the-exec.md b/.abcd/work/issues/open/iss-151-itd-103-shipped-only-one-of-its-two-promised-planes-the-exec.md new file mode 100644 index 0000000..fffa305 --- /dev/null +++ b/.abcd/work/issues/open/iss-151-itd-103-shipped-only-one-of-its-two-promised-planes-the-exec.md @@ -0,0 +1,11 @@ +--- +schema_version: 1 +id: "iss-151" +slug: "itd-103-shipped-only-one-of-its-two-promised-planes-the-exec" +severity: "minor" +category: "observation" +source: "user-observation" +found_during: "manual-capture" +--- + +itd-103 shipped only ONE of its two promised planes: the execution-time guard plane is fully wired (abcd guard check/hook, ahoy health), but the TEACHING plane — the rules loader injecting matched shell-safety rules before shell-heavy work, per spc-16 'Two planes, one registry' — is not built; there is no guard/safety/hazard domain in internal/core/rules/. All four itd-103 ACs concern the guard plane only, so the fidelity review is 3 MET/1 MWC, but the intent headline ('two planes') is only half delivered. Wire the teaching plane as a rules-loader safety domain sourced from the same bundled hazard registry, or amend the intent's scope. \ No newline at end of file