Development record
The Conformance Check Calls Itself Lint
Press Release
The conformance check calls itself what it is. abcd lint checks a repo
against the working conventions — deterministic rules, severities, exit codes
— and the word audit goes back to meaning "did we do what we said":
/abcd:audit returns to its reserved seat for the hash-chain fidelity checks.
"When a verb says lint I know it's checking form — no model, no judgement.
When one says audit I know it's checking a promise. I stopped having to
remember which one lied," says Bob, staff engineer.
Why This Matters
itd-85 shipped deterministic rule-checking under the one name
02-constraints/04-naming.md reserves for itd-16's formal verification. Per
adr-40 the act is a lint, and the maintainer ruled the replacement name
abcd lint (2026-08-16, planning question 1): it matches the existing
record-lint / docs-lint / lint-reviews family, with abcd docs lint
read as the same word at a narrower scope. Clean break, no aliases —
pre-1.0.0, --impact breaking drives version derivation, users re-download.
About 57 references carry the current name; the scoped sweep is smaller (the
word "audit" in its family-2 sense — the intent audit — and third-party
senses never move).
Scope Conditions
None stated.
Acceptance Criteria
BDD format, per the itd-1 discipline. Walked and confirmed by the maintainer, 2026-08-16.
- Given the rename, then
abcd lintreplacesabcd auditwith identical behaviour, flags, and the tri-state exit contract, andabcd auditfails as an unknown command — no alias, no shim. - Given the plugin surface, then
commands/lint.mdreplacescommands/audit.md(/abcd:lint), the04-surfacesregistry row and surface file move, and/abcd:auditstands reserved for itd-16 again — its two04-naming.mdlistings intact. - Given the sweep boundary, then historical and dated records keep
the old name; the brief, commands, code, tests,
docs/, and rules-loader references move. The scoped patterns areabcd audit,/abcd:audit, and the itd-85 surface's identifiers — never the intent audit or third-party senses of the word. - Given anything abcd writes into other repos (managed-repo scaffolding,
prepare-this-repoinstructions), then it emits the new verb, and the breaking CHANGELOG entry names the re-download/re-scaffold step for managed repos. - Given itd-122's extended
surface_coveragearmed, then the registry and sub-verb rows move in the same change —record-lintexit 0 proves the migration complete; landing before the check is armed is forbidden. - Given the task-class tokens, then conformance work carries
lint, neveraudit, and the enum rows in04-naming.mdare re-checked in the same change (adr-40's consequence). - Given the release record, then the CHANGELOG entry is breaking.
SOTA
Same family as itd-123: pre-1.0.0 breaking rename, no aliases (adr-40;
iss-171 precedent). Package ruling after adversarial review (2026-08-16):
the conformance code moves to internal/core/repolint — merging the two
lint engines was reviewed and deliberately deferred to iss-251, a future
consolidation intent, never smuggled into a rename. Chosen path: bespoke
sweep, proved complete by the armed itd-122 gate. No new dependency.
Open Questions
None gating. The engine-consolidation question is captured as iss-251.
Audit Notes
Fidelity review — receipt rcp-76175a58e4f7 (verifier abcd:intent-auditor claude-fable-5-1).
Provenance: abcd:intent-auditor@claude-fable-5-1 · rubric_hash sha256:effa65b3e9e88ff29433b443ec2be159522a8b0b71cf1434526514aa61edb13e · prompt_hash sha256:5bcc47af70779fe87bd6cd3824fa540c602728c19033e3bc05c5fa1543f34864 Input attestations: diff:tree at da7b7cf409b41758b3502d3873687dc8b817d8c4 (worktree HEAD; the host supplied no commit range, so the whole tree at that commit is the delivered reality)@-;
Acceptance rollup: MET 5 · MET_WITH_CONCERNS 2 · NOT_MET 0 · INCONCLUSIVE 0
Per-criterion verdicts:
- ac-1 — MET: lint is the registered command, the conformance core states the tri-state exit semantics and the surface tests exercise exit 0, exit 2 and the usage path, and a dedicated test proves audit is an unknown command at exit 2. evidence: internal/surface/cli/cli.go:440 — "Use: "lint"," evidence: internal/core/repolint/repolint.go:9 — "// severity-to-exit-code semantics (0 clean, 1 warnings, 2 any error), and SARIF" evidence: internal/surface/cli/lint_surface_test.go:169 — "func TestAuditRenameCleanBreak(t *testing.T) {" evidence: internal/surface/cli/lint_surface_test.go:55 — "func TestLintConformingExitsZero(t *testing.T) {"
- ac-2 — MET: commands/lint.md exists and commands/audit.md does not, the registry row 16 reads /abcd:lint with its own surface file, and the naming register keeps both /abcd:audit listings as the reserved formal-verification seat.
evidence: commands/lint.md:73 — "adding
abcd-lint:allowon that line (the earlierabcd-audit:allowspelling is" evidence: .abcd/development/brief/04-surfaces/README.md:31 — "| 16 |/abcd:lint| shipped | Check whether this repo still conforms to the working conventions |" evidence: .abcd/development/brief/02-constraints/04-naming.md:45 — "-/abcd:audit: formal verification surface, staged (itd-16). Reserved, not" evidence: .abcd/development/brief/02-constraints/04-naming.md:72 — "|/abcd:audit| formal verification surface: hash-chain and Merkle audit trails, fidelity checks" - ac-3 — MET_WITH_CONCERNS: No live surface, brief page, code path or doc still spells the verb abcd audit or /abcd:audit in the conformance sense, the decision log and older changelog sections keep it as history; concern: the privacy waiver token abcd-audit:allow is kept as an honoured legacy spelling by design, a signed-off carve-out from the identifier sweep the changelog names.
evidence: internal/surface/cli/lint.go:17 — "//
/abcd:auditreturns to itd-16's reserved hash-chain fidelity surface): it evaluates the" evidence: internal/core/repolint/rule_privacy.go:61 — "const auditWaiver = "abcd-audit:allow"" evidence: dcn-2608160000000003 — "abcd auditis deterministic rule-checking so it is a lint" evidence: CHANGELOG.md:1112 — "The privacy waiver's current spelling isabcd-lint:allow, and every committedabcd-audit:allowline stays honoured forever." - ac-4 — MET: The prepare-this-repo page tells the managed repo to run abcd lint, the launch scaffold code carries neither spelling (it writes no conformance step), and the breaking changelog entry names the re-download and re-scaffold step for managed repos.
evidence: commands/prepare-this-repo.md:104 — "Write the report — the
abcd lintfindings plus these supplements — to the" evidence: commands/prepare-this-repo.md:166 — "surfaces render from it. From then onabcd lintreports any surface that" evidence: CHANGELOG.md:1112 — "Managed repos: re-download the binary, and re-runprepare-this-repo/launch scaffoldwhere a repo's own instructions or CI referencedabcd audit." - ac-5 — MET_WITH_CONCERNS: The registry row and the lint surface's sub-verb table are in place and record-lint exits 0 over the tree at this commit (run by the auditor, warnings only); concern: the landing-order clause (armed before this landed) is a history fact the delivered tree cannot show.
evidence: .abcd/development/brief/04-surfaces/README.md:31 — "| 16 |
/abcd:lint| shipped |" evidence: .abcd/development/brief/04-surfaces/16-lint.md:30 — "|outbound| gate | shipped |" evidence: .abcd/development/brief/04-surfaces/README.md:46 — "The Status column is machine-checked: thesurface_coveragerecord-lint rule" evidence: Makefile:164 — "record-lint:" - ac-6 — MET: The naming register's bucket enum separates lint from audit by what is compared, the task-class enum carries both tokens, and no agent file claims the audit token for conformance work (the conformance check runs with no agent at all).
evidence: .abcd/development/brief/02-constraints/04-naming.md:172 — "|
bucket∈{lint, review, audit, gate}| Assessment-surface classifier, separated by what is compared to what" evidence: .abcd/development/brief/02-constraints/04-naming.md:180 — "|task_classes(capability_scope tokens) ∈ `{oracle_review, intent_audit, spec_planning, code_rescue, principle_distillation, lifeboat_packing, audit, lint," evidence: agents/docs-currency-reviewer.md:8 — "task_classes: [cross_document_audit]" - ac-7 — MET: The shipped record declares impact breaking and the 0.6.0 changelog section carries the entry under the breaking heading.
evidence: .abcd/development/intents/shipped/itd-124-the-conformance-check-calls-itself-lint.md:10 — "impact: breaking"
evidence: CHANGELOG.md:1112 — "- The conformance check calls itself lint.
abcd auditis nowabcd lint"
Gap audit:
- honoured:
- abcd lint replaces abcd audit with the tri-state exit contract and no alias evidence: internal/surface/cli/lint_surface_test.go:174 — "t.Fatalf("abcd audit must be unknown (exit 2), got exit %d stderr %q", code, stderr.String())"
- /abcd:audit returns to its reserved seat
evidence: .abcd/development/brief/02-constraints/04-naming.md:63 — "> Note:
/abcd:auditappears both here and in the exemptions above. The two" - the conformance core moves to its own package evidence: internal/core/repolint/repolint.go:9 — "// severity-to-exit-code semantics (0 clean, 1 warnings, 2 any error), and SARIF"
- diverged:
- the itd-85 surface's identifiers all move evidence: internal/core/repolint/rule_privacy.go:61 — "const auditWaiver = "abcd-audit:allow""
- missing: (none)
Frontmatter
| id | itd-124 |
|---|---|
| type | intent |
| lifecycle | shipped |
| kind | standalone |
| severity | major |
.abcd/development/intents/shipped/itd-124-the-conformance-check-calls-itself-lint.md
open on GitHub ↗ · commit history ↗
Referenced by4
- iss-2610262043515080itd-85 names the repo-conformance check `abcd audit`; itd-124 says the conformance check is `abcd lint` and `audit` is reserved for something elserelated
- iss-2610262045222030itd-124 keeps 'audit' for checking a promise and 'lint' for checking form; itd-65 calls its docs-lint row the documentation-auditorrelated
- itd-2609212130136102abcd's verbs consolidate: modes become flags and five checks become one lintrelated
- spc-29the-conformance-check-calls-itself-lint-abcd-audit-becomes-aimplemented by
mentions14
- adr-40Review, audit, lint, and gate are four buckets, separated by what each compares
- 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-26092300000000232026-09-23 — The payload example in spc-2609231435545473 (closed) is stale on one point: its itd-121 quote opens `"... what I'd do next,"`, a truncation the release-page ingest refuses by design, since a quote is a whole quoted sentence as the press release has it. The example's verb is right: the ingest accepts an attribution after `says` as well as after `said`, because six intents of that release (itd-119, itd-120, itd-121, itd-123, itd-124, itd-125) quote as `says <Name>, <role>.`. The closed spec stays as written; `TestQuoteSaysFormFromARealRecord` carries a working `says` quote, taken from itd-121 as its record has it (lane implementer, on review 2 of the release-page build).
- 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-251Two lint engines under one vocabulary: internal/core/repolint (post-itd-6 rename; Rule/Evaluate/tri-state exit) and internal/core/lint (RuleConfig/Finding stream) are separate engines with separate rule models and config schemas, already entangled (repolint's rule_docs.go wraps docs-lint as a conformance rule). Every new rule author must pick an engine. Consolidating the rule models is a deliberate future intent - deliberately kept out of the itd-123-era rename sweep after adversarial review of merge-now vs rename-only.
- 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-2610262036330589itd-102 calls the positioning check part of every audit; the identity chapter runs it as a rule of abcd lint
- itd-1Every Intent Has Acceptance Criteria; Every Audit Verifies Them
- itd-16`/abcd:audit` Is the Umbrella; Conversation/Edit Chain Is Its Default Application
- itd-85A Read-Only Repo-Conformance Audit
- itd-122The Registry Cannot Wave Its Hands
- itd-123The Intent Audit Says Audit
- itd-125The Lifeboat Verdict Says What It Is
- itd-2609231013154443Every release arrives with a press release composed from what shipped