Development record
Phase as a product-reflection layer between brief and intent
Terminology note. The how layer is named the spec. This ADR's prose was updated by the spec-terminology-rename ADR (adr-11).
Context
abcd organised development work in three layers (adr-1): brief (what is the project), intent (why does this user-facing change matter), spec (how do we build it). Sequencing — which intents and plumbing phases ship together, in what order — had no home of its own. It was carried two ways, both unsatisfying:
- Plugin versions (
v1,v2,v3). The roadmap's "Versioning Convention" section, theroadmap/milestones/directory, and atarget_release: vNfield on every intent all encoded a version axis. But adr-5 had already established that the brief is current state, not a versioned artefact — and a version axis on intents fought that. "v2" is a label with no content; it answers neither "what order" nor "what do we expect to be true." - The dependency DAG in
brief/06-delivery/01-build-sequence.md. This gives dependency edges but not bundling — it cannot say "these five intents form a coherent stretch of work that ends with ahoy working end-to-end."
Neither carrier captured the thing a product thinker actually wants at this grain: a re-statement, in user terms, of what a stretch of work is expected to make true — coarser than a single intent's press release, finer than the whole-project brief. The brief's own mental model gestured at a "phase audit" (reality vs. a phase's acceptance) but never gave it a target to review against, because no phase artefact existed.
Decision
abcd adds a fourth layer: the phase. A phase is an ordered stretch of work that ends in a milestone (a concrete, checkable end condition). Phases replace plugin-version language as the project's sequencing axis.
- Phases live in
.abcd/development/roadmap/phases/— onephase-N-<slug>.mdper phase, plus aREADME.mdindex. Theroadmap/milestones/directory is removed; a milestone is now a section inside a phase doc, not a separate file. - Each phase doc is Expectation-led. Its sections are:
## Expectation(working-backwards: what is true for the user at phase end — press-release voice, at phase granularity),## Milestone(the concrete checkable cut),## Scope(which intents and which brief plumbing-phases this phase bundles),## Maps against(traceability — which brief sections this phase realises),## Dependency rationale,## Open questions. - Specs gain a
phase:frontmatter anchor. A spec already traces to an intent or a brief plumbing-phase; it now also names the phase it belongs to. This makes the phase audit real: when every spec in a phase closes, delivered reality can be reviewed against the phase's## Expectation— the same Given-When-Then fidelity shapeintent-fidelity-reviewerapplies one grain down. - The
target_releasefield is removed from intents entirely. An intent carries no release or sequencing field. The intent → phase mapping is editorial (a sequencing decision), and per the project's own principle — per-item mapping lives in links, coarse-grain mapping is editorial — it lives in the phase doc's## Scope, not in intent frontmatter.target_releasewas unanswerable at capture time anyway (a release number is an output of deciding what each phase contains, not an input a product thinker can stamp on a fresh draft — "they want everything"). An intent not yet listed in any phase doc is implicitly unscheduled. - The bundle invariant is rephrased in phase terms. It was "all bundle
members share
target_release"; it becomes "all bundle members belong to the same phase" (a bundle ships as one spec; one spec belongs to one phase).IL011(the multi-arg-plan guard) becomes a plan-time check rather than a frontmatter-field lint, since phase membership lives in phase docs.
The audit hierarchy is now three grains of one shape: brief audit (reality vs. brief-phase acceptance), phase audit (reality vs. phase Expectation), intent audit (reality vs. intent acceptance).
Alternatives Considered
- Keep plugin versions; treat phases as informal grouping. Rejected: keeps
the
v1/v2label fighting adr-5, keepstarget_releaseas a field a product thinker cannot honestly fill in at capture time, and never gives the phase audit a target. The version axis is a label, not an artefact — it cannot be reviewed against. - Phase as a frontmatter field on intents (
phase: phase-2-ahoy), no phase docs. Rejected: a bare field records membership but not expectation. The load-bearing value of a phase is the product thinker's re-statement of what the phase should make true — that needs prose, which needs a document. - One flat
phases.mdfile instead of a directory. Rejected: a phase carries real per-phase content (Expectation, Milestone, Maps-against, rationale). The brief itself adopted numbered folders over a single file for exactly this reason (brief/00-meta.md); phases follow the same pattern asintents/and the brief sections. - Migrate
target_release→phaseon all intent files. Rejected: replacing one frontmatter sequencing field with another keeps the anti-pattern — it still asks the intent file to record its own sequencing, which then drifts from the phase docs. The editorial intent→phase mapping in phase docs is the single source; intents carry no sequencing field at all. (target_releasewas removed outright in this same change — schema,internal/core/lint/_prd_writer.pyhash recipes, fixtures, and all 40 intent files — rather than renamed.)
Consequences
Gains:
- The roadmap stops fighting adr-5: no version labels on a current-state project. Sequencing has a real artefact instead of a label.
- The product thinker gets a genuine reflection point per phase — a place to re-map expectation against brief and intents partway through the work.
- The "phase audit" the mental model already named becomes buildable: the
phase
## Expectationis what it reviews against. - Specs gain a coarse anchor (
phase:), enabling roll-up status ("Phase 2: 3/5 specs done") and phase-grain fidelity review.
Costs / obligations:
- A fourth layer is one more place to look — discoverability cost. Mitigated:
the layer is thin (a handful of phase docs) and the
roadmap/README.mddashboard renders phase status in one view. brief/01-product/03-mental-model.mdbecomes a four-layer model; its diagram and prose are updated.- The
phase:spec anchor needs eventual lint coverage (verify the named phase exists) — deferred until the phase-audit reviewer is built. Specified (spc-66, predecessor store): thePA001verify-exists anchor lint and the phase-audit reviewer are both specified there; neither is in the Go binary yet. The corpus anchor backfill onto the unanchored specs stays deferred (see the amendment's delivery note). - Removing
target_releasechanges every intent'sintent_source_hash(the field was in the hash recipe). Harmless here — no intent in the corpus is grilled yet, so no storedgrilled_intent_hashis invalidated — but the two hash allow-lists (internal/core/lint,_prd_writer.py) andprd.schema.json's recipe documentation were updated together to keep the "one canonical recipe" invariant intact. - Phase IDs must be stable once specs anchor to them; renaming a phase means re-anchoring its specs.
Downstream decisions enabled:
- A future phase-fidelity-reviewer role (sibling of
intent-fidelity-reviewer) reviewing delivered reality against the phase's## Phase Acceptance(see the amendment below — the original "against## Expectation" was imprecise; prose is not reviewable, structured acceptance is). - A future implementation of
IL011as a plan-time cross-phase bundle check (it can no longer be a frontmatter-field lint).
Amendment — 2026-05-16: phase acceptance is structured, not prose
The decision above said the phase audit reviews delivered reality against the
phase's ## Expectation, "the same Given-When-Then fidelity shape one grain up
from the intent audit." That claim was aspirational, not true as written:
## Expectation is prose (press-release voice). intent-fidelity-reviewer
compares reality against an intent's structured ## Acceptance Criteria, not
against its prose press release. A phase audit needs the same — a structured
target — or it has nothing checkable to review against. This amendment closes
that gap. It completes adr-9; it does not reverse it.
A phase doc carries two parts, mirroring an intent
An intent has a prose press release followed by a structured
## Acceptance Criteria block. A phase doc takes the same shape, one grain up:
## Expectation— prose, working-backwards, the product thinker's re-statement of what the phase makes true. The reflection point. Unchanged.## Phase Acceptance— new, required. Given/When/Then bullets, the same format as intent acceptance. This is the audit target: what the phase-fidelity-reviewer compares delivered reality against. The product thinker authors it — it is the same press-release-voice skill they already use for intents.
## Milestone stays as written: the engineering done-cut ("ahoy install +
uninstall + doctor pass on a fresh repo"). ## Phase Acceptance is the
user-truth cut. The two answer different questions — "is the work finished?"
vs. "is the expectation met?" — and both belong.
The roll-up rule — phase acceptance asserts emergent truth, never copies
This is the load-bearing constraint. A ## Phase Acceptance bullet MUST be a
roll-up, not a re-litigation of intent-level acceptance. It must assert
either:
- (a) an emergent, cross-intent truth no single intent owns — e.g. "the oracle cascade is whole end-to-end: RP → Codex → in-session" is true of Phase 1 but owned by no one intent in it; or
- (b) a user-journey that spans the phase's intents — a path a user can walk that only exists because several intents shipped together.
It MUST NOT copy a bullet that already lives in an intent's ## Acceptance Criteria. Copying duplicates, and duplication drifts — the exact failure the
brief's single-source-of-truth rule and the surface-drift guards exist to
prevent. The phase artefact earns its place precisely by holding the truths no
individual intent can hold.
Consequences of this amendment
- The four existing phase docs gain a
## Phase Acceptancesection (added in the same change as this amendment). - The phase-doc section list in
roadmap/phases/README.mdis updated to include## Phase Acceptancebetween## Milestoneand## Scope. - The mermaid diagram in
brief/01-product/03-mental-model.mdhad the phase audit arrow pointing atBrief; it is re-pointed so the audit target is the phase, agreeing with this amendment. - The deferred phase-fidelity-reviewer now has a concrete spec to point at:
it reviews reality against
## Phase Acceptance, per-bullet, in theintent-fidelity-reviewerverdict shape. - A future lint (
ILor a new prefix) can enforce the roll-up rule — flag a## Phase Acceptancebullet that duplicates an intent-level bullet. Deferred with the reviewer.
Amendment — the phase: spec anchor is deferred, not a standing convention
The decision above said "Specs gain a phase: frontmatter anchor" and that a
spec "now also names the phase it belongs to." Read as a live convention, that
left the corpus in a half-implemented state: four specs carried the anchor,
~37 did not, no tooling read it, and its lint was already deferred (Consequences:
"deferred until the phase-audit reviewer is built"). A half-implemented
convention is the worst state — every spec without the anchor reads as drift
against a rule nothing enforces.
This amendment retires the anchor as a standing convention and re-scopes it as deferred, bundled with the phase-audit tooling that reads it: the anchor, its valid-phase lint, and the phase-fidelity-reviewer land together, in one later spec, or not at all. Until then:
- Phase membership is editorial, reconstructed from each phase doc's
## Scope— the live mechanism today. This is unchanged from the original decision (the intent→phase mapping was always editorial); the amendment only makes the spec→phase mapping editorial too, for now. - No spec is expected to carry
phase:. Its absence is not drift. Specs are neither backfilled (rejected: 37 frontmatter edits is destructive-adjacent and risks the task-JSONupdated_atleak class) nor required to add it going forward. - When the phase-audit tooling is specced, it owns reintroducing the anchor — with backfill and lint as part of that spec's scope, so the convention goes from inert to fully-implemented in one move, never half.
This completes adr-9's deferral posture (the lint was already deferred); it does
not reverse the phase layer itself. The editorial ## Scope mapping, the phase
docs, ## Phase Acceptance, and the phase audit's target all stand. Only the
per-spec frontmatter anchor is deferred. Brief and roadmap docs that described
the anchor as live ("authored going forward") were aligned to this posture in the
same change (roadmap/phases/README.md, brief/01-product/03-mental-model.md,
brief/04-surfaces/04-launch.md).
Delivery note (spc-66, predecessor store). Two of the three bundled
artefacts are specified there: the PA001 valid-phase anchor lint
(verify-exists, line-precise on the phase: key) and the phase-audit reviewer
(a sibling of intent-fidelity-reviewer; specified there, not yet in the Go
binary — reviewing delivered reality against a phase's ## Phase Acceptance via
the editorial ## Scope membership chain, receipt-only). The third artefact
— the corpus anchor backfill onto the unanchored specs — remains deferred,
gated on the reviewer and lint reaching the Go binary: a future spec can then do
the editorial spec→phase mapping with the verification machinery in place.
spc-66 specifies what makes the backfill safe; it deliberately does not
perform it (a spec in no ## Scope stays correctly unscheduled and carries no
anchor).
Frontmatter
| id | adr-9 |
|---|---|
| type | adr |
| status | superseded |
| date | 2026-05-16 |
.abcd/development/decisions/adrs/0009-phase-as-product-layer.md
open on GitHub ↗ · commit history ↗
References1
- adr-10The phase negotiator — a Socratic agent that proposes phases and grounds every trade-offrelated
Referenced by9
- adr-1Three-layer mental model (brief / intent / spec)related
- adr-5Brief is the current state; no version label, no archive directoryrelated
- adr-11One canonical word for a specced block of work — specrelated
- adr-33Launch phase ownership is tiered; the phase index is the sole ownership sourcerelated
- adr-34Intent lifecycle and phase scheduling are orthogonal axesrelated
- adr-40Review, audit, lint, and gate are four buckets, separated by what each comparesrelated
- adr-2609212115255771Phases and milestones are retired: sequencing is dependencies rendered as status, the checkpoint is the derived releaserelated
- adr-2609212115255771Phases and milestones are retired: sequencing is dependencies rendered as status, the checkpoint is the derived releasesuperseded by
- adr-2609292012006845Now, Next and Later list an intent in a lane under Now only; phases stay retiredrelated
mentions19
- adr-35The lifeboat is a coverage experiment — read-only, out-of-tree, and proven before it is packed (supersedes adr-4)
- dcn-26070800000000122026-07-08 — Severity ≠ priority (records an earlier-session decision):
- dcn-26092100000000012026-09-21 — Phases and milestones are retired, and the word roadmap with them (product thinker, at an interactive interview after an independent research pass; adr-2609212115255771 supersedes adr-9). Sequencing is dependencies plus the lifecycle shelves, rendered as a Now / Next / Later status block on the `abcd` board and the site (itd-2609212103568351), never stored; the checkpoint is the derived release plus each intent's acceptance criteria, with an optional `target_release` the cut reports and moves forward (itd-2609212103572513); the unit below a spec is the step, a section not a family (itd-2609212103565953); an issue carries no spec by design; the batch is the run's internal order; one page maps the families (itd-2609211913453478). itd-24 becomes release retrospectives; itd-34 drops its phase rule. Same interview: `build` is the verb a person types and `implement` the loop (itd-2609201916151817 decision 8), the loop takes an issue key (decision 10), only the loop writes a verdict (decision 9); the person's command list is grouped with an agents block behind `--agent` (itd-146), every verb opens with a does/writes/refuses sentence (itd-2609212113220149), modes become flags and five checks one lint (itd-2609212130136102, breaking); the status-line badge is guarded and reset (itd-2609212130146198); a new capture or draft is matched and linked at filing, never refused (itd-2609212137116617); abcd's text names the product thinker or the technical facilitator and never the maintainer (itd-2609212137129937, captured for the run, no sweep today); the lab conventions become `abcd lab` (itd-2609212137128014); a managed repository's site goes live by one verb behind a provider seam (itd-2609061543533170).
- iss-2608261133097575roadmap prose and adr-9 claim the phase-audit reviewer and PA001 lint exist and run as Go tooling; nothing in the Go tree implements either, and sibling records correctly call them a design target from the predecessor store spc-66
- iss-2610262030345408The launch chapter says the repo organises work by phase per adr-9; the mental model says the phase is retired and adr-9 superseded
- iss-2610262031429165The mental model retires the phase and the milestone, but itd-41 builds a negotiator that proposes phases and their Phase Acceptance under adr-9.
- iss-2610262033003041The glossary calls a phase the retired sequencing unit; launch says the repo organises its work by phase
- iss-2610262033041268itd-41 builds a negotiator over ordered phases with Expectation, Milestone and Phase Acceptance; the disembark page says sequence is dependencies plus the lifecycle shelves, and phases and milestones are retired.
- iss-2610262033096678The launch chapter says the repo organises work by phase; itd-24 records that phases are retired and the release is the unit
- iss-2610262033167999itd-2609211913453478 retires phase, milestone and roadmap; the launch chapter still says the repo organises work by phase (adr-9) and uses roadmap as a live record
- iss-2610262044146391The phase negotiator drafts phases, milestones and phase acceptance, but the shipped glossary intent retired phases and milestones
- itd-24Completed Releases Get A Retrospective
- itd-41abcd Tells You, Honestly, What a Phasing Choice Costs
- itd-48`intent-fidelity-reviewer` Gains Its Cross-Doc And Kind-Classification Roles
- itd-78abcd Knows What to Build First — Even When It's Something Small
- itd-2609211913453478One page maps the record families, and phase, milestone and roadmap are retired
- spc-66The scribe: ledger-only context, authors nothing
- spc-2609212131112235one-page-in-the-glossary-maps-abcd-s-record-families-and-how
- spc-2609230613206890Glossary pointers, the family lint and the mental model