Development record
Intent lifecycle and phase scheduling are orthogonal axes
Context
The record carried two contradicting definitions of what intents/planned/
means. intents/README.md defined it as "scoped into a roadmap phase", but the
corpus disagreed in both directions: most planned intents (itd-20, itd-24,
itd-29, itd-46, itd-48, itd-49, itd-50, itd-53, itd-58, itd-63, itd-65, itd-66,
itd-67, itd-69, itd-72) appear in no phase doc's ## Scope, while two intents
named in a phase ## Scope (itd-43 in Phase 0, itd-7 in Phase 6) still lived in
drafts/. With "planned", "phased", and "draft" disagreeing, the roadmap cannot
be used as a scheduler. (Captured as iss-3.)
The same README's own sequencing section already states the opposing model —
"an intent listed in no phase doc's ## Scope is implicitly unscheduled" is a
valid state (per adr-9) — so the record was contradicting itself, not merely
drifting from the corpus.
Decision
- Two orthogonal axes. An intent's lifecycle is its commitment state,
carried by directory location (adr-3):
drafts/= captured, uncommitted;planned/= committed to build;shipped/= built. An intent's scheduling is phase membership, carried editorially by a phase doc's## Scope(adr-9). Neither axis is derived from the other.
- One directional invariant: scheduled ⇒ committed. Any intent named in a
phase doc's
## Scopeis committed by definition, so it lives inplanned/(ordisciplines/for discipline-kind intents). The converse does not hold: a planned intent with no phase is committed but unscheduled — a valid state, the committed bench awaiting sequencing (adr-9's unscheduled-intent rule, now explicitly extended beyonddrafts/).
- Applied to the corpus. itd-43 (Phase 0
## Scope) and itd-7 (Phase 6## Scope) movedrafts/→planned/; the fifteen planned-but-unscheduled intents stay where they are, now legally.intents/README.md'splanned/definition drops the "scoped into a roadmap phase" clause.
- Enumerations derive from the axes, not from each other. Any "later
phase" or "out of scope" list is derived from
## Scopemembership (the scheduling axis), never from thedrafts/directory (the lifecycle axis) — the two sets are different by design.
Alternatives Considered
planned/= phased (enforce the README's old definition). Rejected: it forces every committed-but-unsequenced intent back todrafts/, erasing the commitment signal, or forces premature phase authoring just to keep files in place — exactly the stale forecasting the phases README refuses ("naming which intents land in which future phase before the phase is planned would only go stale").- A
scheduled:frontmatter field on intents. Rejected: duplicates the phase docs'## Scope(adr-9 made that mapping editorial and single-sourced) and reintroduces the stored-status drift adr-3/adr-5 exist to prevent. - Full orthogonality with no invariant (a phase may bundle a draft).
Rejected: a phase
## Scopeis a commitment to build; letting it name an uncommitted draft makes "committed" unreadable from either axis.
Consequences
- itd-43 and itd-7 relocate to
planned/; record-lint checks (the lint engine ininternal/core/lint) can later enforce the scheduled ⇒ committed invariant mechanically. intents/README.mddescribesplanned/as committed (scheduled or awaiting sequencing) and its directory listings match disk.- The out-of-scope/later-phase enumeration (
brief/06-delivery/03-out-of-scope.md) is regenerated from## Scopemembership rather than the drafts directory — tracked asiss-8. - Hand-maintained intent counts keyed to "phased intents"
(
brief/01-product/04-scope.md) are re-derived on the scheduling axis — tracked asiss-7.
Frontmatter
| id | adr-34 |
|---|---|
| type | adr |
| status | accepted |
| date | 2026-07-08 |
.abcd/development/decisions/adrs/0034-lifecycle-and-scheduling-orthogonal.md
open on GitHub ↗ · commit history ↗
References5
- adr-3Directory location is the source of truth for lifecycle staterelated
- adr-9Phase as a product-reflection layer between brief and intentrelated
- adr-33Launch phase ownership is tiered; the phase index is the sole ownership sourcerelated
- itd-7Lifeboats Carry RepoPrompt Workspace Definitions Forwardrelated
- itd-43abcd Speaks One Word for a Specced Block of Work, and That Word Is "Spec"related
mentions24
- adr-5Brief is the current state; no version label, no archive directory
- dcn-26070800000000142026-07-08 — itd-37's itd-36 edge downgraded blocked_by → builds_on: the
- dcn-26082400000000022026-08-24 — Bug-hunt round 5 (bughunt-a): baseline green; five parallel
- iss-3phase membership and lifecycle directories disagree: planned intents (itd-20, itd-24, itd-29, itd-46) appear in no phase Scope, while draft itd-43 is scoped into Phase 0/1 yet listed later-phase. ADR-bound.
- iss-704-scope.md hand-maintains intent counts (thirteen phased intents) that the phase docs and planned corpus have outgrown.
- iss-803-out-of-scope.md omits current drafts itd-74 and itd-75 while including scoped itd-43; regenerate from the actual draft corpus.
- iss-36retired-name banlist population: roughly fifty stale references to retired locations and identifiers survive in the record, and the drift outlived a dedicated same-day consistency pass — development/activity (38 refs in the brief), .work/issues and bare .work/ as a root path (11 refs), scripts/abcd/, .abcd/logbook, .flow/, .github/workflows/lint.yml and lint-corpus.yml, --since-staged, and the python-lint-names pattern narrowly missing bare intent_lint (used by intents/README.md and adr-34). Detector (per retire-the-name and fix-the-detector): add each retired spelling to record-lint banned_tokens with allow_context for genuinely historical passages, widen the intent_lint pattern, then drain the references BEHIND the armed bans — never ahead of them. Acceptance corpus: the reference counts above; the bans are proven when they flag all ~50 on first run and the count ratchets to zero.
- iss-388roadmap phases README states itd-88 is in planned/ and unscheduled, but the intent has shipped — a false bucket claim in present-tense current-state prose
- iss-2608240806090544planned/README.md categorically claims every intent carries a spec_id: spc-N link, but 20 of 43 planned intents have spec_id: null — a legal lint-enforced state (intent_lifecycle) per the surface contract, parent intents/README, and adr-34; the subheading silently reintroduces the over-narrow framing adr-34 already corrected in the parent README (resolved iss-3).
- itd-20`/abcd` Tells You Where You Are
- itd-24Completed Releases Get A Retrospective
- 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-49Flow-State Drift Becomes Visible Before It Compounds
- itd-50The Audit Loop Drives An Intent To Acceptance — Or Calls For A Replan
- itd-53A Shipped Intent No Longer Drifts Out Of Audit Just Because Nobody Ran The Review
- itd-58A Real Reviewer's SHIP Verdict Reaches The Session Gate Through A Channel The Worker Cannot Forge
- itd-63The Amateur Coder Is Told What Is Being Installed And Why, Not Just Asked To Run A Command
- itd-65abcd Refuses To Publish A Payload Until The Full Ship-Time Pre-Flight Gate Suite Passes, Not Just The Secret Scan
- itd-66abcd Renders The Exact Public Payload, Proves The Excludes Never Leak, And Smoke-Tests The Installed Surface Before Any Snapshot
- itd-67abcd Is An Installable, Versioned Claude Code Plugin Whose Repo Is Its Own Marketplace And Whose Every Launch Bumps, Tags, And Publishes A New Version
- itd-69Plugin Metadata Stays Consistent Across Every Duplicated Surface
- itd-72Publishing A Release Is One Atomic, Refusable `ship`