mirror of
https://github.com/Donchitos/Claude-Code-Game-Studios.git
synced 2026-10-16 09:58:36 +00:00
Release 1.1.0 — one config file, and a process weight you choose
`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
This commit is contained in:
co-authored by
Claude Opus 5
parent
984023ddac
commit
d05699707f
@@ -0,0 +1,86 @@
|
||||
# /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 as `IN 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 Evidence` path must **exist** before a COMPLETE verdict is possible — unless `testing.strict` in `project.yaml` sets 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 — unless `testing.strict.visual`/`.ui` is set to `false`, 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-check` and `/smoke-check`, both of which run a suite and both of which come after story closure. See the note under Phase 3 of `SKILL.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: Complete` is written only when verdict is COMPLETE or COMPLETE WITH NOTES and the user explicitly approves
|
||||
- `## Completion Notes` always 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 in `src/` (Grep only), test files in `tests/` (run via Bash; not edited)
|
||||
- MODIFIES: the story `.md` file (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: Complete` without 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.logic` is `true`; it is ADVISORY only when `testing.strict.logic` is explicitly `false`
|
||||
- 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 explicit `false`
|
||||
- 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 under `testing.strict.visual`/`.ui: true`; ADVISORY only under an explicit `false`. 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/` checking `Status: Complete` and presence of `## Completion Notes`
|
||||
- It will read: `tests/unit/` and `tests/integration/` for test file presence and will run the test suite via Bash
|
||||
- It assumes: every Complete Logic story whose `testing.strict.logic` gate resolved to BLOCKING (the default) has a corresponding test file that **exists**; under an explicit `testing.strict.logic: false` a Logic story may be Complete with the test gap documented in `## Completion Notes`
|
||||
> **Existence, not passing.** `/story-done` checks that the test file exists with `Glob` and runs nothing, so a Complete Logic story may carry a test that fails. `/gate-check` running 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 is `NOT ASSESSED` there 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 explicit `testing.strict.visual`/`.ui: false` may such a story be Complete with the deviation documented in `## Completion Notes`
|
||||
- It will read: `production/sprint-status.yaml` for `status: done` entries if that file exists
|
||||
|
||||
## Known Fragile Points
|
||||
- The story's `## Test Evidence` section 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.md` does not exist; the check being skipped is noted in the report but is non-blocking
|
||||
- `production/sprint-status.yaml` update 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
|
||||
@@ -1,12 +1,19 @@
|
||||
---
|
||||
name: story-done
|
||||
description: "End-of-story completion review. Reads the story file, verifies each acceptance criterion against the implementation, checks for GDD/ADR deviations, prompts code review, updates story status to Complete, and surfaces the next ready story from the sprint."
|
||||
description: "End-of-story completion review — verifies each acceptance criterion, checks GDD/ADR deviations, prompts code review, updates status."
|
||||
argument-hint: "[story-file-path] [--review full|lean|solo]"
|
||||
user-invocable: true
|
||||
allowed-tools: Read, Glob, Grep, Bash, Write, Edit, AskUserQuestion, Task
|
||||
disable-model-invocation: true
|
||||
allowed-tools: Read, Glob, Grep, Bash, Write, Edit, AskUserQuestion, Agent
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
!`source "${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/yaml-helper.sh" 2>/dev/null && resolve_config --keys review_mode,automation,workflow,story_granularity,qa.level,testing.strict,system_overrides`
|
||||
|
||||
Resolved above — use as-is; `--review` overrides `review_mode`. No block →
|
||||
defaults in `.claude/docs/config-resolution.md`.
|
||||
|
||||
|
||||
# Story Done
|
||||
|
||||
This skill closes the loop between design and implementation. Run it at the end
|
||||
@@ -21,12 +28,37 @@ forgotten, and the story file reflects actual completion status.
|
||||
|
||||
## Phase 1: Find the Story
|
||||
|
||||
Resolve the review mode (once, store for all gate spawns this run):
|
||||
1. If `--review [full|lean|solo]` was passed → use that
|
||||
2. Else read `production/review-mode.txt` → use that value
|
||||
3. Else → default to `lean`
|
||||
|
||||
See `.claude/docs/director-gates.md` for the full check pattern.
|
||||
See `.claude/docs/director-gates.md` for the full check pattern. Individual gate definitions live in `.claude/docs/director-gates/[gate-id].md` — the spawned agent reads its own gate file; do not read it in the parent session.
|
||||
|
||||
|
||||
Every `AskUserQuestion` call follows `.claude/docs/automation-modes.md`
|
||||
(collaborative asks always · guided major-only · autonomous logs and proceeds;
|
||||
`automation_always_ask` categories always prompt).
|
||||
|
||||
**Workflow tier**: resolved per the story's system (per
|
||||
`.claude/docs/workflow-modes.md`) — **the GDD filename stem** of the story's
|
||||
`GDD:` path (`design/gdd/<stem>.md` → `<stem>`), with the `[system]` segment of
|
||||
its `TR-[system]-NNN` ID accepted only as a fallback alias: use the
|
||||
`system_overrides` row for that system if the block lists one, else the
|
||||
project value. It governs which Phase 4 deviation checks run — see Phase 4.
|
||||
|
||||
**Workflow companion — `modes.story_granularity`** (resolved above — supplied by
|
||||
`modes.rigor` unless set explicitly): cadence expectation only — story-done fires **every 3–5 days** at
|
||||
`coarse`, **every 1–2 days** at `balanced`, **multiple times/day** at `fine`. It
|
||||
does not change any completion check.
|
||||
|
||||
**`qa.level`**: controls whether test *evidence is required*, where
|
||||
`testing.strict` controls whether a failure blocks and `workflow` controls which
|
||||
docs exist. `modes.rigor` sets `qa.level` and `workflow` together; set either
|
||||
explicitly to vary it alone. `testing.strict` is not fronted by `rigor` at all.
|
||||
At `minimal`, no evidence is required → skip the Test Evidence
|
||||
Requirement check (Phase 3), the >50%-untested traceability escalation, and the
|
||||
Phase 4b QA gate entirely; the acceptance-criteria verification still runs. At
|
||||
`standard`, the story's own type requires evidence; at `full`, every type does.
|
||||
`testing.strict` then decides whether present-but-failing evidence blocks.
|
||||
(`rigor: minimal` sets both; `qa.level: minimal` on its own leaves the workflow
|
||||
tier where it was.)
|
||||
|
||||
**If a file path is provided** (e.g., `/story-done production/epics/core/story-damage-calculator.md`):
|
||||
read that file directly.
|
||||
@@ -59,13 +91,19 @@ Read the full story file. Extract and hold in context:
|
||||
- **Estimated vs actual scope** — if an estimate was noted
|
||||
|
||||
Also read:
|
||||
- `docs/architecture/tr-registry.yaml` — look up each TR-ID in the story.
|
||||
Read the *current* `requirement` text from the registry entry. This is the
|
||||
source of truth for what the GDD required — do not use any requirement text
|
||||
that may be quoted inline in the story (it may be stale).
|
||||
- `docs/architecture/tr-registry.yaml` — grep the story's TR-IDs
|
||||
(`Grep pattern="id: <each TR-ID>" path="docs/architecture/tr-registry.yaml" output_mode="content" -A 6`),
|
||||
not a full read of the registry. Read the *current* `requirement` text from each
|
||||
matched entry. This is the source of truth for what the GDD required — do not use any
|
||||
requirement text that may be quoted inline in the story (it may be stale).
|
||||
- The referenced GDD section — just the acceptance criteria and key rules, not
|
||||
the full document. Use this to cross-check the registry text is still accurate.
|
||||
- The referenced ADR(s) — just the Decision and Consequences sections
|
||||
- The referenced ADR(s) — **just the `## Decision` and `## Consequences`
|
||||
sections, never an unbounded full read.** Map headings first
|
||||
(`Grep pattern="^## " path="docs/architecture/[adr-file].md" output_mode="content" -n`),
|
||||
then bounded-`Read` only those two spans. This is the exact same content
|
||||
Phase 4 item 3's ADR constraints check needs — hold it here, do not
|
||||
re-read it there.
|
||||
- `docs/architecture/control-manifest.md` header — extract the current
|
||||
`Manifest Version:` date (used in Phase 4 staleness check)
|
||||
|
||||
@@ -82,7 +120,7 @@ three methods:
|
||||
- **Test pass check**: if a test file path is mentioned, run it via `Bash`.
|
||||
- **No hardcoded values check**: `Grep` for numeric literals in gameplay code
|
||||
paths that should be in config files.
|
||||
- **No hardcoded strings check**: `Grep` for player-facing strings in `src/`
|
||||
- **No hardcoded strings check**: `Grep` for player-facing strings in the **code root** (resolve per `.claude/docs/code-root-resolution.md`). **If the code root is unresolved, report `NOT ASSESSED — code root unresolved` rather than zero hits.**
|
||||
that should be in localization files.
|
||||
- **Dependency check**: if a criterion says "depends on X", check that X exists.
|
||||
|
||||
@@ -118,6 +156,12 @@ For each acceptance criterion in the story:
|
||||
- **Integration test**: check `tests/integration/` similarly
|
||||
- **Manual confirmation**: if the criterion was verified via `AskUserQuestion`
|
||||
above with a "Yes — passes" answer, count that as a manual test
|
||||
- **Retained screenshot**: if the criterion names something on screen and a
|
||||
retained image under `production/qa/evidence/[story-slug]/` shows it (the
|
||||
`Run result: OBSERVED` from `/dev-story` Phase 6 step 4), count that as
|
||||
covered — put the image path in the Test column. A visual criterion
|
||||
verified by looking is not UNTESTED; without this row every UI story
|
||||
reads as >50% untested and false-escalates.
|
||||
|
||||
2. Produce a traceability table:
|
||||
|
||||
@@ -126,10 +170,12 @@ For each acceptance criterion in the story:
|
||||
|-----------|------|--------|
|
||||
| AC-1: [criterion text] | tests/unit/test_foo.gd::test_bar | COVERED |
|
||||
| AC-2: [criterion text] | Manual playtest confirmation | COVERED |
|
||||
| AC-3: [criterion text] | — | UNTESTED |
|
||||
| AC-3: [criterion text] | production/qa/evidence/[slug]/01-shop-open.png | COVERED |
|
||||
| AC-4: [criterion text] | — | UNTESTED |
|
||||
```
|
||||
|
||||
3. Apply these escalation rules:
|
||||
3. Apply these escalation rules (skip entirely at `qa.level: minimal` — no
|
||||
evidence is required, so untested criteria never escalate):
|
||||
|
||||
- If **>50% of criteria are UNTESTED**: escalate to **BLOCKING** — test
|
||||
coverage is insufficient to confirm the story is actually done. The verdict
|
||||
@@ -144,38 +190,118 @@ For each acceptance criterion in the story:
|
||||
|
||||
### Test Evidence Requirement
|
||||
|
||||
Based on the Story Type extracted in Phase 2, check for required evidence:
|
||||
**First apply `qa.level` (resolved in Phase 1).** At `minimal`, no evidence is
|
||||
required — skip this entire subsection (no gate from test evidence; the verdict
|
||||
rests on acceptance-criteria verification alone). At `standard`, require evidence
|
||||
for the story's own type. At `full`, require evidence for every story type. Only
|
||||
when evidence is required does the `testing.strict` resolution below apply.
|
||||
|
||||
| Story Type | Required Evidence | Gate Level |
|
||||
Based on the Story Type extracted in Phase 2, check for required evidence.
|
||||
|
||||
**Resolve the gate level for this story's type.** A gate level is either
|
||||
BLOCKING (a gap prevents the COMPLETE verdict in Phase 6) or ADVISORY (a gap is
|
||||
noted in the Completion Notes but does not block). Resolve it from the
|
||||
`testing.strict` block **already resolved in the resolved-config block at the top of this skill** — not by reading
|
||||
`project.yaml` yourself:
|
||||
|
||||
1. Map the Story Type to a `testing.strict` key — Logic→`logic`,
|
||||
Integration→`integration`, Visual/Feel→`visual`, UI→`ui`, Config/Data→`config`.
|
||||
Take `testing.strict.<key>` from that resolved block. If its value is `true`
|
||||
(case-insensitive) → BLOCKING; if `false` → ADVISORY; `unset` → fall through.
|
||||
2. Else read `testing.strict` as a plain boolean (legacy single-value form). If
|
||||
its value is `true` → BLOCKING or `false` → ADVISORY, it applies to every type.
|
||||
3. Else use the default in the table below.
|
||||
|
||||
> **Use that resolved block, never `project.yaml` directly.** `testing.strict.*` is
|
||||
> on the `/settings --local` whitelist, so a developer can set
|
||||
> `testing.strict.logic=false` in `project.local.yaml` for fast WIP commits —
|
||||
> `effects-map.md` specifies exactly this ("stricter dev's local `/story-done`
|
||||
> blocks earlier"). Reading `project.yaml` alone silently ignores that file: the
|
||||
> setting is accepted, displayed by `/settings`, and has no effect. The
|
||||
> `resolve_config` block at the top of this skill already merges local over base.
|
||||
|
||||
Only `true` and `false` (case-insensitive) are recognized at steps 1–2. A key
|
||||
that is present but holds any other value — `maybe`, `1`, `yes`, etc. — is
|
||||
treated as unset: continue to the next step, and surface the unrecognized value
|
||||
to the user.
|
||||
|
||||
| Story Type | Required Evidence | Default Gate Level |
|
||||
|---|---|---|
|
||||
| **Logic** | Automated unit test in `tests/unit/[system]/` — must exist and pass | BLOCKING |
|
||||
| **Logic** | Automated unit test in `tests/unit/[system]/` — must exist and pass (this skill verifies **existence**; see the note below Phase 3) | BLOCKING |
|
||||
| **Integration** | Integration test in `tests/integration/[system]/` OR playtest doc | BLOCKING |
|
||||
| **Visual/Feel** | Screenshot + sign-off in `production/qa/evidence/` | ADVISORY |
|
||||
| **UI** | Manual walkthrough doc OR interaction test in `production/qa/evidence/` | ADVISORY |
|
||||
| **Visual/Feel** | Retained screenshot + sign-off in `production/qa/evidence/` | BLOCKING |
|
||||
| **UI** | Retained screenshot of each screen touched, in `production/qa/evidence/` | BLOCKING |
|
||||
| **Config/Data** | Smoke check pass report in `production/qa/smoke-*.md` | ADVISORY |
|
||||
|
||||
The **Default Gate Level** column applies when `testing.strict` is unset (the
|
||||
common case). When `testing.strict` is configured, the resolved value from
|
||||
steps 1–2 overrides it. Visual/Feel and UI default to BLOCKING because for a
|
||||
game the rendered result is the product; set `testing.strict.visual` or
|
||||
`testing.strict.ui` to `false` for an advisory gate.
|
||||
|
||||
> **Exception — `/smoke-check`.** The ADVISORY default for **Config/Data** above
|
||||
> governs *per-story evidence* gates, which is what this skill checks.
|
||||
> `/smoke-check` is a build-health gate, not a per-story evidence gate, so its own
|
||||
> unset default for `testing.strict.config` is **BLOCKING** — see
|
||||
> `.claude/skills/smoke-check/SKILL.md` § "Resolve the gate enforcement level".
|
||||
> The divergence is intentional; do not "fix" either side to match the other.
|
||||
|
||||
> **This phase checks that evidence EXISTS. It does not run anything.** The
|
||||
> `Default Gate Level` table above, and `.claude/docs/coding-standards.md`, both
|
||||
> say a Logic story's test "must exist **and pass**". The checks below establish
|
||||
> only the first half — every one of them is a `Glob` or a `Grep`. A unit test
|
||||
> that exists and fails, or that contains no assertions, satisfies them.
|
||||
>
|
||||
> Say which half you verified when you report. "Test file present at `<path>`"
|
||||
> is the honest claim; "tests pass" is not one this phase can make. Pass/fail is
|
||||
> established by `/gate-check` (runs the suite at a phase gate) and
|
||||
> `/smoke-check` (runs it before QA hand-off), both of which do execute.
|
||||
>
|
||||
> Unlike `/regression-suite` and `/launch-checklist`, which stop at existence
|
||||
> because their `allowed-tools` has no `Bash`, this skill HAS `Bash` — the limit
|
||||
> here is the instruction, not the grant. Running the story's own test before
|
||||
> closing it is a live option; it is not enabled because it needs a configured
|
||||
> runner and a decision about what a missing runner should mean.
|
||||
|
||||
**For Logic stories**: first read the story's **Test Evidence** section to extract the
|
||||
exact required file path. Use `Glob` to check that exact path. If the exact path is not
|
||||
found, also search `tests/unit/[system]/` broadly (the file may have been placed at a
|
||||
slightly different location). If no test file is found at either location:
|
||||
- Flag as **BLOCKING**: "Logic story has no unit test file. Story requires it at
|
||||
`[exact-path-from-Test-Evidence-section]`. Create and run the test before marking
|
||||
this story Complete."
|
||||
- Flag at the resolved gate level: "Logic story has no unit test file. Story
|
||||
requires it at `[exact-path-from-Test-Evidence-section]`. Create and run the
|
||||
test before marking this story Complete."
|
||||
|
||||
**For Integration stories**: read the story's **Test Evidence** section for the exact
|
||||
required path. Use `Glob` to check that exact path first, then search
|
||||
`tests/integration/[system]/` broadly, then check `production/session-logs/` for a
|
||||
playtest record referencing this story.
|
||||
If none found: flag as **BLOCKING** (same rule as Logic).
|
||||
If none found: flag at the resolved gate level (same rule as Logic).
|
||||
|
||||
**For Visual/Feel and UI stories**: glob `production/qa/evidence/` for a file
|
||||
referencing this story.
|
||||
- If none: flag as **ADVISORY** — "No manual test evidence found. Create `production/qa/evidence/[story-slug]-evidence.md` using the test-evidence template and obtain sign-off before final closure."
|
||||
- If found: read the file and check the sign-off table for unchecked boxes. Grep for lines matching `| .* | .* | .* | \[ \] Approved` (a sign-off row with an unchecked checkbox). If any unchecked sign-off rows are found: flag as **ADVISORY** — "Evidence file found at `[path]` but [N] sign-off(s) are still pending (shown as `[ ] Approved` in the sign-off table). Obtain required sign-offs before final closure. Note: for solo developers, all roles may be signed off by the same person."
|
||||
- If all sign-off rows show `[x] Approved` or equivalent: note "Evidence file found and all sign-offs complete — ADVISORY passed."
|
||||
**For Visual/Feel and UI stories**: glob `production/qa/evidence/` for both an
|
||||
evidence doc referencing this story and a retained screenshot for it (`*.png`,
|
||||
`*.jpg`, `*.gif`).
|
||||
- If neither is found: flag at the resolved gate level — "No visual evidence found. Capture a screenshot of each screen or effect this story touched, save it under `production/qa/evidence/`, create `production/qa/evidence/[story-slug]-evidence.md` using the test-evidence template, and obtain sign-off before final closure."
|
||||
- If the evidence doc exists but no screenshot is retained beside it: flag at the resolved gate level — "Evidence doc found at `[path]` but no screenshot is retained. A described check is an assertion, not evidence — capture the screen and save the image under `production/qa/evidence/` before final closure."
|
||||
- If found: read the file and check the sign-off table for unchecked boxes. Grep for lines matching `| .* | .* | .* | \[ \] Approved` (a sign-off row with an unchecked checkbox). If any unchecked sign-off rows are found: flag at the resolved gate level — "Evidence file found at `[path]` but [N] sign-off(s) are still pending (shown as `[ ] Approved` in the sign-off table). Obtain required sign-offs before final closure. Note: for solo developers, all roles may be signed off by the same person."
|
||||
- If the doc, the screenshot and all `[x] Approved` sign-off rows are present: note "Evidence doc and retained screenshot found, all sign-offs complete — gate satisfied."
|
||||
|
||||
The retained image **is** the `Run result: OBSERVED` from `/dev-story` Phase 6
|
||||
step 4 (`.claude/docs/run-and-observe.md`); its absence means the run was
|
||||
`NOT VERIFIED` or never happened, and the flag above is the consequence. The
|
||||
run is not waived at `qa.level: minimal`.
|
||||
|
||||
**For every other story type**, read the `Run result:` line from the
|
||||
`/dev-story` summary (the session extract in `production/session-state/active.md`,
|
||||
or the story's `## Completion Notes`). `OBSERVED` with a retained path: note
|
||||
it. `N/A — <reason>`: accept only if the reason names why nothing is
|
||||
observable — "it's a Logic story" is not a reason. `NOT VERIFIED — <reason>`
|
||||
on a story whose acceptance criteria name anything on screen: flag at the
|
||||
resolved gate level for the story's type. No `Run result:` line at all: flag
|
||||
as ADVISORY — "the implementation summary carries no run result; confirm the
|
||||
build was launched and looked at before closure."
|
||||
|
||||
**For Config/Data stories**: check for any `production/qa/smoke-*.md` file.
|
||||
If none: flag as **ADVISORY** — "No smoke check report found. Run `/smoke-check`."
|
||||
If none: flag at the resolved gate level — "No smoke check report found. Run `/smoke-check`."
|
||||
|
||||
**If no Story Type is set**: flag as **ADVISORY** —
|
||||
"Story Type not declared. Add `Type: [Logic|Integration|Visual/Feel|UI|Config/Data]`
|
||||
@@ -189,6 +315,20 @@ Any BLOCKING test evidence gap prevents the COMPLETE verdict in Phase 6.
|
||||
|
||||
Compare the implementation against the design documents.
|
||||
|
||||
> **Workflow tier adjustment** (resolved in Phase 1, per the story's system).
|
||||
> Checks 1 (GDD rules) and 3 (ADR constraints) below are the `full` baseline:
|
||||
> - **`full`** — run both: full GDD traceability against the current TR text +
|
||||
> the ADR constraints check.
|
||||
> - **`standard`** — run the GDD rules check against the **5 required sections**;
|
||||
> run the ADR constraints check only where a **critical ADR** governs the story.
|
||||
> - **`minimal`** — **acceptance-criteria check only**: skip checks 1 and 3 (no
|
||||
> GDD/ADR traceability expected). Checks 2 (manifest), 4 (hardcoded values), and
|
||||
> 5 (scope) still run as written.
|
||||
>
|
||||
> This adjustment governs only the Phase 4 *deviation* checks. The test-evidence
|
||||
> gates (Phase 3 traceability, Phase 4b QA coverage) are governed by `qa.level`
|
||||
> and `testing.strict`, not `workflow` — they run independently of the tier here.
|
||||
|
||||
Run these checks automatically:
|
||||
|
||||
1. **GDD rules check**: Using the current requirement text from `tr-registry.yaml`
|
||||
@@ -206,9 +346,10 @@ Run these checks automatically:
|
||||
is v[current-date]. New rules may apply. Run /story-readiness to check.`
|
||||
- If control-manifest.md does not exist → skip this check.
|
||||
|
||||
3. **ADR constraints check**: Read the referenced ADR's Decision section. Check
|
||||
for forbidden patterns from `docs/architecture/control-manifest.md` (if it
|
||||
exists). `Grep` for patterns explicitly forbidden in the ADR.
|
||||
3. **ADR constraints check**: Use the ADR's `## Decision` section already
|
||||
loaded in Phase 2 — do not read the ADR file again. Check for forbidden
|
||||
patterns from `docs/architecture/control-manifest.md` (if it exists).
|
||||
`Grep` for patterns explicitly forbidden in the ADR.
|
||||
|
||||
4. **Hardcoded values check**: `Grep` the implemented files for numeric literals
|
||||
in gameplay logic that should be in data files.
|
||||
@@ -229,12 +370,16 @@ For each deviation found, categorize:
|
||||
|
||||
## Phase 4b: QA Coverage Gate
|
||||
|
||||
**Skip this phase entirely at `qa.level: minimal`** (resolved in Phase 1) — no
|
||||
test evidence is required, so there is no coverage to review. Note: "QL-TEST-COVERAGE
|
||||
skipped — qa.level minimal." Proceed to Phase 5.
|
||||
|
||||
**Review mode check** — apply before spawning QL-TEST-COVERAGE:
|
||||
- `solo` → skip. Note: "QL-TEST-COVERAGE skipped — Solo mode." Proceed to Phase 5.
|
||||
- `lean` → skip (not a PHASE-GATE). Note: "QL-TEST-COVERAGE skipped — Lean mode." Proceed to Phase 5.
|
||||
- `full` → spawn as normal.
|
||||
|
||||
After completing the deviation checks in Phase 4, spawn `qa-lead` via Task using gate **QL-TEST-COVERAGE** (`.claude/docs/director-gates.md`).
|
||||
After completing the deviation checks in Phase 4, spawn `qa-lead` via `Agent` using gate **QL-TEST-COVERAGE** (`.claude/docs/director-gates/ql-test-coverage.md`).
|
||||
|
||||
Pass:
|
||||
- The story file path and story type
|
||||
@@ -266,7 +411,7 @@ Skip this phase for Config/Data stories (no code tests required).
|
||||
- Record the answer in the completion notes (Phase 7). All three options proceed to Phase 6.
|
||||
- `full` → spawn as normal.
|
||||
|
||||
Spawn `lead-programmer` via Task using gate **LP-CODE-REVIEW** (`.claude/docs/director-gates.md`).
|
||||
Spawn `lead-programmer` via `Agent` using gate **LP-CODE-REVIEW** (`.claude/docs/director-gates/lp-code-review.md`).
|
||||
|
||||
Pass: implementation file paths, story file path, relevant GDD section, governing ADR.
|
||||
|
||||
@@ -314,21 +459,92 @@ Before updating any files, present the full report:
|
||||
[All changes within stated scope] OR:
|
||||
- Extra files touched: [list] — [note whether valid or scope creep]
|
||||
|
||||
### Verdict: COMPLETE / COMPLETE WITH NOTES / BLOCKED
|
||||
### Verdict: COMPLETE / COMPLETE WITH NOTES / NOT ASSESSED / BLOCKED
|
||||
```
|
||||
|
||||
**Verdict definitions:**
|
||||
- **COMPLETE**: all criteria pass, no blocking deviations
|
||||
- **COMPLETE WITH NOTES**: all criteria pass, advisory deviations documented
|
||||
- **NOT ASSESSED**: one or more acceptance criteria could not be evaluated at
|
||||
all — name which, and why
|
||||
- **BLOCKED**: failing criteria or blocking deviations must be resolved first
|
||||
|
||||
If the verdict is **BLOCKED**: do not proceed to Phase 7. List what must be
|
||||
fixed. Offer to help fix the blocking items.
|
||||
**`NOT ASSESSED` — the story nobody could verify.** Rank: it **outranks COMPLETE
|
||||
and COMPLETE WITH NOTES** (a review that could not evaluate a criterion has not
|
||||
shown the criterion is met) and **ranks below BLOCKED** (a criterion known to
|
||||
fail is more actionable than one nobody could check, and demoting it would bury
|
||||
it). It is not a gentler BLOCKED: "this acceptance criterion fails" and "I could
|
||||
not tell whether it passes" send the reader to different fixes.
|
||||
|
||||
**Verdict precedence — first matching rule wins**, evaluated in this order:
|
||||
**BLOCKED**, then **NOT ASSESSED**, then **COMPLETE WITH NOTES**, then
|
||||
**COMPLETE**. A run with both a failing criterion and an unassessable one is
|
||||
BLOCKED. Stating the order mechanically, rather than leaving it to be inferred
|
||||
from the rank sentence, is what keeps two reviewers from grading the same story
|
||||
differently.
|
||||
|
||||
Emit it when any of:
|
||||
|
||||
- An acceptance criterion **cannot be evaluated at all** — it names no observable
|
||||
outcome, so no evidence could settle it either way.
|
||||
> **Not the same as Phase 3's `DEFERRED`.** A criterion that is evaluable but
|
||||
> needs a playtest is `DEFERRED — requires playtest session`, it does **not**
|
||||
> block, and Phase 3 keeps ownership of it. This trigger is for a criterion no
|
||||
> session could ever settle as written. If Phase 3 already marked it DEFERRED,
|
||||
> that classification stands and this trigger does not fire.
|
||||
- The **test evidence is present but unreadable or unclassifiable** — corrupt,
|
||||
empty, or of a type that cannot be determined.
|
||||
> **Absent evidence is Phase 3's, not this trigger's.** Phase 3 resolves a
|
||||
> missing file through `testing.strict`: BLOCKING types produce **BLOCKED**,
|
||||
> ADVISORY types produce **COMPLETE WITH NOTES**. Both outrank or are already
|
||||
> decided, so re-routing "absent" here would silently override an explicit
|
||||
> advisory ruling. *Unreadable* is the genuinely unassessable case, and it is
|
||||
> the only one this trigger claims.
|
||||
- **`/test-evidence-review` returned `NOT ASSESSED`** for this story — applicable
|
||||
only when that skill was actually run against it, which this skill does not do
|
||||
itself. It
|
||||
propagates: that skill's whole point is that "could not check" is not
|
||||
"checked and fine", and collapsing its unknown into a COMPLETE here would undo
|
||||
the distinction one skill downstream. `coding-standards.md` marks Logic and
|
||||
Integration evidence BLOCKING, so this is the path where an unverifiable story
|
||||
would otherwise acquire a verdict saying somebody verified it.
|
||||
- A **deviation's severity cannot be determined** because the GDD or ADR it
|
||||
would be judged against is missing.
|
||||
|
||||
A `NOT ASSESSED` verdict takes the same Phase 7 path as BLOCKED: do not
|
||||
automatically proceed, list what could not be checked and what would make it
|
||||
checkable. Closing anyway remains the user's explicit call, and stays gated by
|
||||
Phase 7's `scope_changes` always-ask rule.
|
||||
|
||||
If the verdict is **BLOCKED**: do not *automatically* proceed to Phase 7. List
|
||||
what must be fixed and offer to help fix the blocking items. This is the
|
||||
default path, not an absolute stop — the user may still explicitly ask to
|
||||
close the story anyway despite the blockers. That request is what routes to
|
||||
Phase 7's menu below, and Phase 7's own `scope_changes` always-ask rule is
|
||||
exactly what stands between that request and a silent close in autonomous
|
||||
mode. Do not treat "do not automatically proceed" as "Phase 7 is now
|
||||
unreachable" — it is reachable, on request, and gated when reached.
|
||||
|
||||
---
|
||||
|
||||
## Phase 7: Update Story Status
|
||||
|
||||
**Reached one of two ways**: normally, immediately after a COMPLETE or
|
||||
COMPLETE-WITH-NOTES verdict in Phase 6; or, after a BLOCKED **or NOT ASSESSED**
|
||||
verdict, only if the user explicitly asks to close the story despite the
|
||||
blockers (Phase 6 does not advance here on its own in either case).
|
||||
|
||||
**Automation note**: This is the story-completion gate. Closing a story whose
|
||||
verdict is BLOCKED (failing acceptance criteria) **or NOT ASSESSED** (criteria
|
||||
nobody could evaluate) — the "Accept deviations as-is and close anyway" option —
|
||||
is a `scope_changes` decision. Call
|
||||
`is_always_ask_category scope_changes`; when it returns 0 (the default), this
|
||||
gate prompts via `AskUserQuestion` **regardless of `modes.automation`** —
|
||||
autonomous mode must NOT silently close a BLOCKED story, even when the user's
|
||||
own request is what got you here. For a COMPLETE or COMPLETE-WITH-NOTES
|
||||
verdict, autonomous mode may pick "Close the story (Recommended)" and record
|
||||
it via `log_decision`.
|
||||
|
||||
Use `AskUserQuestion` before writing anything:
|
||||
- Prompt: "Verification complete. How do you want to proceed?"
|
||||
- Options:
|
||||
@@ -370,7 +586,7 @@ If "Fix first": stop here and list what the user flagged. Do not write any files
|
||||
|
||||
```
|
||||
Suggested commit:
|
||||
git add [src/ and tests/ files changed during implementation] [story-file-path]
|
||||
git add [code-root and tests/ files changed during implementation] [story-file-path]
|
||||
git commit -m "feat: [story title] ([TR-ID])"
|
||||
```
|
||||
|
||||
@@ -382,7 +598,7 @@ After updating the story file, silently append to
|
||||
`production/session-state/active.md`:
|
||||
|
||||
## Session Extract — /story-done [date]
|
||||
- Verdict: [COMPLETE / COMPLETE WITH NOTES / BLOCKED]
|
||||
- Verdict: [COMPLETE / COMPLETE WITH NOTES / NOT ASSESSED / BLOCKED]
|
||||
- Story: [story file path] — [story title]
|
||||
- Tech debt logged: [N items, or "None"]
|
||||
- Next recommended: [next ready story title and path, or "None identified"]
|
||||
@@ -440,13 +656,21 @@ If no more stories are ready but Must Have stories are still In Progress (not Co
|
||||
|
||||
## Collaborative Protocol
|
||||
|
||||
**In `collaborative` mode (the default).** For `guided` and `autonomous` modes,
|
||||
see `.claude/docs/automation-modes.md` — the rules below describe collaborative
|
||||
behavior. The BLOCKED-override close (Phase 7) always prompts regardless of mode
|
||||
(it's a `scope_changes` always-ask decision).
|
||||
|
||||
- **Never mark a story complete without user approval** — Phase 7 requires an
|
||||
explicit "yes" before any file is edited.
|
||||
- **Never auto-fix failing criteria** — report them and ask what to do.
|
||||
- **Deviations are facts, not judgments** — present them neutrally; the user
|
||||
decides if they are acceptable.
|
||||
- **BLOCKED verdict is advisory** — the user can override and mark complete
|
||||
anyway; document the risk explicitly if they do.
|
||||
- **BLOCKED and NOT ASSESSED verdicts are advisory** — the user can override and
|
||||
mark complete anyway; document the risk explicitly if they do. For NOT
|
||||
ASSESSED, the documented risk is that the criterion was never evaluated, not
|
||||
that it failed — record which criteria those were, so the gap is recoverable
|
||||
later rather than closed over.
|
||||
- Use `AskUserQuestion` for the code review prompt and for batching manual
|
||||
criteria confirmations.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user