Development record
A Shipped Intent No Longer Drifts Out Of Audit Just Because Nobody Ran The Review
Re-scoped on 2026-09-21 by the product thinker: one bounded command that pays the backlog,
abcd intent audit --owed, run once by the autonomous run's first batch. The standing list is itd-2609150819445595 and the inline audit of every new lane isabcd build's (itd-2609201916151817, itd-50); the boundary-hooked autodrain and the blocking gate this record first described are dropped. The press release and scope below are read through this paragraph and the Decisions section.
Press Release
abcd closes the audit back-edge: when a specced block of work ships, its owed fidelity review actually gets run at a safe moment, and a standing gate surfaces any shipped intent whose review is missing or unmet — without ever blocking the autonomous loop. Today abcd does the honest half: closing a spec moves its intent to shipped and enqueues a fidelity-review entry. But the review itself only runs when someone manually invokes it, so the queue can quietly accumulate owed reviews that nobody drains, and a shipped intent can sit with its acceptance never machine-checked. This intent adds an opt-in drainer that runs queued reviews at a safe boundary (after a loop, at a session edge, in a pre-commit or CI step — never inside the pure close hook), leaving entries deferred rather than failed when no review backend is reachable, plus a consistency gate that lists shipped intents whose latest review is absent or not-met. Enforcement, not just bookkeeping — and loop purity preserved.
"We shipped a dozen specs and only later found half their intents had never actually been audited against what we built," said Iris, a product manager leaning on abcd's intent discipline. "The queue was doing its job recording that a review was owed. Nothing was paying the queue down. I want the owed reviews to drain themselves when a backend is around, and I want a single list of 'shipped but not really verified' so nothing slips."
Why This Matters
abcd's intent discipline promises that shipped work is reconciled against the intention that justified it. The on-close lifecycle hook (deliberately a pure data function — no subprocess, no oracle dispatch, because it runs inside the autonomous loop) correctly only enqueues the review. That decoupling is right: running a blocking oracle call on the loop's critical path would add latency and, in headless mode, frequently hit an unreachable backend and stall. But the consequence is that "a review is owed" and "a review was run" have drifted apart, with nothing closing the gap.
The fix is not to make the close hook run the review — that would break loop purity and re-introduce the stall. The fix is a separate drainer that runs at a safe boundary where a backend is reachable, plus a gate that reports the truth of record. This keeps the clean seam (enqueue is pure; drain is a deliberate, backend-aware step) while making "shipped" mean "shipped and actually audited." The queue already carries the hard correctness machinery — a two-lock protocol guarding the audit-notes writeback, claim/drain/crash-stale recovery — so the drainer rides existing safety rather than inventing it.
What's In Scope
- An opt-in
review.autodrainconfiguration (default off) that, at a safe boundary (after an autonomous turn, at a session edge, or in a pre-commit/CI step — never in the pure close hook), drains pending fidelity-review queue entries by running them when a backend is reachable. - No-backend behavior: entries stay
deferred(not failed), so a headless run never blocks on an unreachable backend. - A consistency gate / report that lists shipped intents whose latest fidelity review is missing or not-met — turning the back-edge from trigger-and-record into a surfaced gate.
- Coverage vocabulary. The gate reports each intent's consumption state in five words: uncovered (scheduled, no spec claims it), covered-shallow (a spec claims it but that spec's own obligations — implementation, tests, validation — are not all green), covered-deep (claimed and transitively green; the only state that may combine with the intent's own MET criteria into "done"), orphaned (a spec claims an intent that does not exist), and unwanted (a spec claims an intent that never asked for coverage: a draft, a superseded intent, or a discipline — disciplines are complied with, never consumed).
- Preservation of the close hook's purity: the hook still only enqueues; the drainer and gate are separate surfaces.
What's Out of Scope
- Making the on-close hook run the review inline. Explicitly rejected — it breaks loop purity and re-introduces the headless stall. The whole point is to keep enqueue and run separate.
- The headless backend-reachability fix. The drainer needs a reachable backend to make progress; the in-process-oracle gap is itd-47's concern, upstream of this intent.
- The facilitator-elected loop-toward-acceptance policy (re-open work on not-met, terminal unachievable→replan). That rides on this drainer as substrate but is its own intent (itd-50).
Scope Conditions
None stated.
Mechanism
We expect the backlog of owed audits to clear once paying it is one bounded command, because the debt accrued only while each audit was a hand-run request and ingest; shown wrong if the owed count is unchanged a month after it ships.
Acceptance Criteria
- Given
abcd intent audit --owed [--max <n>], when it runs, then it lists the owed audits oldest first and runs each as the host pass a single-intent audit uses, ingesting each verdict; the cap stops it and the summary names how many remain. - Given no reviewer is reachable, when it runs, then every entry is left owed, not failed, and the summary says why nothing ran.
- Given a verdict, when it is ingested, then it lands exactly as a single audit's does (audit notes, receipt, scope-condition dispositions), and a not-met verdict on a long-shipped intent is captured, not fixed.
- Given a spec closes, when the close hook runs, then it still only enqueues; nothing starts a reviewer from it.
Decisions
Ruled by the product thinker on 2026-09-21, in the interview that gave this intent its spec:
- One bounded command for the backlog, run once by the autonomous run's batch 0; no boundary-hooked autodrain.
- The gate reports and never blocks; the report is itd-2609150819445595's listing.
- Cost is bounded by
--maxand by the host pass running one audit at a time.
Open Questions
None open; decisions 1 to 3 settle the three this record carried.
Audit Notes
Fidelity review — receipt rcp-d2372b1cb47f (verifier intent-auditor claude-fable-5-1).
Provenance: intent-auditor@claude-fable-5-1 · rubric_hash sha256:effa65b3e9e88ff29433b443ec2be159522a8b0b71cf1434526514aa61edb13e · prompt_hash sha256:43f905f19cd97de59ca5454a3361eb53a27b88049e9cc2848808ae1a0a4881c4 Input attestations: diff:internal/core/intent/drain.go, internal/core/intent/lifecycle.go, internal/surface/cli/intent_drain.go, commands/intent.md (Drain section) at BASE 4ce401c5 (tree 376356ce669156f45b423eb7858a952ffeb0f9d6)@-;
Acceptance rollup: MET 1 · MET_WITH_CONCERNS 3 · NOT_MET 0 · INCONCLUSIVE 0
Per-criterion verdicts:
- ac-1 — MET_WITH_CONCERNS: OwedQueue orders the owed reviews oldest shipped first and caps at --max with Remaining named, runOwedDrain prints the list and emits the head's request, and the tests pin the order, the cap and the remainder; concern: 'runs each as the host pass … ingesting each verdict' is delivered as the plugin page's prose loop (steps 1-4), not as code, and no test exercises an end-to-end drain that runs and ingests more than the emit of the head
evidence: internal/core/intent/drain.go:68 — "OwedQueue orders the owed fidelity reviews oldest shipped first and caps the"
evidence: internal/core/intent/drain.go:120 — "q.Remaining = q.Owed - len(q.Queue)"
evidence: internal/surface/cli/intent_drain.go:73 — "; %d listed (--max %d), %d remain"
evidence: internal/core/intent/drain_test.go:27 — "TestOwedQueueOrdersOldestShippedFirst"
evidence: internal/core/intent/drain_test.go:85 — "TestOwedQueueCapNamesTheRemainder"
evidence: internal/surface/cli/intent_drain_test.go:58 — "TestIntentAuditOwedOrdersOldestFirstAndEmitsTheHead"
evidence: commands/intent.md:765 — "For each entry in
queue, in order:" - ac-2 — MET_WITH_CONCERNS: the CLI runs no reviewer, so every entry stays owed by construction, and the page's step 1 instructs the host to run no audit and to say why when no intent-auditor is listed or its launch is refused; concern: the no-reviewer detection and the summary wording exist only as page prose executed by the host agent, and nothing in code or a test verifies that path evidence: internal/surface/cli/intent_drain.go:106 — "this command runs no reviewer: every entry stays owed until its verdict is ingested" evidence: commands/intent.md:757 — "Check for an auditor first." evidence: commands/intent.md:759 — "every entry stays owed, nothing is marked failed or dead-lettered for"
- ac-3 — MET_WITH_CONCERNS: the drain emits through the same AuditEmitOptions path a single audit uses and the page ingests through the one
intent audit ingestverb, so a verdict lands as a single audit's does (this lane ingested rcp-dd80727d7bd1 that way); the page's step 3 directs a NOT_MET verdict toabcd capture … --source review-followupand forbids a fix; concern: the capture-not-fix rule is page prose with no mechanical form evidence: internal/core/intent/drain.go:151 — "func NextOwedAudit(repoRoot string, max int, shippedOn ShippedOn, opts AuditEmitOptions) (DrainStep, error)" evidence: commands/intent.md:770 — "intent audit ingest --verdict-json <file> --json. The verdict lands exactly" evidence: commands/intent.md:776 — "A NOT_MET verdict is captured, never fixed." evidence: internal/core/intent/drain_test.go:150 — "TestNextOwedAuditEmitsTheHead" - ac-4 — MET: Reconcile's step 3 calls emitAuditForIntent to park the OWED stub and the ephemeral request and nothing more; no file in internal/core/intent imports os/exec, and the page states the close still only parks the marker with no hook, gate or schedule running a reviewer evidence: internal/core/intent/lifecycle.go:1022 — "3. Emit the fidelity-review OWED stub + ephemeral request over the shipped" evidence: internal/core/intent/lifecycle.go:1027 — "emit, err := emitAuditForIntent(repoRoot, res.Intent)" evidence: commands/intent.md:796 — "the spec close still only parks the OWED marker, and no hook,"
Gap audit:
- honoured:
- one bounded command pays the backlog, oldest first, capped by --max (decisions 1 and 3)
evidence: internal/core/intent/drain.go:68 — "oldest shipped first and caps the"
evidence: internal/surface/cli/intent_drain.go:15 — "runOwedDrain is
abcd intent audit --owed [--max <n>](itd-53," - loop purity: the close hook enqueues and never starts a reviewer evidence: internal/core/intent/lifecycle.go:1027 — "emit, err := emitAuditForIntent(repoRoot, res.Intent)"
- entries are left owed, never failed, when nothing runs them evidence: internal/surface/cli/intent_drain.go:106 — "every entry stays owed until its verdict is ingested"
- one bad record never blocks the drain evidence: internal/core/intent/drain_test.go:234 — "TestNextOwedAuditSkipsAHeadThatCannotBeEmitted"
- one bounded command pays the backlog, oldest first, capped by --max (decisions 1 and 3)
evidence: internal/core/intent/drain.go:68 — "oldest shipped first and caps the"
evidence: internal/surface/cli/intent_drain.go:15 — "runOwedDrain is
- diverged:
- the press release promised a drainer that runs at a safe boundary (after a loop, at a session edge, in a pre-commit or CI step); decision 1 replaced it with one bounded command run by hand, and nothing starts the drain on its own evidence: commands/intent.md:795 — "Nothing starts the" evidence: .abcd/development/intents/shipped/itd-53-review-queue-auto-drain-fidelity-gate.md:21 — "adds an opt-in drainer that runs queued reviews at a safe boundary"
- the press release promised a standing list of shipped intents whose latest review is missing OR not-met; decision 2 names the owed listing as that report, but the listing reads the marker state only, so an intent whose ingested verdict was NOT_MET reads INGESTED and leaves the list, and the unmet half survives only as a page-instructed capture per verdict evidence: internal/core/intent/owed.go:36 — "State is OWED, INGESTED, DEAD_LETTER, or none." evidence: commands/intent.md:776 — "A NOT_MET verdict is captured, never fixed."
- missing: (none)
References
- Substrate for: itd-50 (facilitator-elected loop-toward-acceptance + unachievable→replan) — that policy layer rides this drainer.
- Depends on / coordinates with: itd-47 (headless backend reachability — the drainer needs a reachable backend to make progress).
- Source: design discussion on the audit-loop enforcement design (a dated working-log entry, 2026-06-02, "should spec-close auto-run review" — resolved NO; add a drainer instead).
- Touches: the pure on-close lifecycle hook (spc-28, predecessor store) and the review-queue drain/claim machinery; the fidelity reviewer (spc-12, predecessor store) is the run target.
Grounds
- pursued: the run's first batch audits every shipped-but-open intent and has no verb to run the audits with; we expect the owed count to fall to zero in that batch and stay near it once build audits inline; shown wrong if the owed count is unchanged a month after it ships
Frontmatter
| id | itd-53 |
|---|---|
| type | intent |
| lifecycle | shipped |
| kind | standalone |
| severity | major |
.abcd/development/intents/shipped/itd-53-review-queue-auto-drain-fidelity-gate.md
open on GitHub ↗ · commit history ↗
References1
- adr-16not in the treerelated
Referenced by11
- adr-40Review, audit, lint, and gate are four buckets, separated by what each comparesrelated
- iss-2610262035102052itd-53 calls the shipped-but-unreviewed listing a consistency gate; the intent chapter uses Consistency for the Role 2 cross-document passrelated
- iss-2610262035104777itd-53's press release has an opt-in drainer run owed reviews at loop ends, session edges and pre-commit or CI steps; the intent chapter says nothing starts the drain on its ownrelated
- iss-2610262035112905itd-53 says entries with no backend stay deferred; the intent chapter says such entries stay owedrelated
- iss-2610262040116437The configuration chapter rules out an autodrain config knob on purpose; shipped itd-53 scopes an opt-in `review.autodrain` keyrelated
- iss-2610262042237923A fidelity review that cannot run because no backend is reachable is 'deferred' in itd-53 and 'owed' in the verification matrix.related
- iss-2610262045122268itd-53 calls loop-toward-acceptance a facilitator-elected policy riding on its drainer; itd-50 ruled the loop is build's last stage, not a per-intent moderelated
- iss-2610262045126115itd-50 relies on a drainer that runs queued reviews at a safe boundary; itd-53 ruled out any boundary-hooked autodrainrelated
- iss-2610262045533651itd-53 calls the owed review a queue entry; itd-80 calls it a parked OWED receiptrelated
- itd-50The Audit Loop Drives An Intent To Acceptance — Or Calls For A Replanblocks
- spc-2609211930059886review-queue-auto-drain-fidelity-gateimplemented by
mentions12
- adr-34Intent lifecycle and phase scheduling are orthogonal axes
- dcn-26070800000000032026-07-08 — Consume-model interview: `spec_id` is SCALAR (never a list) —
- iss-2609261536147903Planned intents and disciplines still cite specs of the retired predecessor store unqualified, and such an id at or below spc-70 resolves to a live spec on another subject (spc-12, for one, is live as the disembark grounding spec): itd-48, itd-50 and itd-53 name spc-12, spc-28, spc-29, spc-31, spc-33, spc-43 and spc-52 for the fidelity reviewer, lifecycle hook and cleanup work (which of these are predecessor ids is itself the reading this record owes); itd-24 names spc-66 as the phase-audit receipt; itd-1 and itd-37 name spc-12 as the manual reviewer. The specs charter (Two spc-N Namespaces) rules that every predecessor citation carries the '(predecessor store)' qualifier; iss-239 applied it to the draft corpus only. Each site needs a reading to tell a predecessor citation from a live one, which is why the sweep was not folded into iss-239.
- iss-2609262107472569itd-53 fidelity audit: the press release promises a standing list of shipped intents whose latest fidelity review is missing OR not-met, and decision 2 names the owed listing as that report; the delivered listing (bare intent audit / itd-2609150819445595) reads the review marker state only, so an intent whose ingested verdict was NOT_MET reads INGESTED and leaves the list, and the unmet half survives only as the page-instructed capture per verdict (receipt rcp-d2372b1cb47f)
- 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.
- itd-47Oracle-Backed Gates Pass Honestly Without A Human In The Loop
- itd-51abcd Knows What "Safe Enough to Adopt" Means Before a New Harness Arrives
- itd-97The Facilitator Is a Mode, Not a Person
- itd-2609150819445595A shipped intent's owed fidelity review is listed, so the debt is paid
- itd-2609201916151817One verb takes a READY intent to delivered, and refuses while a decision is open
- spc-12disembark-grounds-a-lifeboat-s-open-questions-on-a-repo-s-to
- spc-28the-intent-audit-says-audit-abcd-intent-review-becomes-abcd