mirror of
https://github.com/Donchitos/Claude-Code-Game-Studios.git
synced 2026-10-16 01:37:05 +00:00
Release 1.1.2 — the default path works end to end
Fix release for 1.1.1: the minimal path end to end, engine commands that run on Godot, Unity and Unreal, hook warnings you can see, and verdicts that say when they could not check. Details in CHANGELOG.md; upgrade steps in UPGRADING.md (v1.1.1 → v1.1.2). Fixes #67 Fixes #131 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WuJn2FdynEybfL5KC697nJ
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
7ed2c3e9c4
commit
b21fa0f7f2
@@ -2,23 +2,34 @@
|
||||
|
||||
## Skill Summary
|
||||
|
||||
`/changelog` is a Haiku-tier skill that auto-generates a developer-facing
|
||||
changelog by reading git commit history and closed sprint stories since the
|
||||
last release tag. It organizes entries into features, fixes, and known issues.
|
||||
No director gates are used. The skill asks "May I write to `docs/CHANGELOG.md`?"
|
||||
before persisting. Verdict is always COMPLETE.
|
||||
`/changelog` is a Sonnet-tier skill that generates two changelogs — an internal
|
||||
one and a player-facing one — from the git commits since the last release tag.
|
||||
Before using the injected history it classifies every commit as Game or
|
||||
Framework / maintenance (Unclear counts as Framework), uses only the Game
|
||||
commits, and says how many of how many it used; with zero Game commits it stops.
|
||||
With no history at all (not a git repository, or no commits) it skips that check
|
||||
and stops at Phase 1. It reads sprint plans in `production/sprints/` and GDDs in
|
||||
`design/gdd/` for context, and sorts changes into New Features, Improvements, Bug
|
||||
Fixes, Balance Changes, Technical Debt / Refactoring (internal changelog only),
|
||||
Known Issues and Miscellaneous. The internal changelog ends with a Metrics
|
||||
section that counts commits without a task reference. With no tags it bounds the
|
||||
range to `git log --oneline -n 100` rather than reading the full log. No director
|
||||
gates are used. The skill asks "May I write this changelog to
|
||||
`docs/CHANGELOG.md`?" with append / overwrite / decline options. Verdicts:
|
||||
CHANGELOG WRITTEN after a write, COMPLETE when the user declines the write,
|
||||
BLOCKED when there is no history or none of it is the game's.
|
||||
|
||||
---
|
||||
|
||||
## Static Assertions (Structural)
|
||||
|
||||
Verified automatically by `/skill-test static` — no fixture needed.
|
||||
Checked against the SKILL.md by `/skill-test spec` — no fixture needed.
|
||||
|
||||
- [ ] Has required frontmatter fields: `name`, `description`, `argument-hint`, `user-invocable`, `allowed-tools`
|
||||
- [ ] Has ≥2 phase headings
|
||||
- [ ] Contains verdict keyword: COMPLETE
|
||||
- [ ] Contains verdict keywords: CHANGELOG WRITTEN, COMPLETE, BLOCKED
|
||||
- [ ] Contains "May I write" language (skill writes changelog)
|
||||
- [ ] Has a next-step handoff (e.g., run /patch-notes for player-facing version)
|
||||
- [ ] Has a next-step handoff (`/patch-notes` for a player-facing release, `/release-checklist`)
|
||||
|
||||
---
|
||||
|
||||
@@ -33,136 +44,210 @@ None. Changelog generation is a fast compilation task; no gates are invoked.
|
||||
### Case 1: Happy Path — Multiple sprints since last release tag
|
||||
|
||||
**Fixture:**
|
||||
- Git history has a tag `v0.3.0` three sprints ago
|
||||
- Since that tag: 12 commits across sprints 006, 007, 008
|
||||
- Sprint story files reference task IDs matching commit messages
|
||||
- Git history has a tag `v0.3.0`; it is the newest tag in the injected tag list
|
||||
- Since that tag: 12 commits across sprints 006, 007, 008 — all Game commits
|
||||
(mechanics, content, bug fixes) naming systems that appear in `design/`
|
||||
- `production/sprints/sprint-006.md` through `sprint-008.md` exist and list the
|
||||
stories whose task IDs appear in the commit messages
|
||||
- `docs/CHANGELOG.md` does not yet exist
|
||||
|
||||
**Input:** `/changelog`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads git log since `v0.3.0` tag
|
||||
2. Skill reads sprint stories to cross-reference task IDs
|
||||
3. Skill compiles entries into Features, Fixes, and Known Issues sections
|
||||
4. Skill presents draft to user
|
||||
5. Skill asks "May I write to `docs/CHANGELOG.md`?"
|
||||
6. User approves; file written; verdict COMPLETE
|
||||
1. Skill classifies the injected commits as Game or Framework / maintenance and
|
||||
states how many of how many it used
|
||||
2. Skill reads `git log --oneline v0.3.0..HEAD`
|
||||
3. Skill reads the sprint plans for sprints 006–008 in `production/sprints/`
|
||||
for the context behind the changes
|
||||
4. Skill categorizes changes into New Features, Improvements, Bug Fixes,
|
||||
Balance Changes, Technical Debt / Refactoring, Known Issues and
|
||||
Miscellaneous, with a Metrics section
|
||||
5. Skill outputs both the internal and the player-facing changelog
|
||||
6. Skill asks "May I write this changelog to `docs/CHANGELOG.md`?" with options
|
||||
[A] append, [B] overwrite, [C] no
|
||||
7. User selects [B]; the file is created; verdict CHANGELOG WRITTEN
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Changelog covers commits since the most recent git tag
|
||||
- [ ] Entries are organized into Features / Fixes / Known Issues sections
|
||||
- [ ] Sprint story references are used to enrich commit descriptions
|
||||
- [ ] "May I write" prompt appears before file write
|
||||
- [ ] Verdict is COMPLETE after write
|
||||
- [ ] Changelog covers the commits in `v0.3.0..HEAD`, and the output states how many of how many injected commits it used
|
||||
- [ ] Entries use the skill's section set — New Features, Improvements, Bug Fixes, Balance Changes, Technical Debt / Refactoring, Known Issues, Miscellaneous — not a generic Features/Fixes split
|
||||
- [ ] Sprint plans in `production/sprints/` for the covered sprints are read for context before categorizing
|
||||
- [ ] Both changelogs are presented before the "May I write" prompt, and nothing is written before approval
|
||||
- [ ] Verdict is CHANGELOG WRITTEN after the write
|
||||
|
||||
---
|
||||
|
||||
### Case 2: No Git Tags Found — All commits used, version baseline noted
|
||||
### Case 2: No Git Tags Found — Bounded range used
|
||||
|
||||
**Fixture:**
|
||||
- Git repository has commits but no tags exist
|
||||
- 20 commits in history across 3 sprints
|
||||
- Git repository has 20 commits and no tags; all 20 are Game commits
|
||||
- The injected tag list is empty
|
||||
- `docs/CHANGELOG.md` does not exist
|
||||
|
||||
**Input:** `/changelog`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill checks for git tags — finds none
|
||||
2. Skill uses all commits in history as the baseline
|
||||
3. Skill notes in the output: "No version tag found — using full commit history; version baseline is unset"
|
||||
4. Skill still compiles organized changelog from available commits
|
||||
5. Skill asks "May I write" and writes on approval
|
||||
1. Skill finds no tag to anchor the range
|
||||
2. Skill bounds the range with `git log --oneline -n 100` — it does not read an
|
||||
unbounded full log
|
||||
3. All 20 commits fall inside the 100-commit bound, so the window reaches the
|
||||
start of history and the skill does not need to ask for a start ref
|
||||
4. Skill states how many of the commits it used
|
||||
5. Skill compiles the categorized changelog and asks "May I write" before writing
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Skill does not error when no git tags exist
|
||||
- [ ] Output explicitly notes that no version baseline was found
|
||||
- [ ] Full commit history is used as the source
|
||||
- [ ] Changelog is still organized into sections despite missing tag
|
||||
- [ ] The range is read with the bounded `git log --oneline -n 100`, never an unbounded full log
|
||||
- [ ] All 20 commits are covered, and the skill does not ask for a start ref (the bound reaches the first commit)
|
||||
- [ ] Output states how many of the 20 commits were used
|
||||
- [ ] Changelog is still organized into sections despite the missing tag
|
||||
|
||||
---
|
||||
|
||||
### Case 3: Commit Messages Without Task IDs — Grouped by date with note
|
||||
### Case 3: Commit Messages Without Task IDs — Categorized by content, counted in Metrics
|
||||
|
||||
**Fixture:**
|
||||
- Git log since last tag has 8 commits
|
||||
- 5 commits have no task ID in the message (e.g., "fix typo", "tweak values")
|
||||
- 3 commits reference task IDs matching sprint stories
|
||||
- Git log since the last tag has 8 Game commits
|
||||
- 3 commits reference task IDs (e.g. `[STORY-012]`) matching sprint stories
|
||||
- 5 commits have no task ID: "tweak dash cooldown 0.8 -> 0.6",
|
||||
"fix player clipping through ledge", "add footstep sounds", "level tweaks",
|
||||
"combat cleanup"
|
||||
|
||||
**Input:** `/changelog`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads commits and sprint stories
|
||||
2. 3 commits are matched to sprint stories and placed in appropriate sections
|
||||
3. 5 untagged commits are grouped by date under a "Misc" or "Other Changes" section
|
||||
4. Output notes: "5 commits without task IDs — grouped by date"
|
||||
5. Skill writes changelog on approval
|
||||
1. Skill categorizes every commit by what it changed, whether or not it has a
|
||||
task ID
|
||||
2. "tweak dash cooldown 0.8 -> 0.6" goes to Balance Changes; "fix player
|
||||
clipping through ledge" goes to Bug Fixes
|
||||
3. "combat cleanup" says it cleans up and names no fix, feature or tuning, so it
|
||||
goes to Technical Debt / Refactoring — in the internal changelog only
|
||||
4. "level tweaks" is too vague to classify confidently and goes to
|
||||
Miscellaneous
|
||||
5. The Metrics section reports `Commits without task reference: 5`
|
||||
6. Skill asks "May I write" and writes on approval
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Commits with task IDs are placed in appropriate sections (Features or Fixes)
|
||||
- [ ] Commits without task IDs are grouped separately with a note
|
||||
- [ ] Output flags the number of commits missing task references
|
||||
- [ ] No commits are silently dropped from the changelog
|
||||
- [ ] Commits are categorized by content with or without a task ID — the untagged "tweak dash cooldown 0.8 -> 0.6" lands in Balance Changes, not in a separate no-ID group
|
||||
- [ ] "combat cleanup" is listed under Technical Debt / Refactoring in the internal changelog and does not appear in the player-facing changelog
|
||||
- [ ] "level tweaks", too vague to classify, is listed under Miscellaneous
|
||||
- [ ] Metrics section contains `Commits without task reference: 5`
|
||||
- [ ] No commits are silently dropped — all 8 appear in a section
|
||||
|
||||
---
|
||||
|
||||
### Case 4: Existing CHANGELOG.md — New section prepended, old entries preserved
|
||||
### Case 4: Existing CHANGELOG.md — New entry at the top, old entries preserved
|
||||
|
||||
**Fixture:**
|
||||
- `docs/CHANGELOG.md` already exists with sections for `v0.2.0` and `v0.3.0`
|
||||
- New commits exist since `v0.3.0` tag
|
||||
- New Game commits exist since the `v0.3.0` tag
|
||||
|
||||
**Input:** `/changelog`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill detects that `docs/CHANGELOG.md` already exists
|
||||
2. Skill compiles new entries for the period since `v0.3.0`
|
||||
3. Skill presents draft with new section prepended above existing content
|
||||
4. Skill asks "May I write to `docs/CHANGELOG.md`?" (confirming prepend strategy)
|
||||
5. User approves; new content is prepended, old entries intact; verdict COMPLETE
|
||||
1. Skill compiles new entries for the period since `v0.3.0`
|
||||
2. Before asking, skill checks whether `docs/CHANGELOG.md` exists — it does, so
|
||||
it recommends [A] append
|
||||
3. Skill asks "May I write this changelog to `docs/CHANGELOG.md`?" with
|
||||
[A] append (recommended), [B] overwrite, [C] no
|
||||
4. User selects [A]; the new entry is placed at the top of the file (newest
|
||||
first); the `v0.2.0` and `v0.3.0` sections are intact; verdict CHANGELOG WRITTEN
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Skill reads existing changelog before writing to detect prior content
|
||||
- [ ] New section is prepended (not appended or overwriting) existing entries
|
||||
- [ ] Old changelog entries for v0.2.0 and v0.3.0 are preserved in the written file
|
||||
- [ ] "May I write" prompt reflects the prepend operation
|
||||
- [ ] Skill checks whether `docs/CHANGELOG.md` exists before asking, and recommends [A] append because it does
|
||||
- [ ] The prompt offers append, overwrite and decline as distinct options
|
||||
- [ ] On [A], the new entry is placed at the top of the file (newest first), not at the bottom and not replacing the file
|
||||
- [ ] Existing `v0.2.0` and `v0.3.0` entries are preserved in the written file
|
||||
|
||||
---
|
||||
|
||||
### Case 5: Gate Compliance — No gate; read-then-write with approval
|
||||
### Case 5: Gate Compliance — No gate; declined write ends COMPLETE
|
||||
|
||||
**Fixture:**
|
||||
- Git history has commits since last tag
|
||||
- `review-mode.txt` contains `full`
|
||||
- Git history has Game commits since the last tag
|
||||
- `project.yaml` sets `modes.review_mode: full`
|
||||
|
||||
**Input:** `/changelog`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill compiles changelog in full mode
|
||||
2. No director gate is invoked (changelog generation is compilation, not a delivery gate)
|
||||
3. Skill runs on Haiku model — fast compilation
|
||||
4. Skill asks user for approval and writes file on confirmation
|
||||
1. Skill compiles both changelogs; no director gate is spawned (the skill
|
||||
resolves only `automation`, never `review_mode`)
|
||||
2. Skill goes straight from presenting the changelogs to the write prompt
|
||||
3. User selects [C] No — I'll copy it manually
|
||||
4. Skill stops without writing; verdict COMPLETE
|
||||
|
||||
**Assertions:**
|
||||
- [ ] No director gate is invoked regardless of review mode
|
||||
- [ ] Output does not reference any gate result
|
||||
- [ ] Skill proceeds directly from compilation to "May I write" prompt
|
||||
- [ ] Verdict is COMPLETE
|
||||
- [ ] Skill proceeds directly from presenting the changelogs to the "May I write" prompt
|
||||
- [ ] On [C], no file is written and the verdict is COMPLETE, not CHANGELOG WRITTEN
|
||||
|
||||
---
|
||||
|
||||
### Case 6: Provenance Stop — Zero Game commits
|
||||
|
||||
**Fixture:**
|
||||
- The 30 injected commits all touch the framework or tooling — subjects such as
|
||||
"fix: session-start hook timeout", "docs: skill catalog", "ci: cache the test
|
||||
runner" — and none names a game system in `design/` or the code root
|
||||
- `docs/CHANGELOG.md` does not exist
|
||||
|
||||
**Input:** `/changelog`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill classifies every injected commit: 0 Game, 30 Framework / maintenance
|
||||
2. Skill stops with "The git history in this repo does not appear to belong to
|
||||
[game] …", describing what the commits actually cover
|
||||
3. No changelog is generated and nothing is written; verdict BLOCKED
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Output names the classification result — 0 of 30 commits are Game commits
|
||||
- [ ] Output contains the "does not appear to belong to" stop, not a changelog built from framework commits (no "Fixed an issue where …" copy from a hook fix)
|
||||
- [ ] No "May I write" prompt appears and no file is written
|
||||
- [ ] Verdict is BLOCKED — not COMPLETE and not CHANGELOG WRITTEN
|
||||
|
||||
---
|
||||
|
||||
### Case 7: No History — Not a git repository
|
||||
|
||||
**Fixture:**
|
||||
- The project directory is not a git repository, so both injected history
|
||||
blocks are empty
|
||||
- `docs/CHANGELOG.md` does not exist
|
||||
|
||||
**Input:** `/changelog`
|
||||
|
||||
**Expected behavior:**
|
||||
1. The injected commit list is empty, so the provenance check is skipped —
|
||||
there is nothing to classify
|
||||
2. Phase 1's `git rev-parse --is-inside-work-tree` fails; skill outputs "No git
|
||||
history found. A changelog is built from commits …"
|
||||
3. Nothing is generated or written; verdict BLOCKED
|
||||
|
||||
**Assertions:**
|
||||
- [ ] The "does not appear to belong to" provenance stop is NOT shown — an empty history is not a wrong history
|
||||
- [ ] Output says no git history was found and offers committing the work or supplying the change list directly
|
||||
- [ ] No changelog is generated, no "May I write" prompt appears, and no file is written
|
||||
- [ ] Verdict is BLOCKED
|
||||
|
||||
---
|
||||
|
||||
## Protocol Compliance
|
||||
|
||||
- [ ] Reads git log and sprint story files before compiling
|
||||
- [ ] Always asks "May I write" before writing changelog
|
||||
- [ ] Classifies the injected commits as Game or Framework / maintenance and uses only Game commits
|
||||
- [ ] Reads the git log and the sprint plans in `production/sprints/` before compiling
|
||||
- [ ] Always asks "May I write" before writing the changelog
|
||||
- [ ] No director gates are invoked
|
||||
- [ ] Verdict is always COMPLETE
|
||||
- [ ] Runs on Haiku model tier (fast, low-cost)
|
||||
- [ ] Verdict is CHANGELOG WRITTEN after a write, COMPLETE when the write is declined, and BLOCKED when there is no history or no Game commit
|
||||
- [ ] Declares `model: sonnet` — it writes player-facing copy
|
||||
|
||||
---
|
||||
|
||||
## Coverage Notes
|
||||
|
||||
- The case where git is not initialized in the repository is not tested;
|
||||
behavior would depend on git command failure handling.
|
||||
- A git repository with no commits yet (the same Phase 1 stop as Case 7) is not
|
||||
separately tested.
|
||||
- More than 100 commits with no tag (the skill says so and asks for a start ref
|
||||
instead of widening the range) is not tested.
|
||||
- Merge commits vs. squash commits are not explicitly differentiated in
|
||||
these tests; implementation detail of the git log parsing phase.
|
||||
- The `/patch-notes` skill should be run after `/changelog` for player-facing
|
||||
|
||||
@@ -2,170 +2,284 @@
|
||||
|
||||
## Skill Summary
|
||||
|
||||
`/milestone-review` generates a comprehensive review of a completed milestone:
|
||||
what shipped, velocity metrics, deferred items, risks surfaced, and retrospective
|
||||
seeds. In full mode the PR-MILESTONE director gate runs after the review is
|
||||
compiled (producer reviews scope delivery). In lean and solo modes the gate is
|
||||
skipped. The skill asks "May I write to `production/milestones/review-milestone-N.md`?"
|
||||
before persisting. Verdicts: MILESTONE COMPLETE or MILESTONE INCOMPLETE.
|
||||
`/milestone-review` reviews a milestone's progress from its definition in
|
||||
`production/milestones/` (when one exists) and the sprint reports in
|
||||
`production/sprints/`: feature completeness, quality metrics, code health, risk,
|
||||
velocity, scope recommendations and a Go/No-Go recommendation (NOT ASSESSED /
|
||||
GO / CONDITIONAL GO / NO-GO). Blocked stories and their blockers come from
|
||||
`production/sprint-status.yaml` and the story files, open bugs from
|
||||
`production/qa/bugs/`. Before producing any report it records each input as
|
||||
FOUND or ABSENT; a section whose inputs are absent reads
|
||||
`NOT ASSESSED — NO DATA`, and if every required input is absent it stops with
|
||||
that as the whole verdict. In full review mode it spawns `producer` with the
|
||||
PR-MILESTONE gate before the Go/No-Go recommendation is generated; the
|
||||
producer's verdict (ON TRACK / AT RISK / OFF TRACK) is shown inline, and AT RISK
|
||||
or OFF TRACK raises an `AskUserQuestion` on how to frame the recommendation. In
|
||||
lean and solo modes the gate is skipped with a note. The skill asks "May I write
|
||||
this to `production/milestones/[milestone-name]-review.md`?" before persisting.
|
||||
Verdicts: COMPLETE (review saved), BLOCKED (write declined), or
|
||||
`NOT ASSESSED — NO DATA` (no inputs at all).
|
||||
|
||||
---
|
||||
|
||||
## Static Assertions (Structural)
|
||||
|
||||
Verified automatically by `/skill-test static` — no fixture needed.
|
||||
Checked against the SKILL.md by `/skill-test spec` — no fixture needed.
|
||||
|
||||
- [ ] Has required frontmatter fields: `name`, `description`, `argument-hint`, `user-invocable`, `allowed-tools`
|
||||
- [ ] Has ≥2 phase headings
|
||||
- [ ] Contains verdict keywords: MILESTONE COMPLETE, MILESTONE INCOMPLETE
|
||||
- [ ] Contains verdict keywords: COMPLETE, BLOCKED, NOT ASSESSED
|
||||
- [ ] Contains Go/No-Go recommendation values: GO, CONDITIONAL GO, NO-GO
|
||||
- [ ] Contains "May I write" language (skill writes review document)
|
||||
- [ ] Has a next-step handoff (what to do after review is written)
|
||||
- [ ] Has a next-step handoff (`/gate-check`, `/sprint-plan`)
|
||||
|
||||
---
|
||||
|
||||
## Director Gate Checks
|
||||
|
||||
| Gate ID | Trigger condition | Mode guard |
|
||||
|---------------|--------------------------------|-------------------------|
|
||||
| PR-MILESTONE | After review document compiled | full only (not lean/solo) |
|
||||
| Gate ID | Trigger condition | Mode guard |
|
||||
|---------------|------------------------------------------------|---------------------------|
|
||||
| PR-MILESTONE | Before the Go/No-Go recommendation is generated | full only (not lean/solo) |
|
||||
|
||||
PR-MILESTONE verdicts: ON TRACK / AT RISK / OFF TRACK — or NOT ASSESSED
|
||||
[missing input] (`.claude/docs/director-gates.md`), on which the skill never
|
||||
recommends GO.
|
||||
|
||||
---
|
||||
|
||||
## Test Cases
|
||||
|
||||
### Case 1: Happy Path — Nearly complete milestone with one deferred story
|
||||
### Case 1: Happy Path — Nearly complete milestone with one deferred feature
|
||||
|
||||
**Fixture:**
|
||||
- `production/milestones/milestone-03.md` exists with 8 stories
|
||||
- 7 stories have `Status: Complete`
|
||||
- 1 story has `Status: Deferred` (deferred to milestone-04)
|
||||
- `review-mode.txt` contains `full`
|
||||
- `production/milestones/milestone-03.md` exists (milestone-definition template)
|
||||
with 8 features in its Feature List
|
||||
- 7 features have `Status: Complete`
|
||||
- 1 feature has `Status: Deferred` (deferred to milestone-04)
|
||||
- `production/sprints/sprint-007.md` through `sprint-009.md` exist with the
|
||||
headings `/sprint-plan` writes
|
||||
- The features' stories exist under `production/epics/`; none is `Blocked`
|
||||
- `project.yaml` sets `modes.review_mode: full`
|
||||
- The producer returns ON TRACK
|
||||
|
||||
**Input:** `/milestone-review milestone-03`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads `milestone-03.md` and all referenced sprint files
|
||||
2. Skill compiles: 7 shipped, 1 deferred; velocity; no blockers
|
||||
3. Skill presents review draft to user
|
||||
4. PR-MILESTONE gate invoked; producer approves
|
||||
5. Skill asks "May I write to `production/milestones/review-milestone-03.md`?"
|
||||
6. User approves; file is written; verdict MILESTONE COMPLETE
|
||||
1. Skill reads `milestone-03.md`, globs the sprint reports (N = 3) and greps
|
||||
their sections, then greps the story files for Blocked statuses (none)
|
||||
2. Skill compiles the review: 7 features under Fully Complete; the deferred
|
||||
feature is not counted as complete
|
||||
3. Skill spawns `producer` with PR-MILESTONE, passing milestone name and target
|
||||
date, completion percentage, blocked story count (0), velocity data and cut
|
||||
candidates
|
||||
4. The producer's ON TRACK verdict is shown inline in the Go/No-Go section; no
|
||||
framing question is asked
|
||||
5. Skill presents the review and asks "May I write this to
|
||||
`production/milestones/milestone-03-review.md`?"
|
||||
6. User approves; file is written; verdict COMPLETE
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Deferred story is noted in the review with its target milestone
|
||||
- [ ] Verdict is MILESTONE COMPLETE despite the one deferred story
|
||||
- [ ] PR-MILESTONE gate is invoked after draft compilation in full mode
|
||||
- [ ] Skill asks "May I write" before writing review file
|
||||
- [ ] Review document path matches `production/milestones/review-milestone-03.md`
|
||||
- [ ] The deferred feature is not listed under Fully Complete and is not counted as complete in the completion percentage (7 of 8)
|
||||
- [ ] PR-MILESTONE is spawned in full mode before the Go/No-Go recommendation, with completion percentage and blocked story count passed
|
||||
- [ ] The producer's ON TRACK verdict appears inline in the Go/No-Go section, and no framing `AskUserQuestion` is raised (only AT RISK and OFF TRACK raise one)
|
||||
- [ ] Skill asks "May I write" before writing, naming `production/milestones/milestone-03-review.md`
|
||||
- [ ] Verdict is COMPLETE after the write
|
||||
|
||||
---
|
||||
|
||||
### Case 2: Blocked Milestone — Multiple blocked stories
|
||||
### Case 2: Blocked Milestone — Producer returns OFF TRACK
|
||||
|
||||
**Fixture:**
|
||||
- `production/milestones/milestone-03.md` exists with 5 stories
|
||||
- 2 stories have `Status: Complete`
|
||||
- 3 stories have `Status: Blocked` (named blockers listed in each story)
|
||||
- `review-mode.txt` contains `full`
|
||||
- `production/milestones/milestone-03.md` lists 5 features
|
||||
- 2 features have `Status: Complete`
|
||||
- 3 features have `Status: Blocked`; each has one story under
|
||||
`production/epics/[its epic]/` whose file carries `> **Status**: Blocked` and
|
||||
a `BLOCKED:` note naming its blocker
|
||||
- Sprint reports exist in `production/sprints/`; they name no blockers
|
||||
- `project.yaml` sets `modes.review_mode: full`
|
||||
- The producer returns OFF TRACK
|
||||
|
||||
**Input:** `/milestone-review milestone-03`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads milestone and sprint files
|
||||
2. Skill finds 3 blocked stories; compiles blocker details
|
||||
3. Verdict is MILESTONE INCOMPLETE
|
||||
4. PR-MILESTONE gate runs; producer notes the unresolved blockers
|
||||
5. Review is written with blocker list on approval
|
||||
1. Skill reads the milestone and sprint reports, then greps the story files for
|
||||
`Blocked` statuses and `BLOCKED:` notes; compiles the 3 blocked features in
|
||||
the Blocked table with their blockers
|
||||
2. Skill spawns PR-MILESTONE, passing a completion percentage of 40% and a
|
||||
blocked story count of 3
|
||||
3. On OFF TRACK, skill asks via `AskUserQuestion`: "Producer verdict: OFF TRACK.
|
||||
The milestone is in jeopardy. This review will recommend NO-GO. How do you
|
||||
want to proceed?" with [A] Accept NO-GO, [B] Override to CONDITIONAL GO,
|
||||
[C] Stop
|
||||
4. User selects [A]; the Go/No-Go recommendation is NO-GO
|
||||
5. Skill presents the review, asks "May I write", and writes on approval
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Verdict is MILESTONE INCOMPLETE when any stories are Blocked
|
||||
- [ ] Each blocked story's name and blocker reason is listed in the review
|
||||
- [ ] PR-MILESTONE gate is still invoked in full mode even for INCOMPLETE verdict
|
||||
- [ ] "May I write" prompt still appears before file write
|
||||
- [ ] Each blocked feature is named in the Blocked table with its blocker, taken from its story's `BLOCKED:` note — the sprint reports carry none, so a blocker not read from the story files is invented
|
||||
- [ ] PR-MILESTONE receives the blocked story count (3), counted from the story files
|
||||
- [ ] OFF TRACK raises the `AskUserQuestion` with Accept NO-GO / Override to CONDITIONAL GO / Stop before the recommendation is generated
|
||||
- [ ] After [A], the recommendation is NO-GO — the skill does not issue GO against an OFF TRACK verdict
|
||||
- [ ] "May I write" prompt still appears before the file is written
|
||||
|
||||
---
|
||||
|
||||
### Case 3: Full Mode — PR-MILESTONE returns CONCERNS
|
||||
### Case 3: Full Mode — PR-MILESTONE returns AT RISK over scope drift
|
||||
|
||||
**Fixture:**
|
||||
- Milestone-03 has 6 complete stories but 2 were not in the original scope (added mid-sprint)
|
||||
- `review-mode.txt` contains `full`
|
||||
- `production/milestones/milestone-03.md` lists 6 complete features, 2 of which
|
||||
were not in the original definition (added mid-milestone)
|
||||
- Sprint reports exist in `production/sprints/`
|
||||
- `project.yaml` sets `modes.review_mode: full`
|
||||
- The producer returns AT RISK, citing the 2 added features as scope drift and
|
||||
listing mitigations
|
||||
|
||||
**Input:** `/milestone-review milestone-03`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill compiles review; notes 2 out-of-scope stories shipped
|
||||
2. PR-MILESTONE gate invoked; producer returns CONCERNS about scope drift
|
||||
3. Skill surfaces the CONCERNS to the user and adds a "scope drift" note to the review
|
||||
4. User approves revised review; file written as MILESTONE COMPLETE with caveat
|
||||
1. Skill compiles the review
|
||||
2. PR-MILESTONE returns AT RISK with mitigations
|
||||
3. Skill asks via `AskUserQuestion`: "Producer verdict: AT RISK. Milestone may
|
||||
slip. How should the Go/No-Go section be framed?" with [A] CONDITIONAL GO,
|
||||
[B] NO-GO, [C] GO
|
||||
4. User selects [A]; the Go/No-Go section reads CONDITIONAL GO and lists the
|
||||
producer's conditions
|
||||
5. Skill presents the review, asks "May I write", and writes on approval
|
||||
|
||||
**Assertions:**
|
||||
- [ ] CONCERNS from PR-MILESTONE gate are shown to user before write
|
||||
- [ ] Scope drift is explicitly noted in the written review document
|
||||
- [ ] Verdict is MILESTONE COMPLETE (stories shipped) with CONCERNS annotation
|
||||
- [ ] Skill does not suppress gate feedback
|
||||
- [ ] The producer's AT RISK assessment, including its scope-drift finding, is shown inline in the Go/No-Go section — not suppressed
|
||||
- [ ] AT RISK raises the `AskUserQuestion` with CONDITIONAL GO / NO-GO / GO before the file is written
|
||||
- [ ] After [A], the recommendation is CONDITIONAL GO and its Conditions list carries the producer's conditions
|
||||
- [ ] The review is written only after "May I write" is approved
|
||||
|
||||
---
|
||||
|
||||
### Case 4: Edge Case — No milestone file found for specified milestone
|
||||
### Case 4: Edge Case — No milestone definition and no sprint data
|
||||
|
||||
**Fixture:**
|
||||
- User calls `/milestone-review milestone-07`
|
||||
- `production/milestones/milestone-07.md` does NOT exist
|
||||
- `production/milestones/` does not exist
|
||||
- `production/sprints/` does not exist
|
||||
- `production/risk-register/` does not exist
|
||||
- No source files exist under the code root
|
||||
- No story files, no `production/sprint-status.yaml` and no `production/qa/bugs/`
|
||||
- `project.yaml` sets `modes.review_mode: full`
|
||||
|
||||
**Input:** `/milestone-review milestone-07`
|
||||
**Input:** `/milestone-review current`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill attempts to read `production/milestones/milestone-07.md`
|
||||
2. File not found; skill outputs an error message
|
||||
3. Skill suggests checking available milestones in `production/milestones/`
|
||||
4. No gate is invoked; no file is written
|
||||
1. Skill lists its inputs and records each as FOUND or ABSENT
|
||||
2. Every required input is ABSENT, so the skill stops and reports
|
||||
`NOT ASSESSED — NO DATA` as the whole verdict
|
||||
3. The report names what was missing and where it comes from: sprint reports
|
||||
are written by `/sprint-plan`; milestone definitions are authored by hand
|
||||
from `.claude/docs/templates/milestone-definition.md`
|
||||
4. No milestone definition is fabricated, no gate is spawned, no file is written
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Skill does not crash when milestone file is absent
|
||||
- [ ] Output names the expected file path in the error message
|
||||
- [ ] Output suggests checking `production/milestones/` for valid milestone names
|
||||
- [ ] Verdict is BLOCKED (cannot review a non-existent milestone)
|
||||
- [ ] Skill does not crash and does not fill the review template with estimated values
|
||||
- [ ] Verdict is `NOT ASSESSED — NO DATA` — not GO and not COMPLETE
|
||||
- [ ] Output names the missing inputs and where each comes from (`/sprint-plan` for sprint reports; the milestone-definition template for milestones)
|
||||
- [ ] PR-MILESTONE is not spawned and no "May I write" prompt appears
|
||||
|
||||
---
|
||||
|
||||
### Case 5: Lean/Solo Mode — PR-MILESTONE gate skipped
|
||||
|
||||
**Fixture:**
|
||||
- `production/milestones/milestone-03.md` exists with 5 complete stories
|
||||
- `review-mode.txt` contains `solo`
|
||||
- `production/milestones/milestone-03.md` lists 5 features, all `Status: Complete`
|
||||
- Sprint reports exist in `production/sprints/`
|
||||
- `production/qa/bugs/` does not exist — no bug has been filed with `/bug-report`
|
||||
- `project.yaml` sets `modes.review_mode: solo`
|
||||
|
||||
**Input:** `/milestone-review milestone-03`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads review mode — determines `solo`
|
||||
2. Skill compiles review draft
|
||||
3. PR-MILESTONE gate is skipped; output notes "[PR-MILESTONE] skipped — Solo mode"
|
||||
4. Skill asks user for direct approval of the review
|
||||
5. User approves; review file is written; verdict MILESTONE COMPLETE
|
||||
1. Skill reads `review_mode` from the injected config block — `solo`
|
||||
2. Skill compiles the review; with no bug files, the Quality Metrics bug lines
|
||||
read `NOT ASSESSED — NO DATA`
|
||||
3. PR-MILESTONE is skipped; output notes "PR-MILESTONE skipped — Solo mode."
|
||||
4. The Go/No-Go section is presented without a producer verdict
|
||||
5. Skill asks "May I write this to `production/milestones/milestone-03-review.md`?"
|
||||
6. User approves; review file is written; verdict COMPLETE
|
||||
|
||||
**Assertions:**
|
||||
- [ ] PR-MILESTONE gate is NOT invoked in solo (or lean) mode
|
||||
- [ ] Skip is explicitly noted in skill output
|
||||
- [ ] User direct approval is still required before write
|
||||
- [ ] Verdict is MILESTONE COMPLETE after successful write
|
||||
- [ ] PR-MILESTONE gate is NOT invoked in solo mode
|
||||
- [ ] Output contains "PR-MILESTONE skipped — Solo mode."
|
||||
- [ ] The Go/No-Go section carries no producer verdict (no ON TRACK / AT RISK / OFF TRACK attributed to the producer)
|
||||
- [ ] The Quality Metrics bug lines read `NOT ASSESSED — NO DATA` — not "0" — while the sections that have inputs are still produced
|
||||
- [ ] User approval is still required before the write
|
||||
- [ ] Verdict is COMPLETE after the write
|
||||
|
||||
---
|
||||
|
||||
### Case 6: Lean Mode from Rigor — PR-MILESTONE skipped with the Lean note
|
||||
|
||||
**Fixture:**
|
||||
- `production/milestones/milestone-03.md` lists 4 features, all `Status: Complete`
|
||||
- Sprint reports exist in `production/sprints/`
|
||||
- `project.yaml` sets `modes.rigor: standard` and pins no review mode, so the
|
||||
injected block reads `review_mode: lean (rigor:standard)`
|
||||
|
||||
**Input:** `/milestone-review milestone-03`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads `review_mode` from the injected config block — `lean`
|
||||
2. Skill compiles the review
|
||||
3. PR-MILESTONE is skipped; output notes "PR-MILESTONE skipped — Lean mode."
|
||||
4. The Go/No-Go section is presented without a producer verdict
|
||||
5. Skill asks "May I write", writes on approval; verdict COMPLETE
|
||||
|
||||
**Assertions:**
|
||||
- [ ] PR-MILESTONE gate is NOT invoked in lean mode
|
||||
- [ ] Output contains "PR-MILESTONE skipped — Lean mode." — not the Solo note
|
||||
- [ ] The Go/No-Go section carries no producer verdict
|
||||
- [ ] User approval is still required before the write, and the verdict is COMPLETE after it
|
||||
|
||||
---
|
||||
|
||||
### Case 7: Gate returns NOT ASSESSED — Never GO
|
||||
|
||||
**Fixture:**
|
||||
- `production/milestones/milestone-03.md` lists 5 features, all `Status: Complete`,
|
||||
but gives no Target Date
|
||||
- Sprint reports exist in `production/sprints/`; the stories exist under
|
||||
`production/epics/` and none is `Blocked`
|
||||
- `project.yaml` sets `modes.review_mode: full`
|
||||
- The producer returns NOT ASSESSED — no target date to judge against
|
||||
- Asked for the date, the user has none to give
|
||||
|
||||
**Input:** `/milestone-review milestone-03`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill compiles the review and spawns PR-MILESTONE; it returns NOT ASSESSED
|
||||
2. Skill names the missing input (the target date) and treats the result as
|
||||
neither ON TRACK nor a reason to recommend GO
|
||||
3. Nothing in the review's own findings calls for CONDITIONAL GO or NO-GO, so
|
||||
the Go/No-Go recommendation reads NOT ASSESSED, naming the missing target date
|
||||
4. Skill asks "May I write", writes on approval; verdict COMPLETE
|
||||
|
||||
**Assertions:**
|
||||
- [ ] The Go/No-Go recommendation is NOT ASSESSED — never GO — although every feature is Complete
|
||||
- [ ] The missing target date is named in the Go/No-Go section
|
||||
- [ ] The AT RISK and OFF TRACK framing questions are not raised for NOT ASSESSED
|
||||
- [ ] "May I write" still appears before the file is written
|
||||
|
||||
---
|
||||
|
||||
## Protocol Compliance
|
||||
|
||||
- [ ] Shows compiled review draft before invoking PR-MILESTONE or asking to write
|
||||
- [ ] Always asks "May I write" before writing review document
|
||||
- [ ] PR-MILESTONE gate only runs in full mode
|
||||
- [ ] Skip message appears in lean and solo output
|
||||
- [ ] Verdict is MILESTONE COMPLETE or MILESTONE INCOMPLETE, stated clearly
|
||||
- [ ] Records each input as FOUND or ABSENT before producing a report; reports `NOT ASSESSED — NO DATA` when every required input is absent, and for any single section whose inputs are absent
|
||||
- [ ] In full mode, spawns PR-MILESTONE before generating the Go/No-Go recommendation, and presents the complete review before asking to write
|
||||
- [ ] Always asks "May I write" before writing the review document
|
||||
- [ ] PR-MILESTONE gate only runs in full mode; the skip message appears in lean and solo output
|
||||
- [ ] Verdict is stated clearly — COMPLETE, BLOCKED (write declined) or `NOT ASSESSED — NO DATA` — and the Go/No-Go recommendation is one of NOT ASSESSED / GO / CONDITIONAL GO / NO-GO
|
||||
|
||||
---
|
||||
|
||||
## Coverage Notes
|
||||
|
||||
- The case where the milestone has zero stories is not tested; it follows the
|
||||
MILESTONE INCOMPLETE pattern with a note suggesting the milestone may not
|
||||
have been planned.
|
||||
- `production/milestones/` absent while sprint reports exist (the skill says so
|
||||
and reviews against the sprint reports alone) is not tested.
|
||||
- `current` selection skipping files that end `-review.md` is not tested.
|
||||
- The declined-write path (verdict BLOCKED) is not tested.
|
||||
- Velocity calculation specifics (story points vs. story count) are not
|
||||
verified here; they are implementation details of the review compilation phase.
|
||||
|
||||
@@ -2,24 +2,36 @@
|
||||
|
||||
## Skill Summary
|
||||
|
||||
`/patch-notes` is a Haiku-tier skill that generates player-facing patch notes
|
||||
from existing changelog content, stripping internal task IDs and technical
|
||||
jargon in favor of plain language. It filters entries to only those relevant
|
||||
to players (visible features and bug fixes; internal refactors are excluded).
|
||||
No director gates are used. The skill asks "May I write to
|
||||
`docs/patch-notes-vX.X.md`?" before persisting. Verdict is always COMPLETE.
|
||||
`/patch-notes` is a Sonnet-tier skill that turns a release's changes into
|
||||
player-facing patch notes. Before reading any history it classifies recent
|
||||
commits as Game or Framework / maintenance (Unclear counts as Framework), uses
|
||||
only the Game commits, and says how many of how many it used. It gathers change
|
||||
data from `production/releases/[version]/changelog.md`, the version's entry in
|
||||
`docs/CHANGELOG.md`, and — as a fallback — `git log` from the previous release
|
||||
tag. It checks for a tone guide (`.claude/docs/technical-preferences.md`,
|
||||
`docs/PATCH-NOTES-STYLE.md`, `design/community/tone-guide.md`) and a patch-notes
|
||||
template (`docs/patch-notes-template.md`,
|
||||
`.claude/docs/templates/patch-notes-template.md`), removes internal-only
|
||||
changes, and translates the rest into player language in Brief, Detailed
|
||||
(default) or Full style — or in the template's structure when one exists, saying
|
||||
which template it used. No director gates are used. The skill asks "May I write
|
||||
these patch notes to `docs/patch-notes/[version].md`, and an archive copy to
|
||||
`production/releases/[version]/patch-notes.md`?" — naming both files — and on
|
||||
approval writes both. Verdicts:
|
||||
COMPLETE (notes generated and saved) or BLOCKED (no changelog data and no git
|
||||
history, or no Game commit in the history).
|
||||
|
||||
---
|
||||
|
||||
## Static Assertions (Structural)
|
||||
|
||||
Verified automatically by `/skill-test static` — no fixture needed.
|
||||
Checked against the SKILL.md by `/skill-test spec` — no fixture needed.
|
||||
|
||||
- [ ] Has required frontmatter fields: `name`, `description`, `argument-hint`, `user-invocable`, `allowed-tools`
|
||||
- [ ] Has ≥2 phase headings
|
||||
- [ ] Contains verdict keyword: COMPLETE
|
||||
- [ ] Contains verdict keywords: COMPLETE, BLOCKED
|
||||
- [ ] Contains "May I write" language (skill writes patch notes file)
|
||||
- [ ] Has a next-step handoff (e.g., share with community manager)
|
||||
- [ ] Has a next-step handoff (`/release-checklist`, community-manager tone review)
|
||||
|
||||
---
|
||||
|
||||
@@ -34,137 +46,216 @@ None. Patch notes generation is a fast compilation task; no gates are invoked.
|
||||
### Case 1: Happy Path — Changelog filtered to player-facing entries
|
||||
|
||||
**Fixture:**
|
||||
- `docs/CHANGELOG.md` exists with 5 entries:
|
||||
- "Add dual-wield melee system" (Features — player-facing)
|
||||
- "Fix crash on level transition" (Fixes — player-facing)
|
||||
- "Add enemy patrol AI" (Features — player-facing)
|
||||
- "Refactor input handler to use event bus" (Fixes — internal only)
|
||||
- `docs/CHANGELOG.md` has a `v0.4.0` entry with 5 items:
|
||||
- "Add dual-wield melee system" (player-facing)
|
||||
- "Fix crash on level transition" (player-facing)
|
||||
- "Add enemy patrol AI" (player-facing)
|
||||
- "Refactor input handler to use event bus" (internal only)
|
||||
- "Update dependency: Godot 4.6" (internal only)
|
||||
- Version is `v0.4.0`
|
||||
- Git history since the previous tag holds the Game commits behind those items
|
||||
- No tone guide and no patch-notes template exist
|
||||
|
||||
**Input:** `/patch-notes v0.4.0`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads `docs/CHANGELOG.md`
|
||||
2. Skill filters to 3 player-facing entries; excludes 2 internal entries
|
||||
3. Skill rewrites entries in plain language (no task IDs, no tech jargon)
|
||||
4. Skill presents draft to user
|
||||
5. Skill asks "May I write to `docs/patch-notes-v0.4.0.md`?"
|
||||
6. User approves; file written; verdict COMPLETE
|
||||
1. Skill classifies the recent commits and says how many of how many it used
|
||||
2. Skill reads the `v0.4.0` entry in `docs/CHANGELOG.md`
|
||||
3. No tone guide is found, so the default tone applies; no template is found,
|
||||
so the built-in Detailed style (the default `--style`) is used
|
||||
4. Skill keeps the 3 player-facing items and removes the 2 internal ones
|
||||
5. Skill rewrites the items in player language (no task IDs, no internal system
|
||||
names)
|
||||
6. Skill presents the notes with a count of changes by category and the list of
|
||||
excluded internal changes
|
||||
7. Skill asks "May I write these patch notes to `docs/patch-notes/v0.4.0.md`, and an archive copy to `production/releases/v0.4.0/patch-notes.md`?"
|
||||
8. User approves; both files are written; verdict COMPLETE
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Only 3 entries appear in the patch notes (2 internal entries excluded)
|
||||
- [ ] Entries are written in plain language without internal task IDs
|
||||
- [ ] File path matches `docs/patch-notes-v0.4.0.md`
|
||||
- [ ] "May I write" prompt appears before file write
|
||||
- [ ] Verdict is COMPLETE after write
|
||||
- [ ] Only the 3 player-facing items appear in the notes; the 2 internal items are listed separately as excluded, for review
|
||||
- [ ] Entries are written in plain language without internal task IDs or system names
|
||||
- [ ] Notes use the built-in Detailed style (Highlights, New Content, … Known Issues) — the default when no `--style` is given and no template exists
|
||||
- [ ] "May I write" prompt naming `docs/patch-notes/v0.4.0.md` appears before any file is written
|
||||
- [ ] Verdict is COMPLETE after the write
|
||||
|
||||
---
|
||||
|
||||
### Case 2: No Changelog Found — Directed to run /changelog first
|
||||
### Case 2: No Changelog File — Falls back to git history
|
||||
|
||||
**Fixture:**
|
||||
- `docs/CHANGELOG.md` does NOT exist
|
||||
- Neither `production/releases/v0.4.0/changelog.md` nor `docs/CHANGELOG.md` exists
|
||||
- Tag `v0.3.0` exists; the range `v0.3.0..HEAD` holds 6 Game commits and 2
|
||||
Framework / maintenance commits (one touching a hook, one touching CI)
|
||||
|
||||
**Input:** `/patch-notes v0.4.0`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill attempts to read `docs/CHANGELOG.md` — not found
|
||||
2. Skill outputs: "No changelog found — run /changelog first to generate one"
|
||||
3. No patch notes are generated; no file is written
|
||||
1. Skill classifies the commits, keeps the Game commits, excludes the 2
|
||||
framework commits, and says how many of how many it used
|
||||
2. Skill finds no changelog source and uses `git log` from `v0.3.0` to HEAD as
|
||||
the fallback
|
||||
3. Skill does NOT stop with BLOCKED — the "No changelog data found … Run
|
||||
`/changelog [version]` first" path requires the git history to be empty or
|
||||
unavailable as well
|
||||
4. Skill generates notes from the Game commits only
|
||||
5. Skill asks "May I write" before writing
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Skill does not crash when changelog is absent
|
||||
- [ ] Output explicitly directs user to run `/changelog`
|
||||
- [ ] No "May I write" prompt appears (nothing to write)
|
||||
- [ ] Verdict is BLOCKED (dependency not met)
|
||||
- [ ] Skill does not crash and does not stop with BLOCKED while git history is available
|
||||
- [ ] Skill falls back to `git log` from the previous tag (`v0.3.0`) to HEAD
|
||||
- [ ] Output states how many of how many commits were used
|
||||
- [ ] The 2 framework / maintenance commits do not appear in the patch notes
|
||||
- [ ] "May I write" prompt appears before any file is written
|
||||
|
||||
---
|
||||
|
||||
### Case 3: Tone Guidance from Design Folder — Incorporated into output
|
||||
|
||||
**Fixture:**
|
||||
- `docs/CHANGELOG.md` exists with player-facing entries
|
||||
- `docs/CHANGELOG.md` has a `v0.4.0` entry with player-facing items; git history
|
||||
holds the matching Game commits
|
||||
- `design/community/tone-guide.md` exists with guidance: "upbeat, encouraging tone; avoid passive voice"
|
||||
- `docs/PATCH-NOTES-STYLE.md` does not exist and
|
||||
`.claude/docs/technical-preferences.md` has no tone, voice or style fields
|
||||
- No patch-notes template exists
|
||||
|
||||
**Input:** `/patch-notes v0.4.0`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads changelog
|
||||
2. Skill detects tone guide at `design/community/tone-guide.md`
|
||||
3. Skill applies tone guidance when rewriting entries in plain language
|
||||
4. Patch notes use upbeat, active-voice phrasing
|
||||
5. Skill presents draft, asks to write, writes on approval
|
||||
1. Skill reads the changelog entry
|
||||
2. Skill checks the three tone sources and finds `design/community/tone-guide.md`
|
||||
3. Skill extracts the guide's instructions and applies them to the language and
|
||||
framing of the notes, in place of the built-in default tone
|
||||
4. Structure stays the built-in Detailed style
|
||||
5. Skill presents the notes, asks "May I write", writes on approval
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Skill checks `design/` for a community or tone guidance file
|
||||
- [ ] Tone guide content influences phrasing of patch note entries
|
||||
- [ ] Output reflects active voice and upbeat tone where applicable
|
||||
- [ ] Skill notes that tone guidance was applied
|
||||
- [ ] Skill checks the tone sources in Phase 2b, including `design/community/tone-guide.md`
|
||||
- [ ] The tone guide's instructions are applied in place of the built-in default tone
|
||||
- [ ] Entries use active voice ("Fixed a crash when…", "You can now…"), not passive ("A crash was fixed")
|
||||
- [ ] Tone guidance changes wording only — the output structure is still the Detailed style
|
||||
|
||||
---
|
||||
|
||||
### Case 4: Patch Note Template Exists — Used instead of generated structure
|
||||
### Case 4: Patch Note Template Exists — Used instead of the built-in styles
|
||||
|
||||
**Fixture:**
|
||||
- `.claude/docs/templates/patch-notes-template.md` exists with a structured header format
|
||||
- `docs/CHANGELOG.md` exists with player-facing entries
|
||||
- `.claude/docs/templates/patch-notes-template.md` exists with a header block,
|
||||
the sections `## New`, `## Fixed` and `## Known Issues`, and a footer
|
||||
- `docs/CHANGELOG.md` has a `v0.4.0` entry with one new feature and one bug fix,
|
||||
both player-facing; git history holds the matching Game commits
|
||||
|
||||
**Input:** `/patch-notes v0.4.0`
|
||||
**Input:** `/patch-notes v0.4.0 --style full`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads changelog and detects template exists
|
||||
2. Skill populates the template with player-facing entries
|
||||
3. Template header/footer structure is preserved in the output
|
||||
4. Skill asks "May I write" and writes on approval
|
||||
1. Skill globs `docs/patch-notes-template.md` and
|
||||
`.claude/docs/templates/patch-notes-template.md`; finds and reads the second
|
||||
2. Skill uses the template as the output structure instead of the built-in
|
||||
Brief / Detailed / Full templates — even though `--style full` was passed
|
||||
3. The new feature goes under `## New`, the fix under `## Fixed`
|
||||
4. The template's header and footer are preserved
|
||||
5. The output says the template was used and that it replaced `--style full`
|
||||
6. Skill asks "May I write" and writes on approval
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Skill checks for a patch notes template before generating from scratch
|
||||
- [ ] Template structure is used when found (not overridden by default format)
|
||||
- [ ] Player-facing entries are inserted into the correct template section
|
||||
- [ ] Output note confirms template was used
|
||||
- [ ] Skill globs both template locations before generating
|
||||
- [ ] The template's structure replaces the built-in style — no "Developer Commentary" section from the Full style despite `--style full`
|
||||
- [ ] The new feature is placed under `## New` and the fix under `## Fixed`
|
||||
- [ ] The template's header and footer are preserved in the output
|
||||
- [ ] Output notes that `.claude/docs/templates/patch-notes-template.md` was used, and that it replaced the requested `--style full`
|
||||
|
||||
---
|
||||
|
||||
### Case 5: Gate Compliance — No gate; community-manager is separate
|
||||
|
||||
**Fixture:**
|
||||
- `docs/CHANGELOG.md` exists with player-facing entries
|
||||
- `review-mode.txt` contains `full`
|
||||
- `docs/CHANGELOG.md` has a `v0.4.0` entry with player-facing items; git history
|
||||
holds the matching Game commits
|
||||
- `project.yaml` sets `modes.review_mode: full`
|
||||
|
||||
**Input:** `/patch-notes v0.4.0`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill compiles patch notes in full mode
|
||||
2. No director gate is invoked (community review is a separate, manual step)
|
||||
3. Skill runs on Haiku model — fast compilation
|
||||
4. Skill notes in output: "Consider sharing draft with community manager before publishing"
|
||||
5. Skill asks user for approval and writes on confirmation
|
||||
1. Skill compiles patch notes; no director gate is spawned (the skill resolves
|
||||
only `automation`, never `review_mode`)
|
||||
2. Skill self-reviews the notes (Phase 5), then presents them and asks to write
|
||||
3. Next steps suggest `/release-checklist` and sharing the draft with the
|
||||
community-manager for tone review before posting publicly
|
||||
4. User approves; notes are written; verdict COMPLETE
|
||||
|
||||
**Assertions:**
|
||||
- [ ] No director gate is invoked regardless of review mode
|
||||
- [ ] Output suggests (but does not require) community manager review
|
||||
- [ ] Skill proceeds directly from compilation to "May I write" prompt
|
||||
- [ ] Output suggests (but does not require) a community-manager tone review before posting
|
||||
- [ ] Skill proceeds directly from compilation and self-review to the "May I write" prompt
|
||||
- [ ] Verdict is COMPLETE
|
||||
|
||||
---
|
||||
|
||||
### Case 6: Provenance Stop — Zero Game commits
|
||||
|
||||
**Fixture:**
|
||||
- `git log --oneline -20` shows 20 commits, all touching the framework or
|
||||
tooling — subjects such as "fix: session-start hook timeout", "docs: skill
|
||||
catalog", "ci: cache the test runner" — and none names a game system in
|
||||
`design/` or the code root
|
||||
- Neither `production/releases/v0.4.0/changelog.md` nor `docs/CHANGELOG.md` exists
|
||||
|
||||
**Input:** `/patch-notes v0.4.0`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Before Phase 2, skill classifies the sampled commits: 0 Game, 20 Framework /
|
||||
maintenance
|
||||
2. Skill stops with "The git history in this repo does not appear to belong to
|
||||
[game] …", describing what the commits actually cover
|
||||
3. No notes are generated and nothing is written; verdict BLOCKED
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Output names the classification result — 0 of 20 commits are Game commits
|
||||
- [ ] Output contains the "does not appear to belong to" stop, not notes written from framework commits (no "Fixed an issue where …" line from a hook fix)
|
||||
- [ ] No "May I write" prompt appears and no file is written
|
||||
- [ ] Verdict is BLOCKED, not COMPLETE
|
||||
|
||||
---
|
||||
|
||||
### Case 7: No Changelog Data — No changelog and no git history
|
||||
|
||||
**Fixture:**
|
||||
- Neither `production/releases/v0.4.0/changelog.md` nor `docs/CHANGELOG.md` exists
|
||||
- The project directory is not a git repository, so `git log` returns nothing
|
||||
|
||||
**Input:** `/patch-notes v0.4.0`
|
||||
|
||||
**Expected behavior:**
|
||||
1. The sampled log is empty, so the provenance check is skipped — there is
|
||||
nothing to classify
|
||||
2. Phase 2 finds no changelog source and no git history; skill outputs "No
|
||||
changelog data found for v0.4.0. Run `/changelog v0.4.0` first to generate
|
||||
the internal changelog, then re-run `/patch-notes v0.4.0`."
|
||||
3. Nothing is generated or written; verdict BLOCKED
|
||||
|
||||
**Assertions:**
|
||||
- [ ] The "does not appear to belong to" provenance stop is NOT shown — an empty history is not a wrong history
|
||||
- [ ] Output contains "No changelog data found for v0.4.0" and recommends `/changelog v0.4.0`
|
||||
- [ ] No notes are generated, no "May I write" prompt appears, and no file is written
|
||||
- [ ] Verdict is BLOCKED
|
||||
|
||||
---
|
||||
|
||||
## Protocol Compliance
|
||||
|
||||
- [ ] Reads `docs/CHANGELOG.md` before generating patch notes
|
||||
- [ ] Filters entries to player-facing items only
|
||||
- [ ] Runs the provenance check before reading history, uses only Game commits, and says how many were used
|
||||
- [ ] Reads the version's changelog entry (`production/releases/[version]/changelog.md`, `docs/CHANGELOG.md`) before falling back to `git log`
|
||||
- [ ] Filters entries to player-facing items only, and lists the excluded internal changes for review
|
||||
- [ ] Rewrites entries in plain language without internal IDs
|
||||
- [ ] Always asks "May I write" before writing patch notes file
|
||||
- [ ] Always asks "May I write" before writing patch notes
|
||||
- [ ] No director gates are invoked
|
||||
- [ ] Runs on Haiku model tier (fast, low-cost)
|
||||
- [ ] Declares `model: sonnet` — it writes player-facing copy
|
||||
|
||||
---
|
||||
|
||||
## Coverage Notes
|
||||
|
||||
- A missing version argument (the skill asks before proceeding) is not tested.
|
||||
- The case where all changelog entries are internal (zero player-facing items)
|
||||
is not tested; behavior is an empty patch notes draft with a warning.
|
||||
- Version number parsing from the changelog header is an implementation detail
|
||||
not verified here.
|
||||
is not tested.
|
||||
- The community manager consultation noted in Case 5 is advisory; a separate
|
||||
skill or manual review handles that step.
|
||||
|
||||
@@ -2,26 +2,38 @@
|
||||
|
||||
## Skill Summary
|
||||
|
||||
`/retrospective` generates a structured sprint or milestone retrospective
|
||||
covering three categories: what went well, what didn't, and action items.
|
||||
It reads sprint files and session logs to compile observations, then produces
|
||||
a retrospective document. No director gates are used — retrospectives are
|
||||
team self-reflection artifacts. The skill asks "May I write to
|
||||
`production/retrospectives/retro-sprint-NNN.md`?" before persisting.
|
||||
Verdict is always COMPLETE (retrospective is structured output, not a pass/fail
|
||||
assessment).
|
||||
`/retrospective` generates a sprint or milestone retrospective. Before loading
|
||||
any data it checks `production/retrospectives/` for an existing retrospective and
|
||||
offers to update it or start fresh (archiving the old file). It reads the sprint
|
||||
plan from `production/sprints/` (or the milestone definition), uses
|
||||
`production/sprint-status.yaml` as the primary source for completion when it
|
||||
exists, runs `git log` for the sprint period, counts TODO/FIXME/HACK markers, and
|
||||
reads previous retrospectives to follow up their action items. The output covers
|
||||
Metrics, Velocity Trend, What Went Well, What Went Poorly, Blockers Encountered,
|
||||
Estimation Accuracy, Carryover Analysis, Technical Debt Status, Previous Action
|
||||
Items Follow-Up, Action Items for Next Iteration, Process Improvements and a
|
||||
Summary; a section whose inputs are absent reads `NOT ASSESSED — NO DATA`, and
|
||||
every `blocked` story in the yaml is a Blocker with an action item. When no
|
||||
sprint data exists it offers manual input or stop — and, at `workflow: minimal`,
|
||||
a look back over the closed stories. No director gates are used —
|
||||
retrospectives are team self-reflection artifacts. The skill asks "May I write
|
||||
this to `production/retrospectives/retro-sprint-[N]-[date].md`?" (naming the
|
||||
archive rename too after Start fresh) and afterwards offers to start
|
||||
`/sprint-plan new`. Verdicts: COMPLETE
|
||||
(retrospective saved) or BLOCKED (user stopped at the no-data prompt or declined
|
||||
the write).
|
||||
|
||||
---
|
||||
|
||||
## Static Assertions (Structural)
|
||||
|
||||
Verified automatically by `/skill-test static` — no fixture needed.
|
||||
Checked against the SKILL.md by `/skill-test spec` — no fixture needed.
|
||||
|
||||
- [ ] Has required frontmatter fields: `name`, `description`, `argument-hint`, `user-invocable`, `allowed-tools`
|
||||
- [ ] Has ≥2 phase headings
|
||||
- [ ] Contains verdict keyword: COMPLETE
|
||||
- [ ] Contains verdict keywords: COMPLETE, BLOCKED
|
||||
- [ ] Contains "May I write" language (skill writes retrospective document)
|
||||
- [ ] Has a next-step handoff (what to do after retrospective is written)
|
||||
- [ ] Has a next-step handoff (offer to start `/sprint-plan new`; `/gate-check` after a milestone retrospective)
|
||||
|
||||
---
|
||||
|
||||
@@ -36,26 +48,38 @@ None. Retrospectives are team self-reflection documents; no gates are invoked.
|
||||
### Case 1: Happy Path — Sprint with mixed outcomes
|
||||
|
||||
**Fixture:**
|
||||
- `production/sprints/sprint-005.md` exists with 6 stories (4 Complete, 1 Blocked, 1 Deferred)
|
||||
- `production/session-logs/` contains log entries for the sprint period
|
||||
- No prior retrospective exists for sprint-005
|
||||
- `production/sprints/sprint-005.md` exists with 6 stories; no earlier sprint
|
||||
plan exists in `production/sprints/`
|
||||
- `production/sprint-status.yaml` covers sprint 5: 4 stories `done`, 1 `blocked`
|
||||
(`blocker: "Waiting on the save-format decision"`), 1 still `backlog`
|
||||
- `project.yaml` sets `modes.workflow: standard`
|
||||
- `production/retrospectives/` holds no retrospective at all
|
||||
|
||||
**Input:** `/retrospective sprint-005`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads sprint-005 and session logs
|
||||
2. Skill compiles three retrospective categories: went well (4 stories shipped),
|
||||
didn't (1 blocked, 1 deferred), and action items (address blocker root cause)
|
||||
3. Skill presents retrospective draft to user
|
||||
4. Skill asks "May I write to `production/retrospectives/retro-sprint-005.md`?"
|
||||
5. User approves; file is written; verdict COMPLETE
|
||||
1. Skill globs `production/retrospectives/retro-sprint-005-*.md` — no match
|
||||
2. Skill reads the sprint plan and `production/sprint-status.yaml`, using the
|
||||
yaml as the primary source for completion (4 of 6 done)
|
||||
3. Skill runs `git log` for the sprint period and counts TODO/FIXME/HACK markers
|
||||
4. Skill generates the retrospective in its template. With no earlier sprint or
|
||||
retrospective, Velocity Trend and Previous Action Items Follow-Up read
|
||||
`NOT ASSESSED — NO DATA`, naming what is missing
|
||||
5. Skill presents the retrospective and top findings (completion rate, velocity
|
||||
trend — reported as not assessed — top blocker, most important action item)
|
||||
6. Skill asks "May I write this to
|
||||
`production/retrospectives/retro-sprint-005-[today's date].md`?"
|
||||
7. User approves; file is written; verdict COMPLETE
|
||||
8. Skill asks whether to start sprint planning now (`/sprint-plan new`)
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Retrospective contains all three categories (went well / didn't / actions)
|
||||
- [ ] Blocked and deferred stories appear in the "what didn't" section
|
||||
- [ ] At least one action item is generated from the blocked story
|
||||
- [ ] Skill asks "May I write" before writing file
|
||||
- [ ] Verdict is COMPLETE after successful write
|
||||
- [ ] Retrospective contains What Went Well, What Went Poorly and Action Items for Next Iteration sections
|
||||
- [ ] Completion metrics come from `production/sprint-status.yaml` (4 of 6 done), not from markdown scanning
|
||||
- [ ] The blocked story appears under Blockers Encountered with "Waiting on the save-format decision" as its Blocker, and an action item addresses it
|
||||
- [ ] Velocity Trend reads `NOT ASSESSED — NO DATA` — no Increasing / Stable / Decreasing trend and no earlier-sprint rows are invented from a single sprint
|
||||
- [ ] Previous Action Items Follow-Up reads `NOT ASSESSED — NO DATA` (no earlier retrospective), not an empty table
|
||||
- [ ] "May I write" prompt names `production/retrospectives/retro-sprint-005-[today's date].md` and appears before the write
|
||||
- [ ] Verdict is COMPLETE after the write, followed by the offer to start `/sprint-plan new`
|
||||
|
||||
---
|
||||
|
||||
@@ -63,68 +87,85 @@ None. Retrospectives are team self-reflection documents; no gates are invoked.
|
||||
|
||||
**Fixture:**
|
||||
- User calls `/retrospective sprint-009`
|
||||
- `production/sprints/sprint-009.md` does NOT exist
|
||||
- No session logs reference sprint-009
|
||||
- `production/sprints/sprint-009.md` does NOT exist and
|
||||
`production/sprint-status.yaml` has no sprint 9
|
||||
- `project.yaml` sets `modes.workflow: standard`
|
||||
- No retrospective for sprint-009 exists
|
||||
|
||||
**Input:** `/retrospective sprint-009`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill attempts to read sprint-009 — not found
|
||||
2. Skill informs user that no sprint data was found for sprint-009
|
||||
3. Skill prompts user to provide retrospective input manually (went well, didn't, actions)
|
||||
4. User provides input; skill formats it into the retrospective structure
|
||||
5. Skill asks "May I write" and writes the document on approval
|
||||
1. Skill finds no sprint plan for sprint-009
|
||||
2. Skill outputs "No sprint data found for sprint-009 …"
|
||||
3. Skill asks via `AskUserQuestion`: [A] Provide data manually, [B] Stop
|
||||
4. User selects [A] and describes the sprint's tasks, dates and outcomes
|
||||
5. Skill uses that input as the source of truth and formats it into the
|
||||
retrospective structure
|
||||
6. Skill asks "May I write" and writes the document on approval
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Skill does not crash or produce an empty document when sprint file is absent
|
||||
- [ ] User is prompted to provide manual input
|
||||
- [ ] Manual input is formatted into the three-category structure
|
||||
- [ ] "May I write" prompt still appears before file write
|
||||
- [ ] Skill does not crash or produce an empty document when the sprint file is absent, and states that no sprint data was found for sprint-009
|
||||
- [ ] `AskUserQuestion` offers [A] Provide data manually and [B] Stop — not [C] Look back over the closed stories, which is offered only at `workflow: minimal`
|
||||
- [ ] Manual input is formatted into the retrospective structure (What Went Well / What Went Poorly / Action Items for Next Iteration)
|
||||
- [ ] "May I write" prompt still appears before the file write
|
||||
|
||||
---
|
||||
|
||||
### Case 3: Prior Retrospective Exists — Offer to append or replace
|
||||
### Case 3: Prior Retrospective Exists — Update existing or start fresh
|
||||
|
||||
**Fixture:**
|
||||
- `production/retrospectives/retro-sprint-005.md` already exists with content
|
||||
- User re-runs `/retrospective sprint-005` after changes
|
||||
- `production/retrospectives/retro-sprint-005-[earlier date].md` already exists
|
||||
with content
|
||||
- `production/sprints/sprint-005.md` exists
|
||||
- User re-runs `/retrospective sprint-005` and, when asked, selects [B] Start fresh
|
||||
|
||||
**Input:** `/retrospective sprint-005`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill detects that `retro-sprint-005.md` already exists
|
||||
2. Skill presents user with choice: append new observations or replace existing file
|
||||
3. User selects "replace"; skill compiles fresh retrospective
|
||||
4. Skill asks "May I write to `production/retrospectives/retro-sprint-005.md`?" (confirming overwrite)
|
||||
5. File is overwritten; verdict COMPLETE
|
||||
1. Before loading any sprint data, skill globs
|
||||
`production/retrospectives/retro-sprint-005-*.md` and finds the existing file
|
||||
2. Skill asks via `AskUserQuestion`: "An existing retrospective was found:
|
||||
[filename]. How do you want to proceed?" with [A] Update existing and
|
||||
[B] Start fresh (archive the old one)
|
||||
3. User selects [B]; skill compiles from a blank slate — the old file is not
|
||||
touched yet
|
||||
4. Skill asks "May I write this to
|
||||
`production/retrospectives/retro-sprint-005-[today's date].md`?", and the
|
||||
same ask names the rename of the old file to its `-archived-[date]` name
|
||||
5. User approves; skill renames the old file, then writes the new one; verdict
|
||||
COMPLETE
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Skill checks for existing retrospective file before compiling
|
||||
- [ ] User is offered append or replace choice — not silently overwritten
|
||||
- [ ] "May I write" prompt reflects the overwrite scenario
|
||||
- [ ] Verdict is COMPLETE after write regardless of append vs. replace
|
||||
- [ ] Skill checks for an existing retrospective before loading sprint data
|
||||
- [ ] User is offered Update existing or Start fresh — the old file is never silently overwritten
|
||||
- [ ] The old file is not renamed before the "May I write" prompt is approved, and that prompt names both the new dated path `retro-sprint-005-[today's date].md` and the rename
|
||||
- [ ] On approval, the old file is kept under an `-archived-[date]` name, not deleted or overwritten
|
||||
- [ ] Verdict is COMPLETE after the write
|
||||
|
||||
---
|
||||
|
||||
### Case 4: Edge Case — Unresolved action items from previous retrospective
|
||||
|
||||
**Fixture:**
|
||||
- `production/retrospectives/retro-sprint-004.md` exists with 2 action items marked `[ ]` (not done)
|
||||
- `production/retrospectives/retro-sprint-004-[date].md` exists with 2 action
|
||||
items marked `[ ]` (not done)
|
||||
- `production/sprints/sprint-005.md` exists; no retrospective for sprint-005 exists
|
||||
- User runs `/retrospective sprint-005`
|
||||
|
||||
**Input:** `/retrospective sprint-005`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads the most recent prior retrospective (retro-sprint-004)
|
||||
2. Skill detects 2 unchecked action items from sprint-004
|
||||
3. Skill includes a "Carry-over from Sprint 004" section in the new retrospective
|
||||
4. The unresolved items are listed with a note that they were not followed up
|
||||
1. Skill reads previous retrospectives in `production/retrospectives/`
|
||||
2. Skill checks whether the sprint-004 action items were addressed — 2 were not
|
||||
3. The new retrospective's "Previous Action Items Follow-Up" table lists both
|
||||
items with a status other than Done
|
||||
4. The follow-up table is separate from "Action Items for Next Iteration"
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Skill reads the most recent prior retrospective to check for open action items
|
||||
- [ ] Unresolved action items appear in the new retrospective under a carry-over section
|
||||
- [ ] Carry-over items are distinct from newly generated action items
|
||||
- [ ] Output notes that these items were not followed up in the previous sprint
|
||||
- [ ] Skill reads the prior retrospective in `production/retrospectives/` to check its action items
|
||||
- [ ] Both unresolved items appear in the "Previous Action Items Follow-Up" table
|
||||
- [ ] Their Status is Not Started or In Progress — not Done
|
||||
- [ ] The follow-up table is distinct from the newly generated "Action Items for Next Iteration"
|
||||
|
||||
---
|
||||
|
||||
@@ -132,38 +173,73 @@ None. Retrospectives are team self-reflection documents; no gates are invoked.
|
||||
|
||||
**Fixture:**
|
||||
- `production/sprints/sprint-005.md` exists with complete stories
|
||||
- `production/session-state/review-mode.txt` contains `full`
|
||||
- `project.yaml` sets `modes.review_mode: full`
|
||||
|
||||
**Input:** `/retrospective sprint-005`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill compiles retrospective in full mode
|
||||
1. Skill compiles the retrospective
|
||||
2. No director gate is invoked (retrospectives are team self-reflection, not delivery gates)
|
||||
3. Skill asks user for approval and writes file on confirmation
|
||||
3. Skill asks user for approval and writes the file on confirmation
|
||||
4. Verdict is COMPLETE
|
||||
|
||||
**Assertions:**
|
||||
- [ ] No director gate is invoked regardless of review mode
|
||||
- [ ] Output does not contain any gate invocation or gate result notation
|
||||
- [ ] Skill proceeds directly from compilation to "May I write" prompt
|
||||
- [ ] Review mode file content is irrelevant to this skill's behavior
|
||||
- [ ] Skill proceeds directly from compilation to the "May I write" prompt
|
||||
- [ ] `review_mode` is not among the keys the skill resolves (it resolves `automation`, `workflow`, `qa.level`)
|
||||
|
||||
---
|
||||
|
||||
### Case 6: Minimal Workflow — Look back over the closed stories
|
||||
|
||||
**Fixture:**
|
||||
- `project.yaml` sets neither `modes.rigor` nor `modes.workflow`, so the injected
|
||||
block reads `workflow: minimal (rigor:minimal)`
|
||||
- `production/sprints/`, `production/milestones/` and
|
||||
`production/retrospectives/` do not exist
|
||||
- 3 stories under `production/epics/core/` have `Status: Complete`; 1 has
|
||||
`Status: In Progress`
|
||||
|
||||
**Input:** `/retrospective sprint-001`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill finds no retrospective and no sprint data for sprint-001
|
||||
2. At `workflow: minimal`, skill asks via `AskUserQuestion` with three options:
|
||||
[A] Provide data manually, [B] Stop, [C] Look back over the closed stories
|
||||
3. User selects [C]; skill reads the 3 `Complete` stories and continues to
|
||||
Phase 3
|
||||
4. The retrospective covers those 3 stories; the sections that need sprint data
|
||||
(planned vs actual, velocity, carryover, estimation accuracy) read
|
||||
`NOT ASSESSED — NO DATA`
|
||||
5. Skill asks "May I write this to
|
||||
`production/retrospectives/retro-sprint-001-[today's date].md`?"; user
|
||||
approves; verdict COMPLETE
|
||||
|
||||
**Assertions:**
|
||||
- [ ] The no-data prompt offers [C] Look back over the closed stories alongside [A] and [B]
|
||||
- [ ] Choosing [C] continues to Phase 3 from the `Complete` stories — the run does not stop BLOCKED
|
||||
- [ ] The `In Progress` story is not reported as completed work
|
||||
- [ ] The sections that need sprint data read `NOT ASSESSED — NO DATA` rather than invented figures
|
||||
- [ ] "May I write" appears before the write, and the verdict is COMPLETE after it
|
||||
|
||||
---
|
||||
|
||||
## Protocol Compliance
|
||||
|
||||
- [ ] Always shows retrospective draft before asking to write
|
||||
- [ ] Always asks "May I write" before writing retrospective file
|
||||
- [ ] Checks for an existing retrospective before loading sprint data
|
||||
- [ ] A section whose inputs are absent reads `NOT ASSESSED — NO DATA` — never an estimate or an empty table
|
||||
- [ ] Always presents the retrospective and its top findings before asking to write
|
||||
- [ ] Always asks "May I write" before writing the retrospective file
|
||||
- [ ] No director gates are invoked
|
||||
- [ ] Verdict is always COMPLETE (not a pass/fail skill)
|
||||
- [ ] Checks prior retrospective for unresolved action items
|
||||
- [ ] Verdict is COMPLETE after a write, BLOCKED when the user stops at the no-data prompt or declines the write
|
||||
- [ ] Checks prior retrospectives for unresolved action items
|
||||
|
||||
---
|
||||
|
||||
## Coverage Notes
|
||||
|
||||
- Milestone retrospectives (as opposed to sprint retrospectives) follow the
|
||||
same pattern but read milestone files instead of sprint files; not
|
||||
separately tested here.
|
||||
- The case where session logs are empty is similar to Case 2 (no data);
|
||||
the skill falls back to manual input in both situations.
|
||||
- Milestone retrospectives (`retro-[milestone-name]-[date].md`, followed by
|
||||
`/gate-check`) are not separately tested here.
|
||||
- The [B] Stop choice at the no-data prompt and a declined write (both verdict
|
||||
BLOCKED) are not tested.
|
||||
|
||||
@@ -2,176 +2,285 @@
|
||||
|
||||
## Skill Summary
|
||||
|
||||
`/sprint-plan` reads the current milestone file and backlog stories, then
|
||||
generates a new numbered sprint with stories prioritized by implementation layer
|
||||
and priority score. In full mode the PR-SPRINT director gate runs after the
|
||||
sprint draft is compiled (producer reviews the plan). In lean and solo modes
|
||||
the gate is skipped. The skill asks "May I write to `production/sprints/sprint-NNN.md`?"
|
||||
before persisting. Verdicts: COMPLETE (sprint generated and written) or
|
||||
BLOCKED (cannot proceed due to missing data or gate failure).
|
||||
`/sprint-plan` (`new`, `update` or `status`) plans a sprint from the story
|
||||
backlog. It globs `production/epics/**/story-*.md`, greps their status lines and
|
||||
plans from the stories marked `Ready`, as many as `story_granularity` allows; it
|
||||
reads the previous sprint (identified from the injected Existing Sprints listing)
|
||||
for velocity and carryover, and the milestone in `production/milestones/` and
|
||||
GDDs for context when they exist. For `new` it numbers the sprint one past the
|
||||
highest `sprint-NNN.md` in the listing and presents a draft with Must Have /
|
||||
Should Have / Nice to Have task tables and a Carryover from Previous Sprint table
|
||||
(every not-Complete story of the previous sprint, listed there only) before any
|
||||
write, and prepares `production/sprint-status.yaml` alongside it. The review
|
||||
mode comes from the injected config block, `--review` overriding it for one run;
|
||||
the skill never asks for one and never writes `modes.review_mode` or
|
||||
`production/review-mode.txt`. In full review mode the PR-SPRINT producer gate
|
||||
reviews the draft; in lean and solo modes the gate is skipped with a note. A QA
|
||||
plan check runs in every mode. The skill asks "May I write the
|
||||
sprint plan to `production/sprints/sprint-NNN.md` and
|
||||
`production/sprint-status.yaml`?" before persisting. Verdicts: COMPLETE (both
|
||||
files written) or BLOCKED (no stories found, or write declined).
|
||||
|
||||
---
|
||||
|
||||
## Static Assertions (Structural)
|
||||
|
||||
Verified automatically by `/skill-test static` — no fixture needed.
|
||||
Checked against the SKILL.md by `/skill-test spec` — no fixture needed.
|
||||
|
||||
- [ ] Has required frontmatter fields: `name`, `description`, `argument-hint`, `user-invocable`, `allowed-tools`
|
||||
- [ ] Has ≥2 phase headings
|
||||
- [ ] Contains verdict keywords: COMPLETE, BLOCKED
|
||||
- [ ] Contains "May I write" language (skill writes sprint file)
|
||||
- [ ] Has a next-step handoff (what to do after sprint is written)
|
||||
- [ ] Has a next-step handoff (`/qa-plan sprint`, `/story-readiness`, `/dev-story`)
|
||||
|
||||
---
|
||||
|
||||
## Director Gate Checks
|
||||
|
||||
| Gate ID | Trigger condition | Mode guard |
|
||||
|-----------|--------------------------|--------------------|
|
||||
| PR-SPRINT | After sprint draft built | full only (not lean/solo) |
|
||||
| Gate ID | Trigger condition | Mode guard |
|
||||
|-----------|----------------------------------------------------|---------------------------|
|
||||
| PR-SPRINT | After the draft is presented, before write approval | full only (not lean/solo) |
|
||||
|
||||
PR-SPRINT verdicts: REALISTIC / CONCERNS / UNREALISTIC — or NOT ASSESSED
|
||||
[missing input] (`.claude/docs/director-gates.md`), which is never treated as
|
||||
REALISTIC.
|
||||
|
||||
---
|
||||
|
||||
## Test Cases
|
||||
|
||||
### Case 1: Happy Path — Backlog with stories generates sprint
|
||||
### Case 1: Happy Path — Ready backlog generates sprint
|
||||
|
||||
**Fixture:**
|
||||
- `production/milestones/milestone-02.md` exists with capacity `10 story points`
|
||||
- Backlog contains 5 unstarted stories across 2 epics, mixed priorities
|
||||
- `production/session-state/review-mode.txt` contains `full`
|
||||
- Next sprint number is `003` (sprints 001 and 002 already exist)
|
||||
- The injected Existing Sprints listing shows `sprint-001.md` and `sprint-002.md`
|
||||
- `production/milestones/milestone-02.md` exists
|
||||
- 5 stories under `production/epics/` across 2 epics have `Status: Ready`
|
||||
- `project.yaml` sets `modes.review_mode: full` and
|
||||
`modes.story_granularity: balanced` (6–10 stories per sprint)
|
||||
- `production/qa/qa-plan-sprint-003.md` exists
|
||||
- The producer returns REALISTIC
|
||||
|
||||
**Input:** `/sprint-plan`
|
||||
**Input:** `/sprint-plan new`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads current milestone to obtain capacity and goals
|
||||
2. Skill reads all unstarted stories from backlog; sorts by layer + priority
|
||||
3. Skill drafts sprint-003 with stories fitting within capacity
|
||||
4. Skill presents draft to user before invoking gate
|
||||
5. Skill invokes PR-SPRINT gate (full mode); producer approves
|
||||
6. Skill asks "May I write to `production/sprints/sprint-003.md`?"
|
||||
7. User approves; file is written
|
||||
1. Skill reads the milestone and the previous sprint (sprint-002)
|
||||
2. Skill globs `production/epics/**/story-*.md`, greps the status lines, and
|
||||
plans all 5 `Ready` stories — fewer than `balanced` allows, so the backlog is
|
||||
the limit
|
||||
3. Skill numbers the new sprint 003 (sprint-002 is the highest in the listing)
|
||||
and presents the draft without asking to write
|
||||
4. Skill spawns PR-SPRINT with the story list, capacity, carryover and milestone
|
||||
constraints; presents the REALISTIC assessment
|
||||
5. QA plan check finds `production/qa/qa-plan-sprint-003.md` and notes it
|
||||
6. Skill asks "May I write the sprint plan to `production/sprints/sprint-003.md`
|
||||
and `production/sprint-status.yaml`?"
|
||||
7. User approves; both files are written; verdict COMPLETE
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Stories are sorted by implementation layer before priority
|
||||
- [ ] Sprint draft is shown before any write or gate invocation
|
||||
- [ ] PR-SPRINT gate is invoked in full mode after draft is ready
|
||||
- [ ] Skill asks "May I write" before writing the sprint file
|
||||
- [ ] Written file path matches `production/sprints/sprint-003.md`
|
||||
- [ ] Verdict is COMPLETE after successful write
|
||||
- [ ] Stories come from `production/epics/**/story-*.md` via the status grep, and only `Ready` stories are planned
|
||||
- [ ] All 5 `Ready` stories are planned — `balanced` allows 6–10, so none is held back
|
||||
- [ ] Sprint draft is shown before any write prompt or gate invocation
|
||||
- [ ] PR-SPRINT gate is invoked in full mode after the draft is presented
|
||||
- [ ] "May I write" prompt names both `production/sprints/sprint-003.md` (next after sprint-002) and `production/sprint-status.yaml`
|
||||
- [ ] Verdict is COMPLETE after both files are written
|
||||
|
||||
---
|
||||
|
||||
### Case 2: Blocked Path — Backlog is empty
|
||||
### Case 2: Blocked Path — No stories in the backlog
|
||||
|
||||
**Fixture:**
|
||||
- `production/milestones/milestone-02.md` exists
|
||||
- No unstarted stories exist in any epic backlog
|
||||
- `production/epics/` contains no story files (`production/epics/**/story-*.md` matches nothing)
|
||||
- No `--review` flag, no `modes.review_mode` in `project.yaml`, no `production/review-mode.txt`
|
||||
|
||||
**Input:** `/sprint-plan`
|
||||
**Input:** `/sprint-plan new`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads backlog — finds no unstarted stories
|
||||
2. Skill outputs "No unstarted stories in backlog"
|
||||
3. Skill suggests running `/create-stories` to populate the backlog
|
||||
4. No gate is invoked; no file is written
|
||||
1. Phase 0 takes the review mode from the injected config block — with nothing
|
||||
configured, the `modes.rigor` value — and asks no review-depth question
|
||||
2. Phase 1's glob returns nothing; skill outputs "No stories found under
|
||||
`production/epics/`. Run `/create-stories` first (at `standard`/`full`,
|
||||
`/create-epics` before it)."
|
||||
3. Skill stops without inventing work items; verdict BLOCKED
|
||||
4. No gate is invoked and nothing is written
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Verdict is BLOCKED
|
||||
- [ ] Output contains "No unstarted stories" or equivalent message
|
||||
- [ ] Output recommends `/create-stories`
|
||||
- [ ] Output contains "No stories found under `production/epics/`" and recommends `/create-stories`
|
||||
- [ ] No sprint draft is produced from invented work items
|
||||
- [ ] PR-SPRINT gate is NOT invoked
|
||||
- [ ] No write tool is called
|
||||
- [ ] No review-depth question is asked, and no write happens — `project.yaml` gains no `modes.review_mode` and no `production/review-mode.txt` is created
|
||||
|
||||
---
|
||||
|
||||
### Case 3: Gate returns CONCERNS — Sprint overloaded, revised before write
|
||||
|
||||
**Fixture:**
|
||||
- Backlog has 8 stories totalling 16 points; milestone capacity is 10 points
|
||||
- `review-mode.txt` contains `full`
|
||||
- 8 `Ready` stories estimated at 16 days in total; available capacity is 10 days
|
||||
- `project.yaml` sets `modes.review_mode: full` and `modes.story_granularity: balanced`
|
||||
- A QA plan for the sprint exists in `production/qa/`
|
||||
- The producer returns CONCERNS: the sprint is overloaded
|
||||
|
||||
**Input:** `/sprint-plan`
|
||||
**Input:** `/sprint-plan new`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill drafts sprint with all 8 stories (over capacity)
|
||||
2. PR-SPRINT gate runs; producer returns CONCERNS: sprint is overloaded
|
||||
3. Skill presents concern to user and asks which stories to defer
|
||||
4. User selects 3 stories to defer; sprint is revised to 5 stories / 10 points
|
||||
5. Skill asks "May I write" with revised sprint; writes on approval
|
||||
1. Skill drafts the sprint with all 8 stories and presents it
|
||||
2. PR-SPRINT runs; producer returns CONCERNS
|
||||
3. Skill asks via `AskUserQuestion`: "Producer flagged concerns with this sprint
|
||||
plan. How do you want to proceed?" with [A] Proceed as planned,
|
||||
[B] Adjust scope, [C] Extend the sprint timeline
|
||||
4. User selects [B]; skill revises the story list and re-presents the plan
|
||||
5. Skill asks "May I write" for the revised plan; writes on approval
|
||||
|
||||
**Assertions:**
|
||||
- [ ] CONCERNS from PR-SPRINT gate surfaces to user before any write
|
||||
- [ ] Skill allows sprint to be revised after gate feedback
|
||||
- [ ] Revised sprint (not original) is written to file
|
||||
- [ ] CONCERNS from PR-SPRINT surfaces through `AskUserQuestion` ([A] Proceed / [B] Adjust scope / [C] Extend timeline) before any write
|
||||
- [ ] On [B], the revised plan is re-presented before write approval
|
||||
- [ ] The revised sprint (not the original) is written, and `production/sprint-status.yaml` lists the revised stories
|
||||
- [ ] Verdict is COMPLETE after revision and write
|
||||
|
||||
---
|
||||
|
||||
### Case 4: Lean Mode — PR-SPRINT gate skipped
|
||||
### Case 4: Lean Mode — PR-SPRINT skipped, QA plan check still runs
|
||||
|
||||
**Fixture:**
|
||||
- Backlog has 4 stories; milestone capacity is 8 points
|
||||
- `review-mode.txt` contains `lean`
|
||||
- 4 `Ready` stories under `production/epics/`
|
||||
- `project.yaml` sets `modes.rigor: standard` and pins no review mode (no
|
||||
`modes.review_mode`, no `production/review-mode.txt`, no `--review`), so the
|
||||
injected block reads `review_mode: lean (rigor:standard)`
|
||||
- No QA plan for this sprint exists in `production/qa/`
|
||||
|
||||
**Input:** `/sprint-plan`
|
||||
**Input:** `/sprint-plan new`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads review mode — determines `lean`
|
||||
2. Skill drafts sprint and presents it to user
|
||||
3. PR-SPRINT gate is skipped; output notes "[PR-SPRINT] skipped — Lean mode"
|
||||
4. Skill asks user for direct approval of the sprint
|
||||
5. User approves; sprint file is written
|
||||
1. Skill reads `review_mode` from the injected config block — `lean` — and asks
|
||||
no review-depth question
|
||||
2. Skill drafts the sprint and presents it
|
||||
3. PR-SPRINT is skipped; output notes "PR-SPRINT skipped — Lean mode."
|
||||
4. The QA plan check still runs: skill states "This sprint has no QA plan …" and
|
||||
asks via `AskUserQuestion` with [A] Run /qa-plan sprint now and
|
||||
[B] Skip for now
|
||||
5. User selects [A]; skill asks for direct approval of the write
|
||||
6. User approves; both files are written; verdict COMPLETE
|
||||
|
||||
**Assertions:**
|
||||
- [ ] PR-SPRINT gate is NOT invoked in lean mode
|
||||
- [ ] Skip is explicitly noted in output
|
||||
- [ ] User approval is still required before write (gate skip ≠ approval skip)
|
||||
- [ ] Verdict is COMPLETE after write
|
||||
- [ ] Output contains "PR-SPRINT skipped — Lean mode."
|
||||
- [ ] The QA plan check still runs in lean mode — the missing QA plan is surfaced explicitly with the [A]/[B] choice, not passed silently
|
||||
- [ ] User approval is still required before the write (gate skip ≠ approval skip)
|
||||
- [ ] The resolved `lean` is used without a review-depth question, and the write names only the sprint plan and `production/sprint-status.yaml` — `project.yaml` gains no `modes.review_mode` and no `production/review-mode.txt` is created
|
||||
- [ ] Verdict is COMPLETE after the write
|
||||
|
||||
---
|
||||
|
||||
### Case 5: Edge Case — Previous sprint still has open stories
|
||||
|
||||
**Fixture:**
|
||||
- `production/sprints/sprint-002.md` exists with 2 stories still `Status: In Progress`
|
||||
- Backlog has 5 new unstarted stories
|
||||
- `review-mode.txt` contains `full`
|
||||
- The injected Existing Sprints listing shows `sprint-002.md` as the latest sprint
|
||||
- `production/sprint-status.yaml` still holds sprint 2; 2 of its stories are not
|
||||
`done`: one `in-progress`, and one `ready-for-dev` that was never started (its
|
||||
story file says `Status: Ready`)
|
||||
- 5 other stories have `Status: Ready`
|
||||
- `project.yaml` sets `modes.review_mode: full` and `modes.story_granularity: balanced`
|
||||
- A QA plan for the sprint exists in `production/qa/`
|
||||
|
||||
**Input:** `/sprint-plan`
|
||||
**Input:** `/sprint-plan new`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads sprint-002 and detects 2 open (in-progress) stories
|
||||
2. Skill flags: "Sprint 002 has 2 open stories — confirm carry-over before planning sprint 003"
|
||||
3. Skill presents user with choice: carry stories over, defer them, or cancel
|
||||
4. User confirms carry-over; carried stories are prepended to new sprint with `[CARRY]` tag
|
||||
5. Sprint draft is built; PR-SPRINT gate runs; sprint is written on approval
|
||||
1. Skill reads sprint-002 for velocity and carryover, and numbers the new
|
||||
sprint 003
|
||||
2. Skill plans the 5 other `Ready` stories in the Must Have / Should Have / Nice
|
||||
to Have tables
|
||||
3. The 2 unfinished sprint-002 stories appear in the "Carryover from Previous
|
||||
Sprint" table with a reason and a new estimate — the unstarted one there
|
||||
only, although its story file says `Ready`
|
||||
4. The carryover is passed to PR-SPRINT with the proposed story list
|
||||
5. Skill asks "May I write the sprint plan to `production/sprints/sprint-003.md`
|
||||
and `production/sprint-status.yaml`?" and writes on approval; the new yaml
|
||||
lists the 2 carryover stories alongside the 5 new ones
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Skill checks the most recent sprint file for open stories
|
||||
- [ ] User is asked to confirm carry-over before sprint planning continues
|
||||
- [ ] Carried stories appear in the new sprint draft with a distinguishing label
|
||||
- [ ] Skill does not silently ignore open stories from the previous sprint
|
||||
- [ ] Skill reads the previous sprint (sprint-002, identified from the injected listing)
|
||||
- [ ] The 2 unfinished stories appear in the "Carryover from Previous Sprint" table with Reason and New Estimate — not silently dropped
|
||||
- [ ] The unstarted sprint-002 story appears only under Carryover — not again in Must Have / Should Have / Nice to Have, although its status is `Ready`
|
||||
- [ ] The carryover is passed to the PR-SPRINT gate
|
||||
- [ ] The written `production/sprint-status.yaml` lists the 2 carryover stories with their previous priority and current status (`in-progress`, `ready-for-dev`)
|
||||
|
||||
---
|
||||
|
||||
### Case 6: Gate returns UNREALISTIC — Stories deferred before the write
|
||||
|
||||
**Fixture:**
|
||||
- The injected Existing Sprints listing shows `sprint-002.md` as the latest sprint
|
||||
- 9 `Ready` stories estimated at 20 days in total; available capacity is 10 days
|
||||
- `project.yaml` sets `modes.review_mode: full` and `modes.story_granularity: balanced`
|
||||
- A QA plan for the sprint exists in `production/qa/`
|
||||
- The producer returns UNREALISTIC and names 4 stories to defer
|
||||
|
||||
**Input:** `/sprint-plan new`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill drafts sprint 003 with the 9 stories and presents it
|
||||
2. PR-SPRINT runs; producer returns UNREALISTIC
|
||||
3. Skill revises the selection — the 4 named stories move down to Should Have or
|
||||
Nice to Have — and re-presents the revised plan
|
||||
4. The QA plan check runs, then skill asks "May I write" for the revised plan
|
||||
5. User approves; both files are written; verdict COMPLETE
|
||||
|
||||
**Assertions:**
|
||||
- [ ] UNREALISTIC does not end the run, and the original plan is never written — the selection is revised first
|
||||
- [ ] The 4 named stories are deferred to Should Have or Nice to Have, not dropped from the plan
|
||||
- [ ] The revised plan is re-presented before the "May I write" prompt
|
||||
- [ ] The written `production/sprint-status.yaml` carries the deferred stories as `should-have` or `nice-to-have` with `status: backlog`
|
||||
- [ ] Verdict is COMPLETE after the write
|
||||
|
||||
---
|
||||
|
||||
### Case 7: Gate returns NOT ASSESSED — No story estimates
|
||||
|
||||
**Fixture:**
|
||||
- 5 `Ready` stories, none with its `Estimate` filled in
|
||||
- `project.yaml` sets `modes.review_mode: full` and `modes.story_granularity: balanced`
|
||||
- A QA plan for the sprint exists in `production/qa/`
|
||||
- The producer returns NOT ASSESSED — the stories carry no estimates
|
||||
- Asked for estimates, the user has none yet and goes ahead
|
||||
|
||||
**Input:** `/sprint-plan new`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill drafts the sprint and presents it; PR-SPRINT returns NOT ASSESSED
|
||||
2. Skill names the missing input (story estimates) and does not treat the
|
||||
result as REALISTIC; with no estimates to supply, it records PR-SPRINT as
|
||||
`NOT ASSESSED — [missing input]` in the plan's header
|
||||
3. The QA plan check runs; the "May I write" prompt repeats that PR-SPRINT was
|
||||
not assessed
|
||||
4. User approves; both files are written; verdict COMPLETE
|
||||
|
||||
**Assertions:**
|
||||
- [ ] The missing input (story estimates) is named in the output
|
||||
- [ ] NOT ASSESSED is not presented as REALISTIC — nothing says the plan's feasibility was reviewed
|
||||
- [ ] The CONCERNS options ([A] Proceed / [B] Adjust scope / [C] Extend timeline) are not raised for NOT ASSESSED
|
||||
- [ ] The written plan's header records PR-SPRINT as NOT ASSESSED with the missing input, and the "May I write" prompt says so before the write
|
||||
|
||||
---
|
||||
|
||||
## Protocol Compliance
|
||||
|
||||
- [ ] Shows draft sprint before invoking PR-SPRINT gate or asking to write
|
||||
- [ ] Always asks "May I write" before writing sprint file
|
||||
- [ ] Shows the draft sprint before invoking PR-SPRINT or asking to write
|
||||
- [ ] Always asks "May I write" before writing, naming both the sprint file and `production/sprint-status.yaml`
|
||||
- [ ] Never asks for a review depth and never writes `modes.review_mode` or `production/review-mode.txt` — the resolved value (or `--review`) is used
|
||||
- [ ] PR-SPRINT gate only runs in full mode
|
||||
- [ ] Skip message appears in lean and solo mode output
|
||||
- [ ] Verdict is clearly stated at the end of the skill output
|
||||
- [ ] The QA plan check runs in every review mode
|
||||
- [ ] Verdict (COMPLETE or BLOCKED) is clearly stated at the end of the skill output
|
||||
|
||||
---
|
||||
|
||||
## Coverage Notes
|
||||
|
||||
- The case where no milestone file exists is not explicitly tested; behavior
|
||||
follows the BLOCKED pattern with a suggestion to run `/gate-check` for
|
||||
milestone progression.
|
||||
- `update` and `status` modes are not tested.
|
||||
- No milestone file is not tested; the skill notes "no milestone defined —
|
||||
planning against the story backlog alone" and continues rather than blocking.
|
||||
- Story files that exist with none marked `Ready` are not tested.
|
||||
- Solo mode behavior is equivalent to lean (gate skipped, user approval
|
||||
required) and is not separately tested.
|
||||
- Parallel story selection algorithms are not tested here; those are unit
|
||||
concerns for the sprint-plan subagent.
|
||||
- The cases pin `story_granularity` to `balanced` (6–10 stories per sprint);
|
||||
the `coarse` (2–4) and `fine` (15–25) allocations are not tested.
|
||||
|
||||
@@ -2,24 +2,34 @@
|
||||
|
||||
## Skill Summary
|
||||
|
||||
`/sprint-status` is a Haiku-tier read-only skill that reads the current active
|
||||
sprint file and the session state to produce a concise sprint health summary.
|
||||
It reports story counts by status (Complete / In Progress / Blocked / Not Started)
|
||||
and emits one of three sprint-health verdicts: ON TRACK, AT RISK, or BLOCKED.
|
||||
It never writes files and does not invoke any director gates. It is designed for
|
||||
fast, low-cost status checks during a session.
|
||||
`/sprint-status` is a Haiku-tier read-only skill that produces a concise sprint
|
||||
snapshot. It uses the sprint named by its argument, or the most recently
|
||||
modified file in `production/sprints/`, and reads `production/sprint-status.yaml`
|
||||
as the source of truth for story status (falling back to markdown scanning with
|
||||
a warning when the yaml is absent). It greps the story files'
|
||||
`Last Updated` fields and flags an In Progress story as STALE when its date is
|
||||
more than 4 days old. The burndown verdict is On Track / At Risk / Behind,
|
||||
derived from completion % against time consumed %, and any STALE story upgrades
|
||||
it to at least At Risk. Fast escalation flags go at the top of the output: the
|
||||
SPRINT AT RISK critical flag, the Must Haves completion flag, and the missing
|
||||
stories flag. When no sprint files exist it points to `/sprint-plan new` at
|
||||
`standard`/`full` workflow, and reports build-order progress at `minimal` —
|
||||
where, if every unfinished story is Blocked, Draft or unstatused, it names them
|
||||
(each blocked one with its blocker) and never reports the build order done. It
|
||||
never writes files, invokes no director gates, and makes at most one
|
||||
recommendation.
|
||||
|
||||
---
|
||||
|
||||
## Static Assertions (Structural)
|
||||
|
||||
Verified automatically by `/skill-test static` — no fixture needed.
|
||||
Checked against the SKILL.md by `/skill-test spec` — no fixture needed.
|
||||
|
||||
- [ ] Has required frontmatter fields: `name`, `description`, `argument-hint`, `user-invocable`, `allowed-tools`
|
||||
- [ ] Has ≥2 phase headings or numbered check sections
|
||||
- [ ] Contains verdict keywords: ON TRACK, AT RISK, BLOCKED
|
||||
- [ ] Contains burndown verdict keywords: On Track, At Risk, Behind
|
||||
- [ ] Does NOT require "May I write" language (read-only skill)
|
||||
- [ ] Has a next-step handoff (what to do based on the verdict)
|
||||
- [ ] Has a next-step handoff (the Recommendation section)
|
||||
|
||||
---
|
||||
|
||||
@@ -31,137 +41,223 @@ None. `/sprint-status` is a read-only reporting skill; no gates are invoked.
|
||||
|
||||
## Test Cases
|
||||
|
||||
### Case 1: Happy Path — Mixed sprint, AT RISK with named blocker
|
||||
### Case 1: Happy Path — Mixed sprint, At Risk with a blocked Must Have
|
||||
|
||||
**Fixture:**
|
||||
- `production/sprints/sprint-004.md` exists (active sprint, linked in `active.md`)
|
||||
- Sprint contains 6 stories:
|
||||
- 3 with `Status: Complete`
|
||||
- 2 with `Status: In Progress`
|
||||
- 1 with `Status: Blocked` (blocker: "Waiting on physics ADR acceptance")
|
||||
- Sprint end date is 2 days away
|
||||
- `production/sprints/sprint-004.md` is the most recently modified sprint file
|
||||
- `production/sprint-status.yaml` covers sprint 4: it started 13 days ago and
|
||||
ends 7 days from today (65% of time consumed)
|
||||
- The yaml lists 6 stories:
|
||||
- 3 with `status: done`
|
||||
- 2 with `status: in-progress`, both last updated within the past 2 days
|
||||
- 1 with `status: blocked`, `priority: must-have`,
|
||||
`blocker: "Waiting on physics ADR acceptance"`
|
||||
|
||||
**Input:** `/sprint-status`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads `production/session-state/active.md` to find active sprint reference
|
||||
2. Skill reads `production/sprints/sprint-004.md`
|
||||
3. Skill counts stories by status: 3 Complete, 2 In Progress, 1 Blocked
|
||||
4. Skill detects a Blocked story and the approaching deadline
|
||||
5. Skill outputs AT RISK verdict with the blocker named explicitly
|
||||
1. Skill selects `sprint-004.md` and reads `production/sprint-status.yaml`
|
||||
2. Skill computes 65% time consumed and 3/6 = 50% complete — 15 points behind
|
||||
3. A blocked Must Have with 35% of sprint time remaining (under 40%) triggers
|
||||
the critical flag at the top: "SPRINT AT RISK: … Recommend replanning with
|
||||
`/sprint-plan update`."
|
||||
4. Skill outputs the status table with the blocker in the Blocker column and
|
||||
the burndown verdict At Risk
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Output includes story count breakdown by status
|
||||
- [ ] Output names the specific blocked story and its blocker reason
|
||||
- [ ] Verdict is AT RISK (not BLOCKED, not ON TRACK) when any story is Blocked
|
||||
- [ ] Output includes "Progress: 3/6 tasks (50%)" and a status table listing all 6 stories
|
||||
- [ ] The blocked story is named with "Waiting on physics ADR acceptance" in its Blocker column
|
||||
- [ ] Burndown is At Risk (50% complete vs 65% time consumed — 15 points behind)
|
||||
- [ ] The SPRINT AT RISK critical flag appears at the top, recommending `/sprint-plan update`
|
||||
- [ ] Skill does not write any files
|
||||
|
||||
---
|
||||
|
||||
### Case 2: All Stories Complete — Sprint COMPLETE verdict
|
||||
### Case 2: All Stories Complete — On Track with completion flag
|
||||
|
||||
**Fixture:**
|
||||
- `production/sprints/sprint-004.md` exists
|
||||
- All 5 stories have `Status: Complete`
|
||||
- `production/sprints/sprint-004.md` is the most recently modified sprint file
|
||||
- `production/sprint-status.yaml` covers sprint 4: it started 5 days ago and ends
|
||||
5 days from today (50% of time consumed)
|
||||
- All 5 stories have `status: done` (3 `must-have`, 2 `should-have`)
|
||||
|
||||
**Input:** `/sprint-status`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads sprint file — all stories are Complete
|
||||
2. Skill outputs ON TRACK verdict or SPRINT COMPLETE label
|
||||
3. Skill suggests running `/milestone-review` or `/sprint-plan` as next steps
|
||||
1. Skill reads the yaml — 5/5 complete
|
||||
2. 100% complete against 50% time consumed → On Track
|
||||
3. The completion flag appears at the top: "All Must Haves complete. Team can
|
||||
pull from Should Have backlog."
|
||||
4. Must-Haves at Risk reads "None."; the Attention Needed section is omitted
|
||||
5. Skill ends with a single recommendation
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Verdict is ON TRACK or SPRINT COMPLETE when all stories are Complete
|
||||
- [ ] Output notes that the sprint is fully done
|
||||
- [ ] Next-step suggestion references `/milestone-review` or `/sprint-plan`
|
||||
- [ ] Burndown is On Track
|
||||
- [ ] The completion flag "All Must Haves complete. Team can pull from Should Have backlog." appears at the top
|
||||
- [ ] Output shows "Progress: 5/5 tasks (100%)"
|
||||
- [ ] Output makes at most one recommendation (or "Sprint is on track — no action needed.")
|
||||
- [ ] No files are written
|
||||
|
||||
---
|
||||
|
||||
### Case 3: No Active Sprint File — Guidance to run /sprint-plan
|
||||
### Case 3: No Sprint Files — Guidance to run /sprint-plan
|
||||
|
||||
**Fixture:**
|
||||
- `production/session-state/active.md` does not reference an active sprint
|
||||
- `production/sprints/` directory is empty or absent
|
||||
- `production/sprints/` directory is absent
|
||||
- `project.yaml` sets `modes.workflow: standard`
|
||||
|
||||
**Input:** `/sprint-status`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads `active.md` — finds no active sprint reference
|
||||
2. Skill checks `production/sprints/` — finds no files
|
||||
3. Skill outputs an informational message: no active sprint detected
|
||||
4. Skill suggests running `/sprint-plan` to create one
|
||||
1. Skill finds no sprint files
|
||||
2. At `standard` workflow, skill reports: "No sprint files found. Start a sprint
|
||||
with `/sprint-plan new`."
|
||||
3. Skill stops
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Skill does not error or crash when no sprint file exists
|
||||
- [ ] Output clearly states no active sprint was found
|
||||
- [ ] Output recommends `/sprint-plan` as the next action
|
||||
- [ ] No verdict keyword is emitted (no sprint to assess)
|
||||
- [ ] Output states "No sprint files found" and recommends `/sprint-plan new`
|
||||
- [ ] Skill stops there — no burndown verdict and no status table are emitted
|
||||
- [ ] The `workflow: minimal` build-order report is not used at `standard`
|
||||
|
||||
---
|
||||
|
||||
### Case 4: Edge Case — Stale In Progress Story (flagged)
|
||||
|
||||
**Fixture:**
|
||||
- `production/sprints/sprint-004.md` exists
|
||||
- One story has `Status: In Progress` with a note in `active.md`:
|
||||
`Last updated: 2026-03-30` (more than 2 days before today's session date)
|
||||
- `production/sprints/sprint-004.md` is the most recently modified sprint file
|
||||
- `production/sprint-status.yaml` covers sprint 4: 10-day sprint, 5 days elapsed
|
||||
(50% of time consumed); 4 stories — 2 `done`, 2 `in-progress` (50% complete)
|
||||
- `production/epics/combat/story-003-dash.md` (in progress) has
|
||||
`> **Last Updated**: [6 days before today]`
|
||||
- `production/epics/combat/story-004-parry.md` (in progress) has
|
||||
`> **Last Updated**: [3 days before today]`
|
||||
- No stories are Blocked
|
||||
|
||||
**Input:** `/sprint-status`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads sprint file and session state
|
||||
2. Skill detects the story has been In Progress for >2 days without update
|
||||
3. Skill flags the story as "stale" in the output
|
||||
4. Verdict is AT RISK (stale in-progress stories indicate a hidden blocker)
|
||||
1. Skill resolves the dates with one grep for the `Last Updated` field across
|
||||
`production/epics/**/story-*.md`
|
||||
2. story-003 is 6 days old — more than the 4-day threshold — and is flagged
|
||||
STALE; story-004 (3 days) is not
|
||||
3. The Attention Needed table lists story-003 with its Last Updated date, Days
|
||||
Stale and the STALE note
|
||||
4. The burndown, On Track by percentage alone, is upgraded to At Risk with the
|
||||
reason "At Risk — 1 stale story(ies): …" naming story-003 with its own age,
|
||||
6 days
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Skill compares story "last updated" metadata against session date
|
||||
- [ ] Stale In Progress story is flagged by name in the output
|
||||
- [ ] Verdict is AT RISK, not ON TRACK, when a stale story is detected
|
||||
- [ ] Output does not conflate "stale" with "Blocked" — the label is distinct
|
||||
- [ ] Dates come from the story files' `Last Updated` field via a single grep, not from `active.md` or a read per story
|
||||
- [ ] story-003 (6 days) is flagged STALE by name in Attention Needed; story-004 (3 days) is not flagged
|
||||
- [ ] Burndown is At Risk despite 50% complete against 50% time consumed, and the escalation reason gives the stale count (1) and story-003's own age (6 days) as separate figures
|
||||
- [ ] Output does not conflate "stale" with "Blocked" — story-003 keeps its IN PROGRESS status with a STALE note
|
||||
|
||||
---
|
||||
|
||||
### Case 5: Gate Compliance — Read-only; no gate invocation
|
||||
|
||||
**Fixture:**
|
||||
- `production/sprints/sprint-004.md` exists with 4 stories (2 Complete, 2 In Progress)
|
||||
- `production/session-state/review-mode.txt` contains `full`
|
||||
- `production/sprints/sprint-004.md` exists and `production/sprint-status.yaml`
|
||||
lists 4 stories (2 `done`, 2 `in-progress`) with sprint dates
|
||||
- `project.yaml` sets `modes.review_mode: full`
|
||||
|
||||
**Input:** `/sprint-status`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill reads sprint and produces status summary
|
||||
1. Skill reads the sprint and produces the status snapshot
|
||||
2. Skill does NOT invoke any director gate regardless of review mode
|
||||
3. Output is a plain status report with ON TRACK, AT RISK, or BLOCKED verdict
|
||||
3. Output is a plain status report with a Burndown verdict (On Track, At Risk or Behind)
|
||||
4. Skill does not prompt for user approval or ask to write any file
|
||||
|
||||
**Assertions:**
|
||||
- [ ] No director gate is invoked in any review mode
|
||||
- [ ] Output does not contain any "May I write" prompt
|
||||
- [ ] Skill completes and returns a verdict without user interaction
|
||||
- [ ] Review mode file is ignored (or confirmed irrelevant) by this skill
|
||||
- [ ] Skill completes and returns a Burndown verdict without user interaction
|
||||
- [ ] `review_mode` is not among the keys the skill resolves (it resolves `story_granularity` and `workflow`)
|
||||
|
||||
---
|
||||
|
||||
### Case 6: Default Minimal Workflow — Build-order progress, no sprint files
|
||||
|
||||
**Fixture:**
|
||||
- `production/sprints/` does not exist
|
||||
- `project.yaml` sets neither `modes.rigor` nor `modes.workflow`, so the injected
|
||||
block reads `workflow: minimal (rigor:minimal)`
|
||||
- The injected `story-status.sh` list reads:
|
||||
```
|
||||
IN_REVIEW production/epics/core/story-003-dash.md
|
||||
IN_PROGRESS production/epics/core/story-002-jump.md
|
||||
TODO production/epics/core/story-004-parry.md (Ready)
|
||||
COMPLETE 1 of 4
|
||||
```
|
||||
|
||||
**Input:** `/sprint-status`
|
||||
|
||||
**Expected behavior:**
|
||||
1. Skill finds no sprint files; at `workflow: minimal` it reports build-order
|
||||
progress instead of pointing to `/sprint-plan`
|
||||
2. Skill prints "Build order: 1 of 4 stories complete"
|
||||
3. Next is story-003 (In Review), the first line — ahead of story-002, which
|
||||
comes first in file order; skill recommends
|
||||
`/story-done production/epics/core/story-003-dash.md`
|
||||
4. Skill stops — no burndown verdict, no status table, no write
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Output does not say "No sprint files found" and does not recommend `/sprint-plan new`
|
||||
- [ ] Output shows "Build order: 1 of 4 stories complete" — the `In Review` story is not counted as complete
|
||||
- [ ] Next is story-003, the first line of the list, with `/story-done` and its path — the story files are not re-ranked into file order
|
||||
- [ ] No burndown verdict is emitted and no file is written
|
||||
|
||||
---
|
||||
|
||||
### Case 7: Minimal Workflow — Every unfinished story Blocked or Draft
|
||||
|
||||
**Fixture:**
|
||||
- `production/sprints/` does not exist; the injected block reads
|
||||
`workflow: minimal (rigor:minimal)`
|
||||
- The injected `story-status.sh` list reads:
|
||||
```
|
||||
BLOCKED production/epics/core/story-003-dash.md (Blocked)
|
||||
OTHER production/epics/core/story-004-parry.md (Draft)
|
||||
COMPLETE 2 of 4
|
||||
```
|
||||
- story-003's file carries the note `BLOCKED: waiting on the dash animation`
|
||||
|
||||
**Input:** `/sprint-status`
|
||||
|
||||
**Expected behavior:**
|
||||
1. There is no `IN_REVIEW`, `IN_PROGRESS` or `TODO` line and 2 of 4 stories are
|
||||
complete, so there is no Next and the build order is not done
|
||||
2. Skill prints "Build order: 2 of 4 stories complete"
|
||||
3. Skill names story-003 with its blocker and story-004 with its status, `Draft`
|
||||
4. Skill makes one recommendation — clearing story-003's blocker — and stops
|
||||
|
||||
**Assertions:**
|
||||
- [ ] Output never says the build order is done — no "Build order done" line, no three ways on
|
||||
- [ ] No story is presented as Next — neither the Blocked story-003 nor the Draft story-004
|
||||
- [ ] story-003 is named with its blocker, "waiting on the dash animation", from its `BLOCKED:` note
|
||||
- [ ] story-004 is named with its status as written, `Draft`
|
||||
- [ ] Output makes exactly one recommendation, and no file is written
|
||||
|
||||
---
|
||||
|
||||
## Protocol Compliance
|
||||
|
||||
- [ ] Does NOT use Write or Edit tools (read-only skill)
|
||||
- [ ] Presents story count breakdown before emitting verdict
|
||||
- [ ] Presents the story status table before the Burndown verdict
|
||||
- [ ] Does not ask for approval
|
||||
- [ ] Ends with a recommended next step based on verdict
|
||||
- [ ] Runs on Haiku model tier (fast, low-cost)
|
||||
- [ ] Ends with at most one recommended next step
|
||||
- [ ] Declares `model: haiku` (when a declared tier is used: `.claude/docs/model-tiers.md`)
|
||||
|
||||
---
|
||||
|
||||
## Coverage Notes
|
||||
|
||||
- The case where multiple sprints are active simultaneously is not tested;
|
||||
the skill reads whichever sprint `active.md` references.
|
||||
- Partial sprint completion percentages are not explicitly verified; the
|
||||
count-by-status output implies them.
|
||||
- The `solo` mode review-mode variant is not separately tested; gate
|
||||
behavior in Case 5 applies to all modes equally.
|
||||
- At `workflow: minimal`, the all-Complete ("Build order done") and
|
||||
`STORIES none` branches are not tested.
|
||||
- The markdown fallback when `production/sprint-status.yaml` is absent (with its
|
||||
"No `sprint-status.yaml` found" warning) is not tested.
|
||||
- A sprint without dates ("burndown assessment skipped") is not tested.
|
||||
- Selecting a specific sprint by argument (`/sprint-status 3`) is not tested;
|
||||
the cases above use the most recently modified sprint file.
|
||||
|
||||
Reference in New Issue
Block a user