Development record
An Intent Ships Itself: `planned → shipped` Follows Its Spec Closing, With A Fidelity Audit Attached
Press Release
abcd ships intent-lifecycle automation: an intent moves from
planned/toshipped/as a side-effect of its linked spec closing, and arrives carrying a fidelity audit. The developer runsabcd intent plan itd-Nto link an intent to a freshly-minted native spec (spc-M) and commit it toplanned/. When the work is done and they runabcd spec close spc-M, a deterministic reconcile detects the change through the intent↔spec link and moves the intent toshipped/— nomoveverb, no hand-editing, because the directory is the lifecycle state. The move emits a host-delegated fidelity-review request over the intent's Acceptance Criteria and the delivered code; the host's verdict is ingested back into the intent's## Audit Notesas per-criterion verdicts (MET / MET_WITH_CONCERNS / NOT_MET / INCONCLUSIVE) plus a three-bucket prose audit (honoured / diverged / missing), every claim carrying a citedfile:lineevidence pointer."I stopped babysitting the roadmap," said Maya, an autonomous-development practitioner. "I plan an intent, I close its spec, and the intent ships itself — and the audit that lands with it tells me, criterion by criterion with evidence, whether what I built actually matches what I promised. The lifecycle stopped being a thing I maintained by hand and became a thing that maintains itself."
Why This Matters
Until now, an intent's journey through drafts → planned → shipped was a set of manual file moves and hand-written audits — the very kind of undisciplined, drift-prone bookkeeping abcd exists to eliminate. itd-3 was driven through the lifecycle entirely by hand (its ## Audit Notes were authored manually) precisely because no machinery existed. That manual precedent is the reference the automation must reproduce.
This intent builds the automation. Directory location stays the single source of truth (adr-26 directory-as-truth): there is no status: field to drift and no abcd intent move to invite manual state-setting. The lifecycle advances only as a consequence of a real event — a spec closing — detected through an ID-anchored link that survives file moves. Because abcd cannot run an LLM itself (adr-25 host-delegated default), the fidelity review is asynchronous: abcd emits a request and parks a receipt; the host runs the reviewer; the verdict is ingested through a validated transport. The result is a lifecycle that advances itself and a shipped record that carries its own evidence.
What's In Scope
- A minimal native spec store (
internal/core/spec): directory-as-truth spec records,spc-Nid minting that does not collide with reserved ids, an ID-anchored bidirectional link to an intent (intent: itd-N), and status-by-directory (open vs closed). abcd intentverb family: bareabcd intentrenders lifecycle status (never mutates);abcd intent plan <itd-N>mints a spec, writes the bidirectional link, setskind(defaultstandalone), and moves the intentdrafts → planned;abcd intent link <itd-N> <spc-N>retroactively links a pre-existing spec;abcd intent review ingestingests a verdict.abcd specverb family: bare render;abcd spec close <spc-N>marks a spec done and runs the reconcile.- A deterministic reconcile: on spec close, detect the linked intent via the immutable link, move it
planned → shippedwith an atomic same-filesystem rename, and repair any drifted derivedspec_id. Fail closed on a missing or ambiguous link — never a silent or partial move. Keeps theintent_lifecyclerecord-lint contract green (theshipped/spec_id ^spc-requirement satisfied, not relaxed). - A host-delegated
intent-fidelity-reviewermarkdown agent (newagents/directory): a single-document (Role 1) fidelity reviewer that reads an intent's Acceptance Criteria + the delivered diff and returns a VSA-shaped verdict JSON with per-criterion verdicts and a honoured/diverged/missing audit, each entry citing evidence. - An async verdict-ingest transport: emit a review-request + park an
OWEDreceipt at the ship-move; ingest schema-gates the verdict, semantically checks it (everycriterion_idexists in the intent, every verdict in-enum), and appends idempotently (keyed on the receipt id) to## Audit Notes. A malformed/absent verdict after retry → receiptDEAD_LETTER, affected criteria recordedINCONCLUSIVE, raw payload retained. - Dogfooding: this intent (itd-80) is the pipeline's first real payload — it is driven
drafts → planned → shippedthrough the machinery it specifies, and its## Audit Notesare produced by the automation, not by hand.
What's Out of Scope
- The inter-spec dependency graph and richer spec-store features (adr-26's full vision) — the store here is the minimal floor: link, status-by-directory, reconcile.
- Bundle-member and discipline lifecycles (itd-34) — slice 1 handles
standaloneonly. - Reviewer Roles 2 and 3 (cross-document consistency, shape-classification; itd-48) and loop-to-acceptance (itd-50) — the reviewer is Role 1, one-shot, report-only.
- Multi-judge juries / calibration harness — a single host verdict; a calibration corpus is added only once real verdicts exist.
- Auto-generation or auto-planning of the spec body —
planmints the spec record and link; authoring the spec's content is not automated here. - A vendor/event "hook" — the reconcile is a deterministic Go step inside
abcd spec close, never a harness event.
Acceptance Criteria
BDD format, per the itd-1 discipline. These gates are checked by
intent-fidelity-reviewer's single-document role when this intent moves toshipped/— this intent dogfoods that path.
- Given a
standaloneintent indrafts/with a valid## Acceptance Criteriasection andspec_id: null, when the developer runsabcd intent plan itd-N, then a native specspc-Mis minted (withintent: itd-N), the intent gainsspec_id: spc-Mand a bindingkind: standalone, the file movesdrafts → planned, andmake record-lintstays green. - Given a planned intent linked to an open spec
spc-M, when the developer runsabcd spec close spc-M, then a deterministic reconcile detects the linked intent through the immutable link and moves itplanned → shippedwith an atomic rename, satisfying theintent_lifecycleshipped/contract, and no unrelated file is modified. - Given the ship-move, when reconcile runs, then exactly one VSA-shaped fidelity-review request (over the intent's Acceptance Criteria + the delivered diff) is emitted and exactly one
OWEDreceipt carrying an idempotency key is parked. - Given a host-produced verdict JSON that matches a parked receipt, when the developer runs
abcd intent review ingest, then the payload is schema-gated and semantically checked (everycriterion_idexists in the intent; every verdict is one of MET / MET_WITH_CONCERNS / NOT_MET / INCONCLUSIVE), and on success the per-criterion verdicts plus a honoured/diverged/missing audit — each entry carrying a citedfile:lineevidence pointer — are appended to the intent's## Audit Notes, and the receipt flipsOWED → INGESTED. - Given a verdict already ingested for a receipt, when ingest runs again with the same
receipt_id, then it is a no-op:## Audit Notesis not duplicated (idempotent append keyed on the receipt id). - Given a malformed/missing intent↔spec link at reconcile time, or a verdict referencing an unknown receipt at ingest time, when the operation runs, then it fails closed — no partial move, no partial append — with a clear error; and a verdict still invalid after retry marks the receipt
DEAD_LETTER, records the affected criteriaINCONCLUSIVE, and retains the raw payload. - Given a crafted
itd-/spc-id containing path-traversal or unexpected characters, when any verb resolves it to a file, then the id is validated against^itd-[0-9]+$/^spc-[0-9]+$and rejected otherwise — no file outside the intent/spec directories is read, written, or moved.
Prior Art
- itd-34 (three intent kinds) — defines the
kindfield and the standalone/bundle/discipline lifecycle paths; slice 1 implements thestandalonepath only. This intent is the lifecycle automation itd-34's ACs assume exists. - itd-46 — the
abcd intentcreate ergonomics (markdown surface); complementary, not overlapping (that is the create path; this is plan→ship→audit). - itd-48 — the reviewer's Roles 2/3; this intent delivers Role 1 that they extend.
- itd-3 (shipped, manual precedent) — its hand-authored
## Audit Notesare the golden reference the automated audit must reproduce in shape. - adr-26 (native spec store — directory-as-truth), adr-25 (host-delegated LLM default), adr-27 (autonomous-run receipt gating) — the load-bearing decisions this intent instantiates.
.abcd/development/plans/2026-07-11-intent-lifecycle.md— the SOTA-researched design plan this intent builds to.
SOTA
Per the sota-per-intent principle: existing alternatives + rough maturity, then the chosen path. Harvested from the SOTA-researched design plan
2026-07-11-intent-lifecycle.md.
- Spec store / lifecycle state. Alternatives: git-native trackers (git-bug —
CRDT, mature; Fossil — mature) avoid directory-state for multi-writer merge,
a pressure a single-maintainer config tool does not have; spec-kit branch-per-spec
(usable) fragments the durable
shipped/record we want; the companion harness spec/task backend (usable) is the intended richer engine. → Path 2: a minimal directory-as-truth native floor (os.Rename, stdlib) with the adr-26 seam to adopt an external spec engine later. No dependency. - Fidelity review (LLM-as-judge). Alternatives: eval/judge harnesses (mature) plus the 2025–26 judge-calibration literature. The literature's conclusions (per-criterion + 4-value ordinal + explicit INCONCLUSIVE + report-not-block, cited evidence, pinned judge/prompt hashes) are adopted as design; the harnesses themselves force a judge and add heavy deps. → Path 2: host-delegated native emit/ingest (adr-25), the better external judge being whatever the host runs. No dependency.
- Async ingestion. The transactional outbox/inbox pattern (de-facto standard)
is adopted as a stdlib pattern (
encoding/json+ hand-rolled validation); the verdict envelope reuses the repo's existing VSA attestation shape. Pattern reuse, not a dependency.
Verdict — Path 2 on every axis. No new dependency ⇒ no path-1 hard stop; the seams are load-bearing (adr-25/26) ⇒ no path-3 review. This is exactly why the build proceeds autonomously without a dependency gate. The design plan's headline: abcd's ADRs (25/26/27 + the VSA shape) already sit on or slightly ahead of generic SOTA here — the work is mostly naming what we have after its mature counterpart and closing two gaps (cited evidence per criterion; pinned judge/prompt/rubric hashes).
Open Questions
spc-Nminting under reserved ids. The corpus pre-referencesspc-ids in planning docs and itd-3 reservedspc-1. Slice 1 mintsmax(spec-store files ∪ intentspec_id) + 1to avoid live collisions; reconciling the store's sequential minting with the brief's aspirational spec numbering is deferred to the richer spec-store slice.- Where the review-request + receipt are parked. A local ephemeral queue vs a committed slot — leaning local-ephemeral under
.abcd/.work.local/for the request, with the receipt as the correlation record; settle at plan.
Audit Notes
Fidelity review — receipt rcp-1c213fa02f85 (verifier intent-fidelity-reviewer claude-opus-4-8).
Provenance: intent-fidelity-reviewer@claude-opus-4-8 · rubric_hash sha256:ab445258f3cb9204b559e976e358e19ba2042a447a057a681c388c4aa8ca4e0e · prompt_hash sha256:aa9225ac1f4b4eeadb4a3c3df9922446cfa1b35b1f9b7975b0210e282a252409 Input attestations: diff:9596454..058072d@sha256:058072d-phases-1-4-on-main;
Acceptance rollup: MET 6 · MET_WITH_CONCERNS 1 · NOT_MET 0 · INCONCLUSIVE 0
Per-criterion verdicts:
- ac-1 — MET: Live-verified this cycle: abcd intent plan itd-80 minted spc-2 (spc-1 reserved by itd-3 correctly skipped), wrote spec_id: spc-2 + kind: standalone, and moved drafts->planned; record-lint stays green. evidence: internal/core/intent/lifecycle.go:97 — "func Plan(repoRoot, intentID string) (PlanResult, error)"
- ac-2 — MET: Live-verified: abcd spec close spc-2 reconciled itd-80 planned->shipped via atomic rename through the immutable link; the shipped spec_id ^spc- contract holds and no unrelated file was modified. evidence: internal/core/intent/lifecycle.go:261 — "func Reconcile(repoRoot, specID string) (ReconcileResult, error)"
- ac-3 — MET_WITH_CONCERNS: Exactly one OWED receipt (rcp-1c213fa02f85) and one review request were parked. Concern: the request references the delivered diff as 'host supplies the range' rather than abcd capturing it — a deliberate adr-25 transport-agnostic divergence (core runs no git), so the diff is host-attested, not abcd-attested. evidence: internal/core/intent/review.go:168 — "func emitReviewForIntent(repoRoot string, it Intent) (ReviewEmitResult, error)"
- ac-4 — MET: Self-demonstrating: this very verdict is schema- and semantic-gated (criterion ids, in-enum verdicts, required policy hashes) and its per-criterion + honoured/diverged/missing audit with cited evidence is what is being appended, flipping the receipt OWED->INGESTED. evidence: internal/core/intent/review.go:295 — "func IngestVerdict(repoRoot, verdictPath string) (IngestVerdictResult, error)"
- ac-5 — MET: Re-ingest of an already-INGESTED receipt short-circuits to a no-op; covered by TestIngestIdempotentNoOp and demonstrated by a second ingest run in this cycle. evidence: internal/core/intent/review.go:326 — "if state == "INGESTED" {"
- ac-6 — MET: Fail-closed throughout: reconcile refuses a missing/malformed/ambiguous link with no partial move; an unsolicited verdict is rejected; a resolvable-but-invalid verdict (incl. a partial one, len(seen)!=k) dead-letters with the raw payload retained and criteria INCONCLUSIVE. security-reviewer PASS. evidence: internal/core/intent/review.go:461 — "func deadLetter(repoRoot string, it Intent, content, rcp string, raw []byte, reason string)"
- ac-7 — MET: Every itd-/spc-/rcp- id is regex-validated before any path is built; crafted traversal ids are rejected and no file outside the intent/spec dirs is touched. security-reviewer PASS after an explicit path-traversal attempt.
evidence: internal/core/intent/intent.go:54 — "intentIDRe = regexp.MustCompile(
^itd-[0-9]+$)"
Gap audit:
- honoured:
- The core promise: an intent ships itself as a side-effect of its linked spec closing, directory-as-truth (no status field, no move verb). evidence: internal/core/intent/lifecycle.go:261 — "func Reconcile"
- ID-anchored bidirectional link with spc-1 reservation respected — the first mint is spc-2, not a collision with itd-3. evidence: internal/core/spec/store.go:91 — "func NextID(repoRoot string) (string, error)"
- Host-delegated async review (adr-25) with the intent's ## Audit Notes as the single source of truth for review state. evidence: internal/core/intent/review.go:295 — "func IngestVerdict"
- diverged:
- The review verdict/receipt live as ## Audit Notes markers rather than a separate receipt store — a simplification that honours single-source-of-truth over the design plan's sketched receipt file. evidence: internal/core/intent/review.go:326 — "if state == "INGESTED""
- missing:
- Automated capture of the delivered diff into the review request is not implemented (the host supplies the range) — the only promise-relevant gap, cross-referenced by ac-3's concern; deliberate under adr-25. evidence: internal/core/intent/review.go:168 — "func emitReviewForIntent"
Frontmatter
| id | itd-80 |
|---|---|
| type | intent |
| lifecycle | shipped |
| kind | standalone |
| severity | major |
.abcd/development/intents/shipped/itd-80-intent-lifecycle-automation.md
open on GitHub ↗ · commit history ↗
References5
- adr-25The LLM is host-delegated by default; oracles are opt-in adaptersrelated
- adr-26A native minimal spec layer with the companion harness `ccpm` as the primary deeper backendrelated
- adr-27The autonomous run is a pluggable seam, not a Ralph portrelated
- itd-1Every Intent Has Acceptance Criteria; Every Audit Verifies Thembuilds on
- itd-34Intents Promote In Three Flavours — Standalone, Bundle-Member, Disciplinebuilds on
Referenced by20
- adr-2609151513118583An intent owns one or more specs, and it ships when its last spec closesrelated
- iss-2610262032163067itd-80 names the Role 1 reviewer `intent-fidelity-reviewer`; the brief's press release says Role 1 belongs to `intent-auditor`related
- iss-2610262032168367itd-80 moves an intent to shipped when its linked spec closes; invariant 17 says a close never ships an intent that another open spec still namesrelated
- iss-2610262035065340itd-80 names the verdict-ingest verb abcd intent review ingest; the intent chapter's command tree names it abcd intent audit ingestrelated
- iss-2610262038106941itd-80 names the Role 1 fidelity agent `intent-fidelity-reviewer`; 34-build gives the same closing-lane fidelity audit to `intent-auditor`related
- iss-2610262040043356The help register names the verdict ingest `intent audit ingest`; itd-80 names it `intent review ingest`related
- iss-2610262040053417The README ships an intent only when no open spec still names it, because an intent owns one or more specs; itd-80's reconcile ships the linked intent whenever its spec closesrelated
- iss-2610262040077279The agent catalog names the fidelity agent `intent-auditor`; itd-80, which created it, names it `intent-fidelity-reviewer`related
- iss-2610262042134366The verb that ingests a fidelity verdict is `abcd intent review ingest` in itd-80 and `abcd intent audit ingest` in the verification matrix.related
- iss-2610262043406581itd-1 calls the fidelity-review sub-verb /abcd:intent audit; itd-80 ships it as abcd intent review ingestrelated
- iss-2610262043417816itd-1 has a repeat review replace the one Audit Notes block in place; itd-80 appends each ingested verdict, keyed on its receiptrelated
- iss-2610262043429522itd-81 requires binary verdicts from every verdict-rendering agent, the intent auditor included; itd-80 ships that reviewer with four-state verdictsrelated
- iss-2610262044454212itd-57 holds a spec back through a native spec dependency that the selector already honours; the native spec store shipped by itd-80 has no dependencies between specsrelated
- iss-2610262044540397itd-44 puts its refusal for the decision kind into a Python plan path (`_choose_candidate_kind`, `plan_single`); in shipped itd-80, planning is the native `abcd intent plan` verbrelated
- iss-2610262045156888The verdict verb is `abcd intent review ingest` in itd-80 and `abcd intent audit` in itd-123related
- iss-2610262045357230itd-34 maps a standalone intent to a flow-next spec made by /flow-next:plan; itd-80 has intent plan mint a native spc-N recordrelated
- iss-2610262045442294itd-80 names the verdict ingest abcd intent review ingest; itd-2609150819445595 names the same review family abcd intent auditrelated
- iss-2610262045533651itd-53 calls the owed review a queue entry; itd-80 calls it a parked OWED receiptrelated
- itd-60When A Surface Ships, The Brief Describes It — Or The Intent Does Not Reach Shippedbuilt on by
- spc-2intent-lifecycle-automationimplemented by
mentions13
- dcn-26071100000000062026-07-11 — Intent-lifecycle slice 1 (build sign-off given): the pipeline is
- dcn-26071200000000012026-07-12 — clean-slate hardening run STEP 0 triage. A fresh adversarial
- dcn-26092500000000022026-09-25 — A scope condition's standing is folded by source precedence, not by position, and a re-ingest for an INGESTED receipt whose payload renders differently replaces the ingested verdict (run A orchestrator, ruling on finding 1 of the lane review of itd-2609020625405251 / spc-2609020626046252, branch feat/scope-condition-verb). The spec's fold took the last disposition in document order, on the premise that both writers append; the verdict ingest does not, since it replaces the receipt's OWED stub in place and the stub is parked at ship time, so on every record the writers produce a verdict ingested after a condition block sits above it, and a same-receipt re-ingest was a noop whatever it carried. The documented override (a verdict whose rationale names the occasion) was therefore unreachable. The ruling: (1) a verdict entry replaces a condition entry iff its rationale names that condition's occasion, wherever either sits; condition blocks among themselves, and verdict blocks among themselves, keep document order; consequently a verdict that has named an occasion keeps overriding a later block written for that same occasion, and a researcher re-dispositioning after it cites a new occasion. (2) A re-ingest whose payload renders to the block already on the record stays a noop; one that renders differently replaces it in place after the first ingest's checks; one that does not validate is refused with nothing written, never dead-lettered over a verdict already ingested. No recorded decision makes the ingest write-once: itd-80's ac-5 ("ingest runs again with the same receipt_id … is a no-op: `## Audit Notes` is not duplicated") is an acceptance criterion whose stated property, one block per receipt and no duplication, the replacement keeps, and `TestIngestIdempotentNoOp` still holds. The closed spec carries a dated correction in place. Separately, the lane's commit bumping cold-reading-detection to 0.1.3 while editing itd-199's markers says readings are pinned to an earlier commit; this tree cannot show that pin, and needs none: no study in this repository is mid-flight, because the reading workstream lives in the research fork (the 2026-09-23 entry above on iss-2609021857343626). History is not rewritten.
- iss-67intent lifecycle fidelity gaps (itd-80): Plan accepts an Acceptance-Criteria section with no top-level bullet (hasAcceptanceCriteria only checks non-blank) so the intent plans then perpetually dead-letters at ingest (countAcceptanceCriteria==0) — Plan and ingest disagree on has-criteria (intent.go:108, C9/seed8); review ingest appends the audit below the template Empty-until placeholder instead of clearing it on first verdict (seed3); ReEmitReview documents a re-park but silently no-ops on an already-INGESTED/DEAD_LETTER receipt (review.go:188, C10/seed10); DEAD_LETTER re-ingest rewrites byte-identical content instead of a no-op (seed9). Detector: Plan and ingest share countAcceptanceCriteria; first-verdict-clears-placeholder; terminal-receipt re-emit; idempotent deadletter. Corpus: C9, seed3, C10, seed9.
- iss-68spec store hardening (itd-80): spec.Create writes a Summary/TODO body — decide the minimal native-spec body and make record-lint tolerant (spec.go:135, seed4); ensureDir/ensureRealDir only Lstat the leaf so a symlinked ancestor (specs/, intents/) is followed — literal guard or honest comment (seed5, spec+intent); readRepoFile Lstat then ReadFile re-resolves the path (symlink TOCTOU) and the size cap is not atomic — open-once O_NOFOLLOW+fstat+LimitReader (store.go:225, P7); Close Lstat-exists-then-Rename is racy and os.Rename silently overwrites — no-replace primitive (store.go:212, P8); maxIntentSpecNum silently drops a non-null unparseable spec_id, fail-open reservation scan (store.go:146, P5). Corpus: seed4, seed5, P7, P8, P5.
- 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-3abcd Loads Its Own Rules On Demand
- itd-29Domain Experts Run A Spec Autonomously And Recover From Anything Without Touching Git
- itd-46`/abcd:intent "<text>"` And `/abcd:capture "<text>"` Become Symmetric Create Paths
- itd-48`intent-fidelity-reviewer` Gains Its Cross-Doc And Kind-Classification Roles
- itd-50The Audit Loop Drives An Intent To Acceptance — Or Calls For A Replan
- spc-11installable-versioned-plugin
- spc-2609020903498198The brief describes every surface that ships, or the intent does not reach shipped