Development record
Review, audit, lint, and gate are four buckets, separated by what each compares
Context
abcd performs many assessment-shaped acts, spread across its three roles. A product thinker wants to know whether what shipped is what they asked for. A facilitator wants to know whether a record is ready to move, and fires the checks that answer it. The implementation team wants to know whether a change is any good. Today these all reach for the word review, and the surface offers no way to tell from a verb name whose question it answers.
The distinction is already recorded.
05-internals/01-agents.md
§ Verdict-tag protocol declares two verdict families and rules them disjoint:
1. Review verdicts …
{SHIP, NEEDS_WORK, MAJOR_RETHINK}… 2. Per-criterion intent acceptance verdicts …{MET, MET_WITH_CONCERNS, NOT_MET, INCONCLUSIVE}… Different category from review verdicts — review verdicts assess a change, criterion verdicts assess a promise vs reality. These two enums are deliberately disjoint and never mixed. Reviews emit family 1; auditors emit family 2.
The rule is sound. Three surfaces do not follow it:
| Surface | Emits | Named | Should be |
|---|---|---|---|
abcd intent review (internal/core/intent/review.go) |
family 2 — MET / NOT_MET / … |
review | audit |
abcd audit (itd-85) |
rule ids + severities; no model | audit | lint |
disembark oracle |
family 1 — SHIP / NEEDS_WORK / … |
"the oracle audit" in prose | review |
The first two crossed with each other. What
01-product/03-mental-model.md
itself calls "the intent audit" — one of "three audit grains of one shape:
brief audit, phase audit, intent audit" — is the one surface named review.
Meanwhile 02-constraints/04-naming.md
reserves /abcd:audit for "formal verification surface — hash-chain /
Merkle audit trails, fidelity checks" (itd-16), and itd-85 took that reserved
name for deterministic repo-conformance checking.
What is not wrong. The brief is deliberately aspirational — it describes
the project as though built, per the working-backwards discipline, while
adr-5 keeps it current rather than versioned.
The mechanism reconciling those two things already exists and works:
04-surfaces/README.md carries a
machine-checked Status column (shipped / staged) enforced by the
surface_coverage record-lint rule, and the brief carries some one hundred
inline design target, not yet shipped markers. This ADR does not replace that
discipline; it extends it to the granularity where it is currently blind.
Where it is blind: sub-verbs. surface_coverage checks that a shipped row
has a backing commands/<name>.md. It cannot see inside a row. So six of twenty
rows read shipped and then qualify themselves in prose — /abcd:embark
("the full embark chapter … remains a design target"), /abcd:intent ("refine /
grill / ship / consistency / shape / reclassify … remain design targets"),
/abcd:capture ("promote is a design target"), and three more. shipped at
surface grain means the top-level verb exists, and every unbuilt sub-verb hides
inside a row that says otherwise. Documents outside the registry then cite those
sub-verbs as live — 02-constraints/04-naming.md calls capture promote "live as
of spc-30/itd-46"; 05-internals/01-agents.md says "spc-29 ships" intent consistency — because nothing checks them. Both cite predecessor-store spec
ids: the capability shipped in an older spec store and the prose survived the
migration to the native one.
Decision
Four buckets, separated by what is compared to what. The comparison — not the implementation, and not the trigger — is what identifies whose question a surface answers, so the comparison is what names it.
| Bucket | Compares | Question | Verdict |
|---|---|---|---|
| lint | an artefact against a rule about its form | "Is this well-formed?" | rule id + severity + exit code |
| review | a change against judgement | "Is this any good?" | SHIP / NEEDS_WORK / MAJOR_RETHINK |
| audit | reality against a recorded commitment | "Did we do what we said?" | MET / MET_WITH_CONCERNS / NOT_MET / INCONCLUSIVE |
| gate | — consumes findings and decides one action | "May I proceed?" | pass/fail + remedy |
1. One surface performs exactly one act
A surface that would perform two is split at design time, not documented as a
bundle. This is what makes the bucket a guarantee rather than a statement of
intent: run an audit and every finding is promise-versus-reality, by
construction.
The cost is borne almost entirely by surfaces that do not yet exist. Every
assessment surface abcd has actually built is already single-act — three are
merely misnamed. The two genuinely multi-act designs, /abcd:intent consistency
(five finding categories spanning at least two buckets) and itd-109's
verification suite, are both unbuilt, so they are specified correctly rather
than refactored.
The alternative — classify acts, and let a surface be named for what it
predominantly does — was rejected because it breaks the role guarantee below: a
product thinker running an audit would receive naming-register collisions and
glossary gaps mixed in among their own findings.
2. The buckets are a closed list, extended by PR
Membership is enumerated in
02-constraints/04-naming.md under
Reserved vocabulary, the same mechanism task_classes, kind, and capture verdict already use. A surface producing findings is lint, review, or
audit. A surface consuming findings to decide one action is a gate.
This is enumeration rather than criterion because an autonomous run given a criterion will interpret it, and a table lookup either matches or fails the gate. The judgement moves from implementation time to review time, where a human is present.
abcd intent ready is why the list needs a fourth bucket. Its four checks
(bucket, acceptance criteria, spec link, spec body) are lint-shaped, but itd-94
shipped ready deliberately with an exit-code contract autonomous runs depend on
as their step-0 skip filter. It is not a synonym competing with lint/review/audit
— it names a decision, not a comparison. Gates are named for the decision they
guard.
3. Determinism is orthogonal and never names a bucket
Whether a model is involved is an implementation property. itd-16's hash-chain verification compares reality against a recorded commitment and needs no model — it is an audit. itd-85's conformance check applies rules about well-formedness — it is a lint however built. Sorting by determinism is what produced the current crossing.
A lint's exit code being consumed by CI does not make it a gate; producing findings is what names it.
4. Automatic versus manual never enters the name
intent review already shows the correct shape: its emit fires automatically
from spec close, its ingest is a deliberate act, one verb. Per
itd-97,
deciding when a check fires is the facilitator's work. Encoding the trigger
would double the namespace for no semantic gain and push a facilitator concern
into a name the other two roles must read.
5. The oracle is a seam beneath the buckets, never a bucket
Per adr-25, review and audit reach a
model through the host-delegated oracle seam; lint never does. The seam is
transport, not vocabulary. disembark oracle is correctly named for the seam it
invokes; what needs correcting is the prose calling its family-1 output an
"audit".
Amendment (2026-08-16). The keep-the-verb ruling above rested on a claim the planning investigation disproved: the binary verb never invokes the oracle seam.
disembark oracleis a compute-or-ingest verdict endpoint — its deterministic mode is a mechanical mapping over the manifest seal and coverage summary, and its delegated mode validates a verdict the host's agent produced elsewhere; the model access happens host-side, outside this verb. Naming the verb for the seam claims a seam it does not touch and collides with the/abcd:oracle askdesign target, which is the seam's real surface. The maintainer therefore reversed this clause: the verb renames todisembark review(itd-125), and the seam itself — adr-25, andoracleas the seam's name — stands unchanged. The rest of this section (the seam is transport, not vocabulary; lint never reaches a model) is unaffected.
6. Status and bucket are recorded together, per sub-verb
Each surface file under 04-surfaces/ carries a sub-verb table with two facts
per verb — what it compares (the bucket, where the verb is an assessment) and
whether it exists (shipped / staged). surface_coverage extends to check
each row against registered cobra sub-commands, in both directions: a sub-verb
that ships without a row fails, and a row claiming a sub-verb that is not
registered fails.
One table serves both disciplines. It is the detector this ADR needs, and it is
the fix for shipped meaning six different things — a staged row for capture promote cannot then be called "live" elsewhere without failing the build.
The buckets map onto the three roles
| Role | Their question | Their bucket |
|---|---|---|
| Product thinker | "Did I get what I asked for?" | audit, and essentially nothing else |
| Facilitator | "Is this ready to move, and what fires when?" | all four, plus ownership of every trigger |
| AI implementation team | "Is this change any good?" | review and lint |
This mapping is the operational reason the split is worth its cost. itd-99 commits abcd to never asking a product thinker to make a technical decision — only to decide on a clear proposal. A product thinker handed a lint failure has been handed a technical decision. The four-bucket split with one act per surface makes that promise mechanically checkable: point at the surface, and it names whose question it is.
Implied renames, and how they ship
abcd intent review→abcd intent audit. It emits family 2; the brief already calls it the intent audit. Theintent-fidelity-revieweragent and theintent_reviewtask-class token move with it.abcd audit(itd-85) → a lint-shaped name, returning/abcd:auditto itd-16 as02-constraints/04-naming.mdreserved it. The replacement name is an open question for the planning interview.disembark oraclekeeps its verb; the prose describing its output as an "audit" is corrected to "review".
Clean break, no aliases. abcd is pre-1.0.0, so a declared-breaking change is
the sanctioned path — --impact breaking is already in live use (iss-171) and
drives version derivation automatically. An alias would additionally collide with
the documentation discipline, which forbids change-narration: the old name could
not be documented in present tense, leaving an undocumented silent forward, which
serves a user worse than a clean break plus a CHANGELOG line. Users re-download.
Each rename is a separate intent carrying its own acceptance criteria. This ADR fixes the vocabulary; it does not authorise a breaking change.
Alternatives Considered
One verb (review) polymorphic on its target. review itd-85, review spc-9, review <diff>. Rejected: it merges two verdict families the record
rules disjoint, and erases the role signal — the one thing the product thinker
most needs from a name.
Classify acts rather than surfaces. Rejected under decision 1: it makes the bucket a statement of intent rather than a guarantee, and breaks itd-99.
Three buckets, no gate. Rejected: it forces intent ready to become
intent lint, discarding a shipped name with a documented exit-code contract.
A criterion instead of a closed list ("no synonym may name an assessment act"). Rejected: it requires a judgement call at exactly the moment no human is present.
Four or more assessment buckets, adding verify / validate. Rejected: no
candidate names a comparison the four do not cover. itd-109's verification suite
is a packaging of lints and audits, not a fifth kind.
Leave the vocabulary and document the exceptions. Rejected: the exceptions are the two most-used assessment surfaces, so the documentation would be read more often than the rule.
Consequences
- Every new assessment surface faces one naming test: what is compared to what? itd-109 is the first to face it and should be planned only after this ADR settles.
- Three shipped surfaces are known-misnamed until their rename intents land. The vocabulary is correct from this ADR; the surface trails it, and the gap is visible rather than silent.
/abcd:auditis re-reserved for itd-16. Any surface wanting the word must compare reality against a recorded commitment.- The sub-verb tables are real work: twenty surface files, and some bucketings
will be arguable (
identityproposes corrections,changelogcarries a guardrail). That population pass lands in the same change as the extendedsurface_coverage, so nothing ships unbucketed. - Once armed, every new verb costs a table row. That friction is intended.
- The
task_classesclosed enum carriesoracle_review,intent_review,audit,lint, andcross_document_audit— five tokens spanning three buckets. They are re-checked against this taxonomy when the rename intents land; the enum is PR-to-extend and no shipped check reads it. - The product thinker's surface narrows to one bucket, which is the point.
Frontmatter
| id | adr-40 |
|---|---|
| type | adr |
| status | accepted |
| date | 2026-08-16 |
.abcd/development/decisions/adrs/0040-review-audit-lint-are-three-verbs.md
open on GitHub ↗ · commit history ↗
References12
- adr-5Brief is the current state; no version label, no archive directoryrelated
- adr-9Phase as a product-reflection layer between brief and intentrelated
- adr-25The LLM is host-delegated by default; oracles are opt-in adaptersrelated
- itd-16`/abcd:audit` Is the Umbrella; Conversation/Edit Chain Is Its Default Applicationrelated
- itd-48`intent-fidelity-reviewer` Gains Its Cross-Doc And Kind-Classification Rolesrelated
- itd-53A Shipped Intent No Longer Drifts Out Of Audit Just Because Nobody Ran The Reviewrelated
- itd-83The Review Bar Fires By Itself, In Every Repo abcd Managesrelated
- itd-85A Read-Only Repo-Conformance Auditrelated
- itd-94An intent that is not planned cannot be implemented: abcd gains a machine-checkable implement-readiness gate that refuses with a remedy and offers the planning interviewrelated
- itd-97The Facilitator Is a Mode, Not a Personrelated
- itd-99A Team of Product Thinkers Decides as Onerelated
- itd-109Acceptance Criteria Verify Themselves, And The Manual Rest Renders For A Humanrelated
Referenced by2
- adr-2609231028044006Shape claims in the brief's surface chapters are derived, never hand-authoredrelated
- itd-2610090831227812A person who types `/abcd:` sees the commands people userelated
mentions37
- 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).
- dcn-26081600000000052026-08-16 — adr-40 §5 REVERSED at the process-planning interview (amendment recorded in-place in adr-40): `disembark oracle` renames to `disembark review` (itd-125, breaking) instead of keeping the verb and fixing prose. The investigation finding that turned it: the binary verb never invokes the oracle seam — it is a compute-or-ingest verdict endpoint (deterministic manifest+coverage mapping, or validate-and-ingest of a host-produced verdict), so the seam name claims transport the verb does not touch and collides with the `/abcd:oracle ask` design target, the seam's real surface. The sweep carries the artefact (`audit/oracle-<manifest12>.*` → `review/review-<manifest12>.*`, clean-replacement across the rename so one manifest never holds two verdicts) and the agent (`lifeboat-oracle` → `lifeboat-reviewer`). Naming convention ruled in the same session: assessment agents are target-grain + role (`intent-auditor`, `lifeboat-reviewer`). adr-25 and the seam name `oracle` stand unchanged. Rejected: prose-only fix (leaves the artefact contradicting the vocabulary), renaming the seam itself (adr-25 is correct), a superseding mini-ADR (same-day clause amendment suffices).
- dcn-26081700000000012026-08-17 — spc-27 population calls, made unattended within adr-40's test
- dcn-26081700000000022026-08-17 — README bucket-vocabulary alignment (#289), made unattended
- dcn-26081900000000032026-08-19 — bughunt round 1 (branch bughunt-b/round-1): captured iss-291..iss-304 and fixed
- dcn-26081900000000052026-08-19 — Design review of the candidate record extensions (scope
- iss-171The PATH-install detector and installer assume one blessed layout: binTarget defaults to /usr/local/bin/abcd (sudo territory abcd cannot assume) and symlink detection only recognises that exact target, so a working ~/.local/bin/abcd symlink install — the field-standard single-user location used by uv/pipx/rustup-class tools — reports symlink.missing, a false gap; the detector is itself running as abcd from PATH while reporting abcd not installed. Letting ahoy install 'fix' it would write a symlink to <plugin-root>/abcd without validating the target exists — a dangling symlink shadowing the working install. Redesign per fix-the-detector and no-sudo: detection scans PATH for abcd, resolves symlinks (EvalSymlinks, same seam as iss-170), classifies dev-shim/owned/foreign; install defaults to ~/.local/bin (create if needed), adopts an existing owned install in place, does system-wide dirs only behind an explicit --bin-dir flag failing loudly when unwritable, never escalates privileges, refuses to create a symlink whose target does not exist; '~/.local/bin not on PATH' becomes its own loud gap with the printed one-line fix (script-first: print the export line, do not auto-patch shell profiles as the first rung).
- 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-284The adr-40 vocabulary renames narrow the public surface for v0.6.0: abcd audit is abcd lint, abcd disembark oracle is abcd disembark review, and abcd intent review / intent review ingest are abcd intent audit / intent audit ingest. Four command paths leave the surface; each successor refuses the old spelling by naming the new one. Deliberate breaks, documented in the CHANGELOG Breaking section (itd-123, itd-124, itd-125)
- iss-297adr-40's v0.6.0 verb renames (intent review -> intent audit, disembark oracle -> disembark review) left stale residue in durable present-tense docs: roadmap/phases/{README.md,phase-0-substrate.md,phase-6-lifeboat.md} still say 'intent review', and brief/05-internals/08-skills.md plus brief/04-surfaces/README.md still list 'oracle' as a disembark sub-verb the binary now refuses
- iss-334intents/README.md teaches the v0.6.0-retired intent review verb and the intent-fidelity-reviewer agent (retired to intent audit / intent-auditor by adr-40); the intents store front door documents an invocation that exits non-zero and an agent absent from the tree, and its template block is copied into new intents while contradicting create.go
- iss-2608221310142705New top-level verbs face no design-time test outside the assessment family, and the ideate verdict on the verb taxonomy left one unclaimed. adr-40 already imposes a design-time test, but only on assessment surfaces and only on one axis: what is compared to what, with a surface that would perform two acts split at design time rather than documented as a bundle. It says nothing about whether a proposed verb belongs at the top level at all, so a non-assessment verb faces no test. The 2026-08-22 ideate verdict (research/notes/2026-08-22-ideate-cli-verb-taxonomy-restructure.md) killed an open-ended 'restructure when confusable pairs appear' deferral because a condition with no detector is the phantom gate enforcement-claims-are-facts forbids. What it put in that place is a design-time question asked when a verb is proposed: does an existing record-owning verb already own this act? The question is answerable by the human designing the verb, which a trigger conditioned on future confusion is not. Five unbuilt verb names are already in play across three different statuses, so the test has live subjects: dredge, loot and audit sit in the reserved table of brief/02-constraints/04-naming.md; audit and reflect sit on its metaphor-exemptions list; and oracle is in neither, appearing only as a design-target sub-verb under a note recording that no oracle verb is registered. It currently exists only inside a research note, which is not where a design-time rule can be found by the person who needs it. Decide its home: a principle under development/principles/, a line in the naming register at brief/02-constraints/04-naming.md beside the existing metaphor-vs-exempt criterion and the bare-command-as-render discipline, or an explicit decision to leave it in the verdict record. itd-146 carries the same question as an open question; this capture exists so the test survives that intent not shipping.
- iss-2610151422061914The brief at .abcd/development/brief/04-surfaces/07-library.md:11-16 says: The library command merges `source` and `memory`, and under adr-40 "neither old name survives as an alias". The chapter then calls `.abcd/memory/` "the memory store" throughout and never mentions another memory surface. The shipped surface differs: `source` is gone from the binary, but `memory` is still a registered top-level verb (`abcd memory --help`: "Count the memory notes in both layers"). It now addresses a different store, the memory notes in `~/.abcd.noindex/memory.json` and `.abcd/memory.json`, and is documented in 37-memory.md. Strictly it is not an alias, but the old name does survive on the verb tree with a different meaning. This chapter does not mention it or tell the two memory stores apart. (v0.14.2 release crosscheck, false-claim, raised by opus in a06.)
- iss-261025221431467616-lint.md:70-81 justifies the gate bucket for the outbound and site targets by CI consumption ('wired into CI to make a binary pass/fail decision'; 'its exit is the release job's publish decision') and says 'the distinction is the one adr-40 draws'. adr-40:136-137 says 'A lint's exit code being consumed by CI does not make it a gate; producing findings is what names it', and :113-114 says a surface that produces findings is lint, review or audit.
- iss-2610262034207649itd-30 calls the promise-against-delivery agent `intent-fidelity-reviewer`; the intent chapter calls it `intent-auditor`.
- iss-2610262034354642The intent chapter names the Role 1 fidelity agent intent-auditor; itd-50 calls the same actor intent-fidelity-reviewer.
- iss-2610262035510145The voyage entry calls privacy-hygiene an 'audit rule' run by abcd's 'own audit'; the lint chapter says that verb is a lint and that 'audit' is reserved
- iss-2610262036067608itd-16 makes /abcd:audit an open umbrella a schema or prompt-quality audit can join; 16-lint reserves it for hash-chain fidelity and calls a check of form a lint.
- iss-2610262039195057itd-85 makes `abcd audit` a repository conformance check, but the agent catalogue reserves the top-level `/abcd:audit` for itd-16's hash-chain surface
- iss-2610262043322187itd-126 adds abcd source share and abcd source ingest; itd-2610090831227812 merged the source family into library with no alias
- iss-2610262044229426The audit draft wires into prepare-this-repo Phase 2, but prepare-this-repo has folded into ahoy install with no alias
- iss-2610262045409665itd-2609231013154443 names abcd changelog as the read-only preview; itd-2610090831227812 merges changelog into launch with no alias
- iss-2610262045442294itd-80 names the verdict ingest abcd intent review ingest; itd-2609150819445595 names the same review family abcd intent audit
- itd-46`/abcd:intent "<text>"` And `/abcd:capture "<text>"` Become Symmetric Create Paths
- itd-122The Registry Cannot Wave Its Hands
- itd-123The Intent Audit Says Audit
- itd-124The Conformance Check Calls Itself Lint
- itd-125The Lifeboat Verdict Says What It Is
- itd-146abcd's help renders in labelled command groups, and the grouping is gated like every other surface claim
- spc-9an-intent-that-is-not-planned-cannot-be-implemented-abcd-gai
- spc-27the-registry-cannot-wave-its-hands-every-surface-file-carrie
- spc-28the-intent-audit-says-audit-abcd-intent-review-becomes-abcd
- spc-29the-conformance-check-calls-itself-lint-abcd-audit-becomes-a
- spc-30the-lifeboat-verdict-says-what-it-is-disembark-oracle-become
- spc-2609230613204830Every surface file carries its sub-verb table
- spc-2610100613109045a-person-who-types-abcd-sees-only-the-commands-people-use
- spc-2610110931381316append-only-logs-conflict-on-every-merge