Development record
a-spec-lists-its-steps-and-the-build-lands-them-one-at-a
specclosedspc-2609212138246060
Summary
The design record for itd-2609212103565953: the ## Steps section and the loop's per-step lanes.
Scope
- The template:
## Stepsseeded empty byintent plan; the readiness gate reports the section's shape (a list or empty) as advisory (criterion 1). - The parser:
spec.Steps(spec)returns the ordered list with footprints, or one implicit step (criterion 1). - The loop: the lane in the state file gains
step: n/N;implementstarts the next step's lane only when the previous lane's pull request is an ancestor of the default branch (criterion 2). - The remainder:
spec close --remaindercopies steps not marked landed into the new spec (criterion 3). Each step's indented lines are copied verbatim except a- needs:line, which is rewritten against the remainder's numbering (spc-2609202134341288, piece 6, "Which steps may run side by side"). - Briefs and the run record: the brief renderer prints the step and its predecessors; the record lists
stepper lane (criterion 4). - The page:
commands/intent.mdand the build page say the word once for both (criterion 5).
Out of scope
- The build proposing a split; a task family; reordering mid-run.
Approach
A parser in the spec store, a counter in the state file, one branch in the loop's advance; the first spec to carry steps is the implement spec itself, whose three pieces become its ## Steps.
Footprint
- packages: internal/core/spec, internal/core/implement, internal/surface/cli
- tests: the parser over a stepped and an unstepped spec; the loop advancing only after merge with a fake forge; the remainder copy; the brief
How the criteria are satisfied
| Criterion | Where |
|---|---|
| 1 template and one implicit step | scope 1, 2 |
| 2 lanes in order | scope 3 |
| 3 remainder carries steps | scope 4 |
| 4 briefs and record | scope 5 |
| 5 one word | scope 6 |
Progress
- Criteria 1 and 3 (scope 1, 2 and 4) are delivered by commit e5dfe0fc: the plan stub carries an empty
## Stepssection, rendered from one list of stub sections;internal/core/spec/steps.goparses the section (- packages:,- tests:and- landed: <pull request or commit>indented under each numbered step) and turns a spec listing none into one implicit step;spec close --remaindercarries the steps not marked landed into the remainder and refuses, writing nothing, on a section it cannot read;intent readyreports the section's shape on an advisorystepsrow. - Criterion 4 (scope 5) is delivered by commit 3f20b5167: the brief renderer names the lane's spec step and each step before it with what landed it (the spec's
landed:line at the lane's base, and the run's earlier lane with its branch, head and pull request), and refuses a base listing the lane's step otherwise; the run record carries anopenline naming each later lane's spec step, beside the start line naming the first. - Criterion 2 (scope 3) is delivered by the implement loop's landing (itd-2609201916151817, piece 9, commit 8ede4810f) and its scheduler (commit 3c19408cb): each spec step lands as its own lane through its own pull request, and a step with no
- needs:line needs every earlier step (ruling DR6b keeps this intent's wording of 2026-09-21), so its lane opens only once the earlier lanes are done, a lane being done only when its pushed head is an ancestor of the default branch onorigin(landedInRunandreadyPendingininternal/core/implement/loop/schedule.go).TestAStepWithoutANeedsLineWaitsForEveryEarlierStepininternal/core/implement/loop/parallel_test.goholds step 2's lane closed while lane 1's pull request is armed but not merged, with every slot free, and opens it once lane 1 has landed. - Criterion 5 (scope 6) is delivered by the lane-stage rename the product thinker ruled on 2026-09-29 (BU1: "SPEC PIECES keep 'step'; rename the lane stages"; iss-2609291313276243): "step" now names the spec's piece and nothing else, a lane's are its stages (the state file, the loop's payloads and refusals say
stage, schema version 4), andcommands/intent.mdandcommands/build.mdsay so — one word for one thing.
Frontmatter
| id | spc-2609212138246060 |
|---|---|
| type | spec |
| lifecycle | closed |
.abcd/development/specs/closed/spc-2609212138246060-a-spec-lists-its-steps-and-the-build.md
open on GitHub ↗ · commit history ↗
References1
- itd-2609212103565953A spec lists its steps, and the build lands them one at a timeimplements
mentions3
- iss-2609291313276243The glossary entry for step (.abcd/development/brief/glossary/core/step.md) says the loop's step interface, abcd implement step, uses the same word for the same thing as a spec's steps: the next piece of the current spec. The loop does not work that way: implement step performs one stage of the current lane (worktree, brief, implement, validate, land), and a lane lands one spec step, so the state file, the JSON payloads (step, performed, refusal.step) and the command pages already use one word for two things and qualify the spec's as spec step. itd-2609212103565953 criterion 5 asks the command page to describe them as one word for one thing, which cannot be written truthfully until someone rules which of the two keeps the word (rename the lane's stages, or change what implement step means) or restates the criterion.
- itd-2609201916151817One verb takes a READY intent to delivered, and refuses while a decision is open
- spc-2609202134341288an-autonomous-implementation-run-paces-itself-by-default-and