`project.yaml` at the repo root is now the single source of truth for a project's configuration, replacing `production/stage.txt`, `production/review-mode.txt` and `.claude/docs/technical-preferences.md` (all three still read as a fallback; nothing is force-deleted). **`modes.rigor` — one question instead of six.** `minimal`, `standard` or `full` fronts six knobs: `modes.workflow`, `docs.density`, `qa.level`, `modes.story_granularity`, `modes.review_mode` and `team.size`. It defaults to `minimal`, which is a change from 1.0's behaviour: the heavier tier was measured costing several times more to reach working code without producing a better result, and returning nothing when a fresh developer inherited the project. Pin `modes.rigor: standard` to keep 1.0's process level. Also in this release: - `/settings` to view or change any setting, and `project.local.yaml` for per-developer preferences that should not be committed. - `system_overrides` to hold one system to a higher standard than the rest of the project, and `testing.strict` to set per test type whether missing evidence blocks a story or warns. - A story that changes anything the player sees is not closed until the game has been launched, observed, and a screenshot retained in `production/qa/evidence/`. A parse check is not a run. This holds at every rigor level, including `minimal`, where automated tests are waived but the look is not. - The code root is engine-specific and enforced as such: Godot `src/`, Unity `Assets/`, Unreal `Source/<Module>/`. Two of the three will not build a project laid out any other way. - Migration tooling for existing projects: `.claude/scripts/migrate-v1-config.sh` converts a 1.0 layout, non-destructively by default, with a report to review before `--finalize` deletes anything. - Ask-before-write holds regardless of personal automation settings. Upgrading from 1.0 or earlier: see UPGRADING.md. Full list of changes: CHANGELOG.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016xvzG3i7pWQg4LjyDwWMXd
9.4 KiB
/story-done — Handoff Contract
Role in Pipeline
Closes the implementation loop for a single story by verifying every acceptance criterion, checking test evidence, detecting GDD/ADR deviations, and — after user approval — updating the story file to Status: Complete with a ## Completion Notes section.
Inputs Required
Files That Must Exist
| File | Required Fields / Sections | Read-Only? |
|---|---|---|
production/epics/**/*.md (the story file) |
Status: (expected: In Progress, or Ready if /dev-story was skipped — /dev-story sets In Progress, and /story-done is the only skill that writes Status: Complete), Type:, Manifest Version, TR-ID(s), ADR reference(s), ## Acceptance Criteria, list of files to create/modify, ## Test Evidence path |
No — status and completion notes written after approval |
docs/architecture/tr-registry.yaml |
Entry per TR-ID with current requirement text |
Yes |
| GDD section referenced by each TR-ID | Acceptance criteria and key rules for cross-check | Yes |
docs/architecture/adr-NNNN-[slug].md (referenced ADR) |
## Decision, ## Consequences |
Yes |
docs/architecture/control-manifest.md |
Manifest Version: header date, forbidden patterns |
Yes (existence checked; absent = skip staleness check) |
production/session-state/active.md |
Active story path (used when no argument given) | No — session extract appended |
Test Evidence Files (presence checked, not pre-required to exist — absence triggers gate)
| Story Type | Expected Location |
|---|---|
| Logic | tests/unit/[system]/[story-slug]_test.[ext] |
| Integration | tests/integration/[system]/[story-slug]_test.[ext] OR production/session-logs/ playtest record |
| Visual/Feel | production/qa/evidence/[story-slug]-evidence.md + a retained screenshot |
| UI | production/qa/evidence/[story-slug]-evidence.md + a retained screenshot of each screen touched |
| Config/Data | production/qa/smoke-*.md |
Preconditions
- The story file must be findable either by argument path, in
production/session-state/active.md, or in the current sprint file asIN PROGRESS - Implementation must have been attempted (source files listed in the story's "files to create/modify" should exist) — this skill does not implement; it verifies
- For Logic and Integration stories, the test file at the
## Test Evidencepath must exist before a COMPLETE verdict is possible — unlesstesting.strictinproject.yamlsets that type to advisory (testing.strict.logic/.integration: false), in which case a missing test is recorded as a warning but does not block - For Visual/Feel and UI stories, a retained screenshot and an evidence doc must exist under
production/qa/evidence/before a COMPLETE verdict is possible — unlesstesting.strict.visual/.uiis set tofalse, in which case the gap is recorded as a warning but does not block - This skill does not execute the test. Phase 3 checks existence with
Glob; nothing runs. A test that exists and FAILS satisfies the gate, so a failing test cannot block a COMPLETE verdict here — this gate is existence, not "exist and pass". Pass/fail is established by/gate-checkand/smoke-check, both of which run a suite and both of which come after story closure. See the note under Phase 3 ofSKILL.md.
Verdicts Emitted
COMPLETE / COMPLETE WITH NOTES / NOT ASSESSED / BLOCKED.
NOT ASSESSED outranks COMPLETE — one or more acceptance criteria could not
be evaluated at all, which is not the same as evaluating them and finding them
met. Precedence is BLOCKED, then NOT ASSESSED, then COMPLETE WITH NOTES,
then COMPLETE; see the verdict section of SKILL.md. This contract listed no
verdict set at all, so a reader had nothing to branch on.
Outputs Produced
Files Written
| File | Guaranteed Fields / Sections | Notes |
|---|---|---|
production/epics/**/*.md (the story file) |
Status: Complete, ## Completion Notes block (date, criteria count, deviations, test evidence path, code review status) |
updated after explicit user approval |
production/sprint-status.yaml |
status: done, completed: [date], top-level updated field |
updated silently alongside story file if file exists |
docs/tech-debt-register.md |
Advisory deviation entries (if user confirms) | appended if advisory deviations exist and user agrees |
production/session-state/active.md |
## Session Extract — /story-done [date] block: verdict, story path, tech debt count, next recommended story |
appended (created if absent) |
Output Guarantees
Status: Completeis written only when verdict is COMPLETE or COMPLETE WITH NOTES and the user explicitly approves## Completion Notesalways contains: completion date, criteria pass count, deviation summary, test evidence path (or "None required"), code review status- Session state always records the final verdict and the next recommended story path
Immutability Rules
- READS but does NOT modify:
docs/architecture/tr-registry.yaml,docs/architecture/adr-NNNN-[slug].md(Decision + Consequences only), GDD sections,docs/architecture/control-manifest.md, source files insrc/(Grep only), test files intests/(run via Bash; not edited) - MODIFIES: the story
.mdfile (status + completion notes),production/sprint-status.yaml(if exists),production/session-state/active.md(append),docs/tech-debt-register.md(append, only with user approval) - Does NOT write to the code root or
tests/under any circumstances
Hard Constraints (Never Violate)
- Never sets
Status: Completewithout explicit user approval ("May I update the story file?") - Never marks a Logic story Complete on a missing unit test when its resolved gate level is BLOCKING — the level is BLOCKING by default and whenever
testing.strict.logicistrue; it is ADVISORY only whentesting.strict.logicis explicitlyfalse - Never marks an Integration story Complete on missing evidence (integration test file or playtest session log) when its resolved gate level is BLOCKING — BLOCKING by default and under
testing.strict.integration: true; ADVISORY only under an explicitfalse - Never marks a Visual/Feel or UI story Complete on a missing retained screenshot in
production/qa/evidence/when its resolved gate level is BLOCKING — BLOCKING by default and undertesting.strict.visual/.ui: true; ADVISORY only under an explicitfalse. A written description of a visual check is not a substitute for the image - Never auto-fixes failing acceptance criteria — report failures and ask the user what to do
- Never proceeds to Phase 7 (file update) when the verdict is BLOCKED — list blockers and offer help resolving them
- Never silently overrides a BLOCKED verdict — if the user insists on advancing despite blockers, document the override risk explicitly in
## Completion Notes
Downstream Skill Expects
Next skill: /gate-check (Production → Polish gate, or end-of-sprint review)
- It will read: story files in
production/epics/checkingStatus: Completeand presence of## Completion Notes - It will read:
tests/unit/andtests/integration/for test file presence and will run the test suite via Bash - It assumes: every Complete Logic story whose
testing.strict.logicgate resolved to BLOCKING (the default) has a corresponding test file that exists; under an explicittesting.strict.logic: falsea Logic story may be Complete with the test gap documented in## Completion NotesExistence, not passing.
/story-donechecks that the test file exists withGloband runs nothing, so a Complete Logic story may carry a test that fails./gate-checkrunning the suite is the FIRST point at which pass/fail is established, so it must never treat a Complete status as evidence the tests passed — it has to run them. That is also why an unconfigured test runner isNOT ASSESSEDthere rather than a silent skip: with no run, nothing upstream has verified the story either. - It assumes: Visual/Feel and UI stories that are Complete have both an evidence doc and a retained screenshot in
production/qa/evidence/— that gate is BLOCKING by default; only under an explicittesting.strict.visual/.ui: falsemay such a story be Complete with the deviation documented in## Completion Notes - It will read:
production/sprint-status.yamlforstatus: doneentries if that file exists
Known Fragile Points
- The story's
## Test Evidencesection must contain the exact file path written by/dev-story; a path mismatch causes a false BLOCKING result even if the test file exists under a slightly different name - If
Type:is absent from the story header, test evidence gate enforcement is ADVISORY only — stories can slip through without tests - Manifest version staleness check is skipped if
docs/architecture/control-manifest.mddoes not exist; the check being skipped is noted in the report but is non-blocking production/sprint-status.yamlupdate is silent (no separate approval); if that file uses a different key structure than expected, the update silently fails and sprint tracking becomes stale- The traceability table escalation rule (>50% UNTESTED = BLOCKING) can be triggered by deferred Visual/Feel criteria that are legitimately not automatable — ensure deferred criteria are explicitly marked
DEFERRED(not left as unchecked) to avoid false escalation