"Closes a finished story: verifies each acceptance criterion, checks for design or ADR deviations and updates its status. Use when the user says a story is done, finished or ready to close."
Resources
2Install
npx skillscat add sneakkestrel16/mininginc/story-done Install via the SkillsCat registry.
!bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys review_mode,review_gate,automation,automation_always_ask,workflow,qa.level,gate_level,system_overrides
Resolved above — use as-is; --review overrides review_mode. No block →
defaults in .claude/docs/config-resolution.md.
Ask with the question tool. Without one, list the options numbered and end your turn
to wait. A skipped or dismissed question is not an answer: ask again in plain text.
Story Done
Closes a finished story. Every acceptance criterion is checked against evidence,
deviations from the GDD, the ADRs and the story's own scope are reported as facts,
and the story is marked Complete only on the user's yes.
Writes, after the user's yes: the story file (Status, Last Updated, a## Completion Notes section) and its production/sprint-status.yaml entry;docs/tech-debt-register.md only when the user picks that option. The session
checkpoint is written at the end of every run, whatever the verdict.
Next: the next story (Phase 8).
Asks follow .claude/docs/automation-modes.md (collaborative always asks, guided
asks on major choices, autonomous logs and goes on; automation_always_ask
categories always ask).
Checklist (copy it and tick as you go):
- [ ] Phase 1: story found, facts and settings read
- [ ] Phase 2: what the story is checked against, loaded for its tier
- [ ] Phase 3: each criterion verified, traceability table built
- [ ] Phase 4: test evidence and run result checked
- [ ] Phase 5: deviations and scope checked
- [ ] Phase 6: review gates run, or their skip noted
- [ ] Phase 7: report and verdict shown; close asked
- [ ] Phase 8: next story named, checkpoint written, closing block printedPhase 1: The story and its settings
Which story. The text typed after the skill name, with any --review <mode>
pair removed, is the story path. With nothing typed:
- The checkpoint in
production/session-state/active.md: its Current task
line, when it names a story. - Else the stories in progress:
bash .claude/scripts/story-facts.sh --all, rows
whose state isIN_REVIEWorIN_PROGRESS. Several: ask "Which story are we
closing?" with one option per story. - None: ask for the path. When
production/epics/holds no story file at all,
stop:
"No stories found inproduction/epics/— run/create-stories [epic-slug]to make them (atstandardandfull, run/create-epicsfirst if there is no epic yet)."
Its facts. bash .claude/scripts/story-facts.sh <story-path> gives the status,
type, layer, TR-IDs, ADRs, criteria count, test-evidence status and dependencies.
Then read the story in full: the criteria text, the Test Evidence path, ## Files,
Out of Scope.
Tier. workflow for the story's system, keyed on the GDD filename stem of itsGDD: path (design/gdd/<stem>.md → <stem>; the [system] of its TR-ID only
when there is no GDD path): that system's system_overrides row if there is one,
else the project value.
What qa.level requires (the evidence rows of .claude/docs/coding-standards.md).
Take the value from the qa.level line above, never from workflow or rigor: the
two are set apart, so workflow: minimal with qa.level: standard still requires a
Logic story's unit test.
| Check | qa.level: minimal |
qa.level: standard |
qa.level: full |
|---|---|---|---|
| Logic, Integration test | waived | required | required |
| Config/Data smoke report | waived | required, advisory by default | required, blocking by default |
| Visual/Feel, UI retained screenshot | required | required | required |
| Untested criteria (Phase 3) | never escalate | more than half block | any blocks |
The look is never waived: a Visual/Feel or UI story needs its screenshot at every
level. Gate level per type is the gate_level line above. At full, a
Config/Data default (config=advisory(default…)) becomes blocking; an explicittesting.strict.config: false still makes it advisory.
Phase 2: What the story is checked against
By the tier. Read every document by section, never whole.
full: the current requirement text of each TR-ID: indocs/architecture/tr-registry.yaml, the lines matchingid: <TR-ID>\s*$and the
entry's text below (the anchor keepsTR-combat-001from matchingTR-combat-0010;\s*takes a Windows line ending). Never use text quoted in the
story; the GDD's Acceptance Criteria and Detailed Design
(bash .claude/scripts/md-section.sh extract design/gdd/<file>.md "Acceptance Criteria",
then the same for"Detailed Design"; exit 3: try"Detailed Rules", the design
standard's name for the same section);
each ADR's status withbash .claude/scripts/adr-status.sh <ADR ids>, then its
Decision and Consequences sections.standard: the same GDD sections; the ADR sections only for a critical ADR
(adr-status.sh's layer column reads Foundation, or has no layer).minimal: none. The story's criteria are the spec.
At every tier, when docs/architecture/control-manifest.md exists, note itsManifest Version line.
Phase 3: Verify each criterion
Take each acceptance criterion in turn:
- Checked by looking: a file the criterion names exists; a test file it names
exists (report "test file present", never "test passes": nothing here runs it);
numeric literals in gameplay code that belong in data files; player-facing
strings in the code root that belong in localization files (resolve the root
per.claude/docs/code-root-resolution.md; unresolved, reportNOT ASSESSED — code root unresolved, never zero hits). - Asked: behaviour ("the player takes damage when…"), feel, and performance
criteria. Never mark one passed from reading the code: the code says what should
happen, not what the build does. Up to four per ask: "Does [criterion]?" Options:
Yes — passes / No — fails / Not tested yet.Not tested yetis UNTESTED, and
keeps the verdict at best NOT ASSESSED until someone checks it. - Seen on screen: a criterion about something visible is covered by a retained
image underproduction/qa/evidence/[story-slug]/([story-slug]: the story
file's name without.md) that you opened and saw it in.
Never describe an image you have not opened; a checkpoint'sRun result: OBSERVED — <text>is/dev-story's description, to quote as such. - Needs a full playtest:
DEFERRED — requires playtest session. It does not
block.
Then map each criterion to what covers it: a test under the test root, a
"Yes — passes", or a retained image.
| Criterion | Covered by | Status |
|-----------|------------|--------|
| AC-1: [text] | tests/unit/[system]/[file]::[test] | COVERED |
| AC-2: [text] | production/qa/evidence/[slug]/01-[what].png | COVERED |
| AC-3: [text] | — | UNTESTED |Untested criteria escalate by the Phase 1 table: blocking above the line; below it,
advisory, listed in the Completion Notes as "Untested criteria: [AC-N list]".
Phase 4: Test evidence and the run result
By the story's type, at the Phase 1 gate level. Skip a check qa.level waives, and
say so: Test evidence: waived at qa.level minimal.
- Logic: the exact path in the story's Test Evidence section, else anywhere
undertests/unit/[system]/. - Integration: the same under
tests/integration/[system]/, else a playtest
record naming this story inproduction/qa/playtests/(/playtest-report
writes them there). - UI: a UI story is satisfied by the retained screenshot of each screen touched,
underproduction/qa/evidence/. No evidence doc or sign-off needed. - Visual/Feel: the screenshot, and a Visual/Feel story also needs the sign-off:
production/qa/evidence/[story-slug]-evidence.mdwith every sign-off row[x] Approved(one person may sign every role). - Config/Data: a
production/qa/smoke-*.mdreport; none: "No smoke check
report found. Run/smoke-check." - No Type: advisory: "Story Type not declared. Add
Type:to the story header."
A missing item is a gap at the gate level: BLOCKING stops COMPLETE, ADVISORY goes
in the notes. Name what is missing and where it goes. An evidence doc with no image
beside it is not evidence: a described check is an assertion.
Is the evidence older than its code? For a retained image, runbash .claude/scripts/review-receipts.sh check production/qa/evidence/[story-slug]/stamp.txt.
Each CHANGED: or GONE: file: "[file] changed after the evidence was captured —
re-capture it." RECEIPT: NONE: "no stamp — whether the evidence is older than the
code cannot be told". Report these lines; they never change the verdict.
Run result, every other type. Take the Run result: line from the /dev-story
checkpoint (only when its Current task names this story) or the story's Completion Notes.OBSERVED with a path: note it. N/A — <reason>: accept only a reason that says
why nothing is observable ("it's a Logic story" is not one). NOT VERIFIED on a
story whose criteria name something on screen: a gap at the gate level. No line:
advisory, "confirm the build was launched and looked at". A user's "Yes — passes"
to an on-screen criterion with no retained image is an assertion, not an
observation: a gap at the gate level.
Phase 5: Deviations and scope
Run, by tier (minimal skips 1 and 3):
- GDD rules (
full;standardon its required sections): search the changed
files for the names the current GDD text and TR requirement use. - Manifest: the story's
Manifest Versionolder than the manifest's: ADVISORY,
"written against manifest v[story]; current is v[current] — run/story-readinessto check". No manifest: skip. AManifest-Note:line in the
story is carried into the deviations as written. - ADR constraints (
full;standardfor a critical ADR): search for the
patterns the ADR's Decision or the manifest forbids. - Hardcoded values in the changed files.
- Scope: the files the story lists under
## Filesagainst the code and test
files changed (git status --porcelain). A changed file the list does not name
is OUT OF SCOPE. A story with no## Filessection: use the checkpoint's
Files in progress when its Current task names this story; else reportScope: NOT ASSESSED — the story lists no files. A clean working tree: reportScope: not checked — no uncommitted changes to compare.
Each deviation is BLOCKING (contradicts the GDD or ADR), ADVISORY (drifts
but works the same; the user decides) or OUT OF SCOPE (for awareness). State
them as facts; the user judges them.
Phase 6: Review gates
Read the review_gate line above.
skill-gates=skip: no agent. NoteQL-TEST-COVERAGE skipped — [Solo | Lean] modeandLP-CODE-REVIEW skipped — [Solo | Lean] mode. Inleanmode, ask: "Did
you run/code-reviewon the implemented files?" Options: Yes — it passed or was
approved with suggestions / No — skipping review for this story / No — I'll run
it before the sprint close-out. The answer sets Reviewed by.skill-gates=run: readreferences/review-gates.mdand.claude/docs/director-gates.md, and run both gates now. On a skip, do not load
it.
Reviewed by is never blank: lead-programmer when LP-CODE-REVIEW ran;/code-review (you said you ran it; not verified here) for the lean Yes; self, no independent review in solo mode, for either No, and when no implementation file
exists yet.
Phase 7: Report, verdict, and the close
## Story Done: [title]
**Story**: [path] · **Type**: [type] · **Date**: [today]
### Acceptance Criteria: [X/Y passing]
- [x] [criterion] — [how verified]
- [ ] [criterion] — FAILS: [reason]
- [?] [criterion] — DEFERRED: requires playtest
### Traceability
[the Phase 3 table]
### Test Evidence
**Required**: [what the type needs at this qa.level, or "waived at qa.level minimal"]
**Found**: [YES — path | NO — BLOCKING | NO — ADVISORY]
### Deviations
[NONE, or each: BLOCKING / ADVISORY / OUT OF SCOPE — description — reference]
### Review
**Reviewed by**: [value]
### Verdict: [COMPLETE | COMPLETE WITH NOTES | NOT ASSESSED | BLOCKED]Verdicts, the first that matches wins:
- BLOCKED: a criterion fails, or a BLOCKING gap or deviation stands.
- NOT ASSESSED: a criterion could not be evaluated: it names no observable
outcome, the user answered "Not tested yet", a review gate returned NOT ASSESSED
and its input was not supplied, evidence exists but cannot be read, or the GDD
or ADR a deviation would be judged against is missing. Name each one and what
would settle it. It outranks the two passes and never hides a failure. - COMPLETE WITH NOTES: every criterion passes or is DEFERRED, with advisory
items listed. Information lines are not advisory items: the evidence-stamp
lines, an absent sprint file and the run result never turn COMPLETE into COMPLETE
WITH NOTES. - COMPLETE: every criterion passes, nothing advisory.
Then ask, before writing anything: "How do you want to proceed?" Options:
Close the story — mark it Complete and log notes (Recommended) / Close and log the
advisory deviations as tech debt / Don't close yet — I'll fix things first / Close
anyway, accepting the deviations. On BLOCKED or NOT ASSESSED, recommend "Don't close
yet" and list what must change. Closing such a story is a scope_changes decision:
when the automation_always_ask line lists it, ask in every automation mode, even
when the user's own request is what got here. Write only on an explicit choice to
close.
On close:
bash .claude/scripts/md-section.sh set-field <story> Status Complete, thenset-field <story> "Last Updated" <YYYY-MM-DD> --after Status.- Add at the end of the story, with a file edit, never a shell command (a shell
write skips the project's write checks):## Completion Notes **Completed**: [date] **Criteria**: [X/Y passing] ([deferred items]) **Deviations**: [None, or the advisory ones] **Test Evidence**: [path, or "waived at qa.level minimal", or "none required"] **Reviewed by**: [value] - "Close and log as tech debt": read
references/tech-debt-row.mdand add one
row per advisory deviation. production/sprint-status.yaml, when it exists: this story's entry getsstatus: doneandcompleted: [date], and the top-levelupdatedgets today.
The close answer covers it.- Print a suggested commit:
git add [the changed code and test files] [story path]
andgit commit -m "feat: [story title] ([TR-ID])".
On "Don't close yet": change no story file. List what the user flagged. Never
fix a failing criterion yourself: report it and ask what to do.
Phase 8: Next story, checkpoint, close
The next story. With no sprint plan in production/sprints/ (always atworkflow: minimal): Run bash .claude/scripts/story-status.sh after the close, so
this story's new status is in it. It prints the unfinished stories in route order;
do not re-rank them. The first In Review story is next (the first IN_REVIEW
line), else the first In Progress one, else the first Ready or Not Started
one (TODO):
### Next Up
**[Story NNN: title]** — [one line]
Run `/story-done [path]` to close it (In Review) — else `/dev-story [path]` to implement it.When the workflow line above reads minimal, print no /story-readiness line at
all, not even as an option: it is not on that path. With no sprint plan atworkflow: standard or full, add "Run /story-readiness [path] first."
- Only
COMPLETE N of N: every story is built. Offer: play the build and note what
feels wrong; add stories from the brief with/create-stories; or/settingsto
raisemodes.rigorif the game has outgrown its brief. - Only
BLOCKED,OTHERorNO_STATUSlines left: there is no Next Up, and the
build order is not done. Name each story with its blocker,Draftorno status. - Never print the Sprint Close-Out Sequence on this branch: there is no sprint.
With a sprint plan: read references/sprint-next.md.
The checkpoint, on every verdict, closed or not. Pipe the block tobash .claude/scripts/session-state.sh checkpoint, which replaces the old block:
**Updated:** [date]
**Branch:** `[current git branch]`
**Current task:** /story-done — [story path]: [verdict], [closed | left open]
**Next step:** [the Next Up command, or the fix the verdict named]
**Blocked on:** [nothing, or what blocked the verdict]
**Files in progress:** none
**Open questions:** [tech debt logged: N items, or none]The run's last reply ends with this block (repeat it if you showed it earlier):
Verdict: [COMPLETE | COMPLETE WITH NOTES | NOT ASSESSED | BLOCKED] — [story path]
Story: [closed — Status: Complete | left open — Status: [status]]
Review: [Reviewed by value; the gates' skip notes]
Next step: [/dev-story [path] | /story-done [path] | the fix | play the build]