Development record
the-registry-cannot-wave-its-hands-every-surface-file-carrie
Summary
Delivers per-surface sub-verb tables (bucket + existence per verb) across
04-surfaces/, and extends the surface_coverage record-lint rule to check
every table row against the committed command-tree snapshot in both
directions. This is adr-40's detector (decision 6), the fix for iss-246, and
the arming step that must land before any rename intent ships.
Scope
internal/core/lint/lint.go— extendcheckSurfaceCoverage(lint.go, thesurfaceRowparser and the three existing invariants) with the sub-verb pass; new parsing/check helpers may split intointernal/core/lint/ subverbs.go.internal/core/lint/config.go— rule config gains: the snapshot path (default.abcd/development/release/surface.json), the host-delegated surface list (consult,ingest,prepare-this-repo), and the operator-internal verb list (spec,rules,hook,completion) — all explicit config beside the existingBareCommand, never hard-coded silent skips..abcd/development/brief/04-surfaces/*.md(all twenty) — the population pass: one sub-verb table per file, fixed format (below), rows reflecting current pre-rename names..abcd/development/brief/04-surfaces/README.md— the prose describing the machine-checked column extends to the sub-verb grain..abcd/development/brief/02-constraints/04-naming.md— register the bucket enum{lint, review, audit, gate}under Reserved vocabulary (source: adr-40 + this spec), per the VR001 discipline.CHANGELOG.md— additive entry.
Out of scope: any rename (intents 5–7); any change to the surface-grain
Status semantics (stays two-valued); any new surface.json content —
the snapshot generator (cmd/abcd-gen-surface, cli.GenerateSurface) is
consumed, not modified, unless it omits sub-command data the check needs, in
which case extending its emitted shape is in scope but its drift-test
contract (byte-identical regeneration) must be preserved.
Approach
Table format (parse target, one per surface file):
## Sub-verbs
| Verb | Bucket | Status |
|---|---|---|
| `probe` | — | shipped |
| `oracle` | review | shipped |
Anchored by the exact ## Sub-verbs heading. Verb is the sub-command name
as registered (code-span, one token; nested sub-verbs space-separated, e.g.
review ingest). Bucket is one of lint / review / audit / gate, or
— for a non-assessment verb. Status is shipped / staged. Any other
value in either column is a lint finding (mirrors the existing unknown-status
finding).
The check, per surface with a table:
- Load
surface.json; build the registered sub-command set for the surface's top-level verb (the snapshot is drift-checked against the cobra tree byinternal/surface/cli/surface_test.go, so committed bytes are a trustworthy proxy for the tree — no import of the surface package from core/lint). shippedrow → its verb must be in the registered set;stagedrow → it must not; registered sub-command → a row must exist. Each violation is one finding at the row's (or file's) line, rule idsurface_coverage.- Exemptions, all from config: host-delegated surfaces skip step 1–2's cobra
comparison (their rows are format-checked only); operator-internal verbs
are absent from the registry by design and excluded from the reverse
check; the
bare_commandexemption stays as-is. Cobra's auto-addedhelpsub-command is excluded structurally. - A surface file with no
## Sub-verbsheading: fails the lint if the snapshot registers sub-commands for its verb (blindness is what this intent removes); passes if the verb has none.
Population pass (same change, binding rulings):
- Buckets follow adr-40's comparison test. Pre-ruled by the maintainer
(2026-08-16, binding):
identitybare/render = audit; the launch changelog guardrail = gate;guard check= gate.intent ready= gate (adr-40);docs lint= lint;intent reviewanddisembark oraclekeep their current names in rows (the renames update code and table together, gated by this check). - Any other genuinely ambiguous bucket is a STOP for an unattended run — record the ambiguity, do not guess into the closed list.
Acceptance-criteria mapping
- Tables present, two facts per verb — population pass + check step 4; test: a fixture surface file without a table for a sub-command-bearing verb fails.
- Both-direction check — step 2; tests: shipped-but-unregistered, staged-but-registered, registered-but-rowless, each one finding.
- Explicit exemptions — step 3 + config; tests: host-delegated surface passes without cobra backing; an unlisted silent skip is impossible (config absence means the check applies).
- Same-change population, pre-rename names — the twenty files land in this
spec's change;
make record-lintexit 0 on the branch is the proof. - Pre-ruled buckets — recorded above; the population pass applies them.
- Enum registered — the
04-naming.mdReserved-vocabulary row. - No
partial— no code change; the two-valued parse is unchanged and the README prose states the ruling. - Docs sweep — Scope's file list;
record-lint/docs-lintclean.
Every new behaviour lands with a test watched fail before the change.
Frontmatter
| id | spc-27 |
|---|---|
| type | spec |
| lifecycle | closed |
.abcd/development/specs/closed/spc-27-the-registry-cannot-wave-its-hands-every.md
open on GitHub ↗ · commit history ↗
References1
- itd-122The Registry Cannot Wave Its Handsimplements
mentions13
- adr-40Review, audit, lint, and gate are four buckets, separated by what each compares
- dcn-26081700000000012026-08-17 — spc-27 population calls, made unattended within adr-40's test
- 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-250Brief-surface drift found by the v0.5.0 release gate: the full-tier crosscheck (22 checkers, both directions) returned 28 unique discrepancies between the brief's surface prose and the shipped binary — 14 false-claim, 8 undocumented-surface, 2 criterion-violation, 2 stale-count, 2 fictional-layout. Dominant clusters: the vintage/staleness surfaces (bare 'abcd version' three-line render, version --json four fields, version --check, --allow-stale-binary, uninstall --bin-dir) landed without their brief rows; the citation-baseline dry-run gate and render line are undocumented in 04-launch.md; 01-ahoy.md's envelope shape omits the banlist key and guard.detail; 05-intent.md:335 claims gap_audit is deferred (shipped) and an MG004 check ships (does not exist); 07-memory.md's spec-count claim is stale (spc-2..spc-27 exist); the agents/ plugin surface has no registry row and surface_coverage does not check it; skills/-era phrasing survives in 02-constraints/04-naming.md, 06-delivery/01-build-sequence.md and 02-verification-matrix.md. Full list with file:line, claim, reality and class: the iss35-brief-surface-crosscheck receipt for content commit d1afd2c under .abcd/work/reviews/. Not release-blocking (design-record drift, no user-facing doc affected) — same class and disposition as iss-192 at v0.4.2.
- iss-264cmd/record-lint prints Finding.File and Finding.Message raw — no termsafe.Sanitize and no path scrub on the findings path (its scrubPaths covers only the two error exits), so any rule echoing repo content lets a hostile clone inject terminal escapes into CI logs, and any finding message embedding an os error can leak absolute paths. The abcd CLI surface sanitizes at its findings renderer; the standalone binary does not. Found by the spc-27 security review, which also caught (and the change fixed) the one in-diff instance.
- iss-2609290448510918The predecessor-store qualifier sweep reaches past the six intents iss-2609261536147903 named: outside drafts/ and those six, 192 citation sites across about forty intents name a spc-N at or below spc-70 that is not the citing intent's own spec, with no '(predecessor store)' on the line. Some are live cross-references (the cold-reading family's intents cite each other's live specs), and some are the predecessor store's (itd-4, itd-6, itd-29, itd-47 and itd-49 describe pre-rebuild work in its terms), so each site needs the same reading against the live spec it collides with; the specs charter's Two spc-N Namespaces section is the rule. Found while sweeping the pattern of iss-2609261536147903 in lane drainDrift3; a census script over intents/{planned,shipped,disciplines} reproduces the count.
- iss-2609300032219282Superseded itd-47's Implementing specs section says its frontmatter spec_id records spc-27 as the primary delivering spec, while the frontmatter holds spec_id: null, and spc-27 and spc-32 are predecessor-store ids that the live store reuses for the surface-coverage registry and abcd update. The same defect iss-2609300025372991 fixed in itd-36 and itd-4, found in a third intent while qualifying predecessor-store citations for iss-2609290448510918.
- itd-47Oracle-Backed Gates Pass Honestly Without A Human In The Loop
- itd-65abcd Refuses To Publish A Payload Until The Full Ship-Time Pre-Flight Gate Suite Passes, Not Just The Secret Scan
- 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