Development record
brief-vs-shipped-surface reconciliation: 05-internals/08-skills.md claims abcd ships zero user-facing skills and six top-level commands while 04-surfaces/README.md itself tables nine and /abcd:consult and /abcd:ingest are shipped; the shipped skills violate the brief criterion that any artefact mutation is a command, not a skill; the skills/ layout described (abcd-ahoy, commit-attribution, secrets-and-pii) is fictional vs the real consult/ and ingest/; the implemented, user-reachable abcd docs lint and abcd history verbs have no home in 04-surfaces at all; the operator-internal paragraph contradicts the commands/ directory that exists. Detector (per spec-moves-with-the-surface): a record-lint cross-check that every entry under commands/ and skills/ resolves to a brief surface row, and every brief surface row resolves to a shipped or explicitly staged surface. Acceptance corpus: each falsified claim above — the check fails on all of them today. Fix amends the criterion or the surface in one change, never silently.
brief-vs-shipped-surface reconciliation: 05-internals/08-skills.md claims abcd ships zero user-facing skills and six top-level commands while 04-surfaces/README.md itself tables nine and /abcd:consult and /abcd:ingest are shipped; the shipped skills violate the brief criterion that any artefact mutation is a command, not a skill; the skills/ layout described (abcd-ahoy, commit-attribution, secrets-and-pii) is fictional vs the real consult/ and ingest/; the implemented, user-reachable abcd docs lint and abcd history verbs have no home in 04-surfaces at all; the operator-internal paragraph contradicts the commands/ directory that exists. Detector (per spec-moves-with-the-surface): a record-lint cross-check that every entry under commands/ and skills/ resolves to a brief surface row, and every brief surface row resolves to a shipped or explicitly staged surface. Acceptance corpus: each falsified claim above — the check fails on all of them today. Fix amends the criterion or the surface in one change, never silently.
Detector run 1 (2026-07-10, autonomous run, workflow MVP per
script-first): the bidirectional cross-check ran as 22 checker agents
(11 brief docs verified against the shipped binary, 11 real surfaces
seeking their brief home). 150 unique discrepancies: false-claim 77,
fictional-layout 29, undocumented-surface 24, criterion-violation 15,
stale-count 5. Every falsified claim enumerated above reproduced, plus:
no abcd init/config/run verbs exist though the brief cites them
unmarked; launch's brief row claims artifact-cutting while the binary is
read-only preview; the bare-command-as-help "universal convention" is met
by no shipped verb; docs and history verbs have no brief home. Worst
docs: 05-intent (17), 07-memory (13), 01-ahoy/04-launch/06-capture/
08-abcd/08-skills (10 each). Full corpus: the run's local log
(iss35-discrepancies.json) — re-derivable by re-running the workflow.
Next: reconcile per doc behind this detector (amend criterion or surface,
never silently), then graduate the check to a record-lint rule
(spec-moves-with-the-surface).
Reconciliation batch 1 (2026-07-10, b32cf40): 60/150 dispositioned across the five worst surface chapters (01-ahoy, 04-launch, 05-intent, 06-capture, 07-memory). Every finding re-verified against the binary before editing; 2 rows batched for maintainer adjudication.
Reconciliation batch 2 (2026-07-10): the six remaining direction-A surface docs (08-abcd, 05-internals/08-skills, 04-surfaces/README, 09-reflect, 02-disembark, 03-embark) — 43 rows dispositioned: 20 fixed, 20 staged, 3 adjudication, 0 rejected. Reconcilers ran on Opus 4.8 high (Fable 5 credit exhaustion this session; see NEXT.md model-gap note) and emitted per-row binary evidence; every load-bearing claim independently re-verified in the main loop (all held — no invented-home defects, unlike the batch-1 Fable sweep that needed a 30-item review pass). record-lint and docs lint both clean. 3 new adjudication items batched to NEXT.md's ADJUDICATION QUEUE (docs/history surface-taxonomy ×2; the read-only-skill boundary rule vs the three mutating shipped skills). Remaining: re-run the cross-check detector to measure the direction-B ratchet, fix true direction-B leftovers, then graduate the check to a record-lint rule.
Detector re-run (2026-07-10, wf_ed4cf12c-231, same 22-checker arg set): 150 -> 24 discrepancies (false-claim 10, undocumented-surface 5, fictional-layout 3, criterion-violation 4, stale-count 2) — an 84% ratchet. Finding: the remaining 24 were mostly direction-A leftovers the per-doc reconciliations had not sampled — the LLM cross-check is a stochastic discovery tool, not a convergent gate; each run surfaces a different subset — plus one self-introduced slip and two adjudication clusters. 13 fixes applied across 8 docs (6ab1432), each re-verified against the binary; 1 detector finding disproved and skipped (repo-scope vs user-scope meta.json). The 2 adjudication clusters remain the only substantive criterion/direction-B items (docs/history taxonomy; read-only-skill rule vs mutating skills) — batched for the maintainer, NOT fixed. Lesson: chasing the stochastic detector to zero is the wrong loop; the fix is to graduate the cross-check to a deterministic record-lint rule (spec-moves-with-the-surface) so the invariant is enforced structurally. That graduation is the next work item.
Graduation is a design-STOP (2026-07-11, slice 10), held for maintainer
sign-off. Building the record-lint rule surfaced that the detector is
bidirectional but only Direction B (surface→brief coverage) is deterministically
lintable; Direction A (brief→binary-behaviour) is irreducibly semantic and stays
an agent/periodic check. Even the structural half cannot be armed to green until
the docs/history surface-taxonomy adjudication is decided (the rule fires on the
three chapterless shipped verbs), and it needs a decided staged-vs-shipped marker
convention. Design options (3, recommend Option A) written to
.abcd/development/plans/2026-07-11-iss35-record-lint-graduation.md. iss-35 stays
open ONLY for this gate — the reconciliation itself is complete to the limit of
what is decidable without the maintainer (remaining discrepancies = the 2
adjudication clusters). Blockers: adjudication items 5 (docs/history taxonomy)
and 6 (skill classification) in NEXT.md.
Frontmatter
| id | iss-35 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | critical |
.abcd/work/issues/resolved/iss-35-brief-surface-reconciliation.md
open on GitHub ↗ · commit history ↗
mentions17
- dcn-26071000000000052026-07-10 — CONTEXT.md goes status-free: it keeps orientation and the
- dcn-26071100000000012026-07-11 — iss-35's brief↔surface cross-check is **bidirectional, but only
- dcn-26071100000000022026-07-11 — iss-35 graduation SIGNED OFF (maintainer, 4 decisions):
- dcn-26071200000000012026-07-12 — clean-slate hardening run STEP 0 triage. A fresh adversarial
- dcn-26071400000000052026-07-14 — adr-35's blast radius across the record was FAR wider than the plan
- dcn-26071800000000012026-07-18 — The iss-35 semantic release gate was self-referential
- dcn-26072400000000012026-07-24 — iss-35 resolves: everything it stayed open for is verified
- dcn-26072400000000052026-07-24 — Next-run queue reshaped by the grill: the small consequences
- dcn-26080300000000012026-08-03 — iss-42 (v0.5.0 item D): CONTEXT.md's sharp-edges list gains a detector rather than only a correction, because the correction alone would have been the third one. The stale trust caveat (still calling iss-35's brief-vs-surface reconciliation "the open cross-check" months after `surface_coverage` shipped and iss-122 pinned the Direction-A crosscheck) is an instance of a class: the orientation doc grounds a live claim in a record, the record reaches a terminal state, and nothing in the workflow asks anyone to go back. `context_citation_currency` is that missing requirement made mechanical — it resolves every `iss-N`/`itd-N`/`spc-N`/`adr-N` handle in the "Live constraints / sharp edges" section against its store and blocks a citation to a terminal bucket (or, for the flat ADR store, a declared supersession or retired status). Deliberately narrow on two axes: ONE section of ONE document, because a terminal-state citation is legitimate in an evidence trail, a supersession chain, and a dated plan — history is supposed to name closed records; and terminal-state only, because a dangling handle is `record_schema`'s question and a second weaker implementation of an answered check is worse than none. Rejected: a git-diff-shaped handoff rule ("a change to a cited record must touch CONTEXT.md in the same commit"), which the ledger entry's wording suggests but which gates the wrong thing — it fires on commits that need no orientation change and stays silent on the case that actually bit us, a record moved in one branch and the caveat left standing in another. The state-based check has no such blind spot: whenever the citation is stale, the gate is red, regardless of which commit made it so. Alongside: `research/` stops contradicting its own README (five dated notes move into `notes/`, where ~25 peers already sit, with every citation followed — the itd-88 fidelity evidence trail, two DECISIONS.md evidence paths, `.abcd/rules.json`, and a plan link), the development record map's routing row names `research/`'s real children (`notes/` + `prompting/`, not the phantom `spikes/`), and two banned_tokens entries make both stalenesses non-silent on reintroduction. The dated plan and the ratified ADR that also mention `spikes/` are left untouched: they are chronological snapshots and a ratified decision, not living indexes, and rewriting them to match today would falsify the record — `development/README.md` alone is corrected because it alone claims to be current.
- dcn-26081600000000032026-08-16 — the assessment vocabulary settled at a maintainer grill and filed as adr-40 (proposed): **four buckets — lint / review / audit / gate — separated by what each compares**, not by determinism, not by trigger. The rule was already half-recorded (05-internals/01-agents.md rules the two verdict families disjoint: "reviews assess a change, criterion verdicts assess a promise vs reality") and three shipped surfaces contradict it — `intent review` emits family 2 so it is an audit, `abcd audit` is deterministic rule-checking so it is a lint (and it consumed the `/abcd:audit` name 02-constraints/04-naming.md reserves for itd-16), and `disembark oracle` emits family 1 while the brief calls its output an audit. Grill rulings: **one surface performs exactly one act** (multi-act surfaces split at design time — cheap, because every multi-act surface abcd has is unbuilt, so they are specified rather than refactored); the buckets are a **closed list extended by PR, not a criterion** (an autonomous run given a criterion interprets it; a table lookup matches or fails); `intent ready` survives as the fourth bucket **gate** because it names a decision rather than a comparison, preserving itd-94's exit-code contract; determinism is orthogonal (itd-16's hash-chain check is a deterministic *audit*; itd-85's conformance check is a *lint* however built); automatic-vs-manual never enters a verb name (the trigger is the facilitator's, per itd-97); the oracle is the model-access seam beneath review and audit, never a bucket. **Clean break, no aliases** — pre-1.0.0, `--impact breaking` drives version derivation (iss-171 precedent), users re-download; an alias would additionally collide with the documentation discipline's ban on change-narration, leaving an undocumented silent forward. The role mapping is the operational reason the split earns its cost: product thinker reads `audit` and essentially nothing else, which makes itd-99's "never hand a product thinker a technical decision" mechanically checkable. Same grill corrected a wrong finding: iss-246 was filed claiming abcd's record documents a surface far larger than the binary with no gate catching it; **false** — the `Status` column in 04-surfaces/README.md is machine-checked by `surface_coverage` (iss-35), the brief carries ~100 inline `design target` markers, and adr-5 makes the brief aspirational by design. The real defect is narrower: `surface_coverage` is blind *inside* a row, so six of twenty rows read `shipped` then qualify themselves in prose, and documents outside the registry cite those sub-verbs as live (all three citing **predecessor-store** spec ids spc-29/spc-30, whose prose survived the migration to the native store). Fix per adr-40 §6: sub-verb tables carrying two facts per verb — bucket and existence — with `surface_coverage` extended to registered cobra sub-commands, one table serving both disciplines. Also established: the twelve-step record walk completes at ten steps; step 2 (`capture promote`) has no verb and step 12 (`capture resolve`) cannot write `resolved_by`, so **walkability is sequenced before coherence** — renaming ~90 files across a process nobody can walk is polish before function. Plan at plans/2026-08-16-process-coherence-and-walkability.md; six intents to plan, none plannable unattended. Rejected: one polymorphic `review <id>` verb (merges the disjoint families, erases the role signal), classifying acts rather than surfaces (makes the bucket a statement of intent rather than a guarantee, and hands product thinkers lint findings), three buckets without `gate` (forces `intent ready` to become `intent lint`), and adding `verify`/`validate` (itd-109's verification suite is a packaging of lints and audits, not a fifth kind).
- iss-108iss-35 semantic release gate was self-referential under changelog-driven auto-release (adr-37): it armed receipt_gate with the tagged commit but read receipts from that commit's own tree, which can never hold a receipt naming itself. Dormant while private, it fail-closed the first public release (v0.3.0).
- iss-246`surface_coverage` is blind inside a row, so `shipped` means "the top-level verb exists" and every unbuilt sub-verb hides behind it.
- iss-2608211146562243RD001 is documented as unconditional in both definition sites (.abcd/work/reviews/README.md and brief/05-internals/06-lint.md name only the root README as exempt), but scripts/check-reviews.sh exempts 40-hex sha-keyed semantic-gate receipt directories — 7 of the 10 live review directories. The exemption is principled and recorded elsewhere ([dcn-2607180000000001](../../decisions/dcn-2607180000000001-the-iss-35-semantic-release-gate-was.md), spc-14, itd-93 acceptance criterion), but a reader auditing the folder against either charter sees 7 apparent blockers, and 06-lint.md says the rule 'ports into internal/core/lint', so an implementer working from the record alone would port it without the exemption and turn the gate permanently red.
- iss-2608250743421381two slash-command argument-hints advertise sub-verbs the binary refuses, in the one string a user reads before invoking. commands/ahoy.md:4 offers '[status | install | uninstall | doctor | dry-run]': 'abcd ahoy status' exits 2 with unknown command — bare 'abcd ahoy' is the status render — and the real sub-verb identity-check is absent from the hint. commands/launch.md:4 offers '[dry-run | ship | scaffold]': dry-run is a FLAG, so 'abcd launch dry-run' exits 2 while 'abcd launch --dry-run' exits 0; the binary registers only scaffold and ship. Both files' own bodies get it right, so the drift is confined to the frontmatter hint, which is exactly the part no prose reader checks and the part the harness surfaces first. The brief does NOT get it right: 04-surfaces/01-ahoy.md's dispatch sentence carries the same phantom status token, which is brief-tier and tracked under iss-2608231346137587. A first attempt at this fix ALSO added identity-check to the ahoy hint, which is wrong in the other direction: that verb is deliberately CLI-only, the command page carries a scoping note saying it stays a bare-CLI entrypoint rather than a plugin sub-verb, and the page carries a flow section for every other hinted token and none for it. The plugin dispatch set is install, uninstall, doctor and dry-run. This is a shipped surface, not record drift: commands/ is carried in the release bundle, so the adr-28 disposition that covers brief-tier findings does not apply. Found by the iss-35 crosscheck's plugin-command-surface probe at the v0.6.6 gate; the docs-currency pass had not flagged it across three runs, because its scope reads command prose rather than frontmatter.
- iss-2609012020521049checkReceiptGate enforces judgeModel non-empty but not the documented pinned-snapshot rule. The release-gate runbook, receipt.example.json and the iss-35 plan all state that a receipt's judgeModel is a pinned model snapshot, never a floating alias, yet checkReceiptGate (internal/core/lint/lint.go) refuses only a blank judgeModel: a receipt carrying a bare family name such as opus or an alias such as claude-opus-latest passes the gate, so the auditability the runbook promises is carried by the receipt author's honesty alone. The v0.7.0 receipts record this gap in their _reviewProvenance. The fix must refuse a judgeModel that carries no version or date component or that names a floating alias, with a test, while leaving every committed receipt (all of which carry a family plus version id) valid.
- iss-2609091956001547The iss-35 brief-surface crosscheck does not converge on a clean run. Three
- prefer-sotaPrefer SOTA