Skip to Content
Story state machine

Story state machine

A user story moves through a small set of well-defined states. The exact path depends on the team’s profile — specifically whether peer_pr_review.required is on.

The states

StatusMeaning
backlogExists in the Product Backlog but not yet ready. discipline is typically still empty at this point.
readyPasses the Definition of Ready — including a discipline assignment from the Tech Lead; can be pulled into a sprint.
in-progressAssigned and being implemented (/conclave-dev).
reviewPR open, awaiting QA verification.
verifiedQA passed acceptance criteria; awaiting Tech Lead PR approval. Used only when peer_pr_review.required: true.
doneAll gates passed, DoD met, PR mergeable.
retired (v0.8.0+)Parallel terminal state to done. Entered via /conclave-story retire or /conclave-story split (on the parent). Excluded from every command’s story collection.

Transitions

backlog → ready → in-progress → review → [verified] → done retired (parallel terminal — via /conclave-story)

The retired terminal state (v0.8.0+)

A story with status: retired is out of every command’s scope — /conclave-planning, /conclave-dev, /conclave-qa, /conclave-pr-review, and /conclave-sprint all skip it. Only /conclave-spec is exempt (it authors new stories rather than collecting existing ones).

There are two ways in:

  1. /conclave-story retire US-NNN — explicit retirement. A retirement_reason frontmatter field is populated with the user’s reason; retired_at is set to today. No LLM call — this is a mechanical policy decision.
  2. /conclave-story split US-NNN — decomposition. The parent story becomes retired with superseded_by: [US-CHILD_1, ...] and retirement_reason: "Split into ...". The children carry split_from: US-NNN.

There is no un-retire command. If a team changes their mind, they hand-edit the frontmatter — git preserves the audit trail.

Refusal cases:

  • /conclave-story retire refuses stories past ready (in-progress / review / verified / done) — retiring active or shipped work would be dishonest.
  • /conclave-story split refuses the same, plus refuses if the PM subagent’s scenario-coverage rule cannot be satisfied under the requested axis (a SPLIT_UNSAFE: line names the offending scenario; no files are written).

When peer_pr_review.required: true (full-scrum default)

review ──/conclave-qa──→ verified ──/conclave-pr-review──→ done ↘ ↗ blocked → back to review for fixes

QA passes → status: verified, posts a PR comment with the verdict. The Tech Lead runs /conclave-pr-review, reviews the diff against the architecture and ADRs, then runs gh pr review --approve. On approve → status: done.

When peer_pr_review.required: false (lean default)

review ──/conclave-qa──→ done blocked → back to review for fixes

QA passes → status: done directly. No separate Tech Lead gate. QA is the merge signal.

UAT: a verdict distinction, not a new status (v0.3.0+)

When conclave/team/testing-environments.md is configured, /conclave-qa generates CI-runnable UAT tests from the story’s Gherkin scenarios (Playwright for frontend/multi, the shared Postman/Newman collection for backend/multi, a manual checklist for mobile), pushes them, and waits for the target repo’s own CI to run them — it never executes them itself. This doesn’t add a new story-frontmatter status value; it adds a third verdict, alongside passed and blocked:

review ──/conclave-qa──→ pending_uat (stays review, "## QA pending") review ──/conclave-qa──→ blocked (stays review, "## QA blockers" — CI failed or timed out) review ──/conclave-qa──→ passed → verified/done as above
  • pending_uat — only reachable for mobile stories, whose checklist has just been generated or is still incomplete. The story stays review, but the appended section is ## QA pending, not ## QA blockers — nothing has actually failed, a human just hasn’t finished yet. Re-run /conclave-qa once the checklist records an Overall result.
  • blocked via UAT — a CI run on the generated Playwright/Newman tests fails, or no run is found / the wait times out (ceremonies.qa_verification.ci_wait_timeout_minutes, default 20). Both are treated exactly like a failing Gherkin scenario — never silently passed.
  • Not configured yet — a missing or all-TBD testing-environments.md degrades gracefully: /conclave-qa skips UAT entirely and verifies acceptance criteria exactly as it did before this file existed.

Bugs reuse this exact state machine (v0.10.0+)

A BUG-NNN reported via /conclave-bug report is written directly in status: ready — no new state, no new transition table. It never passes through backlog or Sprint Planning (/conclave-planning and /conclave-sprint never look inside conclave/product/bugs/), and from ready it follows the identical path a story does: /conclave-dev BUG-NNN/conclave-qa BUG-NNN/conclave-pr-review BUG-NNN (if peer_pr_review.required: true). US-NNN and BUG-NNN IDs can be mixed in the same /conclave-dev//conclave-qa invocation — the ID prefix is all that disambiguates which directory a given ID resolves against. retired is available as a manual escape hatch for a mis-filed bug (hand-edit the frontmatter — there’s no /conclave-bug retire sub-action yet).

When discipline gets assigned

Unlike assignee (set at planning time), discipline follows a specific sequence inside /conclave-planning:

  1. Wave 1 — the Tech Lead reviews each story’s feasibility and assigns a discipline value (frontend | backend | qa | design | devops | mobile | multi) in the same pass, in parallel with the Product Manager’s scope review.
  2. DoR validation — a story with no discipline fails the Definition of Ready and cannot enter the sprint, in either lean or full-scrum.
  3. Wave 2 — the Scrum Master assigns each story to a roster member whose Discipline matches (or who holds Tech Lead, for cross-cutting stories), using the value from Wave 1.
  4. If no roster member matches a story’s discipline, the orchestrator surfaces a coverage-gap question to the human directly — the Scrum Master subagent never guesses an assignee.

Failure handling

A failure in either gate drops the story back to review. The dev fixes the issue, pushes new commits, and the gate(s) re-run:

  • QA found criteria failing (Gherkin, DoD, or the generated UAT tests’ CI run) → story stays review with a ## QA blockers section added to the story file, including a log excerpt + CI run URL when the failure came from UAT. Fix → push → re-run /conclave-qa.
  • TL found code blockers → story moves back to review with a ## TL findings section. Fix → push → re-run /conclave-qa (criteria may have shifted) → /conclave-pr-review.

A single blocker is enough to keep the story out of done. No “approve with notes” when a blocker exists.

Audit trail

Every transition is committed to git. The verification report on acceptance/AC-US-NNN.md is append-only — each /conclave-qa run adds a new ## Verification — <date> section, never deletes prior runs. The same applies to the TL’s findings.

You can reconstruct the complete history of any story with:

git log -- conclave/sprints/SPRINT-NNN/stories/US-NNN-*.md
Last updated on