Development record
Phantom enforcement claims: developer docs describe gates that do not run as described. Re-scoped by the 2026-08-03 maintainer disposition to three doc-claim instances, each a claim about the local pre-push gate or CI:
Phantom enforcement claims: developer docs describe gates that do not run as described. Re-scoped by the 2026-08-03 maintainer disposition to three doc-claim instances, each a claim about the local pre-push gate or CI:
AGENTS.md— themake preflightcomment in the build block names only build, vet, test and race, omitting the three lint gates the target actually runs (lint-reviews,record-lint,docs-lint); and the definition of done attributes thegofmt -l .gate tomake preflight, which does not run gofmt (CI enforces it as its own format step)..github/workflows/ci.yml— the record-lint step's comment calls the gate "visible but non-blocking for now", though the step carries nocontinue-on-errorandgo run ./cmd/record-lintexits non-zero on a blocker-severity finding, so it blocks the job.README.mdandCONTRIBUTING.md— both describe the gate suite incompletely: the README build block omits the lint gates, and CONTRIBUTING both omits them and claimsmake preflightruns "the same checks" as CI, which is not true of CI's gofmt step.
Of the five instances originally filed, instance 1 — docs/reference/cli/README.md describing CI-generated reference pages and a freshness check — was verified accurate in round 13 and carries no work.
The brief's 06-lint.md section 1 catalogue (the predecessor project's Python-era IL001–RC007 families) and the proposed gate cross-check detector are re-filed as iss-181, which carries the maintainer's disposition on both: the catalogue is removed rather than archived and is not replaced by a Go-equivalent table, and the detector's two open scoping questions must be settled in that issue's body before any round implements it.
Frontmatter
| id | iss-37 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | major |
.abcd/work/issues/resolved/iss-37-phantom-enforcement-claims.md
open on GitHub ↗ · commit history ↗
mentions9
- dcn-26072900000000022026-07-29 — v0.5.0 scoped as "security & consistency" (plan: plans/2026-07-29-v0.5.0-security-and-consistency.md): the security half closes the NEXT.md leak class end-to-end (itd-74/spc-20; the atomic iss-154+157+125+153 detector item; iss-155/156; guard batch iss-159+144+148; boundary fixes iss-30/34), the consistency half retires the record-currency majors (iss-37..44, iss-80) — maintainer added the latter rather than deferring them. Version is derived by launch ship, not declared; 0.5.0 is the prediction given itd-74 additive. Deferred majors listed explicitly in the plan (largest: iss-124); the 2026-07-24 queue's pick-up role is superseded.
- dcn-26080200000000032026-08-02 — iss-38 (v0.5.0 item D): hand-maintained indexes are either DELETED or GATED, never corrected and left hand-kept, because a corrected list drifts again on the next commit and nobody notices the second time either (adr-5, derive don't store). The ledger named four stale indexes; three were real and one does not hold. (1) `intents/README.md` transcribed four lifecycle directories as ASCII trees and had fallen sixteen drafts, one promotion (itd-73, listed as a draft while living in `planned/`), two disciplines and two superseded intents behind, with a `shipped/` section still calling the directory empty over thirteen shipped intents — deleted, because the enumeration carried nothing the directory does not carry better, and what a filesystem cannot state (the kind taxonomy, the lifecycle contract, the bundle history) stays. (2) `commands/README.md` (fourteen verbs named, eighteen files present) and (3) `internal/README.md` (core described as "identity/version and the read-only status snapshot" while its own later bullets described twenty packages, and `adapter/scanner` filed under planned seams although it ships with its own pattern set, redactor and tests) keep short, high-value enumerations — so those ship WITH the detector rather than as a promise to remember. The new `index_drift` rule holds a marked region (`<!-- index: <id> -->`) to the directory it enumerates in one of two modes: `exact`, where listing and directory must agree both ways, and `absent`, where every listed path must still be missing — the planned-seams shape, whose drift is a seam that shipped. Scoping is an explicit marker plus a configured entry pattern rather than a markdown-list parser: one generic rule, no bespoke parser per README, and unrelated prose beside a list cannot fire it. It fails closed three ways (region gone while the config entry remains; region parsing to zero entries; malformed spec), so half-deleting an index is a finding rather than a silent disarm. (4) The fourth instance — "the repo README Layout omits `skills/` from the plugin surface" — was investigated and does NOT hold: there is no `skills/` directory, abcd ships zero skills deliberately (the three workflows once shaped as skills became commands, closing iss-61; `brief/05-internals/08-skills.md` states it), so the Layout section is correct by omission and was left untouched. Inventing a `skills/` reference to satisfy a finding would have written a falsehood into the record to close a ticket — the same disposition iss-37 reached on its one non-holding instance. CHANGELOG: an entry, unlike iss-34's test-only pass, and impact `additive` rather than `internal` — the rule lives in the shipped lint engine that `abcd docs lint` runs, so any abcd-managed repo gains it by declaring its own pairs in `.abcd/docs-lint.json`.
- dcn-26080200000000082026-08-02 — iss-40: one canonical glossary, chosen as a ROUTING rule rather than a migration. `.abcd/development/brief/glossary/` keeps the name "glossary" and 04-naming.md stops claiming it; what stays behind in 04-naming.md is its ~60-row Reserved-vocabulary table, unchanged, because those rows are closed enums and spec-pinned reserved names (`dormant`, `task_classes` members, `index.json` field names) and the glossary schema's `aliases`/`forbidden_synonyms` fields mean nothing for an enum value. Folding them into term files would have invented scope and misused the schema; the defect was the false self-identification, and only that is retired. `VR001` keeps its reserved status and its two registration targets — the word "glossary" is removed from its descriptions across the brief and itd-37 so the term resolves to one place, but nothing about what the reserved lint would check is changed, since no Go code implements it. The index is made derived on the brief↔lifeboat-mapping pattern (`internal/core/glossary` renders, a test in the same package gates the committed README against it) rather than by a new schema-validation engine, which the README had been promising through a JSON-schema file and a `abcd lint terminology` verb that do not exist. Three limits are recorded rather than papered over: the drift gate checks the index against the term files, NOT each term file against the field tables, so the frontmatter shape stays a review responsibility; the banlist entry `names/record/glossary-self-identification` reaches only the docs-lint roots (`docs/`, root `README.md`), so it guards the published surface, not the brief where the retired phrase lived — adding `.abcd/development/brief` as a lint root surfaces 75 pre-existing blockers and is its own piece of work; and `05-internals/06-lint.md`'s `TM003`–`TM011`/H1 rows still claim `terminology.schema.json`-backed schema validation "Delivered" that no Go code implements — the same phantom-enforcement-claim class this change retires for the glossary README's validation section, but for TM003+ it sits outside iss-40's self-identification scope and inside iss-37 (phantom-enforcement-claims), stopped at round 13 pending maintainer disposition; left untouched here rather than pre-empting that disposition.
- dcn-26080500000000012026-08-05 — iss-37 (v0.5.0 item D): re-scoped in place per the 2026-08-03 maintainer disposition, from five instances to the three doc claims that describe the gate suite wrongly, and the fix direction is doc-side throughout because the issue's class is claims-must-match-reality and the disposition frames all three as doc claims — the Makefile and every gate's behaviour are untouched. `AGENTS.md` names the three lint gates `make preflight` runs (`lint-reviews`, `record-lint`, `docs-lint`) ahead of build/vet/test/race, and its definition of done keeps `gofmt -l .` as a requirement while attributing it to CI's own format step rather than to preflight, which does not run gofmt. The `ci.yml` record-lint comment claimed the step was "visible but non-blocking for now"; the step has no `continue-on-error` and `record-lint` exits non-zero on a blocker, so the comment described an intention the workflow had already outgrown — it now states the gate blocks and that warns surface in the log only (comment-only; no step structure touched). `README.md` and `CONTRIBUTING.md` describe the real suite, and CONTRIBUTING stops claiming preflight and CI run "the same checks" where they do not. Instance 1 of the original five (the `docs/reference/cli/README.md` freshness claim) was verified accurate in round 13 and carries no work. The brief's 06-lint.md section-1 catalogue — a predecessor project's Python-era `IL001`–`RC007` families and class names — plus the gate cross-check detector are re-filed as iss-181 rather than reworked here, because the disposition on them is substantive (remove the catalogue, never archive it; do NOT mint a Go-equivalent numbered scheme, which is taxonomy design and would ship already-stale against this cycle's own rules; rework section 1 generically over the live armed rules and `internal/core/lint`, with any literal enumeration generated and gated) and the detector's scoping — scan root, and what "a live definition" means for a prose-named gate — is unsettled and recorded as two open questions in that issue's body. iss-37 is resolved against the re-scoped body.
- iss-142prompt-quality brief self-contradiction: 05-prompt-quality.md states PQ001-PQ006 are shipped by spc-8, while 06-lint.md declares the PQ family a design target with no PromptLinter in internal/core/lint — the code sides with 06-lint. An instance of the iss-37 phantom-enforcement class, surfaced by the itd-100 docs-currency review when the crosswalk nearly repeated the phantom claim. Detector: enforcement-claims-are-facts sweep over the brief's Shipped-by annotations; acceptance corpus: the two contradicting lines.
- iss-18106-lint.md section 1 (the lint-code namespace) is a catalogue of a predecessor project's Python-era implementation — the `IL001`–`RC007` code families and the class names they cite (`IntentLinter`, `BundleLinter`, `PromptLinter`, `SpecLinter`) describe code this repo does not carry. Re-filed here from iss-37 (2026-08-03 maintainer disposition), which is re-scoped to its three doc-claim instances.
- iss-182Three build-plumbing comments still describe the pre-push gate and CI by an older, smaller shape. Same class as iss-37 (claims must match reality), in living files its re-scope does not cover, and no ledger entry records them until now. The fix direction is the same bar: state what actually runs, verified against the recipe or workflow beside the comment.
- iss-389the examples-use-reserved-identifiers principle still says a fixture-identifier lint would make it a discipline — the allowlist-inversion lint shipped (iss-154) and cites the principle by name, so the Promotion paragraph misdirects an agent to build an existing rule
- iss-2608260944055780Brief self-contradiction on abcd lint's exit grammar: 05-internals/06-lint.md:174 states "Exit code follows the standalone grammar (blocker -> 1, warn -> 2, clean -> 0)", which inverts the two non-zero codes. internal/core/repolint/repolint.go:147 exitCode() returns 2 on any blocker, 1 on warnings only, 0 clean, and its own comment names the Conftest tri-state; 04-surfaces/16-lint.md:41 agrees with the code. Observed: this tree at 19 errors and 3 warnings exits 2. The consequence is worse than count drift, because an exit code is a number a CI job branches on: a job written against 06-lint.md would treat 1 as its failure condition and pass green on a tree full of blockers, a gate that runs and never fires. Same class as iss-142 (the iss-37 phantom-enforcement class) and the same file, different line; iss-181 and iss-251 also sit on this file and cover neither. Brief-tier, so under adr-28 it ships in no release artefact and reaches no installed surface, which is the standing disposition for brief drift and the argument for a lower severity. Refines iss-2608261029074763, which records the wider defect this is one symptom of: 06-lint.md section 3 documents an architecture that was never built, verified as internal/core/lint having no package main so the documented invocation cannot run, --codes-filter, --promote-check, --touched-line and --display-path having zero hits across internal/ and cmd/, no .pre-commit-config.yaml, and IntentLinter, _classify_and_filter, _parse_hunk_lines and _detect_location present in no source file. That record cites this one for the exit grammar rather than restating it. Adjacent and distinct: iss-2608231000561060 covers the gates-CI claim and gate-readiness. Detector: enforcement-claims-are-facts sweep over the brief's exit-code and gating claims. Acceptance corpus: the three lines above.