diff --git a/.claude/agents/art-director.md b/.claude/agents/art-director.md index bb8bcefd..d512bc52 100644 --- a/.claude/agents/art-director.md +++ b/.claude/agents/art-director.md @@ -58,23 +58,14 @@ Before proposing any design: - Iterate based on feedback without defensiveness - Celebrate when the user's modifications improve your suggestion -#### Structured Decision UI +#### Structured Decisions -Use the `AskUserQuestion` tool to present decisions as a selectable UI instead of -plain text. Follow the **Explain -> Capture** pattern: - -1. **Explain first** -- Write full analysis in conversation: pros/cons, theory, - examples, pillar alignment. -2. **Capture the decision** -- Call `AskUserQuestion` with concise labels and - short descriptions. User picks or types a custom answer. - -**Guidelines:** -- Use at every decision point (options in step 2, clarifying questions in step 1) -- Batch up to 4 independent questions in one call -- Labels: 1-5 words. Descriptions: 1 sentence. Add "(Recommended)" to your pick. -- For open-ended questions or file-write confirmations, use conversation instead -- If running as a Task subagent, structure text so the orchestrator can present - options via `AskUserQuestion` +`AskUserQuestion` is not in your `tools:` grant, so whoever called you presents +your decisions. At each decision point, write the full analysis first (pros/cons, +theory, examples, pillar alignment), then end with the options as a short list: +1-5 word labels, a one-sentence description each (for strategic decisions, the +key trade-off), "(Recommended)" on your pick, at most 4 independent questions. +Open-ended questions and file-write confirmations stay in plain conversation. ### Key Responsibilities diff --git a/.claude/agents/audio-director.md b/.claude/agents/audio-director.md index d26b42e2..1a1b39f1 100644 --- a/.claude/agents/audio-director.md +++ b/.claude/agents/audio-director.md @@ -60,23 +60,14 @@ Before proposing any design: - Iterate based on feedback without defensiveness - Celebrate when the user's modifications improve your suggestion -#### Structured Decision UI +#### Structured Decisions -Use the `AskUserQuestion` tool to present decisions as a selectable UI instead of -plain text. Follow the **Explain -> Capture** pattern: - -1. **Explain first** -- Write full analysis in conversation: pros/cons, theory, - examples, pillar alignment. -2. **Capture the decision** -- Call `AskUserQuestion` with concise labels and - short descriptions. User picks or types a custom answer. - -**Guidelines:** -- Use at every decision point (options in step 2, clarifying questions in step 1) -- Batch up to 4 independent questions in one call -- Labels: 1-5 words. Descriptions: 1 sentence. Add "(Recommended)" to your pick. -- For open-ended questions or file-write confirmations, use conversation instead -- If running as a Task subagent, structure text so the orchestrator can present - options via `AskUserQuestion` +`AskUserQuestion` is not in your `tools:` grant, so whoever called you presents +your decisions. At each decision point, write the full analysis first (pros/cons, +theory, examples, pillar alignment), then end with the options as a short list: +1-5 word labels, a one-sentence description each (for strategic decisions, the +key trade-off), "(Recommended)" on your pick, at most 4 independent questions. +Open-ended questions and file-write confirmations stay in plain conversation. ### Key Responsibilities diff --git a/.claude/agents/creative-director.md b/.claude/agents/creative-director.md index bb36fb82..dcdd1355 100644 --- a/.claude/agents/creative-director.md +++ b/.claude/agents/creative-director.md @@ -155,23 +155,14 @@ You: [Creates ADR, updates docs, notifies relevant agents] - Once decided, commit fully — document and cascade the decision - Set up success metrics — "we'll know this was right if..." -#### Structured Decision UI +#### Structured Decisions -Use the `AskUserQuestion` tool to present strategic decisions as a selectable UI. -Follow the **Explain → Capture** pattern: - -1. **Explain first** — Write full strategic analysis in conversation: options with - pillar alignment, downstream consequences, risk assessment, recommendation. -2. **Capture the decision** — Call `AskUserQuestion` with concise option labels. - -**Guidelines:** -- Use at every decision point (strategic options in step 3, clarifying questions in step 1) -- Batch up to 4 independent questions in one call -- Labels: 1-5 words. Descriptions: 1 sentence with key trade-off. -- Add "(Recommended)" to your preferred option's label -- For open-ended context gathering, use conversation instead -- If running as a Task subagent, structure text so the orchestrator can present - options via `AskUserQuestion` +`AskUserQuestion` is not in your `tools:` grant, so whoever called you presents +your decisions. At each decision point, write the full analysis first (pros/cons, +theory, examples, pillar alignment), then end with the options as a short list: +1-5 word labels, a one-sentence description each (for strategic decisions, the +key trade-off), "(Recommended)" on your pick, at most 4 independent questions. +Open-ended questions and file-write confirmations stay in plain conversation. ### Key Responsibilities diff --git a/.claude/agents/economy-designer.md b/.claude/agents/economy-designer.md index 2045b271..f4f9d9f0 100644 --- a/.claude/agents/economy-designer.md +++ b/.claude/agents/economy-designer.md @@ -60,23 +60,14 @@ Before proposing any design: - Iterate based on feedback without defensiveness - Celebrate when the user's modifications improve your suggestion -#### Structured Decision UI +#### Structured Decisions -Use the `AskUserQuestion` tool to present decisions as a selectable UI instead of -plain text. Follow the **Explain -> Capture** pattern: - -1. **Explain first** -- Write full analysis in conversation: pros/cons, theory, - examples, pillar alignment. -2. **Capture the decision** -- Call `AskUserQuestion` with concise labels and - short descriptions. User picks or types a custom answer. - -**Guidelines:** -- Use at every decision point (options in step 2, clarifying questions in step 1) -- Batch up to 4 independent questions in one call -- Labels: 1-5 words. Descriptions: 1 sentence. Add "(Recommended)" to your pick. -- For open-ended questions or file-write confirmations, use conversation instead -- If running as a Task subagent, structure text so the orchestrator can present - options via `AskUserQuestion` +`AskUserQuestion` is not in your `tools:` grant, so whoever called you presents +your decisions. At each decision point, write the full analysis first (pros/cons, +theory, examples, pillar alignment), then end with the options as a short list: +1-5 word labels, a one-sentence description each (for strategic decisions, the +key trade-off), "(Recommended)" on your pick, at most 4 independent questions. +Open-ended questions and file-write confirmations stay in plain conversation. ### Registry Awareness diff --git a/.claude/agents/game-designer.md b/.claude/agents/game-designer.md index ba9744ed..0ab794be 100644 --- a/.claude/agents/game-designer.md +++ b/.claude/agents/game-designer.md @@ -62,23 +62,14 @@ Before proposing any design: - Iterate based on feedback without defensiveness - Celebrate when the user's modifications improve your suggestion -#### Structured Decision UI +#### Structured Decisions -Use the `AskUserQuestion` tool to present decisions as a selectable UI instead of -plain text. Follow the **Explain -> Capture** pattern: - -1. **Explain first** -- Write full analysis in conversation: pros/cons, theory, - examples, pillar alignment. -2. **Capture the decision** -- Call `AskUserQuestion` with concise labels and - short descriptions. User picks or types a custom answer. - -**Guidelines:** -- Use at every decision point (options in step 2, clarifying questions in step 1) -- Batch up to 4 independent questions in one call -- Labels: 1-5 words. Descriptions: 1 sentence. Add "(Recommended)" to your pick. -- For open-ended questions or file-write confirmations, use conversation instead -- If running as a Task subagent, structure text so the orchestrator can present - options via `AskUserQuestion` +`AskUserQuestion` is not in your `tools:` grant, so whoever called you presents +your decisions. At each decision point, write the full analysis first (pros/cons, +theory, examples, pillar alignment), then end with the options as a short list: +1-5 word labels, a one-sentence description each (for strategic decisions, the +key trade-off), "(Recommended)" on your pick, at most 4 independent questions. +Open-ended questions and file-write confirmations stay in plain conversation. ### Key Responsibilities @@ -106,7 +97,8 @@ plain text. Follow the **Explain -> Capture** pattern: how the design handles them. Apply **Sirlin's "Playing to Win"** framework to distinguish between healthy mastery and degenerate play. 6. **Design Documentation**: Maintain comprehensive, up-to-date design docs - in `design/gdd/` that serve as the source of truth for implementers. + in `design/gdd/` (at `minimal`, `design/game-brief.md`) that serve as the + source of truth for implementers. ### Theoretical Frameworks diff --git a/.claude/agents/gameplay-programmer.md b/.claude/agents/gameplay-programmer.md index ea893dac..5006cf7d 100644 --- a/.claude/agents/gameplay-programmer.md +++ b/.claude/agents/gameplay-programmer.md @@ -89,12 +89,12 @@ Before writing any code: If the reference files do not cover an API or a difference, say so and mark it unverified rather than asserting it from memory. -**ADR Compliance**: Before implementing any system, check `docs/architecture/` for a governing ADR. +**ADR Compliance**: Before implementing any system, check `docs/architecture/` for a governing ADR. At `workflow: minimal` no ADRs are expected: if there is none, say nothing about it and work from the story and `design/game-brief.md`. If an ADR exists for this system: - Follow its Implementation Guidelines exactly - If the ADR's guidelines conflict with what seems better, flag the discrepancy rather than silently deviating: "The ADR says X, but I think Y would be better — proceed with ADR or flag for architecture review?" - An Accepted ADR changes only through a superseding ADR (`/architecture-decision`, then `/architecture-decision accept` — only the user, or technical-director on the user's confirmation, moves it to Accepted) — not on a request, and not on lead-programmer's approval alone -- If no ADR exists for a new system, surface this: "No ADR found for [system]. Consider running /architecture-decision first." +- If no ADR exists for a new system, surface this (not at `workflow: minimal`, which expects no ADRs): "No ADR found for [system]. Consider running /architecture-decision first." ### Code Standards @@ -104,7 +104,7 @@ If an ADR exists for this system: - No direct references to UI code (use events/signals) - Frame-rate independent logic (delta time everywhere) - Document the design doc each feature implements in code comments -- Implement the GDD's Edge Cases section along with its rules — an unhandled edge case is a deviation from the spec +- Implement the GDD's Edge Cases section along with its rules (at `minimal`, the story's acceptance criteria) — an unhandled edge case is a deviation from the spec ### What This Agent Must NOT Do diff --git a/.claude/agents/level-designer.md b/.claude/agents/level-designer.md index e81e0c3a..eaa4fa31 100644 --- a/.claude/agents/level-designer.md +++ b/.claude/agents/level-designer.md @@ -60,23 +60,14 @@ Before proposing any design: - Iterate based on feedback without defensiveness - Celebrate when the user's modifications improve your suggestion -#### Structured Decision UI +#### Structured Decisions -Use the `AskUserQuestion` tool to present decisions as a selectable UI instead of -plain text. Follow the **Explain -> Capture** pattern: - -1. **Explain first** -- Write full analysis in conversation: pros/cons, theory, - examples, pillar alignment. -2. **Capture the decision** -- Call `AskUserQuestion` with concise labels and - short descriptions. User picks or types a custom answer. - -**Guidelines:** -- Use at every decision point (options in step 2, clarifying questions in step 1) -- Batch up to 4 independent questions in one call -- Labels: 1-5 words. Descriptions: 1 sentence. Add "(Recommended)" to your pick. -- For open-ended questions or file-write confirmations, use conversation instead -- If running as a Task subagent, structure text so the orchestrator can present - options via `AskUserQuestion` +`AskUserQuestion` is not in your `tools:` grant, so whoever called you presents +your decisions. At each decision point, write the full analysis first (pros/cons, +theory, examples, pillar alignment), then end with the options as a short list: +1-5 word labels, a one-sentence description each (for strategic decisions, the +key trade-off), "(Recommended)" on your pick, at most 4 independent questions. +Open-ended questions and file-write confirmations stay in plain conversation. ### Key Responsibilities diff --git a/.claude/agents/live-ops-designer.md b/.claude/agents/live-ops-designer.md index e21c2423..e1ab6df4 100644 --- a/.claude/agents/live-ops-designer.md +++ b/.claude/agents/live-ops-designer.md @@ -49,23 +49,14 @@ Before proposing any design: - Iterate based on feedback without defensiveness - Celebrate when the user's modifications improve your suggestion -#### Structured Decision UI +#### Structured Decisions -Use the `AskUserQuestion` tool to present decisions as a selectable UI instead of -plain text. Follow the **Explain → Capture** pattern: - -1. **Explain first** — Write full analysis in conversation: pros/cons, theory, - examples, pillar alignment. -2. **Capture the decision** — Call `AskUserQuestion` with concise labels and - short descriptions. User picks or types a custom answer. - -**Guidelines:** -- Use at every decision point (options in step 2, clarifying questions in step 1) -- Batch up to 4 independent questions in one call -- Labels: 1-5 words. Descriptions: 1 sentence. Add "(Recommended)" to your pick. -- For open-ended questions or file-write confirmations, use conversation instead -- If running as a Task subagent, structure text so the orchestrator can present - options via `AskUserQuestion` +`AskUserQuestion` is not in your `tools:` grant, so whoever called you presents +your decisions. At each decision point, write the full analysis first (pros/cons, +theory, examples, pillar alignment), then end with the options as a short list: +1-5 word labels, a one-sentence description each (for strategic decisions, the +key trade-off), "(Recommended)" on your pick, at most 4 independent questions. +Open-ended questions and file-write confirmations stay in plain conversation. ## Core Responsibilities - Design seasonal content calendars and event cadences diff --git a/.claude/agents/narrative-director.md b/.claude/agents/narrative-director.md index 1791e52c..1dfe772f 100644 --- a/.claude/agents/narrative-director.md +++ b/.claude/agents/narrative-director.md @@ -60,23 +60,14 @@ Before proposing any design: - Iterate based on feedback without defensiveness - Celebrate when the user's modifications improve your suggestion -#### Structured Decision UI +#### Structured Decisions -Use the `AskUserQuestion` tool to present decisions as a selectable UI instead of -plain text. Follow the **Explain -> Capture** pattern: - -1. **Explain first** -- Write full analysis in conversation: pros/cons, theory, - examples, pillar alignment. -2. **Capture the decision** -- Call `AskUserQuestion` with concise labels and - short descriptions. User picks or types a custom answer. - -**Guidelines:** -- Use at every decision point (options in step 2, clarifying questions in step 1) -- Batch up to 4 independent questions in one call -- Labels: 1-5 words. Descriptions: 1 sentence. Add "(Recommended)" to your pick. -- For open-ended questions or file-write confirmations, use conversation instead -- If running as a Task subagent, structure text so the orchestrator can present - options via `AskUserQuestion` +`AskUserQuestion` is not in your `tools:` grant, so whoever called you presents +your decisions. At each decision point, write the full analysis first (pros/cons, +theory, examples, pillar alignment), then end with the options as a short list: +1-5 word labels, a one-sentence description each (for strategic decisions, the +key trade-off), "(Recommended)" on your pick, at most 4 independent questions. +Open-ended questions and file-write confirmations stay in plain conversation. ### Key Responsibilities diff --git a/.claude/agents/producer.md b/.claude/agents/producer.md index b4377dc6..28701b39 100644 --- a/.claude/agents/producer.md +++ b/.claude/agents/producer.md @@ -60,23 +60,14 @@ When the user asks you to make a decision or resolve a conflict: - Once decided, commit fully — document and cascade the decision - Set up success metrics — "we'll know this was right if..." -#### Structured Decision UI +#### Structured Decisions -Use the `AskUserQuestion` tool to present strategic decisions as a selectable UI. -Follow the **Explain → Capture** pattern: - -1. **Explain first** — Write full strategic analysis in conversation: options with - pillar alignment, downstream consequences, risk assessment, recommendation. -2. **Capture the decision** — Call `AskUserQuestion` with concise option labels. - -**Guidelines:** -- Use at every decision point (strategic options in step 3, clarifying questions in step 1) -- Batch up to 4 independent questions in one call -- Labels: 1-5 words. Descriptions: 1 sentence with key trade-off. -- Add "(Recommended)" to your preferred option's label -- For open-ended context gathering, use conversation instead -- If running as a Task subagent, structure text so the orchestrator can present - options via `AskUserQuestion` +`AskUserQuestion` is not in your `tools:` grant, so whoever called you presents +your decisions. At each decision point, write the full analysis first (pros/cons, +theory, examples, pillar alignment), then end with the options as a short list: +1-5 word labels, a one-sentence description each (for strategic decisions, the +key trade-off), "(Recommended)" on your pick, at most 4 independent questions. +Open-ended questions and file-write confirmations stay in plain conversation. ### Key Responsibilities diff --git a/.claude/agents/systems-designer.md b/.claude/agents/systems-designer.md index c8493c4f..d1bd06bc 100644 --- a/.claude/agents/systems-designer.md +++ b/.claude/agents/systems-designer.md @@ -60,23 +60,14 @@ Before proposing any design: - Iterate based on feedback without defensiveness - Celebrate when the user's modifications improve your suggestion -#### Structured Decision UI +#### Structured Decisions -Use the `AskUserQuestion` tool to present decisions as a selectable UI instead of -plain text. Follow the **Explain -> Capture** pattern: - -1. **Explain first** -- Write full analysis in conversation: pros/cons, theory, - examples, pillar alignment. -2. **Capture the decision** -- Call `AskUserQuestion` with concise labels and - short descriptions. User picks or types a custom answer. - -**Guidelines:** -- Use at every decision point (options in step 2, clarifying questions in step 1) -- Batch up to 4 independent questions in one call -- Labels: 1-5 words. Descriptions: 1 sentence. Add "(Recommended)" to your pick. -- For open-ended questions or file-write confirmations, use conversation instead -- If running as a Task subagent, structure text so the orchestrator can present - options via `AskUserQuestion` +`AskUserQuestion` is not in your `tools:` grant, so whoever called you presents +your decisions. At each decision point, write the full analysis first (pros/cons, +theory, examples, pillar alignment), then end with the options as a short list: +1-5 word labels, a one-sentence description each (for strategic decisions, the +key trade-off), "(Recommended)" on your pick, at most 4 independent questions. +Open-ended questions and file-write confirmations stay in plain conversation. ### Registry Awareness diff --git a/.claude/agents/technical-director.md b/.claude/agents/technical-director.md index c405d7a9..24093d8c 100644 --- a/.claude/agents/technical-director.md +++ b/.claude/agents/technical-director.md @@ -59,23 +59,14 @@ When the user asks you to make a decision or resolve a conflict: - Once decided, commit fully — document and cascade the decision - Set up success metrics — "we'll know this was right if..." -#### Structured Decision UI +#### Structured Decisions -Use the `AskUserQuestion` tool to present strategic decisions as a selectable UI. -Follow the **Explain → Capture** pattern: - -1. **Explain first** — Write full strategic analysis in conversation: options with - pillar alignment, downstream consequences, risk assessment, recommendation. -2. **Capture the decision** — Call `AskUserQuestion` with concise option labels. - -**Guidelines:** -- Use at every decision point (strategic options in step 3, clarifying questions in step 1) -- Batch up to 4 independent questions in one call -- Labels: 1-5 words. Descriptions: 1 sentence with key trade-off. -- Add "(Recommended)" to your preferred option's label -- For open-ended context gathering, use conversation instead -- If running as a Task subagent, structure text so the orchestrator can present - options via `AskUserQuestion` +`AskUserQuestion` is not in your `tools:` grant, so whoever called you presents +your decisions. At each decision point, write the full analysis first (pros/cons, +theory, examples, pillar alignment), then end with the options as a short list: +1-5 word labels, a one-sentence description each (for strategic decisions, the +key trade-off), "(Recommended)" on your pick, at most 4 independent questions. +Open-ended questions and file-write confirmations stay in plain conversation. ### Key Responsibilities diff --git a/.claude/agents/ux-designer.md b/.claude/agents/ux-designer.md index 52889e6e..eedf58f4 100644 --- a/.claude/agents/ux-designer.md +++ b/.claude/agents/ux-designer.md @@ -53,23 +53,14 @@ Before proposing any design: - Iterate based on feedback without defensiveness - Celebrate when the user's modifications improve your suggestion -#### Structured Decision UI +#### Structured Decisions -Use the `AskUserQuestion` tool to present decisions as a selectable UI instead of -plain text. Follow the **Explain -> Capture** pattern: - -1. **Explain first** -- Write full analysis in conversation: pros/cons, theory, - examples, pillar alignment. -2. **Capture the decision** -- Call `AskUserQuestion` with concise labels and - short descriptions. User picks or types a custom answer. - -**Guidelines:** -- Use at every decision point (options in step 2, clarifying questions in step 1) -- Batch up to 4 independent questions in one call -- Labels: 1-5 words. Descriptions: 1 sentence. Add "(Recommended)" to your pick. -- For open-ended questions or file-write confirmations, use conversation instead -- If running as a Task subagent, structure text so the orchestrator can present - options via `AskUserQuestion` +`AskUserQuestion` is not in your `tools:` grant, so whoever called you presents +your decisions. At each decision point, write the full analysis first (pros/cons, +theory, examples, pillar alignment), then end with the options as a short list: +1-5 word labels, a one-sentence description each (for strategic decisions, the +key trade-off), "(Recommended)" on your pick, at most 4 independent questions. +Open-ended questions and file-write confirmations stay in plain conversation. ### Key Responsibilities diff --git a/.claude/agents/world-builder.md b/.claude/agents/world-builder.md index 7fe14b6b..e942400b 100644 --- a/.claude/agents/world-builder.md +++ b/.claude/agents/world-builder.md @@ -60,23 +60,14 @@ Before proposing any design: - Iterate based on feedback without defensiveness - Celebrate when the user's modifications improve your suggestion -#### Structured Decision UI +#### Structured Decisions -Use the `AskUserQuestion` tool to present decisions as a selectable UI instead of -plain text. Follow the **Explain -> Capture** pattern: - -1. **Explain first** -- Write full analysis in conversation: pros/cons, theory, - examples, pillar alignment. -2. **Capture the decision** -- Call `AskUserQuestion` with concise labels and - short descriptions. User picks or types a custom answer. - -**Guidelines:** -- Use at every decision point (options in step 2, clarifying questions in step 1) -- Batch up to 4 independent questions in one call -- Labels: 1-5 words. Descriptions: 1 sentence. Add "(Recommended)" to your pick. -- For open-ended questions or file-write confirmations, use conversation instead -- If running as a Task subagent, structure text so the orchestrator can present - options via `AskUserQuestion` +`AskUserQuestion` is not in your `tools:` grant, so whoever called you presents +your decisions. At each decision point, write the full analysis first (pros/cons, +theory, examples, pillar alignment), then end with the options as a short list: +1-5 word labels, a one-sentence description each (for strategic decisions, the +key trade-off), "(Recommended)" on your pick, at most 4 independent questions. +Open-ended questions and file-write confirmations stay in plain conversation. ### Key Responsibilities diff --git a/.claude/agents/writer.md b/.claude/agents/writer.md index 5be86c4b..45cfa0e8 100644 --- a/.claude/agents/writer.md +++ b/.claude/agents/writer.md @@ -67,12 +67,12 @@ Before drafting anything: - Flag conflicts with other documents explicitly — their owners should know - You do not write game code — route implementation to the programmer who owns it -#### Structured Decision UI +#### Structured Decisions -Use the `AskUserQuestion` tool for implementation choices and next-step decisions. -Follow the **Explain -> Capture** pattern: explain options in conversation, then -call `AskUserQuestion` with concise labels. Batch up to 4 questions in one call. -For open-ended writing questions, use conversation instead. +`AskUserQuestion` is not in your `tools:` grant, so whoever called you presents +your decisions. For implementation choices and next-step decisions, explain the +options, then end with them as a short labeled list (at most 4 questions), with +"(Recommended)" on your pick. Use conversation for open-ended writing questions. ### Key Responsibilities diff --git a/.claude/docs/automation-modes.md b/.claude/docs/automation-modes.md index c01ea247..35869de3 100644 --- a/.claude/docs/automation-modes.md +++ b/.claude/docs/automation-modes.md @@ -13,7 +13,7 @@ through `AskUserQuestion` or writes files should follow this pattern. section `modes.automation` is the source of truth for behavior. This document is the implementation pattern. -> **Do not read `effects-map.md` during a skill run** — it is ~110 KB, a +> **Do not read `effects-map.md` during a skill run** — it is a very large file, a > reference for authoring the spec rather than a runtime input, and **this > document is self-sufficient** for deciding what to ask and what to proceed on. > If a case genuinely is not covered here, read only its `modes.automation` @@ -77,8 +77,8 @@ the right rule. - `AskUserQuestion` called for **major decisions only** (see classification below) - Minor decisions: AI states recommendation inline and proceeds — e.g. > *"Going with a static utility pattern here — it fits the existing architecture. Continuing unless you want to change direction."* -- Draft shown briefly before writing — proceeds after a short summary, does not wait for explicit "yes" -- "May I write?" asked for **new files only** — updates to existing files proceed directly +- Updates to existing files: draft shown briefly before writing — proceeds after a short summary, does not wait for explicit "yes" +- "May I write?" asked for **new files only**, and a new file waits for the answer — updates to existing files proceed directly - Still presents options for major decisions but caps at 2 choices with a clear recommendation - Multi-section authoring: writes each approved section immediately, no per-section confirmation @@ -92,6 +92,21 @@ the right rule. `production/session-logs/decision-log.md` - User reviews decision log post-session to audit choices made +### Every mode: a question with no answer + +A question that comes back **skipped, dismissed or empty is not an answer**, in +every mode and on every tool: the user closing the question, a headless run that +returns every question as skipped, a reply that picks nothing. + +- Do not write a file, change a mode or setting, or pick an option on its behalf. +- Ask again in plain text, say what is waiting on the answer, and wait. +- In `autonomous`, a question the mode did not require can be decided as usual: + pick the recommended option and log it via `log_decision`. A question in an + `automation_always_ask` category, or in an exempt skill, is the user's: ask + again and wait. +- Where nobody can answer (CI, a headless run), stop and report what is waiting + rather than choosing. + --- ## Major vs Minor Decision Classification @@ -135,9 +150,9 @@ Even in `autonomous` mode, certain decision categories ALWAYS trigger the categories actually listed in `modes.automation_always_ask` — the three defaults above, unless the project overrides them — interrupt an `autonomous` run. The other rows do nothing until a project opts into them. Read the resolved -list with `resolve_config` rather than assuming a row here is active; a real run -logged two `architecture_decisions` as rule violations on a project where that -category was never configured. +list with `resolve_config` rather than assuming a row here is active. Treating a +category the project never configured, such as `architecture_decisions`, as +active reports rule violations the project never asked for. | Category | Examples of decisions in this category | |----------|----------------------------------------| @@ -255,6 +270,8 @@ At each decision point in this skill: guided + minor: State recommendation inline, proceed. autonomous + always_ask: AskUserQuestion (regardless of mode). autonomous + other: Pick recommended, log via log_decision, proceed. +4. If the question comes back skipped, dismissed or empty, it is not an + answer: see §Every mode: a question with no answer. ``` This is the contract. Skills that follow this pattern produce diff --git a/.claude/docs/code-root-resolution.md b/.claude/docs/code-root-resolution.md index dc9f8406..8d3d921c 100644 --- a/.claude/docs/code-root-resolution.md +++ b/.claude/docs/code-root-resolution.md @@ -1,9 +1,8 @@ # Code Root Resolution Shared procedure for any skill that reads, scans, counts or writes game source -files. Referenced from the point of use in each such skill. Those skills keep -the one load-bearing imperative inline — **an unresolved code root means the -check did not run** — and cite this file for the resolution order. +files. **An unresolved code root means the check did not run.** This file gives +the resolution order. `.claude/docs/directory-structure.md` is the authority for which directory holds code. This file is the procedure for applying it. diff --git a/.claude/docs/coding-standards.md b/.claude/docs/coding-standards.md index c2d270ed..0507fbf4 100644 --- a/.claude/docs/coding-standards.md +++ b/.claude/docs/coding-standards.md @@ -69,8 +69,7 @@ falling back to the defaults above when it is absent. > **Exception — `/smoke-check`.** The ADVISORY default for **Config/Data** above > applies to *per-story evidence* gates. `/smoke-check` is a build-health gate, > not a per-story evidence gate, so its own unset default for -> `testing.strict.config` is **BLOCKING**. This divergence is intentional and is -> documented at both sites; do not reconcile one to the other. +> `testing.strict.config` is **BLOCKING**. The two defaults differ on purpose. ## Automated Test Rules diff --git a/.claude/docs/config-resolution.md b/.claude/docs/config-resolution.md index 28320698..e06fedbc 100644 --- a/.claude/docs/config-resolution.md +++ b/.claude/docs/config-resolution.md @@ -38,12 +38,12 @@ a command that would normally just prompt — **aborts the whole invocation**, a the model never sees the skill. A read-only command such as `git status`, which Claude Code approves on its own, comes back "allow" and runs without a grant. A preloaded skill (`skills:` on an agent) is checked the same way at agent launch, so a failing bootstrap line stops the agent -from starting. Measured on Claude Code 2.1.281 in default -mode: +from starting. In default +mode, the bootstrap forms behave as follows: | Bootstrap form | Repo root | Subdirectory | Bash-less agent preloading it | |---|---|---|---| -| `source "${CLAUDE_PROJECT_DIR:-.}/…" && resolve_config` (v1.1.0) | aborts | aborts | fails to launch | +| `source "${CLAUDE_PROJECT_DIR:-.}/…" && resolve_config` | aborts | aborts | fails to launch | | same, with a bare `Bash` grant | aborts | — | — | | `bash "${CLAUDE_PROJECT_DIR}/…"` + grant | runs | aborts | — | | **`bash "${CLAUDE_SKILL_DIR}/../../hooks/…"` + per-skill grant** | **runs** | **runs** | **launches** | @@ -181,8 +181,8 @@ set the sub-knob. Their effective values come from the rigor level: Because `rigor` itself defaults to `minimal`, an unconfigured project resolves these six to the lean row. That default was `standard`; it changed because the -heavier tier measured several times more expensive to reach working code without -producing a better result. See the rationale block above `_yaml_helper_defaults` +heavier tier costs more to reach working code without producing a better +result. See the rationale block above `_yaml_helper_defaults` in `.claude/hooks/yaml-helper.sh` for the reasoning and the ordering constraint. Raising the tier is one question in `/start` or one `/settings` call, and `settings-guidance.md § 4`'s upward triggers are written to fire from @@ -242,40 +242,34 @@ condition below degrades to defaults and is named on `notes:`: | Locked key in `project.local.yaml` | ignored as always, but now **named** on `notes:` — `local: not locally overridable, ignored — modes.rigor (move to project.yaml or delete)` | | No Python interpreter | legacy files and defaults only; **explicitly noted** on `notes:` | | No block at all | shell preprocessing disabled (`disableSkillShellExecution`) — use the defaults table above | +| A task notice where the block should be ("Command did not complete within its 120s timeout and was moved to the background") | the settings line ran past Claude Code's 120-second limit for a skill's `!` line, because every process start was slowed — usually by antivirus real-time scanning of the project folder. The settings exist: read each key yourself from `project.local.yaml`, then `project.yaml`, then the defaults table above | | Bootstrap line not approved, or exits non-zero | **not a degraded state — the skill never renders at all.** See "Why exactly this command" above | A skill must never treat a missing block as "config is unset in an interesting -way". It means the block did not render; the defaults apply. +way". It means the block did not render; the defaults apply. The exception is +that task notice: the settings line ran out of time, not the settings, so read +the files as that row says instead of taking the defaults. If it keeps +happening, exclude the project folder from real-time scanning. -### Two behaviours that are correct but SILENT +### Two inputs that resolve without a note -In both cases the -resolved *value* is right — the chain falls through to the default — but the user -is told nothing, and their explicit configuration was discarded. +In both cases `resolve_config` follows a fixed rule and emits no note, so it does +not tell you that something you wrote was not used. | Input | What happens | Note emitted | |---|---|---| | **Duplicate key** (`rigor:` twice in one block) | **the last occurrence wins**, deterministically | **none** | | **Wrong shape** — a list where a scalar belongs (`rigor:` followed by `- standard`) | key resolves empty, falls through to the default | **none** | -**Why this is worth knowing rather than shrugging at.** An enum-*invalid* value is -announced (`modes.workflow: 'medium' is not a valid value … — ignored, chain -continued`). A structurally-invalid one is not. So a user who mistypes the value -gets told, and a user who mistypes the *structure* does not — and the second -mistake is the easier one to make by copy-paste. The framework has the mechanism -(`notes:`) and already uses it for absence, emptiness, tabs, locked keys, orphan -locals and bad enums. Shape is the gap. +An enum-*invalid* value is announced (`modes.workflow: 'medium' is not a valid +value … — ignored, chain continued`). A wrong shape is not: the key is present +but resolves to nothing, which is also what a key with an empty value does on +purpose (the "Key present, value empty" row above), and `resolve_config` does not +tell the two apart. When a setting seems ignored, check the structure of its key +in the file: one scalar on the key's own line, the key written once per block, +and no list under it. `/settings` shows the value that is actually in effect. -**Why it is not caught yet.** Detecting "this key is present in the file but -resolved to nothing" means changing the parser every config read in the framework -goes through, and the empty-value fall-through above is a *legitimate* case of -exactly that signature. Distinguishing "empty on purpose" from "unparseable" is -real work, not a one-liner, and it lands in the most load-bearing file there is. -Until then, check the structure yourself when a setting seems ignored. - -**Duplicate-key precedence was undocumented before this entry.** Last-wins is -deterministic and reproducible, so it is not a bug — but nothing said so, which -meant nobody could rely on it either. +The last-wins rule for a duplicate key is fixed, so you can rely on it. ## Why not inject at session start diff --git a/.claude/docs/context-management.md b/.claude/docs/context-management.md index 33b89b31..faff273e 100644 --- a/.claude/docs/context-management.md +++ b/.claude/docs/context-management.md @@ -32,13 +32,11 @@ The checkpoint holds: current task, next step, what it is blocked on, files in progress, open questions. Write it so a cold reader can resume without opening anything else. -> **Why the split.** One append-only file doing both jobs grows without bound — -> past 700 lines every consumer invents its own slice: a status line parsing a -> STATUS block nothing writes, `pre-compact` injecting `head -100` (12.7 KB, at -> the moment context is scarcest), `session-start` previewing `tail -20` — the -> opposite end. None was wrong, because nothing defined where -> the recoverable state lived. Now every consumer reads the named region, and -> the cost is fixed no matter how long the narrative grows. +> **Why the split.** One append-only file doing both jobs grows without bound, +> and every consumer then reads a different slice of it: the top, the bottom, or +> a block nothing writes. None of them is wrong, because nothing defines where +> the recoverable state lives. With a named region, every consumer reads the +> same part, and the cost is fixed no matter how long the narrative grows. **Rotation.** When the narrative passes ~200 lines, move it into `production/session-logs/`: @@ -125,7 +123,7 @@ Current helpers: - **`review-scope.sh`** — which GDDs changed since the last cross-review, plus their declared dependencies. Replaces reasoning through git history. -Two rules when adding one: +Two rules for helpers: 1. **Grant it the way `.claude/docs/config-resolution.md` shows.** `allowed-tools` pre-approves commands; it does not restrict them — a skill without the grant diff --git a/.claude/docs/coordination-rules.md b/.claude/docs/coordination-rules.md index 9daacafb..d2b9f8ef 100644 --- a/.claude/docs/coordination-rules.md +++ b/.claude/docs/coordination-rules.md @@ -17,7 +17,7 @@ Read `.claude/docs/model-tiers.md` on demand. It carries the tier table, the per-skill assignments and the authoring rule. -**Load-bearing enough to restate here:** whether a skill's `model:` is used +**Key point:** whether a skill's `model:` is used depends on how the skill starts. Typed as `/skill-name`: yes, except a `haiku` pin in auto mode. Started by Claude through the Skill tool: no. Never tell a user a `haiku` skill saves money; an `opus` skill typed in a Sonnet session @@ -43,8 +43,7 @@ must NOT be parallelised. ### Agent Teams (experimental — opt-in) Multiple independent Claude Code *sessions* coordinated via a shared task list. -Opt-in and never yet used here — read `.claude/docs/agent-teams.md` on demand -before proposing one. +Opt-in only — read `.claude/docs/agent-teams.md` on demand before proposing one. ## Parallel Task Protocol diff --git a/.claude/docs/director-gates.md b/.claude/docs/director-gates.md index 0b12d4fa..867aa343 100644 --- a/.claude/docs/director-gates.md +++ b/.claude/docs/director-gates.md @@ -190,19 +190,6 @@ Collect every verdict from the directors that ran, then apply escalation rules: --- -## Adding New Gates - -1. Assign a gate ID: `[DIRECTOR-PREFIX]-[DESCRIPTIVE-SLUG]`. Prefixes: `CD-` - `TD-` `PR-` `LP-` `QL-` `ND-` `AD-`; add new ones for new agents - (`audio-director` → `AU-`, `ux-designer` → `UX-`) -2. Create `.claude/docs/director-gates/[gate-id].md` (lowercase), starting with - the standard "> Gate definition..." header note, with all five fields: - Trigger, Context to pass, Prompt, Verdicts, special handling notes -3. Add its row to the Gate Index table above -4. Reference it in skills by ID only — never copy the prompt text into the skill - ---- - ## Gate Coverage by Stage | Stage | Required Gates | Optional Gates | diff --git a/.claude/docs/effects-map.md b/.claude/docs/effects-map.md index 0a68e333..fc22895f 100644 --- a/.claude/docs/effects-map.md +++ b/.claude/docs/effects-map.md @@ -2,11 +2,11 @@ > ## READ ONE SECTION, NEVER THIS WHOLE FILE > -> This document is **~31,000 tokens** — roughly **four times an entire turn's -> context budget**, which sits near 8,300. It is organised as **36 sections of -> ~900 tokens each**, one per setting, headed `## `. +> This document is very large, far more than any one lookup needs. It is +> organised as one section per setting, headed `## `, so a reader can take +> only the section it wants. > -> **So opening it costs 36× what you need.** To look up a setting: +> **So opening it whole costs many times what you need.** To look up a setting: > > ``` > Grep pattern="^## modes.review_mode" path=".claude/docs/effects-map.md" -A 40 @@ -15,13 +15,12 @@ > Read the section for your key and stop. The same rule the skills already apply > to their own reference files — `/gate-check` loads only the row for the target > phase and says "never load the others" — applies here, and this is the largest -> file in the framework by a factor of seven. +> file in the framework. > -> This banner exists because six skills cite this document and **none of them -> scoped the citation**. None instructed a full read either, so -> nothing was actually loading 31k — but "see effects-map.md for full schema" in -> front of a file this size is an invitation, and the cost of accepting it is -> silent. +> Cite a section of this document, never the whole file. A pointer such as "see +> effects-map.md for full schema" invites a full read of a file this size, and +> the cost of accepting that invitation is silent. Name the `## ` section +> you need instead. This document defines what each `project.yaml` setting actually does across every skill that reads it. It is the tracked, authoritative reference. @@ -341,22 +340,17 @@ behavior: strict project defaults for CI, looser developer overrides for local w > **Hotfix / day-one-patch exception:** These skills are emergency or release-critical > pipelines. They are never gated by `review_mode` — all agents always run. -> **Known inertness — `full` and `lean` barely differ in the nine `team-*` -> orchestrators.** Each documents a three-way split: `full` spawns every director -> and lead gate, `lean` skips director gates *unless* they are PHASE-GATE type, -> `solo` skips gate spawning entirely. But the director gates the team skills name -> are the four PHASE-GATEs, which `lean` keeps — and no team pipeline spawns one -> (`/gate-check` is their only spawner). Two things differ: `/team-release`'s -> technical-director release sign-off runs only at `full`, and `/team-narrative` at -> `team.size: small` adds `localization-lead` and `world-builder` only at `full`. +> **`review_mode` in the nine `team-*` orchestrators.** `review_mode` sets +> director-gate depth: `full` spawns every director gate a pipeline names, `lean` +> skips director gates unless they are PHASE-GATE type, and `solo` skips gate +> spawning entirely. No team pipeline spawns a PHASE-GATE (`/gate-check` is their +> only spawner), so in the orchestrators +> `lean` and `solo` behave the same, and `full` adds two things: +> `/team-release`'s technical-director release sign-off, and, at +> `team.size: small`, `/team-narrative`'s `localization-lead` and `world-builder`. > -> `solo` genuinely differs, and outside the orchestrators (`/design-review`, -> `/architecture-review`) all three levels differ as documented. -> -> **This is recorded, not fixed.** Making `lean` mean something in the -> orchestrators requires deciding which non-phase-gate reviewers each of the nine -> should call at `full` — a design decision about review depth, not a wording fix, -> and one that changes how many agents a run spawns. +> Outside the orchestrators, the skills in the *Core skills* table below read +> `review_mode` as that table documents. --- @@ -395,15 +389,18 @@ behavior: strict project defaults for CI, looser developer overrides for local w --- -### Skills to be made review-mode aware (currently ignore the setting) +### Skills that do not read `modes.review_mode` -| Skill | full | lean | solo | -|-------|------|------|------| -| **review-all-gdds** | Phase 2 consistency pass + Phase 3 design theory pass (parallel) | Phase 2 consistency pass only, Phase 3 skipped | Phase 2 only, Phase 3 skipped | -| **architecture-review** | Engine specialist + security-engineer (if online features) | Both skipped | Both skipped | -| **dev-story** | Core programmer routing always runs + engine-specialist escalation on HIGH risk stories | Core programmer routing always runs, engine-specialist escalation skipped | Core programmer routing always runs, engine-specialist escalation skipped | -| **code-review** | Language, shader, UI specialists + qa-tester | All optional specialists skipped | All optional specialists skipped | -| **security-audit** | security-engineer spawned | Skipped | Skipped | +These skills run the same way at `full`, `lean` and `solo`. None of them takes a +`--review` flag. + +| Skill | What runs at every level | +|-------|--------------------------| +| **review-all-gdds** | Phase 2 consistency pass and Phase 3 design-theory pass, in parallel | +| **architecture-review** | The primary engine specialist is consulted after the engine audit (recorded as NOT ASSESSED when no engine is configured) | +| **dev-story** | Core programmer routing, plus the engine specialist when the story involves engine-specific APIs or patterns, and always when engine risk is HIGH | +| **code-review** | Language, shader and UI specialists when an engine is configured, plus `qa-tester` for Logic and Integration stories | +| **security-audit** | `security-engineer` is spawned to run the audit | --- @@ -427,9 +424,9 @@ pipeline's own review steps run in every mode. phase gates always run. Only `solo` skips them. This is intentional: phase gates are the minimum quality bar, not optional extras. **How many directors run is a separate axis** — `modes.workflow` sets panel width (`minimal` → PR - only, `standard` → TD + PR, `full` → all four), because a fixed four-director - Opus panel cost a two-system jam exactly what it cost a thirty-system - commercial project. Width never softens a verdict: the strictest verdict from + only, `standard` → TD + PR, `full` → all four), because directors are + Opus-tier and a small project should not pay for the same four-director panel + as a large one. Width never softens a verdict: the strictest verdict from whoever ran still wins, and `/gate-check` names the perspectives it skipped. - **art-bible** always spawns its section specialists regardless of mode — only the final sign-off gate is controlled by `review_mode`. Specialist delegation is @@ -459,8 +456,8 @@ pipeline's own review steps run in every mode. `/start` asks that sets the six knobs below **Values:** `minimal` | `standard` | `full` **Default:** `minimal` — see the rationale block above `_yaml_helper_defaults` -in `.claude/hooks/yaml-helper.sh`. Short version: the heavier tier cost several -times more to reach working code without producing a better result. +in `.claude/hooks/yaml-helper.sh`. Short version: the heavier tier costs more to +reach working code without producing a better result. **Set by:** `/start` (Phase 3d), `/settings` **Read by:** nothing directly — it is read *through* the six knobs it supplies @@ -646,8 +643,8 @@ checklists differ per phase per mode. `minimal`. --> **Director panel width** (`/gate-check` Section 4b) is workflow's second effect -here. Directors are Opus-tier, so a fixed four-director panel charged a -two-system jam exactly what it charged a thirty-system commercial project: +here. Directors are Opus-tier, so the panel is sized to the project rather than +fixed at four: | `workflow` | Panel | Directors | |---|---|---| @@ -823,10 +820,10 @@ recommend and proceed — the tradeoff between user control and speed - Minor decisions: AI states recommendation inline and proceeds — e.g. *"Going with a static utility pattern here — it fits the existing architecture. Continuing unless you want to change direction."* -- Draft shown briefly before writing — proceeds after a short summary, does not - wait for explicit "yes" -- "May I write?" asked for **new files only** — updates to existing files proceed - directly +- Updates to existing files: draft shown briefly before writing — proceeds after a + short summary, does not wait for explicit "yes" +- "May I write?" asked for **new files only**, and a new file waits for the answer + — updates to existing files proceed directly - Still presents options for major decisions but caps at 2 choices with a clear recommendation - Multi-section authoring: writes each approved section immediately, no per-section @@ -842,6 +839,18 @@ recommend and proceed — the tradeoff between user control and speed with: timestamp, skill, decision point, option chosen, reasoning - User reviews decision log post-session to audit choices made +#### every mode — a question with no answer + +- A question that comes back skipped, dismissed or empty is **not an answer**, in + every mode and on every tool (a closed question, a headless run that returns + every question as skipped, a reply that picks nothing) +- Nothing is written, no mode or setting changes and no option is picked on its + behalf; the question is asked again in plain text, naming what waits on it +- `autonomous`: a question the mode did not require is decided and logged as + usual; an `automation_always_ask` category or an exempt skill asks again +- Where nobody can answer (CI, headless), the skill stops and reports what is + waiting rather than choosing + --- ### Major vs minor decision classification (guided mode) @@ -1239,7 +1248,7 @@ closing, or produces a warning and lets work continue — per test type > **No skill or hook reads this setting. Setting it has no effect.** Everything > below describes the intended design, not current behaviour. > -> The value is checked for valid spelling when you set it, and then ignored. +> The value is not checked when you set it, and nothing reads it. **Controls:** Whether phase gate failures block stage transition or just warn **Values:** `true` | `false` @@ -1437,7 +1446,7 @@ must tell them apart) | Value | Required compliance | Best for | |-------|---------------------|----------| -| `none` | No certification — internal release, alpha, jam game | Default | +| `none` | No certification | Internal releases, alphas, jam games (an explicit choice — unset is not `none`) | | `itch` | itch.io upload requirements (build size, page setup, age tags) | Indie web/desktop releases | | `steam` | Steamworks integration, store page, achievements, depot build, system requirements, common content rules | Commercial PC releases | | `console` | Platform certification (PlayStation/Xbox/Switch) — heavy compliance: TRC/XR/Lotcheck, save data rules, controller mapping rules, age rating boards | Console releases | @@ -1450,7 +1459,6 @@ must tell them apart) |-------|------|------|-------|---------| | **launch-checklist** | Internal launch only — no external requirements | + itch.io page setup, butler upload, build size | + Steamworks integration, store page, achievements depot, common content checks | + Platform-specific TRC, certification submission, console save format compliance | | **release-checklist** | Smoke pass + version bump only | + itch.io page live, build uploaded to butler | + Steam store page live, depot pushed, achievements live | + Platform submission accepted, age rating boards cleared | -| **/pre-cert** (future) | Not applicable | Lightweight readiness check | Steam common content audit | Full TRC compliance audit | --- @@ -1477,8 +1485,8 @@ must tell them apart) > **Default is `none`, not `standard`.** Most CCGS users are solo devs and jam-game > makers — defaulting to `standard` would auto-spawn the accessibility specialist -> for projects where it's overhead. `/start` asks the question explicitly so users -> who care can opt into `standard` or `aaa` consciously. +> for projects where it's overhead. `/start` does not ask about it; you set it with +> `/settings`. --- @@ -1564,9 +1572,9 @@ must tell them apart) > > **Unset is not zero and not a default.** A budget nobody set is not a budget > that was met — `/perf-profile` must report `NOT ASSESSED` for a metric with no -> committed target rather than measuring against a placeholder. That exact -> failure (">99% headroom against a 16.67ms budget", from zero profiler data) -> is one of the two instances that motivated `.claude/rules/skill-authoring.md`. +> committed target rather than measuring against a placeholder. A headroom figure +> computed against an invented budget, with no profiler data behind it, reads as +> a pass and is not one; see obligations 1 and 2 in `.claude/rules/skill-authoring.md`. ## performance.enforce @@ -1832,7 +1840,8 @@ engine reference in this repo can source it. See `/setup-engine` §"The Godot The Unreal row is Windows'. `/setup-engine` writes the Linux block (`Engine/Build/BatchFiles/RunUAT.sh`, `Engine/Binaries/Linux/UnrealEditor`) on Linux, and on macOS only `build`, leaving `test`, `run` and -`smoke` as TODOs — see `docs/engine-reference/unreal/current-best-practices.md`, "Command Line". +`smoke` unset, with a comment in `project.yaml` asking you to set them via `/settings` — see +`docs/engine-reference/unreal/current-best-practices.md`, "Command Line". > **`` and `` are placeholders, not values to copy.** A Godot > export preset is whatever string the operator typed into `export_presets.cfg`; @@ -1880,16 +1889,15 @@ conventions into a brief, manifest or spec. **NOT by `/code-review` and NOT by > and `validate-commit.sh` does not warn on violations — neither contains any > naming logic. If you need enforcement, it has to be added. > -> **Known rough edge — asset filenames.** `validate-assets.sh` warns unless files -> under Godot's `assets/` are lowercase-with-underscores, and it takes no config -> input, while `/asset-spec` specifies asset names from `naming.*`. Unity's -> `Assets/` and Unreal's `Content/` are not naming-checked: those engines name -> assets in PascalCase. On Godot-C#, where `/setup-engine` sets -> `naming.files: PascalCase`, the hook will warn on assets named exactly as -> `/asset-spec` specified them. The two are -> measuring different things — `naming.files` describes **source** files by its -> own examples (`PlayerController.cs`), and no key currently governs asset -> filenames — so treat the hook's naming warning as advisory on those engines. +> **Asset filenames.** `validate-assets.sh` warns when a file under Godot's +> `assets/` has an uppercase letter, a space or a hyphen in its name (it expects +> lowercase with underscores), and it takes no config input. `/asset-spec` +> specifies asset names from `naming.*`. Unity's `Assets/` and Unreal's `Content/` +> are not naming-checked: those engines name assets in PascalCase. On Godot-C#, +> where `/setup-engine` sets `naming.files: PascalCase`, the hook warns on assets +> named exactly as `/asset-spec` specified them. `naming.files` describes +> **source** files by its own examples (`PlayerController.cs`), and no key governs +> asset filenames, so treat the hook's naming warning as advisory there. > **Moved from `technical-preferences.md`**, which is being deleted. Naming > conventions are project-level facts shared by everyone on the project, so they @@ -1931,19 +1939,8 @@ No skill or hook validates code *against* these conventions — see the note abo ## features.session_state -> ⚠️ **`active.yaml` does not exist and nothing writes it — anywhere in this -> document.** It is deferred design. What ships is -> `production/session-state/**active.md**`, whose `` region -> `session-start.sh` and `pre-compact.sh` both read, and whose -> `` block `statusline.sh` parses. **Read every `active.yaml` and -> `status:` mention in this file — above and below — as the deferred design, and -> substitute `active.md` (and its STATUS block).** This scope note is -> document-wide on purpose: the equivalent warning under *Status line behavior* -> scoped itself to mentions "below", which left this section's own Controls line -> and Hook behavior table describing a file that does not exist. - **Controls:** Whether the harness runs a full session tracking pipeline (hooks, -log files, `active.yaml` checkpoint — see the scope note above) or relies on +log files, `active.md` checkpoint) or relies on skeleton-first output files for recovery **Values:** `off` | `on` **Default:** `on` @@ -2000,11 +1997,11 @@ skeleton-first output files for recovery | Hook | session_state: off | session_state: on | |------|--------------------|-------------------| -| **session-start.sh** | Runs normally (git/sprint context) — skips active.yaml preview block | Runs fully including active.yaml preview | +| **session-start.sh** | Runs normally (git/sprint context) — skips the `active.md` checkpoint preview | Runs fully, including the `active.md` checkpoint preview | | **detect-gaps.sh** | Runs unchanged — gap detection is independent of session state | Runs unchanged | | **pre-compact.sh** | No-op — exits silently (no compaction-log append) | The CHECKPOINT block (and any STATUS lines) from `active.md`, changed and untracked file names and design docs with WIP markers — each list capped at 20 — then a compaction-log append; the output goes to the debug log, since PreCompact output never reaches Claude | | **post-compact.sh** | No-op — exits silently | Runs: prints a re-read reminder to the debug log (PostCompact output never reaches Claude; `session-start.sh` restores context) | -| **session-stop.sh** | No-op — exits silently | Archives active.yaml to session-log, appends commits and diffs | +| **session-stop.sh** | No-op — exits silently | Archives `active.md` to `session-log.md` when it has changed, appends commits and uncommitted file names | | **log-agent.sh** | No-op — exits silently | Appends to agent-audit.log | | **log-agent-stop.sh** | No-op — exits silently | Appends to agent-audit.log | @@ -2015,7 +2012,7 @@ skeleton-first output files for recovery | File | session_state: off | session_state: on | |------|--------------------|-------------------| | `production/session-state/active.md` | Still written by skills; session start does not show it | Written by skills; session start shows its checkpoint | -| `production/session-logs/session-log.md` | Not written | Append-only archive of each session's active.yaml | +| `production/session-logs/session-log.md` | Not written | Append-only archive of each session's `active.md` | | `production/session-logs/compaction-log.txt` | Not written | Append-only timestamp log of compaction events | | `production/session-logs/agent-audit.log` | Not written | Append-only log of agent spawn/complete events | @@ -2044,7 +2041,7 @@ bodies and a `` marker per section. As each section is approved and written, the marker changes to ``. On recovery (after /clear or compaction), the agent reads the skeleton, identifies which sections are `done` vs `incomplete`, reads relevant ADRs and the systems index, -and resumes at the first `incomplete` section. No active.yaml needed. +and resumes at the first `incomplete` section. No `active.md` needed. **Skills required to implement skeleton-first:** @@ -2068,14 +2065,6 @@ and resumes at the first `incomplete` section. No active.yaml needed. ### Status line behavior -> ⚠️ **The table below describes POST-YAML-EXPANSION behavior, which is NOT -> IMPLEMENTED.** `active.yaml` does not exist and nothing writes it. What ships -> today: `statusline.sh` parses the ` ... ` -> markdown comment block inside `production/session-state/active.md`. Substitute -> "the STATUS block in `active.md`" for every `active.yaml` / `status:` mention -> here. **The same substitution applies document-wide, not just below this -> point** — see the scope note under `## features.session_state`. - > **Stage detection is always independent of session state.** `statusline.sh` > auto-detects stage from `project.yaml` `project.stage` or artifact heuristics regardless > of `session_state` value, and so is the breadcrumb: `statusline.sh` never reads @@ -2087,24 +2076,24 @@ and resumes at the first `incomplete` section. No active.yaml needed. | Context % display | Always shown | Always shown | | Model display | Always shown | Always shown | | Stage display | From project.yaml or heuristics — except at `workflow: minimal`, where `Minimal · / stories` (or `Minimal · brief` before any story exists) replaces it | Same | -| Epic/Feature/Task breadcrumb | Parsed from `status:` block in `active.yaml` (not gated) | Parsed from `status:` block in `active.yaml` | +| Epic/Feature/Task breadcrumb | Parsed from the `` block in `active.md` (not gated) | Parsed from the `` block in `active.md` | --- ### Affected skills -Skills interact with session state in two ways: **inference** (reading active.yaml +Skills interact with session state in two ways: **inference** (reading `active.md` to resolve a missing argument) and **extraction** (appending a SESSION EXTRACT block after completing work). Neither is gated: no skill reads `session_state`, so both happen whatever its value. -#### Inference — skills that read active.yaml to fill in missing arguments +#### Inference — skills that read `active.md` to fill in missing arguments -When active.yaml holds nothing to infer from, these skills must receive the +When `active.md` holds nothing to infer from, these skills must receive the argument explicitly. If called without an argument, they should prompt the user rather than fail silently. -| Skill | What it infers from active.yaml | Fallback when nothing is found | +| Skill | What it infers from `active.md` | Fallback when nothing is found | |-------|----------------------------------|---------------------| | **dev-story** | Active story path (when no arg given) | Prompt user for story path | | **story-done** | In-progress story path (when no arg given) | Prompt user for story path | @@ -2137,7 +2126,7 @@ the `` block; the others append a SESSION EXTRACT. | Per session start | ~500 tokens (git/sprint context only) | ~500–1,250 tokens (+ checkpoint preview, at most ~750) | | Per compaction event | 0 (compaction hook output never reaches Claude) | 0 (logged to disk only) | | Per session end | 0 | File I/O only (no conversation tokens) | -| Recovery after /clear | Read skeleton + 2–3 docs (~1,000–3,000 tokens) | Read active.yaml (~200–500 tokens) | +| Recovery after /clear | Read skeleton + 2–3 docs (~1,000–3,000 tokens) | Read `active.md` (~200–500 tokens) | > **Note:** The `off` recovery cost (reading skeleton + docs) is paid only when > recovery is actually needed. The `on` session-start cost is paid every session @@ -2152,7 +2141,7 @@ the `` block; the others append a SESSION EXTRACT. > **No skill or hook reads this setting. Setting it has no effect.** Everything > below describes the intended design, not current behaviour. > -> The value is checked for valid spelling when you set it, and then ignored. +> The value is not checked when you set it, and nothing reads it. > Nothing warns at any threshold. **Controls:** Context usage threshold at which session warnings fire @@ -2281,7 +2270,7 @@ preserved raw and flagged for manual resolution, never coerced. Settings absent from the legacy files (new v1.1 settings like `qa.level`, `docs.density`, `team.size`, etc.) get hardcoded defaults from the v1.1 schema. -### Cleanup (deferred, non-destructive) +### Cleanup (optional, non-destructive) Migration is **non-destructive in v1.1**: legacy files are NOT auto-deleted. Migration produces `project.yaml` and leaves the legacy files in place. Hooks diff --git a/.claude/docs/error-recovery-protocol.md b/.claude/docs/error-recovery-protocol.md index 9667887e..e4bd138c 100644 --- a/.claude/docs/error-recovery-protocol.md +++ b/.claude/docs/error-recovery-protocol.md @@ -1,10 +1,10 @@ # Error Recovery Protocol -Shared procedure for any skill that spawns agents via the `Agent` tool. Referenced from the -`## Error Recovery Protocol` section of each orchestration/review skill. Those -skills keep the two load-bearing imperatives (surface immediately, produce a -partial report) inline, and keep their own **Common blockers** list inline — -those are skill-specific. This file holds the full procedure. +Shared procedure for any skill that spawns agents via the `Agent` tool, used by +the `## Error Recovery Protocol` section of each orchestration and review skill. +Two imperatives apply to all of them: **surface a blocked agent immediately, and +produce a partial report.** Each skill's own **Common blockers** list is +skill-specific and is not repeated here. ## Trigger 0 — verify the artifact before reading the response @@ -15,19 +15,18 @@ response reads. This trigger exists because the three below are not sufficient. They fire on BLOCKED, on an error, and on "cannot complete" — and an agent can fail in a way -that is none of those. Observed live: a `devops-engineer` spawned -as half of a parallel phase ran **26 tool calls and ~31,600 tokens**, then -returned a single fluent preamble — "I'll verify the build infrastructure…" — -with no path, no summary, no BLOCKED item, and **no file written**. Nothing in +that is none of those. A parallel agent can do a lot of work and then return a +single fluent preamble — "I'll verify the build infrastructure…" — with no +path, no summary, no BLOCKED item, and **no file written**. Nothing in steps 1–4 matches that shape. An orchestrator reading the transcript sees a plausible response and advances, and half a parallel phase disappears with no signal at all. -The work was not lost — resumed with an explicit "you did not honour the return -contract" message, the same agent completed in **one tool call**, because its -investigation was still in context. Only the write-and-return step had failed. -So the recovery is cheap; the detection is the hard part, and the detection -cannot come from reading the response. +The work is usually not lost. Resume the agent with an explicit "you did not +honour the return contract" message. Its investigation is still in context, so +it only has to do the write-and-return step it skipped. So the recovery is +cheap; the detection is the hard part, and the detection cannot come from +reading the response. **A fluent response is not evidence that a phase ran.** The artifact is — observe the artifact, not the transcript. The rule applies to sub-agents diff --git a/.claude/docs/hooks-reference.md b/.claude/docs/hooks-reference.md index 801c804c..0645b940 100644 --- a/.claude/docs/hooks-reference.md +++ b/.claude/docs/hooks-reference.md @@ -35,17 +35,12 @@ YYYYMMDD_HHMMSS | | Agent invoked: to tally the current session, then writes a count plus a per-agent breakdown to `production/session-logs/session-cost.md` and echoes a one-line total. -Three constraints that must not be "tidied" later: +The field order of that record is fixed. `session-stop.sh` matches it literally, +so a different order silently zeroes the spawn count instead of raising an error. -- **The field order is load-bearing.** Nothing else parses this log, so a - reformat looks free — but it silently zeroes the spawn count rather than - erroring. -- **`session-stop.sh` reads stdin last, on purpose.** Everything above the - tally block (notably archiving `active.md`) runs first, so a stdin read that - ever blocked would cost only the count, not the state archive. -- **No session id means no number.** The hook prints nothing rather than a - total spanning every session in the log. Silence here is correct; a - plausible-but-wrong cost figure is worse than none. +When the hook input has no session id, `session-stop.sh` prints no total. A +total spanning every session in the log would look plausible and be wrong, which +is worse than none. `agent_type` — not `agent_name` — is the field carrying the agent name. See `hooks-reference/hook-input-schemas.md`. @@ -53,16 +48,15 @@ Three constraints that must not be "tidied" later: ## Events considered and deliberately not added Claude Code offers many more hook events than the nine the hooks above use. These were -evaluated and rejected. Recorded so a future review does not re-propose them -from the event list alone. +evaluated and not adopted, for the reasons given. | Event | Why not | | ---- | ---- | | `UserPromptSubmit` | Would re-inject session state on **every prompt**. `.claude/docs/config-resolution.md` already rejects the weaker version of this — injecting config at session start — because it "would cost tokens on every session whether or not any skill needs config, and it would go stale mid-session as `/settings` writes land". Firing per prompt is the same argument, multiplied. | -| `ConfigChange` | Fires only for Claude Code's own settings files — user, project, local, policy and skills. It does **not** fire for `project.yaml`, so a hook watching CCGS config here would never run. `FileChanged` is the event that watches arbitrary files. | -| `FileChanged` on `project.yaml` | Config is resolved per skill invocation, in the skill body, precisely so each run reads fresh values. The only staleness left is text already injected into an earlier invocation, which is the accepted trade in `config-resolution.md`. A warning hook would second-guess a settled decision. | +| `ConfigChange` | Fires only for Claude Code's own settings files — user, project, local, policy and skills. It does **not** fire for `project.yaml`, so a hook watching the framework's config here would never run. `FileChanged` is the event that watches arbitrary files. | +| `FileChanged` on `project.yaml` | Config is resolved per skill invocation, in the skill body, precisely so each run reads fresh values. The only staleness left is text already injected into an earlier invocation, which is the accepted trade in `config-resolution.md`. | | `PreToolUse` `updatedInput` | Could rewrite a non-conventional commit message instead of blocking it. Silently editing the user's input contradicts the collaboration protocol: this project blocks and explains rather than acting unasked. | -| `PostToolUseFailure` | Would add another log with no reader. This repo has already been bitten by that — `log-agent.sh` wrote per-spawn records nothing consumed until `session-stop.sh` was given the job. | +| `PostToolUseFailure` | Would add another log with no reader. | | `SessionEnd` | `session-stop.sh` stays on `Stop`. `SessionEnd` fires on termination, which a crash may never reach, and the content-hash guard already makes the per-response firing cheap. | | `InstructionsLoaded` | Useful for debugging which CLAUDE.md and rules files actually loaded, but it is a diagnostic, not a project requirement. Wire it in your own `.claude/settings.local.json` when you need it rather than paying for it on every load. | diff --git a/.claude/docs/model-tiers.md b/.claude/docs/model-tiers.md index 1b705a31..ed6582c2 100644 --- a/.claude/docs/model-tiers.md +++ b/.claude/docs/model-tiers.md @@ -4,14 +4,13 @@ > > A skill's `model:` overrides the session model for the rest of the turn the > skill runs in, and your next prompt returns to the session model. Whether the -> override happens depends on how the skill starts (measured on Claude Code -> 2.1.282): +> override happens depends on how the skill starts: > > | How the skill starts | Is `model:` used? | > |---|---| > | You type `/skill-name` in Manual (`default`) mode | Yes | -> | You type `/skill-name` in auto mode | `sonnet` and `opus`: yes. `haiku`: no — auto mode does not support Haiku, so the session keeps its model (documented) | -> | Claude starts the skill itself, through the Skill tool | No — the session model runs it (measured; the docs do not say) | +> | You type `/skill-name` in auto mode | `sonnet` and `opus`: yes. `haiku`: no — auto mode does not support Haiku, so the session keeps its model | +> | Claude starts the skill itself, through the Skill tool | No — the session model runs it | > > Two things follow: > @@ -59,10 +58,9 @@ Skills with `model: opus` (3): `/architecture-review`, `/gate-check`, `/review-a All other skills are Sonnet. When creating a new skill, assign Haiku if it only reads and formats; assign Opus if it must synthesize 5+ documents with -high-stakes output; otherwise write `model: sonnet` explicitly. Every skill in -this repo declares a tier, and the lists above are kept in step with what the -`SKILL.md` files declare. That is a check on two descriptions agreeing; it -proves nothing about which model actually runs. +high-stakes output; otherwise write `model: sonnet` explicitly. Every skill +declares a tier. Whether the tier takes effect depends on how the skill starts +(see the table at the top of this file). **Agent model tiers.** 30 agents use `model: inherit` and run on the session's model. 19 are pinned: @@ -87,7 +85,7 @@ model. 19 are pinned: writing player-facing text are Sonnet work, as they are for `/patch-notes`. Every agent not named above is `inherit`. The `model:` line in the agent's own -file is what runs, and this list is kept in step with those files. +file is what runs. A pin gets that model's context window, whatever the session runs. On the Anthropic API `sonnet` currently resolves to Sonnet 5, which always has a 1M diff --git a/.claude/docs/quick-start.md b/.claude/docs/quick-start.md index 443f59f4..4be68683 100644 --- a/.claude/docs/quick-start.md +++ b/.claude/docs/quick-start.md @@ -117,7 +117,7 @@ Ask yourself: "What department would handle this in a real studio?" | `/ux-review` | Validate UX specs for accessibility and GDD alignment | | `/create-architecture` | Master architecture document for the game | | `/architecture-decision` | Creates an ADR | -| `/architecture-review` | Validate all ADRs, dependency ordering, GDD traceability | +| `/architecture-review` | Validate all ADRs, dependency ordering, GDD traceability — writes the index to `docs/architecture/requirements-traceability.md` | | `/create-control-manifest` | Flat programmer rules sheet from Accepted ADRs | | `/create-epics` | Translate GDDs + ADRs into epics (one per architectural module) | | `/create-stories` | Break a single epic into implementable story files | @@ -180,8 +180,9 @@ Templates are in `.claude/docs/templates/`: - `game-design-document.md` -- for new mechanics and systems - `architecture-decision-record.md` -- for technical decisions -- `architecture-traceability.md` -- maps GDD requirements to ADRs to story IDs - (`/architecture-review` writes it to `docs/architecture/requirements-traceability.md`) +- `architecture-traceability.md` -- sample layout for a GDD requirement to ADR to + story index (`/architecture-review` writes its own index to + `docs/architecture/requirements-traceability.md`) - `risk-register-entry.md` -- for new risks - `narrative-character-sheet.md` -- for new characters - `test-plan.md` -- for feature test plans @@ -247,13 +248,13 @@ If you already know what you need, jump directly to the relevant path: current docs from the web so agents suggest correct APIs 3. **Validate the concept** — Run `/design-review design/gdd/game-concept.md` (or `design/game-brief.md`, if `/brainstorm` wrote the one-page brief) -4. **Decompose into systems** — Run `/map-systems` to map all systems and dependencies -5. **Design each system** — Run `/design-system [system-name]` (or `/map-systems next`) - to write GDDs in dependency order -6. **Prototype the mechanic** — Run `/prototype [core-mechanic]` (1–3 days — before writing GDDs) -7. **Design each system** — Run `/design-system [system-name]` to write GDDs, informed by prototype findings -8. **Plan the first sprint** — After architecture and `/vertical-slice`, run `/sprint-plan new` -9. Start building +4. **Prototype the mechanic** — Run `/prototype [core-mechanic]` (1–3 days) to + test that the core idea is fun before you write GDDs +5. **Decompose into systems** — Run `/map-systems` to map all systems and dependencies +6. **Design each system** — Run `/design-system [system-name]` (or `/map-systems next`) + to write GDDs in dependency order, informed by the prototype findings +7. **Plan the first sprint** — After architecture and `/vertical-slice`, run `/sprint-plan new` +8. Start building ### Path B: "I know what I want to build" diff --git a/.claude/docs/run-and-observe.md b/.claude/docs/run-and-observe.md index 3487bc20..ee7f63f7 100644 --- a/.claude/docs/run-and-observe.md +++ b/.claude/docs/run-and-observe.md @@ -1,10 +1,9 @@ # Run and Observe Shared procedure for any skill that closes a story which changes something a -player can see. Referenced from the point of use in `/dev-story` (Phase 6) and -`/story-done` (Phase 3). Those skills keep the one load-bearing imperative -inline — **a parse check is not a run, and a story nobody looked at does not -close** — and cite this file for how to look. +player can see. Used by `/dev-story` (Phase 6) and `/story-done` (Phase 3). +**A parse check is not a run, and a story nobody looked at does not close.** +This file explains how to look. `.claude/docs/coding-standards.md` is the authority for *what* evidence a story needs. This file is the procedure for *producing* the visual half of it. diff --git a/.claude/docs/settings-guidance.md b/.claude/docs/settings-guidance.md index 09db9d9b..c3c13919 100644 --- a/.claude/docs/settings-guidance.md +++ b/.claude/docs/settings-guidance.md @@ -6,7 +6,7 @@ other doc does: 1. **Which value should a skill recommend** for a given project or user? 2. **When should a skill proactively suggest changing** a setting already set? -## Boundary with its siblings — do not duplicate their content here +## Boundary with its siblings | Doc | Answers | Nature | |---|---|---| @@ -15,8 +15,8 @@ other doc does: | **`settings-guidance.md`** (this file) | Which value to *recommend*, and *when* | Prescriptive | Skills reference this doc **on demand**, only at a "recommend a setting" moment. -It is deliberately **not** a CLAUDE.md import — advisory content must not ride in -per-turn context (the same reason `context-management.md` was demoted). +It is **not** a CLAUDE.md import — advisory content must not ride in per-turn +context. --- @@ -26,8 +26,7 @@ Almost every "what settings should I use?" question reduces to one choice: `modes.rigor` (`minimal` | `standard` | `full`, default `minimal`). It fronts six sub-knobs — `modes.workflow`, `docs.density`, `qa.level`, `modes.story_granularity`, `modes.review_mode`, `team.size`. Recommend **rigor**, not the six; let the -expansion do the rest. Full expansion table lives in `effects-map.md § modes.rigor` -— do not restate it here. +expansion do the rest. The full expansion table is in `effects-map.md § modes.rigor`. `modes.automation` (`collaborative` | `guided` | `autonomous`) is a **separate axis** — how often skills stop to confirm — and is *not* fronted by rigor. Pick it @@ -73,8 +72,8 @@ rigor; want that?"). If the user has **no concept yet** (exploring), do not seed "No concept yet" means **no signal**, not a particular onboarding path. A rough one-line hint is still a description: if it trips the signals above, seed from the signal. Only fall back to `minimal`-for-exploring when the user has given you -nothing to map. (`/start` Phase 3d states the same rule for its Path A/B branch — -the two must agree, since both drive the identical recommendation.) +nothing to map. (`/start` Phase 3d states the same rule for its Path A/B branch; +both drive the same recommendation.) --- @@ -106,7 +105,7 @@ state is needed — but never emit the same suggestion twice in one session. | `/gate-check` | on PASS into a new stage | § 4 (raise trigger) | | `/settings` | view output — further reading | § 2 (choosing a value) | -Each skill carries a **one-line pointer** to this doc, not a copy of its tables. +These skills each carry a **one-line pointer** to this doc. --- diff --git a/.claude/docs/setup-requirements.md b/.claude/docs/setup-requirements.md index 0332fda3..e35ae21f 100644 --- a/.claude/docs/setup-requirements.md +++ b/.claude/docs/setup-requirements.md @@ -98,19 +98,34 @@ available on native Windows, which is CCGS's primary platform. ### One setting CCGS does ship `permissions.defaultMode` is set to `default` in `.claude/settings.json`, on -purpose. It makes Claude Code ask before acting, which is what every approval -gate in this framework depends on. Project settings outrank personal ones, so -this holds even if your own config sets `acceptEdits` or `auto` — otherwise -CCGS's collaboration protocol would be silently switched off for you and the -agents would write files you never approved. +purpose. A terminal session started **at the project root** then starts in +Claude Code's ask-first mode, so file edits wait for your approval even if your +own config sets `acceptEdits` or `auto`. -If you genuinely want it off, override it in `.claude/settings.local.json`, -which takes precedence. Understand what you are turning off first. +It sets the mode a session starts in. It is a backstop, not a guarantee, and +these routes go around it: -**The VS Code extension does not read it.** The extension never reads a -project's `.claude/settings.json` for the permission mode a conversation starts -in. To get the same behaviour there, set `claudeCode.initialPermissionMode` to -`default` in your VS Code user settings. +- **Starting in a subfolder** such as `design/` or the code root (`src/`, + `Assets/` or `Source/`, depending on the engine). Claude Code loads + `.claude/settings.json` only from the folder it starts in, so that session has + none of this project's hooks, deny rules or permission mode. Start at the root. +- **Resuming a session.** A resumed session keeps the mode it ended in. +- **Switching during a session**: Shift+Tab, answering "Yes, and switch to auto + mode", or allowing all edits for the session. +- **`claude --permission-mode auto`** on the command line. +- **The VS Code extension**, which never reads a project's `.claude/settings.json` + for the mode a conversation starts in. Set `claudeCode.initialPermissionMode` + to `default` in your VS Code user settings to get the same behaviour. +- **The Desktop app**, which remembers the mode you last picked for a folder and + uses that instead. + +In any mode that accepts edits without asking, the framework's "May I write?" is +an instruction to the model, not a stop. + +To start terminal sessions in a different mode, set `permissions.defaultMode` in +`.claude/settings.local.json`, which takes precedence. Terminal sessions accept +any mode from it except `auto` and `bypassPermissions`. Understand what you are +turning off first. ## Recommended IDE diff --git a/.claude/docs/templates/accessibility-requirements.md b/.claude/docs/templates/accessibility-requirements.md index 58e5ce08..d189dcb9 100644 --- a/.claude/docs/templates/accessibility-requirements.md +++ b/.claude/docs/templates/accessibility-requirements.md @@ -14,7 +14,7 @@ > - PlayStation Accessibility (Sony Guidelines) [Yes / No / Partial] > - Apple / Google Accessibility Guidelines [Yes / No / N/A — mobile only] > **Accessibility Consultant**: [Name and organization, or "None engaged"] -> **Linked Documents**: `design/gdd/systems-index.md`, `docs/ux/interaction-pattern-library.md` +> **Linked Documents**: `design/gdd/systems-index.md`, `design/ux/interaction-patterns.md` > **Why this document exists**: Per-screen accessibility annotations belong in > UX specs. This document captures the project-wide accessibility commitments, diff --git a/.claude/docs/templates/architecture-decision-record.md b/.claude/docs/templates/architecture-decision-record.md index 5708116c..147f1225 100644 --- a/.claude/docs/templates/architecture-decision-record.md +++ b/.claude/docs/templates/architecture-decision-record.md @@ -6,11 +6,10 @@ > **Who may move this to `Accepted`: the user, or `technical-director` on the > user's explicit confirmation. No other agent, and no skill on its own.** -> Stated here because every consumer of this field enforces the *consequences* -> of acceptance (stories referencing a `Proposed` ADR are set `Blocked`; epics -> require `Accepted`), so something has to say who may produce it. `technical-director` is the role `coordination-rules.md` -> already escalates technical conflicts to, and an ADR is exactly that decision -> made durable. +> Why this is stated here: stories referencing a `Proposed` ADR are set `Blocked`, +> and epics require `Accepted`, so the field needs a named owner. +> `technical-director` is the role `coordination-rules.md` already escalates +> technical conflicts to, and an ADR is that decision made durable. > > This does **not** relax the existing rule that `Status: Accepted` is never set > without explicit user confirmation — it narrows *which agent* may set it once @@ -59,10 +58,9 @@ chosen approach.] > `/architecture-decision`, `/story-readiness`, `/propagate-design-change` and > `gate-pre-production.md`; a missing row counts as critical. At `standard`, > `/create-stories` **stops** for a missing critical ADR and only **warns** for a -> non-critical one, so this row decides whether a run halts. Earlier revisions of -> this template recorded no layer at all, leaving those sites to infer one from -> the referencing epic — which gives the wrong answer whenever a Foundation-layer -> ADR is referenced by a Core-layer epic, the common case. +> non-critical one, so this row decides whether a run halts. Do not infer the +> layer from the referencing epic: a Foundation-layer ADR is commonly referenced +> by a Core-layer epic, which would give the wrong answer. > > The vocabulary is the same `Foundation / Core / Feature / Presentation` that > epics and stories already carry — do not invent a fifth value, and do not diff --git a/.claude/docs/templates/difficulty-curve.md b/.claude/docs/templates/difficulty-curve.md index 4e92ea3a..0494642b 100644 --- a/.claude/docs/templates/difficulty-curve.md +++ b/.claude/docs/templates/difficulty-curve.md @@ -3,7 +3,7 @@ > **Status**: Draft | In Review | Approved > **Author**: [game-designer / systems-designer] > **Last Updated**: [Date] -> **Links To**: `design/gdd/game-concept.md` +> **Links To**: `design/gdd/game-concept.md` (or `design/game-brief.md`) > **Relevant GDDs**: [e.g., `design/gdd/combat.md`, `design/gdd/progression.md`] --- diff --git a/.claude/docs/templates/interaction-pattern-library.md b/.claude/docs/templates/interaction-pattern-library.md index 6d5a6251..a9e5494b 100644 --- a/.claude/docs/templates/interaction-pattern-library.md +++ b/.claude/docs/templates/interaction-pattern-library.md @@ -11,7 +11,7 @@ > **Related Documents**: > - `design/art/art-bible.md` — visual standards (colors, typography, iconography) > - `design/accessibility-requirements.md` — accessibility commitments per feature -> - `docs/ux/ux-spec-[screen].md` — individual screen specs that reference patterns +> - `design/ux/[screen].md` — individual screen specs that reference patterns > > **Template**: Interaction Pattern Library diff --git a/.claude/docs/templates/player-journey.md b/.claude/docs/templates/player-journey.md index 23641c70..5e4ca425 100644 --- a/.claude/docs/templates/player-journey.md +++ b/.claude/docs/templates/player-journey.md @@ -3,7 +3,7 @@ > **Status**: Draft | In Review | Approved > **Author**: [game-designer / creative-director] > **Last Updated**: [Date] -> **Links To**: `design/gdd/game-concept.md`, `design/gdd/game-pillars.md` +> **Links To**: `design/gdd/game-concept.md` (or `design/game-brief.md`), `design/gdd/game-pillars.md` --- diff --git a/.claude/docs/templates/prototype-report.md b/.claude/docs/templates/prototype-report.md index e5d1c6e4..01b45945 100644 --- a/.claude/docs/templates/prototype-report.md +++ b/.claude/docs/templates/prototype-report.md @@ -2,7 +2,7 @@ > **Date**: [YYYY-MM-DD] > **Prototype Path**: [HTML / Engine / Paper] -> **Concept File**: design/gdd/game-concept.md (if exists) +> **Concept File**: design/gdd/game-concept.md, or design/game-brief.md (if either exists) --- diff --git a/.claude/docs/templates/session-state.md b/.claude/docs/templates/session-state.md index 1ce7d19e..e4529e70 100644 --- a/.claude/docs/templates/session-state.md +++ b/.claude/docs/templates/session-state.md @@ -1,7 +1,7 @@ # Active Session State — [project or branch] diff --git a/.claude/docs/templates/systems-index.md b/.claude/docs/templates/systems-index.md index ab52bb2c..6210cebc 100644 --- a/.claude/docs/templates/systems-index.md +++ b/.claude/docs/templates/systems-index.md @@ -3,7 +3,7 @@ > **Status**: [Draft / Under Review / Approved] > **Created**: [Date] > **Last Updated**: [Date] -> **Source Concept**: design/gdd/game-concept.md +> **Source Concept**: design/gdd/game-concept.md (or design/game-brief.md) --- diff --git a/.claude/docs/templates/ux-spec.md b/.claude/docs/templates/ux-spec.md index 1c1e7b82..f97a5f94 100644 --- a/.claude/docs/templates/ux-spec.md +++ b/.claude/docs/templates/ux-spec.md @@ -9,7 +9,7 @@ > **Platform Target**: [PC | Console | Mobile | All — list all that this spec covers] > **Related GDDs**: [Links to the GDD sections that generated this UI requirement — e.g., `design/gdd/inventory.md § UI Requirements`] > **Related ADRs**: [Any architectural decisions that constrain this screen — e.g., `ADR-0012: UI Framework Selection`] -> **Related UX Specs**: [Sibling and parent screens — e.g., `ux-spec-pause-menu.md`, `ux-spec-settings.md`] +> **Related UX Specs**: [Sibling and parent screens — e.g., `pause-menu.md`, `settings.md`] > **Accessibility Tier**: Basic | Standard | Comprehensive | Exemplary > **Template**: UX Spec diff --git a/.claude/docs/templates/vertical-slice-report.md b/.claude/docs/templates/vertical-slice-report.md index fc71c19a..b4fcdb5a 100644 --- a/.claude/docs/templates/vertical-slice-report.md +++ b/.claude/docs/templates/vertical-slice-report.md @@ -3,7 +3,7 @@ > **Date**: [YYYY-MM-DD] > **Slice Duration**: [N days] > **Target Scope**: 3–5 minutes of polished, continuous gameplay -> **Source GDD**: design/gdd/game-concept.md +> **Source GDD**: design/gdd/game-concept.md (or design/game-brief.md) --- diff --git a/.claude/docs/workflow-catalog.yaml b/.claude/docs/workflow-catalog.yaml index bc6c7ab7..aa7bb60e 100644 --- a/.claude/docs/workflow-catalog.yaml +++ b/.claude/docs/workflow-catalog.yaml @@ -92,11 +92,10 @@ phases: name: "Engine Setup" command: /setup-engine required: true - # v1.1: engine.name in project.yaml is the primary source; technical- - # preferences.md is the legacy fallback. Checking only the legacy file - # made a correctly-configured project fail this REQUIRED gate. + # engine.name in project.yaml is the primary source; technical- + # preferences.md is the legacy fallback. Either one completes the step. # /setup-engine writes the value quoted (`name: "Godot"`), so the quote - # is optional; without it only the legacy alternative ever matched. + # is optional in the first alternative. # Single-quoted so the `"` needs no escape — artifact-check.sh strips # the outer quotes and does not unescape. artifact: @@ -104,9 +103,7 @@ phases: - glob: "project.yaml" pattern: 'name:[[:space:]]*"?(Godot|Unity|Unreal)' # technical-preferences.md writes "- **Engine**: Godot 4.6", so the - # pattern must clear the bold markers. The previous "Engine: [^[]" - # required a literal "Engine: " and therefore never matched any - # file /setup-engine produces. The [^[] guard rejects the + # pattern must clear the bold markers. The [^[] guard rejects the # "[TO BE CONFIGURED]" placeholder. - glob: ".claude/docs/technical-preferences.md" pattern: '\*\*Engine\*\*: [^[]' @@ -219,11 +216,6 @@ phases: - id: accessibility-doc name: "Accessibility Requirements" - # This step had no `command:` at all -- the only artifact entry in the - # catalog that named no producer. It was REQUIRED, so the Technical - # Setup -> Pre-Production gate could never pass, and the remediation - # every skill printed ("run /ux-design") wrote into design/ux/ where - # this glob does not look. /ux-design now has an `accessibility` mode. command: /ux-design required: true artifact: @@ -289,10 +281,10 @@ phases: command: /prototype required: false artifact: - # /prototype writes prototypes/[name]-concept/REPORT.md -- it has never - # written a README. The `-concept` suffix is load-bearing: /vertical-slice - # writes the same REPORT.md basename under `-vertical-slice`, so a bare - # `prototypes/*/REPORT.md` here would let either step satisfy the other. + # /prototype writes prototypes/[name]-concept/REPORT.md. The `-concept` + # suffix matters: /vertical-slice writes the same REPORT.md basename + # under `-vertical-slice`, so a bare `prototypes/*/REPORT.md` here + # would let either step satisfy the other. glob: "prototypes/*-concept/REPORT.md" min_count: 1 description: "Build a throwaway prototype to validate the core mechanic is fun before committing to full production. Recommended for first-time mechanics or high-risk design decisions. Solo devs with proven concepts may skip." @@ -331,9 +323,9 @@ phases: command: /vertical-slice required: false artifact: - # Must stay scoped to `-vertical-slice`: the untethered form matched - # /prototype's concept report, so running only /prototype silently - # marked the vertical slice complete and skipped the validation the + # Scoped to `-vertical-slice`: an unscoped form would match + # /prototype's concept report, so running only /prototype would mark + # the vertical slice complete and skip the validation the # Pre-Production → Production gate exists to require. glob: "prototypes/*-vertical-slice/REPORT.md" min_count: 1 @@ -454,8 +446,6 @@ phases: required: true artifact: # /playtest-report writes production/qa/playtests/, not production/playtests/. - # The old glob matched nothing on every project, so this REQUIRED step - # read as 0/3 forever no matter how many playtests were actually run. glob: "production/qa/playtests/*.md" min_count: 3 description: "Cover: new player experience, mid-game systems, difficulty curve" diff --git a/.claude/docs/workflow-modes.md b/.claude/docs/workflow-modes.md index 1978afb0..9ead27c6 100644 --- a/.claude/docs/workflow-modes.md +++ b/.claude/docs/workflow-modes.md @@ -9,10 +9,10 @@ this document instead of embedding the tier tables inline. sections `modes.workflow` and `workflow_overrides` are the source of truth for behavior. This document is the implementation pattern. -> **Do not read `effects-map.md` during a skill run.** It is ~2,150 lines -> (~110 KB) — about five times the size of everything CLAUDE.md loads per -> session combined — and it is a reference for *authoring and changing the -> spec*, not a runtime input. **This document is self-sufficient** for resolving +> **Do not read `effects-map.md` during a skill run.** It is many times the +> size of everything CLAUDE.md loads per session combined — and it is a +> reference for *authoring and changing the spec*, not a runtime input. +> **This document is self-sufficient** for resolving > the tier and applying it: the resolution chain, the three tiers, the required > sections, and the override rules are all here. If you hit a case this document > genuinely does not cover, read only the one `effects-map.md` section for the @@ -50,8 +50,8 @@ its fallback will ignore `rigor: minimal` and `rigor: full` entirely. ### What `` is — one derivation, everywhere -**`` is the GDD filename stem**: `design/gdd/hammer-heat-system.md` → -`hammer-heat-system`. That is the key to write under +**`` is the GDD filename stem**: `design/gdd/forge-heat-system.md` → +`forge-heat-system`. That is the key to write under `workflow_overrides.system_overrides`, and every skill must derive it the same way. @@ -61,18 +61,18 @@ from it in preference to the stem. > **Why this is stated here rather than per skill.** Reading *"the `[system]` > segment of its `TR-[system]-NNN` ID (else its `design/gdd/` path)"* — TR-ID -> **first** — is the wrong order. A system whose GDD is `hammer-heat-system.md` and -> whose requirements are `TR-heat-001` then had **two different override keys -> depending on whether a registry entry existed**, and the documented remedy for -> a missing GDD section — "set -> `workflow_overrides.system_overrides.hammer-heat-system: full`" — was looked up -> under `heat`, found nothing, and continued at the project tier **silently**. -> The escape hatch existed and could not be reached. +> **first** — is the wrong order. A system whose GDD is `forge-heat-system.md` and +> whose requirements are `TR-forge-001` would then have **two different override +> keys depending on whether a registry entry existed**, and the documented remedy +> for a missing GDD section — "set +> `workflow_overrides.system_overrides.forge-heat-system: full`" — would be looked +> up under `forge`, find nothing, and continue at the project tier **silently**. +> The escape hatch would exist and could not be reached. **A key that matches no system is an error, not a no-op.** If `workflow_overrides.system_overrides` contains a key that resolves to no GDD stem in `design/gdd/`, say so — naming the unmatched key and the stems available. -Silently ignoring it is how the above went unnoticed. +Silently ignoring it would leave an override that does nothing, unnoticed. > **Checked where GDDs are expected to already exist — not by the skill that > writes them.** `/gate-check` is the single implementing site (see diff --git a/.claude/hooks/pre-compact.sh b/.claude/hooks/pre-compact.sh index 6a44cf53..5b981305 100644 --- a/.claude/hooks/pre-compact.sh +++ b/.claude/hooks/pre-compact.sh @@ -98,15 +98,11 @@ echo "" echo "## Files Modified (git working tree)" # BOUNDED. These three lists must never be emitted in full, one line per -# file, with no cap. (They were bounded believing this output goes into the -# compacting context; it reaches the debug log, where an unbounded dump still -# costs time and log size.) The checkpoint above was redesigned to be by-reference for exactly -# that reason (see the note at the top of this file); the lists below were left -# unbounded, so the hook still dumped whatever the working tree happened to -# contain at the moment context was scarcest. Measured on a tree with ~5k -# untracked files: 181,125 bytes, roughly 45,000 tokens, of which ~4,984 lines -# were this section. A fresh asset import or un-gitignored build output is -# enough to trigger it. +# file, with no cap. This output reaches the debug log, where an unbounded dump +# still costs time and log size: a tree with thousands of untracked files (a +# fresh asset import, or build output that is not gitignored) would otherwise +# print one line per file on every compaction. The checkpoint above is +# by-reference for the same reason (see the note at the top of this file). # # A count plus a sample is what this section is actually for -- orienting the # agent after compaction -- and the full list is one `git status` away. @@ -141,8 +137,8 @@ WIP_FOUND=false # BOUNDED and BATCHED. One `grep -n` per design doc, printing every matching # line from every file, fails twice over -- the same two ways as above: # unbounded OUTPUT into a compacting context, and unbounded -# COST -- ~85ms per file, crossing this hook's 10s budget at roughly 90 GDDs. -# Measured: 220 docs 18262ms, 420 docs killed at the timeout. +# COST -- one process spawn per file, which grows past this hook's 10s budget +# on a project with a large set of GDDs. # # `xargs -0` bounds the spawn count by ARG_MAX rather than by file count, and # the NUL delimiter keeps it portable: `-d` is GNU-only, BSD xargs rejects it, diff --git a/.claude/hooks/session-stop.sh b/.claude/hooks/session-stop.sh index d681a60f..3d5320b9 100644 --- a/.claude/hooks/session-stop.sh +++ b/.claude/hooks/session-stop.sh @@ -51,16 +51,12 @@ MODIFIED_FILES=$(git diff --name-only 2>/dev/null) # It is only valid to delete active.md manually or when explicitly superseded. # APPEND ONLY WHEN THE CONTENT CHANGED. # -# The Stop hook fires once per RESPONSE, not once per session. Both blocks below -# appended unconditionally, so a long session wrote the whole of active.md on -# every turn. Measured on this repository before this guard: -# -# 3,187 Stop firings, 665 archived copies, session-log.md at 17.5 MB -# -# and session-logs/ is gitignored, so nothing ever surfaced it. The growth -# compounds: the larger active.md gets, the more each firing appends -- and -# rotate-session-state.sh caps active.md precisely because it grows, while the -# log accumulating full copies of it had no cap at all. +# The Stop hook fires once per RESPONSE, not once per session. Appending +# unconditionally in the two blocks below would write the whole of active.md on +# every turn of a long session, and session-logs/ is gitignored, so nothing +# would surface the growth. It compounds: the larger active.md gets, the more +# each firing appends -- and rotate-session-state.sh caps active.md precisely +# because it grows, so a log accumulating full copies of it needs a guard too. # # Content hash, not mtime: an editor that rewrites a file unchanged would # otherwise re-archive it. Same reasoning and same tool as review-receipts.sh -- diff --git a/.claude/hooks/validate-commit.sh b/.claude/hooks/validate-commit.sh index df043897..3aba5d53 100644 --- a/.claude/hooks/validate-commit.sh +++ b/.claude/hooks/validate-commit.sh @@ -38,7 +38,7 @@ INPUT=$(cat) # Most Bash and PowerShell calls do not mention git at all. Leave before any # parsing: this hook runs on every one of them, and the parse is most of its -# cost (~350 ms a call measured; the early exit is the shell start-up alone). +# cost (the early exit is the shell start-up alone). # Tested only after the "tool_input" key: matching the whole payload also # tests cwd and transcript_path, so a project path containing "GitHub" or # "digital" never took this exit and paid the full parse on every call. @@ -253,6 +253,15 @@ fi # `cd assets && git commit -m x data/item.json` named nothing here and the file # went unchecked. There, and whenever a pathspec names no tracked file, every # modified tracked file is checked (`:/`), and the index with it. +# +# A `git add` (or `git stage`) earlier in the same command stages its files +# after this hook has read the index, so `git add -A && git commit` committed a +# new broken data file unchecked. Each add before a commit is read too, and +# what it will stage -- modified tracked files, and untracked ones unless it is +# -u (ignored ones only with -f) -- is checked as working copies. A dry run +# (-n) stages nothing, an add after the commit is for a later one, a +# path-limited commit still records only its own paths, and after a cd or -C +# an add's pathspecs are read as the whole tree, as above. if [ -n "$_VC_PY" ]; then if command -v jq >/dev/null 2>&1; then _VC_CWD=$(echo "$INPUT" | jq -r '.cwd // empty') @@ -280,9 +289,37 @@ def words(line): def git(*args): return subprocess.run(["git", "-c", "core.quotePath=false"] + list(args), stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) +def add(w, k): # git add/stage from w[k] -> pathspecs, takes untracked, -f, -n, next k + specs, rest, alln, upd, force, dry = [], False, False, False, False, False + while k < len(w): + a = w[k] + if a.isdigit() and k + 1 < len(w) and w[k + 1][:1] in "<>": + k += 1 + continue + if REDIR.match(a): + k += 2 + continue + if a and set(a) <= OPS: + break + if rest or not a.startswith("-") or a == "-": + specs.append(a) + elif a == "--": + rest = True + elif a.startswith("--"): + alln = alln or a in ("--all", "--no-ignore-removal") + upd, force, dry = upd or a == "--update", force or a == "--force", dry or a == "--dry-run" + if a.startswith("--pathspec-from-file"): + specs.append(":/") # paths only git reads + else: # no short option of git add takes a value: -Av is -A -v + alln, upd, force, dry = alln or "A" in a, upd or "u" in a, force or "f" in a, dry or "n" in a + k += 1 + if not specs and (alln or upd): + specs = [":/"] # -A and -u with no pathspec take the whole tree + return specs, alln or not upd, force, dry, k text = sys.stdin.buffer.read().decode("utf-8", "replace") away = sys.argv[1] == "1" or re.search(r"(^|[^\w.-])(cd|pushd|popd)(\s|[;&|)]|$)", text, re.M) is not None specs, commits, only = [], 0, True +adds, pending = [], [] # what each git add stages: before a commit, not yet for line in text.splitlines(): w, i = words(line), 0 while i < len(w): @@ -293,10 +330,16 @@ for line in text.splitlines(): while j < len(w) and w[j].startswith("-"): away = away or w[j] in ("-C", "--git-dir", "--work-tree") or w[j].startswith(("--git-dir=", "--work-tree=")) j += 2 if w[j] in GIT_ARG else 1 + if j < len(w) and w[j] in ("add", "stage"): + s, new, force, dry, i = add(w, j + 1) + if not dry: + pending.append((s, new, force)) + continue if j >= len(w) or w[j] != "commit": i = j continue commits += 1 + adds, pending = adds + pending, [] k, rest, mine, index = j + 1, False, [], False while k < len(w): a = w[k] @@ -344,7 +387,13 @@ out = git("diff", "--name-only", "HEAD", "--", *specs) if only else None if out is None or out.returncode != 0: # not path-limited, or no HEAD yet only = False out = git("diff", "--name-only", "--", *specs) if specs else None -sys.stdout.buffer.write((b"CCGS-ONLY\n" if only else b"CCGS-INDEX\n") + (out.stdout if out else b"")) +more = b"" +for s, new, force in ([] if only else adds): + s = [":/"] if away else s + more += git("diff", "--name-only", "--", *s).stdout + if new: + more += git("ls-files", "--others", "--full-name", *([] if force else ["--exclude-standard"]), "--", *s).stdout +sys.stdout.buffer.write((b"CCGS-ONLY\n" if only else b"CCGS-INDEX\n") + (out.stdout if out else b"") + more) ' "$_VC_AWAY" 2>/dev/null) case "$_VC_TOK" in CCGS-ONLY*) INDEX_FILES="" ;; esac WT_FILES=$(printf '%s\n%s' "$WT_FILES" "$(printf '%s\n' "$_VC_TOK" | tail -n +2)") @@ -355,8 +404,24 @@ else for _p in $(printf '%s' "$_AFTER" | LC_ALL=C grep -oE '(assets|Assets|Content)/[^[:space:]"'"'"';|&)]*'); do WT_FILES=$(printf '%s\n%s' "$WT_FILES" "$($_GIT diff --name-only -- "$_p" 2>/dev/null)") done + # No tokeniser to read a `git add`'s paths: take every change and new file. + if git_segment add "$COMMAND" >/dev/null || git_segment stage "$COMMAND" >/dev/null; then + WT_FILES=$(printf '%s\n%s\n%s' "$WT_FILES" "$($_GIT diff --name-only 2>/dev/null)" \ + "$($_GIT ls-files --others --exclude-standard --full-name 2>/dev/null)") + fi fi WT_FILES=$(printf '%s\n' "$WT_FILES" | grep -v '^$' | sort -u) +# A project in a subfolder of a larger repository (game/ in a monorepo): git +# names every path above from the repository's top level, and every check below +# matches from the PROJECT root (^assets/, ^design/gdd/, the code root) and +# reads files relative to it. Unconverted, nothing matched and the commit went +# through unchecked. Keep this project's paths with the prefix dropped; files +# outside the project are not ours to check. "" at the top level. +_VC_PREFIX=$(git rev-parse --show-prefix 2>/dev/null) +if [ -n "$_VC_PREFIX" ]; then + INDEX_FILES=$(printf '%s\n' "$INDEX_FILES" | LC_ALL=C awk -v p="$_VC_PREFIX" 'index($0, p) == 1 { print substr($0, length(p) + 1) }') + WT_FILES=$(printf '%s\n' "$WT_FILES" | LC_ALL=C awk -v p="$_VC_PREFIX" 'index($0, p) == 1 { print substr($0, length(p) + 1) }') +fi STAGED=$(printf '%s\n%s\n' "$INDEX_FILES" "$WT_FILES" | grep -v '^$' | sort -u) if [ -z "$STAGED" ]; then exit 0 @@ -390,14 +455,11 @@ trap '[ -n "$TMP_DESIGN" ] && rm -f "$TMP_DESIGN"' EXIT # it appends to $WARNINGS and the hook still exits 0. This block is the only one # that can exit 2, and exit 2 is the entire reason the hook is registered. # -# Running it THIRD, after the design-section scan, and validating one file -# per `python -m json.tool` invocation -- one interpreter spawn each, ~110ms on -# Windows -- gets the hook killed by its 15s timeout on a large commit before -# it reaches the corrupt file, so whether a bad file is caught depends on where -# its NAME SORTED. Measured with 201 staged files and one corrupt: -# -# corrupt sorts FIRST -> 730ms, rc=2, BLOCKED emitted -# corrupt sorts LAST -> 15217ms, rc=124, nothing emitted, commit not blocked +# Running it after the design-section scan, and validating one file per +# `python -m json.tool` invocation -- one interpreter spawn each -- would get the +# hook killed by its 15s timeout on a large commit before it reaches a corrupt +# file, so whether a bad file is caught would depend on where its NAME SORTS: a +# corrupt file sorting first is blocked, one sorting last lets the commit through. # # Two independent fixes, because either alone is a mitigation rather than a # guarantee: @@ -432,17 +494,19 @@ if [ -n "$DATA_FILES" ]; then JSON_OUT=$(LC_ALL=C awk -v OFS='\t' 'NR == FNR { if ($0 != "") wt[$0] = 1; next } $0 != "" { print (($0 in wt) ? "W" : "I"), $0 }' \ <(printf '%s\n' "$WT_FILES") <(printf '%s\n' "$DATA_FILES") \ - | "$PYTHON_CMD" -c ' + | CCGS_VC_PREFIX="$_VC_PREFIX" "$PYTHON_CMD" -c ' import json, sys, os, subprocess -bad = [] +bad, lfs_unread = [], [] # Bytes in, decoded as UTF-8: a Windows console code page would mangle a # non-ASCII path before it reached os.path or git. items = [l.split("\t", 1) for l in sys.stdin.buffer.read().decode("utf-8").splitlines() if "\t" in l] staged = [p for mode, p in items if mode == "I"] +# Paths are project-relative; the index names them from the repository top. +prefix = os.environ.get("CCGS_VC_PREFIX", "") blobs = {} if staged: out = subprocess.run(["git", "cat-file", "--batch"], stdout=subprocess.PIPE, - input="".join(":" + p + "\n" for p in staged).encode("utf-8")).stdout + input="".join(":" + prefix + p + "\n" for p in staged).encode("utf-8")).stdout pos = 0 for p in staged: end = out.index(b"\n", pos) @@ -458,6 +522,16 @@ for mode, p in items: if p not in blobs: continue # removed from the index: nothing of it is committed data = blobs[p] + if data.startswith(b"version https://git-lfs.github.com/spec/"): + # A Git LFS pointer: git add stored the file in LFS and staged + # this stub, which is never JSON. The working copy is the file + # it stored. With no working copy there is nothing to read -- + # say so, do not block a valid file or pass it in silence. + if not os.path.isfile(p): + lfs_unread.append(p) + continue + with open(p, "rb") as fh: + data = fh.read() else: if not os.path.isfile(p): continue @@ -470,13 +544,20 @@ for mode, p in items: # putting a CR inside every path but the last. Invisible in a terminal and in # a line-by-line diff -- only a byte comparison against the pre-batch # implementation surfaced it. get_yaml_key writes bytes for the same reason. -sys.stdout.buffer.write(("CCGS-JSON-CHECKED\n" + "\n".join(bad)).encode("utf-8")) +# One line per file: "Bpath" not valid JSON, "Spath" an LFS pointer +# with no working copy to read. +sys.stdout.buffer.write(("CCGS-JSON-CHECKED\n" + "".join("B\t" + p + "\n" for p in bad) + + "".join("S\t" + p + "\n" for p in lfs_unread)).encode("utf-8")) ' 2>/dev/null) if [ "$(printf '%s\n' "$JSON_OUT" | head -1)" != "CCGS-JSON-CHECKED" ]; then echo "BLOCKED: $(printf '%s\n' "$DATA_FILES" | grep -c .) staged data file(s) could not be validated -- the JSON check did not run under '$PYTHON_CMD'. Check that it is a working Python 3 and commit again." >&2 exit 2 fi - BAD_JSON=$(printf '%s\n' "$JSON_OUT" | tail -n +2) + BAD_JSON=$(printf '%s\n' "$JSON_OUT" | tail -n +2 | LC_ALL=C awk -F'\t' '$1 == "B" { print $2 }') + LFS_UNREAD=$(printf '%s\n' "$JSON_OUT" | tail -n +2 | LC_ALL=C awk -F'\t' '$1 == "S" { print $2 }') + if [ -n "$LFS_UNREAD" ]; then + WARNINGS="$WARNINGS\nSKIPPED: $(printf '%s\n' "$LFS_UNREAD" | grep -c .) staged data file(s) are Git LFS pointers with no working copy, so the JSON check did NOT read them: $(printf '%s' "$LFS_UNREAD" | tr '\n' ' ')" + fi if [ -n "$BAD_JSON" ]; then # Every offender at once. The per-file loop reported only the first # and exited, so a commit with several bad files took several @@ -518,7 +599,12 @@ if [ -f .claude/hooks/yaml-helper.sh ]; then command -v resolve_setting >/dev/null 2>&1 && _VC_HELPER=1 fi -DESIGN_FILES=$(echo "$STAGED" | grep -E '^design/gdd/') +# design/gdd/ also holds governance and registry files that are not system +# GDDs and have none of these sections, so they warned on every commit (#133). +# Skip the names not_a_system_gdd() skips in gdd-structure-check.sh and +# review-scope.sh; keep the three lists the same. +DESIGN_FILES=$(echo "$STAGED" | grep -E '^design/gdd/' \ + | grep -vE '/(game-concept|systems-index|game-pillars|gdd-cross-review-[^/]*|gameplay-tags|fixture-swap-ledger|entity-registry|sound-bible)\.md$') if [ -n "$DESIGN_FILES" ]; then WORKFLOW="standard" if [ "$_VC_HELPER" = 1 ]; then @@ -545,11 +631,9 @@ if [ -n "$DESIGN_FILES" ]; then # # A nested shell loop -- for each staged design doc, `echo | # tr | while read` then one `grep -qi` per required section -- does not - # scale. At - # workflow=full that is 8 greps per file, and each is a process. 50 - # design docs measured 14644ms -- 97% of this hook's 15s budget, from - # the ADVISORY half alone. 50 GDDs is an ordinary project, not a - # stress case. + # scale. At workflow=full that is 8 greps per file, and each is a + # process, so an ordinary project of about 50 GDDs would use nearly all + # of this hook's 15s budget on the ADVISORY half alone. # # Matching is unchanged on purpose: case-insensitive SUBSTRING anywhere # in the file, exactly what `grep -qi "$section"` did. It is looser than diff --git a/.claude/hooks/validate-push.sh b/.claude/hooks/validate-push.sh index b3f8c83b..727889c5 100644 --- a/.claude/hooks/validate-push.sh +++ b/.claude/hooks/validate-push.sh @@ -39,7 +39,7 @@ INPUT=$(cat) # Most Bash and PowerShell calls do not mention git at all. Leave before any # parsing: this hook runs on every one of them, and the parse is most of its -# cost (~350 ms a call measured; the early exit is the shell start-up alone). +# cost (the early exit is the shell start-up alone). # Tested only after the "tool_input" key: matching the whole payload also # tests cwd and transcript_path, so a project path containing "GitHub" or # "digital" never took this exit and paid the full parse on every call. diff --git a/.claude/hooks/yaml-helper.sh b/.claude/hooks/yaml-helper.sh index 408a01f5..d4e2ffc8 100644 --- a/.claude/hooks/yaml-helper.sh +++ b/.claude/hooks/yaml-helper.sh @@ -569,7 +569,11 @@ EOF # and must agree on YAML edge cases exactly, and a shared copy that drifted # would make two functions disagree about what a file says. validate_local_scope() { - local file="${1:-project.local.yaml}" + local file="${1:-}" + # Default to the PROJECT ROOT's local file, not the working directory's: run + # from src/, a bare `project.local.yaml` names a file that is not there, and + # the check passes because it found nothing to check. + if [ -z "$file" ]; then _yaml_helper_set_root; file="$_YH_ROOT/project.local.yaml"; fi [ -f "$file" ] || return 0 if ! _yaml_helper_resolve_python; then return 0; fi local found key rc=0 @@ -646,7 +650,10 @@ def walk(node, prefix): elif dotted.startswith(EXEMPT_PREFIX): continue else: - print(dotted) + # Bytes, not print(): on Windows print() writes CRLF, bash keeps + # the CR, and every key but the last reached the notes line with + # a carriage return on it. The other parsers here write this way. + sys.stdout.buffer.write((dotted + '\n').encode('utf-8')) walk(data, '') PYEOF @@ -682,7 +689,9 @@ EOF # would be self-defeating. session_state_enabled() { local f v - for f in project.local.yaml project.yaml; do + # The root, not the working directory (builtins only -- no added spawn). + _yaml_helper_set_root + for f in "$_YH_ROOT/project.local.yaml" "$_YH_ROOT/project.yaml"; do [ -f "$f" ] || continue v=$(awk ' /^features:[[:space:]]*$/ { inf=1; next } @@ -792,8 +801,8 @@ data = parse(raw_lines) # default. Every enum check below passed on such a file, because a key that # cannot be read cannot hold an invalid value. That is rc=0 on a config that # configures nothing, byte-identical in outcome to a genuinely clean file. -# Measured before this check: the same file with tabs instead of spaces -# reported no errors while `modes.review_mode: BOGUS_VALUE` sat in it unread. +# Without this check, the same file with tabs instead of spaces reports no +# errors while `modes.review_mode: BOGUS_VALUE` sits in it unread. # # This is the validator's own version of the rule the skills are held to -- # absence of evidence is not evidence of absence. It cannot report "no invalid @@ -944,12 +953,12 @@ EOF # Whole-config resolution. # # WHY THIS EXISTS -# ~51 SKILL.md files each carried an English description of a deterministic -# fallback chain ("1. If --review passed -> use that; 2. Else read -# modes.review_mode from project.yaml; 3. Else production/review-mode.txt; -# 4. Else lean"), re-interpreted by a model on every invocation at roughly -# +1,360 tokens per skill. resolve_config computes the same answer once, in -# ~150 tokens, deterministically -- and testably, which prose never was. +# Every skill that reads a setting needs the same deterministic fallback chain +# ("1. If --review passed -> use that; 2. Else read modes.review_mode from +# project.yaml; 3. Else production/review-mode.txt; 4. Else lean"). Written out +# in each SKILL.md, a model would re-interpret that prose on every invocation. +# resolve_config computes the same answer once, deterministically -- and +# testably, which prose never was. # # CONTRACT BOUNDARY # This layer resolves SOURCES. It does not own per-skill policy. Anything @@ -969,32 +978,31 @@ EOF # and this table. Leaving a terminal default here as well would shadow the # expansion and make `rigor` a no-op for anyone who had not also set the sub-knob. # modes.review_mode is fronted by rigor so `rigor: minimal` resolves -# review_mode to `solo` (skipping the ~44k-token director/specialist gates), -# `standard` yields `lean` and `full` yields `full`. team.size joined the fronted -# set the same way: `full` yields `studio` (the whole roster) while +# review_mode to `solo` (skipping the director and specialist gates), +# `standard` yields `lean` and `full` yields `full`. team.size is fronted the +# same way: `full` yields `studio` (the whole roster) while # `minimal`/`standard` yield `individual`. Both stay locally overridable (they # are personal-experience knobs, not on-disk artifacts): that source sits ABOVE -# the expansion, so only the terminal fallback moved. +# the expansion, so a local value wins over the rigor level. # # --- WHY modes.rigor DEFAULTS TO `minimal` ----------------------------------- # -# It defaulted to `standard`. Building the same project both ways showed the -# heavier tier costing several times as much to reach working code without -# producing a better result, and giving nothing back when a fresh developer -# picked the project up. A default that costs more and does not repay is the -# wrong default, and it was what every user who never opened /settings received. +# The heavier tier costs more to reach working code without producing a better +# result, and gives nothing back when a new contributor picks the project up. A +# default that costs more and does not repay is the wrong default, and it is +# what every user who never opens /settings would receive. # -# Raising rigor stays one question in /start and one `/settings` call, and +# Raising rigor is one question in /start and one `/settings` call, and # settings-guidance.md's upward triggers ("system-GDD count crosses ~9", # "gate-check PASS into Production while rigor is minimal") are written to fire # from exactly this starting state. The cost of under-running is one prompt. # # ORDER MATTERS: this default is only safe while /gate-check keeps its floors. # `rigor: minimal` expands to `workflow: minimal` + `qa.level: minimal`, which -# together once left the Production->Polish gate with ZERO required artifacts -- -# a vacuous PASS. That is fixed (the smoke-report floor and the "nothing -# required -> NOT ASSESSED, never PASS" rule). Do not move this default again -# without re-checking that the gates below it still require something. +# together would leave the Production->Polish gate with ZERO required artifacts +# -- a vacuous PASS -- without the smoke-report floor and the "nothing required +# -> NOT ASSESSED, never PASS" rule. Do not change this default without +# re-checking that each /gate-check gate still requires something. _yaml_helper_defaults="\ modes.automation::collaborative modes.rigor::minimal @@ -1002,12 +1010,11 @@ performance.enforce::warn" # Rigor expansion — one asked-at-/start knob that supplies four. # -# WHY: /start has never asked about workflow, docs.density, qa.level or -# story_granularity, so in practice every project ran all four at their defaults. -# Between them the latter three drive ONE behaviour each (prose verbosity, is- -# evidence-required, story size) restated across 19 skills with 17 "we are -# orthogonal" disclaimers. `rigor` makes the common case reachable in one -# question while each knob stays individually settable. +# WHY: /start does not ask about workflow, docs.density, qa.level or +# story_granularity, so in practice a project runs all four at their defaults. +# The latter three each drive one behaviour (prose verbosity, whether evidence +# is required, story size) that many skills read. `rigor` makes the common case +# reachable in one question while each knob stays individually settable. # # modes.workflow is fronted, NOT replaced: it drives ~5 distinct behaviours and # owns the only per-system override mechanism (workflow_overrides.system_ @@ -1120,6 +1127,8 @@ get_legacy_key() { [ -z "$path" ] && return 0 file=$(_yaml_helper_legacy_file_for "$path") [ -z "$file" ] && return 0 + _yaml_helper_set_root + file="$_YH_ROOT/$file" [ -f "$file" ] || return 0 awk 'BEGIN{FS="\n"} { gsub(/\r/,""); sub(/^[ \t]+/,""); sub(/[ \t]+$/,""); if (length($0) > 0) { print; exit } }' "$file" @@ -1153,7 +1162,8 @@ resolve_setting() { if [ -z "$val" ]; then legacy=$(_yaml_helper_legacy_file_for "$path") - if [ -n "$legacy" ] && [ -f "$legacy" ]; then + # Checked under the root; labelled with the short path the user knows. + if [ -n "$legacy" ] && [ -f "$_YH_ROOT/$legacy" ]; then val=$(get_legacy_key "$path") if [ -n "$val" ] && ! validate_enum_value "$path" "$val" 2>/dev/null; then val=""; fi [ -n "$val" ] && src="$legacy" @@ -1330,11 +1340,9 @@ PYEOF # a truncated block a skill might half-read. # resolve_config [--keys k1,k2,...] [] # -# --keys restricts output to the named knobs. USE IT. Emitting all 12 lines costs -# ~188 tokens, while the resolution prose it replaces averages only ~101 tokens -# per skill -- so a full block is a NET LOSS for any skill that reads 2-3 knobs. -# A 3-knob block costs ~45 tokens, which is the actual win. Measured, not -# estimated. +# --keys restricts output to the named knobs. USE IT. A block of every knob +# costs more than the resolution prose it replaces in a skill that reads 2-3 +# knobs; a block of just those knobs is the saving. # Valid key names are the output labels: rigor, review_mode, automation, workflow, # docs.density, story_granularity, qa.level, team.size, project.stage, # automation_always_ask, engine, testing.strict, system_overrides. @@ -1363,11 +1371,14 @@ resolve_config() { orphan=$(validate_local_yaml_base 2>&1) || notes="${notes:+$notes; }$orphan" # Collect enum complaints from both files so a typo is visible, not silent. + # Every file below is named under $_YH_ROOT. A bare `project.yaml` is the + # WORKING directory's, so run from src/ these checks found no file and + # reported nothing, while the values above them resolved from the root. local enum_err - enum_err=$(validate_yaml_enum project.yaml 2>&1 >/dev/null) + enum_err=$(validate_yaml_enum "$_YH_ROOT/project.yaml" 2>&1 >/dev/null) [ -n "$enum_err" ] && notes="${notes:+$notes; }$(echo "$enum_err" | tr '\n' ';' | sed 's/;$//') — ignored, chain continued" if [ -f "$_YH_ROOT/project.local.yaml" ]; then - enum_err=$(validate_yaml_enum project.local.yaml 2>&1 >/dev/null) + enum_err=$(validate_yaml_enum "$_YH_ROOT/project.local.yaml" 2>&1 >/dev/null) [ -n "$enum_err" ] && notes="${notes:+$notes; }local: $(echo "$enum_err" | tr '\n' ';' | sed 's/;$//')" # Locked keys in the local file. Separate from the enum check # above because their VALUES are legal — it is the location that is not, so @@ -1377,17 +1388,16 @@ resolve_config() { # full remedy sentence per key for direct callers, and three copies of it # would cost more of this block than every resolved value put together. local scope_err scope_keys - scope_err=$(validate_local_scope project.local.yaml 2>&1 >/dev/null) + scope_err=$(validate_local_scope "$_YH_ROOT/project.local.yaml" 2>&1 >/dev/null) if [ -n "$scope_err" ]; then scope_keys=$(printf '%s\n' "$scope_err" | sed -n 's/.*`\([^`]*\)`.*/\1/p' | paste -sd, - | sed 's/,/, /g') notes="${notes:+$notes; }local: not locally overridable, ignored — $scope_keys (move to project.yaml or delete)" fi fi - # Framing costs ~81 chars. For a skill reading 1-2 knobs that is more than the + # For a skill reading 1-2 knobs the block's framing would cost more than the # inline chain it replaced, so bare lines are emitted instead -- "automation: - # guided (project.local.yaml)" is self-describing without a banner. Measured: - # single-knob skills were +226 chars WITH framing, negative without it. + # guided (project.local.yaml)" is self-describing without a banner. local nkeys=0 if [ -n "$want" ]; then nkeys=$(printf '%s' "$want" | tr ',' '\n' | grep -c '[a-z]') @@ -1418,13 +1428,21 @@ resolve_config() { done # automation_always_ask: array-valued, so it does not go through resolve_setting. + # Joined item by item. It used to join on commas and then turn every comma + # into ", ", so one quoted item holding a comma printed as two items. An item + # that holds a comma is now quoted, so one item stays one item. + _rc_join() { + printf '%s\n' "$1" | awk '/^[[:space:]]*$/ { next } + { s = $0; if (index(s, ",")) s = "\"" s "\""; out = out (n++ ? ", " : "") s } + END { print out }' + } local aaa if _rc_want automation_always_ask; then aaa=$(get_effective_yaml_array modes.automation_always_ask 2>/dev/null) if [ -n "$aaa" ]; then - echo "automation_always_ask: $(echo "$aaa" | tr '\n' ',' | sed 's/,$//; s/,/, /g') (configured)" + echo "automation_always_ask: $(_rc_join "$aaa") (configured)" else - echo "automation_always_ask: $(echo "$_yaml_helper_always_ask_default" | tr '\n' ',' | sed 's/,$//; s/,/, /g') (default)" + echo "automation_always_ask: $(_rc_join "$_yaml_helper_always_ask_default") (default)" fi fi @@ -1444,11 +1462,29 @@ resolve_config() { # testing.strict.*: reported as CONFIGURED STATE ONLY, never defaulted here. # Its unset default differs per skill by design. - local ts_out="" k tv + # + # Each value is validated before it counts: get_effective_yaml_key printed an + # invalid value (`logic: maybe`) as the value while the notes line said it was + # ignored. Local first (the keys are locally overridable), then project.yaml, + # then the scalar shorthand (`testing.strict: true`), each checked against + # true|false. Not resolve_setting: that adds a rigor lookup per type, and + # testing.strict is neither rigor-fronted nor defaulted -- five more + # interpreter spawns for nothing. validate_enum_value is bash only. + local ts_out="" k tv ts_all if _rc_want testing.strict; then + ts_all=$(get_yaml_key "$_YH_ROOT/project.yaml" testing.strict 2>/dev/null) + if [ -n "$ts_all" ] && ! validate_enum_value testing.strict.logic "$ts_all" 2>/dev/null; then ts_all=""; fi for k in logic integration visual ui config; do - tv=$(get_effective_yaml_key "testing.strict.$k" 2>/dev/null) - [ -z "$tv" ] && tv=$(get_yaml_key "$_YH_ROOT/project.yaml" testing.strict 2>/dev/null) + tv="" + if [ -f "$_YH_ROOT/project.local.yaml" ]; then + tv=$(get_yaml_key "$_YH_ROOT/project.local.yaml" "testing.strict.$k" 2>/dev/null) + if [ -n "$tv" ] && ! validate_enum_value "testing.strict.$k" "$tv" 2>/dev/null; then tv=""; fi + fi + if [ -z "$tv" ]; then + tv=$(get_yaml_key "$_YH_ROOT/project.yaml" "testing.strict.$k" 2>/dev/null) + if [ -n "$tv" ] && ! validate_enum_value "testing.strict.$k" "$tv" 2>/dev/null; then tv=""; fi + fi + [ -z "$tv" ] && tv="$ts_all" ts_out="$ts_out $k=${tv:-unset}" done echo "testing.strict:${ts_out} (unset = each skill applies its own default)" @@ -1498,11 +1534,18 @@ resolve_config() { # skill-authoring.md. Substituting `none` would make the question unaskable; # substituting anything else would emit every track, which is the ~150-item # checklist a single-platform jam project once received. - local ct + # + # Through resolve_setting, as performance.enforce above. get_effective_yaml_key + # let a hand-edited project.local.yaml win although platform.* is locked, and + # printed an invalid value (`banana`) as the value while the notes line said + # it was ignored. Only project.yaml can set it, so any other source -- there is + # no default to fall to -- leaves it unset and the skill asks. + local ct cs if _rc_want cert_tier || _rc_want platform.cert_tier; then - ct=$(get_effective_yaml_key platform.cert_tier 2>/dev/null) - if [ -n "$ct" ]; then - echo "platform.cert_tier: $ct" + ct=$(resolve_setting platform.cert_tier) + cs="${ct#*$(printf '\t')}"; ct="${ct%%$(printf '\t')*}" + if [ -n "$ct" ] && [ "$cs" = "project.yaml" ]; then + echo "platform.cert_tier: $ct ($cs)" else echo "platform.cert_tier: (unset -- ask which platforms are in scope)" fi @@ -1512,7 +1555,7 @@ resolve_config() { # second call. A named is echoed explicitly for convenience. local so_keys so_out="" sk sv if _rc_want system_overrides; then - so_keys=$(get_yaml_child_keys project.yaml workflow_overrides.system_overrides 2>/dev/null) + so_keys=$(get_yaml_child_keys "$_YH_ROOT/project.yaml" workflow_overrides.system_overrides 2>/dev/null) if [ -n "$so_keys" ]; then while IFS= read -r sk; do [ -z "$sk" ] && continue @@ -1582,7 +1625,7 @@ hook_warn() { # Skills cannot `source` this file in their `` !`cmd` `` bootstrap line. Claude # Code permission-checks every injected command before the skill renders, and # outside auto mode anything short of "allow" ABORTS the whole invocation -- -# measured on 2.1.281, see .claude/docs/config-resolution.md. A `${VAR:-x}` or +# see .claude/docs/config-resolution.md. A `${VAR:-x}` or # `$( )` in the command fails that check as "Contains expansion" and no grant can # approve it; a `source … && resolve_config` compound needs every part approved. # `${CLAUDE_SKILL_DIR}` is substituted as text before the check, so one plain @@ -1594,7 +1637,7 @@ hook_warn() { # every name added here widens what a skill grant can reach. # # ROOT. Run from a subdirectory, the skill shell's cwd has no project.yaml and -# $CLAUDE_PROJECT_DIR is the launch directory, not the repo root (measured), so +# $CLAUDE_PROJECT_DIR is the launch directory, not the repo root, so # rules 1-3 of _yaml_helper_set_root all miss. This file's own location is the # one anchor that cannot drift: hooks/ sits two levels below the root. It only # fills CLAUDE_PROJECT_DIR when that has no project.yaml, so rules 1-2 (cwd diff --git a/.claude/rules/agent-memory.md b/.claude/rules/agent-memory.md index 4029abd2..d523248a 100644 --- a/.claude/rules/agent-memory.md +++ b/.claude/rules/agent-memory.md @@ -5,16 +5,25 @@ paths: # Agent Memory Rules -**Agent memory is the one place an agent may write without asking — and the only -one.** `.claude/agent-memory/` is gitignored, per-agent, and never ships. That -exemption exists because the memory is the agent's own working notes about how to -do its job, not a project artifact. +**Agent memory is one of three writes that need no "May I write?"** The other two +are named in `CLAUDE.md`: -It does **not** extend anywhere else. The Collaboration Protocol still governs -every file under the code root (`src/`, `Assets/` or `Source/`), `design/`, -`docs/`, `production/` and `assets/`: ask -first, naming the path. Writing a memory is never a substitute for asking, and a -memory must never be used to record something the user declined to have written. +- **Appends to `production/session-state/active.md`** — the session checkpoint + the hooks and the next session rely on. An append, never a rewrite of what is + already there. +- **A subagent's new file at the path its orchestrating skill named.** Only a + new file under `production/`, `docs/` or `tests/`, only at a path the skill's + prompt names (never one you chose), and only inside a phase the user approved. + +`.claude/agent-memory/` is gitignored, per-agent, and never ships. Its exemption +exists because the memory is the agent's own working notes about how to do its +job, not a project artifact. + +None of the three extends anywhere else. The Collaboration Protocol still governs +every other write under the code root (`src/`, `Assets/` or `Source/`), +`design/`, `docs/`, `production/` and `assets/`: ask first, naming the path. +Writing a memory is never a substitute for asking, and a memory must never be +used to record something the user declined to have written. ## Never record a temporary absence as a durable fact diff --git a/.claude/rules/skill-authoring.md b/.claude/rules/skill-authoring.md index 05848e6c..6993e82e 100644 --- a/.claude/rules/skill-authoring.md +++ b/.claude/rules/skill-authoring.md @@ -78,32 +78,16 @@ list.** A gate that fires on forty files does not get fixed, it gets muted — a a muted gate is worse than a narrow one, because it reads as coverage. When you keep a list, record *why* derivation failed and state the obligation to extend it. -Two further gate rules earned the hard way: +Two further gate rules: - **Assert something that cannot be true by accident.** A check for the word - "unity" was satisfied by a file path, and case-insensitively by "community". + "unity" is satisfied by a file path, and case-insensitively by "community". Assert a distinctive token instead. - **A gate you have not watched fail is not a gate.** Break the thing it guards, confirm it fails, restore. One mutation per tool invocation — a batch that times out leaves the repo holding a broken file, and `trap … EXIT` does not survive `SIGTERM`. -## Evidence - -Every row below is a real instance this rule was written to prevent. - -| Where | What was indistinguishable from success | -|---|---| -| `team-*` engine step | Specialist skipped when no engine configured — output identical to a run that consulted one | -| `team-ui` accessibility gate | Passed vacuously; its criterion file did not exist | -| `yaml-helper` | Locked key in `project.local.yaml` dropped in silence; user saw the default they were overriding | -| all nine `team-*` | Pipeline printed six agents and ran one, with no statement of the difference | -| `/security-audit` | Godot-only greps returned zero hits on Unity/Unreal, and zero hits read as clean | -| `unity/VERSION.md` | "Post-cutoff" table listed pre-cutoff versions, inverting the signal it exists to send | -| `/security-audit` | `platform.multiplayer` had a reader and no writer; the network category never ran, on any project | -| `test-evidence-review` | No verdict for "could not check", so an unverifiable story got a verdict saying it was verified | -| the gate meant to catch all of this | Was a hand-written list, and read green over the gap | - ## The test to apply Before shipping a skill or gate, ask: **if this step silently did not run, what diff --git a/.claude/scripts/migrate-v1-config.sh b/.claude/scripts/migrate-v1-config.sh index 8c9caae2..353d8678 100644 --- a/.claude/scripts/migrate-v1-config.sh +++ b/.claude/scripts/migrate-v1-config.sh @@ -569,7 +569,7 @@ fi echo "schema_version: 1" echo "" echo "framework:" - echo " version: 1.1.2" + echo " version: 1.1.3" echo "" # Emit `project:` only when there is a stage to put in it -- same rule as the # `modes:` block below. Writing `stage: null` produced a file that FAILED THIS diff --git a/.claude/scripts/project-coherence.sh b/.claude/scripts/project-coherence.sh index 0e372a0d..8aedc4bd 100644 --- a/.claude/scripts/project-coherence.sh +++ b/.claude/scripts/project-coherence.sh @@ -33,7 +33,10 @@ set -u export LC_ALL=C -ROOT="${CLAUDE_PROJECT_DIR:-$(cd "$(dirname "$0")/../.." && pwd)}" +ROOT="$(cd "$(dirname "$0")/../.." && pwd)" +if [ -n "${CLAUDE_PROJECT_DIR:-}" ] && [ -f "$CLAUDE_PROJECT_DIR/project.yaml" ]; then + ROOT="$CLAUDE_PROJECT_DIR" +fi cd "$ROOT" || exit 0 DIFFERS=0 @@ -163,7 +166,45 @@ case "$ENGINE_LC" in fi [ -n "$UEXE" ] && [ -x "$UEXE" ] && PROBE="$("$UEXE" -version 2>/dev/null | head -1)" ;; - unreal) command -v UnrealEditor-Cmd >/dev/null 2>&1 && PROBE="$(UnrealEditor-Cmd -version 2>/dev/null | head -1)" ;; + unreal) + # Never start the editor to learn its version: UnrealEditor-Cmd has no + # -version flag (UE 5.8), so it opened the editor and ran until killed, and + # /smoke-check's step 0 waited for ever. Read the engine's own + # Engine/Build/Build.version instead, under the first engine root found: + # engine.path (/setup-engine writes the UE root there), the editor path in + # commands.test, the launcher folder for the .uproject's EngineAssociation, + # then UnrealEditor-Cmd on PATH. A candidate that is not itself a root is + # cut back to the folder above its last /Engine. A source build's + # EngineAssociation is a GUID with no folder to derive, so it adds nothing. + UASSOC="$(sed -n 's/.*"EngineAssociation"[[:space:]]*:[[:space:]]*"\([0-9][0-9.]*\)".*/\1/p' ./*.uproject 2>/dev/null | head -1)" + ULAUNCH="" + if [ -n "$UASSOC" ]; then + case "$(uname -s)" in + Darwin) ULAUNCH="/Users/Shared/Epic Games/UE_$UASSOC" ;; + Linux) ;; + *) ULAUNCH="C:/Program Files/Epic Games/UE_$UASSOC" ;; + esac + fi + UROOT="" + for UCAND in \ + "$(yaml_block_value engine path)" \ + "$(yaml_block_value commands test | grep -oE '"[^"]*UnrealEditor[^"]*"' | head -1 | tr -d '"')" \ + "$ULAUNCH" \ + "$(command -v UnrealEditor-Cmd 2>/dev/null)"; do + [ -n "$UCAND" ] || continue + UCAND="$(printf '%s' "$UCAND" | tr '\\' '/')" + for UTRY in "$UCAND" "$(printf '%s' "$UCAND" | sed -E 's#^(.*)/Engine(/.*)?$#\1#')"; do + if [ -f "$UTRY/Engine/Build/Build.version" ]; then UROOT="$UTRY"; break 2; fi + done + done + if [ -n "$UROOT" ]; then + UBV="$(tr -d '\r\n' < "$UROOT/Engine/Build/Build.version")" + UMAJ="$(printf '%s' "$UBV" | grep -oE '"MajorVersion"[[:space:]]*:[[:space:]]*[0-9]+' | grep -oE '[0-9]+$')" + UMIN="$(printf '%s' "$UBV" | grep -oE '"MinorVersion"[[:space:]]*:[[:space:]]*[0-9]+' | grep -oE '[0-9]+$')" + UPAT="$(printf '%s' "$UBV" | grep -oE '"PatchVersion"[[:space:]]*:[[:space:]]*[0-9]+' | grep -oE '[0-9]+$')" + [ -n "$UMAJ" ] && [ -n "$UMIN" ] && PROBE="$UMAJ.$UMIN${UPAT:+.$UPAT} (Engine/Build/Build.version)" + fi + ;; esac if [ -z "$PROBE" ]; then @@ -171,6 +212,8 @@ if [ -z "$PROBE" ]; then skipped "declared version vs installed binary — no Unity editor at the path in commands.test or in the Hub folder for engine.version. A probe that could not run has not established absence." elif [ "$ENGINE_LC" = "godot" ]; then skipped "declared version vs installed binary — no Godot executable found (commands.test, engine.path, PATH). A probe that could not run has not established absence." + elif [ "$ENGINE_LC" = "unreal" ]; then + skipped "declared version vs installed engine — no readable Engine/Build/Build.version under engine.path, the editor in commands.test, the launcher folder for the .uproject's EngineAssociation, or UnrealEditor-Cmd on PATH. A probe that could not run has not established absence." else skipped "declared version vs installed binary — no $ENGINE binary found on PATH. A probe that could not run has not established absence." fi diff --git a/.claude/settings.json b/.claude/settings.json index eba4d5fc..c4672535 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -7,16 +7,9 @@ "permissions": { "defaultMode": "default", "allow": [ - "Bash(git status*)", - "Bash(git diff*)", - "Bash(git log*)", - "Bash(git branch*)", - "Bash(git rev-parse*)", - "Bash(ls *)", "Bash(dir *)", - "Bash(python -m json.tool*)", - "Bash(python -m pytest*)", - "Bash(py -m pytest*)" + "Bash(python -m pytest *)", + "Bash(py -m pytest *)" ], "deny": [ "Bash(rm -rf *)", @@ -95,6 +88,7 @@ "Bash(cat *.env*)", "Bash(type *.env*)", "Read(**/.env*)", + "Edit(**/.env*)", "PowerShell(Remove-Item *-Recurse*)", "PowerShell(Remove-Item * -r*)", "PowerShell(Remove-Item -r*)", diff --git a/.claude/skills/adopt/SKILL.md b/.claude/skills/adopt/SKILL.md index edeb0cd4..a0a877ff 100644 --- a/.claude/skills/adopt/SKILL.md +++ b/.claude/skills/adopt/SKILL.md @@ -13,7 +13,6 @@ Resolved above — use as-is. `/adopt` also inspects `project.yaml` and the lega config files directly when reporting and writing migration state; that raw inspection is deliberate and separate from the resolved values above. - # Adopt — Brownfield Template Adoption This skill audits an existing project's artifacts for **format compliance** with @@ -53,510 +52,31 @@ only the required docs/sections (optional sections are informational, not gaps); ## Phase 1: Detect Project State -Emit one line before reading: `"Scanning project artifacts..."` — this confirms the -skill is running during the silent read phase. - -Then read silently before presenting anything else. - -### Existence check -- `project.stage` in `project.yaml` (fallback `production/stage.txt`) — if either is present, use that value (authoritative phase) -- `design/gdd/game-concept.md` (or, at the minimal tier, `design/game-brief.md`) — concept exists? -- `design/gdd/systems-index.md` — systems index exists? -- Count GDD files: `design/gdd/*.md` (excluding game-concept.md and systems-index.md) -- Count ADR files: `docs/architecture/adr-*.md` -- Count story files: `production/epics/**/*.md` (excluding EPIC.md) -- `project.yaml` (`engine.name`) / `.claude/docs/technical-preferences.md` — engine configured? -- `docs/engine-reference/` — engine reference docs present? -- Glob `docs/adoption-plan-*.md` — note the filename of the most recent prior plan if any exist - -### Infer phase (if no project.stage / stage.txt) -Use the same heuristic as `/project-stage-detect`: -- 10+ source files in the code root → Production -- Stories in `production/epics/` → Pre-Production -- ADRs exist → Technical Setup -- systems-index.md exists → Systems Design -- game-concept.md (or `design/game-brief.md`) exists → Concept -- Nothing → Fresh (not a brownfield project — suggest `/start`) - -If the project appears fresh (no artifacts at all), use `AskUserQuestion`: -- "This looks like a fresh project — no existing artifacts found. `/adopt` is for - projects with work to migrate. What would you like to do?" - - "Run `/start` — begin guided first-time onboarding" - - "My artifacts are in a non-standard location — help me find them" - - "Cancel" - -Then stop — do not proceed with the audit regardless of which option the user picks -(each option leads to a different skill or manual investigation). - -Report: "Detected phase: [phase]. Found: [N] GDDs, [M] ADRs, [P] stories." - ---- +**Read `references/1-detect.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 2: Format Audit -For each artifact type in scope (based on argument mode **and the resolved -workflow tier**), check not just that the file exists but that it contains the -internal structure the template requires. At `minimal`, scope the audit to -`design/game-brief.md` — do not audit for GDDs, ADRs, or UX specs (they are not expected). -Steps 2e (the Engine reference row only), 2f (project config) and 2g (v1.0 -migration check) run at every tier. - -### 2a: GDD Format Audit - -**Gather section presence deterministically — do not read the GDDs to count -headings.** For each GDD discovered in Phase 1, pass its path explicitly to the -structure-check script: - -``` -Bash: bash .claude/scripts/gdd-structure-check.sh [path-to-gdd] -``` - -**Pass paths one at a time; do not invoke it bare.** The no-argument form sweeps -`design/gdd/` only, and a brownfield project's GDDs are not guaranteed to live -there — pass whatever paths Phase 1 found. The script prints a `PRESENT:` list -and, when applicable, an `ABSENT:` list per file. It reports **presence only** -and makes no REQUIRED/ADVISORY judgment (that is the tier logic below), and it -already accepts `## Detailed Design` as satisfying the `Detailed Rules` -requirement, so do not flag that alias as missing. - -If the script prints `Not found:` for a path or errors, that is a **discovery -failure, not a format gap** — report it as "could not audit [path]" and do not -count it as a missing-sections finding. - -**Then apply the workflow tier** resolved above to each file's PRESENT/ABSENT -lists. Which sections are **required** (a miss = gap) vs **advisory** (a miss = -informational): -- **`full`** — all 8 sections are required. -- **`standard`** — the 5 required (Overview, Detailed Rules, Edge Cases, - Dependencies, Acceptance Criteria) + Formulas for any system that defines - numeric rules (rates, curves, thresholds, costs — the system's `Category` is a - hint, not the test); Player Fantasy and Tuning Knobs are advisory. -- **`minimal`** — GDDs are not expected; audit `design/game-brief.md` instead, - against `.claude/docs/templates/game-brief.md`: each of the six required fields - present and not a placeholder; the three one-liners advisory. Any GDD that - does exist is checked at the `standard` bar, advisorily. - -The script's 8 canonical labels are: Overview, Player Fantasy, Detailed Rules, -Formulas, Edge Cases, Dependencies, Tuning Knobs, Acceptance Criteria. - -A section reported PRESENT can still be an empty heading. For each GDD, also -record with a targeted grep (not a full read): -- Placeholder-only sections — `Grep pattern="\[To be designed\]"` (or an - equivalent empty/single-line body) marks a present-but-unwritten section. -- The `**Status**:` header field — `Grep pattern="^>?[[:space:]]*\*\*Status\*\*:"`. - Valid values: `Draft`, `In Design`, `Designed`, `In Review`, `Approved`, - `Implemented`, `Needs Revision`. - -> **The `>?` is load-bearing, and so are `Draft`/`Implemented`.** Both emitters -> write this field inside a blockquote — `.claude/docs/templates/game-design-document.md` -> and `/design-system` produce `> **Status**: …` — so an anchor of -> `^\*\*Status\*\*:` matches nothing and reports *every* template-compliant GDD -> as missing its Status. The template's own value list offers `Draft` and -> `Implemented`, so both must count as valid. - -### 2b: ADR Format Audit - -For each ADR file found, check for these critical sections: - -| Section | Impact if missing | -|---|---| -| `## Status` | **BLOCKING** — `/story-readiness` ADR status check silently passes everything | -| `## ADR Dependencies` | HIGH — dependency ordering in `/architecture-review` breaks | -| `## Engine Compatibility` | HIGH — post-cutoff API risk is unknown | -| `## GDD Requirements Addressed` | MEDIUM — traceability matrix loses coverage | -| `## Performance Implications` | LOW — not pipeline-critical | - -For each ADR, record: which sections present, which missing, current Status value -if the Status section exists. - -### 2c: systems-index.md Format Audit - -If `design/gdd/systems-index.md` exists: - -1. **Parenthetical status values** — Grep for any Status cell containing - parentheses: `"Needs Revision ("`, `"In Progress ("`, etc. - These break exact-string matching in `/gate-check`, `/create-stories`, - and `/architecture-review`. **BLOCKING.** - -2. **Valid status values** — check that Status column values are only from: - `Not Started`, `In Progress`, `In Review`, `Designed`, `Approved`, `Needs Revision` - Flag any unrecognised values. - -3. **Column structure** — check that the table has at minimum: System name, - Layer, Priority, Status columns. Missing columns degrade skill functionality. - -### 2d: Story Format Audit - -For each story file found: - -- **`Manifest Version:` field** — present in story header? (LOW — auto-passes if absent) -- **TR-ID reference** — does story contain `TR-[a-z]+-[0-9]+` pattern? (MEDIUM — no staleness tracking) -- **ADR reference** — does story reference at least one ADR? (check for `ADR-` pattern) -- **Status field** — present and readable? -- **Acceptance criteria** — does the story have a checkbox list (`- [ ]`)? - -### 2e: Infrastructure Audit - -| Artifact | Path | Impact if missing | -|---|---|---| -| TR registry | `docs/architecture/tr-registry.yaml` | HIGH — no stable requirement IDs | -| Control manifest | `docs/architecture/control-manifest.md` | HIGH — no layer rules for stories | -| Manifest version stamp | In manifest header: `Manifest Version:` | MEDIUM — staleness checks blind | -| Sprint status | `production/sprint-status.yaml` | MEDIUM — `/sprint-status` falls back to markdown | -| Stage file | `project.stage` in `project.yaml` (fallback `production/stage.txt`) | MEDIUM — phase auto-detect unreliable | -| Engine reference | `docs/engine-reference/[engine]/VERSION.md` | HIGH — ADR engine checks blind | -| Architecture traceability | `docs/architecture/requirements-traceability.md` | MEDIUM — no persistent matrix | - -At `workflow: minimal` only the Engine reference row applies. The TR registry, -control manifest and its version stamp, sprint status, stage file and -traceability matrix are not on the minimal path, so their absence is not a gap. - -### 2f: Project Config Audit - -Read `project.yaml` (the primary config store) and `.claude/docs/technical-preferences.md` (legacy mirror). A setting counts as configured if EITHER source has a real value (in technical-preferences.md, `[TO BE CONFIGURED]` means unconfigured): -- `engine.name`/`version`/`language`/`rendering`/`physics` (else the Engine/Language/Rendering/Physics fields) → HIGH if unconfigured in both (ADR skills fail) -- `naming.*` (else Naming conventions) → MEDIUM -- `performance.*` (else Performance budgets) → MEDIUM -- Forbidden Patterns, Allowed Libraries (technical-preferences.md only — not migrated to project.yaml) → LOW (starts empty by design) - -### 2g: v1.0 Migration Check - -A project is a **v1.0 project needing migration** when `project.yaml` does NOT -exist at the repo root AND at least one legacy file does: `production/stage.txt`, -`production/review-mode.txt`, or a `.claude/docs/technical-preferences.md` with -real values. - -"Real values" means one of the keys the converter actually migrates — Engine, -Language, Rendering, Physics, the naming, platform and performance fields, -Framework, or the specialists. Not merely "some bullet is filled in": the -shipped template ships one prose default (`- **Required Tests**: …`) that is -never migrated, and counting it made every fresh clone read as a v1.0 project. - -Do not hand-migrate. Run the converter, which is deterministic and covered by -the framework's own test suite: - -```bash -bash .claude/scripts/migrate-v1-config.sh --dry-run -``` - -The dry run writes nothing; record what it lists for the report. Do not run the -converter during the audit — Phase 2 reads silently. The migration is -classified BLOCKING in Phase 3, heads the plan, and **Phase 7 offers it as the -first action**: report what the dry run listed, then ask "May I run the -converter? It writes `project.yaml` and `production/migration-report.md`." If -the user approves, run it without `--dry-run`. It -writes `project.yaml` plus `production/migration-report.md` and **deletes -nothing** — the whole operation stays reversible with `git checkout`. - -Then tell the user to read `production/migration-report.md` before running: - -```bash -bash .claude/scripts/migrate-v1-config.sh --finalize -``` - -`--finalize` deletes a legacy file only after proving its value is present in -`project.yaml`; on mismatch it deletes nothing and exits 4. It never deletes -`technical-preferences.md`, which still holds Forbidden Patterns and Allowed -Libraries. - -**If the script refuses with exit 3**, do not work around it. Exit 3 means one -of two things, and the message says which: - -- **the values DISAGREE** — two sources of truth and no way to know which the - user edited last. Surface it and let them decide. -- **a `production/migration-report.md` is already present** — a migration ran - here, so these are post-migration leftovers and `--finalize` is the next step, - not a second `migrate`. - -Both files merely *existing* is not exit 3 and must not be reported as a -conflict: `/start` writes `production/stage.txt` on every new v1.1 project as a -mirror, so agreement is the normal state. The script says -`the legacy files mirror it (values agree)` and exits 0 for that. - -Classify as **BLOCKING** in Phase 3: until migration runs, every skill reads -config through the legacy fallback chain, and v1.1 settings are unavailable. - ---- +**Read `references/2-format-audit.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 3: Classify and Prioritise Gaps -Organise every gap found across all audits into four severity tiers: - -**BLOCKING** — Will cause template skills to silently produce wrong results *right now*. -Examples: ADR missing Status field, systems-index parenthetical status values, -engine not configured when ADRs exist. - -**HIGH** — Will cause stories to be generated with missing safety checks, or -infrastructure bootstrapping will fail. -Examples: ADRs missing Engine Compatibility, GDDs missing Acceptance Criteria -(stories can't be generated from them), tr-registry.yaml missing. - -**MEDIUM** — Degrades quality and pipeline tracking but does not break functionality. -Examples: GDDs missing Tuning Knobs or Formulas sections, stories missing TR-IDs, -sprint-status.yaml missing. - -**LOW** — Retroactive improvements that are nice-to-have but not urgent. -Examples: Stories missing Manifest Version stamps, GDDs missing Open Questions section. - -Count totals per tier. If zero BLOCKING and zero HIGH gaps: report that the project -is template-compatible and only advisory improvements remain. - ---- +**Read `references/3-classify.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 4: Build the Migration Plan -Compose a numbered, ordered action plan. Ordering rules: -1. BLOCKING gaps first (must fix before any pipeline skill runs reliably) -2. HIGH gaps next, infrastructure before GDD/ADR content (bootstrapping needs correct formats) -3. MEDIUM gaps ordered: GDD gaps before ADR gaps before story gaps (stories depend on GDDs and ADRs) -4. LOW gaps last - -For each gap, produce a plan entry with: -- A clear problem statement (one sentence, no jargon) -- The exact command to fix it, if a skill handles it -- Manual steps if it requires direct editing -- A time estimate (rough: 5 min / 30 min / 1 session) -- A checkbox `- [ ]` for tracking - -**Special case — systems-index parenthetical status values:** -This is always the first item if present. Show the exact values that need changing -and the exact replacement text. Offer to fix this immediately before writing the plan. - -**Special case — ADRs missing Status field:** -For each affected ADR, the fix is: -`/architecture-decision retrofit docs/architecture/adr-[NNNN]-[slug].md` -List each ADR as a separate checkable item. - -**Special case — GDDs missing sections:** -For each affected GDD, list which sections are missing and the fix: -`/design-system retrofit design/gdd/[filename].md` - -**Infrastructure bootstrap ordering** — always present in this sequence: -1. Fix ADR formats first (registry depends on reading ADR Status fields) -2. Run `/architecture-review` → bootstraps `tr-registry.yaml` -3. Run `/create-control-manifest` → creates manifest with version stamp -4. Run `/sprint-plan update` → creates `sprint-status.yaml` -5. Run `/gate-check [phase]` (the gate into the phase the project is in; at Concept there is none — Concept is the default stage, nothing to run) → writes `project.stage` in `project.yaml` (and legacy `stage.txt`) authoritatively - -**At `workflow: minimal` the plan prescribes none of this sequence.** None of it -is on the minimal path: ADRs are not expected, the brief's build order is the -plan (no `/sprint-plan`), and nothing there runs `/gate-check`. The plan's -Step 3 says so in one line and names the path's next step instead — -`/create-stories` when no stories exist, else `/dev-story`. - -**Existing stories** — note explicitly: -> "Existing stories continue to work with all template skills — all new format -> checks auto-pass when the fields are absent. They won't benefit from TR-ID -> staleness tracking or manifest version checks until they're regenerated. This -> is intentional: do not regenerate stories that are already in progress." - ---- +**Read `references/4-migration-plan.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 5: Present Summary and Ask to Write -Present a compact summary before writing: - -``` -## Adoption Audit Summary -Phase detected: [phase] -Engine: [configured / NOT CONFIGURED] -GDDs audited: [N] ([X] fully compliant, [Y] with gaps) -ADRs audited: [N] ([X] fully compliant, [Y] with gaps) -Stories audited: [N] - -Gap counts: - BLOCKING: [N] — template skills will malfunction without these fixes - HIGH: [N] — unsafe to run /create-stories or /story-readiness - MEDIUM: [N] — quality degradation - LOW: [N] — optional improvements - -Estimated remediation: [X blocking items × ~Y min each = roughly Z hours] -``` - -Before asking to write, show a **Gap Preview**: -- List every BLOCKING gap as a one-line bullet describing the actual problem - (e.g. `systems-index.md: 3 rows have parenthetical status values`, - `adr-0002.md: missing ## Status section`). No counts — show the actual items. -- Show HIGH / MEDIUM / LOW as counts only (e.g. `HIGH: 4, MEDIUM: 2, LOW: 1`). - -This gives the user enough context to judge scope before committing to writing the file. - -If a prior adoption plan was detected in Phase 1, add a note: -> "A previous plan exists at `docs/adoption-plan-[prior-date].md`. The new plan will -> reflect current project state — it does not diff against the prior run." - -Use `AskUserQuestion`: -- "Ready to write the migration plan?" - - "Yes — write `docs/adoption-plan-[date].md`" - - "Show me the full plan preview first (don't write yet)" - - "Cancel — I'll handle migration manually" - -If the user picks "Show me the full plan preview", output the complete plan as a -fenced markdown block. Then ask again with the same three options. - ---- +**Read `references/5-summary.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 6: Write the Adoption Plan -If approved, write `docs/adoption-plan-[date].md` with this structure: - -```markdown -# Adoption Plan - -> **Generated**: [date] -> **Project phase**: [phase] -> **Engine**: [name + version, or "Not configured"] -> **Template version**: v1.0+ - -Work through these steps in order. Check off each item as you complete it. -Re-run `/adopt` anytime to check remaining gaps. - ---- - -## Step 1: Fix Blocking Gaps - -[One sub-section per blocking gap with problem, fix command, time estimate, checkbox] - ---- - -## Step 2: Fix High-Priority Gaps - -[One sub-section per high gap] - ---- - -## Step 3: Bootstrap Infrastructure - -[At `workflow: minimal`, replace 3a–3d with one line: "Not on the minimal path — -the brief's build order is the plan. Next: `/create-stories` (or `/dev-story` -once stories exist)."] - -### 3a. Register existing requirements (creates tr-registry.yaml) -Run `/architecture-review` — even if ADRs already exist, this run bootstraps -the TR registry from your existing GDDs and ADRs. -**Time**: 1 session (review can be long for large codebases) -- [ ] tr-registry.yaml created - -### 3b. Create control manifest -Run `/create-control-manifest` -**Time**: 30 min -- [ ] docs/architecture/control-manifest.md created - -### 3c. Create sprint tracking file -Run `/sprint-plan update` -**Time**: 5 min (if sprint plan already exists as markdown) -- [ ] production/sprint-status.yaml created - -### 3d. Set authoritative project stage -Run `/gate-check [current-phase]` (the gate into the phase the project is in; -at Concept there is none — Concept is the default stage, nothing to run) -**Time**: 5 min -- [ ] `project.stage` in `project.yaml` written (legacy `production/stage.txt` also updated) - ---- - -## Step 4: Medium-Priority Gaps - -[One sub-section per medium gap] - ---- - -## Step 5: Optional Improvements - -[One sub-section per low gap] - ---- - -## What to Expect from Existing Stories - -Existing stories continue to work with all template skills. New format checks -(TR-ID validation, manifest version staleness) auto-pass when the fields are -absent — so nothing breaks. They won't benefit from staleness tracking until -regenerated. Do not regenerate stories that are in progress or done. - ---- - -## Re-run - -Run `/adopt` again after completing Step 3 to verify all blocking and high gaps -are resolved. The new run will reflect the current state of the project. -``` - ---- - -## Phase 6b: Report Review Mode - -**Do not write a review mode.** `modes.review_mode` is one of the six knobs -`modes.rigor` fronts: pinning it in `project.yaml` shadows the rigor expansion, and -the legacy `production/review-mode.txt` sits *above* that expansion in resolution, -so either write would freeze director-review depth for good — the rule `/start` -and `project.yaml`'s header comment both state. - -Report the value the bootstrap above resolved instead: "Review mode resolves to -`[value]` — from `modes.rigor`, unless something pins it." If the user wants a -different depth, point them to changing `modes.rigor`, or to pinning it on purpose -with `/settings --local modes.review_mode=` (a personal override in -`project.local.yaml`). - ---- +**Read `references/6-write.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 7: Offer First Action -After writing the plan, don't stop there. Pick the single highest-priority gap -and offer to handle it immediately using `AskUserQuestion`. Choose the first -branch that applies: - -**If Phase 2g found a v1.0 project needing migration:** offer the converter run -described there — report what the dry run listed and ask "May I run the -converter? It writes `project.yaml` and `production/migration-report.md`." -Every other fix reads config through it, so it comes first. - -**If there are parenthetical status values in systems-index.md:** -Use `AskUserQuestion`: -- "The most urgent fix is `systems-index.md` — [N] rows have parenthetical status - values (e.g. `Needs Revision (see notes)`) that break /gate-check, - /create-stories, and /architecture-review right now. I can fix these in-place." - - "Fix it now — edit systems-index.md" - - "I'll fix it myself" - - "Done — leave me with the plan" - -**If ADRs are missing `## Status` (and no parenthetical issue):** -Use `AskUserQuestion`: -- "The most urgent fix is adding `## Status` to [N] ADR(s): [list filenames]. - Without it, /story-readiness silently passes all ADR checks. Start with - [first affected filename]?" - - "Yes — retrofit [first affected filename] now" - - "Retrofit all [N] ADRs one by one" - - "I'll handle ADRs myself" - -**If GDDs are missing Acceptance Criteria (and no blocking issues above):** -Use `AskUserQuestion`: -- "The most urgent gap is missing Acceptance Criteria in [N] GDD(s): - [list filenames]. Without them, /create-stories can't generate stories. - Start with [highest-priority GDD filename]?" - - "Yes — add Acceptance Criteria to [GDD filename] now" - - "Do all [N] GDDs one by one" - - "I'll handle GDDs myself" - -**Otherwise, if any BLOCKING or HIGH gap remains** (one no branch above names — -e.g. a missing TR registry): -Use `AskUserQuestion`: -- "The most urgent remaining gap is [first BLOCKING or HIGH item in the plan] — - [one line on what it breaks]. Start on it now?" - - "Yes — start on [item]" - - "Show me that plan item first" - - "Done — leave me with the plan" - -**If no BLOCKING or HIGH gaps exist:** -Use `AskUserQuestion`: -- "No blocking gaps — this project is template-compatible. What next?" - - "Walk me through the medium-priority improvements" - - "Run /project-stage-detect for a broader health check" - - "Done — I'll work through the plan at my own pace" - -> **Adoption plan saved to `docs/adoption-plan-[date].md`.** Re-run `/adopt` at any time to re-check remaining gaps as you complete them. - ---- +**Read `references/7-first-action.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Collaborative Protocol diff --git a/.claude/skills/adopt/references/1-detect.md b/.claude/skills/adopt/references/1-detect.md new file mode 100644 index 00000000..7f5ab618 --- /dev/null +++ b/.claude/skills/adopt/references/1-detect.md @@ -0,0 +1,45 @@ +# /adopt — Phase 1: Detect Project State + +> Part of `/adopt`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 1: Detect Project State + +Emit one line before reading: `"Scanning project artifacts..."` — this confirms the +skill is running during the silent read phase. + +Then read silently before presenting anything else. + +### Existence check +- `project.stage` in `project.yaml` (fallback `production/stage.txt`) — if either is present, use that value (authoritative phase) +- `design/gdd/game-concept.md` (or, at the minimal tier, `design/game-brief.md`) — concept exists? +- `design/gdd/systems-index.md` — systems index exists? +- Count GDD files: `design/gdd/*.md` (excluding game-concept.md and systems-index.md) +- Count ADR files: `docs/architecture/adr-*.md` +- Count story files: `production/epics/**/*.md` (excluding EPIC.md) +- `project.yaml` (`engine.name`) / `.claude/docs/technical-preferences.md` — engine configured? +- `docs/engine-reference/` — engine reference docs present? +- Glob `docs/adoption-plan-*.md` — note the filename of the most recent prior plan if any exist + +### Infer phase (if no project.stage / stage.txt) +Use the same heuristic as `/project-stage-detect`: +- 10+ source files in the code root → Production +- Stories in `production/epics/` → Pre-Production +- ADRs exist → Technical Setup +- systems-index.md exists → Systems Design +- game-concept.md (or `design/game-brief.md`) exists → Concept +- Nothing → Fresh (not a brownfield project — suggest `/start`) + +If the project appears fresh (no artifacts at all), use `AskUserQuestion`: +- "This looks like a fresh project — no existing artifacts found. `/adopt` is for + projects with work to migrate. What would you like to do?" + - "Run `/start` — begin guided first-time onboarding" + - "My artifacts are in a non-standard location — help me find them" + - "Cancel" + +Then stop — do not proceed with the audit regardless of which option the user picks +(each option leads to a different skill or manual investigation). + +Report: "Detected phase: [phase]. Found: [N] GDDs, [M] ADRs, [P] stories." + +--- diff --git a/.claude/skills/adopt/references/2-format-audit.md b/.claude/skills/adopt/references/2-format-audit.md new file mode 100644 index 00000000..a0d43100 --- /dev/null +++ b/.claude/skills/adopt/references/2-format-audit.md @@ -0,0 +1,200 @@ +# /adopt — Phase 2: Format Audit + +> Part of `/adopt`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 2: Format Audit + +**In this file:** + +- 2a: GDD Format Audit +- 2b: ADR Format Audit +- 2c: systems-index.md Format Audit +- 2d: Story Format Audit +- 2e: Infrastructure Audit +- 2f: Project Config Audit +- 2g: v1.0 Migration Check + +For each artifact type in scope (based on argument mode **and the resolved +workflow tier**), check not just that the file exists but that it contains the +internal structure the template requires. At `minimal`, scope the audit to +`design/game-brief.md` — do not audit for GDDs, ADRs, or UX specs (they are not expected). +Steps 2e (the Engine reference row only), 2f (project config) and 2g (v1.0 +migration check) run at every tier. + +### 2a: GDD Format Audit + +**Gather section presence deterministically — do not read the GDDs to count +headings.** For each GDD discovered in Phase 1, pass its path explicitly to the +structure-check script: + +``` +Bash: bash .claude/scripts/gdd-structure-check.sh [path-to-gdd] +``` + +**Pass paths one at a time; do not invoke it bare.** The no-argument form sweeps +`design/gdd/` only, and a brownfield project's GDDs are not guaranteed to live +there — pass whatever paths Phase 1 found. The script prints a `PRESENT:` list +and, when applicable, an `ABSENT:` list per file. It reports **presence only** +and makes no REQUIRED/ADVISORY judgment (that is the tier logic below), and it +already accepts `## Detailed Design` as satisfying the `Detailed Rules` +requirement, so do not flag that alias as missing. + +If the script prints `Not found:` for a path or errors, that is a **discovery +failure, not a format gap** — report it as "could not audit [path]" and do not +count it as a missing-sections finding. + +**Then apply the workflow tier** resolved above to each file's PRESENT/ABSENT +lists. Which sections are **required** (a miss = gap) vs **advisory** (a miss = +informational): +- **`full`** — all 8 sections are required. +- **`standard`** — the 5 required (Overview, Detailed Rules, Edge Cases, + Dependencies, Acceptance Criteria) + Formulas for any system that defines + numeric rules (rates, curves, thresholds, costs — the system's `Category` is a + hint, not the test); Player Fantasy and Tuning Knobs are advisory. +- **`minimal`** — GDDs are not expected; audit `design/game-brief.md` instead, + against `.claude/docs/templates/game-brief.md`: each of the six required fields + present and not a placeholder; the three one-liners advisory. Any GDD that + does exist is checked at the `standard` bar, advisorily. + +The script's 8 canonical labels are: Overview, Player Fantasy, Detailed Rules, +Formulas, Edge Cases, Dependencies, Tuning Knobs, Acceptance Criteria. + +A section reported PRESENT can still be an empty heading. For each GDD, also +record with a targeted grep (not a full read): +- Placeholder-only sections — `Grep pattern="\[To be designed\]"` (or an + equivalent empty/single-line body) marks a present-but-unwritten section. +- The `**Status**:` header field — `Grep pattern="^>?[[:space:]]*\*\*Status\*\*:"`. + Valid values: `Draft`, `In Design`, `Designed`, `In Review`, `Approved`, + `Implemented`, `Needs Revision`. + +> **The `>?` is load-bearing, and so are `Draft`/`Implemented`.** Both emitters +> write this field inside a blockquote — `.claude/docs/templates/game-design-document.md` +> and `/design-system` produce `> **Status**: …` — so an anchor of +> `^\*\*Status\*\*:` matches nothing and reports *every* template-compliant GDD +> as missing its Status. The template's own value list offers `Draft` and +> `Implemented`, so both must count as valid. + +### 2b: ADR Format Audit + +For each ADR file found, check for these critical sections: + +| Section | Impact if missing | +|---|---| +| `## Status` | **BLOCKING** — `/story-readiness` ADR status check silently passes everything | +| `## ADR Dependencies` | HIGH — dependency ordering in `/architecture-review` breaks | +| `## Engine Compatibility` | HIGH — post-cutoff API risk is unknown | +| `## GDD Requirements Addressed` | MEDIUM — traceability matrix loses coverage | +| `## Performance Implications` | LOW — not pipeline-critical | + +For each ADR, record: which sections present, which missing, current Status value +if the Status section exists. + +### 2c: systems-index.md Format Audit + +If `design/gdd/systems-index.md` exists: + +1. **Parenthetical status values** — Grep for any Status cell containing + parentheses: `"Needs Revision ("`, `"In Progress ("`, etc. + These break exact-string matching in `/gate-check`, `/create-stories`, + and `/architecture-review`. **BLOCKING.** + +2. **Valid status values** — check that Status column values are only from: + `Not Started`, `In Progress`, `In Review`, `Designed`, `Approved`, `Needs Revision` + Flag any unrecognised values. + +3. **Column structure** — check that the table has at minimum: System name, + Layer, Priority, Status columns. Missing columns degrade skill functionality. + +### 2d: Story Format Audit + +For each story file found: + +- **`Manifest Version:` field** — present in story header? (LOW — auto-passes if absent) +- **TR-ID reference** — does story contain `TR-[a-z]+-[0-9]+` pattern? (MEDIUM — no staleness tracking) +- **ADR reference** — does story reference at least one ADR? (check for `ADR-` pattern) +- **Status field** — present and readable? +- **Acceptance criteria** — does the story have a checkbox list (`- [ ]`)? + +### 2e: Infrastructure Audit + +| Artifact | Path | Impact if missing | +|---|---|---| +| TR registry | `docs/architecture/tr-registry.yaml` | HIGH — no stable requirement IDs | +| Control manifest | `docs/architecture/control-manifest.md` | HIGH — no layer rules for stories | +| Manifest version stamp | In manifest header: `Manifest Version:` | MEDIUM — staleness checks blind | +| Sprint status | `production/sprint-status.yaml` | MEDIUM — `/sprint-status` falls back to markdown | +| Stage file | `project.stage` in `project.yaml` (fallback `production/stage.txt`) | MEDIUM — phase auto-detect unreliable | +| Engine reference | `docs/engine-reference/[engine]/VERSION.md` | HIGH — ADR engine checks blind | +| Architecture traceability | `docs/architecture/requirements-traceability.md` | MEDIUM — no persistent matrix | + +At `workflow: minimal` only the Engine reference row applies. The TR registry, +control manifest and its version stamp, sprint status, stage file and +traceability matrix are not on the minimal path, so their absence is not a gap. + +### 2f: Project Config Audit + +Read `project.yaml` (the primary config store) and `.claude/docs/technical-preferences.md` (legacy mirror). A setting counts as configured if EITHER source has a real value (in technical-preferences.md, `[TO BE CONFIGURED]` means unconfigured): +- `engine.name`/`version`/`language`/`rendering`/`physics` (else the Engine/Language/Rendering/Physics fields) → HIGH if unconfigured in both (ADR skills fail) +- `naming.*` (else Naming conventions) → MEDIUM +- `performance.*` (else Performance budgets) → MEDIUM +- Forbidden Patterns, Allowed Libraries (technical-preferences.md only — not migrated to project.yaml) → LOW (starts empty by design) + +### 2g: v1.0 Migration Check + +A project is a **v1.0 project needing migration** when `project.yaml` does NOT +exist at the repo root AND at least one legacy file does: `production/stage.txt`, +`production/review-mode.txt`, or a `.claude/docs/technical-preferences.md` with +real values. + +"Real values" means one of the keys the converter actually migrates — Engine, +Language, Rendering, Physics, the naming, platform and performance fields, +Framework, or the specialists. Not merely "some bullet is filled in": the +shipped template ships one prose default (`- **Required Tests**: …`) that is +never migrated, and counting it made every fresh clone read as a v1.0 project. + +Do not hand-migrate. Run the converter, which is deterministic and covered by +the framework's own test suite: + +```bash +bash .claude/scripts/migrate-v1-config.sh --dry-run +``` + +The dry run writes nothing; record what it lists for the report. Do not run the +converter during the audit — Phase 2 reads silently. The migration is +classified BLOCKING in Phase 3, heads the plan, and **Phase 7 offers it as the +first action**: report what the dry run listed, then ask "May I run the +converter? It writes `project.yaml` and `production/migration-report.md`." If +the user approves, run it without `--dry-run`. It +writes `project.yaml` plus `production/migration-report.md` and **deletes +nothing** — the whole operation stays reversible with `git checkout`. + +Then tell the user to read `production/migration-report.md` before running: + +```bash +bash .claude/scripts/migrate-v1-config.sh --finalize +``` + +`--finalize` deletes a legacy file only after proving its value is present in +`project.yaml`; on mismatch it deletes nothing and exits 4. It never deletes +`technical-preferences.md`, which still holds Forbidden Patterns and Allowed +Libraries. + +**If the script refuses with exit 3**, do not work around it. Exit 3 means one +of two things, and the message says which: + +- **the values DISAGREE** — two sources of truth and no way to know which the + user edited last. Surface it and let them decide. +- **a `production/migration-report.md` is already present** — a migration ran + here, so these are post-migration leftovers and `--finalize` is the next step, + not a second `migrate`. + +Both files merely *existing* is not exit 3 and must not be reported as a +conflict: `/start` writes `production/stage.txt` on every new v1.1 project as a +mirror, so agreement is the normal state. The script says +`the legacy files mirror it (values agree)` and exits 0 for that. + +Classify as **BLOCKING** in Phase 3: until migration runs, every skill reads +config through the legacy fallback chain, and v1.1 settings are unavailable. + +--- diff --git a/.claude/skills/adopt/references/3-classify.md b/.claude/skills/adopt/references/3-classify.md new file mode 100644 index 00000000..fc87b537 --- /dev/null +++ b/.claude/skills/adopt/references/3-classify.md @@ -0,0 +1,29 @@ +# /adopt — Phase 3: Classify and Prioritise Gaps + +> Part of `/adopt`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 3: Classify and Prioritise Gaps + +Organise every gap found across all audits into four severity tiers: + +**BLOCKING** — Will cause template skills to silently produce wrong results *right now*. +Examples: ADR missing Status field, systems-index parenthetical status values, +engine not configured when ADRs exist. + +**HIGH** — Will cause stories to be generated with missing safety checks, or +infrastructure bootstrapping will fail. +Examples: ADRs missing Engine Compatibility, GDDs missing Acceptance Criteria +(stories can't be generated from them), tr-registry.yaml missing. + +**MEDIUM** — Degrades quality and pipeline tracking but does not break functionality. +Examples: GDDs missing Tuning Knobs or Formulas sections, stories missing TR-IDs, +sprint-status.yaml missing. + +**LOW** — Retroactive improvements that are nice-to-have but not urgent. +Examples: Stories missing Manifest Version stamps, GDDs missing Open Questions section. + +Count totals per tier. If zero BLOCKING and zero HIGH gaps: report that the project +is template-compatible and only advisory improvements remain. + +--- diff --git a/.claude/skills/adopt/references/4-migration-plan.md b/.claude/skills/adopt/references/4-migration-plan.md new file mode 100644 index 00000000..5aa50326 --- /dev/null +++ b/.claude/skills/adopt/references/4-migration-plan.md @@ -0,0 +1,53 @@ +# /adopt — Phase 4: Build the Migration Plan + +> Part of `/adopt`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 4: Build the Migration Plan + +Compose a numbered, ordered action plan. Ordering rules: +1. BLOCKING gaps first (must fix before any pipeline skill runs reliably) +2. HIGH gaps next, infrastructure before GDD/ADR content (bootstrapping needs correct formats) +3. MEDIUM gaps ordered: GDD gaps before ADR gaps before story gaps (stories depend on GDDs and ADRs) +4. LOW gaps last + +For each gap, produce a plan entry with: +- A clear problem statement (one sentence, no jargon) +- The exact command to fix it, if a skill handles it +- Manual steps if it requires direct editing +- A time estimate (rough: 5 min / 30 min / 1 session) +- A checkbox `- [ ]` for tracking + +**Special case — systems-index parenthetical status values:** +This is always the first item if present. Show the exact values that need changing +and the exact replacement text. Offer to fix this immediately before writing the plan. + +**Special case — ADRs missing Status field:** +For each affected ADR, the fix is: +`/architecture-decision retrofit docs/architecture/adr-[NNNN]-[slug].md` +List each ADR as a separate checkable item. + +**Special case — GDDs missing sections:** +For each affected GDD, list which sections are missing and the fix: +`/design-system retrofit design/gdd/[filename].md` + +**Infrastructure bootstrap ordering** — always present in this sequence: +1. Fix ADR formats first (registry depends on reading ADR Status fields) +2. Run `/architecture-review` → bootstraps `tr-registry.yaml` +3. Run `/create-control-manifest` → creates manifest with version stamp +4. Run `/sprint-plan update` → creates `sprint-status.yaml` +5. Run `/gate-check [phase]` (the gate into the phase the project is in; at Concept there is none — Concept is the default stage, nothing to run) → writes `project.stage` in `project.yaml` (and legacy `stage.txt`) authoritatively + +**At `workflow: minimal` the plan prescribes none of this sequence.** None of it +is on the minimal path: ADRs are not expected, the brief's build order is the +plan (no `/sprint-plan`), and nothing there runs `/gate-check`. The plan's +Step 3 says so in one line and names the path's next step instead — +`/create-stories` when no stories exist, else `/dev-story`. + +**Existing stories** — note explicitly: +> "Existing stories continue to work with all template skills — all new format +> checks auto-pass when the fields are absent. They won't benefit from TR-ID +> staleness tracking or manifest version checks until they're regenerated. This +> is intentional: do not regenerate stories that are already in progress." + +--- diff --git a/.claude/skills/adopt/references/5-summary.md b/.claude/skills/adopt/references/5-summary.md new file mode 100644 index 00000000..521637bf --- /dev/null +++ b/.claude/skills/adopt/references/5-summary.md @@ -0,0 +1,48 @@ +# /adopt — Phase 5: Present Summary and Ask to Write + +> Part of `/adopt`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 5: Present Summary and Ask to Write + +Present a compact summary before writing: + +``` +## Adoption Audit Summary +Phase detected: [phase] +Engine: [configured / NOT CONFIGURED] +GDDs audited: [N] ([X] fully compliant, [Y] with gaps) +ADRs audited: [N] ([X] fully compliant, [Y] with gaps) +Stories audited: [N] + +Gap counts: + BLOCKING: [N] — template skills will malfunction without these fixes + HIGH: [N] — unsafe to run /create-stories or /story-readiness + MEDIUM: [N] — quality degradation + LOW: [N] — optional improvements + +Estimated remediation: [X blocking items × ~Y min each = roughly Z hours] +``` + +Before asking to write, show a **Gap Preview**: +- List every BLOCKING gap as a one-line bullet describing the actual problem + (e.g. `systems-index.md: 3 rows have parenthetical status values`, + `adr-0002.md: missing ## Status section`). No counts — show the actual items. +- Show HIGH / MEDIUM / LOW as counts only (e.g. `HIGH: 4, MEDIUM: 2, LOW: 1`). + +This gives the user enough context to judge scope before committing to writing the file. + +If a prior adoption plan was detected in Phase 1, add a note: +> "A previous plan exists at `docs/adoption-plan-[prior-date].md`. The new plan will +> reflect current project state — it does not diff against the prior run." + +Use `AskUserQuestion`: +- "Ready to write the migration plan?" + - "Yes — write `docs/adoption-plan-[date].md`" + - "Show me the full plan preview first (don't write yet)" + - "Cancel — I'll handle migration manually" + +If the user picks "Show me the full plan preview", output the complete plan as a +fenced markdown block. Then ask again with the same three options. + +--- diff --git a/.claude/skills/adopt/references/6-write.md b/.claude/skills/adopt/references/6-write.md new file mode 100644 index 00000000..4fc281e8 --- /dev/null +++ b/.claude/skills/adopt/references/6-write.md @@ -0,0 +1,113 @@ +# /adopt — Phases 6 and 6b: Write the Adoption Plan and Report Review Mode + +> Part of `/adopt`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 6: Write the Adoption Plan + +**In this file:** + +- Phase 6: the adoption plan template, then the write +- Phase 6b: Report Review Mode + +If approved, write `docs/adoption-plan-[date].md` with this structure: + +```markdown +# Adoption Plan + +> **Generated**: [date] +> **Project phase**: [phase] +> **Engine**: [name + version, or "Not configured"] +> **Template version**: v1.0+ + +Work through these steps in order. Check off each item as you complete it. +Re-run `/adopt` anytime to check remaining gaps. + +--- + +## Step 1: Fix Blocking Gaps + +[One sub-section per blocking gap with problem, fix command, time estimate, checkbox] + +--- + +## Step 2: Fix High-Priority Gaps + +[One sub-section per high gap] + +--- + +## Step 3: Bootstrap Infrastructure + +[At `workflow: minimal`, replace 3a–3d with one line: "Not on the minimal path — +the brief's build order is the plan. Next: `/create-stories` (or `/dev-story` +once stories exist)."] + +### 3a. Register existing requirements (creates tr-registry.yaml) +Run `/architecture-review` — even if ADRs already exist, this run bootstraps +the TR registry from your existing GDDs and ADRs. +**Time**: 1 session (review can be long for large codebases) +- [ ] tr-registry.yaml created + +### 3b. Create control manifest +Run `/create-control-manifest` +**Time**: 30 min +- [ ] docs/architecture/control-manifest.md created + +### 3c. Create sprint tracking file +Run `/sprint-plan update` +**Time**: 5 min (if sprint plan already exists as markdown) +- [ ] production/sprint-status.yaml created + +### 3d. Set authoritative project stage +Run `/gate-check [current-phase]` (the gate into the phase the project is in; +at Concept there is none — Concept is the default stage, nothing to run) +**Time**: 5 min +- [ ] `project.stage` in `project.yaml` written (legacy `production/stage.txt` also updated) + +--- + +## Step 4: Medium-Priority Gaps + +[One sub-section per medium gap] + +--- + +## Step 5: Optional Improvements + +[One sub-section per low gap] + +--- + +## What to Expect from Existing Stories + +Existing stories continue to work with all template skills. New format checks +(TR-ID validation, manifest version staleness) auto-pass when the fields are +absent — so nothing breaks. They won't benefit from staleness tracking until +regenerated. Do not regenerate stories that are in progress or done. + +--- + +## Re-run + +Run `/adopt` again after completing Step 3 to verify all blocking and high gaps +are resolved. The new run will reflect the current state of the project. +``` + +--- + +## Phase 6b: Report Review Mode + +**Do not write a review mode.** `modes.review_mode` is one of the six knobs +`modes.rigor` fronts: pinning it in `project.yaml` shadows the rigor expansion, and +the legacy `production/review-mode.txt` sits *above* that expansion in resolution, +so either write would freeze director-review depth for good — the rule `/start` +and `project.yaml`'s header comment both state. + +Report the value the bootstrap above resolved instead: "Review mode resolves to +`[value]` — from `modes.rigor`, unless something pins it." If the user wants a +different depth, point them to changing `modes.rigor`, or to pinning it on purpose +with `/settings --local modes.review_mode=` (a personal override in +`project.local.yaml`). + +--- diff --git a/.claude/skills/adopt/references/7-first-action.md b/.claude/skills/adopt/references/7-first-action.md new file mode 100644 index 00000000..53662681 --- /dev/null +++ b/.claude/skills/adopt/references/7-first-action.md @@ -0,0 +1,62 @@ +# /adopt — Phase 7: Offer First Action + +> Part of `/adopt`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 7: Offer First Action + +After writing the plan, don't stop there. Pick the single highest-priority gap +and offer to handle it immediately using `AskUserQuestion`. Choose the first +branch that applies: + +**If Phase 2g found a v1.0 project needing migration:** offer the converter run +described there — report what the dry run listed and ask "May I run the +converter? It writes `project.yaml` and `production/migration-report.md`." +Every other fix reads config through it, so it comes first. + +**If there are parenthetical status values in systems-index.md:** +Use `AskUserQuestion`: +- "The most urgent fix is `systems-index.md` — [N] rows have parenthetical status + values (e.g. `Needs Revision (see notes)`) that break /gate-check, + /create-stories, and /architecture-review right now. I can fix these in-place." + - "Fix it now — edit systems-index.md" + - "I'll fix it myself" + - "Done — leave me with the plan" + +**If ADRs are missing `## Status` (and no parenthetical issue):** +Use `AskUserQuestion`: +- "The most urgent fix is adding `## Status` to [N] ADR(s): [list filenames]. + Without it, /story-readiness silently passes all ADR checks. Start with + [first affected filename]?" + - "Yes — retrofit [first affected filename] now" + - "Retrofit all [N] ADRs one by one" + - "I'll handle ADRs myself" + +**If GDDs are missing Acceptance Criteria (and no blocking issues above):** +Use `AskUserQuestion`: +- "The most urgent gap is missing Acceptance Criteria in [N] GDD(s): + [list filenames]. Without them, /create-stories can't generate stories. + Start with [highest-priority GDD filename]?" + - "Yes — add Acceptance Criteria to [GDD filename] now" + - "Do all [N] GDDs one by one" + - "I'll handle GDDs myself" + +**Otherwise, if any BLOCKING or HIGH gap remains** (one no branch above names — +e.g. a missing TR registry): +Use `AskUserQuestion`: +- "The most urgent remaining gap is [first BLOCKING or HIGH item in the plan] — + [one line on what it breaks]. Start on it now?" + - "Yes — start on [item]" + - "Show me that plan item first" + - "Done — leave me with the plan" + +**If no BLOCKING or HIGH gaps exist:** +Use `AskUserQuestion`: +- "No blocking gaps — this project is template-compatible. What next?" + - "Walk me through the medium-priority improvements" + - "Run /project-stage-detect for a broader health check" + - "Done — I'll work through the plan at my own pace" + +> **Adoption plan saved to `docs/adoption-plan-[date].md`.** Re-run `/adopt` at any time to re-check remaining gaps as you complete them. + +--- diff --git a/.claude/skills/architecture-decision/SKILL.md b/.claude/skills/architecture-decision/SKILL.md index 67481165..cdca26ae 100644 --- a/.claude/skills/architecture-decision/SKILL.md +++ b/.claude/skills/architecture-decision/SKILL.md @@ -12,15 +12,14 @@ model: sonnet Resolved above — use as-is; `--review` overrides `review_mode`. No block → defaults in `.claude/docs/config-resolution.md`. +# Architecture Decision When this skill is invoked: ## 0. Parse Arguments — Detect Retrofit / Acceptance Mode - See `.claude/docs/director-gates.md` for the full check pattern. Individual gate definitions live in `.claude/docs/director-gates/[gate-id].md` — the spawned agent reads its own gate file; do not read it in the parent session. - Every `AskUserQuestion` call follows `.claude/docs/automation-modes.md` (collaborative asks always · guided major-only · autonomous logs and proceeds; `automation_always_ask` categories always prompt). @@ -46,135 +45,12 @@ density. - `minimal` — not required. Can still be run voluntarily. **If the argument starts with `retrofit` followed by a file path** -(e.g., `/architecture-decision retrofit docs/architecture/adr-0001-event-system.md`): -Enter **retrofit mode**: - -1. Read the existing ADR file completely. -2. Identify which template sections are present by scanning headings: - - `## Status` — **BLOCKING if missing**: `/story-readiness` cannot check ADR acceptance - - `## ADR Dependencies` — HIGH if missing: dependency ordering breaks - - `## Engine Compatibility` — HIGH if missing: post-cutoff risk unknown - - `## GDD Requirements Addressed` — MEDIUM if missing: traceability lost - - `## Date` — MEDIUM if missing, and no `## Last Verified` either: `/create-stories` - stamps stories with it and `/dev-story` compares against it, so without it a - story can never tell whether the ADR changed -3. Present to the user: - ``` - ## Retrofit: [ADR title] - File: [path] - - Sections already present (will not be touched): - ✓ Status: [current value, or "MISSING — will add"] - ✓ [section] - - Missing sections to add: - ✗ Status — BLOCKING (stories cannot validate ADR acceptance without this) - ✗ ADR Dependencies — HIGH - ✗ Engine Compatibility — HIGH - ``` -4. Ask: "Shall I add the [N] missing sections? I will not modify any existing content." - If no: write nothing, and report the missing sections by name. -5. If yes: - - For **Status**: ask the user — "What is the current status of this decision?" - Options: "Proposed", "Accepted", "Deprecated", "Superseded by ADR-XXXX" - An `Accepted` answer — a decision already in force — is not written as - given: write `Proposed`, add the other missing sections, then run - acceptance mode (below) on this ADR. Its dependency check, confirmation and - story unblocking apply here too; it stays the only path that sets `Accepted`. - - For **ADR Dependencies**: ask — "Does this decision depend on any other ADR? - Does it enable or block any other ADR or epic?" Accept "None" for each field. - - For **Engine Compatibility**: read the engine reference docs (same as Step 1 below) - and ask the user to confirm the domain. Then generate the table with verified data. - - For **GDD Requirements Addressed**: ask — "Which GDD systems motivated this decision? - What specific requirement in each GDD does this ADR address?" - - Append each missing section to the ADR file using the Edit tool. - - For **Date** (counted only when there is no `## Last Verified`): append - `## Date` with today's date — even when it is the only missing section, the - case `/dev-story` sends you here for — and say that it records the retrofit, - not when the decision was made. - - **Never modify any existing section.** Only append or fill absent sections. -6. Suggest: "Run `/architecture-review` to re-validate coverage now that this ADR - has its Status and Dependencies fields." +**Read `references/0-retrofit.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. **If the argument starts with `accept` followed by an ADR id** -(e.g., `/architecture-decision accept ADR-0005`): -Enter **acceptance mode**. This is the *only* path in the framework that moves an -ADR from `Proposed` to `Accepted`. Authoring always produces `Proposed` -(Step 5), while -`/create-control-manifest`, `/create-epics`, `/create-stories` and `/gate-check` -all require `Accepted` — so without this mode the pipeline had a state it could -enter and never leave. - -1. **Resolve the id to a file, then read it.** Glob - `docs/architecture/adr-NNNN-*.md` for the given number. If **no** file matches, - or **more than one** does, stop and say which — do not pick one. If the file - has no `## Status` section, stop and say so; a missing Status is exactly what - retrofit mode is for. -2. **Check the current status.** If it is already `Accepted`, say so and stop. - If it is `Deprecated` or `Superseded`, refuse: reviving a superseded decision - is a new ADR, not a status edit. -3. **Check its dependencies first.** Read `## ADR Dependencies`. - - **If that section is absent, empty, or reads `UNKNOWN`, do not read it as - "no dependencies" — refuse and say which:** - > "ADR-0005's dependency section is [absent / UNKNOWN], so I cannot tell what - > this decision rests on. An empty dependency list and an unexamined one look - > identical here, and only one of them is safe to accept. Run - > `/architecture-decision retrofit ` to establish it." - - A dependency check reading a field that defaults to empty is the vacuous-pass - shape this gate exists to prevent — the check would examine nothing and report - clean. - - If it depends on any ADR that is not itself `Accepted`, **refuse and name them**: - > "ADR-0005 depends on ADR-0002, which is still Proposed. Accept ADR-0002 - > first — an accepted decision resting on an unaccepted one is not a decision, - > it is a deferral with a different label." - This is the same dependency rule `/architecture-review` already flags; here it - is enforced rather than reported. -4. **Confirm with the user, always.** Per `CONTRACT.md`, acceptance authority is - **the user, or `technical-director` on the user's explicit confirmation — no - other agent, and never this skill on its own.** Use `AskUserQuestion`: - - Prompt: "Accept ADR-NNNN — [title]? This is what unblocks stories and epics - that depend on it." - - Options: `[A] Yes — accept it` / `[B] Not yet — leave it Proposed` - **This prompt fires regardless of `modes.automation`, including `autonomous`.** - Acceptance is the decision the whole architecture pipeline gates on; it is not - a step to be inferred. -5. **Find the stories this will unblock, BEFORE the prompt in step 4.** Grep - every story for a Blocked Status line — - `Grep pattern="Status\**:\**\s*Blocked" path="production/epics" glob="**/story-*.md" output_mode="files_with_matches"`, - which matches `> **Status**: Blocked` (the form `/create-stories` writes), - `**Status:** Blocked` and `Status: Blocked` — and keep the files that name - this ADR's id as the reason they are blocked. That pairing is what "blocked - pending this ADR" means — a story blocked for an unrelated reason will not - name it. Leave out a story that names this ADR only as the successor to point - at (`point the story at ADR-NNNN`, the note for a `Deprecated` or - `Superseded` ADR): it is still governed by the old ADR, and accepting the - successor does not re-point it. - > **Stories live only under `production/epics/`.** A flat top-level stories - > directory does not exist and no skill creates one — never write or match a - > path outside `production/epics/`. `/dev-story` matches entries *by file - > path*, so a story recorded under any other path silently fails to match and - > never gets picked up. - - Feed the count into step 4's prompt so it reads *"3 stories become Ready"* - rather than a generic claim: **the user is being asked to authorise an effect, and should be - shown the effect.** If none match, say "no stories are waiting on this" — that - is useful information, not an empty result to omit. -6. On confirmation, `Edit` the `## Status` line to `Accepted`. Leave an existing - `## Date` as it is: it records when the ADR was written, and `/create-stories` - stamps stories with it (or `## Last Verified`), so rewriting it on acceptance - would make every story drafted against the Proposed ADR look out of date to - `/dev-story`. **If that section is absent, add it** with today's date — retrofit - mode already owns this shape, and acceptance must not fail on a template that - predates the field. -7. Then set each story found in step 5 from `Blocked` to `Ready`. Unblocking is a - consequence of acceptance, never of authoring — see Step 6's note below. -8. Report what moved: the ADR (and its `## Date`, if one was added), and every - story that became Ready. +**Read `references/0-accept.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. If NOT in retrofit or acceptance mode, proceed to Step 1 below (normal ADR authoring). @@ -190,47 +66,7 @@ Use the user's response as the title, then proceed to Step 1. ## 1. Load Engine Context (ALWAYS FIRST) -Before doing anything else, establish the engine environment: - -1. Read `docs/engine-reference/[engine]/VERSION.md` to get: - - Engine name and version - - LLM knowledge cutoff date - - Post-cutoff version risk levels (LOW / MEDIUM / HIGH) - -2. Identify the **domain** of this architecture decision from the title or - user description. Common domains: Physics, Rendering, UI, Audio, Navigation, - Animation, Networking, Core, Input, Scripting. - -3. Read the corresponding module reference if it exists: - `docs/engine-reference/[engine]/modules/[domain].md` - -4. Read `docs/engine-reference/[engine]/breaking-changes.md` — flag any - changes in the relevant domain that post-date the LLM's training cutoff. - -5. Read `docs/engine-reference/[engine]/deprecated-apis.md` — flag any APIs - in the relevant domain that should not be used. - -6. **Display a knowledge gap warning** before proceeding if the domain carries - MEDIUM or HIGH risk: - - ``` - ⚠️ ENGINE KNOWLEDGE GAP WARNING - Engine: [name + version] - Domain: [domain] - Risk Level: HIGH — This version is post-LLM-cutoff. - - Key changes verified from engine-reference docs: - - [Change 1 relevant to this domain] - - [Change 2] - - This ADR will be cross-referenced against the engine reference library. - Proceed with verified information only — do NOT rely solely on training data. - ``` - - If no engine has been configured yet, prompt: "No engine is configured. - Run `/setup-engine` first, or tell me which engine you are using." - ---- +**Read `references/1-engine-context.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 2. Determine the next ADR number @@ -240,379 +76,15 @@ Scan `docs/architecture/` for existing ADRs to find the next number. ## 3. Gather context -### 3a: Architecture Registry Check (BLOCKING gate) — do this FIRST - -Read `docs/registry/architecture.yaml`. Extract entries relevant to this ADR's -domain and decision (grep by system name, domain keyword, or state being touched). -Run this before reading any existing ADR — the registry exists specifically so a -new ADR's author does not need to open prior ADRs to learn their binding facts -(state ownership, interface contracts, forbidden patterns). - -Present any relevant stances to the user **before** the collaborative design -begins, as locked constraints: - -``` -## Existing Architectural Stances (must not contradict) - -State Ownership: - player_health → owned by health-system (ADR-0001) - Interface: HealthComponent.current_health (read-only float) - → If this ADR reads or writes player health, it must use this interface. - -Interface Contracts: - damage_delivery → signal pattern (ADR-0003) - Signal: damage_dealt(amount, target, is_crit) - → If this ADR delivers or receives damage events, it must use this signal. - -Forbidden Patterns: - ✗ autoload_singleton_coupling (ADR-0001) - ✗ direct_cross_system_state_write (ADR-0000) - → The proposed approach must not use these patterns. -``` - -If the user's proposed decision would contradict any registered stance, surface -the conflict immediately: - -> "⚠️ Conflict: This ADR proposes [X], but ADR-[NNNN] established that [Y] is -> the accepted pattern for this purpose. Proceeding without resolving this will -> produce contradictory ADRs and inconsistent stories. -> Options: (1) Align with the existing stance, (2) Supersede ADR-[NNNN] with -> an explicit replacement, (3) Explain why this case is an exception." - -Do not proceed to Step 4 (collaborative design) until any conflict is resolved -or explicitly accepted as an intentional exception. - -### 3b: Existing ADRs and Related GDDs — registry-scoped, never unbounded - -The registry (3a) covers *what* prior decisions bind — not always *why*. If the -registry surfaced a directly relevant ADR and its reasoning matters here (not -just its stated facts), read that specific ADR — never glob-and-read every -ADR in `docs/architecture/` on the chance one is relevant: - -1. **Map its headings first** (cheap): - ``` - Grep pattern="^## " path="docs/architecture/[adr-file].md" output_mode="content" -n - ``` -2. **Under ~50KB** (`Bash: wc -c "docs/architecture/[adr-file].md"`) — one full - `Read` is fine; per-call overhead exceeds the savings from bounded reads at - this size. -3. **~50KB or larger** — bounded-read only `## Context`, `## Decision`, and - `## Consequences` (the sections that carry reasoning, not just facts) via - `Read(offset, limit)` from the heading map. - -Read GDDs the same way `/design-system` Step 2b does: only GDDs the registry -or the ADR list names as directly relevant, and only their `## Dependencies`, -`## Formulas`, and `## Edge Cases` sections -(`Grep pattern="^## (Dependencies|Formulas|Edge Cases)" ... -A 40`) — never a -speculative full read of `design/gdd/*.md` looking for anything that might -relate. - -Skip 3b entirely if the registry already answers everything this decision -needs — most ADRs will. - ---- +**Read `references/3-gather-context.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 4. Guide the decision collaboratively -Before asking anything, derive the skill's best guesses from the context already -gathered (GDDs read, engine reference loaded, existing ADRs scanned). Then present -a **confirm/adjust** prompt using `AskUserQuestion` — not open-ended questions. - -**Derive assumptions first:** -- **Problem**: Infer from the title + GDD context what decision needs to be made -- **Alternatives**: Propose 2-3 concrete options from engine reference + GDD requirements -- **Dependencies**: Scan existing ADRs for upstream dependencies. **If the scan is - inconclusive, present `UNKNOWN — scan inconclusive, please confirm`, never - `None`.** The two are not interchangeable: `None` asserts that nothing upstream - constrains this decision, and a user confirming a prefilled list cannot tell an - assertion from a guess. This field is load-bearing — `/architecture-review` - flags unaccepted dependencies, `/dev-story` reads it, and the acceptance route - in Phase 0 **refuses to accept an ADR whose dependencies are not themselves - Accepted**. A dependency list that defaulted to empty makes that check pass - while examining nothing. `UNKNOWN` must be resolved during the confirm/adjust - prompt; it is a prompt state, never a value written to the file -- **GDD linkage**: Extract which GDD systems the title directly relates to -- **Status**: Always `Proposed` for new ADRs — never ask the user what the status is - -**Scope of assumptions tab**: Assumptions cover only: problem framing, alternative approaches, upstream dependencies, GDD linkage, and status. Schema design questions (e.g., "How should spawn timing work?", "Should data be inline or external?") are NOT assumptions — they are design decisions belonging to a separate step after the assumptions are confirmed. Do not include schema design questions in the assumptions AskUserQuestion widget. - -**After assumptions are confirmed**, if the ADR involves schema or data design choices, use a separate multi-tab `AskUserQuestion` to ask each design question independently before drafting. - -**Present assumptions with `AskUserQuestion`:** - -``` -Here's what I'm assuming before drafting: - -Problem: [one-sentence problem statement derived from context] -Alternatives I'll consider: - A) [option derived from engine reference] - B) [option derived from GDD requirements] - C) [option from common patterns] -GDD systems driving this: [list derived from context] -Dependencies: [upstream ADRs if any, otherwise "None"] -Status: Proposed - -[A] Proceed — draft with these assumptions -[B] Change the alternatives list -[C] Adjust the GDD linkage -[D] Add a performance budget constraint -[E] Something else needs changing first -``` - -Do not generate the ADR until the user confirms assumptions or provides corrections. - -**After engine specialist and TD reviews return** (Step 5.5/5.6), if unresolved -decisions remain, present each one as a separate `AskUserQuestion` with the proposed -options as choices plus a free-text escape: - -``` -Decision: [specific unresolved point] -[A] [option from specialist review] -[B] [alternative option] -[C] Different approach — I'll describe it -``` - -**ADR Dependencies** — derive from existing ADRs, then confirm: -- Does this decision depend on any other ADR not yet Accepted? -- Does it unlock or unblock any other ADR or epic? -- Does it block any specific epic from starting? - -Record answers in the **ADR Dependencies** section. Write "None" for each field if no constraints apply. - ---- +**Read `references/4-decide.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 5. Generate the ADR -Following this format: - -```markdown -# ADR-[NNNN]: [Title] - -## Status -[Proposed | Accepted | Deprecated | Superseded by ADR-XXXX] - -## Date -[Date of decision] - -## Last Verified -[YYYY-MM-DD — when this ADR was last confirmed accurate against the current -engine version and design. Update this date when you re-read and confirm it is -still correct, even if nothing changed.] - -## Decision Makers -[Who was involved in this decision] - -## Summary -[2 sentences: what problem this ADR solves, and what was decided. Written for -tiered context loading — a skill scanning 20 ADRs uses this to decide whether to -read the full decision. Be specific: name the system, the problem, and the -chosen approach.] - -## Engine Compatibility - -| Field | Value | -|-------|-------| -| **Engine** | [e.g. Godot 4.6] | -| **Domain** | [Physics / Rendering / UI / Audio / Navigation / Animation / Networking / Core / Input] | -| **Knowledge Risk** | [LOW / MEDIUM / HIGH — from VERSION.md] | -| **References Consulted** | [List engine-reference docs read, e.g. `docs/engine-reference/godot/modules/physics.md`] | -| **Post-Cutoff APIs Used** | [Any APIs from post-LLM-cutoff versions this decision depends on, or "None"] | -| **Verification Required** | [Specific behaviours to test before shipping, or "None"] | - -## ADR Dependencies - -| Field | Value | -|-------|-------| -| **Depends On** | [ADR-NNNN (must be Accepted before this can be implemented), or "None"] | -| **Enables** | [ADR-NNNN (this ADR unlocks that decision), or "None"] | -| **Blocks** | [Epic/Story name — cannot start until this ADR is Accepted, or "None"] | -| **Ordering Note** | [Any sequencing constraint that isn't captured above] | - -## Context - -### Problem Statement -[What problem are we solving? Why does this decision need to be made now?] - -### Constraints -- [Technical constraints] -- [Timeline constraints] -- [Resource constraints] -- [Compatibility requirements] - -### Requirements -- [Must support X] -- [Must perform within Y budget] -- [Must integrate with Z] - -## Decision - -[The specific technical decision made, described in enough detail for someone -to implement it.] - -### Architecture Diagram -[ASCII diagram or description of the system architecture this creates] - -### Key Interfaces -[API contracts or interface definitions this decision creates] - -### Implementation Guidelines -[Specific guidance for the programmer implementing this decision — the rules a -`/create-control-manifest` or `/dev-story` run should follow. State mandates as -"must / must never" so they extract cleanly.] - -## Alternatives Considered - -### Alternative 1: [Name] -- **Description**: [How this would work] -- **Pros**: [Advantages] -- **Cons**: [Disadvantages] -- **Rejection Reason**: [Why this was not chosen] - -### Alternative 2: [Name] -- **Description**: [How this would work] -- **Pros**: [Advantages] -- **Cons**: [Disadvantages] -- **Rejection Reason**: [Why this was not chosen] - -## Consequences - -### Positive -- [Good outcomes of this decision] - -### Negative -- [Trade-offs and costs accepted] - -## Risks -- [Things that could go wrong] -- [Mitigation for each risk] - -## GDD Requirements Addressed - -| GDD System | Requirement | How This ADR Addresses It | -|------------|-------------|--------------------------| -| [system-name].md | [specific rule, formula, or performance constraint from that GDD] | [how this decision satisfies it] | - -## Performance Implications -- **CPU**: [Expected impact] -- **Memory**: [Expected impact] -- **Load Time**: [Expected impact] -- **Network**: [Expected impact, if applicable] - -## Migration Plan -[If this changes existing code, how do we get from here to there?] - -## Validation Criteria -[How will we know this decision was correct? What metrics or tests?] - -## Related -- [Links to related ADRs — note if supersedes, contradicts, or depends on] -- [Links to related design documents] -``` - -5.5. **Engine Specialist Validation** — Before saving, spawn the **primary engine specialist** via `Agent` to validate the drafted ADR: - - Resolve the primary specialist: `-specialist` derived from `engine.name` in `project.yaml` (Godot→`godot-specialist`, Unity→`unity-specialist`, Unreal→`unreal-specialist`); if `engine.name` is absent or empty, read the Primary line of the `## Engine Specialists` section in `.claude/docs/technical-preferences.md` - - If no engine is configured (neither source yields an engine), skip this step **Record ``Engine validation: NOT ASSESSED — no engine configured (`engine.name` unset in `project.yaml`)`` in this run's output.** A skipped check that says nothing is indistinguishable from a check that passed; the reader cannot tell engine guidance was never sought. - - Spawn `subagent_type: [primary specialist]` with: the ADR's Engine Compatibility section, Decision section, Key Interfaces, and the engine reference docs path. Ask them to: - 1. Confirm the proposed approach is idiomatic for the pinned engine version - 2. Flag any APIs or patterns that are deprecated or changed post-training-cutoff - 3. Identify engine-specific risks or gotchas not captured in the current ADR draft - - If the specialist identifies a **blocking issue** (wrong API, deprecated approach, engine version incompatibility): revise the Decision and Engine Compatibility sections accordingly, then confirm the changes with the user before proceeding - - If the specialist finds **minor notes** only: incorporate them into the ADR's Risks subsection - -**Review mode check** — apply before spawning TD-ADR: -- `solo` → skip. Note: "TD-ADR skipped — Solo mode." Proceed to Step 5.7 (GDD sync check). -- `lean` → skip (not a PHASE-GATE). Note: "TD-ADR skipped — Lean mode." Proceed to Step 5.7 (GDD sync check). -- `full` → spawn as normal. - -5.6. **Technical Director Strategic Review** — After the engine specialist validation, spawn `technical-director` via `Agent` using gate **TD-ADR** (`.claude/docs/director-gates/td-adr.md`): - - Pass: the ADR file path (or draft content), engine version, domain, any existing ADRs in the same domain - - The TD validates architectural coherence (is this decision consistent with the whole system?) — distinct from the engine specialist's API-level check - - On CONCERNS: show them to the user verbatim and ask with the standard options from `director-gates.md` — `Revise flagged items` / `Accept and proceed` / `Discuss further`. Revise the flagged Decision or Alternatives sections only on `Revise flagged items`. - - On REJECT: show the blockers verbatim and revise the Decision or Alternatives sections before proceeding. - - A revised draft still reaches the user through the write approval below; nothing is written before it. A `NOT ASSESSED` answer is not an approval — name the missing input (`director-gates.md`). - -5.7. **GDD Sync Check** — Before presenting the write approval, scan all GDDs -referenced in the "GDD Requirements Addressed" section for naming inconsistencies -with the ADR's Key Interfaces and Decision sections (renamed signals, API methods, -or data types). If any are found, surface them as a **prominent warning block** -immediately before the write approval — not as a footnote: - -``` -⚠️ GDD SYNC REQUIRED -[gdd-filename].md uses names this ADR has renamed: - [old_name] → [new_name_from_adr] - [old_name_2] → [new_name_2_from_adr] -The GDD must be updated before or alongside writing this ADR to prevent -developers reading the GDD from implementing the wrong interface. -``` - -**This check has three outcomes, not two.** The two above are "found" and "none -found"; the third is **could not check**, and until now it fell through the -silent branch and rendered exactly like a clean result. - -- **None found** — print one line, do not stay silent: - `GDD sync: checked [N] referenced GDD(s), no naming inconsistencies.` - A silent pass is indistinguishable from a check that never ran, and this one - guards against developers implementing the wrong interface from a stale GDD. -- **Could not check** — the ADR has no `GDD Requirements Addressed` section, it - names no GDDs, or a named GDD does not exist on disk. Print: - `GDD sync: NOT ASSESSED — [which reason, and which files]` - Do **not** treat an ADR that references no GDDs as one whose GDDs are - consistent. Nothing was compared. - -Only the warning block itself is conditional; the check always reports. - -5. **Write approval** — Use `AskUserQuestion`: - -If GDD sync issues were found: -- "ADR draft is complete. How would you like to proceed?" - - [A] Write ADR + update GDD in the same pass - - [B] Write ADR only — I'll update the GDD manually - - [C] Not yet — I need to review further - -If no GDD sync issues: -- "ADR draft is complete. May I write it?" - - [A] Write ADR to `docs/architecture/adr-[NNNN]-[slug].md` - - [B] Not yet — I need to review further - -If yes to any write option, write the file, creating the directory if needed. -For option [A] with GDD update: also update the GDD file(s) to use the new names. - -6. **Update Architecture Registry** - -Scan the written ADR for new architectural stances that should be registered: -- State it claims ownership of -- Interface contracts it defines (signal signatures, method APIs) -- Performance budget it claims -- API choices it makes explicitly -- Patterns it bans (Consequences → Negative or explicit "do not use X") - -Present candidates: -``` -Registry candidates from this ADR: - NEW state ownership: player_stamina → stamina-system - NEW interface contract: stamina_depleted signal - NEW performance budget: stamina-system: 0.5ms/frame - NEW forbidden pattern: polling stamina each frame (use signal instead) - EXISTING (referenced_by update only): player_health → already registered ✅ -``` - -**Registry append logic**: When writing to `docs/registry/architecture.yaml`, do NOT assume sections are empty. The file may already have entries from previous ADRs written in this session. Before each Edit call: -1. Read the current state of `docs/registry/architecture.yaml` -2. Find the correct section (state_ownership, interfaces, forbidden_patterns, api_decisions) -3. Append the new entry AFTER the last existing entry in that section — do not try to replace a `[]` placeholder that may no longer exist -4. If the section has entries already, use the closing content of the last entry as the `old_string` anchor, and append the new entry after it - -**BLOCKING — do not write to `docs/registry/architecture.yaml` without explicit user approval.** - -Ask using `AskUserQuestion`: -- "May I update `docs/registry/architecture.yaml` with these [N] new stances?" - - Options: "Yes — update the registry", "Not yet — I want to review the candidates", "Skip registry update" - -Only proceed if the user selects yes. If yes: append new entries. Never modify existing entries — if a stance is -changing, set the old entry to `status: superseded_by: ADR-[NNNN]` and add the new entry. - ---- +**Read `references/5-generate.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 6. Closing Next Steps diff --git a/.claude/skills/architecture-decision/references/0-accept.md b/.claude/skills/architecture-decision/references/0-accept.md new file mode 100644 index 00000000..6b6029df --- /dev/null +++ b/.claude/skills/architecture-decision/references/0-accept.md @@ -0,0 +1,84 @@ +# /architecture-decision — Acceptance Mode + +> Part of `/architecture-decision`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +**If the argument starts with `accept` followed by an ADR id** + +(e.g., `/architecture-decision accept ADR-0005`): + +Enter **acceptance mode**. This is the *only* path in the framework that moves an +ADR from `Proposed` to `Accepted`. Authoring always produces `Proposed` +(Step 5), while +`/create-control-manifest`, `/create-epics`, `/create-stories` and `/gate-check` +all require `Accepted` — so without this mode the pipeline had a state it could +enter and never leave. + +1. **Resolve the id to a file, then read it.** Glob + `docs/architecture/adr-NNNN-*.md` for the given number. If **no** file matches, + or **more than one** does, stop and say which — do not pick one. If the file + has no `## Status` section, stop and say so; a missing Status is exactly what + retrofit mode is for. +2. **Check the current status.** If it is already `Accepted`, say so and stop. + If it is `Deprecated` or `Superseded`, refuse: reviving a superseded decision + is a new ADR, not a status edit. +3. **Check its dependencies first.** Read `## ADR Dependencies`. + + **If that section is absent, empty, or reads `UNKNOWN`, do not read it as + "no dependencies" — refuse and say which:** + > "ADR-0005's dependency section is [absent / UNKNOWN], so I cannot tell what + > this decision rests on. An empty dependency list and an unexamined one look + > identical here, and only one of them is safe to accept. Run + > `/architecture-decision retrofit ` to establish it." + + A dependency check reading a field that defaults to empty is the vacuous-pass + shape this gate exists to prevent — the check would examine nothing and report + clean. + + If it depends on any ADR that is not itself `Accepted`, **refuse and name them**: + > "ADR-0005 depends on ADR-0002, which is still Proposed. Accept ADR-0002 + > first — an accepted decision resting on an unaccepted one is not a decision, + > it is a deferral with a different label." + This is the same dependency rule `/architecture-review` already flags; here it + is enforced rather than reported. +4. **Confirm with the user, always.** Per `CONTRACT.md`, acceptance authority is + **the user, or `technical-director` on the user's explicit confirmation — no + other agent, and never this skill on its own.** Use `AskUserQuestion`: + - Prompt: "Accept ADR-NNNN — [title]? This is what unblocks stories and epics + that depend on it." + - Options: `[A] Yes — accept it` / `[B] Not yet — leave it Proposed` + **This prompt fires regardless of `modes.automation`, including `autonomous`.** + Acceptance is the decision the whole architecture pipeline gates on; it is not + a step to be inferred. +5. **Find the stories this will unblock, BEFORE the prompt in step 4.** Grep + every story for a Blocked Status line — + `Grep pattern="Status\**:\**\s*Blocked" path="production/epics" glob="**/story-*.md" output_mode="files_with_matches"`, + which matches `> **Status**: Blocked` (the form `/create-stories` writes), + `**Status:** Blocked` and `Status: Blocked` — and keep the files that name + this ADR's id as the reason they are blocked. That pairing is what "blocked + pending this ADR" means — a story blocked for an unrelated reason will not + name it. Leave out a story that names this ADR only as the successor to point + at (`point the story at ADR-NNNN`, the note for a `Deprecated` or + `Superseded` ADR): it is still governed by the old ADR, and accepting the + successor does not re-point it. + > **Stories live only under `production/epics/`.** A flat top-level stories + > directory does not exist and no skill creates one — never write or match a + > path outside `production/epics/`. `/dev-story` matches entries *by file + > path*, so a story recorded under any other path silently fails to match and + > never gets picked up. + + Feed the count into step 4's prompt so it reads *"3 stories become Ready"* + rather than a generic claim: **the user is being asked to authorise an effect, and should be + shown the effect.** If none match, say "no stories are waiting on this" — that + is useful information, not an empty result to omit. +6. On confirmation, `Edit` the `## Status` line to `Accepted`. Leave an existing + `## Date` as it is: it records when the ADR was written, and `/create-stories` + stamps stories with it (or `## Last Verified`), so rewriting it on acceptance + would make every story drafted against the Proposed ADR look out of date to + `/dev-story`. **If that section is absent, add it** with today's date — retrofit + mode already owns this shape, and acceptance must not fail on a template that + predates the field. +7. Then set each story found in step 5 from `Blocked` to `Ready`. Unblocking is a + consequence of acceptance, never of authoring — see Step 6's note below. +8. Report what moved: the ADR (and its `## Date`, if one was added), and every + story that became Ready. diff --git a/.claude/skills/architecture-decision/references/0-retrofit.md b/.claude/skills/architecture-decision/references/0-retrofit.md new file mode 100644 index 00000000..20b25dfa --- /dev/null +++ b/.claude/skills/architecture-decision/references/0-retrofit.md @@ -0,0 +1,57 @@ +# /architecture-decision — Retrofit Mode + +> Part of `/architecture-decision`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +**If the argument starts with `retrofit` followed by a file path** + +(e.g., `/architecture-decision retrofit docs/architecture/adr-0001-event-system.md`): + +Enter **retrofit mode**: + +1. Read the existing ADR file completely. +2. Identify which template sections are present by scanning headings: + - `## Status` — **BLOCKING if missing**: `/story-readiness` cannot check ADR acceptance + - `## ADR Dependencies` — HIGH if missing: dependency ordering breaks + - `## Engine Compatibility` — HIGH if missing: post-cutoff risk unknown + - `## GDD Requirements Addressed` — MEDIUM if missing: traceability lost + - `## Date` — MEDIUM if missing, and no `## Last Verified` either: `/create-stories` + stamps stories with it and `/dev-story` compares against it, so without it a + story can never tell whether the ADR changed +3. Present to the user: + ``` + ## Retrofit: [ADR title] + File: [path] + + Sections already present (will not be touched): + ✓ Status: [current value, or "MISSING — will add"] + ✓ [section] + + Missing sections to add: + ✗ Status — BLOCKING (stories cannot validate ADR acceptance without this) + ✗ ADR Dependencies — HIGH + ✗ Engine Compatibility — HIGH + ``` +4. Ask: "Shall I add the [N] missing sections? I will not modify any existing content." + If no: write nothing, and report the missing sections by name. +5. If yes: + - For **Status**: ask the user — "What is the current status of this decision?" + Options: "Proposed", "Accepted", "Deprecated", "Superseded by ADR-XXXX" + An `Accepted` answer — a decision already in force — is not written as + given: write `Proposed`, add the other missing sections, then run + acceptance mode (below) on this ADR. Its dependency check, confirmation and + story unblocking apply here too; it stays the only path that sets `Accepted`. + - For **ADR Dependencies**: ask — "Does this decision depend on any other ADR? + Does it enable or block any other ADR or epic?" Accept "None" for each field. + - For **Engine Compatibility**: read the engine reference docs (same as Step 1 below) + and ask the user to confirm the domain. Then generate the table with verified data. + - For **GDD Requirements Addressed**: ask — "Which GDD systems motivated this decision? + What specific requirement in each GDD does this ADR address?" + - Append each missing section to the ADR file using the Edit tool. + - For **Date** (counted only when there is no `## Last Verified`): append + `## Date` with today's date — even when it is the only missing section, the + case `/dev-story` sends you here for — and say that it records the retrofit, + not when the decision was made. + - **Never modify any existing section.** Only append or fill absent sections. +6. Suggest: "Run `/architecture-review` to re-validate coverage now that this ADR + has its Status and Dependencies fields." diff --git a/.claude/skills/architecture-decision/references/1-engine-context.md b/.claude/skills/architecture-decision/references/1-engine-context.md new file mode 100644 index 00000000..87e791fa --- /dev/null +++ b/.claude/skills/architecture-decision/references/1-engine-context.md @@ -0,0 +1,48 @@ +# /architecture-decision — Step 1: Load Engine Context + +> Part of `/architecture-decision`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 1. Load Engine Context (ALWAYS FIRST) + +Before doing anything else, establish the engine environment: + +1. Read `docs/engine-reference/[engine]/VERSION.md` to get: + - Engine name and version + - LLM knowledge cutoff date + - Post-cutoff version risk levels (LOW / MEDIUM / HIGH) + +2. Identify the **domain** of this architecture decision from the title or + user description. Common domains: Physics, Rendering, UI, Audio, Navigation, + Animation, Networking, Core, Input, Scripting. + +3. Read the corresponding module reference if it exists: + `docs/engine-reference/[engine]/modules/[domain].md` + +4. Read `docs/engine-reference/[engine]/breaking-changes.md` — flag any + changes in the relevant domain that post-date the LLM's training cutoff. + +5. Read `docs/engine-reference/[engine]/deprecated-apis.md` — flag any APIs + in the relevant domain that should not be used. + +6. **Display a knowledge gap warning** before proceeding if the domain carries + MEDIUM or HIGH risk: + + ``` + ⚠️ ENGINE KNOWLEDGE GAP WARNING + Engine: [name + version] + Domain: [domain] + Risk Level: HIGH — This version is post-LLM-cutoff. + + Key changes verified from engine-reference docs: + - [Change 1 relevant to this domain] + - [Change 2] + + This ADR will be cross-referenced against the engine reference library. + Proceed with verified information only — do NOT rely solely on training data. + ``` + + If no engine has been configured yet, prompt: "No engine is configured. + Run `/setup-engine` first, or tell me which engine you are using." + +--- diff --git a/.claude/skills/architecture-decision/references/3-gather-context.md b/.claude/skills/architecture-decision/references/3-gather-context.md new file mode 100644 index 00000000..c5088c96 --- /dev/null +++ b/.claude/skills/architecture-decision/references/3-gather-context.md @@ -0,0 +1,78 @@ +# /architecture-decision — Steps 3a and 3b: Gather Context + +> Part of `/architecture-decision`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 3. Gather context + +### 3a: Architecture Registry Check (BLOCKING gate) — do this FIRST + +Read `docs/registry/architecture.yaml`. Extract entries relevant to this ADR's +domain and decision (grep by system name, domain keyword, or state being touched). +Run this before reading any existing ADR — the registry exists specifically so a +new ADR's author does not need to open prior ADRs to learn their binding facts +(state ownership, interface contracts, forbidden patterns). + +Present any relevant stances to the user **before** the collaborative design +begins, as locked constraints: + +``` +## Existing Architectural Stances (must not contradict) + +State Ownership: + player_health → owned by health-system (ADR-0001) + Interface: HealthComponent.current_health (read-only float) + → If this ADR reads or writes player health, it must use this interface. + +Interface Contracts: + damage_delivery → signal pattern (ADR-0003) + Signal: damage_dealt(amount, target, is_crit) + → If this ADR delivers or receives damage events, it must use this signal. + +Forbidden Patterns: + ✗ autoload_singleton_coupling (ADR-0001) + ✗ direct_cross_system_state_write (ADR-0000) + → The proposed approach must not use these patterns. +``` + +If the user's proposed decision would contradict any registered stance, surface +the conflict immediately: + +> "⚠️ Conflict: This ADR proposes [X], but ADR-[NNNN] established that [Y] is +> the accepted pattern for this purpose. Proceeding without resolving this will +> produce contradictory ADRs and inconsistent stories. +> Options: (1) Align with the existing stance, (2) Supersede ADR-[NNNN] with +> an explicit replacement, (3) Explain why this case is an exception." + +Do not proceed to Step 4 (collaborative design) until any conflict is resolved +or explicitly accepted as an intentional exception. + +### 3b: Existing ADRs and Related GDDs — registry-scoped, never unbounded + +The registry (3a) covers *what* prior decisions bind — not always *why*. If the +registry surfaced a directly relevant ADR and its reasoning matters here (not +just its stated facts), read that specific ADR — never glob-and-read every +ADR in `docs/architecture/` on the chance one is relevant: + +1. **Map its headings first** (cheap): + ``` + Grep pattern="^## " path="docs/architecture/[adr-file].md" output_mode="content" -n + ``` +2. **Under ~50KB** (`Bash: wc -c "docs/architecture/[adr-file].md"`) — one full + `Read` is fine; per-call overhead exceeds the savings from bounded reads at + this size. +3. **~50KB or larger** — bounded-read only `## Context`, `## Decision`, and + `## Consequences` (the sections that carry reasoning, not just facts) via + `Read(offset, limit)` from the heading map. + +Read GDDs the same way `/design-system` Step 2b does: only GDDs the registry +or the ADR list names as directly relevant, and only their `## Dependencies`, +`## Formulas`, and `## Edge Cases` sections +(`Grep pattern="^## (Dependencies|Formulas|Edge Cases)" ... -A 40`) — never a +speculative full read of `design/gdd/*.md` looking for anything that might +relate. + +Skip 3b entirely if the registry already answers everything this decision +needs — most ADRs will. + +--- diff --git a/.claude/skills/architecture-decision/references/4-decide.md b/.claude/skills/architecture-decision/references/4-decide.md new file mode 100644 index 00000000..c04da533 --- /dev/null +++ b/.claude/skills/architecture-decision/references/4-decide.md @@ -0,0 +1,73 @@ +# /architecture-decision — Step 4: Guide the Decision Collaboratively + +> Part of `/architecture-decision`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 4. Guide the decision collaboratively + +Before asking anything, derive the skill's best guesses from the context already +gathered (GDDs read, engine reference loaded, existing ADRs scanned). Then present +a **confirm/adjust** prompt using `AskUserQuestion` — not open-ended questions. + +**Derive assumptions first:** +- **Problem**: Infer from the title + GDD context what decision needs to be made +- **Alternatives**: Propose 2-3 concrete options from engine reference + GDD requirements +- **Dependencies**: Scan existing ADRs for upstream dependencies. **If the scan is + inconclusive, present `UNKNOWN — scan inconclusive, please confirm`, never + `None`.** The two are not interchangeable: `None` asserts that nothing upstream + constrains this decision, and a user confirming a prefilled list cannot tell an + assertion from a guess. This field is load-bearing — `/architecture-review` + flags unaccepted dependencies, `/dev-story` reads it, and the acceptance route + in Phase 0 **refuses to accept an ADR whose dependencies are not themselves + Accepted**. A dependency list that defaulted to empty makes that check pass + while examining nothing. `UNKNOWN` must be resolved during the confirm/adjust + prompt; it is a prompt state, never a value written to the file +- **GDD linkage**: Extract which GDD systems the title directly relates to +- **Status**: Always `Proposed` for new ADRs — never ask the user what the status is + +**Scope of assumptions tab**: Assumptions cover only: problem framing, alternative approaches, upstream dependencies, GDD linkage, and status. Schema design questions (e.g., "How should spawn timing work?", "Should data be inline or external?") are NOT assumptions — they are design decisions belonging to a separate step after the assumptions are confirmed. Do not include schema design questions in the assumptions AskUserQuestion widget. + +**After assumptions are confirmed**, if the ADR involves schema or data design choices, use a separate multi-tab `AskUserQuestion` to ask each design question independently before drafting. + +**Present assumptions with `AskUserQuestion`:** + +``` +Here's what I'm assuming before drafting: + +Problem: [one-sentence problem statement derived from context] +Alternatives I'll consider: + A) [option derived from engine reference] + B) [option derived from GDD requirements] + C) [option from common patterns] +GDD systems driving this: [list derived from context] +Dependencies: [upstream ADRs if any, otherwise "None"] +Status: Proposed + +[A] Proceed — draft with these assumptions +[B] Change the alternatives list +[C] Adjust the GDD linkage +[D] Add a performance budget constraint +[E] Something else needs changing first +``` + +Do not generate the ADR until the user confirms assumptions or provides corrections. + +**After engine specialist and TD reviews return** (Step 5.5/5.6), if unresolved +decisions remain, present each one as a separate `AskUserQuestion` with the proposed +options as choices plus a free-text escape: + +``` +Decision: [specific unresolved point] +[A] [option from specialist review] +[B] [alternative option] +[C] Different approach — I'll describe it +``` + +**ADR Dependencies** — derive from existing ADRs, then confirm: +- Does this decision depend on any other ADR not yet Accepted? +- Does it unlock or unblock any other ADR or epic? +- Does it block any specific epic from starting? + +Record answers in the **ADR Dependencies** section. Write "None" for each field if no constraints apply. + +--- diff --git a/.claude/skills/architecture-decision/references/5-generate.md b/.claude/skills/architecture-decision/references/5-generate.md new file mode 100644 index 00000000..967adb50 --- /dev/null +++ b/.claude/skills/architecture-decision/references/5-generate.md @@ -0,0 +1,246 @@ +# /architecture-decision — Step 5: Generate the ADR + +> Part of `/architecture-decision`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 5. Generate the ADR + +**In this file:** + +- The ADR template +- 5.5 Engine Specialist Validation +- 5.6 Technical Director Strategic Review, with the review mode check +- 5.7 GDD Sync Check: found, none found, could not check +- Write approval +- Update Architecture Registry, and the registry append logic + +Following this format: + +```markdown +# ADR-[NNNN]: [Title] + +## Status +[Proposed | Accepted | Deprecated | Superseded by ADR-XXXX] + +## Date +[Date of decision] + +## Last Verified +[YYYY-MM-DD — when this ADR was last confirmed accurate against the current +engine version and design. Update this date when you re-read and confirm it is +still correct, even if nothing changed.] + +## Decision Makers +[Who was involved in this decision] + +## Summary +[2 sentences: what problem this ADR solves, and what was decided. Written for +tiered context loading — a skill scanning 20 ADRs uses this to decide whether to +read the full decision. Be specific: name the system, the problem, and the +chosen approach.] + +## Engine Compatibility + +| Field | Value | +|-------|-------| +| **Engine** | [e.g. Godot 4.6] | +| **Domain** | [Physics / Rendering / UI / Audio / Navigation / Animation / Networking / Core / Input] | +| **Knowledge Risk** | [LOW / MEDIUM / HIGH — from VERSION.md] | +| **References Consulted** | [List engine-reference docs read, e.g. `docs/engine-reference/godot/modules/physics.md`] | +| **Post-Cutoff APIs Used** | [Any APIs from post-LLM-cutoff versions this decision depends on, or "None"] | +| **Verification Required** | [Specific behaviours to test before shipping, or "None"] | + +## ADR Dependencies + +| Field | Value | +|-------|-------| +| **Depends On** | [ADR-NNNN (must be Accepted before this can be implemented), or "None"] | +| **Enables** | [ADR-NNNN (this ADR unlocks that decision), or "None"] | +| **Blocks** | [Epic/Story name — cannot start until this ADR is Accepted, or "None"] | +| **Ordering Note** | [Any sequencing constraint that isn't captured above] | + +## Context + +### Problem Statement +[What problem are we solving? Why does this decision need to be made now?] + +### Constraints +- [Technical constraints] +- [Timeline constraints] +- [Resource constraints] +- [Compatibility requirements] + +### Requirements +- [Must support X] +- [Must perform within Y budget] +- [Must integrate with Z] + +## Decision + +[The specific technical decision made, described in enough detail for someone +to implement it.] + +### Architecture Diagram +[ASCII diagram or description of the system architecture this creates] + +### Key Interfaces +[API contracts or interface definitions this decision creates] + +### Implementation Guidelines +[Specific guidance for the programmer implementing this decision — the rules a +`/create-control-manifest` or `/dev-story` run should follow. State mandates as +"must / must never" so they extract cleanly.] + +## Alternatives Considered + +### Alternative 1: [Name] +- **Description**: [How this would work] +- **Pros**: [Advantages] +- **Cons**: [Disadvantages] +- **Rejection Reason**: [Why this was not chosen] + +### Alternative 2: [Name] +- **Description**: [How this would work] +- **Pros**: [Advantages] +- **Cons**: [Disadvantages] +- **Rejection Reason**: [Why this was not chosen] + +## Consequences + +### Positive +- [Good outcomes of this decision] + +### Negative +- [Trade-offs and costs accepted] + +## Risks +- [Things that could go wrong] +- [Mitigation for each risk] + +## GDD Requirements Addressed + +| GDD System | Requirement | How This ADR Addresses It | +|------------|-------------|--------------------------| +| [system-name].md | [specific rule, formula, or performance constraint from that GDD] | [how this decision satisfies it] | + +## Performance Implications +- **CPU**: [Expected impact] +- **Memory**: [Expected impact] +- **Load Time**: [Expected impact] +- **Network**: [Expected impact, if applicable] + +## Migration Plan +[If this changes existing code, how do we get from here to there?] + +## Validation Criteria +[How will we know this decision was correct? What metrics or tests?] + +## Related +- [Links to related ADRs — note if supersedes, contradicts, or depends on] +- [Links to related design documents] +``` + +5.5. **Engine Specialist Validation** — Before saving, spawn the **primary engine specialist** via `Agent` to validate the drafted ADR: + - Resolve the primary specialist: `-specialist` derived from `engine.name` in `project.yaml` (Godot→`godot-specialist`, Unity→`unity-specialist`, Unreal→`unreal-specialist`); if `engine.name` is absent or empty, read the Primary line of the `## Engine Specialists` section in `.claude/docs/technical-preferences.md` + - If no engine is configured (neither source yields an engine), skip this step **Record ``Engine validation: NOT ASSESSED — no engine configured (`engine.name` unset in `project.yaml`)`` in this run's output.** A skipped check that says nothing is indistinguishable from a check that passed; the reader cannot tell engine guidance was never sought. + - Spawn `subagent_type: [primary specialist]` with: the ADR's Engine Compatibility section, Decision section, Key Interfaces, and the engine reference docs path. Ask them to: + 1. Confirm the proposed approach is idiomatic for the pinned engine version + 2. Flag any APIs or patterns that are deprecated or changed post-training-cutoff + 3. Identify engine-specific risks or gotchas not captured in the current ADR draft + - If the specialist identifies a **blocking issue** (wrong API, deprecated approach, engine version incompatibility): revise the Decision and Engine Compatibility sections accordingly, then confirm the changes with the user before proceeding + - If the specialist finds **minor notes** only: incorporate them into the ADR's Risks subsection + +**Review mode check** — apply before spawning TD-ADR: +- `solo` → skip. Note: "TD-ADR skipped — Solo mode." Proceed to Step 5.7 (GDD sync check). +- `lean` → skip (not a PHASE-GATE). Note: "TD-ADR skipped — Lean mode." Proceed to Step 5.7 (GDD sync check). +- `full` → spawn as normal. + +5.6. **Technical Director Strategic Review** — After the engine specialist validation, spawn `technical-director` via `Agent` using gate **TD-ADR** (`.claude/docs/director-gates/td-adr.md`): + - Pass: the ADR file path (or draft content), engine version, domain, any existing ADRs in the same domain + - The TD validates architectural coherence (is this decision consistent with the whole system?) — distinct from the engine specialist's API-level check + - On CONCERNS: show them to the user verbatim and ask with the standard options from `director-gates.md` — `Revise flagged items` / `Accept and proceed` / `Discuss further`. Revise the flagged Decision or Alternatives sections only on `Revise flagged items`. + - On REJECT: show the blockers verbatim and revise the Decision or Alternatives sections before proceeding. + - A revised draft still reaches the user through the write approval below; nothing is written before it. A `NOT ASSESSED` answer is not an approval — name the missing input (`director-gates.md`). + +5.7. **GDD Sync Check** — Before presenting the write approval, scan all GDDs +referenced in the "GDD Requirements Addressed" section for naming inconsistencies +with the ADR's Key Interfaces and Decision sections (renamed signals, API methods, +or data types). If any are found, surface them as a **prominent warning block** +immediately before the write approval — not as a footnote: + +``` +⚠️ GDD SYNC REQUIRED +[gdd-filename].md uses names this ADR has renamed: + [old_name] → [new_name_from_adr] + [old_name_2] → [new_name_2_from_adr] +The GDD must be updated before or alongside writing this ADR to prevent +developers reading the GDD from implementing the wrong interface. +``` + +**This check has three outcomes, not two.** The two above are "found" and "none +found"; the third is **could not check**, and until now it fell through the +silent branch and rendered exactly like a clean result. + +- **None found** — print one line, do not stay silent: + `GDD sync: checked [N] referenced GDD(s), no naming inconsistencies.` + A silent pass is indistinguishable from a check that never ran, and this one + guards against developers implementing the wrong interface from a stale GDD. +- **Could not check** — the ADR has no `GDD Requirements Addressed` section, it + names no GDDs, or a named GDD does not exist on disk. Print: + `GDD sync: NOT ASSESSED — [which reason, and which files]` + Do **not** treat an ADR that references no GDDs as one whose GDDs are + consistent. Nothing was compared. + +Only the warning block itself is conditional; the check always reports. + +5. **Write approval** — Use `AskUserQuestion`: + +If GDD sync issues were found: +- "ADR draft is complete. How would you like to proceed?" + - [A] Write ADR + update GDD in the same pass + - [B] Write ADR only — I'll update the GDD manually + - [C] Not yet — I need to review further + +If no GDD sync issues: +- "ADR draft is complete. May I write it?" + - [A] Write ADR to `docs/architecture/adr-[NNNN]-[slug].md` + - [B] Not yet — I need to review further + +If yes to any write option, write the file, creating the directory if needed. +For option [A] with GDD update: also update the GDD file(s) to use the new names. + +6. **Update Architecture Registry** + +Scan the written ADR for new architectural stances that should be registered: +- State it claims ownership of +- Interface contracts it defines (signal signatures, method APIs) +- Performance budget it claims +- API choices it makes explicitly +- Patterns it bans (Consequences → Negative or explicit "do not use X") + +Present candidates: +``` +Registry candidates from this ADR: + NEW state ownership: player_stamina → stamina-system + NEW interface contract: stamina_depleted signal + NEW performance budget: stamina-system: 0.5ms/frame + NEW forbidden pattern: polling stamina each frame (use signal instead) + EXISTING (referenced_by update only): player_health → already registered ✅ +``` + +**Registry append logic**: When writing to `docs/registry/architecture.yaml`, do NOT assume sections are empty. The file may already have entries from previous ADRs written in this session. Before each Edit call: +1. Read the current state of `docs/registry/architecture.yaml` +2. Find the correct section (state_ownership, interfaces, forbidden_patterns, api_decisions) +3. Append the new entry AFTER the last existing entry in that section — do not try to replace a `[]` placeholder that may no longer exist +4. If the section has entries already, use the closing content of the last entry as the `old_string` anchor, and append the new entry after it + +**BLOCKING — do not write to `docs/registry/architecture.yaml` without explicit user approval.** + +Ask using `AskUserQuestion`: +- "May I update `docs/registry/architecture.yaml` with these [N] new stances?" + - Options: "Yes — update the registry", "Not yet — I want to review the candidates", "Skip registry update" + +Only proceed if the user selects yes. If yes: append new entries. Never modify existing entries — if a stance is +changing, set the old entry to `status: superseded_by: ADR-[NNNN]` and add the new entry. + +--- diff --git a/.claude/skills/architecture-review/SKILL.md b/.claude/skills/architecture-review/SKILL.md index 2b445402..7463dc11 100644 --- a/.claude/skills/architecture-review/SKILL.md +++ b/.claude/skills/architecture-review/SKILL.md @@ -9,8 +9,6 @@ model: opus !`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys automation,workflow` - - # Architecture Review The architecture review validates that the complete body of architectural decisions @@ -43,791 +41,39 @@ Every `AskUserQuestion` call follows `.claude/docs/automation-modes.md` ## Phase 1: Load Everything -### Phase 1a — L0: Summary Scan (fast, low tokens) - -**Freshness check before any scan.** Locate the latest prior report — Glob -`docs/architecture/architecture-review-*.md` and take the newest — then: - -``` -Bash: bash .claude/scripts/review-receipts.sh check "[latest-report]" docs/architecture/adr-*.md design/gdd/*.md -``` - -- **Any `UNRESOLVED`** — check this FIRST; it disqualifies every option - below. One of the two globs matched no file, so that whole document class - was never examined and the comparison covered less than it appears to. - Say which pattern came back unresolved and stop: an ADR or GDD directory - that is empty, renamed or misspelled is a finding about the project, not a - reason to stand on a prior report. Never read a set of `UNCHANGED` lines as - "everything is current" while an `UNRESOLVED` line is present — the set - compared was not the set requested. -- **Everything `UNCHANGED`** (and no `UNRESOLVED`) — nothing this review - reads has changed since that report; re-running reproduces it. Surface the - prior report's date and verdict and offer via `AskUserQuestion`: `[A] Stand - on the prior report (Recommended)` / `[B] Re-run the full review anyway` — - `guided` proceeds with [A] and notes it; `autonomous` logs via - `log_decision` and stands on the prior report. -- **Some `CHANGED`/`NEW`** — name them, then scope instead of re-running - everything: recommend `/architecture-review [system]` (single-system mode) - for just the changed systems. A full re-run stays available on request, - and structural changes (a `NEW` ADR, a deleted file) warrant one. -- **`RECEIPT: NONE`** — no prior report, or one written before receipts - existed. Proceed with the full review; this run's report will carry the - first stamps. - -Before reading any full document, use Grep to extract `## Summary` sections -from all GDDs and ADRs: - -``` -Grep pattern="## Summary" glob="design/gdd/*.md" output_mode="content" -A 4 -Grep pattern="## Summary" glob="docs/architecture/adr-*.md" output_mode="content" -A 3 -``` - -**Fail open on a missing Summary.** Establish the denominator: glob -`design/gdd/*.md` and count **N**. A scan matching fewer than N means those GDDs -predate `## Summary` (`/design-system` emits it, but older GDDs lack it) — never -treat an absent Summary as a system out of scope. A zero-match scan means "no GDD -carries a Summary yet", not "nothing to review": full-read the unmatched set. - -For `single-gdd [path]` mode: use the target GDD's summary to identify which -ADRs reference the same system (Grep ADRs for the system name), then load only -those ADRs' sections per Phase 1b. Skip unrelated GDDs entirely. - -For `engine` mode: load ADR sections only — GDDs are not needed for engine checks. -In practice this is the `## Engine Compatibility` scan alone. - -For `coverage` or `full` mode: proceed to Phase 1b for the full in-scope set. -**This is a section load, not a full-file load** — see below for why, and for the -narrow cases that still justify escalating to a whole document. - -### Phase 1b — L1/L2: Targeted Section Load - -Load the sections the later phases actually consume — **not whole files**. This -skill reads the two largest document sets in the project (every GDD *and* every -ADR); at realistic sizes a full load of both exhausts the context window before -Phase 2 starts, and most of what it loads is narrative this skill never uses. - -**Establish the denominator first.** Glob `design/gdd/*.md` and count **N_gdd**; -glob `docs/architecture/adr-*.md` and count **N_adr**. Report both. A section -scan matching fewer than the denominator means those documents lack the section — -**never treat an absent section as an absent document.** The scan narrows the -*read* set; it never shrinks the *in-scope* set. - -### Design Documents - -Phase 2 extracts *technical requirements* — data structures, performance -constraints, engine capabilities, cross-system communication, persistence, -threading, platform needs. Those live in a known set of sections; Overview and -Player Fantasy are narrative and yield none. - -``` -Grep pattern="^## (Detailed Rules|Detailed Design|Formulas|Dependencies|Tuning Knobs|Acceptance Criteria)" glob="design/gdd/*.md" output_mode="content" -A 40 -``` - -Accept **either** `## Detailed Rules` or `## Detailed Design` — the design -standard and the GDD template disagree on the name and they denote the same -required section. Full-read a single GDD only when a scanned section -cross-references material outside itself, or when a GDD matched zero sections -(it predates the template — read it whole and say so). - -- `design/gdd/systems-index.md` — the authoritative list of systems; read whole (small, and it is an index) - -### Architecture Documents - -Phases 3–5 need the traceability table, the decision itself, engine claims, and -the dependency edges — not Context, Consequences, Alternatives, Migration Plan or -Validation Criteria, which explain *why* a decision was made. - -``` -Grep pattern="^## (Status|Decision|GDD Requirements Addressed|Engine Compatibility|ADR Dependencies|Performance Implications)" glob="docs/architecture/adr-*.md" output_mode="content" -A 30 -``` - -Interpret against **N_adr**, and distinguish the two zero-match cases — they are -not the same finding: - -| Result | Meaning | Action | -|---|---|---| -| N_adr matches | Normal. | Proceed on the scanned sections. | -| Some ADRs match, some do not | Those ADRs are missing sections. | Record each as a **structural gap** in the Phase 7 report — a missing `## GDD Requirements Addressed` is itself a traceability finding. | -| **0 matches, N_adr > 0** | **Malformed ADRs**, not "no architecture". | "[N_adr] ADRs found, none carries a scannable section — run `/architecture-decision retrofit [file]` on each." Do **not** report zero coverage; that would read as a design failure when it is a format failure. | - -Escalate to a full read of one ADR only when judging a conflict needs its -reasoning (Phase 4) — that is a per-ADR decision, not a blanket load. - -- `docs/architecture/architecture.md` if it exists - -### Engine Reference -- `docs/engine-reference/[engine]/VERSION.md` -- `docs/engine-reference/[engine]/breaking-changes.md` -- `docs/engine-reference/[engine]/deprecated-apis.md` -- **Only the module docs the in-scope ADRs actually name** — take the union of - each ADR's `References Consulted` and `Post-Cutoff APIs Used` fields (already - captured by the `## Engine Compatibility` scan above) and read those files. - Reading the whole `modules/` directory loads engine subsystems the project may - not use at all. If no ADR names any module, read none and note it: Phase 5 - cannot cross-check engine claims that were never made. - -### Project Standards -- `project.yaml` — `naming.*` and `performance.*`; plus `.claude/docs/technical-preferences.md` for those keys when absent and for forbidden patterns / allowed libraries - -Report a count: "Loaded [N] GDDs, [M] ADRs, engine: [name + version]." - -**Also read `docs/consistency-failures.md`** if it exists. Extract entries with -Domain matching the systems under review (Architecture, Engine, or any GDD domain -being covered). Surface recurring patterns as a "Known conflict-prone areas" note -at the top of the Phase 4 conflict detection output. - ---- +**Read `references/1-load.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 2: Extract Technical Requirements from Every GDD -### Pre-load the TR Registry - -Before extracting any requirements, read `docs/architecture/tr-registry.yaml` -if it exists. Index existing entries by `id` and by normalized `requirement` -text (lowercase, trimmed). This prevents ID renumbering across review runs. - -For each requirement you extract, the matching rule is: -1. **Exact/near match** to an existing registry entry for the same system → - reuse that entry's TR-ID unchanged. Update the `requirement` text in the - registry only if the GDD wording changed (same intent, clearer phrasing) — - add a `revised: [date]` field. -2. **No match** → assign a new ID: next available `TR-[system]-NNN` for that - system, starting from the highest existing sequence + 1. -3. **Ambiguous** (partial match, intent unclear) → ask the user: - > "Does '[new requirement text]' refer to the same requirement as - > `TR-[system]-NNN: [existing text]'`, or is it a new requirement?" - User answers: "Same requirement" (reuse ID) or "New requirement" (new ID). - -For any requirement with `status: deprecated` in the registry — skip it. -It was removed from the GDD intentionally. - -For each GDD, read it and extract all **technical requirements** — things the -architecture must provide for the system to work. A technical requirement is any -statement that implies a specific architectural decision. - -Categories to extract: - -| Category | Example | -|----------|---------| -| **Data structures** | "Each entity has health, max health, status effects" → needs a component/data schema | -| **Performance constraints** | "Collision detection must run at 60fps with 200 entities" → physics budget ADR | -| **Engine capability** | "Inverse kinematics for character animation" → IK system ADR | -| **Cross-system communication** | "Damage system notifies UI and audio simultaneously" → event/signal architecture ADR | -| **State persistence** | "Player progress persists between sessions" → save system ADR | -| **Threading/timing** | "AI decisions happen off the main thread" → concurrency ADR | -| **Platform requirements** | "Supports keyboard, gamepad, touch" → input system ADR | - -For each GDD, produce a structured list: - -``` -GDD: [filename] -System: [system name] -Technical Requirements: - TR-[GDD]-001: [requirement text] → Domain: [Physics/Rendering/etc] - TR-[GDD]-002: [requirement text] → Domain: [...] -``` - -This becomes the **requirements baseline** — the complete set of what the -architecture must cover. - ---- +**Read `references/2-extract-requirements.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 3: Build the Traceability Matrix -For each technical requirement extracted in Phase 2, search the ADRs: - -1. Use the ADRs **already loaded in Phase 1b** — do not re-read them. Extract each - ADR's "GDD Requirements Addressed" section from what is already in context. - (If Phase 1b ran in a mode that did not load every ADR, `Grep pattern="## GDD - Requirements Addressed" glob="docs/architecture/adr-*.md" output_mode="content" - -A 15` fills the gap without a full re-read.) -2. Check if it explicitly references the requirement or its GDD -3. Check if the ADR's decision text implicitly covers the requirement -4. Mark coverage status: - -| Status | Meaning | -|--------|---------| -| ✅ **Covered** | An **Accepted** ADR explicitly addresses this requirement | -| 🟡 **Covered (Proposed)** | An ADR addresses it, but that ADR is still `Proposed` | -| ⚠️ **Partial** | An ADR partially covers this, or coverage is ambiguous | -| ❌ **Gap** | No ADR addresses this requirement | -| ❓ **Not assessed** | The ADR is unreadable, or has no `## Status` section | - -> **Read each ADR's `## Status` before marking coverage — an unaccepted decision -> is not coverage.** If `✅` meant only that *an ADR addresses this*, with no -> status qualification, a requirement covered entirely by `Proposed` ADRs would -> count as covered and this review could return **PASS: All requirements -> covered** over an architecture nobody had accepted. Four skills downstream -> (`create-control-manifest`, `create-epics`, `create-stories`, `gate-check`) -> require `Accepted`, so a PASS on that basis sends work forward that every one -> of them will refuse. -> -> `🟡` is **not** a pass state: it caps the verdict at **CONCERNS**, and names the -> route out — `/architecture-decision accept ADR-NNNN`. That route is the only -> thing that moves an ADR to `Accepted`; without it, grading `Proposed` as -> covered would be the only option, which is why it must never be graded so. - -Build the full matrix: - -``` -## Traceability Matrix - -| Requirement ID | GDD | System | Requirement | ADR Coverage | Status | -|---------------|-----|--------|-------------|--------------|--------| -| TR-combat-001 | combat.md | Combat | Hitbox detection < 1 frame | ADR-0003 | ✅ | -| TR-combat-002 | combat.md | Combat | Combo window timing | — | ❌ GAP | -| TR-inventory-001 | inventory.md | Inventory | Persistent item storage | ADR-0005 | ✅ | -``` - -Count the totals: X covered, Y partial, Z gaps. - ---- - -## Phase 3b: Story and Test Linkage (RTM mode only) - -*Skip this phase unless the argument is `rtm` or `full` with stories present.* - -This phase extends the Phase 3 matrix to include the story that implements -each requirement and the test that verifies it — producing the full -Requirements Traceability Matrix (RTM). - -### Step 3b-1 — Load stories - -Glob `production/epics/**/*.md` (excluding EPIC.md index files) to establish the -denominator. Then collect the fields with **targeted section greps, not a full -read of each story** — the same two-grep form `/test-evidence-review` uses for -this identical extraction: - -``` -Grep pattern="## Test Evidence" glob="production/epics/**/story-*.md" output_mode="content" -A 8 -Grep pattern="TR-" glob="production/epics/**/story-*.md" output_mode="content" -``` - -- **TR-ID** — from the second grep. -- **Test file path** — under `## Test Evidence`, captured by the first grep's `-A 8`. -- **Status** — from the story header; add `Grep pattern="^> \*\*Status\*\*"` if not already captured. -- **Story path and title** — from the file name and path; no read at all. - -Full-read a story only when its Test Evidence section is missing or ambiguous. - -### Step 3b-2 — Load test files - -Glob the engine's test root (`.claude/docs/directory-structure.md`): Godot -`tests/unit/**/*_test.*` and `tests/integration/**/*_test.*`; Unity -`Assets/Tests/**/*Tests.cs`; Unreal `Source/*/Private/Tests/**/*.cpp`. With no -engine configured, say the test index could not be built rather than reading an -empty glob as "no tests". Build an index: system → [test file paths]. - -For each test file path from Step 3b-1, confirm via Glob whether the file -actually exists. Note MISSING if the stated path does not exist. - -### Step 3b-3 — Build the extended RTM - -For each TR-ID in the Phase 3 matrix, add: -- **Story**: the story file path(s) that reference this TR-ID (may be multiple) -- **Test File**: the test file path stated in the story's Test Evidence section -- **Test Status**: COVERED (test file exists) / MISSING (path stated but not - found) / NONE (no test path stated, story type may be Visual/Feel/UI) / - NO STORY (requirement has no story yet — pre-production gap) - -Extended matrix format: - -``` -## Requirements Traceability Matrix (RTM) - -| TR-ID | GDD | Requirement | ADR | Story | Test File | Test Status | -|-------|-----|-------------|-----|-------|-----------|-------------| -| TR-combat-001 | combat.md | Hitbox < 1 frame | ADR-0003 | story-001-hitbox.md | tests/unit/combat/hitbox_test.gd | COVERED | -| TR-combat-002 | combat.md | Combo window | — | story-002-combo.md | — | NONE (Visual/Feel) | -| TR-inventory-001 | inventory.md | Persistent storage | ADR-0005 | — | — | NO STORY | -``` - -RTM coverage summary: -- COVERED: [N] — requirements with ADR + story + passing test -- MISSING test: [N] — story exists but test file not found -- NO STORY: [N] — requirements with ADR but no story yet -- NO ADR: [N] — requirements without architectural coverage (from Phase 3 gaps) -- Full chain complete (COVERED): [N/total] ([%]) - ---- +**Read `references/3-traceability.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 4: Cross-ADR Conflict Detection -Compare every ADR against every other ADR to detect contradictions. A conflict -exists when: - -- **Data ownership conflict**: Two ADRs claim exclusive ownership of the same data -- **Integration contract conflict**: ADR-A assumes System X has interface Y, but - ADR-B defines System X with a different interface -- **Performance budget conflict**: ADR-A allocates N ms to physics, ADR-B allocates - N ms to AI, together they exceed the total frame budget -- **Dependency cycle**: ADR-A says System X initialises before Y; ADR-B says Y - initialises before X -- **Architecture pattern conflict**: ADR-A uses event-driven communication for a - subsystem; ADR-B uses direct function calls to the same subsystem -- **State management conflict**: Two ADRs define authority over the same game state - (e.g. both Combat ADR and Character ADR claim to own the health value) - -For each conflict found: - -``` -## Conflict: [ADR-NNNN] vs [ADR-MMMM] -Type: [Data ownership / Integration / Performance / Dependency / Pattern / State] -ADR-NNNN claims: [...] -ADR-MMMM claims: [...] -Impact: [What breaks if both are implemented as written] -Resolution options: - 1. [Option A] - 2. [Option B] -``` - -### ADR Dependency Ordering - -After conflict detection, analyse the dependency graph across all ADRs. - -**Build the graph deterministically — do not trace it by hand:** - -``` -Bash: bash .claude/scripts/adr-dep-graph.sh -``` - -It collects every `Depends On` edge, runs Kahn's algorithm, and emits -`ADRS:` / `EDGES:` / `NO_DEPS_SECTION:` / `CYCLE:`. A model tracing A→B→C→A across -a dozen ADRs eventually misses an edge; the algorithm cannot. It reports -observations, not a verdict — you apply the meaning below. - -**`NO_DEPS_SECTION` is load-bearing**: it makes "no cycles because the graph is -clean" distinguishable from "no cycles because half the ADRs declare no -dependencies". Report the second case as a structural gap, never as a clean graph. - -Then interpret: - -1. **Topological sort**: the emitted order — ADRs with no - dependencies come first (Foundation), ADRs that depend on those come next, etc. -2. **Flag unresolved dependencies**: cross the `EDGES:` list against the `## Status` - values already scanned in Phase 1b. If ADR-A depends on an ADR that is still - `Proposed` or does not exist, flag it: - ``` - ⚠️ ADR-0005 depends on ADR-0002 — but ADR-0002 is still Proposed. - ADR-0005 cannot be safely implemented until ADR-0002 is Accepted. - ``` -3. **Cycle detection**: every `CYCLE:` line the script emitted is a - `DEPENDENCY CYCLE` — report each one. Do not re-derive them by hand: - ``` - 🔴 DEPENDENCY CYCLE: ADR-0003 → ADR-0006 → ADR-0003 - This cycle must be broken before either can be implemented. - ``` -4. **Output recommended implementation order**: - ``` - ### Recommended ADR Implementation Order (topologically sorted) - Foundation (no dependencies): - 1. ADR-0001: [title] - 2. ADR-0003: [title] - Depends on Foundation: - 3. ADR-0002: [title] (requires ADR-0001) - 4. ADR-0005: [title] (requires ADR-0003) - Feature layer: - 5. ADR-0004: [title] (requires ADR-0002, ADR-0005) - ``` - ---- +**Read `references/4-conflicts.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 5: Engine Compatibility Cross-Check -Across all ADRs, check for engine consistency: - -### Version Consistency -- Do all ADRs that mention an engine version agree on the same version? -- If any ADR was written for an older engine version, flag it as potentially stale - -### Post-Cutoff API Consistency -- Collect all "Post-Cutoff APIs Used" fields from all ADRs -- For each, verify against the relevant module reference doc -- Check that no two ADRs make contradictory assumptions about the same post-cutoff API - -### Deprecated API Check -- Grep all ADRs for API names listed in `deprecated-apis.md` -- Flag any ADR referencing a deprecated API - -### Missing Engine Compatibility Sections -- List all ADRs that are missing the Engine Compatibility section entirely -- These are blind spots — their engine assumptions are unknown - -Output format: -``` -### Engine Audit Results -Engine: [name + version] -ADRs with Engine Compatibility section: X / Y total - -Deprecated API References: - - ADR-0002: uses [deprecated API] — deprecated since [version] - -Stale Version References: - - ADR-0001: written for [older version] — current project version is [version] - -Post-Cutoff API Conflicts: - - ADR-0004 and ADR-0007 both use [API] with incompatible assumptions -``` - ---- - -### Engine Specialist Consultation - -After completing the engine audit above, spawn the **primary engine specialist** via `Agent` for a domain-expert second opinion: -- Resolve the primary specialist: `-specialist` derived from `engine.name` in `project.yaml` (Godot→`godot-specialist`, Unity→`unity-specialist`, Unreal→`unreal-specialist`); if `engine.name` is absent or empty, read the Primary line of the `## Engine Specialists` section in `.claude/docs/technical-preferences.md` -- If no engine is configured (neither source yields an engine), skip this consultation **Record ``Engine validation: NOT ASSESSED — no engine configured (`engine.name` unset in `project.yaml`)`` in this run's output.** A skipped check that says nothing is indistinguishable from a check that passed; the reader cannot tell engine guidance was never sought. -- Spawn `subagent_type: [primary specialist]` with: all ADRs that contain engine-specific decisions or `Post-Cutoff APIs Used` fields, the engine reference docs, and the Phase 5 audit findings. Ask them to: - 1. Confirm or challenge each audit finding — specialists may know of engine nuances not captured in the reference docs - 2. Identify engine-specific anti-patterns in the ADRs that the audit may have missed (e.g., using the wrong Godot node type, Unity component coupling, Unreal subsystem misuse) - 3. Flag ADRs that make assumptions about engine behaviour that differ from the actual pinned version - -Incorporate additional findings under `### Engine Specialist Findings` in the Phase 5 output. These feed into the final verdict — specialist-identified issues carry the same weight as audit-identified issues. - ---- - -## Phase 5b: Design Revision Flags (Architecture → GDD Feedback) - -For each **HIGH RISK engine finding** from Phase 5, check whether any GDD makes an -assumption that the verified engine reality contradicts. - -Specific cases to check: - -1. **Post-cutoff API behaviour differs from training-data assumptions**: If an ADR - records a verified API behaviour that differs from the default LLM assumption, - check all GDDs that reference the related system. Look for design rules written - around the old (assumed) behaviour. - -2. **Known engine limitations in ADRs**: If an ADR records a known engine limitation - (e.g. "Jolt ignores HingeJoint3D damp", "D3D12 is now the default backend"), check - GDDs that design mechanics around the affected feature. - -3. **Deprecated API conflicts**: If Phase 5 flagged a deprecated API used in an ADR, - check whether any GDD contains mechanics that assume the deprecated API's behaviour. - -For each conflict found, record it in the GDD Revision Flags table: - -``` -### GDD Revision Flags (Architecture → Design Feedback) -These GDD assumptions conflict with verified engine behaviour or accepted ADRs. -The GDD should be revised before its system enters implementation. - -| GDD | Assumption | Reality (from ADR/engine-reference) | Action | -|-----|-----------|--------------------------------------|--------| -| combat.md | "Use HingeJoint3D damp for weapon recoil" | Jolt ignores damp — ADR-0003 | Revise GDD | -``` - -If no revision flags are found, write: "No GDD revision flags — all GDD assumptions -are consistent with verified engine behaviour." - -Before asking, display the proposed change inline — show the current systems-index row for each flagged GDD and the proposed updated row side by side so the user can see exactly what will change. - -Then use `AskUserQuestion`: -- "I found [N] GDD revision flag(s). May I update the systems index?" - - [A] Yes — apply all [N] updates to the systems index now - - [B] Show me the full diff first, then ask again - - [C] No — leave the systems index unchanged for now - -If [A]: apply the updates. Status field must be exactly `Needs Revision` — no parentheticals -(other skills match that exact string and parentheticals break the match). -If [B]: display the complete proposed systems-index section, then re-ask with `AskUserQuestion`. - ---- +**Read `references/5-engine.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 6: Architecture Document Coverage -**If `docs/architecture/architecture.md` does not exist, say so in the report** — -`Architecture document coverage: NOT ASSESSED — no docs/architecture/architecture.md` -— and carry it into the Phase 7 verdict per the trigger list below. Phase 5 -already models this for the engine consultation (*"A skipped check that says -nothing is indistinguishable from a check that passed"*); this phase is the one -that did not. Silently producing no Phase 6 findings reads as an architecture -document that was checked and found clean, which is the opposite of what -happened. - -If it exists, validate it against GDDs: - -- Does every system from `systems-index.md` appear in the architecture layers? -- Does the data flow section cover all cross-system communication defined in GDDs? -- Do the API boundaries support all integration requirements from GDDs? -- Are there systems in the architecture doc that have no corresponding GDD - (orphaned architecture)? - ---- +**Read `references/6-document-coverage.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 7: Output the Review Report -``` -## Architecture Review Report -Date: [date] -Engine: [name + version] -GDDs Reviewed: [N] -ADRs Reviewed: [M] - -[output of: Bash: bash .claude/scripts/review-receipts.sh hash docs/architecture/adr-*.md design/gdd/*.md - — one Reviewed-Content-Hash line per file reviewed; Phase 1a's freshness - check reads these on the next run to skip or scope an unchanged re-review] - ---- - -### Traceability Summary -Total requirements: [N] -✅ Covered: [X] -⚠️ Partial: [Y] -❌ Gaps: [Z] - -### Coverage Gaps (no ADR exists) -For each gap: - ❌ TR-[id]: [GDD] → [system] → [requirement] - Suggested ADR: "/architecture-decision [suggested title]" - Domain: [Physics/Rendering/etc] - Engine Risk: [LOW/MEDIUM/HIGH] - -### Cross-ADR Conflicts -[List all conflicts from Phase 4] - -### ADR Dependency Order -[Topologically sorted implementation order from Phase 4 — dependency ordering section] -[Unresolved dependencies and cycles if any] - -### GDD Revision Flags -[GDD assumptions that conflict with verified engine behaviour — from Phase 5b] -[Or: "None — all GDD assumptions consistent with verified engine behaviour"] - -### Engine Compatibility Issues -[List all engine issues from Phase 5] - -### Architecture Document Coverage -[List missing systems and orphaned architecture from Phase 6] - ---- - -### Verdict: [PASS / NOT ASSESSED / CONCERNS / FAIL] - -PASS: All requirements covered by **Accepted** ADRs, no conflicts, engine consistent -NOT ASSESSED: The review could not be performed over its stated scope — name why -CONCERNS: Some gaps, partial coverage, or coverage resting on `Proposed` ADRs, - but no blocking conflicts -FAIL: Critical gaps (Foundation/Core layer requirements uncovered), - or blocking cross-ADR conflicts detected - -**`NOT ASSESSED` ranks above PASS and below CONCERNS and FAIL.** Emit it when: - -- **No ADRs exist, or none could be read.** Zero requirements traced is not full - coverage — it is an untraced architecture, and a matrix of `❌ Gap` rows at - least says so while an empty matrix says nothing. -- **The requirement source is missing** — no `tr-registry.yaml` and no GDD - requirements to trace *from*. A review with no left-hand column cannot report - coverage; it can only report that it had nothing to compare. -- **An ADR is unreadable or has no `## Status`**, so its rows are `❓` and their - coverage is unknown rather than absent. -- **Phase 6 could not run** — no `docs/architecture/architecture.md`. It must - appear as a named `NOT ASSESSED` **line item** in the report rather than as - absent findings. ADR traceability can still be complete, so a CONCERNS or FAIL - finding elsewhere still stands; but in `full` mode, whose scope includes - Phase 6, the verdict cannot be PASS — a review that could not look at part of - its scope has not shown that part is sound, so it is NOT ASSESSED. -- **No engine is configured** (`full` and `engine` modes) — Phase 5 has no pinned - engine reference to audit the ADRs against, and the specialist consultation was - skipped. Record the `Engine validation: NOT ASSESSED` line item; like Phase 6 - above, it keeps the verdict from PASS. - -Do not resolve any of these to PASS on the grounds that no gap was *found*. No -gap was looked for. - -### Blocking Issues (must resolve before PASS) -[List items that must be resolved — FAIL verdict only] - -### Required ADRs -[Prioritised list of ADRs to create, most foundational first] -``` - ---- +**Read `references/7-report.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 8: Write and Update Traceability Index -Use `AskUserQuestion` for the write approval: -- "Review complete. What would you like to write?" - - [A] Write all three files — review report (`docs/architecture/architecture-review-[date].md`), traceability index (`docs/architecture/requirements-traceability.md`), TR registry (`docs/architecture/tr-registry.yaml`) - - [B] Write review report only — `docs/architecture/architecture-review-[date].md` - - [C] Don't write anything yet — I need to review the findings first - -When Phase 4 found a 🔴 conflict and `docs/consistency-failures.md` exists, name -that file in option [A] as well — "…and append [N] conflict entr(y/ies) to -`docs/consistency-failures.md`". Only [A] appends there (see Reflexion Log -Update); [B] writes the report and nothing else. - -### RTM Output (rtm mode only) - -For `rtm` mode, use `AskUserQuestion`: -- "May I write the full Requirements Traceability Matrix?" - - [A] Yes — write to `docs/architecture/requirements-traceability.md` - - [B] Not yet — show me the full RTM data first, then ask again - -RTM file format: - -```markdown -# Requirements Traceability Matrix (RTM) - -> Last Updated: [date] -> Mode: /architecture-review rtm -> Coverage: [N]% full chain complete (GDD → ADR → Story → Test) - -## How to read this matrix - -| Column | Meaning | -|--------|---------| -| TR-ID | Stable requirement ID from tr-registry.yaml | -| GDD | Source design document | -| ADR | Architectural decision governing implementation | -| Story | Story file that implements this requirement | -| Test File | Automated test file path | -| Test Status | COVERED / MISSING / NONE / NO STORY | - -## Full Traceability Matrix - -| TR-ID | GDD | Requirement | ADR | Story | Test File | Status | -|-------|-----|-------------|-----|-------|-----------|--------| -[Full matrix rows from Phase 3b] - -## Coverage Summary - -| Status | Count | % | -|--------|-------|---| -| COVERED — full chain complete | [N] | [%] | -| MISSING test — story exists, no test | [N] | [%] | -| NO STORY — ADR exists, not yet implemented | [N] | [%] | -| NO ADR — architectural gap | [N] | [%] | -| **Total requirements** | **[N]** | **100%** | - -## Uncovered Requirements (Priority Fix List) - -Requirements where the full chain is broken, prioritised by layer: - -### Foundation layer gaps -[list with suggested action per gap] - -### Core layer gaps -[list] - -### Feature / Presentation layer gaps -[list — lower priority] - -## History - -| Date | Full Chain % | Notes | -|------|-------------|-------| -| [date] | [%] | Initial RTM | -``` - -### TR Registry Update - -Also ask: "May I update `docs/architecture/tr-registry.yaml` with new requirement -IDs from this review?" - -If yes: -- **Append** any new TR-IDs that weren't in the registry before this review -- **Update** `requirement` text and `revised` date for any entries whose GDD - wording changed (ID stays the same) -- **Mark** `status: deprecated` for any registry entries whose GDD requirement - no longer exists (confirm with user before marking deprecated) -- **Never** renumber or delete existing entries -- Update the `last_updated` and `version` fields at the top - -This ensures all future story files can reference stable TR-IDs that persist -across every subsequent architecture review. - -### Reflexion Log Update - -When the user chose Phase 8's [A] — the option that named this file — append -any 🔴 CONFLICT entries found in Phase 4 to `docs/consistency-failures.md` (if -the file exists), after writing the review report: - -```markdown -### [YYYY-MM-DD] — /architecture-review — 🔴 CONFLICT -**Domain**: Architecture / [specific domain e.g. State Ownership, Performance] -**Documents involved**: [ADR-NNNN] vs [ADR-MMMM] -**What happened**: [specific conflict — what each ADR claims] -**Resolution**: [how it was or should be resolved] -**Pattern**: [generalised lesson for future ADR authors in this domain] -``` - -Only append CONFLICT entries — do not log GAP entries (missing ADRs are expected -before the architecture is complete). Do not create the file if missing — only -append when it already exists. - -### Session State Update - -After writing all approved files, silently append to -`production/session-state/active.md`: - - ## Session Extract — /architecture-review [date] - - Verdict: [PASS / NOT ASSESSED / CONCERNS / FAIL] - - Requirements: [N] total — [X] covered, [Y] partial, [Z] gaps - - New TR-IDs registered: [N, or "None"] - - GDD revision flags: [comma-separated GDD names, or "None"] - - Top ADR gaps: [top 3 gap titles from the report, or "None"] - - Report: docs/architecture/architecture-review-[date].md - -If `active.md` does not exist, create it with this block as the initial content. -Confirm in conversation: "Session state updated." - -The traceability index — written to `docs/architecture/requirements-traceability.md`, -the path `/propagate-design-change` and the Pre-Production gate read; `rtm` mode -later extends the same file with story and test columns — uses this format: - -```markdown -# Architecture Traceability Index -Last Updated: [date] -Engine: [name + version] - -## Coverage Summary -- Total requirements: [N] -- Covered: [X] ([%]) -- Partial: [Y] -- Gaps: [Z] - -## Full Matrix -[Complete traceability matrix from Phase 3] - -## Known Gaps -[All ❌ items with suggested ADRs] - -## Superseded Requirements -[Requirements whose GDD was changed after the ADR was written] -``` - ---- +**Read `references/8-write.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 9: Handoff -After completing the review and writing approved files, present: - -1. **Immediate actions**: List the top 3 ADRs to create (highest-impact gaps first, - Foundation layer before Feature layer) -2. **Pre-gate checklist**: Check whether these exist via Glob and mark each ✅ or ❌: - - the engine's test root — `tests/unit/` and `tests/integration/` (Godot), `Assets/Tests/EditMode/` and `Assets/Tests/PlayMode/` (Unity), `Source//Private/Tests/` (Unreal) — if ❌: run `/test-setup` - - `.github/workflows/tests.yml` — if ❌: run `/test-setup` - - `design/accessibility-requirements.md` — if ❌: run `/ux-design` - - `design/ux/interaction-patterns.md` — if ❌: run `/ux-design` - Present ❌ items as required steps before gate-check. Do not offer `/gate-check` - as an option if any item is ❌ — offer the missing skill to run instead. -3. **Rerun trigger**: "Re-run `/architecture-review` after each new ADR is written - to verify coverage improves" - -Then close with `AskUserQuestion` tailored to the pre-gate checklist state: -- If ADR gaps remain or any pre-gate item is ❌: - - "Architecture review complete. What would you like to do next?" - - [A] Write a missing ADR — open a fresh session and run `/architecture-decision [system]` - - [B] Run `/test-setup` — required before gate-check (only show if test infrastructure is ❌) - - [C] Run `/ux-design` — required before gate-check (only show if UX/accessibility files are ❌) - - [D] Stop here for this session -- If all pre-gate checklist items are ✅ and no blocking ADR gaps remain: - - "Architecture review complete. All pre-gate items confirmed. What would you like to do next?" - - [A] Run `/gate-check pre-production` - - [B] Write a missing ADR — open a fresh session and run `/architecture-decision [system]` - - [C] Stop here for this session - ---- +**Read `references/9-handoff.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Error Recovery Protocol diff --git a/.claude/skills/architecture-review/references/1-load.md b/.claude/skills/architecture-review/references/1-load.md new file mode 100644 index 00000000..26abe796 --- /dev/null +++ b/.claude/skills/architecture-review/references/1-load.md @@ -0,0 +1,150 @@ +# /architecture-review — Phase 1: Load Everything + +> Part of `/architecture-review`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 1: Load Everything + +**In this file:** + +- Phase 1a — L0: Summary Scan (fast, low tokens) +- Phase 1b — L1/L2: Targeted Section Load +- Design Documents +- Architecture Documents +- Engine Reference +- Project Standards + +### Phase 1a — L0: Summary Scan (fast, low tokens) + +**Freshness check before any scan.** Locate the latest prior report — Glob +`docs/architecture/architecture-review-*.md` and take the newest — then: + +``` +Bash: bash .claude/scripts/review-receipts.sh check "[latest-report]" docs/architecture/adr-*.md design/gdd/*.md +``` + +- **Any `UNRESOLVED`** — check this FIRST; it disqualifies every option + below. One of the two globs matched no file, so that whole document class + was never examined and the comparison covered less than it appears to. + Say which pattern came back unresolved and stop: an ADR or GDD directory + that is empty, renamed or misspelled is a finding about the project, not a + reason to stand on a prior report. Never read a set of `UNCHANGED` lines as + "everything is current" while an `UNRESOLVED` line is present — the set + compared was not the set requested. +- **Everything `UNCHANGED`** (and no `UNRESOLVED`) — nothing this review + reads has changed since that report; re-running reproduces it. Surface the + prior report's date and verdict and offer via `AskUserQuestion`: `[A] Stand + on the prior report (Recommended)` / `[B] Re-run the full review anyway` — + `guided` proceeds with [A] and notes it; `autonomous` logs via + `log_decision` and stands on the prior report. +- **Some `CHANGED`/`NEW`** — name them, then scope instead of re-running + everything: recommend `/architecture-review [system]` (single-system mode) + for just the changed systems. A full re-run stays available on request, + and structural changes (a `NEW` ADR, a deleted file) warrant one. +- **`RECEIPT: NONE`** — no prior report, or one written before receipts + existed. Proceed with the full review; this run's report will carry the + first stamps. + +Before reading any full document, use Grep to extract `## Summary` sections +from all GDDs and ADRs: + +``` +Grep pattern="## Summary" glob="design/gdd/*.md" output_mode="content" -A 4 +Grep pattern="## Summary" glob="docs/architecture/adr-*.md" output_mode="content" -A 3 +``` + +**Fail open on a missing Summary.** Establish the denominator: glob +`design/gdd/*.md` and count **N**. A scan matching fewer than N means those GDDs +predate `## Summary` (`/design-system` emits it, but older GDDs lack it) — never +treat an absent Summary as a system out of scope. A zero-match scan means "no GDD +carries a Summary yet", not "nothing to review": full-read the unmatched set. + +For `single-gdd [path]` mode: use the target GDD's summary to identify which +ADRs reference the same system (Grep ADRs for the system name), then load only +those ADRs' sections per Phase 1b. Skip unrelated GDDs entirely. + +For `engine` mode: load ADR sections only — GDDs are not needed for engine checks. +In practice this is the `## Engine Compatibility` scan alone. + +For `coverage` or `full` mode: proceed to Phase 1b for the full in-scope set. +**This is a section load, not a full-file load** — see below for why, and for the +narrow cases that still justify escalating to a whole document. + +### Phase 1b — L1/L2: Targeted Section Load + +Load the sections the later phases actually consume — **not whole files**. This +skill reads the two largest document sets in the project (every GDD *and* every +ADR); at realistic sizes a full load of both exhausts the context window before +Phase 2 starts, and most of what it loads is narrative this skill never uses. + +**Establish the denominator first.** Glob `design/gdd/*.md` and count **N_gdd**; +glob `docs/architecture/adr-*.md` and count **N_adr**. Report both. A section +scan matching fewer than the denominator means those documents lack the section — +**never treat an absent section as an absent document.** The scan narrows the +*read* set; it never shrinks the *in-scope* set. + +### Design Documents + +Phase 2 extracts *technical requirements* — data structures, performance +constraints, engine capabilities, cross-system communication, persistence, +threading, platform needs. Those live in a known set of sections; Overview and +Player Fantasy are narrative and yield none. + +``` +Grep pattern="^## (Detailed Rules|Detailed Design|Formulas|Dependencies|Tuning Knobs|Acceptance Criteria)" glob="design/gdd/*.md" output_mode="content" -A 40 +``` + +Accept **either** `## Detailed Rules` or `## Detailed Design` — the design +standard and the GDD template disagree on the name and they denote the same +required section. Full-read a single GDD only when a scanned section +cross-references material outside itself, or when a GDD matched zero sections +(it predates the template — read it whole and say so). + +- `design/gdd/systems-index.md` — the authoritative list of systems; read whole (small, and it is an index) + +### Architecture Documents + +Phases 3–5 need the traceability table, the decision itself, engine claims, and +the dependency edges — not Context, Consequences, Alternatives, Migration Plan or +Validation Criteria, which explain *why* a decision was made. + +``` +Grep pattern="^## (Status|Decision|GDD Requirements Addressed|Engine Compatibility|ADR Dependencies|Performance Implications)" glob="docs/architecture/adr-*.md" output_mode="content" -A 30 +``` + +Interpret against **N_adr**, and distinguish the two zero-match cases — they are +not the same finding: + +| Result | Meaning | Action | +|---|---|---| +| N_adr matches | Normal. | Proceed on the scanned sections. | +| Some ADRs match, some do not | Those ADRs are missing sections. | Record each as a **structural gap** in the Phase 7 report — a missing `## GDD Requirements Addressed` is itself a traceability finding. | +| **0 matches, N_adr > 0** | **Malformed ADRs**, not "no architecture". | "[N_adr] ADRs found, none carries a scannable section — run `/architecture-decision retrofit [file]` on each." Do **not** report zero coverage; that would read as a design failure when it is a format failure. | + +Escalate to a full read of one ADR only when judging a conflict needs its +reasoning (Phase 4) — that is a per-ADR decision, not a blanket load. + +- `docs/architecture/architecture.md` if it exists + +### Engine Reference +- `docs/engine-reference/[engine]/VERSION.md` +- `docs/engine-reference/[engine]/breaking-changes.md` +- `docs/engine-reference/[engine]/deprecated-apis.md` +- **Only the module docs the in-scope ADRs actually name** — take the union of + each ADR's `References Consulted` and `Post-Cutoff APIs Used` fields (already + captured by the `## Engine Compatibility` scan above) and read those files. + Reading the whole `modules/` directory loads engine subsystems the project may + not use at all. If no ADR names any module, read none and note it: Phase 5 + cannot cross-check engine claims that were never made. + +### Project Standards +- `project.yaml` — `naming.*` and `performance.*`; plus `.claude/docs/technical-preferences.md` for those keys when absent and for forbidden patterns / allowed libraries + +Report a count: "Loaded [N] GDDs, [M] ADRs, engine: [name + version]." + +**Also read `docs/consistency-failures.md`** if it exists. Extract entries with +Domain matching the systems under review (Architecture, Engine, or any GDD domain +being covered). Surface recurring patterns as a "Known conflict-prone areas" note +at the top of the Phase 4 conflict detection output. + +--- diff --git a/.claude/skills/architecture-review/references/2-extract-requirements.md b/.claude/skills/architecture-review/references/2-extract-requirements.md new file mode 100644 index 00000000..cb929aca --- /dev/null +++ b/.claude/skills/architecture-review/references/2-extract-requirements.md @@ -0,0 +1,58 @@ +# /architecture-review — Phase 2: Extract Technical Requirements + +> Part of `/architecture-review`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 2: Extract Technical Requirements from Every GDD + +### Pre-load the TR Registry + +Before extracting any requirements, read `docs/architecture/tr-registry.yaml` +if it exists. Index existing entries by `id` and by normalized `requirement` +text (lowercase, trimmed). This prevents ID renumbering across review runs. + +For each requirement you extract, the matching rule is: +1. **Exact/near match** to an existing registry entry for the same system → + reuse that entry's TR-ID unchanged. Update the `requirement` text in the + registry only if the GDD wording changed (same intent, clearer phrasing) — + add a `revised: [date]` field. +2. **No match** → assign a new ID: next available `TR-[system]-NNN` for that + system, starting from the highest existing sequence + 1. +3. **Ambiguous** (partial match, intent unclear) → ask the user: + > "Does '[new requirement text]' refer to the same requirement as + > `TR-[system]-NNN: [existing text]'`, or is it a new requirement?" + User answers: "Same requirement" (reuse ID) or "New requirement" (new ID). + +For any requirement with `status: deprecated` in the registry — skip it. +It was removed from the GDD intentionally. + +For each GDD, read it and extract all **technical requirements** — things the +architecture must provide for the system to work. A technical requirement is any +statement that implies a specific architectural decision. + +Categories to extract: + +| Category | Example | +|----------|---------| +| **Data structures** | "Each entity has health, max health, status effects" → needs a component/data schema | +| **Performance constraints** | "Collision detection must run at 60fps with 200 entities" → physics budget ADR | +| **Engine capability** | "Inverse kinematics for character animation" → IK system ADR | +| **Cross-system communication** | "Damage system notifies UI and audio simultaneously" → event/signal architecture ADR | +| **State persistence** | "Player progress persists between sessions" → save system ADR | +| **Threading/timing** | "AI decisions happen off the main thread" → concurrency ADR | +| **Platform requirements** | "Supports keyboard, gamepad, touch" → input system ADR | + +For each GDD, produce a structured list: + +``` +GDD: [filename] +System: [system name] +Technical Requirements: + TR-[GDD]-001: [requirement text] → Domain: [Physics/Rendering/etc] + TR-[GDD]-002: [requirement text] → Domain: [...] +``` + +This becomes the **requirements baseline** — the complete set of what the +architecture must cover. + +--- diff --git a/.claude/skills/architecture-review/references/3-traceability.md b/.claude/skills/architecture-review/references/3-traceability.md new file mode 100644 index 00000000..bb7b6b65 --- /dev/null +++ b/.claude/skills/architecture-review/references/3-traceability.md @@ -0,0 +1,129 @@ +# /architecture-review — Phases 3 and 3b: Traceability Matrix and Story Linkage + +> Part of `/architecture-review`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 3: Build the Traceability Matrix + +**In this file:** + +- Step 3b-1 — Load stories +- Step 3b-2 — Load test files +- Step 3b-3 — Build the extended RTM + +For each technical requirement extracted in Phase 2, search the ADRs: + +1. Use the ADRs **already loaded in Phase 1b** — do not re-read them. Extract each + ADR's "GDD Requirements Addressed" section from what is already in context. + (If Phase 1b ran in a mode that did not load every ADR, `Grep pattern="## GDD + Requirements Addressed" glob="docs/architecture/adr-*.md" output_mode="content" + -A 15` fills the gap without a full re-read.) +2. Check if it explicitly references the requirement or its GDD +3. Check if the ADR's decision text implicitly covers the requirement +4. Mark coverage status: + +| Status | Meaning | +|--------|---------| +| ✅ **Covered** | An **Accepted** ADR explicitly addresses this requirement | +| 🟡 **Covered (Proposed)** | An ADR addresses it, but that ADR is still `Proposed` | +| ⚠️ **Partial** | An ADR partially covers this, or coverage is ambiguous | +| ❌ **Gap** | No ADR addresses this requirement | +| ❓ **Not assessed** | The ADR is unreadable, or has no `## Status` section | + +> **Read each ADR's `## Status` before marking coverage — an unaccepted decision +> is not coverage.** If `✅` meant only that *an ADR addresses this*, with no +> status qualification, a requirement covered entirely by `Proposed` ADRs would +> count as covered and this review could return **PASS: All requirements +> covered** over an architecture nobody had accepted. Four skills downstream +> (`create-control-manifest`, `create-epics`, `create-stories`, `gate-check`) +> require `Accepted`, so a PASS on that basis sends work forward that every one +> of them will refuse. +> +> `🟡` is **not** a pass state: it caps the verdict at **CONCERNS**, and names the +> route out — `/architecture-decision accept ADR-NNNN`. That route is the only +> thing that moves an ADR to `Accepted`; without it, grading `Proposed` as +> covered would be the only option, which is why it must never be graded so. + +Build the full matrix: + +``` +## Traceability Matrix + +| Requirement ID | GDD | System | Requirement | ADR Coverage | Status | +|---------------|-----|--------|-------------|--------------|--------| +| TR-combat-001 | combat.md | Combat | Hitbox detection < 1 frame | ADR-0003 | ✅ | +| TR-combat-002 | combat.md | Combat | Combo window timing | — | ❌ GAP | +| TR-inventory-001 | inventory.md | Inventory | Persistent item storage | ADR-0005 | ✅ | +``` + +Count the totals: X covered, Y partial, Z gaps. + +--- + +## Phase 3b: Story and Test Linkage (RTM mode only) + +*Skip this phase unless the argument is `rtm` or `full` with stories present.* + +This phase extends the Phase 3 matrix to include the story that implements +each requirement and the test that verifies it — producing the full +Requirements Traceability Matrix (RTM). + +### Step 3b-1 — Load stories + +Glob `production/epics/**/*.md` (excluding EPIC.md index files) to establish the +denominator. Then collect the fields with **targeted section greps, not a full +read of each story** — the same two-grep form `/test-evidence-review` uses for +this identical extraction: + +``` +Grep pattern="## Test Evidence" glob="production/epics/**/story-*.md" output_mode="content" -A 8 +Grep pattern="TR-" glob="production/epics/**/story-*.md" output_mode="content" +``` + +- **TR-ID** — from the second grep. +- **Test file path** — under `## Test Evidence`, captured by the first grep's `-A 8`. +- **Status** — from the story header; add `Grep pattern="^> \*\*Status\*\*"` if not already captured. +- **Story path and title** — from the file name and path; no read at all. + +Full-read a story only when its Test Evidence section is missing or ambiguous. + +### Step 3b-2 — Load test files + +Glob the engine's test root (`.claude/docs/directory-structure.md`): Godot +`tests/unit/**/*_test.*` and `tests/integration/**/*_test.*`; Unity +`Assets/Tests/**/*Tests.cs`; Unreal `Source/*/Private/Tests/**/*.cpp`. With no +engine configured, say the test index could not be built rather than reading an +empty glob as "no tests". Build an index: system → [test file paths]. + +For each test file path from Step 3b-1, confirm via Glob whether the file +actually exists. Note MISSING if the stated path does not exist. + +### Step 3b-3 — Build the extended RTM + +For each TR-ID in the Phase 3 matrix, add: +- **Story**: the story file path(s) that reference this TR-ID (may be multiple) +- **Test File**: the test file path stated in the story's Test Evidence section +- **Test Status**: COVERED (test file exists) / MISSING (path stated but not + found) / NONE (no test path stated, story type may be Visual/Feel/UI) / + NO STORY (requirement has no story yet — pre-production gap) + +Extended matrix format: + +``` +## Requirements Traceability Matrix (RTM) + +| TR-ID | GDD | Requirement | ADR | Story | Test File | Test Status | +|-------|-----|-------------|-----|-------|-----------|-------------| +| TR-combat-001 | combat.md | Hitbox < 1 frame | ADR-0003 | story-001-hitbox.md | tests/unit/combat/hitbox_test.gd | COVERED | +| TR-combat-002 | combat.md | Combo window | — | story-002-combo.md | — | NONE (Visual/Feel) | +| TR-inventory-001 | inventory.md | Persistent storage | ADR-0005 | — | — | NO STORY | +``` + +RTM coverage summary: +- COVERED: [N] — requirements with ADR + story + passing test +- MISSING test: [N] — story exists but test file not found +- NO STORY: [N] — requirements with ADR but no story yet +- NO ADR: [N] — requirements without architectural coverage (from Phase 3 gaps) +- Full chain complete (COVERED): [N/total] ([%]) + +--- diff --git a/.claude/skills/architecture-review/references/4-conflicts.md b/.claude/skills/architecture-review/references/4-conflicts.md new file mode 100644 index 00000000..11e356f4 --- /dev/null +++ b/.claude/skills/architecture-review/references/4-conflicts.md @@ -0,0 +1,85 @@ +# /architecture-review — Phase 4: Cross-ADR Conflict Detection + +> Part of `/architecture-review`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 4: Cross-ADR Conflict Detection + +Compare every ADR against every other ADR to detect contradictions. A conflict +exists when: + +- **Data ownership conflict**: Two ADRs claim exclusive ownership of the same data +- **Integration contract conflict**: ADR-A assumes System X has interface Y, but + ADR-B defines System X with a different interface +- **Performance budget conflict**: ADR-A allocates N ms to physics, ADR-B allocates + N ms to AI, together they exceed the total frame budget +- **Dependency cycle**: ADR-A says System X initialises before Y; ADR-B says Y + initialises before X +- **Architecture pattern conflict**: ADR-A uses event-driven communication for a + subsystem; ADR-B uses direct function calls to the same subsystem +- **State management conflict**: Two ADRs define authority over the same game state + (e.g. both Combat ADR and Character ADR claim to own the health value) + +For each conflict found: + +``` +## Conflict: [ADR-NNNN] vs [ADR-MMMM] +Type: [Data ownership / Integration / Performance / Dependency / Pattern / State] +ADR-NNNN claims: [...] +ADR-MMMM claims: [...] +Impact: [What breaks if both are implemented as written] +Resolution options: + 1. [Option A] + 2. [Option B] +``` + +### ADR Dependency Ordering + +After conflict detection, analyse the dependency graph across all ADRs. + +**Build the graph deterministically — do not trace it by hand:** + +``` +Bash: bash .claude/scripts/adr-dep-graph.sh +``` + +It collects every `Depends On` edge, runs Kahn's algorithm, and emits +`ADRS:` / `EDGES:` / `NO_DEPS_SECTION:` / `CYCLE:`. A model tracing A→B→C→A across +a dozen ADRs eventually misses an edge; the algorithm cannot. It reports +observations, not a verdict — you apply the meaning below. + +**`NO_DEPS_SECTION` is load-bearing**: it makes "no cycles because the graph is +clean" distinguishable from "no cycles because half the ADRs declare no +dependencies". Report the second case as a structural gap, never as a clean graph. + +Then interpret: + +1. **Topological sort**: the emitted order — ADRs with no + dependencies come first (Foundation), ADRs that depend on those come next, etc. +2. **Flag unresolved dependencies**: cross the `EDGES:` list against the `## Status` + values already scanned in Phase 1b. If ADR-A depends on an ADR that is still + `Proposed` or does not exist, flag it: + ``` + ⚠️ ADR-0005 depends on ADR-0002 — but ADR-0002 is still Proposed. + ADR-0005 cannot be safely implemented until ADR-0002 is Accepted. + ``` +3. **Cycle detection**: every `CYCLE:` line the script emitted is a + `DEPENDENCY CYCLE` — report each one. Do not re-derive them by hand: + ``` + 🔴 DEPENDENCY CYCLE: ADR-0003 → ADR-0006 → ADR-0003 + This cycle must be broken before either can be implemented. + ``` +4. **Output recommended implementation order**: + ``` + ### Recommended ADR Implementation Order (topologically sorted) + Foundation (no dependencies): + 1. ADR-0001: [title] + 2. ADR-0003: [title] + Depends on Foundation: + 3. ADR-0002: [title] (requires ADR-0001) + 4. ADR-0005: [title] (requires ADR-0003) + Feature layer: + 5. ADR-0004: [title] (requires ADR-0002, ADR-0005) + ``` + +--- diff --git a/.claude/skills/architecture-review/references/5-engine.md b/.claude/skills/architecture-review/references/5-engine.md new file mode 100644 index 00000000..318ecbc1 --- /dev/null +++ b/.claude/skills/architecture-review/references/5-engine.md @@ -0,0 +1,113 @@ +# /architecture-review — Phases 5 and 5b: Engine Cross-Check and Design Revision Flags + +> Part of `/architecture-review`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 5: Engine Compatibility Cross-Check + +**In this file:** + +- Version Consistency +- Post-Cutoff API Consistency +- Deprecated API Check +- Missing Engine Compatibility Sections +- Engine Specialist Consultation + +Across all ADRs, check for engine consistency: + +### Version Consistency +- Do all ADRs that mention an engine version agree on the same version? +- If any ADR was written for an older engine version, flag it as potentially stale + +### Post-Cutoff API Consistency +- Collect all "Post-Cutoff APIs Used" fields from all ADRs +- For each, verify against the relevant module reference doc +- Check that no two ADRs make contradictory assumptions about the same post-cutoff API + +### Deprecated API Check +- Grep all ADRs for API names listed in `deprecated-apis.md` +- Flag any ADR referencing a deprecated API + +### Missing Engine Compatibility Sections +- List all ADRs that are missing the Engine Compatibility section entirely +- These are blind spots — their engine assumptions are unknown + +Output format: +``` +### Engine Audit Results +Engine: [name + version] +ADRs with Engine Compatibility section: X / Y total + +Deprecated API References: + - ADR-0002: uses [deprecated API] — deprecated since [version] + +Stale Version References: + - ADR-0001: written for [older version] — current project version is [version] + +Post-Cutoff API Conflicts: + - ADR-0004 and ADR-0007 both use [API] with incompatible assumptions +``` + +--- + +### Engine Specialist Consultation + +After completing the engine audit above, spawn the **primary engine specialist** via `Agent` for a domain-expert second opinion: +- Resolve the primary specialist: `-specialist` derived from `engine.name` in `project.yaml` (Godot→`godot-specialist`, Unity→`unity-specialist`, Unreal→`unreal-specialist`); if `engine.name` is absent or empty, read the Primary line of the `## Engine Specialists` section in `.claude/docs/technical-preferences.md` +- If no engine is configured (neither source yields an engine), skip this consultation **Record ``Engine validation: NOT ASSESSED — no engine configured (`engine.name` unset in `project.yaml`)`` in this run's output.** A skipped check that says nothing is indistinguishable from a check that passed; the reader cannot tell engine guidance was never sought. +- Spawn `subagent_type: [primary specialist]` with: all ADRs that contain engine-specific decisions or `Post-Cutoff APIs Used` fields, the engine reference docs, and the Phase 5 audit findings. Ask them to: + 1. Confirm or challenge each audit finding — specialists may know of engine nuances not captured in the reference docs + 2. Identify engine-specific anti-patterns in the ADRs that the audit may have missed (e.g., using the wrong Godot node type, Unity component coupling, Unreal subsystem misuse) + 3. Flag ADRs that make assumptions about engine behaviour that differ from the actual pinned version + +Incorporate additional findings under `### Engine Specialist Findings` in the Phase 5 output. These feed into the final verdict — specialist-identified issues carry the same weight as audit-identified issues. + +--- + +## Phase 5b: Design Revision Flags (Architecture → GDD Feedback) + +For each **HIGH RISK engine finding** from Phase 5, check whether any GDD makes an +assumption that the verified engine reality contradicts. + +Specific cases to check: + +1. **Post-cutoff API behaviour differs from training-data assumptions**: If an ADR + records a verified API behaviour that differs from the default LLM assumption, + check all GDDs that reference the related system. Look for design rules written + around the old (assumed) behaviour. + +2. **Known engine limitations in ADRs**: If an ADR records a known engine limitation + (e.g. "Jolt ignores HingeJoint3D damp", "D3D12 is now the default backend"), check + GDDs that design mechanics around the affected feature. + +3. **Deprecated API conflicts**: If Phase 5 flagged a deprecated API used in an ADR, + check whether any GDD contains mechanics that assume the deprecated API's behaviour. + +For each conflict found, record it in the GDD Revision Flags table: + +``` +### GDD Revision Flags (Architecture → Design Feedback) +These GDD assumptions conflict with verified engine behaviour or accepted ADRs. +The GDD should be revised before its system enters implementation. + +| GDD | Assumption | Reality (from ADR/engine-reference) | Action | +|-----|-----------|--------------------------------------|--------| +| combat.md | "Use HingeJoint3D damp for weapon recoil" | Jolt ignores damp — ADR-0003 | Revise GDD | +``` + +If no revision flags are found, write: "No GDD revision flags — all GDD assumptions +are consistent with verified engine behaviour." + +Before asking, display the proposed change inline — show the current systems-index row for each flagged GDD and the proposed updated row side by side so the user can see exactly what will change. + +Then use `AskUserQuestion`: +- "I found [N] GDD revision flag(s). May I update the systems index?" + - [A] Yes — apply all [N] updates to the systems index now + - [B] Show me the full diff first, then ask again + - [C] No — leave the systems index unchanged for now + +If [A]: apply the updates. Status field must be exactly `Needs Revision` — no parentheticals +(other skills match that exact string and parentheticals break the match). +If [B]: display the complete proposed systems-index section, then re-ask with `AskUserQuestion`. + +--- diff --git a/.claude/skills/architecture-review/references/6-document-coverage.md b/.claude/skills/architecture-review/references/6-document-coverage.md new file mode 100644 index 00000000..a3e25a35 --- /dev/null +++ b/.claude/skills/architecture-review/references/6-document-coverage.md @@ -0,0 +1,25 @@ +# /architecture-review — Phase 6: Architecture Document Coverage + +> Part of `/architecture-review`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 6: Architecture Document Coverage + +**If `docs/architecture/architecture.md` does not exist, say so in the report** — +`Architecture document coverage: NOT ASSESSED — no docs/architecture/architecture.md` +— and carry it into the Phase 7 verdict per the trigger list below. Phase 5 +already models this for the engine consultation (*"A skipped check that says +nothing is indistinguishable from a check that passed"*); this phase is the one +that did not. Silently producing no Phase 6 findings reads as an architecture +document that was checked and found clean, which is the opposite of what +happened. + +If it exists, validate it against GDDs: + +- Does every system from `systems-index.md` appear in the architecture layers? +- Does the data flow section cover all cross-system communication defined in GDDs? +- Do the API boundaries support all integration requirements from GDDs? +- Are there systems in the architecture doc that have no corresponding GDD + (orphaned architecture)? + +--- diff --git a/.claude/skills/architecture-review/references/7-report.md b/.claude/skills/architecture-review/references/7-report.md new file mode 100644 index 00000000..41fab541 --- /dev/null +++ b/.claude/skills/architecture-review/references/7-report.md @@ -0,0 +1,93 @@ +# /architecture-review — Phase 7: Output the Review Report + +> Part of `/architecture-review`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 7: Output the Review Report + +``` +## Architecture Review Report +Date: [date] +Engine: [name + version] +GDDs Reviewed: [N] +ADRs Reviewed: [M] + +[output of: Bash: bash .claude/scripts/review-receipts.sh hash docs/architecture/adr-*.md design/gdd/*.md + — one Reviewed-Content-Hash line per file reviewed; Phase 1a's freshness + check reads these on the next run to skip or scope an unchanged re-review] + +--- + +### Traceability Summary +Total requirements: [N] +✅ Covered: [X] +⚠️ Partial: [Y] +❌ Gaps: [Z] + +### Coverage Gaps (no ADR exists) +For each gap: + ❌ TR-[id]: [GDD] → [system] → [requirement] + Suggested ADR: "/architecture-decision [suggested title]" + Domain: [Physics/Rendering/etc] + Engine Risk: [LOW/MEDIUM/HIGH] + +### Cross-ADR Conflicts +[List all conflicts from Phase 4] + +### ADR Dependency Order +[Topologically sorted implementation order from Phase 4 — dependency ordering section] +[Unresolved dependencies and cycles if any] + +### GDD Revision Flags +[GDD assumptions that conflict with verified engine behaviour — from Phase 5b] +[Or: "None — all GDD assumptions consistent with verified engine behaviour"] + +### Engine Compatibility Issues +[List all engine issues from Phase 5] + +### Architecture Document Coverage +[List missing systems and orphaned architecture from Phase 6] + +--- + +### Verdict: [PASS / NOT ASSESSED / CONCERNS / FAIL] + +PASS: All requirements covered by **Accepted** ADRs, no conflicts, engine consistent +NOT ASSESSED: The review could not be performed over its stated scope — name why +CONCERNS: Some gaps, partial coverage, or coverage resting on `Proposed` ADRs, + but no blocking conflicts +FAIL: Critical gaps (Foundation/Core layer requirements uncovered), + or blocking cross-ADR conflicts detected + +**`NOT ASSESSED` ranks above PASS and below CONCERNS and FAIL.** Emit it when: + +- **No ADRs exist, or none could be read.** Zero requirements traced is not full + coverage — it is an untraced architecture, and a matrix of `❌ Gap` rows at + least says so while an empty matrix says nothing. +- **The requirement source is missing** — no `tr-registry.yaml` and no GDD + requirements to trace *from*. A review with no left-hand column cannot report + coverage; it can only report that it had nothing to compare. +- **An ADR is unreadable or has no `## Status`**, so its rows are `❓` and their + coverage is unknown rather than absent. +- **Phase 6 could not run** — no `docs/architecture/architecture.md`. It must + appear as a named `NOT ASSESSED` **line item** in the report rather than as + absent findings. ADR traceability can still be complete, so a CONCERNS or FAIL + finding elsewhere still stands; but in `full` mode, whose scope includes + Phase 6, the verdict cannot be PASS — a review that could not look at part of + its scope has not shown that part is sound, so it is NOT ASSESSED. +- **No engine is configured** (`full` and `engine` modes) — Phase 5 has no pinned + engine reference to audit the ADRs against, and the specialist consultation was + skipped. Record the `Engine validation: NOT ASSESSED` line item; like Phase 6 + above, it keeps the verdict from PASS. + +Do not resolve any of these to PASS on the grounds that no gap was *found*. No +gap was looked for. + +### Blocking Issues (must resolve before PASS) +[List items that must be resolved — FAIL verdict only] + +### Required ADRs +[Prioritised list of ADRs to create, most foundational first] +``` + +--- diff --git a/.claude/skills/architecture-review/references/8-write.md b/.claude/skills/architecture-review/references/8-write.md new file mode 100644 index 00000000..ee5c4bbf --- /dev/null +++ b/.claude/skills/architecture-review/references/8-write.md @@ -0,0 +1,172 @@ +# /architecture-review — Phase 8: Write and Update Traceability Index + +> Part of `/architecture-review`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 8: Write and Update Traceability Index + +**In this file:** + +- RTM Output (rtm mode only) +- TR Registry Update +- Reflexion Log Update +- Session State Update + +Use `AskUserQuestion` for the write approval: +- "Review complete. What would you like to write?" + - [A] Write all three files — review report (`docs/architecture/architecture-review-[date].md`), traceability index (`docs/architecture/requirements-traceability.md`), TR registry (`docs/architecture/tr-registry.yaml`) + - [B] Write review report only — `docs/architecture/architecture-review-[date].md` + - [C] Don't write anything yet — I need to review the findings first + +When Phase 4 found a 🔴 conflict and `docs/consistency-failures.md` exists, name +that file in option [A] as well — "…and append [N] conflict entr(y/ies) to +`docs/consistency-failures.md`". Only [A] appends there (see Reflexion Log +Update); [B] writes the report and nothing else. + +### RTM Output (rtm mode only) + +For `rtm` mode, use `AskUserQuestion`: +- "May I write the full Requirements Traceability Matrix?" + - [A] Yes — write to `docs/architecture/requirements-traceability.md` + - [B] Not yet — show me the full RTM data first, then ask again + +RTM file format: + +```markdown +# Requirements Traceability Matrix (RTM) + +> Last Updated: [date] +> Mode: /architecture-review rtm +> Coverage: [N]% full chain complete (GDD → ADR → Story → Test) + +## How to read this matrix + +| Column | Meaning | +|--------|---------| +| TR-ID | Stable requirement ID from tr-registry.yaml | +| GDD | Source design document | +| ADR | Architectural decision governing implementation | +| Story | Story file that implements this requirement | +| Test File | Automated test file path | +| Test Status | COVERED / MISSING / NONE / NO STORY | + +## Full Traceability Matrix + +| TR-ID | GDD | Requirement | ADR | Story | Test File | Status | +|-------|-----|-------------|-----|-------|-----------|--------| +[Full matrix rows from Phase 3b] + +## Coverage Summary + +| Status | Count | % | +|--------|-------|---| +| COVERED — full chain complete | [N] | [%] | +| MISSING test — story exists, no test | [N] | [%] | +| NO STORY — ADR exists, not yet implemented | [N] | [%] | +| NO ADR — architectural gap | [N] | [%] | +| **Total requirements** | **[N]** | **100%** | + +## Uncovered Requirements (Priority Fix List) + +Requirements where the full chain is broken, prioritised by layer: + +### Foundation layer gaps +[list with suggested action per gap] + +### Core layer gaps +[list] + +### Feature / Presentation layer gaps +[list — lower priority] + +## History + +| Date | Full Chain % | Notes | +|------|-------------|-------| +| [date] | [%] | Initial RTM | +``` + +### TR Registry Update + +Also ask: "May I update `docs/architecture/tr-registry.yaml` with new requirement +IDs from this review?" + +If yes, read the current `docs/architecture/tr-registry.yaml` again first: +the review read it at the start, and another skill or session may have changed +it since. Build the update from that fresh read, never from the earlier copy, +and keep every entry already in it. Then: +- **Append** any new TR-IDs that weren't in the registry before this review +- **Update** `requirement` text and `revised` date for any entries whose GDD + wording changed (ID stays the same) +- **Mark** `status: deprecated` for any registry entries whose GDD requirement + no longer exists (confirm with user before marking deprecated) +- **Mark** `status: "superseded-by: TR-[system]-NNN"` for an entry whose + requirement was split or replaced, naming the new TR-ID(s). Keep the quotes: + unquoted, the second colon makes the file invalid YAML +- **Never** renumber or delete existing entries +- Update the `last_updated` and `version` fields at the top + +This ensures all future story files can reference stable TR-IDs that persist +across every subsequent architecture review. + +### Reflexion Log Update + +When the user chose Phase 8's [A] — the option that named this file — append +any 🔴 CONFLICT entries found in Phase 4 to `docs/consistency-failures.md` (if +the file exists), after writing the review report: + +```markdown +### [YYYY-MM-DD] — /architecture-review — 🔴 CONFLICT +**Domain**: Architecture / [specific domain e.g. State Ownership, Performance] +**Documents involved**: [ADR-NNNN] vs [ADR-MMMM] +**What happened**: [specific conflict — what each ADR claims] +**Resolution**: [how it was or should be resolved] +**Pattern**: [generalised lesson for future ADR authors in this domain] +``` + +Only append CONFLICT entries — do not log GAP entries (missing ADRs are expected +before the architecture is complete). Do not create the file if missing — only +append when it already exists. + +### Session State Update + +After writing all approved files, silently append to +`production/session-state/active.md`: + + ## Session Extract — /architecture-review [date] + - Verdict: [PASS / NOT ASSESSED / CONCERNS / FAIL] + - Requirements: [N] total — [X] covered, [Y] partial, [Z] gaps + - New TR-IDs registered: [N, or "None"] + - GDD revision flags: [comma-separated GDD names, or "None"] + - Top ADR gaps: [top 3 gap titles from the report, or "None"] + - Report: docs/architecture/architecture-review-[date].md + +If `active.md` does not exist, create it with this block as the initial content. +Confirm in conversation: "Session state updated." + +The traceability index — written to `docs/architecture/requirements-traceability.md`, +the path `/propagate-design-change` and the Pre-Production gate read; `rtm` mode +later extends the same file with story and test columns — uses this format: + +```markdown +# Architecture Traceability Index +Last Updated: [date] +Engine: [name + version] + +## Coverage Summary +- Total requirements: [N] +- Covered: [X] ([%]) +- Partial: [Y] +- Gaps: [Z] + +## Full Matrix +[Complete traceability matrix from Phase 3] + +## Known Gaps +[All ❌ items with suggested ADRs] + +## Superseded Requirements +[Requirements whose GDD was changed after the ADR was written] +``` + +--- diff --git a/.claude/skills/architecture-review/references/9-handoff.md b/.claude/skills/architecture-review/references/9-handoff.md new file mode 100644 index 00000000..fd5f681f --- /dev/null +++ b/.claude/skills/architecture-review/references/9-handoff.md @@ -0,0 +1,35 @@ +# /architecture-review — Phase 9: Handoff + +> Part of `/architecture-review`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 9: Handoff + +After completing the review and writing approved files, present: + +1. **Immediate actions**: List the top 3 ADRs to create (highest-impact gaps first, + Foundation layer before Feature layer) +2. **Pre-gate checklist**: Check whether these exist via Glob and mark each ✅ or ❌: + - the engine's test root — `tests/unit/` and `tests/integration/` (Godot), `Assets/Tests/EditMode/` and `Assets/Tests/PlayMode/` (Unity), `Source//Private/Tests/` (Unreal) — if ❌: run `/test-setup` + - `.github/workflows/tests.yml` — if ❌: run `/test-setup` + - `design/accessibility-requirements.md` — if ❌: run `/ux-design` + - `design/ux/interaction-patterns.md` — if ❌: run `/ux-design` + Present ❌ items as required steps before gate-check. Do not offer `/gate-check` + as an option if any item is ❌ — offer the missing skill to run instead. +3. **Rerun trigger**: "Re-run `/architecture-review` after each new ADR is written + to verify coverage improves" + +Then close with `AskUserQuestion` tailored to the pre-gate checklist state: +- If ADR gaps remain or any pre-gate item is ❌: + - "Architecture review complete. What would you like to do next?" + - [A] Write a missing ADR — open a fresh session and run `/architecture-decision [system]` + - [B] Run `/test-setup` — required before gate-check (only show if test infrastructure is ❌) + - [C] Run `/ux-design` — required before gate-check (only show if UX/accessibility files are ❌) + - [D] Stop here for this session +- If all pre-gate checklist items are ✅ and no blocking ADR gaps remain: + - "Architecture review complete. All pre-gate items confirmed. What would you like to do next?" + - [A] Run `/gate-check pre-production` + - [B] Write a missing ADR — open a fresh session and run `/architecture-decision [system]` + - [C] Stop here for this session + +--- diff --git a/.claude/skills/art-bible/SKILL.md b/.claude/skills/art-bible/SKILL.md index 5cfad261..8776e8bb 100644 --- a/.claude/skills/art-bible/SKILL.md +++ b/.claude/skills/art-bible/SKILL.md @@ -12,6 +12,8 @@ model: sonnet Resolved above — use as-is; `--review` overrides `review_mode`. No block → defaults in `.claude/docs/config-resolution.md`. +# Art Bible + ## Phase 0: Parse Arguments and Context Check diff --git a/.claude/skills/asset-audit/SKILL.md b/.claude/skills/asset-audit/SKILL.md index 77152550..840ffc53 100644 --- a/.claude/skills/asset-audit/SKILL.md +++ b/.claude/skills/asset-audit/SKILL.md @@ -8,6 +8,8 @@ model: sonnet # Read-only diagnostic skill — no specialist agent delegation needed --- +# Asset Audit + ## Measuring file sizes and formats requires Bash This skill's report asks for **file sizes against budgets**, **texture dimensions** @@ -43,11 +45,10 @@ not a filled-in report.** Check first, and stop if the check fails. **A verdict of `NOT ASSESSED` is a success.** It is the correct, useful answer to "what does the data say?" when there is no data. The failure mode this prevents is -specific and has been observed in practice: report templates whose verdict -enum had no "could not run" state produced **false clean passes** — an asset audit -returning COMPLIANT on a project with no assets and no standards, and a -performance profile reporting ">99% headroom against a 16.67ms budget" with zero -profiler data and no budget ever set. +specific: a report whose verdict enum has no "could not run" state produces +**false clean passes** — an asset audit returning COMPLIANT on a project with no +assets and no standards, or a performance profile reporting ">99% headroom against +a 16.67ms budget" with zero profiler data and no budget ever set. **Absence of evidence is never evidence of absence.** A scan that finds no matches because there are no files to scan has not verified anything. Say which of diff --git a/.claude/skills/asset-spec/SKILL.md b/.claude/skills/asset-spec/SKILL.md index 0191fdcb..946dbabd 100644 --- a/.claude/skills/asset-spec/SKILL.md +++ b/.claude/skills/asset-spec/SKILL.md @@ -9,6 +9,8 @@ model: sonnet !`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys review_mode,automation` +# Asset Spec + If no argument is provided, check whether `design/assets/entity-inventory.md` exists: diff --git a/.claude/skills/balance-check/SKILL.md b/.claude/skills/balance-check/SKILL.md index c1736642..f15ea62a 100644 --- a/.claude/skills/balance-check/SKILL.md +++ b/.claude/skills/balance-check/SKILL.md @@ -9,6 +9,8 @@ model: sonnet !`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys automation` +# Balance Check + Every `AskUserQuestion` call follows `.claude/docs/automation-modes.md` @@ -33,11 +35,10 @@ not a filled-in report.** Check first, and stop if the check fails. **A verdict of `NOT ASSESSED` is a success.** It is the correct, useful answer to "what does the data say?" when there is no data. The failure mode this prevents is -specific and has been observed in practice: report templates whose verdict -enum had no "could not run" state produced **false clean passes** — an asset audit -returning COMPLIANT on a project with no assets and no standards, and a -performance profile reporting ">99% headroom against a 16.67ms budget" with zero -profiler data and no budget ever set. +specific: a report whose verdict enum has no "could not run" state produces +**false clean passes** — an asset audit returning COMPLIANT on a project with no +assets and no standards, or a performance profile reporting ">99% headroom against +a 16.67ms budget" with zero profiler data and no budget ever set. **Absence of evidence is never evidence of absence.** A scan that finds no matches because there are no files to scan has not verified anything. Say which of diff --git a/.claude/skills/brainstorm/SKILL.md b/.claude/skills/brainstorm/SKILL.md index a957eef1..90c3d197 100644 --- a/.claude/skills/brainstorm/SKILL.md +++ b/.claude/skills/brainstorm/SKILL.md @@ -12,6 +12,8 @@ model: sonnet Resolved above — use as-is. No block → defaults in `.claude/docs/config-resolution.md`. +# Brainstorm + `--review` overrides `review_mode`; store it for all gate spawns this run. See `.claude/docs/director-gates.md` for the full check pattern. Individual gate definitions live in `.claude/docs/director-gates/[gate-id].md` — the spawned agent reads its own gate file; do not read it in the parent session. diff --git a/.claude/skills/bug-report/SKILL.md b/.claude/skills/bug-report/SKILL.md index f9e5493f..2623ef36 100644 --- a/.claude/skills/bug-report/SKILL.md +++ b/.claude/skills/bug-report/SKILL.md @@ -15,6 +15,8 @@ every file write follows `.claude/docs/automation-modes.md` (collaborative asks always · guided major-only · autonomous logs and proceeds; `automation_always_ask` categories always prompt). +# Bug Report + ## Phase 1: Parse Arguments Determine the mode from the argument: diff --git a/.claude/skills/bug-triage/SKILL.md b/.claude/skills/bug-triage/SKILL.md index 7b01c4e9..b22c2d35 100644 --- a/.claude/skills/bug-triage/SKILL.md +++ b/.claude/skills/bug-triage/SKILL.md @@ -7,7 +7,7 @@ allowed-tools: Read, Glob, Grep, Write, Edit, Bash(bash "*/.claude/skills/bug-tr model: sonnet --- -!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys automation` +!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys automation,workflow` **Automation mode**: Resolve `modes.automation` (`project.local.yaml` → `project.yaml` → default `collaborative`). Every `AskUserQuestion` call and @@ -77,7 +77,7 @@ Read the most recently modified file in `production/sprints/` to understand: - Stories in scope (for assignment target) - Sprint capacity constraints (if noted) -If no sprint file exists: note "No sprint plan found — assigning to backlog only." +If no sprint file exists: note "No sprint plan found — assigning to backlog only." At `workflow: minimal` there are no sprints by design — say that instead, and name the P1 bugs as the next fixes, ahead of the next story in the brief's build order. ### Step 2c — Load severity reference diff --git a/.claude/skills/changelog/SKILL.md b/.claude/skills/changelog/SKILL.md index 78399ed6..202eeaee 100644 --- a/.claude/skills/changelog/SKILL.md +++ b/.claude/skills/changelog/SKILL.md @@ -15,6 +15,8 @@ every file write follows `.claude/docs/automation-modes.md` (collaborative asks always · guided major-only · autonomous logs and proceeds; `automation_always_ask` categories always prompt). +# Changelog + ## Recent History Recent commits: diff --git a/.claude/skills/code-review/SKILL.md b/.claude/skills/code-review/SKILL.md index 72a47570..6d224fc1 100644 --- a/.claude/skills/code-review/SKILL.md +++ b/.claude/skills/code-review/SKILL.md @@ -9,6 +9,8 @@ model: sonnet !`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys automation` +# Code Review + Every `AskUserQuestion` call follows `.claude/docs/automation-modes.md` @@ -33,11 +35,10 @@ not a filled-in report.** Check first, and stop if the check fails. **A verdict of `NOT ASSESSED` is a success.** It is the correct, useful answer to "what does the data say?" when there is no data. The failure mode this prevents is -specific and has been observed in practice: report templates whose verdict -enum had no "could not run" state produced **false clean passes** — an asset audit -returning COMPLIANT on a project with no assets and no standards, and a -performance profile reporting ">99% headroom against a 16.67ms budget" with zero -profiler data and no budget ever set. +specific: a report whose verdict enum has no "could not run" state produces +**false clean passes** — an asset audit returning COMPLIANT on a project with no +assets and no standards, or a performance profile reporting ">99% headroom against +a 16.67ms budget" with zero profiler data and no budget ever set. **Absence of evidence is never evidence of absence.** A scan that finds no matches because there are no files to scan has not verified anything. Say which of diff --git a/.claude/skills/consistency-check/SKILL.md b/.claude/skills/consistency-check/SKILL.md index 040dfe3b..e9ca39b6 100644 --- a/.claude/skills/consistency-check/SKILL.md +++ b/.claude/skills/consistency-check/SKILL.md @@ -271,6 +271,12 @@ Verdict: PASS | CONFLICTS FOUND | NOT ASSESSED ## Phase 6: Registry Corrections +**Re-read before you write.** Phase 1 read the registry before the scans, and +another skill or session may have changed it since. Before each Edit, read the +current `design/registry/entities.yaml`, find the entry in its section, and +anchor the Edit on the entry's current text, never on what Phase 1 saw. Append +a new entry after the last existing entry of its section. + If stale registry entries were found, ask: > "May I update `design/registry/entities.yaml` to fix the [N] stale entries?" diff --git a/.claude/skills/content-audit/SKILL.md b/.claude/skills/content-audit/SKILL.md index bcddcf90..93c4b476 100644 --- a/.claude/skills/content-audit/SKILL.md +++ b/.claude/skills/content-audit/SKILL.md @@ -17,6 +17,8 @@ every file write follows `.claude/docs/automation-modes.md` Resolved above — use as-is. No block → defaults in `.claude/docs/config-resolution.md`. +# Content Audit + > This skill declares tier-dependent behaviour ("audit only specs in the required > sections"), which is unreachable unless the tier is actually resolved — without > it the skill applies whatever tier it assumed. Resolve `modes.workflow` before @@ -59,11 +61,10 @@ not a filled-in report.** Check first, and stop if the check fails. **A verdict of `NOT ASSESSED` is a success.** It is the correct, useful answer to "what does the data say?" when there is no data. The failure mode this prevents is -specific and has been observed in practice: report templates whose verdict -enum had no "could not run" state produced **false clean passes** — an asset audit -returning COMPLIANT on a project with no assets and no standards, and a -performance profile reporting ">99% headroom against a 16.67ms budget" with zero -profiler data and no budget ever set. +specific: a report whose verdict enum has no "could not run" state produces +**false clean passes** — an asset audit returning COMPLIANT on a project with no +assets and no standards, or a performance profile reporting ">99% headroom against +a 16.67ms budget" with zero profiler data and no budget ever set. **Absence of evidence is never evidence of absence.** A scan that finds no matches because there are no files to scan has not verified anything. Say which of diff --git a/.claude/skills/create-architecture/SKILL.md b/.claude/skills/create-architecture/SKILL.md index 75567ceb..f451be46 100644 --- a/.claude/skills/create-architecture/SKILL.md +++ b/.claude/skills/create-architecture/SKILL.md @@ -12,7 +12,6 @@ model: sonnet Resolved above — use as-is; `--review` overrides `review_mode`. No block → defaults in `.claude/docs/config-resolution.md`. - # Create Architecture This skill produces `docs/architecture/architecture.md` — the master architecture @@ -22,10 +21,8 @@ It sits between design and implementation, and must exist before sprint planning **Distinct from `/architecture-decision`**: ADRs record individual point decisions. This skill creates the whole-system blueprint that gives ADRs their context. - See `.claude/docs/director-gates.md` for the full check pattern. Individual gate definitions live in `.claude/docs/director-gates/[gate-id].md` — the spawned agent reads its own gate file; do not read it in the parent session. - Every `AskUserQuestion` call follows `.claude/docs/automation-modes.md` (collaborative asks always · guided major-only · autonomous logs and proceeds; `automation_always_ask` categories always prompt). @@ -54,505 +51,39 @@ considered per layer. Apply it to every section you author. ## Phase 0: Load All Context -Before anything else, load the full project context in this order: - -### 0a. Engine Context (Critical) - -Read the four project-wide engine documents in full — they are small, and every -part of each is used: - -1. `docs/engine-reference/[engine]/VERSION.md` - → Extract: engine name, version, LLM cutoff, post-cutoff risk levels -2. `docs/engine-reference/[engine]/breaking-changes.md` - → Extract: all HIGH and MEDIUM risk changes -3. `docs/engine-reference/[engine]/deprecated-apis.md` - → Extract: APIs to avoid -4. `docs/engine-reference/[engine]/current-best-practices.md` - → Extract: post-cutoff best practices that differ from training data - -Then read **only the module docs whose domain this game actually uses** — -not the whole `modules/` directory: - -5. `docs/engine-reference/[engine]/modules/` — glob it to establish what exists, - then match against the domains present in `design/gdd/systems-index.md` - (the same domain vocabulary the ADR template uses: Physics, Rendering, UI, - Audio, Navigation, Animation, Networking, Core, Input). Read the matching - modules; skip the rest. - → Extract: current API patterns per domain - - A game with no multiplayer system does not need the networking module loaded - to write its architecture, and loading it costs the same as one that does. - **If the domain match is ambiguous, read the module** — a missed engine - constraint is far more expensive here than a redundant read, because this - phase is where those constraints get baked into the architecture. - -If no engine is configured, stop and prompt: -> "No engine is configured. Run `/setup-engine` first. Architecture cannot be -> written without knowing which engine and version you are targeting." - -### 0b. Design Context + Technical Requirements Extraction - -Load the approved design documents and extract technical requirements from each: - -1. `design/gdd/game-concept.md` — game pillars, genre, core loop -2. `design/gdd/systems-index.md` — all systems, dependencies, priority tiers - -**Check both exist before reading either. Neither is optional here, and both -need an absence branch** — §0a stops for an unconfigured engine, and these two -matter just as much: - -- **`systems-index.md` absent** — stop: - > "No systems index found. Run `/map-systems` first. An architecture written - > without it invents layers for systems nobody mapped, and every ADR, epic and - > story downstream inherits that invention." - At `minimal` the index is not required (§ tier note above) — say so and proceed - from the brief instead. -- **`game-concept.md` absent** — at `standard`/`full`, stop and point at - `/brainstorm`. At `minimal`, read `design/game-brief.md` in its place; if that - is absent too, stop — there is no design record to architect against. -- **Either present but empty or still template placeholders** — treat as absent. - Present-but-empty is the case that most looks like present. - -Do not proceed on a partial read and note it later. This phase is where design -assumptions get baked into ADRs, and an assumption made here is re-derived by -everything downstream rather than re-checked. -3. Project config — `naming.*` and `performance.*` from `project.yaml` (for any - key absent or empty, fall back to `.claude/docs/technical-preferences.md`); - allowed libraries and forbidden patterns from - `.claude/docs/technical-preferences.md` (not migrated to project.yaml) -4. **Every GDD in `design/gdd/`** — extract technical requirements from the - sections that carry them, **not from whole files**. Establish the denominator - first (glob `design/gdd/*.md`, count **N**), then: - ``` - Grep pattern="^## (Detailed Rules|Detailed Design|Formulas|Dependencies|Tuning Knobs|Acceptance Criteria)" glob="design/gdd/*.md" output_mode="content" -A 40 - ``` - Overview and Player Fantasy are narrative and imply no architecture; the - scanned set is where rules, numbers, and cross-system contracts live. Accept - either `## Detailed Rules` or `## Detailed Design` — the design standard and - the GDD template disagree on the name and they denote the same section. - - Full-read a GDD when it matched **zero** sections (it predates the template — - a zero-match means "unstructured", never "no requirements") or when a scanned - section refers to material outside itself. **Never treat an absent section as - an absent requirement**: report any GDD that contributed nothing, rather than - letting it drop silently out of the baseline below. - - For each, extract: - - Data structures implied by the game rules - - Performance constraints stated or implied - - Engine capabilities the system requires - - Cross-system communication patterns (what talks to what, how) - - State that must persist (save/load implications) - - Threading or timing requirements - -Build a **Technical Requirements Baseline** — a flat list of all extracted -requirements across all GDDs, numbered `TR-[gdd-slug]-[NNN]`. This is the -complete set of what the architecture must cover. Present it as: - -``` -## Technical Requirements Baseline -Extracted from [N] GDDs | [X] total requirements - -| Req ID | GDD | System | Requirement | Domain | -|--------|-----|--------|-------------|--------| -| TR-combat-001 | combat.md | Combat | Hitbox detection per-frame | Physics | -| TR-combat-002 | combat.md | Combat | Combo state machine | Core | -| TR-inventory-001 | inventory.md | Inventory | Item persistence | Save/Load | -``` - -This baseline feeds into every subsequent phase. No GDD requirement should be -left without an architectural decision to support it by the end of this session. - -### 0c. Existing Architecture Decisions - -To learn **what has already been decided and in which domain**, scan the ADR -headers — do not full-read every ADR to produce a list of numbers and domains: -``` -Grep pattern="^## (Status|Summary)" glob="docs/architecture/adr-*.md" output_mode="content" -A 4 -Grep pattern="\*\*Domain\*\*" glob="docs/architecture/adr-*.md" output_mode="content" -``` -`## Summary` (a 2-sentence what-and-why) plus `## Status` and the Engine -Compatibility `Domain` field are exactly "what was decided and its domain". List -the ADRs found, their status, and their domains from the scan. Full-read a -specific ADR only when a new decision this session would collide with it and you -need its reasoning — not to build the inventory. - -### 0d. Generate Knowledge Gap Inventory - -Before proceeding, display a structured summary: - -``` -## Engine Knowledge Gap Inventory -Engine: [name + version] -LLM Training Covers: up to approximately [version] -Post-Cutoff Versions: [list] - -### HIGH RISK Domains (must verify against engine reference before deciding) -- [Domain]: [Key changes] - -### MEDIUM RISK Domains (verify key APIs) -- [Domain]: [Key changes] - -### LOW RISK Domains (in training data, likely reliable) -- [Domain]: [no significant post-cutoff changes] - -### Systems from GDD that touch HIGH/MEDIUM risk domains: -- [GDD system name] → [domain] → [risk level] -``` - -Use `AskUserQuestion`: -- Prompt: "One or more engine domains are HIGH RISK — the LLM's knowledge may be unreliable for these areas. Architectural recommendations in these domains should be cross-referenced with the engine docs before being acted on. How would you like to proceed?" -- Options: - - `[A] Proceed — flag HIGH RISK domains throughout the output` - - `[B] Let me check the engine reference first — pause here` - - `[C] Show me which domains are HIGH RISK and why` - -### 0e. Existing Architecture Document - -Glob `docs/architecture/architecture.md`. If it exists, this run updates it — -it never replaces it unasked. Read its `## Document Status` block and its `##` -headings, then use `AskUserQuestion`: -- Prompt: "An architecture document already exists (v[N], [last updated]). What should this run do?" -- Options: `[A] Update chosen sections in place` / `[B] Rewrite the whole document — replaces the existing file` / `[C] Stop` - -On `[A]`, ask which sections. Phases 1–6 author only those and say which they -skipped; Phase 7 replaces just those sections and raises `Version` to N+1, -leaving every other section as it is. `[B]` runs the full walkthrough, and -Phase 7's ask says it replaces the existing file. - -A focus-area argument (`layers`, `data-flow`, `api-boundaries`, `adr-audit`) -is `[A]` with that one section chosen: it runs only its phase (1, 3, 4 or 5), -and Phase 7 writes that section. Phase 7b still runs on the updated document — -an update is reviewed like a first draft, at the review modes that review one. With no existing document there is nothing to -update — say so, and offer the full walkthrough instead. - ---- +**Read `references/0-load-context.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 1: System Layer Mapping -Map every system from `systems-index.md` into an architecture layer. The standard -game architecture layers are: - -``` -┌─────────────────────────────────────────────┐ -│ PRESENTATION LAYER │ ← UI, HUD, menus, VFX, audio -├─────────────────────────────────────────────┤ -│ FEATURE LAYER │ ← gameplay systems, AI, quests -├─────────────────────────────────────────────┤ -│ CORE LAYER │ ← physics, input, combat, movement -├─────────────────────────────────────────────┤ -│ FOUNDATION LAYER │ ← engine integration, save/load, -│ │ scene management, event bus -├─────────────────────────────────────────────┤ -│ PLATFORM LAYER │ ← OS, hardware, engine API surface -└─────────────────────────────────────────────┘ -``` - -For each GDD system, ask: -- Which layer does it belong to? -- What are its module boundaries? -- What does it own exclusively? (data, state, behaviour) - -Present the proposed layer assignment and ask for approval before proceeding to -the next section. Record the approved layer map in -`production/session-state/active.md`; it goes into the document at Phase 7. - -**Engine awareness check**: For each system assigned to the Core and Foundation -layers, flag if it touches a HIGH or MEDIUM risk engine domain. Show the relevant -engine reference excerpt inline. - ---- +**Read `references/1-layers.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 2: Module Ownership Map -For each module defined in Phase 1, define ownership: - -- **Owns**: what data and state this module is solely responsible for -- **Exposes**: what other modules may read or call -- **Consumes**: what it reads from other modules -- **Engine APIs used**: which specific engine classes/nodes/signals this module - calls directly (with version and risk level noted) - -Format as a table per layer, then as an ASCII dependency diagram. - -**Engine awareness check**: For every engine API listed, verify against the -relevant module reference doc. If an API is post-cutoff, flag it: - -``` -⚠️ [ClassName.method()] — Godot 4.6 (post-cutoff, HIGH risk) - Verified against: docs/engine-reference/godot/modules/[domain].md - Behaviour confirmed: [yes / NEEDS VERIFICATION] -``` - -Get user approval on the ownership map, then record it in -`production/session-state/active.md`; it is written at Phase 7. - ---- +**Read `references/2-module-ownership.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 3: Data Flow -Define how data moves between modules during key game scenarios. Cover at minimum: - -1. **Frame update path**: Input → Core systems → State → Rendering -2. **Event/signal path**: How systems communicate without tight coupling -3. **Save/load path**: What state is serialised, which module owns serialisation -4. **Initialisation order**: Which modules must boot before others - -Use ASCII sequence diagrams where helpful. For each data flow: -- Name the data being transferred -- Identify the producer and consumer -- State whether this is synchronous call, signal/event, or shared state -- Flag any data flows that cross thread boundaries - -Get user approval on each scenario, then record it in -`production/session-state/active.md`; it is written at Phase 7. - ---- +**Read `references/3-data-flow.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 4: API Boundaries -Define the public contracts between modules. For each boundary: - -- What is the interface a module exposes to the rest of the system? -- What are the entry points (functions/signals/properties)? -- What invariants must callers respect? -- What must the module guarantee to callers? - -Write in pseudocode or the project's actual language (from technical preferences). -These become the contracts programmers implement against. - -**Engine awareness check**: If any interface uses engine-specific types (e.g. -`Node`, `Resource`, `Signal` in Godot), flag the version and verify the type -exists and has not changed signature in the target engine version. - -Get user approval on the API boundaries, then record them in -`production/session-state/active.md`; they are written at Phase 7. - ---- +**Read `references/4-api-boundaries.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 5: ADR Audit + Traceability Check -Review all existing ADRs from Phase 0c against both the architecture built in -Phases 1-4 AND the Technical Requirements Baseline from Phase 0b. - -### ADR Quality Check - -For each ADR: -- [ ] Does it have an Engine Compatibility section? -- [ ] Is the engine version recorded? -- [ ] Are post-cutoff APIs flagged? -- [ ] Does it have a "GDD Requirements Addressed" section? -- [ ] Does it conflict with the layer/ownership decisions made in this session? -- [ ] Is it still valid for the pinned engine version? - -| ADR | Engine Compat | Version | GDD Linkage | Conflicts | Valid | -|-----|--------------|---------|-------------|-----------|-------| -| ADR-0001: [title] | ✅/❌ | ✅/❌ | ✅/❌ | None/[conflict] | ✅/⚠️ | - -### Traceability Coverage Check - -Map every requirement from the Technical Requirements Baseline to existing ADRs. -For each requirement, check if any ADR's "GDD Requirements Addressed" section -or decision text covers it: - -| Req ID | Requirement | ADR Coverage | Status | -|--------|-------------|--------------|--------| -| TR-combat-001 | Hitbox detection per-frame | ADR-0003 | ✅ | -| TR-combat-002 | Combo state machine | — | ❌ GAP | - -Count: X covered, Y gaps. For each gap, it becomes a **Required New ADR**. - -### Required New ADRs - -List all decisions made during this architecture session (Phases 1-4) that do -not yet have a corresponding ADR, PLUS all uncovered Technical Requirements. -Group by layer — Foundation first: - -**Foundation Layer (must create before any coding):** -- `/architecture-decision [title]` → covers: TR-[id], TR-[id] - -**Core Layer:** -- `/architecture-decision [title]` → covers: TR-[id] - ---- +**Read `references/5-adr-audit.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 6: Missing ADR List -Based on the full architecture, produce a complete list of ADRs that should exist -but don't yet. Group by priority: - -**Must have before coding starts (Foundation & Core decisions):** -- [e.g. "Scene management and scene loading strategy"] -- [e.g. "Event bus vs direct signal architecture"] - -**Should have before the relevant system is built:** -- [e.g. "Inventory serialisation format"] - -**Can defer to implementation:** -- [e.g. "Specific shader technique for water"] - ---- +**Read `references/6-missing-adrs.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 7: Write the Master Architecture Document -Once all sections are approved, write the complete document to -`docs/architecture/architecture.md`. - -In an update (Phase 0e `[A]`, or a focus-area argument), write only the chosen -sections instead, replacing each in place with `Edit`, and raise `Version`; the -ask below then names those sections and the version change. - -Display a one-paragraph summary of what the document will contain (layers, modules, data flows, ADR gaps). Then use `AskUserQuestion`: -- "All sections approved. May I write the master architecture document?" - - [A] Yes — write to `docs/architecture/architecture.md` now - - [B] Show me the full draft inline first, then ask again - - [C] Not yet — I have more changes to discuss - -The document structure: - -```markdown -# [Game Name] — Master Architecture - -## Document Status -- Version: [N] -- Last Updated: [date] -- Engine: [name + version] -- GDDs Covered: [list] -- ADRs Referenced: [list] - -## Engine Knowledge Gap Summary -[Condensed from Phase 0d inventory — HIGH/MEDIUM risk domains and their implications] - -## System Layer Map -[From Phase 1] - -## Module Ownership -[From Phase 2] - -## Data Flow -[From Phase 3] - -## API Boundaries -[From Phase 4] - -## ADR Audit -[From Phase 5] - -## Required ADRs -[From Phase 6] - -## Architecture Principles -[3-5 key principles that govern all technical decisions for this project, -derived from the game concept, GDDs, and technical preferences] - -## Open Questions -[Decisions deferred — must be resolved before the relevant layer is built] -``` - ---- - -## Phase 7b: Technical Director Sign-Off + Lead Programmer Feasibility Review - -After writing the master architecture document, perform an explicit sign-off before handoff. - -**Review mode check** — apply before spawning either gate: -- `solo` → skip both. Note: "TD-ARCHITECTURE and LP-FEASIBILITY skipped — Solo mode." Go to Step 4 and record both as skipped, then Phase 8. -- `lean` → skip both (neither is a PHASE-GATE). Note: "TD-ARCHITECTURE and LP-FEASIBILITY skipped — Lean mode." Go to Step 4 and record both as skipped, then Phase 8. -- `full` → spawn both, in parallel. - -**Step 1 — Spawn `technical-director` via `Agent` using gate TD-ARCHITECTURE (`.claude/docs/director-gates/td-architecture.md`):** - -Pass: the architecture document path (`docs/architecture/architecture.md`), the Technical Requirements Baseline (TR-IDs and count), the ADR list with statuses, and the Engine Knowledge Gap Inventory from Phase 0d. Issue this call and Step 2's before waiting for either result. - -**Step 2 — Spawn `lead-programmer` via `Agent` using gate LP-FEASIBILITY (`.claude/docs/director-gates/lp-feasibility.md`):** - -Pass: architecture document path, technical requirements baseline summary, ADR list. - -**Step 3 — Present both assessments to the user:** - -Show the TD-ARCHITECTURE verdict (APPROVE / CONCERNS / REJECT) and the LP-FEASIBILITY verdict (FEASIBLE / CONCERNS / INFEASIBLE) side by side. - -Use `AskUserQuestion` — "Technical Director and Lead Programmer have reviewed the architecture. How would you like to proceed?" -Options: `Accept — proceed to handoff` / `Revise flagged items first` / `Discuss specific concerns`. -If either verdict is REJECT or INFEASIBLE, do not offer `Accept` — the blockers are revised (or discussed) first. -`Revise flagged items first` re-drafts each flagged section and shows it for approval as in Phases 1–4; the revised document is then written once, through Phase 7's ask, and Step 4 records `REVISED after [verdict]`. -A `NOT ASSESSED` answer is never recorded as `APPROVE` or `FEASIBLE`: Step 4 records it with the input that was missing (`director-gates.md`). - -**Step 4 — Record sign-off in the architecture document:** - -Update the Document Status section: -``` -- TD-ARCHITECTURE: [date] — APPROVE / CONCERNS (accepted) / REVISED after CONCERNS / REVISED after REJECT / NOT ASSESSED — [missing input] / skipped — [mode] mode -- LP-FEASIBILITY: [date] — FEASIBLE / CONCERNS (accepted) / REVISED after CONCERNS / REVISED after INFEASIBLE / NOT ASSESSED — [missing input] / skipped — [mode] mode -``` - -Show the proposed Document Status block inline, then use `AskUserQuestion`: -- "May I update the Document Status section with the sign-off results?" - - [A] Yes — apply to `docs/architecture/architecture.md` - - [B] Not yet — I want to revisit the concerns first - ---- +**Read `references/7-write.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 8: Handoff -**Step 1 — Update session state**: Write a summary to `production/session-state/active.md` covering: artifact written, TD/LP sign-off verdicts, any blockers, required ADRs remaining, and next step. - -**Step 2 — Output the handoff** using exactly this template (no freeform prose, no rephrasing of section titles): - ---- - -## Architecture Complete - -`docs/architecture/architecture.md` v[N] — [TD-ARCHITECTURE: APPROVE / CONCERNS (accepted) / REVISED after CONCERNS / REVISED after REJECT / NOT ASSESSED / skipped — [mode] mode]. [One sentence on what the architecture covers.] - ---- - -## Run These ADRs Next - -**1. `/architecture-decision "[Title]"` → ADR-[XXXX]** -[One sentence: what it defines and what it unblocks.] - -**2. `/architecture-decision "[Title]"` → ADR-[XXXX]** -[One sentence.] - -**3. `/architecture-decision "[Title]"` → ADR-[XXXX]** -[One sentence.] - -**Then:** `/architecture-review`, and `/create-control-manifest` once it passes and those ADRs are Accepted — it turns them into the layer rules manifest. - -List top 3 from Phase 6 in priority order. If fewer than 3 remain, list only what's outstanding. - ---- - -## Gate-Check Readiness - -> **Required before `/gate-check pre-production`:** -> - [ ] Accept ADRs: [list Proposed ADR IDs that must be Accepted] -> - [ ] Write ADRs: [list ADR IDs that must still be written] -> - [ ] Run `/architecture-review` — writes the review report and the traceability index (`docs/architecture/requirements-traceability.md`) the gate reads -> - [ ] Run `/test-setup` — scaffolds `tests/unit/`, `tests/integration/`, CI workflow, and an example test file -> - [ ] Run `/ux-design` — creates `design/ux/interaction-patterns.md` and `design/accessibility-requirements.md` -> -> Run `/gate-check pre-production` when all boxes are checked. - -If nothing is blocking, write instead: -> No blockers — run `/gate-check pre-production` now. - ---- - -## Open Questions to Watch - -| ID | Summary | Priority | Resolution Path | -|----|---------|----------|-----------------| -| QQ-XX | [short description] | High / Medium / Low | [ADR or system that resolves it] | - -Omit this section entirely if there are no open QQs. - ---- - -(End of handoff. Do not add trailing commentary after the closing rule.) - ---- +**Read `references/8-handoff.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Collaborative Protocol diff --git a/.claude/skills/create-architecture/references/0-load-context.md b/.claude/skills/create-architecture/references/0-load-context.md new file mode 100644 index 00000000..565a17ed --- /dev/null +++ b/.claude/skills/create-architecture/references/0-load-context.md @@ -0,0 +1,189 @@ +# /create-architecture — Phase 0: Load All Context + +> Part of `/create-architecture`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 0: Load All Context + +**In this file:** + +- 0a. Engine Context (Critical) +- 0b. Design Context + Technical Requirements Extraction +- 0c. Existing Architecture Decisions +- 0d. Generate Knowledge Gap Inventory +- 0e. Existing Architecture Document + +Before anything else, load the full project context in this order: + +### 0a. Engine Context (Critical) + +Read the four project-wide engine documents in full — they are small, and every +part of each is used: + +1. `docs/engine-reference/[engine]/VERSION.md` + → Extract: engine name, version, LLM cutoff, post-cutoff risk levels +2. `docs/engine-reference/[engine]/breaking-changes.md` + → Extract: all HIGH and MEDIUM risk changes +3. `docs/engine-reference/[engine]/deprecated-apis.md` + → Extract: APIs to avoid +4. `docs/engine-reference/[engine]/current-best-practices.md` + → Extract: post-cutoff best practices that differ from training data + +Then read **only the module docs whose domain this game actually uses** — +not the whole `modules/` directory: + +5. `docs/engine-reference/[engine]/modules/` — glob it to establish what exists, + then match against the domains present in `design/gdd/systems-index.md` + (the same domain vocabulary the ADR template uses: Physics, Rendering, UI, + Audio, Navigation, Animation, Networking, Core, Input). Read the matching + modules; skip the rest. + → Extract: current API patterns per domain + + A game with no multiplayer system does not need the networking module loaded + to write its architecture, and loading it costs the same as one that does. + **If the domain match is ambiguous, read the module** — a missed engine + constraint is far more expensive here than a redundant read, because this + phase is where those constraints get baked into the architecture. + +If no engine is configured, stop and prompt: +> "No engine is configured. Run `/setup-engine` first. Architecture cannot be +> written without knowing which engine and version you are targeting." + +### 0b. Design Context + Technical Requirements Extraction + +Load the approved design documents and extract technical requirements from each: + +1. `design/gdd/game-concept.md` — game pillars, genre, core loop +2. `design/gdd/systems-index.md` — all systems, dependencies, priority tiers + +**Check both exist before reading either. Neither is optional here, and both +need an absence branch** — §0a stops for an unconfigured engine, and these two +matter just as much: + +- **`systems-index.md` absent** — stop: + > "No systems index found. Run `/map-systems` first. An architecture written + > without it invents layers for systems nobody mapped, and every ADR, epic and + > story downstream inherits that invention." + At `minimal` the index is not required (§ tier note above) — say so and proceed + from the brief instead. +- **`game-concept.md` absent** — at `standard`/`full`, stop and point at + `/brainstorm`. At `minimal`, read `design/game-brief.md` in its place; if that + is absent too, stop — there is no design record to architect against. +- **Either present but empty or still template placeholders** — treat as absent. + Present-but-empty is the case that most looks like present. + +Do not proceed on a partial read and note it later. This phase is where design +assumptions get baked into ADRs, and an assumption made here is re-derived by +everything downstream rather than re-checked. +3. Project config — `naming.*` and `performance.*` from `project.yaml` (for any + key absent or empty, fall back to `.claude/docs/technical-preferences.md`); + allowed libraries and forbidden patterns from + `.claude/docs/technical-preferences.md` (not migrated to project.yaml) +4. **Every GDD in `design/gdd/`** — extract technical requirements from the + sections that carry them, **not from whole files**. Establish the denominator + first (glob `design/gdd/*.md`, count **N**), then: + ``` + Grep pattern="^## (Detailed Rules|Detailed Design|Formulas|Dependencies|Tuning Knobs|Acceptance Criteria)" glob="design/gdd/*.md" output_mode="content" -A 40 + ``` + Overview and Player Fantasy are narrative and imply no architecture; the + scanned set is where rules, numbers, and cross-system contracts live. Accept + either `## Detailed Rules` or `## Detailed Design` — the design standard and + the GDD template disagree on the name and they denote the same section. + + Full-read a GDD when it matched **zero** sections (it predates the template — + a zero-match means "unstructured", never "no requirements") or when a scanned + section refers to material outside itself. **Never treat an absent section as + an absent requirement**: report any GDD that contributed nothing, rather than + letting it drop silently out of the baseline below. + + For each, extract: + - Data structures implied by the game rules + - Performance constraints stated or implied + - Engine capabilities the system requires + - Cross-system communication patterns (what talks to what, how) + - State that must persist (save/load implications) + - Threading or timing requirements + +Build a **Technical Requirements Baseline** — a flat list of all extracted +requirements across all GDDs, numbered `TR-[system]-[NNN]`, the TR registry's +ID format. This is the +complete set of what the architecture must cover. Present it as: + +``` +## Technical Requirements Baseline +Extracted from [N] GDDs | [X] total requirements + +| Req ID | GDD | System | Requirement | Domain | +|--------|-----|--------|-------------|--------| +| TR-combat-001 | combat.md | Combat | Hitbox detection per-frame | Physics | +| TR-combat-002 | combat.md | Combat | Combo state machine | Core | +| TR-inventory-001 | inventory.md | Inventory | Item persistence | Save/Load | +``` + +This baseline feeds into every subsequent phase. No GDD requirement should be +left without an architectural decision to support it by the end of this session. + +### 0c. Existing Architecture Decisions + +To learn **what has already been decided and in which domain**, scan the ADR +headers — do not full-read every ADR to produce a list of numbers and domains: +``` +Grep pattern="^## (Status|Summary)" glob="docs/architecture/adr-*.md" output_mode="content" -A 4 +Grep pattern="\*\*Domain\*\*" glob="docs/architecture/adr-*.md" output_mode="content" +``` +`## Summary` (a 2-sentence what-and-why) plus `## Status` and the Engine +Compatibility `Domain` field are exactly "what was decided and its domain". List +the ADRs found, their status, and their domains from the scan. Full-read a +specific ADR only when a new decision this session would collide with it and you +need its reasoning — not to build the inventory. + +### 0d. Generate Knowledge Gap Inventory + +Before proceeding, display a structured summary: + +``` +## Engine Knowledge Gap Inventory +Engine: [name + version] +LLM Training Covers: up to approximately [version] +Post-Cutoff Versions: [list] + +### HIGH RISK Domains (must verify against engine reference before deciding) +- [Domain]: [Key changes] + +### MEDIUM RISK Domains (verify key APIs) +- [Domain]: [Key changes] + +### LOW RISK Domains (in training data, likely reliable) +- [Domain]: [no significant post-cutoff changes] + +### Systems from GDD that touch HIGH/MEDIUM risk domains: +- [GDD system name] → [domain] → [risk level] +``` + +Use `AskUserQuestion`: +- Prompt: "One or more engine domains are HIGH RISK — the LLM's knowledge may be unreliable for these areas. Architectural recommendations in these domains should be cross-referenced with the engine docs before being acted on. How would you like to proceed?" +- Options: + - `[A] Proceed — flag HIGH RISK domains throughout the output` + - `[B] Let me check the engine reference first — pause here` + - `[C] Show me which domains are HIGH RISK and why` + +### 0e. Existing Architecture Document + +Glob `docs/architecture/architecture.md`. If it exists, this run updates it — +it never replaces it unasked. Read its `## Document Status` block and its `##` +headings, then use `AskUserQuestion`: +- Prompt: "An architecture document already exists (v[N], [last updated]). What should this run do?" +- Options: `[A] Update chosen sections in place` / `[B] Rewrite the whole document — replaces the existing file` / `[C] Stop` + +On `[A]`, ask which sections. Phases 1–6 author only those and say which they +skipped; Phase 7 replaces just those sections and raises `Version` to N+1, +leaving every other section as it is. `[B]` runs the full walkthrough, and +Phase 7's ask says it replaces the existing file. + +A focus-area argument (`layers`, `data-flow`, `api-boundaries`, `adr-audit`) +is `[A]` with that one section chosen: it runs only its phase (1, 3, 4 or 5), +and Phase 7 writes that section. Phase 7b still runs on the updated document — +an update is reviewed like a first draft, at the review modes that review one. With no existing document there is nothing to +update — say so, and offer the full walkthrough instead. + +--- diff --git a/.claude/skills/create-architecture/references/1-layers.md b/.claude/skills/create-architecture/references/1-layers.md new file mode 100644 index 00000000..ce9cc0fc --- /dev/null +++ b/.claude/skills/create-architecture/references/1-layers.md @@ -0,0 +1,39 @@ +# /create-architecture — Phase 1: System Layer Mapping + +> Part of `/create-architecture`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 1: System Layer Mapping + +Map every system from `systems-index.md` into an architecture layer. The standard +game architecture layers are: + +``` +┌─────────────────────────────────────────────┐ +│ PRESENTATION LAYER │ ← UI, HUD, menus, VFX, audio +├─────────────────────────────────────────────┤ +│ FEATURE LAYER │ ← gameplay systems, AI, quests +├─────────────────────────────────────────────┤ +│ CORE LAYER │ ← physics, input, combat, movement +├─────────────────────────────────────────────┤ +│ FOUNDATION LAYER │ ← engine integration, save/load, +│ │ scene management, event bus +├─────────────────────────────────────────────┤ +│ PLATFORM LAYER │ ← OS, hardware, engine API surface +└─────────────────────────────────────────────┘ +``` + +For each GDD system, ask: +- Which layer does it belong to? +- What are its module boundaries? +- What does it own exclusively? (data, state, behaviour) + +Present the proposed layer assignment and ask for approval before proceeding to +the next section. Record the approved layer map in +`production/session-state/active.md`; it goes into the document at Phase 7. + +**Engine awareness check**: For each system assigned to the Core and Foundation +layers, flag if it touches a HIGH or MEDIUM risk engine domain. Show the relevant +engine reference excerpt inline. + +--- diff --git a/.claude/skills/create-architecture/references/2-module-ownership.md b/.claude/skills/create-architecture/references/2-module-ownership.md new file mode 100644 index 00000000..0083c498 --- /dev/null +++ b/.claude/skills/create-architecture/references/2-module-ownership.md @@ -0,0 +1,30 @@ +# /create-architecture — Phase 2: Module Ownership Map + +> Part of `/create-architecture`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 2: Module Ownership Map + +For each module defined in Phase 1, define ownership: + +- **Owns**: what data and state this module is solely responsible for +- **Exposes**: what other modules may read or call +- **Consumes**: what it reads from other modules +- **Engine APIs used**: which specific engine classes/nodes/signals this module + calls directly (with version and risk level noted) + +Format as a table per layer, then as an ASCII dependency diagram. + +**Engine awareness check**: For every engine API listed, verify against the +relevant module reference doc. If an API is post-cutoff, flag it: + +``` +⚠️ [ClassName.method()] — Godot 4.6 (post-cutoff, HIGH risk) + Verified against: docs/engine-reference/godot/modules/[domain].md + Behaviour confirmed: [yes / NEEDS VERIFICATION] +``` + +Get user approval on the ownership map, then record it in +`production/session-state/active.md`; it is written at Phase 7. + +--- diff --git a/.claude/skills/create-architecture/references/3-data-flow.md b/.claude/skills/create-architecture/references/3-data-flow.md new file mode 100644 index 00000000..2a565e6d --- /dev/null +++ b/.claude/skills/create-architecture/references/3-data-flow.md @@ -0,0 +1,24 @@ +# /create-architecture — Phase 3: Data Flow + +> Part of `/create-architecture`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 3: Data Flow + +Define how data moves between modules during key game scenarios. Cover at minimum: + +1. **Frame update path**: Input → Core systems → State → Rendering +2. **Event/signal path**: How systems communicate without tight coupling +3. **Save/load path**: What state is serialised, which module owns serialisation +4. **Initialisation order**: Which modules must boot before others + +Use ASCII sequence diagrams where helpful. For each data flow: +- Name the data being transferred +- Identify the producer and consumer +- State whether this is synchronous call, signal/event, or shared state +- Flag any data flows that cross thread boundaries + +Get user approval on each scenario, then record it in +`production/session-state/active.md`; it is written at Phase 7. + +--- diff --git a/.claude/skills/create-architecture/references/4-api-boundaries.md b/.claude/skills/create-architecture/references/4-api-boundaries.md new file mode 100644 index 00000000..f0ae0f25 --- /dev/null +++ b/.claude/skills/create-architecture/references/4-api-boundaries.md @@ -0,0 +1,25 @@ +# /create-architecture — Phase 4: API Boundaries + +> Part of `/create-architecture`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 4: API Boundaries + +Define the public contracts between modules. For each boundary: + +- What is the interface a module exposes to the rest of the system? +- What are the entry points (functions/signals/properties)? +- What invariants must callers respect? +- What must the module guarantee to callers? + +Write in pseudocode or the project's actual language (from technical preferences). +These become the contracts programmers implement against. + +**Engine awareness check**: If any interface uses engine-specific types (e.g. +`Node`, `Resource`, `Signal` in Godot), flag the version and verify the type +exists and has not changed signature in the target engine version. + +Get user approval on the API boundaries, then record them in +`production/session-state/active.md`; they are written at Phase 7. + +--- diff --git a/.claude/skills/create-architecture/references/5-adr-audit.md b/.claude/skills/create-architecture/references/5-adr-audit.md new file mode 100644 index 00000000..8edafc61 --- /dev/null +++ b/.claude/skills/create-architecture/references/5-adr-audit.md @@ -0,0 +1,50 @@ +# /create-architecture — Phase 5: ADR Audit and Traceability Check + +> Part of `/create-architecture`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 5: ADR Audit + Traceability Check + +Review all existing ADRs from Phase 0c against both the architecture built in +Phases 1-4 AND the Technical Requirements Baseline from Phase 0b. + +### ADR Quality Check + +For each ADR: +- [ ] Does it have an Engine Compatibility section? +- [ ] Is the engine version recorded? +- [ ] Are post-cutoff APIs flagged? +- [ ] Does it have a "GDD Requirements Addressed" section? +- [ ] Does it conflict with the layer/ownership decisions made in this session? +- [ ] Is it still valid for the pinned engine version? + +| ADR | Engine Compat | Version | GDD Linkage | Conflicts | Valid | +|-----|--------------|---------|-------------|-----------|-------| +| ADR-0001: [title] | ✅/❌ | ✅/❌ | ✅/❌ | None/[conflict] | ✅/⚠️ | + +### Traceability Coverage Check + +Map every requirement from the Technical Requirements Baseline to existing ADRs. +For each requirement, check if any ADR's "GDD Requirements Addressed" section +or decision text covers it: + +| Req ID | Requirement | ADR Coverage | Status | +|--------|-------------|--------------|--------| +| TR-combat-001 | Hitbox detection per-frame | ADR-0003 | ✅ | +| TR-combat-002 | Combo state machine | — | ❌ GAP | + +Count: X covered, Y gaps. For each gap, it becomes a **Required New ADR**. + +### Required New ADRs + +List all decisions made during this architecture session (Phases 1-4) that do +not yet have a corresponding ADR, PLUS all uncovered Technical Requirements. +Group by layer — Foundation first: + +**Foundation Layer (must create before any coding):** +- `/architecture-decision [title]` → covers: TR-[id], TR-[id] + +**Core Layer:** +- `/architecture-decision [title]` → covers: TR-[id] + +--- diff --git a/.claude/skills/create-architecture/references/6-missing-adrs.md b/.claude/skills/create-architecture/references/6-missing-adrs.md new file mode 100644 index 00000000..31fb0e8d --- /dev/null +++ b/.claude/skills/create-architecture/references/6-missing-adrs.md @@ -0,0 +1,21 @@ +# /create-architecture — Phase 6: Missing ADR List + +> Part of `/create-architecture`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 6: Missing ADR List + +Based on the full architecture, produce a complete list of ADRs that should exist +but don't yet. Group by priority: + +**Must have before coding starts (Foundation & Core decisions):** +- [e.g. "Scene management and scene loading strategy"] +- [e.g. "Event bus vs direct signal architecture"] + +**Should have before the relevant system is built:** +- [e.g. "Inventory serialisation format"] + +**Can defer to implementation:** +- [e.g. "Specific shader technique for water"] + +--- diff --git a/.claude/skills/create-architecture/references/7-write.md b/.claude/skills/create-architecture/references/7-write.md new file mode 100644 index 00000000..1fd98947 --- /dev/null +++ b/.claude/skills/create-architecture/references/7-write.md @@ -0,0 +1,109 @@ +# /create-architecture — Phases 7 and 7b: Write and Sign-Off + +> Part of `/create-architecture`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 7: Write the Master Architecture Document + +**In this file:** + +- Phase 7: the master architecture document template, then the write +- Phase 7b: Technical Director Sign-Off + Lead Programmer Feasibility Review: review mode check, presenting both assessments, recording the sign-off + +Once all sections are approved, write the complete document to +`docs/architecture/architecture.md`. + +In an update (Phase 0e `[A]`, or a focus-area argument), write only the chosen +sections instead, replacing each in place with `Edit`, and raise `Version`; the +ask below then names those sections and the version change. + +Display a one-paragraph summary of what the document will contain (layers, modules, data flows, ADR gaps). Then use `AskUserQuestion`: +- "All sections approved. May I write the master architecture document?" + - [A] Yes — write to `docs/architecture/architecture.md` now + - [B] Show me the full draft inline first, then ask again + - [C] Not yet — I have more changes to discuss + +The document structure: + +```markdown +# [Game Name] — Master Architecture + +## Document Status +- Version: [N] +- Last Updated: [date] +- Engine: [name + version] +- GDDs Covered: [list] +- ADRs Referenced: [list] + +## Engine Knowledge Gap Summary +[Condensed from Phase 0d inventory — HIGH/MEDIUM risk domains and their implications] + +## System Layer Map +[From Phase 1] + +## Module Ownership +[From Phase 2] + +## Data Flow +[From Phase 3] + +## API Boundaries +[From Phase 4] + +## ADR Audit +[From Phase 5] + +## Required ADRs +[From Phase 6] + +## Architecture Principles +[3-5 key principles that govern all technical decisions for this project, +derived from the game concept, GDDs, and technical preferences] + +## Open Questions +[Decisions deferred — must be resolved before the relevant layer is built] +``` + +--- + +## Phase 7b: Technical Director Sign-Off + Lead Programmer Feasibility Review + +After writing the master architecture document, perform an explicit sign-off before handoff. + +**Review mode check** — apply before spawning either gate: +- `solo` → skip both. Note: "TD-ARCHITECTURE and LP-FEASIBILITY skipped — Solo mode." Go to Step 4 and record both as skipped, then Phase 8. +- `lean` → skip both (neither is a PHASE-GATE). Note: "TD-ARCHITECTURE and LP-FEASIBILITY skipped — Lean mode." Go to Step 4 and record both as skipped, then Phase 8. +- `full` → spawn both, in parallel. + +**Step 1 — Spawn `technical-director` via `Agent` using gate TD-ARCHITECTURE (`.claude/docs/director-gates/td-architecture.md`):** + +Pass: the architecture document path (`docs/architecture/architecture.md`), the Technical Requirements Baseline (TR-IDs and count), the ADR list with statuses, and the Engine Knowledge Gap Inventory from Phase 0d. Issue this call and Step 2's before waiting for either result. + +**Step 2 — Spawn `lead-programmer` via `Agent` using gate LP-FEASIBILITY (`.claude/docs/director-gates/lp-feasibility.md`):** + +Pass: architecture document path, technical requirements baseline summary, ADR list. + +**Step 3 — Present both assessments to the user:** + +Show the TD-ARCHITECTURE verdict (APPROVE / CONCERNS / REJECT) and the LP-FEASIBILITY verdict (FEASIBLE / CONCERNS / INFEASIBLE) side by side. + +Use `AskUserQuestion` — "Technical Director and Lead Programmer have reviewed the architecture. How would you like to proceed?" +Options: `Accept — proceed to handoff` / `Revise flagged items first` / `Discuss specific concerns`. +If either verdict is REJECT or INFEASIBLE, do not offer `Accept` — the blockers are revised (or discussed) first. +`Revise flagged items first` re-drafts each flagged section and shows it for approval as in Phases 1–4; the revised document is then written once, through Phase 7's ask, and Step 4 records `REVISED after [verdict]`. +A `NOT ASSESSED` answer is never recorded as `APPROVE` or `FEASIBLE`: Step 4 records it with the input that was missing (`director-gates.md`). + +**Step 4 — Record sign-off in the architecture document:** + +Update the Document Status section: +``` +- TD-ARCHITECTURE: [date] — APPROVE / CONCERNS (accepted) / REVISED after CONCERNS / REVISED after REJECT / NOT ASSESSED — [missing input] / skipped — [mode] mode +- LP-FEASIBILITY: [date] — FEASIBLE / CONCERNS (accepted) / REVISED after CONCERNS / REVISED after INFEASIBLE / NOT ASSESSED — [missing input] / skipped — [mode] mode +``` + +Show the proposed Document Status block inline, then use `AskUserQuestion`: +- "May I update the Document Status section with the sign-off results?" + - [A] Yes — apply to `docs/architecture/architecture.md` + - [B] Not yet — I want to revisit the concerns first + +--- diff --git a/.claude/skills/create-architecture/references/8-handoff.md b/.claude/skills/create-architecture/references/8-handoff.md new file mode 100644 index 00000000..826879b2 --- /dev/null +++ b/.claude/skills/create-architecture/references/8-handoff.md @@ -0,0 +1,65 @@ +# /create-architecture — Phase 8: Handoff + +> Part of `/create-architecture`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 8: Handoff + +**Step 1 — Update session state**: Write a summary to `production/session-state/active.md` covering: artifact written, TD/LP sign-off verdicts, any blockers, required ADRs remaining, and next step. + +**Step 2 — Output the handoff** using exactly this template (no freeform prose, no rephrasing of section titles): + +--- + +## Architecture Complete + +`docs/architecture/architecture.md` v[N] — [TD-ARCHITECTURE: APPROVE / CONCERNS (accepted) / REVISED after CONCERNS / REVISED after REJECT / NOT ASSESSED / skipped — [mode] mode]. [One sentence on what the architecture covers.] + +--- + +## Run These ADRs Next + +**1. `/architecture-decision "[Title]"` → ADR-[XXXX]** +[One sentence: what it defines and what it unblocks.] + +**2. `/architecture-decision "[Title]"` → ADR-[XXXX]** +[One sentence.] + +**3. `/architecture-decision "[Title]"` → ADR-[XXXX]** +[One sentence.] + +**Then:** `/architecture-review`, and `/create-control-manifest` once it passes and those ADRs are Accepted — it turns them into the layer rules manifest. + +List top 3 from Phase 6 in priority order. If fewer than 3 remain, list only what's outstanding. + +--- + +## Gate-Check Readiness + +> **Required before `/gate-check pre-production`:** +> - [ ] Accept ADRs: [list Proposed ADR IDs that must be Accepted] +> - [ ] Write ADRs: [list ADR IDs that must still be written] +> - [ ] Run `/architecture-review` — writes the review report and the traceability index (`docs/architecture/requirements-traceability.md`) the gate reads +> - [ ] Run `/test-setup` — scaffolds `tests/unit/`, `tests/integration/`, CI workflow, and an example test file +> - [ ] Run `/ux-design` — creates `design/ux/interaction-patterns.md` and `design/accessibility-requirements.md` +> +> Run `/gate-check pre-production` when all boxes are checked. + +If nothing is blocking, write instead: +> No blockers — run `/gate-check pre-production` now. + +--- + +## Open Questions to Watch + +| ID | Summary | Priority | Resolution Path | +|----|---------|----------|-----------------| +| QQ-XX | [short description] | High / Medium / Low | [ADR or system that resolves it] | + +Omit this section entirely if there are no open QQs. + +--- + +(End of handoff. Do not add trailing commentary after the closing rule.) + +--- diff --git a/.claude/skills/create-stories/SKILL.md b/.claude/skills/create-stories/SKILL.md index 74f3bcb6..cda1eea1 100644 --- a/.claude/skills/create-stories/SKILL.md +++ b/.claude/skills/create-stories/SKILL.md @@ -130,7 +130,7 @@ For `standard`/`full` (a `/create-epics` epic exists), read in full (these are s - `production/epics/[epic-slug]/EPIC.md` — epic overview, governing ADRs, GDD requirements table - The epic's GDD (`design/gdd/[filename].md`) — at `full` read all 8 sections; at `standard` the 5 required sections (+ conditional Formulas); at `minimal` the GDD may not exist — work from the epic brief + acceptance criteria. Always prioritise Acceptance Criteria, Formulas, and Edge Cases where present. - `docs/architecture/control-manifest.md` — grep only this epic's layer (`Grep pattern="^## Layer Rules" path="docs/architecture/control-manifest.md" output_mode="content" -A 40`) plus the header Manifest Version date, not a full read of all layers -- `docs/architecture/tr-registry.yaml` — grep only this system's entries (`Grep pattern="system: " path="docs/architecture/tr-registry.yaml" output_mode="content" -B1 -A5`, or `id: TR--`), not the whole cross-system registry +- `docs/architecture/tr-registry.yaml` — grep only this system's entries (`Grep pattern="system: \s*$" path="docs/architecture/tr-registry.yaml" output_mode="content" -B1 -A5`, or `id: TR--[0-9]`; the anchors keep `combat` from matching `combat-ai`), not the whole cross-system registry **Load each governing ADR by section — never with an unbounded full read.** A substantial ADR exceeds the 25k-token `Read` cap, and a capped read's only diff --git a/.claude/skills/day-one-patch/SKILL.md b/.claude/skills/day-one-patch/SKILL.md index 77443376..dd7883aa 100644 --- a/.claude/skills/day-one-patch/SKILL.md +++ b/.claude/skills/day-one-patch/SKILL.md @@ -261,4 +261,5 @@ Use `AskUserQuestion`: - **Rollback plan first, always** — a patch without a rollback plan is irresponsible - **Deferred is not forgotten** — every deferred bug is listed in the record's "Deferred to 1.1" table; run `/bug-triage` afterwards to schedule them into the 1.1 sprint + (if the project has no sprint plan, as on the default minimal workflow, into the brief's build order) - **Player communication is part of the patch** — `/patch-notes` is a required output, not optional diff --git a/.claude/skills/design-review/SKILL.md b/.claude/skills/design-review/SKILL.md index 90f0ddf4..d6347dcb 100644 --- a/.claude/skills/design-review/SKILL.md +++ b/.claude/skills/design-review/SKILL.md @@ -15,6 +15,8 @@ the pre-1.1 name for the same flag: treat `--depth ` exactly as wins and `--depth` is ignored — say so. No block → defaults in `.claude/docs/config-resolution.md`. +# Design Review + ## Phase 0: Parse Arguments diff --git a/.claude/skills/design-system/SKILL.md b/.claude/skills/design-system/SKILL.md index bd5c5efd..2132fac3 100644 --- a/.claude/skills/design-system/SKILL.md +++ b/.claude/skills/design-system/SKILL.md @@ -12,1165 +12,29 @@ model: sonnet Resolved above — use as-is; `--review` overrides `review_mode`. No block → defaults in `.claude/docs/config-resolution.md`. +# Design System When this skill is invoked: ## 1. Parse Arguments & Validate - -See `.claude/docs/director-gates.md` for the full check pattern. Individual gate definitions live in `.claude/docs/director-gates/[gate-id].md` — the spawned agent reads its own gate file; do not read it in the parent session. - - -Every `AskUserQuestion` call follows `.claude/docs/automation-modes.md` -(collaborative asks always · guided major-only · autonomous logs and proceeds; -`automation_always_ask` categories always prompt). - -**`docs.density`** — it controls per-section *depth*, where `workflow` -controls which sections exist. `modes.rigor` sets both together; set -`docs.density` explicitly to vary depth alone: `terse` (the default, via `rigor: minimal`) = bullet points, 2–5 lines per section, -skip rationale and preambles; `balanced` = paragraphs with light rationale -(`rigor: standard`); `thorough` = full prose with rationale, examples, and alternatives -considered. Apply it to every section you author. Mandated structures (the -Formulas variable table, Given-When-Then acceptance criteria) are correctness -requirements at every density — `terse` trims the surrounding prose, never the -required structure itself. - -A system name or retrofit path is **required**. If missing: - -1. Check if `design/gdd/systems-index.md` exists. -2. If it exists: read it, find the highest-priority system with status "Not Started" or equivalent, and use `AskUserQuestion`: - - Prompt: "The next system in your design order is **[system-name]** ([priority] | [layer]). Start designing it?" - - Options: `[A] Yes — design [system-name]` / `[B] Pick a different system` / `[C] Stop here` - - If [A]: proceed with that system name. If [B]: ask which system to design (plain text). If [C]: exit. -3. If no systems index exists, fail with: - > "Usage: `/design-system ` — e.g., `/design-system movement` - > Or to fill gaps in an existing GDD: `/design-system retrofit design/gdd/[system-name].md` - > No systems index found. Run `/map-systems` first to map your systems and get the design order." - -**Detect retrofit mode:** -If the argument starts with `retrofit` or the argument is a file path to an -existing `.md` file in `design/gdd/`, enter **retrofit mode**: - -1. Read the existing GDD file. -2. Identify which of the 8 **possible** sections are present (scan for section - headings): Overview, Player Fantasy, Detailed Design/Rules, Formulas, - Edge Cases, Dependencies, Tuning Knobs, Acceptance Criteria. - **Which of them are *required* depends on the effective tier** (§1) — at - `standard` only 5 are, plus Formulas for math categories, and Player Fantasy - and Tuning Knobs are skipped **by design**. Report an absent section as a gap - only when the tier requires it; otherwise list it as available-to-add. Calling - all 8 required here reports two by-design-absent sections as gaps on every - `standard` project. -3. Identify which sections contain only placeholder text (`[To be designed]` or - equivalent — blank, a single line, or obviously incomplete). -4. Present to the user before doing anything: - ``` - ## Retrofit: [System Name] - File: design/gdd/[filename].md - - Sections already written (will not be touched): - ✓ [section name] - ✓ [section name] - - Missing or incomplete sections (will be authored): - ✗ [section name] — missing - ✗ [section name] — placeholder only - ``` -5. Ask: "Shall I fill the [N] missing sections? I will not modify any existing content." -6. If yes: proceed to **Phase 2 (Gather Context)** as normal, but in **Phase 3** - skip creating the skeleton (file already exists) and in **Phase 4** skip - sections that are already complete. Only run the section cycle for missing/ - incomplete sections. -7. **Never overwrite existing section content.** Use Edit tool to replace only - `[To be designed]` placeholders or empty section bodies. - -If NOT in retrofit mode, normalize the system name to kebab-case for the -filename (e.g., "combat system" becomes `combat-system`). - -**`workflow`** for this system (per `.claude/docs/workflow-modes.md`) — use the -`system_overrides` row for this system if the block lists one, else the project -value. - -The resolved tier determines which GDD sections are **required** (applied in §4). -**`## Summary` is required at every tier and is not one of the 8** — §5-pre -authors it unconditionally (*"This runs at every tier"*), but it appeared in none -of the per-tier lists below, and these lists are what other skills and gates -apply. A GDD checked against a tier list alone would pass with no Summary, the -one section `/review-all-gdds` and the tiered-loading readers depend on. Read -every list below as "`## Summary`, plus:". -- `full` — all 8 sections -- `standard` — Overview, Detailed Design, Edge Cases, Dependencies, Acceptance - Criteria (5 required); **Formulas conditional** — required when the system - **defines numeric rules**: rates, curves, thresholds, costs, damage, drop - weights, or any value a balance pass would tune. Optional only when the system - defines no such value. **The `Category` in `systems-index.md` is a hint, not - the test** — `Gameplay`, `Economy` and `Progression` systems almost always - qualify, and a `Core`, `UI` or `Persistence` system that defines a numeric rule - qualifies too. If the Detailed Design states a quantity that is not a constant - of the engine, Formulas is required. **Player Fantasy and Tuning Knobs skipped** - unless `workflow_overrides` force them (`tuning_knobs: true` forces Tuning Knobs) - - > **Do not gate this on a category token.** A rule of the form "required when - > the system category is combat / economy / progression / AI" does not work: - > those four tokens are not what `/map-systems` writes — `templates/systems-index.md` - > defines the categories as `Core · Gameplay · Progression · Economy · - > Persistence · UI · Audio · Narrative · Meta` and lists **combat and AI as - > example systems under `Gameplay`**. A combat system categorised exactly as the - > template instructs matches none of the four, and Formulas would be dropped for - > the system most likely to need it. -- `minimal` — a GDD is not required (the game brief replaces it). If invoked - voluntarily at minimal, author exactly the 5 standard sections (Overview, - Detailed Design, Edge Cases, Dependencies, Acceptance Criteria) — the - conditional Formulas rule does NOT re-apply at minimal — and tell the user - the GDD is optional at this workflow level. - -Retrofit mode is unaffected — it fills whatever sections are missing regardless -of tier. - ---- +**Read `references/1-parse-arguments.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 2. Gather Context (Read Phase) -Read all relevant context **before** asking the user anything. This is the skill's -primary advantage over ad-hoc design — it arrives informed. - -### 2a: Required Reads - -> **At `minimal`** (design-system is voluntary at this tier): read -> `design/game-brief.md` in place of the game concept, and **skip the systems-index -> read** — neither `game-concept.md` nor `systems-index.md` exists at `minimal`. -> Author from the brief's relevant MVP feature and its core loop. -> -> **This callout keys on the PROJECT tier, not this system's effective tier.** -> The two differ whenever `workflow_overrides.system_overrides` bumps one system -> above a `minimal` project — the configuration `.claude/docs/settings-guidance.md` -> advertises as the reason the override exists ("bump one deep system"). Those two -> files are absent because the *project* is `minimal`; raising *this system* to -> `standard` or `full` does not create them. So on a `minimal` project, take this -> branch **even for an overridden system**, and read the brief. -> -> The effective tier still governs everything downstream — the required section -> set (§1), the skeleton (§3), the section cycle (§4) and §5a. Only the -> required-*reads* branch here follows the project tier. -> -> **Then derive `Category`, `Layer` and `Priority` from the brief, once, here.** -> Six later steps are keyed on the systems index you just skipped — §2e's engine -> domain, Section A's and Section B's recommended options, the Visual/Audio -> REQUIRED table, §6 specialist routing, and §5-pre's Quick reference — and none -> of them has an absent-index branch. An overridden system reaches all six at -> `standard` or `full`, so "skip the index" leaves them with no input at all. -> Derive from the brief instead: -> -> - **`Category`** — one of the nine in `templates/systems-index.md` -> (`Core · Gameplay · Progression · Economy · Persistence · UI · Audio · -> Narrative · Meta`), chosen from what the brief says the system *does*. -> - **`Layer`** — `Foundation` if other systems depend on it, else `Feature`. -> - **`Priority`** — `MVP` if the brief's build order lists it, else `Post-MVP`. -> -> Carry all three for the rest of the run and treat them as the index's answer. -> **Mark them inferred** in §5-pre's Quick reference (*"Category: Gameplay -> (inferred from the brief — no systems index at this tier)"*) so a later reader -> does not mistake a derivation for an indexed fact. Do **not** write a systems -> index to hold them: `/map-systems` owns that file (§5d). -> -> Read literally without this rule, an overridden system resolves to `full`, falls -> through to the fail-fast reads below, and aborts with *"No game concept found. -> Run `/brainstorm` first"* — killing the escape hatch on step one of the very -> configuration it was built for. - -- **Game concept**: Read `design/gdd/game-concept.md` — fail if missing: - > "No game concept found. Run `/brainstorm` first." -- **Systems index**: Read `design/gdd/systems-index.md` — fail if missing: - > "No systems index found. Run `/map-systems` first to map your systems." -- **Target system**: Find the system in the index. If not listed, warn: - > "[system-name] is not in the systems index. Would you like to add it, or - > design it as an off-index system?" -- **Entity registry**: Read `design/registry/entities.yaml` if it exists. - Extract all entries referenced by or relevant to this system (grep - `referenced_by.*[system-name]` and `source.*[system-name]`). Hold these - in context as **known facts** — values that other GDDs have already - established and this GDD must not contradict. -- **Reflexion log**: Read `docs/consistency-failures.md` if it exists. - Extract entries whose Domain matches this system's category. These are - recurring conflict patterns — present them under "Past failure patterns" - in the Phase 2d context summary so the user knows where mistakes have - occurred before in this domain. - -### 2b: Dependency Reads - -From the systems index, identify: -- **Upstream dependencies**: Systems this one depends on (decisions this system - must respect). -- **Downstream dependents**: Systems that depend on this one (expectations this - system must satisfy). - -For each dependency GDD that exists, read **only the four sections that carry the -cross-system contract** — not the whole GDD: -``` -Grep pattern="^## ([0-9]+\. )?(Dependencies|Formulas|Edge Cases|Tuning Knobs)" glob="design/gdd/[dep].md" output_mode="content" -A 20 -``` -- Key interfaces and data flow (from Dependencies) -- Formulas that reference this system's outputs -- Edge cases that assume this system's behavior -- Tuning knobs that feed into this system - -Much of this is already in `entities.yaml` (loaded in 2a) — the registry's -`formula_map`/`constant_map` carry the owned values with their `source:`. Use the -registry first; the section grep fills what it does not hold. - -### 2c: Optional Reads - -- **Game pillars**: Read `design/gdd/game-pillars.md` if it exists -- **Existing GDD**: Read `design/gdd/[system-name].md` if it exists (resume, don't - restart from scratch) -- **Related systems**: do **not** glob-and-read `design/gdd/*.md` hunting for - "thematically related" systems — there is no deterministic proxy for that and it - is the read the registry exists to replace. `entities.yaml` (2a) already holds - the cross-system facts a related GDD would supply. If a specific overlap is - known, treat it as a dependency above and section-grep it; otherwise rely on the - registry. - -### 2d: Present Context Summary - -Before starting design work, present a brief summary to the user: - -> **Designing: [System Name]** -> - Priority: [from index] | Layer: [from index] -> - Depends on: [list, noting which have GDDs vs. undesigned] -> - Depended on by: [list, noting which have GDDs vs. undesigned] -> - Existing decisions to respect: [key constraints from dependency GDDs] -> - Pillar alignment: [which pillar(s) this system primarily serves] -> - **Known cross-system facts (from registry):** -> - [entity_name]: [attribute]=[value], [attribute]=[value] (owned by [source GDD]) -> - [item_name]: [attribute]=[value], [attribute]=[value] (owned by [source GDD]) -> - [formula_name]: variables=[list], output=[min–max] (owned by [source GDD]) -> - [constant_name]: [value] [unit] (owned by [source GDD]) -> *(These values are locked — if this GDD needs different values, surface -> the conflict before writing. Do not silently use different numbers.)* -> -> If no registry entries are relevant: omit the "Known cross-system facts" section. - -If any upstream dependencies are undesigned, warn: -> "[dependency] doesn't have a GDD yet. We'll need to make assumptions about -> its interface. Consider designing it first, or we can define the expected -> contract and flag it as provisional." - -### 2e: Technical Feasibility Pre-Check - -Before asking the user to begin designing, load engine context and surface any -constraints or knowledge gaps that will shape the design. - -**Step 1 — Determine the engine domain for this system:** -Map the system's category (from systems-index.md) to an engine domain: - -Keyed on the `Category` column of `systems-index.md`. All nine categories -`templates/systems-index.md` defines appear here; where a category spans several -engine domains, pick the row matching what the system actually does and say -which you picked. - -| `Category` | Engine Domain | -|-----------|--------------| -| `Gameplay` | **Physics** for combat / collision / movement; **Navigation** for AI and pathfinding; **Scripting** for rule-only systems with no engine surface | -| `Core` | **Core** — scene management, state, resource loading; **Input** for controls and keybinding | -| `UI` | UI | -| `Audio` | Audio | -| `Narrative` | Scripting — dialogue, quests, cutscenes | -| `Progression` | Scripting — save-adjacent rule logic, no dedicated domain | -| `Economy` | Scripting — data and rule logic, no dedicated domain | -| `Persistence` | Core — save/load, settings, serialization | -| `Meta` | Core — analytics, tutorials, accessibility plumbing | - -> Animation, Rendering and Networking are engine domains with no category of -> their own: a system needing them will be `Gameplay` or `Core`. Name the domain -> you read the reference for, whichever row you came in on. - -**Step 2 — Read engine context (if available):** -- Identify the engine and version: read `engine.name` and `engine.version` from `project.yaml`. Resolve each field independently — if its key is absent or empty (including when `project.yaml` has no `engine:` block), fall back to `.claude/docs/technical-preferences.md` (a `[TO BE CONFIGURED]` value means not set) -- If engine is configured, read `docs/engine-reference/[engine]/VERSION.md` -- Read `docs/engine-reference/[engine]/modules/[domain].md` if it exists. - **If it does not exist, say so by name** — *"no engine reference for `[domain]` - under `docs/engine-reference/[engine]/modules/`; feasibility not checked against - the pinned engine"* — and carry that into §5-pre. A silent skip here is - indistinguishable from a feasibility check that ran and found nothing wrong, - which is the failure `.claude/rules/skill-authoring.md` obligation 3 exists to - stop. - - > **This is not a rare branch.** The domain table above names `Scripting` and - > `Core` for five of the nine categories (`Narrative`, `Progression`, `Economy` - > → Scripting; `Persistence`, `Meta` → Core), plus a sub-row each under - > `Gameplay` and `Core`. The Godot reference ships `animation, audio, input, - > navigation, networking, physics, rendering, ui` — **there is no - > `scripting.md` and no `core.md`**. So the majority of non-`Gameplay` systems - > hit the absent branch every time, and `if it exists` turned that into - > silence. Either the reference gains those two files or the check reports it; - > until the former, do the latter. -- Read `docs/engine-reference/[engine]/breaking-changes.md` for domain-relevant entries -- Find the domain-matching ADRs without reading every ADR to learn the field you - filter on — grep the Domain field first, then read only the matches: - ``` - Grep pattern="\*\*Domain\*\*" glob="docs/architecture/adr-*.md" output_mode="content" - ``` - Read only the ADRs whose Domain matches this system's category (its `## Decision` - and `## Engine Compatibility` sections); skip the rest. - -**Step 3 — Present the Feasibility Brief:** - -If engine reference docs exist, present before starting design: - -``` -## Technical Feasibility Brief: [System Name] -Engine: [name + version] -Domain: [domain] - -### Known Engine Capabilities (verified for [version]) -- [capability relevant to this system] -- [capability 2] - -### Engine Constraints That Will Shape This Design -- [constraint from engine-reference or existing ADR] - -### Knowledge Gaps (verify before committing to these) -- [post-cutoff feature this design might rely on — mark HIGH/MEDIUM risk] - -### Existing ADRs That Constrain This System -- ADR-XXXX: [decision summary] — means [implication for this GDD] - (or "None yet") -``` - -If no engine reference docs exist (engine not yet configured), show a short note: -> "No engine configured yet — skipping technical feasibility check. Run -> `/setup-engine` before moving to architecture if you haven't already." - -**Step 4 — Ask before proceeding:** - -Use `AskUserQuestion`: -- "Any constraints to add before we begin, or shall we proceed with these noted?" - - Options: "Proceed with these noted", "Add a constraint first", "I need to check the engine docs — pause here" - ---- - -Use `AskUserQuestion`: -- "Ready to start designing [system-name]?" - - Options: "Yes, let's go", "Show me more context first", "Design a dependency first" - ---- +**Read `references/2-gather-context.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 3. Create File Skeleton -Once the user confirms, **immediately** create the GDD file with empty section -headers. This ensures incremental writes have a target. - -**Scaffold only the sections required at the resolved tier** (§1): at -`standard`, omit Player Fantasy and Tuning Knobs (and Formulas only when the -system defines no numeric rule — see §1; the category is a hint, not the test); -at `full`, scaffold all 8. -**Only the sections §1 named as omitted are skipped** — do not leave empty -`[To be designed]` placeholders for those. Every other section in the template -is scaffolded with its placeholder, including the ones §4 has not decided yet. -This sentence governs the three tier omissions above (Player Fantasy, Tuning -Knobs, and Formulas when no numeric rule exists) and nothing else: it is not a -licence to strip a section because it looks optional, and §4 cannot fill a -section §3 never created. - -Use the template structure from `.claude/docs/templates/game-design-document.md`: - -```markdown -# [System Name] - -> **Status**: In Design -> **Author**: [user + agents] -> **Last Updated**: [today's date] -> **Last Verified**: [today's date] -> **Implements Pillar**: [from context] - -## Summary - -[To be designed] - -> **Quick reference** — Layer: `[Foundation | Core | Feature | Presentation]` · Priority: `[MVP | Vertical Slice | Alpha | Full Vision]` · Key deps: `[System names or "None"]` - -## Overview - -[To be designed] - -## Player Fantasy - -[To be designed] - -## Detailed Design - -### Core Rules - -[To be designed] - -### States and Transitions - -[To be designed] - -### Interactions with Other Systems - -[To be designed] - -## Formulas - -[To be designed] - -## Edge Cases - -[To be designed] - -## Dependencies - -[To be designed] - -## Tuning Knobs - -[To be designed] - -## Visual/Audio Requirements - -[To be designed] - -## Game Feel - -[To be designed] - -## UI Requirements - -[To be designed] - -## Cross-References - -[To be designed] - -## Acceptance Criteria - -[To be designed] - -## Open Questions - -[To be designed] -``` - -> **This skeleton and the template must stay identical in section set and -> order.** They diverged once and it was invisible: the skeleton omitted -> `## Game Feel` and `## Cross-References`, so §3's own rule — *"§4 cannot fill a -> section §3 never created"* — made both unreachable **at every tier, `full` -> included**, while §3's prose above still said *"every other section in the -> template is scaffolded"*. Two agents authoring a combat GDD noticed the gap -> only by opening the template. If you add a section to one file, add it to the -> other in the same commit. - -Ask: "May I create the skeleton file at `design/gdd/[system-name].md`?" - -If the user declines: Stop with the following message: -> "Verdict: **BLOCKED** — skeleton creation declined. The design session cannot proceed without the skeleton file, as all subsequent phases use it as the base. Re-run `/design-system [system]` when ready to create the file." -Do not proceed to Section A. - -After writing, update `production/session-state/active.md`: -- Use Glob to check if the file exists. -- If it **does not exist**: use the **Write** tool to create it. Never attempt Edit on a file that may not exist. -- If it **already exists**: use the **Edit** tool to update the relevant fields. - -File content: -- Task: Designing [system-name] GDD -- Current section: Starting (skeleton created) -- File: design/gdd/[system-name].md - ---- +**Read `references/3-file-skeleton.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 4. Section-by-Section Design -**Author only the sections required at the resolved tier** (§1). At `standard`, -the walk covers A (Overview), C (Detailed Design), E (Edge Cases), -F (Dependencies), H (Acceptance Criteria) — plus D (Formulas) when the system -defines numeric rules (see §1; the category is a hint, not the test); skip B (Player Fantasy) and -G (Tuning Knobs) unless `workflow_overrides.tuning_knobs: true` forces G. At -`full`, walk all eight (A–H). At `minimal`, the GDD is optional — if authoring -voluntarily, walk the standard set. Any `system_overrides.` tier was -already folded into the resolved tier in §1. - -Walk through each required section in order. For **each section**, follow this cycle: - -### The Section Cycle - -``` -Context -> Questions -> Options -> Decision -> Draft -> Approval -> Write -``` - -1. **Context**: State what this section needs to contain, and surface any relevant - decisions from dependency GDDs that constrain it. - -2. **Questions**: Ask clarifying questions specific to this section. Use - `AskUserQuestion` for constrained questions, conversational text for open-ended - exploration. - -3. **Options**: Where the section involves design choices (not just documentation), - present 2-4 approaches with pros/cons. Explain reasoning in conversation text, - then use `AskUserQuestion` to capture the decision. - -4. **Decision**: User picks an approach or provides custom direction. - -5. **Draft**: Write the section content in conversation text for review. Flag any - provisional assumptions about undesigned dependencies. - -6. **Approval**: Per the resolved `modes.automation` mode - (`.claude/docs/automation-modes.md`): - - **In `collaborative` mode**: Immediately after the draft — in the SAME - response — use `AskUserQuestion`. **NEVER use plain text. NEVER skip - this step.** - - Prompt: "Approve the [Section Name] section?" - - Options: `[A] Approve — write it to file` / `[B] Make changes — describe what to fix` / `[C] Start over` - - **The draft and the approval widget MUST appear together in one response. - If the draft appears without the widget, the user is left at a blank prompt - with no path forward — this is a protocol violation in collaborative mode.** - - **In `guided` mode**: Write the section immediately after the draft with - a brief one-line summary of what was decided. Skip the per-section widget; - the multi-section authoring rule (no per-section confirmation) applies. - - **In `autonomous` mode**: Write the section directly and call - `log_decision` with `Decision point: Approve [Section Name] section`, - `Chosen: [A] Approve`, `Category: minor`. - -7. **Write**: Use the Edit tool to replace the placeholder with the approved content. - **CRITICAL**: Always include the section heading in the `old_string` to ensure - uniqueness — never match `[To be designed]` alone, as multiple sections use the - same placeholder and the Edit tool requires a unique match. Use this pattern: - ``` - old_string: "## [Section Name]\n\n[To be designed]" - new_string: "## [Section Name]\n\n[approved content]" - ``` - Confirm the write. - -8. **Registry conflict check** (Sections C and D only — Detailed Design and Formulas): - After writing, scan the section content for entity names, item names, formula - names, and numeric constants that appear in the registry. For each match: - - Compare the value just written against the registry entry. - - If they differ: **surface the conflict immediately** before starting the next - section. Do not continue silently. - > "Registry conflict: [name] is registered in [source GDD] as [registry_value]. - > This section just wrote [new_value]. Which is correct?" - - If new (not in registry): flag it as a candidate for registry registration - (will be handled in Phase 5). - -After writing each section, update `production/session-state/active.md` with the -completed section name. Use Glob to check if the file exists — use Write to create -it if absent, Edit to update it if present. - -### Section-Specific Guidance - -Each section has unique design considerations and may benefit from specialist agents: - -**Every skipped spawn is announced.** When a section's review-mode check below -skips its specialist — in `lean` as well as `solo` — print that section's note -with the mode it ran in, e.g. "`creative-director` not consulted — Lean mode. -Review manually before production." A section drafted without its specialist -must say so in the output, whichever mode skipped it. - ---- - -### Section A: Overview - -**Goal**: One paragraph a stranger could read and understand. - -**Derive recommended options before building the widget**: Read the system's category and layer from the systems index (already in context from Phase 2), then determine the recommended option for each tab: -- **Framing tab**: keyed on the `Category` column (`Core · Gameplay · Progression · Economy · Persistence · UI · Audio · Narrative · Meta`). Player-facing — `Gameplay`, `UI`, `Audio`, `Narrative` → `[C] Both` recommended. Internal — `Core`, `Persistence`, `Meta` → `[A]` recommended. Mixed — `Economy`, `Progression` → `[C] Both`. **Tiebreak, when Layer and Category disagree** (a `Foundation`-layer `Gameplay` system is the common case): **Category wins** — the framing describes what the section is *about*, and a player-facing system stays player-facing wherever it sits in the dependency graph. -- **ADR ref tab**: Glob `docs/architecture/adr-*.md` and grep for the system name in the GDD Requirements section of any ADR. If a matching ADR is found → `[A] Yes — cite the ADR` recommended. If none found → `[B] No` recommended. -- **Fantasy tab**: Foundation/Infrastructure layer → `[B] No` recommended. All other categories → `[A] Yes` recommended. - -Append `(Recommended)` to the appropriate option text in each tab. - -**Framing questions (ask BEFORE drafting)**: Use `AskUserQuestion` with a multi-tab widget: -- Tab "Framing" — "How should the overview frame this system?" Options: `[A] As a data/infrastructure layer (technical framing)` / `[B] Through its player-facing effect (design framing)` / `[C] Both — describe the data layer and its player impact` -- Tab "ADR ref" — "Should the overview reference the existing ADR for this system?" Options: `[A] Yes — cite the ADR for implementation details` / `[B] No — keep the GDD at pure design level` -- Tab "Fantasy" — "Does this system have a player fantasy worth stating?" Options: `[A] Yes — players feel it directly` / `[B] No — pure infrastructure, players feel what it enables` - -Use the answers to shape the draft. **In `collaborative` mode, do NOT answer -these questions yourself and auto-draft** — the widget must appear. In `guided` -and `autonomous`, this is a MINOR framing decision: select the recommended -option derived above, state it in one line, and proceed (that is the whole -point of pre-deriving recommendations). Applies to every "ask BEFORE drafting" -widget in this section walk, not just this one. - -**Questions to ask**: -- What is this system in one sentence? -- How does a player interact with it? (active/passive/automatic) -- Why does this system exist — what would the game lose without it? - -**Cross-reference**: Check that the description aligns with how the systems index -describes it. Flag discrepancies. - -**Design vs. implementation boundary**: Overview questions must stay at the behavior -level — what the system *does*, not *how it is built*. If implementation questions -arise during the Overview (e.g., "Should this use an Autoload singleton or a signal -bus?"), note them as "→ becomes an ADR" and move on. Implementation patterns belong -in `/architecture-decision`, not the GDD. The GDD describes behavior; the ADR -describes the technical approach used to achieve it. - ---- - -### Section B: Player Fantasy - -**Goal**: The emotional target — what the player should *feel*. - -**Derive recommended option before building the widget**: Read the system's category and layer from Phase 2 context: -Keyed on the `Category` column (`Core · Gameplay · Progression · Economy · Persistence · UI · Audio · Narrative · Meta`): -- Player-facing — `Gameplay`, `UI`, `Audio`, `Narrative` → `[A] Direct` recommended -- Internal — `Core`, `Persistence`, `Meta` → `[B] Indirect` recommended -- Mixed — `Economy`, `Progression` → `[C] Both` recommended - -**When Layer and Category disagree, Category wins** — same tiebreak as the -Framing tab above. - -Append `(Recommended)` to the appropriate option text. - -**Framing question (ask BEFORE drafting)**: Use `AskUserQuestion`: -- Prompt: "Is this system something the player engages with directly, or infrastructure they experience indirectly?" -- Options: `[A] Direct — player actively uses or feels this system` / `[B] Indirect — player experiences the effects, not the system` / `[C] Both — has a direct interaction layer and infrastructure beneath it` - -Use the answer to frame the Player Fantasy section appropriately. Do NOT assume the answer. - -**Questions to ask**: -- What emotion or power fantasy does this serve? -- What reference games nail this feeling? What specifically creates it? -- Is this a "system you love engaging with" or "infrastructure you don't notice"? - -**Cross-reference**: Must align with the game pillars. If the system serves a pillar, -quote the relevant pillar text. - -**Review mode check** (apply before spawning): -- `solo` → skip this agent spawn. Draft the section without the specialist. Add a note: "`creative-director` not consulted — Solo mode. Review manually before production." -- `lean` → skip unless this is a section with HIGH implementation risk (Sections D and H only). For other sections, draft without the agent. -- `full` → spawn as described below. - -**Agent delegation (MANDATORY)**: After the framing answer is given but before drafting, -spawn `creative-director` via `Agent`: -- Provide: system name, framing answer (direct/indirect/both), game pillars, any reference games the user mentioned, the game concept summary -- Ask: "Shape the Player Fantasy for this system. What emotion or power fantasy should it serve? What player moment should we anchor to? What tone and language fits the game's established feeling? Be specific — give me 2-3 candidate framings." -- Collect the creative-director's framings and present them to the user alongside the draft. - -**Do NOT draft Section B without first consulting `creative-director`.** The framing -answer tells us *what kind* of fantasy it is; the creative-director shapes *how it's -described* — tone, language, the specific player moment to anchor to. - ---- - -### Section C: Detailed Design (Core Rules, States, Interactions) - -**Goal**: Unambiguous specification a programmer could implement without questions. - -This is usually the largest section. Break it into sub-sections: - -1. **Core Rules**: The fundamental mechanics. Use numbered rules for sequential - processes, bullets for properties. -2. **States and Transitions**: If the system has states, map every state and - every valid transition. Use a table. -3. **Interactions with Other Systems**: For each dependency (upstream and downstream), - specify what data flows in, what flows out, and who owns the interface. - -**Questions to ask**: -- Walk me through a typical use of this system, step by step -- What are the decision points the player faces? -- What can the player NOT do? (Constraints are as important as capabilities) - -**Review mode check** (apply before spawning): -- `solo` → skip this agent spawn. Draft the section without the specialist. Add a note naming them: "`[the Section 6 routing table's Primary and Supporting Agents for this category]` not consulted — Solo mode. Review manually before production." -- `lean` → skip unless this is a section with HIGH implementation risk (Sections D and H only). For other sections, draft without the agent. -- `full` → spawn as described below. - -**Agent delegation (MANDATORY)**: Before drafting Section C, spawn specialist agents via `Agent` in parallel: -- Look up the system category in the routing table (Section 6 of this skill) -- Spawn the Primary Agent AND Supporting Agent(s) listed for this category -- Provide each agent: system name, game concept summary, pillar set, dependency GDD excerpts, the specific section being worked on -- Collect their findings before drafting -- Surface any disagreements between agents to the user via `AskUserQuestion` -- Draft only after receiving specialist input - -**Do NOT draft Section C without first consulting the appropriate specialists.** A `systems-designer` reviewing rules and mechanics will catch design gaps the main session cannot. - -**Cross-reference**: For each interaction listed, verify it matches what the -dependency GDD specifies. If a dependency defines a value or formula and this -system expects something different, flag the conflict. - ---- - -### Section D: Formulas - -**Goal**: Every mathematical formula, with variables defined, ranges specified, -and edge cases noted. - -**Completion Steering — always begin each formula with this exact structure:** - -``` -The [formula_name] formula is defined as: - -`[formula_name] = [expression]` - -**Variables:** -| Variable | Type | Range | Source | Description | -|----------|------|-------|--------|-------------| -| [name] | float/int | [min–max] | data file / calculated / constant | [what it represents] | - -**Output Range:** [min] to [max] under normal play; [behaviour at extremes] -**Example:** [worked example with real numbers] -``` - -Do NOT write `[Formula TBD]` or describe a formula in prose without the variable -table. A formula without defined variables cannot be implemented without guesswork. - -> **These columns must match `templates/game-design-document.md` exactly.** They -> did not: this block said `Symbol` where the template says `Source`, so a -> correctly-authored GDD was wrong against whichever of the two its reader -> happened to hold. `Source` is the column that stays, because it is what carries -> the coding-standards rule *"gameplay values must be data-driven (external -> config), never hardcoded"* into the design document — a variable marked -> `data file` is a tuning knob, one marked `constant` is a deliberate exception, -> and the distinction is invisible under a `Symbol` column. Put a symbol, where -> one helps, in the expression itself. - -**Questions to ask**: -- What are the core calculations this system performs? -- Should scaling be linear, logarithmic, or stepped? -- What should the output ranges be at early/mid/late game? - -**Review mode check** (apply before spawning): -- `solo` → skip this agent spawn. Draft the section without the specialist. Add a note: "`systems-designer` not consulted — Solo mode. Review manually before production." -- `lean` → skip unless this is a section with HIGH implementation risk (Sections D and H only). For other sections, draft without the agent. -- `full` → spawn as described below. - -**Agent delegation (MANDATORY)**: Before proposing any formulas or balance values, spawn specialist agents via `Agent` in parallel: -- **Always spawn `systems-designer`**: provide Core Rules from Section C, tuning goals from user, balance context from dependency GDDs. Ask them to propose formulas with variable tables and output ranges. -- **For economy/cost systems, also spawn `economy-designer`**: provide placement costs, upgrade cost intent, and progression goals. Ask them to validate cost curves and ratios. -- Present the specialists' proposals to the user for review via `AskUserQuestion` -- The user decides; the main session writes to file -- **Do NOT invent formula values or balance numbers without specialist input.** A user without balance design expertise cannot evaluate raw numbers — they need the specialists' reasoning. - -**Cross-reference**: If a dependency GDD defines a formula whose output feeds into -this system, reference it explicitly. Don't reinvent — connect. - ---- - -### Section E: Edge Cases - -**Goal**: Explicitly handle unusual situations so they don't become bugs. - -**Completion Steering — format each edge case as:** -- **If [condition]**: [exact outcome]. [rationale if non-obvious] - -Example (adapt terminology to the game's domain): -- **If [resource] reaches 0 while [protective condition] is active**: hold at minimum until condition ends, then apply consequence. -- **If two [triggers/events] fire simultaneously**: resolve in [defined priority order]; ties use [defined tiebreak rule]. - -Do NOT write vague entries like "handle appropriately" — each must name the exact -condition and the exact resolution. An edge case without a resolution is an open -design question, not a specification. - -**Questions to ask**: -- What happens at zero? At maximum? At out-of-range values? -- What happens when two rules apply at the same time? -- What happens if a player finds an unintended interaction? (Identify degenerate strategies) - -**Review mode check** (apply before spawning): -- `solo` → skip this agent spawn. Draft the section without the specialist. Add a note: "`systems-designer` not consulted — Solo mode. Review manually before production." -- `lean` → skip unless this is a section with HIGH implementation risk (Sections D and H only). For other sections, draft without the agent. -- `full` → spawn as described below. - -**Agent delegation (MANDATORY)**: Spawn `systems-designer` via `Agent` before finalising edge cases. Provide: the completed Sections C and D, and ask them to identify edge cases from the formula and rule space that the main session may have missed. For narrative systems, also spawn `narrative-director`. Present their findings and ask the user which to include. - -**Cross-reference**: Check edge cases against dependency GDDs. If a dependency -defines a floor, cap, or resolution rule that this system could violate, flag it. - ---- - -### Section F: Dependencies - -**Goal**: Map every system connection with direction and nature. - -This section is partially pre-filled from the context gathering phase. Present the -known dependencies from the systems index and ask: -- Are there dependencies I'm missing? -- For each dependency, what's the specific data interface? -- Which dependencies are hard (system cannot function without it) vs. soft - (enhanced by it but works without it)? - -**Cross-reference**: This section must be bidirectionally consistent. If this system -lists "depends on Combat", then the Combat GDD should list "depended on by [this -system]". Flag any one-directional dependencies for correction. - ---- - -### Section G: Tuning Knobs - -**Goal**: Every designer-adjustable value, with safe ranges and extreme behaviors. - -**Questions to ask**: -- What values should designers be able to tweak without code changes? -- For each knob, what breaks if it's set too high? Too low? -- Which knobs interact with each other? (Changing A makes B irrelevant) - -**Review mode check** (apply before spawning): -- `solo` → skip this agent spawn. Derive the knobs from Section D's variable table yourself. Add a note: "`systems-designer` not consulted — Solo mode. Review manually before production." -- `lean` → skip unless Section D defines a formula whose knobs interact (changing one makes another inert). -- `full` → delegate as described below. - -**Agent delegation**: If formulas are complex, delegate to `systems-designer` -to derive tuning knobs from the formula variables. - -> The guard above was missing here while Sections B, C, D, E and H all carried -> one — and this delegation names `systems-designer`, the same agent Section D's -> guard has already told a `solo` run to skip. Read without it, `solo` skips the -> specialist for the formulas and then consults it for the knobs derived from -> those same formulas. - -**Cross-reference**: If a dependency GDD lists tuning knobs that affect this system, -reference them here. Don't create duplicate knobs — point to the source of truth. - ---- - -### Section H: Acceptance Criteria - -**Goal**: Testable conditions that prove the system works as designed. - -**Completion Steering — format each criterion as Given-When-Then:** -- **GIVEN** [initial state], **WHEN** [action or trigger], **THEN** [measurable outcome] - -Example (adapt terminology to the game's domain): -- **GIVEN** [initial state], **WHEN** [player action or system trigger], **THEN** [specific measurable outcome]. -- **GIVEN** [a constraint is active], **WHEN** [player attempts an action], **THEN** [feedback shown and action result]. - -Include at least: one criterion per core rule from Section C, and one per formula -from Section D. Do NOT write "the system works as designed" — every criterion must -be independently verifiable by a QA tester without reading the GDD. - -> **When Section D was not authored** (Formulas optional at this tier because the -> system defines no numeric rule), there are no formulas to cover and the -> criteria come from Section C alone — say so in one line rather than silently -> writing fewer criteria. **If Section D was skipped but Section C states a -> quantity** — a rate, threshold, cost or curve — that is the §1 test being met -> after the fact: stop, tell the user Formulas is required for this system, and -> author it before finalising the criteria. A criterion cannot verify a number -> the GDD never defines. -> -> **That escalation applies at `standard` only.** It re-runs §1's *conditional* -> Formulas test, and §1 disables that conditional at `minimal` outright — *"the -> conditional Formulas rule does NOT re-apply at minimal"*. At `minimal` a -> Section C quantity is expected and does **not** pull Formulas back in: state -> the value inline in Core Rules so it stays implementable, and move on. At -> `full`, Section D is unconditionally required, so the case cannot arise. Read -> without this scope, the two rules contradict each other for any `minimal` -> system that defines a rate — which is most of them. - -**Review mode check** (apply before spawning): -- `solo` → skip this agent spawn. Draft the section without the specialist. Add a note: "`qa-lead` not consulted — Solo mode. Review manually before production." -- `lean` → skip unless this is a section with HIGH implementation risk (Sections D and H only). For other sections, draft without the agent. -- `full` → spawn as described below. - -**Agent delegation (MANDATORY)**: Spawn `qa-lead` via `Agent` before finalising acceptance criteria. Provide: the completed GDD sections C, D, E, and ask them to validate that the criteria are independently testable and cover all core rules and formulas. Surface any gaps or untestable criteria to the user. - -**Questions to ask**: -- What's the minimum set of tests that prove this works? -- What performance budget does this system get? (frame time, memory) -- What would a QA tester check first? - -**Cross-reference**: Include criteria that verify cross-system interactions work, -not just this system in isolation. - ---- - -### Optional Sections: Visual/Audio, Game Feel, UI Requirements, Cross-References, Open Questions - -These five are the template sections that are **not** among §1's eight. They are -governed here, not by the tier: §1's per-tier lists decide the *required* set, -and this block decides the rest independently. Adding a section here therefore -never changes a tier's section count. - -Visual/Audio and Game Feel are **REQUIRED** for some categories — not optional. -Determine the requirement level before asking: - -**Keyed on the `Category` column of `systems-index.md`** — the nine values -`templates/systems-index.md` defines. Every one of the nine appears below -exactly once, so nothing falls through: - -**Visual/Audio is REQUIRED (mandatory — do not offer to skip) for:** -- `Gameplay` — combat, AI, stealth, movement, interaction: everything the player - sees resolve -- `UI` — HUD, menus, inventory screens, dialogue UI -- `Narrative` — dialogue, quests, cutscenes, lore delivery -- `Audio` — by definition - -> **`Gameplay` is the row this table was missing.** It is the category -> `/map-systems` assigns to combat, AI and movement — the largest bucket in most -> action games. If it appears in **neither** this list nor the "all other" list -> below, the skill has no defined behaviour for it and the author has to guess. -> All nine categories must be covered between the two lists. - -For required systems: **spawn `art-director` via `Agent`** before drafting this section. Provide: system name, game concept, game pillars, art bible sections 1–4 if they exist. Ask them to specify: (1) VFX and visual feedback requirements for this system's events, (2) any animation or visual style constraints, (3) which art bible principles most directly apply to this system. Present their output; do NOT leave this section as `[To be designed]` for visual systems. - -**Review mode check** (apply before spawning): -- `solo` → skip this agent spawn. Draft the section without the specialist. Add a note: "`art-director` not consulted — Solo mode. Review manually before production." -- `lean` → skip unless this system's visual feedback is central to it (a `Gameplay` or `UI` system whose events the player reads to play). Otherwise draft without the agent. -- `full` → spawn as described above. - -> Sections B, C, D, E and H each carry this block and this spawn did not, while -> being worded as mandatory (*"do NOT leave this section as `[To be designed]`"*). -> Two agents in `solo` skipped it anyway, on the strength of the other five, and -> both flagged the guess. `director-gates.md`'s *"solo → no director gates -> anywhere"* governs director **gates**, not specialist spawns, so it did not -> settle it — this block does. - -**Game Feel is REQUIRED (mandatory — do not offer to skip) for `Gameplay` and -`UI`** — the categories whose systems the player directly operates, where -responsiveness, weight and snap are design targets rather than polish. It is -optional for the other seven. The template argues the point itself: feel *"drives -animation budgets, input handling architecture, and hitbox timing. Retrofitting -feel targets after implementation is expensive."* - -**Cross-References is REQUIRED whenever the Dependencies section names another -GDD.** The rule is derived, not category-keyed: if this document references -another system's mechanic, value or rule anywhere, that reference belongs in the -table. Where Dependencies names nothing, write *"None — this system references no -other GDD"* rather than leaving the placeholder. `/review-all-gdds` Phase 2c -reads this table when it exists. - -For the remaining five categories — `Core`, `Progression`, `Economy`, -`Persistence`, `Meta` — Visual/Audio is optional: offer the optional sections -after the required sections. - -> **At `minimal`, force nothing.** §1 says a voluntary `minimal` GDD is *"exactly -> the 5 standard sections"*, which contradicts a category rule that makes -> Visual/Audio or Game Feel mandatory. §1 wins: at `minimal` both drop to -> optional and the whole set goes through the widget below. The contradiction is -> real — an agent authoring a `minimal` inventory GDD hit it and had to choose. - -Use `AskUserQuestion`: -- "The required sections for this workflow tier are complete. Which of the - remaining template sections do you want to define?" - - Options: "All of them", "Just Cross-References and open questions", "Skip — I'll add these later" - - List in the question only the ones still outstanding: Visual/Audio, Game - Feel, UI Requirements, Cross-References, Open Questions **minus** any this - system's category or dependencies already made mandatory above. Offering to - skip a section the rules just made required is how a mandatory section gets - skipped. - - **Recommended option**: "All of them" when the system has any dependency, - UI surface or player-facing feedback; "Just Cross-References and open - questions" otherwise. `autonomous` needs a marked recommendation to pick — - the three options previously carried none, unlike the Section A/B widgets, - so an unattended run had nothing to choose by and defaulted to skipping. - - Do **not** state a section count here. The required set is tier-dependent - (§1: 8 at `full`, 5 + conditional Formulas at `standard`, 5 at a voluntary - `minimal`), so the previous hardcoded "8 required sections are complete" was - false on every run below `full` — it told a `standard`-tier user that 8 - sections existed when 6 had been authored. - -For **Visual/Audio** (non-required systems): Coordinate with `art-director` and `audio-director` if detail is needed. Often a brief note suffices at the GDD stage. - -> **Asset Spec Flag**: After the Visual/Audio section is written with real content, output this notice: -> "📌 **Asset Spec** — Visual/Audio requirements are defined. After the art bible is approved, run `/asset-spec system:[system-name]` to produce per-asset visual descriptions, dimensions, and generation prompts from this section." - -For **UI Requirements**: Coordinate with `ux-designer` for complex UI systems. -After writing this section, check whether it contains real content (not just -`[To be designed]` or a note that this system has no UI). If it does have real -UI requirements, output this flag immediately: - -> **📌 UX Flag — [System Name]**: This system has UI requirements. In Phase 4 -> (Pre-Production), run `/ux-design` to create a UX spec for each screen or -> HUD element this system contributes to **before** writing epics. Stories that -> reference UI should cite `design/ux/[screen].md`, not the GDD directly. -> -> Note this in the systems index for this system if you update it. - -For **Open Questions**: Capture anything that came up during design that wasn't -fully resolved. Each question should have an owner and target resolution date. - ---- +**Read `references/4-section-design.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 5. Post-Design Validation -After all sections are written: - -### 5-pre: Author the Summary - -Write `## Summary` and its `> **Quick reference**` line now — after the design -exists, so the summary distils real content rather than intentions. This runs -**at every tier**, including `standard` and a voluntary `minimal` GDD: the -Summary is what lets a later skill scan 20 GDDs and decide which to read in full -(`/create-epics`, `/architecture-review`, `/review-all-gdds` all grep it), so a -GDD without it silently forces those consumers back to full reads. - -- **Summary body**: 2–3 sentences — what this system is, what it does for the - player, why it exists in this game. No jargon; a reader who has not seen the - GDD should learn whether it is relevant to their task. -- **Quick reference**: `Layer` and `Priority` from the systems index - (`design/gdd/systems-index.md`); `Key deps` from the Dependencies section just - written (system names, or `None`). - -Replace the `[To be designed]` Summary placeholder in the skeleton. Then apply -the section cycle's Write step as for any other section. - -### 5a: Self-Check - -Read back the complete GDD from file (not from conversation memory — the file is -the source of truth). Verify: -- The `## Summary` and its Quick reference are populated (not the placeholder) -- Every section **required at this system's effective tier** has real content - (not placeholders) — §1: 8 at `full`, 5 + conditional Formulas at `standard`, - 5 at a voluntary `minimal`. Do not verify against a fixed count of 8: below - `full` that reports a correctly-authored GDD as incomplete, which is the same - error already corrected in the optional-sections prompt above -- Formulas reference defined variables -- Edge cases have resolutions -- Dependencies are listed with interfaces -- Acceptance criteria are testable - -### 5a-bis: Creative Director Pillar Review - -**Review mode check** — apply before spawning CD-GDD-ALIGN: -- `solo` → skip. Note: "CD-GDD-ALIGN skipped — Solo mode." Proceed to Step 5b. -- `lean` → skip (not a PHASE-GATE). Note: "CD-GDD-ALIGN skipped — Lean mode." Proceed to Step 5b. -- `full` → spawn as normal. - -Before finalizing the GDD, spawn `creative-director` via `Agent` using gate **CD-GDD-ALIGN** (`.claude/docs/director-gates/cd-gdd-align.md`). - -Pass: completed GDD file path, game pillars (from `design/gdd/game-concept.md` or `design/gdd/game-pillars.md`; if there is neither, the pitch and "what they feel" line of `design/game-brief.md`), MDA aesthetics target, and the GDD's Player Fantasy section — or, when this tier did not author one, say so. - -Handle verdict per the standard rules in `director-gates.md`. -On `Revise flagged items`, or to resolve a REJECT, each flagged section runs its -section cycle again — its specialist consulted as that section's review-mode -check says — and is re-approved through its "Approve the [Section Name] -section?" widget before the Edit that writes it; then record `REVISED [date]`. -A `NOT ASSESSED` answer is never an approval: name the missing input, then -supply it and re-run the gate, or record `NOT ASSESSED`. -After resolution, record the verdict in the GDD Status header: -`> **Creative Director Review (CD-GDD-ALIGN)**: APPROVED [date] / CONCERNS (accepted) [date] / REVISED [date] / NOT ASSESSED [date] — [missing input]` - ---- - -### 5b: Update Entity Registry - -Scan the completed GDD for cross-system facts that should be registered: -- Named entities (enemies, NPCs, bosses) with stats or drops -- Named items with values, weights, or categories -- Named formulas with defined variables and output ranges -- Named constants referenced by value in more than one place - -**First check the registry exists** — §2a reads it *"if it exists"*, and this -step never carried the same guard. At `standard` and below the file is often -absent, and a grep against a missing path returns nothing, which is -indistinguishable from "no candidate is registered yet": - -- **Absent** — say so, and ask whether to create it: - *"`design/registry/entities.yaml` does not exist. May I create it with these - [N] entries?"* If the user declines, skip 5b and say the registry was not - written — do not treat the skip as a clean pass. -- **Present but empty** — every list is `[]`, or the only matches are inside - comment blocks. Treat it as present, register the candidates, but say which - state you found: *"registry exists and is empty — all [N] entries are new."* - The shipped template's comments carry fully-formed examples referencing - `design/gdd/inventory.md` with real-looking values (`base_inventory_slots: 20`, - `gold_carry_limit: 9999`), so §2a's prescribed - `grep referenced_by.*[system-name]` returns **comment lines** on an empty - registry — and §2d would then present those invented numbers to the user as - *"These values are locked."* Match entries under a live `entities:`/`items:`/ - `formulas:`/`constants:` key, never a commented example. -- **Present** — for each candidate, check whether it is already registered: - -``` -Grep pattern=" - name: [candidate_name]" path="design/registry/entities.yaml" -``` - -Present a summary: -``` -Registry candidates from this GDD: - NEW (not yet registered): - - [entity_name] [entity]: [attribute]=[value], [attribute]=[value] - - [item_name] [item]: [attribute]=[value], [attribute]=[value] - - [formula_name] [formula]: variables=[list], output=[min–max] - ALREADY REGISTERED (referenced_by will be updated): - - [constant_name] [constant]: value=[N] ← matches registry ✅ -``` - -Ask: "May I update `design/registry/entities.yaml` with these [N] new entries -and update `referenced_by` for the existing entries?" (If the file was absent -and the user approved creating it, the wording is *create*, not *update*, and -there are no `referenced_by` arrays to merge.) - -If yes: append new entries and update `referenced_by` arrays. Never modify -existing `value` / attribute fields without surfacing it as a conflict first. - -### 5c: Offer Design Review - -Present a completion summary: - -> **GDD Complete: [System Name]** -> - Sections written: [list] -> - Provisional assumptions: [list any assumptions about undesigned dependencies] -> - Cross-system conflicts found: [list or "none"] - -> **To validate this GDD, open a fresh Claude Code session and run:** -> `/design-review design/gdd/[system-name].md` -> -> **Never run `/design-review` in the same session as `/design-system`.** The reviewing -> agent must be independent of the authoring context. Running it here would inherit -> the full design history, making independent critique impossible. - -**NEVER offer to run `/design-review` inline.** Always direct the user to a fresh window. - -### 5d: Update Systems Index - -After the GDD is complete (and optionally reviewed): - -**First check the systems index exists.** §2a skips it at `minimal` because it is -never written at that tier, and this step never carried the same guard — the same -class of bug §5b was patched for. It bites hardest on a `minimal` project with a -`system_overrides` bump, where the effective tier is `standard` or `full` and -nothing else in §5 hints the file may be absent. - -- **Absent** — say so in one line (*"no `design/gdd/systems-index.md` at this - workflow tier; nothing to update"*) and skip to §5e. Do **not** offer to create - one: `/map-systems` owns that file, and a stub written here would be a systems - index listing exactly one system. -- **Present** — continue: - -- Read the systems index -- Update the target system's row: - - If design-review was run and verdict is APPROVED: Status → "Approved" - - If design-review was run and verdict is NEEDS REVISION or MAJOR REVISION NEEDED: Status → "Needs Revision" (that exact string — `/design-review` sets "In Review" only once the revisions are applied) - - If design-review was skipped: Status → "Designed" (pending review) - - If the user chose "I'll review it myself first": Status → "Designed" - - Design Doc: link to `design/gdd/[system-name].md` -- Update the Progress Tracker counts - -Ask: "May I update the systems index at `design/gdd/systems-index.md`?" - -### 5e: Update Session State - -Update `production/session-state/active.md` with: -- Task: [system-name] GDD -- Status: Complete (or In Review if design-review was run) -- File: design/gdd/[system-name].md -- Sections: [list the sections actually authored, by name] — **never a fixed - count**; §5a forbids verifying against `/8`, and the same reasoning applies to - recording it. Below `full` a correctly-authored GDD has fewer than 8 sections, - and writing "All 8 written" into session state makes the next reader believe - a complete GDD is incomplete -- Next: [suggest next system from design order] - -### 5f: Suggest Next Steps - -Use `AskUserQuestion`: -- "What's next?" - - Options: - - "Run `/consistency-check` — verify this GDD's values don't conflict with existing GDDs (recommended before designing the next system)" - - "Design next system ([next-in-order])" — if undesigned systems remain - - "Fix review findings" — if design-review flagged issues - - "Stop here for this session" - - "Run `/gate-check`" — if enough MVP systems are designed - ---- +**Read `references/5-post-design.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 6. Specialist Agent Routing diff --git a/.claude/skills/design-system/references/1-parse-arguments.md b/.claude/skills/design-system/references/1-parse-arguments.md new file mode 100644 index 00000000..5143cd2a --- /dev/null +++ b/.claude/skills/design-system/references/1-parse-arguments.md @@ -0,0 +1,124 @@ +# /design-system — Phase 1: Parse Arguments & Validate + +> Part of `/design-system`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 1. Parse Arguments & Validate + +**In this file:** + +- `docs.density` +- No system name given: the systems index picks the next one +- Detect retrofit mode +- `workflow` for this system, and `## Summary` at every tier + +See `.claude/docs/director-gates.md` for the full check pattern. Individual gate definitions live in `.claude/docs/director-gates/[gate-id].md` — the spawned agent reads its own gate file; do not read it in the parent session. + + +Every `AskUserQuestion` call follows `.claude/docs/automation-modes.md` +(collaborative asks always · guided major-only · autonomous logs and proceeds; +`automation_always_ask` categories always prompt). + +**`docs.density`** — it controls per-section *depth*, where `workflow` +controls which sections exist. `modes.rigor` sets both together; set +`docs.density` explicitly to vary depth alone: `terse` (the default, via `rigor: minimal`) = bullet points, 2–5 lines per section, +skip rationale and preambles; `balanced` = paragraphs with light rationale +(`rigor: standard`); `thorough` = full prose with rationale, examples, and alternatives +considered. Apply it to every section you author. Mandated structures (the +Formulas variable table, Given-When-Then acceptance criteria) are correctness +requirements at every density — `terse` trims the surrounding prose, never the +required structure itself. + +A system name or retrofit path is **required**. If missing: + +1. Check if `design/gdd/systems-index.md` exists. +2. If it exists: read it, find the highest-priority system with status "Not Started" or equivalent, and use `AskUserQuestion`: + - Prompt: "The next system in your design order is **[system-name]** ([priority] | [layer]). Start designing it?" + - Options: `[A] Yes — design [system-name]` / `[B] Pick a different system` / `[C] Stop here` + - If [A]: proceed with that system name. If [B]: ask which system to design (plain text). If [C]: exit. +3. If no systems index exists, fail with: + > "Usage: `/design-system ` — e.g., `/design-system movement` + > Or to fill gaps in an existing GDD: `/design-system retrofit design/gdd/[system-name].md` + > No systems index found. Run `/map-systems` first to map your systems and get the design order." + +**Detect retrofit mode:** +If the argument starts with `retrofit` or the argument is a file path to an +existing `.md` file in `design/gdd/`, enter **retrofit mode**: + +1. Read the existing GDD file. +2. Identify which of the 8 **possible** sections are present (scan for section + headings): Overview, Player Fantasy, Detailed Design/Rules, Formulas, + Edge Cases, Dependencies, Tuning Knobs, Acceptance Criteria. + **Which of them are *required* depends on the effective tier** (§1) — at + `standard` only 5 are, plus Formulas for math categories, and Player Fantasy + and Tuning Knobs are skipped **by design**. Report an absent section as a gap + only when the tier requires it; otherwise list it as available-to-add. Calling + all 8 required here reports two by-design-absent sections as gaps on every + `standard` project. +3. Identify which sections contain only placeholder text (`[To be designed]` or + equivalent — blank, a single line, or obviously incomplete). +4. Present to the user before doing anything: + ``` + ## Retrofit: [System Name] + File: design/gdd/[filename].md + + Sections already written (will not be touched): + ✓ [section name] + ✓ [section name] + + Missing or incomplete sections (will be authored): + ✗ [section name] — missing + ✗ [section name] — placeholder only + ``` +5. Ask: "Shall I fill the [N] missing sections? I will not modify any existing content." +6. If yes: proceed to **Phase 2 (Gather Context)** as normal, but in **Phase 3** + skip creating the skeleton (file already exists) and in **Phase 4** skip + sections that are already complete. Only run the section cycle for missing/ + incomplete sections. +7. **Never overwrite existing section content.** Use Edit tool to replace only + `[To be designed]` placeholders or empty section bodies. + +If NOT in retrofit mode, normalize the system name to kebab-case for the +filename (e.g., "combat system" becomes `combat-system`). + +**`workflow`** for this system (per `.claude/docs/workflow-modes.md`) — use the +`system_overrides` row for this system if the block lists one, else the project +value. + +The resolved tier determines which GDD sections are **required** (applied in §4). +**`## Summary` is required at every tier and is not one of the 8** — §5-pre +authors it unconditionally (*"This runs at every tier"*), but it appeared in none +of the per-tier lists below, and these lists are what other skills and gates +apply. A GDD checked against a tier list alone would pass with no Summary, the +one section `/review-all-gdds` and the tiered-loading readers depend on. Read +every list below as "`## Summary`, plus:". +- `full` — all 8 sections +- `standard` — Overview, Detailed Design, Edge Cases, Dependencies, Acceptance + Criteria (5 required); **Formulas conditional** — required when the system + **defines numeric rules**: rates, curves, thresholds, costs, damage, drop + weights, or any value a balance pass would tune. Optional only when the system + defines no such value. **The `Category` in `systems-index.md` is a hint, not + the test** — `Gameplay`, `Economy` and `Progression` systems almost always + qualify, and a `Core`, `UI` or `Persistence` system that defines a numeric rule + qualifies too. If the Detailed Design states a quantity that is not a constant + of the engine, Formulas is required. **Player Fantasy and Tuning Knobs skipped** + unless `workflow_overrides` force them (`tuning_knobs: true` forces Tuning Knobs) + + > **Do not gate this on a category token.** A rule of the form "required when + > the system category is combat / economy / progression / AI" does not work: + > those four tokens are not what `/map-systems` writes — `templates/systems-index.md` + > defines the categories as `Core · Gameplay · Progression · Economy · + > Persistence · UI · Audio · Narrative · Meta` and lists **combat and AI as + > example systems under `Gameplay`**. A combat system categorised exactly as the + > template instructs matches none of the four, and Formulas would be dropped for + > the system most likely to need it. +- `minimal` — a GDD is not required (the game brief replaces it). If invoked + voluntarily at minimal, author exactly the 5 standard sections (Overview, + Detailed Design, Edge Cases, Dependencies, Acceptance Criteria) — the + conditional Formulas rule does NOT re-apply at minimal — and tell the user + the GDD is optional at this workflow level. + +Retrofit mode is unaffected — it fills whatever sections are missing regardless +of tier. + +--- diff --git a/.claude/skills/design-system/references/2-gather-context.md b/.claude/skills/design-system/references/2-gather-context.md new file mode 100644 index 00000000..0ddd1161 --- /dev/null +++ b/.claude/skills/design-system/references/2-gather-context.md @@ -0,0 +1,244 @@ +# /design-system — Phase 2: Gather Context + +> Part of `/design-system`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 2. Gather Context (Read Phase) + +**In this file:** + +- 2a: Required Reads +- 2b: Dependency Reads +- 2c: Optional Reads +- 2d: Present Context Summary +- 2e: Technical Feasibility Pre-Check + +Read all relevant context **before** asking the user anything. This is the skill's +primary advantage over ad-hoc design — it arrives informed. + +### 2a: Required Reads + +> **At `minimal`** (design-system is voluntary at this tier): read +> `design/game-brief.md` in place of the game concept, and **skip the systems-index +> read** — neither `game-concept.md` nor `systems-index.md` exists at `minimal`. +> Author from the brief's relevant MVP feature and its core loop. +> +> **This callout keys on the PROJECT tier, not this system's effective tier.** +> The two differ whenever `workflow_overrides.system_overrides` bumps one system +> above a `minimal` project — the configuration `.claude/docs/settings-guidance.md` +> advertises as the reason the override exists ("bump one deep system"). Those two +> files are absent because the *project* is `minimal`; raising *this system* to +> `standard` or `full` does not create them. So on a `minimal` project, take this +> branch **even for an overridden system**, and read the brief. +> +> The effective tier still governs everything downstream — the required section +> set (§1), the skeleton (§3), the section cycle (§4) and §5a. Only the +> required-*reads* branch here follows the project tier. +> +> **Then derive `Category`, `Layer` and `Priority` from the brief, once, here.** +> Six later steps are keyed on the systems index you just skipped — §2e's engine +> domain, Section A's and Section B's recommended options, the Visual/Audio +> REQUIRED table, §6 specialist routing, and §5-pre's Quick reference — and none +> of them has an absent-index branch. An overridden system reaches all six at +> `standard` or `full`, so "skip the index" leaves them with no input at all. +> Derive from the brief instead: +> +> - **`Category`** — one of the nine in `templates/systems-index.md` +> (`Core · Gameplay · Progression · Economy · Persistence · UI · Audio · +> Narrative · Meta`), chosen from what the brief says the system *does*. +> - **`Layer`** — `Foundation` if other systems depend on it, else `Feature`. +> - **`Priority`** — `MVP` if the brief's build order lists it, else `Post-MVP`. +> +> Carry all three for the rest of the run and treat them as the index's answer. +> **Mark them inferred** in §5-pre's Quick reference (*"Category: Gameplay +> (inferred from the brief — no systems index at this tier)"*) so a later reader +> does not mistake a derivation for an indexed fact. Do **not** write a systems +> index to hold them: `/map-systems` owns that file (§5d). +> +> Read literally without this rule, an overridden system resolves to `full`, falls +> through to the fail-fast reads below, and aborts with *"No game concept found. +> Run `/brainstorm` first"* — killing the escape hatch on step one of the very +> configuration it was built for. + +- **Game concept**: Read `design/gdd/game-concept.md` — fail if missing: + > "No game concept found. Run `/brainstorm` first." +- **Systems index**: Read `design/gdd/systems-index.md` — fail if missing: + > "No systems index found. Run `/map-systems` first to map your systems." +- **Target system**: Find the system in the index. If not listed, warn: + > "[system-name] is not in the systems index. Would you like to add it, or + > design it as an off-index system?" +- **Entity registry**: If `design/registry/entities.yaml` exists, grep it for + the entries this system owns and the entries that reference it: + ``` + Grep pattern="source: design/gdd/[system-name].md" path="design/registry/entities.yaml" output_mode="content" -A 6 + Grep pattern="design/gdd/[system-name].md" path="design/registry/entities.yaml" output_mode="content" -B 8 + ``` + `referenced_by:` is a block list (the key and its paths are on separate + lines), so match the path with `-B 8` context to see the owning entry; a + `referenced_by.*[system-name]` one-liner never matches it. Hold these + in context as **known facts** — values that other GDDs have already + established and this GDD must not contradict. +- **Reflexion log**: Read `docs/consistency-failures.md` if it exists. + Extract entries whose Domain matches this system's category. These are + recurring conflict patterns — present them under "Past failure patterns" + in the Phase 2d context summary so the user knows where mistakes have + occurred before in this domain. + +### 2b: Dependency Reads + +From the systems index, identify: +- **Upstream dependencies**: Systems this one depends on (decisions this system + must respect). +- **Downstream dependents**: Systems that depend on this one (expectations this + system must satisfy). + +For each dependency GDD that exists, read **only the four sections that carry the +cross-system contract** — not the whole GDD: +``` +Grep pattern="^## ([0-9]+\. )?(Dependencies|Formulas|Edge Cases|Tuning Knobs)" glob="design/gdd/[dep].md" output_mode="content" -A 20 +``` +- Key interfaces and data flow (from Dependencies) +- Formulas that reference this system's outputs +- Edge cases that assume this system's behavior +- Tuning knobs that feed into this system + +Much of this is already in `entities.yaml` (loaded in 2a) — the registry's +`formula_map`/`constant_map` carry the owned values with their `source:`. Use the +registry first; the section grep fills what it does not hold. + +### 2c: Optional Reads + +- **Game pillars**: Read `design/gdd/game-pillars.md` if it exists +- **Existing GDD**: Read `design/gdd/[system-name].md` if it exists (resume, don't + restart from scratch) +- **Related systems**: do **not** glob-and-read `design/gdd/*.md` hunting for + "thematically related" systems — there is no deterministic proxy for that and it + is the read the registry exists to replace. `entities.yaml` (2a) already holds + the cross-system facts a related GDD would supply. If a specific overlap is + known, treat it as a dependency above and section-grep it; otherwise rely on the + registry. + +### 2d: Present Context Summary + +Before starting design work, present a brief summary to the user: + +> **Designing: [System Name]** +> - Priority: [from index] | Layer: [from index] +> - Depends on: [list, noting which have GDDs vs. undesigned] +> - Depended on by: [list, noting which have GDDs vs. undesigned] +> - Existing decisions to respect: [key constraints from dependency GDDs] +> - Pillar alignment: [which pillar(s) this system primarily serves] +> - **Known cross-system facts (from registry):** +> - [entity_name]: [attribute]=[value], [attribute]=[value] (owned by [source GDD]) +> - [item_name]: [attribute]=[value], [attribute]=[value] (owned by [source GDD]) +> - [formula_name]: variables=[list], output=[min–max] (owned by [source GDD]) +> - [constant_name]: [value] [unit] (owned by [source GDD]) +> *(These values are locked — if this GDD needs different values, surface +> the conflict before writing. Do not silently use different numbers.)* +> +> If no registry entries are relevant: omit the "Known cross-system facts" section. + +If any upstream dependencies are undesigned, warn: +> "[dependency] doesn't have a GDD yet. We'll need to make assumptions about +> its interface. Consider designing it first, or we can define the expected +> contract and flag it as provisional." + +### 2e: Technical Feasibility Pre-Check + +Before asking the user to begin designing, load engine context and surface any +constraints or knowledge gaps that will shape the design. + +**Step 1 — Determine the engine domain for this system:** +Map the system's category (from systems-index.md) to an engine domain: + +Keyed on the `Category` column of `systems-index.md`. All nine categories +`templates/systems-index.md` defines appear here; where a category spans several +engine domains, pick the row matching what the system actually does and say +which you picked. + +| `Category` | Engine Domain | +|-----------|--------------| +| `Gameplay` | **Physics** for combat / collision / movement; **Navigation** for AI and pathfinding; **Scripting** for rule-only systems with no engine surface | +| `Core` | **Core** — scene management, state, resource loading; **Input** for controls and keybinding | +| `UI` | UI | +| `Audio` | Audio | +| `Narrative` | Scripting — dialogue, quests, cutscenes | +| `Progression` | Scripting — save-adjacent rule logic, no dedicated domain | +| `Economy` | Scripting — data and rule logic, no dedicated domain | +| `Persistence` | Core — save/load, settings, serialization | +| `Meta` | Core — analytics, tutorials, accessibility plumbing | + +> Animation, Rendering and Networking are engine domains with no category of +> their own: a system needing them will be `Gameplay` or `Core`. Name the domain +> you read the reference for, whichever row you came in on. + +**Step 2 — Read engine context (if available):** +- Identify the engine and version: read `engine.name` and `engine.version` from `project.yaml`. Resolve each field independently — if its key is absent or empty (including when `project.yaml` has no `engine:` block), fall back to `.claude/docs/technical-preferences.md` (a `[TO BE CONFIGURED]` value means not set) +- If engine is configured, read `docs/engine-reference/[engine]/VERSION.md` +- Read `docs/engine-reference/[engine]/modules/[domain].md` if it exists. + **If it does not exist, say so by name** — *"no engine reference for `[domain]` + under `docs/engine-reference/[engine]/modules/`; feasibility not checked against + the pinned engine"* — and carry that into §5-pre. A silent skip here is + indistinguishable from a feasibility check that ran and found nothing wrong, + which is the failure `.claude/rules/skill-authoring.md` obligation 3 exists to + stop. + + > **This is not a rare branch.** The domain table above names `Scripting` and + > `Core` for five of the nine categories (`Narrative`, `Progression`, `Economy` + > → Scripting; `Persistence`, `Meta` → Core), plus a sub-row each under + > `Gameplay` and `Core`. The Godot reference ships `animation, audio, input, + > navigation, networking, physics, rendering, ui` — **there is no + > `scripting.md` and no `core.md`**. So the majority of non-`Gameplay` systems + > hit the absent branch every time, and `if it exists` turned that into + > silence. Either the reference gains those two files or the check reports it; + > until the former, do the latter. +- Read `docs/engine-reference/[engine]/breaking-changes.md` for domain-relevant entries +- Find the domain-matching ADRs without reading every ADR to learn the field you + filter on — grep the Domain field first, then read only the matches: + ``` + Grep pattern="\*\*Domain\*\*" glob="docs/architecture/adr-*.md" output_mode="content" + ``` + Read only the ADRs whose Domain matches this system's category (its `## Decision` + and `## Engine Compatibility` sections); skip the rest. + +**Step 3 — Present the Feasibility Brief:** + +If engine reference docs exist, present before starting design: + +``` +## Technical Feasibility Brief: [System Name] +Engine: [name + version] +Domain: [domain] + +### Known Engine Capabilities (verified for [version]) +- [capability relevant to this system] +- [capability 2] + +### Engine Constraints That Will Shape This Design +- [constraint from engine-reference or existing ADR] + +### Knowledge Gaps (verify before committing to these) +- [post-cutoff feature this design might rely on — mark HIGH/MEDIUM risk] + +### Existing ADRs That Constrain This System +- ADR-XXXX: [decision summary] — means [implication for this GDD] + (or "None yet") +``` + +If no engine reference docs exist (engine not yet configured), show a short note: +> "No engine configured yet — skipping technical feasibility check. Run +> `/setup-engine` before moving to architecture if you haven't already." + +**Step 4 — Ask before proceeding:** + +Use `AskUserQuestion`: +- "Any constraints to add before we begin, or shall we proceed with these noted?" + - Options: "Proceed with these noted", "Add a constraint first", "I need to check the engine docs — pause here" + +--- + +Use `AskUserQuestion`: +- "Ready to start designing [system-name]?" + - Options: "Yes, let's go", "Show me more context first", "Design a dependency first" + +--- diff --git a/.claude/skills/design-system/references/3-file-skeleton.md b/.claude/skills/design-system/references/3-file-skeleton.md new file mode 100644 index 00000000..99b92ec3 --- /dev/null +++ b/.claude/skills/design-system/references/3-file-skeleton.md @@ -0,0 +1,134 @@ +# /design-system — Phase 3: Create File Skeleton + +> Part of `/design-system`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 3. Create File Skeleton + +**In this file:** + +- Which sections to scaffold at the resolved tier +- The GDD skeleton +- Writing the file, then the session state update + +Once the user confirms, **immediately** create the GDD file with empty section +headers. This ensures incremental writes have a target. + +**Scaffold only the sections required at the resolved tier** (§1): at +`standard`, omit Player Fantasy and Tuning Knobs (and Formulas only when the +system defines no numeric rule — see §1; the category is a hint, not the test); +at `full`, scaffold all 8. +**Only the sections §1 named as omitted are skipped** — do not leave empty +`[To be designed]` placeholders for those. Every other section in the template +is scaffolded with its placeholder, including the ones §4 has not decided yet. +This sentence governs the three tier omissions above (Player Fantasy, Tuning +Knobs, and Formulas when no numeric rule exists) and nothing else: it is not a +licence to strip a section because it looks optional, and §4 cannot fill a +section §3 never created. + +Use the template structure from `.claude/docs/templates/game-design-document.md`: + +```markdown +# [System Name] + +> **Status**: In Design +> **Author**: [user + agents] +> **Last Updated**: [today's date] +> **Last Verified**: [today's date] +> **Implements Pillar**: [from context] + +## Summary + +[To be designed] + +> **Quick reference** — Layer: `[Foundation | Core | Feature | Presentation]` · Priority: `[MVP | Vertical Slice | Alpha | Full Vision]` · Key deps: `[System names or "None"]` + +## Overview + +[To be designed] + +## Player Fantasy + +[To be designed] + +## Detailed Design + +### Core Rules + +[To be designed] + +### States and Transitions + +[To be designed] + +### Interactions with Other Systems + +[To be designed] + +## Formulas + +[To be designed] + +## Edge Cases + +[To be designed] + +## Dependencies + +[To be designed] + +## Tuning Knobs + +[To be designed] + +## Visual/Audio Requirements + +[To be designed] + +## Game Feel + +[To be designed] + +## UI Requirements + +[To be designed] + +## Cross-References + +[To be designed] + +## Acceptance Criteria + +[To be designed] + +## Open Questions + +[To be designed] +``` + +> **This skeleton and the template must stay identical in section set and +> order.** They diverged once and it was invisible: the skeleton omitted +> `## Game Feel` and `## Cross-References`, so §3's own rule — *"§4 cannot fill a +> section §3 never created"* — made both unreachable **at every tier, `full` +> included**, while §3's prose above still said *"every other section in the +> template is scaffolded"*. Two agents authoring a combat GDD noticed the gap +> only by opening the template. If you add a section to one file, add it to the +> other in the same commit. + +Ask: "May I create the skeleton file at `design/gdd/[system-name].md`?" + +If the user declines: Stop with the following message: +> "Verdict: **BLOCKED** — skeleton creation declined. The design session cannot proceed without the skeleton file, as all subsequent phases use it as the base. Re-run `/design-system [system]` when ready to create the file." +Do not proceed to Section A. + +After writing, update `production/session-state/active.md`: +- Use Glob to check if the file exists. +- If it **does not exist**: use the **Write** tool to create it. Never attempt Edit on a file that may not exist. +- If it **already exists**: use the **Edit** tool to update the relevant fields. + +File content: +- Task: Designing [system-name] GDD +- Current section: Starting (skeleton created) +- File: design/gdd/[system-name].md + +--- diff --git a/.claude/skills/design-system/references/4-section-design.md b/.claude/skills/design-system/references/4-section-design.md new file mode 100644 index 00000000..a152a9b1 --- /dev/null +++ b/.claude/skills/design-system/references/4-section-design.md @@ -0,0 +1,527 @@ +# /design-system — Phase 4: Section-by-Section Design + +> Part of `/design-system`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 4. Section-by-Section Design + +**In this file:** + +- The Section Cycle +- Section-Specific Guidance +- Section A: Overview +- Section B: Player Fantasy +- Section C: Detailed Design (Core Rules, States, Interactions) +- Section D: Formulas +- Section E: Edge Cases +- Section F: Dependencies +- Section G: Tuning Knobs +- Section H: Acceptance Criteria +- Optional Sections: Visual/Audio, Game Feel, UI Requirements, Cross-References, Open Questions + +**Author only the sections required at the resolved tier** (§1). At `standard`, +the walk covers A (Overview), C (Detailed Design), E (Edge Cases), +F (Dependencies), H (Acceptance Criteria) — plus D (Formulas) when the system +defines numeric rules (see §1; the category is a hint, not the test); skip B (Player Fantasy) and +G (Tuning Knobs) unless `workflow_overrides.tuning_knobs: true` forces G. At +`full`, walk all eight (A–H). At `minimal`, the GDD is optional — if authoring +voluntarily, walk the standard set. Any `system_overrides.` tier was +already folded into the resolved tier in §1. + +Walk through each required section in order. For **each section**, follow this cycle: + +### The Section Cycle + +``` +Context -> Questions -> Options -> Decision -> Draft -> Approval -> Write +``` + +1. **Context**: State what this section needs to contain, and surface any relevant + decisions from dependency GDDs that constrain it. + +2. **Questions**: Ask clarifying questions specific to this section. Use + `AskUserQuestion` for constrained questions, conversational text for open-ended + exploration. + +3. **Options**: Where the section involves design choices (not just documentation), + present 2-4 approaches with pros/cons. Explain reasoning in conversation text, + then use `AskUserQuestion` to capture the decision. + +4. **Decision**: User picks an approach or provides custom direction. + +5. **Draft**: Write the section content in conversation text for review. Flag any + provisional assumptions about undesigned dependencies. + +6. **Approval**: Per the resolved `modes.automation` mode + (`.claude/docs/automation-modes.md`): + + **In `collaborative` mode**: Immediately after the draft — in the SAME + response — use `AskUserQuestion`. **NEVER use plain text. NEVER skip + this step.** + - Prompt: "Approve the [Section Name] section?" + - Options: `[A] Approve — write it to file` / `[B] Make changes — describe what to fix` / `[C] Start over` + + **The draft and the approval widget MUST appear together in one response. + If the draft appears without the widget, the user is left at a blank prompt + with no path forward — this is a protocol violation in collaborative mode.** + + **In `guided` mode**: Write the section immediately after the draft with + a brief one-line summary of what was decided. Skip the per-section widget; + the multi-section authoring rule (no per-section confirmation) applies. + + **In `autonomous` mode**: Write the section directly and call + `log_decision` with `Decision point: Approve [Section Name] section`, + `Chosen: [A] Approve`, `Category: minor`. + +7. **Write**: Use the Edit tool to replace the placeholder with the approved content. + **CRITICAL**: Always include the section heading in the `old_string` to ensure + uniqueness — never match `[To be designed]` alone, as multiple sections use the + same placeholder and the Edit tool requires a unique match. Use this pattern: + ``` + old_string: "## [Section Name]\n\n[To be designed]" + new_string: "## [Section Name]\n\n[approved content]" + ``` + Confirm the write. + +8. **Registry conflict check** (Sections C and D only — Detailed Design and Formulas): + After writing, scan the section content for entity names, item names, formula + names, and numeric constants that appear in the registry. For each match: + - Compare the value just written against the registry entry. + - If they differ: **surface the conflict immediately** before starting the next + section. Do not continue silently. + > "Registry conflict: [name] is registered in [source GDD] as [registry_value]. + > This section just wrote [new_value]. Which is correct?" + - If new (not in registry): flag it as a candidate for registry registration + (will be handled in Phase 5). + +After writing each section, update `production/session-state/active.md` with the +completed section name. Use Glob to check if the file exists — use Write to create +it if absent, Edit to update it if present. + +### Section-Specific Guidance + +Each section has unique design considerations and may benefit from specialist agents: + +**Every skipped spawn is announced.** When a section's review-mode check below +skips its specialist — in `lean` as well as `solo` — print that section's note +with the mode it ran in, e.g. "`creative-director` not consulted — Lean mode. +Review manually before production." A section drafted without its specialist +must say so in the output, whichever mode skipped it. + +--- + +### Section A: Overview + +**Goal**: One paragraph a stranger could read and understand. + +**Derive recommended options before building the widget**: Read the system's category and layer from the systems index (already in context from Phase 2), then determine the recommended option for each tab: +- **Framing tab**: keyed on the `Category` column (`Core · Gameplay · Progression · Economy · Persistence · UI · Audio · Narrative · Meta`). Player-facing — `Gameplay`, `UI`, `Audio`, `Narrative` → `[C] Both` recommended. Internal — `Core`, `Persistence`, `Meta` → `[A]` recommended. Mixed — `Economy`, `Progression` → `[C] Both`. **Tiebreak, when Layer and Category disagree** (a `Foundation`-layer `Gameplay` system is the common case): **Category wins** — the framing describes what the section is *about*, and a player-facing system stays player-facing wherever it sits in the dependency graph. +- **ADR ref tab**: Glob `docs/architecture/adr-*.md` and grep for the system name in the GDD Requirements section of any ADR. If a matching ADR is found → `[A] Yes — cite the ADR` recommended. If none found → `[B] No` recommended. +- **Fantasy tab**: Foundation/Infrastructure layer → `[B] No` recommended. All other categories → `[A] Yes` recommended. + +Append `(Recommended)` to the appropriate option text in each tab. + +**Framing questions (ask BEFORE drafting)**: Use `AskUserQuestion` with a multi-tab widget: +- Tab "Framing" — "How should the overview frame this system?" Options: `[A] As a data/infrastructure layer (technical framing)` / `[B] Through its player-facing effect (design framing)` / `[C] Both — describe the data layer and its player impact` +- Tab "ADR ref" — "Should the overview reference the existing ADR for this system?" Options: `[A] Yes — cite the ADR for implementation details` / `[B] No — keep the GDD at pure design level` +- Tab "Fantasy" — "Does this system have a player fantasy worth stating?" Options: `[A] Yes — players feel it directly` / `[B] No — pure infrastructure, players feel what it enables` + +Use the answers to shape the draft. **In `collaborative` mode, do NOT answer +these questions yourself and auto-draft** — the widget must appear. In `guided` +and `autonomous`, this is a MINOR framing decision: select the recommended +option derived above, state it in one line, and proceed (that is the whole +point of pre-deriving recommendations). Applies to every "ask BEFORE drafting" +widget in this section walk, not just this one. + +**Questions to ask**: +- What is this system in one sentence? +- How does a player interact with it? (active/passive/automatic) +- Why does this system exist — what would the game lose without it? + +**Cross-reference**: Check that the description aligns with how the systems index +describes it. Flag discrepancies. + +**Design vs. implementation boundary**: Overview questions must stay at the behavior +level — what the system *does*, not *how it is built*. If implementation questions +arise during the Overview (e.g., "Should this use an Autoload singleton or a signal +bus?"), note them as "→ becomes an ADR" and move on. Implementation patterns belong +in `/architecture-decision`, not the GDD. The GDD describes behavior; the ADR +describes the technical approach used to achieve it. + +--- + +### Section B: Player Fantasy + +**Goal**: The emotional target — what the player should *feel*. + +**Derive recommended option before building the widget**: Read the system's category and layer from Phase 2 context: +Keyed on the `Category` column (`Core · Gameplay · Progression · Economy · Persistence · UI · Audio · Narrative · Meta`): +- Player-facing — `Gameplay`, `UI`, `Audio`, `Narrative` → `[A] Direct` recommended +- Internal — `Core`, `Persistence`, `Meta` → `[B] Indirect` recommended +- Mixed — `Economy`, `Progression` → `[C] Both` recommended + +**When Layer and Category disagree, Category wins** — same tiebreak as the +Framing tab above. + +Append `(Recommended)` to the appropriate option text. + +**Framing question (ask BEFORE drafting)**: Use `AskUserQuestion`: +- Prompt: "Is this system something the player engages with directly, or infrastructure they experience indirectly?" +- Options: `[A] Direct — player actively uses or feels this system` / `[B] Indirect — player experiences the effects, not the system` / `[C] Both — has a direct interaction layer and infrastructure beneath it` + +Use the answer to frame the Player Fantasy section appropriately. Do NOT assume the answer. + +**Questions to ask**: +- What emotion or power fantasy does this serve? +- What reference games nail this feeling? What specifically creates it? +- Is this a "system you love engaging with" or "infrastructure you don't notice"? + +**Cross-reference**: Must align with the game pillars. If the system serves a pillar, +quote the relevant pillar text. + +**Review mode check** (apply before spawning): +- `solo` → skip this agent spawn. Draft the section without the specialist. Add a note: "`creative-director` not consulted — Solo mode. Review manually before production." +- `lean` → skip unless this is a section with HIGH implementation risk (Sections D and H only). For other sections, draft without the agent. +- `full` → spawn as described below. + +**Agent delegation (MANDATORY)**: After the framing answer is given but before drafting, +spawn `creative-director` via `Agent`: +- Provide: system name, framing answer (direct/indirect/both), game pillars, any reference games the user mentioned, the game concept summary +- Ask: "Shape the Player Fantasy for this system. What emotion or power fantasy should it serve? What player moment should we anchor to? What tone and language fits the game's established feeling? Be specific — give me 2-3 candidate framings." +- Collect the creative-director's framings and present them to the user alongside the draft. + +**Do NOT draft Section B without first consulting `creative-director`.** The framing +answer tells us *what kind* of fantasy it is; the creative-director shapes *how it's +described* — tone, language, the specific player moment to anchor to. + +--- + +### Section C: Detailed Design (Core Rules, States, Interactions) + +**Goal**: Unambiguous specification a programmer could implement without questions. + +This is usually the largest section. Break it into sub-sections: + +1. **Core Rules**: The fundamental mechanics. Use numbered rules for sequential + processes, bullets for properties. +2. **States and Transitions**: If the system has states, map every state and + every valid transition. Use a table. +3. **Interactions with Other Systems**: For each dependency (upstream and downstream), + specify what data flows in, what flows out, and who owns the interface. + +**Questions to ask**: +- Walk me through a typical use of this system, step by step +- What are the decision points the player faces? +- What can the player NOT do? (Constraints are as important as capabilities) + +**Review mode check** (apply before spawning): +- `solo` → skip this agent spawn. Draft the section without the specialist. Add a note naming them: "`[the Section 6 routing table's Primary and Supporting Agents for this category]` not consulted — Solo mode. Review manually before production." +- `lean` → skip unless this is a section with HIGH implementation risk (Sections D and H only). For other sections, draft without the agent. +- `full` → spawn as described below. + +**Agent delegation (MANDATORY)**: Before drafting Section C, spawn specialist agents via `Agent` in parallel: +- Look up the system category in the routing table (Section 6 of this skill) +- Spawn the Primary Agent AND Supporting Agent(s) listed for this category +- Provide each agent: system name, game concept summary, pillar set, dependency GDD excerpts, the specific section being worked on +- Collect their findings before drafting +- Surface any disagreements between agents to the user via `AskUserQuestion` +- Draft only after receiving specialist input + +**Do NOT draft Section C without first consulting the appropriate specialists.** A `systems-designer` reviewing rules and mechanics will catch design gaps the main session cannot. + +**Cross-reference**: For each interaction listed, verify it matches what the +dependency GDD specifies. If a dependency defines a value or formula and this +system expects something different, flag the conflict. + +--- + +### Section D: Formulas + +**Goal**: Every mathematical formula, with variables defined, ranges specified, +and edge cases noted. + +**Completion Steering — always begin each formula with this exact structure:** + +``` +The [formula_name] formula is defined as: + +`[formula_name] = [expression]` + +**Variables:** +| Variable | Type | Range | Source | Description | +|----------|------|-------|--------|-------------| +| [name] | float/int | [min–max] | data file / calculated / constant | [what it represents] | + +**Output Range:** [min] to [max] under normal play; [behaviour at extremes] +**Example:** [worked example with real numbers] +``` + +Do NOT write `[Formula TBD]` or describe a formula in prose without the variable +table. A formula without defined variables cannot be implemented without guesswork. + +> **These columns must match `templates/game-design-document.md` exactly.** They +> did not: this block said `Symbol` where the template says `Source`, so a +> correctly-authored GDD was wrong against whichever of the two its reader +> happened to hold. `Source` is the column that stays, because it is what carries +> the coding-standards rule *"gameplay values must be data-driven (external +> config), never hardcoded"* into the design document — a variable marked +> `data file` is a tuning knob, one marked `constant` is a deliberate exception, +> and the distinction is invisible under a `Symbol` column. Put a symbol, where +> one helps, in the expression itself. + +**Questions to ask**: +- What are the core calculations this system performs? +- Should scaling be linear, logarithmic, or stepped? +- What should the output ranges be at early/mid/late game? + +**Review mode check** (apply before spawning): +- `solo` → skip this agent spawn. Draft the section without the specialist. Add a note: "`systems-designer` not consulted — Solo mode. Review manually before production." +- `lean` → skip unless this is a section with HIGH implementation risk (Sections D and H only). For other sections, draft without the agent. +- `full` → spawn as described below. + +**Agent delegation (MANDATORY)**: Before proposing any formulas or balance values, spawn specialist agents via `Agent` in parallel: +- **Always spawn `systems-designer`**: provide Core Rules from Section C, tuning goals from user, balance context from dependency GDDs. Ask them to propose formulas with variable tables and output ranges. +- **For economy/cost systems, also spawn `economy-designer`**: provide placement costs, upgrade cost intent, and progression goals. Ask them to validate cost curves and ratios. +- Present the specialists' proposals to the user for review via `AskUserQuestion` +- The user decides; the main session writes to file +- **Do NOT invent formula values or balance numbers without specialist input.** A user without balance design expertise cannot evaluate raw numbers — they need the specialists' reasoning. + +**Cross-reference**: If a dependency GDD defines a formula whose output feeds into +this system, reference it explicitly. Don't reinvent — connect. + +--- + +### Section E: Edge Cases + +**Goal**: Explicitly handle unusual situations so they don't become bugs. + +**Completion Steering — format each edge case as:** +- **If [condition]**: [exact outcome]. [rationale if non-obvious] + +Example (adapt terminology to the game's domain): +- **If [resource] reaches 0 while [protective condition] is active**: hold at minimum until condition ends, then apply consequence. +- **If two [triggers/events] fire simultaneously**: resolve in [defined priority order]; ties use [defined tiebreak rule]. + +Do NOT write vague entries like "handle appropriately" — each must name the exact +condition and the exact resolution. An edge case without a resolution is an open +design question, not a specification. + +**Questions to ask**: +- What happens at zero? At maximum? At out-of-range values? +- What happens when two rules apply at the same time? +- What happens if a player finds an unintended interaction? (Identify degenerate strategies) + +**Review mode check** (apply before spawning): +- `solo` → skip this agent spawn. Draft the section without the specialist. Add a note: "`systems-designer` not consulted — Solo mode. Review manually before production." +- `lean` → skip unless this is a section with HIGH implementation risk (Sections D and H only). For other sections, draft without the agent. +- `full` → spawn as described below. + +**Agent delegation (MANDATORY)**: Spawn `systems-designer` via `Agent` before finalising edge cases. Provide: the completed Sections C and D, and ask them to identify edge cases from the formula and rule space that the main session may have missed. For narrative systems, also spawn `narrative-director`. Present their findings and ask the user which to include. + +**Cross-reference**: Check edge cases against dependency GDDs. If a dependency +defines a floor, cap, or resolution rule that this system could violate, flag it. + +--- + +### Section F: Dependencies + +**Goal**: Map every system connection with direction and nature. + +This section is partially pre-filled from the context gathering phase. Present the +known dependencies from the systems index and ask: +- Are there dependencies I'm missing? +- For each dependency, what's the specific data interface? +- Which dependencies are hard (system cannot function without it) vs. soft + (enhanced by it but works without it)? + +**Cross-reference**: This section must be bidirectionally consistent. If this system +lists "depends on Combat", then the Combat GDD should list "depended on by [this +system]". Flag any one-directional dependencies for correction. + +--- + +### Section G: Tuning Knobs + +**Goal**: Every designer-adjustable value, with safe ranges and extreme behaviors. + +**Questions to ask**: +- What values should designers be able to tweak without code changes? +- For each knob, what breaks if it's set too high? Too low? +- Which knobs interact with each other? (Changing A makes B irrelevant) + +**Review mode check** (apply before spawning): +- `solo` → skip this agent spawn. Derive the knobs from Section D's variable table yourself. Add a note: "`systems-designer` not consulted — Solo mode. Review manually before production." +- `lean` → skip unless Section D defines a formula whose knobs interact (changing one makes another inert). +- `full` → delegate as described below. + +**Agent delegation**: If formulas are complex, delegate to `systems-designer` +to derive tuning knobs from the formula variables. + +> The guard above was missing here while Sections B, C, D, E and H all carried +> one — and this delegation names `systems-designer`, the same agent Section D's +> guard has already told a `solo` run to skip. Read without it, `solo` skips the +> specialist for the formulas and then consults it for the knobs derived from +> those same formulas. + +**Cross-reference**: If a dependency GDD lists tuning knobs that affect this system, +reference them here. Don't create duplicate knobs — point to the source of truth. + +--- + +### Section H: Acceptance Criteria + +**Goal**: Testable conditions that prove the system works as designed. + +**Completion Steering — format each criterion as Given-When-Then:** +- **GIVEN** [initial state], **WHEN** [action or trigger], **THEN** [measurable outcome] + +Example (adapt terminology to the game's domain): +- **GIVEN** [initial state], **WHEN** [player action or system trigger], **THEN** [specific measurable outcome]. +- **GIVEN** [a constraint is active], **WHEN** [player attempts an action], **THEN** [feedback shown and action result]. + +Include at least: one criterion per core rule from Section C, and one per formula +from Section D. Do NOT write "the system works as designed" — every criterion must +be independently verifiable by a QA tester without reading the GDD. + +> **When Section D was not authored** (Formulas optional at this tier because the +> system defines no numeric rule), there are no formulas to cover and the +> criteria come from Section C alone — say so in one line rather than silently +> writing fewer criteria. **If Section D was skipped but Section C states a +> quantity** — a rate, threshold, cost or curve — that is the §1 test being met +> after the fact: stop, tell the user Formulas is required for this system, and +> author it before finalising the criteria. A criterion cannot verify a number +> the GDD never defines. +> +> **That escalation applies at `standard` only.** It re-runs §1's *conditional* +> Formulas test, and §1 disables that conditional at `minimal` outright — *"the +> conditional Formulas rule does NOT re-apply at minimal"*. At `minimal` a +> Section C quantity is expected and does **not** pull Formulas back in: state +> the value inline in Core Rules so it stays implementable, and move on. At +> `full`, Section D is unconditionally required, so the case cannot arise. Read +> without this scope, the two rules contradict each other for any `minimal` +> system that defines a rate — which is most of them. + +**Review mode check** (apply before spawning): +- `solo` → skip this agent spawn. Draft the section without the specialist. Add a note: "`qa-lead` not consulted — Solo mode. Review manually before production." +- `lean` → skip unless this is a section with HIGH implementation risk (Sections D and H only). For other sections, draft without the agent. +- `full` → spawn as described below. + +**Agent delegation (MANDATORY)**: Spawn `qa-lead` via `Agent` before finalising acceptance criteria. Provide: the completed GDD sections C, D, E, and ask them to validate that the criteria are independently testable and cover all core rules and formulas. Surface any gaps or untestable criteria to the user. + +**Questions to ask**: +- What's the minimum set of tests that prove this works? +- What performance budget does this system get? (frame time, memory) +- What would a QA tester check first? + +**Cross-reference**: Include criteria that verify cross-system interactions work, +not just this system in isolation. + +--- + +### Optional Sections: Visual/Audio, Game Feel, UI Requirements, Cross-References, Open Questions + +These five are the template sections that are **not** among §1's eight. They are +governed here, not by the tier: §1's per-tier lists decide the *required* set, +and this block decides the rest independently. Adding a section here therefore +never changes a tier's section count. + +Visual/Audio and Game Feel are **REQUIRED** for some categories — not optional. +Determine the requirement level before asking: + +**Keyed on the `Category` column of `systems-index.md`** — the nine values +`templates/systems-index.md` defines. Every one of the nine appears below +exactly once, so nothing falls through: + +**Visual/Audio is REQUIRED (mandatory — do not offer to skip) for:** +- `Gameplay` — combat, AI, stealth, movement, interaction: everything the player + sees resolve +- `UI` — HUD, menus, inventory screens, dialogue UI +- `Narrative` — dialogue, quests, cutscenes, lore delivery +- `Audio` — by definition + +> **`Gameplay` is the row this table was missing.** It is the category +> `/map-systems` assigns to combat, AI and movement — the largest bucket in most +> action games. If it appears in **neither** this list nor the "all other" list +> below, the skill has no defined behaviour for it and the author has to guess. +> All nine categories must be covered between the two lists. + +For required systems: **spawn `art-director` via `Agent`** before drafting this section. Provide: system name, game concept, game pillars, art bible sections 1–4 if they exist. Ask them to specify: (1) VFX and visual feedback requirements for this system's events, (2) any animation or visual style constraints, (3) which art bible principles most directly apply to this system. Present their output; do NOT leave this section as `[To be designed]` for visual systems. + +**Review mode check** (apply before spawning): +- `solo` → skip this agent spawn. Draft the section without the specialist. Add a note: "`art-director` not consulted — Solo mode. Review manually before production." +- `lean` → skip unless this system's visual feedback is central to it (a `Gameplay` or `UI` system whose events the player reads to play). Otherwise draft without the agent. +- `full` → spawn as described above. + +> Sections B, C, D, E and H each carry this block and this spawn did not, while +> being worded as mandatory (*"do NOT leave this section as `[To be designed]`"*). +> Two agents in `solo` skipped it anyway, on the strength of the other five, and +> both flagged the guess. `director-gates.md`'s *"solo → no director gates +> anywhere"* governs director **gates**, not specialist spawns, so it did not +> settle it — this block does. + +**Game Feel is REQUIRED (mandatory — do not offer to skip) for `Gameplay` and +`UI`** — the categories whose systems the player directly operates, where +responsiveness, weight and snap are design targets rather than polish. It is +optional for the other seven. The template argues the point itself: feel *"drives +animation budgets, input handling architecture, and hitbox timing. Retrofitting +feel targets after implementation is expensive."* + +**Cross-References is REQUIRED whenever the Dependencies section names another +GDD.** The rule is derived, not category-keyed: if this document references +another system's mechanic, value or rule anywhere, that reference belongs in the +table. Where Dependencies names nothing, write *"None — this system references no +other GDD"* rather than leaving the placeholder. `/review-all-gdds` Phase 2c +reads this table when it exists. + +For the remaining five categories — `Core`, `Progression`, `Economy`, +`Persistence`, `Meta` — Visual/Audio is optional: offer the optional sections +after the required sections. + +> **At `minimal`, force nothing.** §1 says a voluntary `minimal` GDD is *"exactly +> the 5 standard sections"*, which contradicts a category rule that makes +> Visual/Audio or Game Feel mandatory. §1 wins: at `minimal` both drop to +> optional and the whole set goes through the widget below. The contradiction is +> real — an agent authoring a `minimal` inventory GDD hit it and had to choose. + +Use `AskUserQuestion`: +- "The required sections for this workflow tier are complete. Which of the + remaining template sections do you want to define?" + - Options: "All of them", "Just Cross-References and open questions", "Skip — I'll add these later" + - List in the question only the ones still outstanding: Visual/Audio, Game + Feel, UI Requirements, Cross-References, Open Questions **minus** any this + system's category or dependencies already made mandatory above. Offering to + skip a section the rules just made required is how a mandatory section gets + skipped. + - **Recommended option**: "All of them" when the system has any dependency, + UI surface or player-facing feedback; "Just Cross-References and open + questions" otherwise. `autonomous` needs a marked recommendation to pick — + the three options previously carried none, unlike the Section A/B widgets, + so an unattended run had nothing to choose by and defaulted to skipping. + + Do **not** state a section count here. The required set is tier-dependent + (§1: 8 at `full`, 5 + conditional Formulas at `standard`, 5 at a voluntary + `minimal`), so the previous hardcoded "8 required sections are complete" was + false on every run below `full` — it told a `standard`-tier user that 8 + sections existed when 6 had been authored. + +For **Visual/Audio** (non-required systems): Coordinate with `art-director` and `audio-director` if detail is needed. Often a brief note suffices at the GDD stage. + +> **Asset Spec Flag**: After the Visual/Audio section is written with real content, output this notice: +> "📌 **Asset Spec** — Visual/Audio requirements are defined. After the art bible is approved, run `/asset-spec system:[system-name]` to produce per-asset visual descriptions, dimensions, and generation prompts from this section." + +For **UI Requirements**: Coordinate with `ux-designer` for complex UI systems. +After writing this section, check whether it contains real content (not just +`[To be designed]` or a note that this system has no UI). If it does have real +UI requirements, output this flag immediately: + +> **📌 UX Flag — [System Name]**: This system has UI requirements. In Phase 4 +> (Pre-Production), run `/ux-design` to create a UX spec for each screen or +> HUD element this system contributes to **before** writing epics. Stories that +> reference UI should cite `design/ux/[screen].md`, not the GDD directly. +> +> Note this in the systems index for this system if you update it. + +For **Open Questions**: Capture anything that came up during design that wasn't +fully resolved. Each question should have an owner and target resolution date. + +--- diff --git a/.claude/skills/design-system/references/5-post-design.md b/.claude/skills/design-system/references/5-post-design.md new file mode 100644 index 00000000..d0f0dae9 --- /dev/null +++ b/.claude/skills/design-system/references/5-post-design.md @@ -0,0 +1,198 @@ +# /design-system — Phase 5: Post-Design Validation + +> Part of `/design-system`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 5. Post-Design Validation + +**In this file:** + +- 5-pre: Author the Summary +- 5a: Self-Check +- 5a-bis: Creative Director Pillar Review +- 5b: Update Entity Registry +- 5c: Offer Design Review +- 5d: Update Systems Index +- 5e: Update Session State +- 5f: Suggest Next Steps + +After all sections are written: + +### 5-pre: Author the Summary + +Write `## Summary` and its `> **Quick reference**` line now — after the design +exists, so the summary distils real content rather than intentions. This runs +**at every tier**, including `standard` and a voluntary `minimal` GDD: the +Summary is what lets a later skill scan 20 GDDs and decide which to read in full +(`/create-epics`, `/architecture-review`, `/review-all-gdds` all grep it), so a +GDD without it silently forces those consumers back to full reads. + +- **Summary body**: 2–3 sentences — what this system is, what it does for the + player, why it exists in this game. No jargon; a reader who has not seen the + GDD should learn whether it is relevant to their task. +- **Quick reference**: `Layer` and `Priority` from the systems index + (`design/gdd/systems-index.md`); `Key deps` from the Dependencies section just + written (system names, or `None`). + +Replace the `[To be designed]` Summary placeholder in the skeleton. Then apply +the section cycle's Write step as for any other section. + +### 5a: Self-Check + +Read back the complete GDD from file (not from conversation memory — the file is +the source of truth). Verify: +- The `## Summary` and its Quick reference are populated (not the placeholder) +- Every section **required at this system's effective tier** has real content + (not placeholders) — §1: 8 at `full`, 5 + conditional Formulas at `standard`, + 5 at a voluntary `minimal`. Do not verify against a fixed count of 8: below + `full` that reports a correctly-authored GDD as incomplete, which is the same + error already corrected in the optional-sections prompt above +- Formulas reference defined variables +- Edge cases have resolutions +- Dependencies are listed with interfaces +- Acceptance criteria are testable + +### 5a-bis: Creative Director Pillar Review + +**Review mode check** — apply before spawning CD-GDD-ALIGN: +- `solo` → skip. Note: "CD-GDD-ALIGN skipped — Solo mode." Proceed to Step 5b. +- `lean` → skip (not a PHASE-GATE). Note: "CD-GDD-ALIGN skipped — Lean mode." Proceed to Step 5b. +- `full` → spawn as normal. + +Before finalizing the GDD, spawn `creative-director` via `Agent` using gate **CD-GDD-ALIGN** (`.claude/docs/director-gates/cd-gdd-align.md`). + +Pass: completed GDD file path, game pillars (from `design/gdd/game-concept.md` or `design/gdd/game-pillars.md`; if there is neither, the pitch and "what they feel" line of `design/game-brief.md`), MDA aesthetics target, and the GDD's Player Fantasy section — or, when this tier did not author one, say so. + +Handle verdict per the standard rules in `director-gates.md`. +On `Revise flagged items`, or to resolve a REJECT, each flagged section runs its +section cycle again — its specialist consulted as that section's review-mode +check says — and is re-approved through its "Approve the [Section Name] +section?" widget before the Edit that writes it; then record `REVISED [date]`. +A `NOT ASSESSED` answer is never an approval: name the missing input, then +supply it and re-run the gate, or record `NOT ASSESSED`. +After resolution, record the verdict in the GDD Status header: +`> **Creative Director Review (CD-GDD-ALIGN)**: APPROVED [date] / CONCERNS (accepted) [date] / REVISED [date] / NOT ASSESSED [date] — [missing input]` + +--- + +### 5b: Update Entity Registry + +Scan the completed GDD for cross-system facts that should be registered: +- Named entities (enemies, NPCs, bosses) with stats or drops +- Named items with values, weights, or categories +- Named formulas with defined variables and output ranges +- Named constants referenced by value in more than one place + +**First check the registry exists** — §2a reads it *"if it exists"*, and this +step never carried the same guard. At `standard` and below the file is often +absent, and a grep against a missing path returns nothing, which is +indistinguishable from "no candidate is registered yet": + +- **Absent** — say so, and ask whether to create it: + *"`design/registry/entities.yaml` does not exist. May I create it with these + [N] entries?"* If the user declines, skip 5b and say the registry was not + written — do not treat the skip as a clean pass. +- **Present but empty** — every list is `[]`, or the only matches are inside + comment blocks. Treat it as present, register the candidates, but say which + state you found: *"registry exists and is empty — all [N] entries are new."* + The shipped template's comments carry fully-formed examples referencing + `design/gdd/inventory.md` with real-looking values (`base_inventory_slots: 20`, + `gold_carry_limit: 9999`), so §2a's registry greps return **comment + lines** on an empty registry — and §2d would then present those invented numbers to the user as + *"These values are locked."* Match entries under a live `entities:`/`items:`/ + `formulas:`/`constants:` key, never a commented example. +- **Present** — for each candidate, check whether it is already registered: + +``` +Grep pattern=" - name: [candidate_name]" path="design/registry/entities.yaml" +``` + +Present a summary: +``` +Registry candidates from this GDD: + NEW (not yet registered): + - [entity_name] [entity]: [attribute]=[value], [attribute]=[value] + - [item_name] [item]: [attribute]=[value], [attribute]=[value] + - [formula_name] [formula]: variables=[list], output=[min–max] + ALREADY REGISTERED (referenced_by will be updated): + - [constant_name] [constant]: value=[N] ← matches registry ✅ +``` + +Ask: "May I update `design/registry/entities.yaml` with these [N] new entries +and update `referenced_by` for the existing entries?" (If the file was absent +and the user approved creating it, the wording is *create*, not *update*, and +there are no `referenced_by` arrays to merge.) + +If yes: append new entries and update `referenced_by` arrays. Never modify +existing `value` / attribute fields without surfacing it as a conflict first. + +### 5c: Offer Design Review + +Present a completion summary: + +> **GDD Complete: [System Name]** +> - Sections written: [list] +> - Provisional assumptions: [list any assumptions about undesigned dependencies] +> - Cross-system conflicts found: [list or "none"] + +> **To validate this GDD, open a fresh Claude Code session and run:** +> `/design-review design/gdd/[system-name].md` +> +> **Never run `/design-review` in the same session as `/design-system`.** The reviewing +> agent must be independent of the authoring context. Running it here would inherit +> the full design history, making independent critique impossible. + +**NEVER offer to run `/design-review` inline.** Always direct the user to a fresh window. + +### 5d: Update Systems Index + +After the GDD is complete (and optionally reviewed): + +**First check the systems index exists.** §2a skips it at `minimal` because it is +never written at that tier, and this step never carried the same guard — the same +class of bug §5b was patched for. It bites hardest on a `minimal` project with a +`system_overrides` bump, where the effective tier is `standard` or `full` and +nothing else in §5 hints the file may be absent. + +- **Absent** — say so in one line (*"no `design/gdd/systems-index.md` at this + workflow tier; nothing to update"*) and skip to §5e. Do **not** offer to create + one: `/map-systems` owns that file, and a stub written here would be a systems + index listing exactly one system. +- **Present** — continue: + +- Read the systems index +- Update the target system's row: + - If design-review was run and verdict is APPROVED: Status → "Approved" + - If design-review was run and verdict is NEEDS REVISION or MAJOR REVISION NEEDED: Status → "Needs Revision" (that exact string — `/design-review` sets "In Review" only once the revisions are applied) + - If design-review was skipped: Status → "Designed" (pending review) + - If the user chose "I'll review it myself first": Status → "Designed" + - Design Doc: link to `design/gdd/[system-name].md` +- Update the Progress Tracker counts + +Ask: "May I update the systems index at `design/gdd/systems-index.md`?" + +### 5e: Update Session State + +Update `production/session-state/active.md` with: +- Task: [system-name] GDD +- Status: Complete (or In Review if design-review was run) +- File: design/gdd/[system-name].md +- Sections: [list the sections actually authored, by name] — **never a fixed + count**; §5a forbids verifying against `/8`, and the same reasoning applies to + recording it. Below `full` a correctly-authored GDD has fewer than 8 sections, + and writing "All 8 written" into session state makes the next reader believe + a complete GDD is incomplete +- Next: [suggest next system from design order] + +### 5f: Suggest Next Steps + +Use `AskUserQuestion`: +- "What's next?" + - Options: + - "Run `/consistency-check` — verify this GDD's values don't conflict with existing GDDs (recommended before designing the next system)" + - "Design next system ([next-in-order])" — if undesigned systems remain + - "Fix review findings" — if design-review flagged issues + - "Stop here for this session" + - "Run `/gate-check`" — if enough MVP systems are designed + +--- diff --git a/.claude/skills/dev-story/SKILL.md b/.claude/skills/dev-story/SKILL.md index 8f39eb0e..95da9b46 100644 --- a/.claude/skills/dev-story/SKILL.md +++ b/.claude/skills/dev-story/SKILL.md @@ -13,7 +13,6 @@ model: sonnet Resolved above — use as-is. No block → defaults in `.claude/docs/config-resolution.md`. - # Dev Story This skill bridges planning and code. It reads a story file in full, assembles @@ -74,541 +73,27 @@ If not found, ask: "Which story are we implementing?" Glob ## Phase 2: Load Full Context -**Before loading any context, resolve the workflow tier for this story's system** (see the Workflow tier note above), then **verify required files exist.** Extract the ADR path from the story's `ADR Governing Implementation` field. The "If missing — `full`" column is the baseline; the tier columns relax it: - -| File | Path | If missing — `full` | `standard` | `minimal` | -|------|------|---------------------|-----------|-----------| -| TR registry | `docs/architecture/tr-registry.yaml` | **STOP** — "TR registry not found at `docs/architecture/tr-registry.yaml`. Run `/architecture-review` to bootstrap the registry from your GDDs and ADRs." | optional — proceed without it | not expected — proceed | -| Governing ADR | path from story's ADR field | **STOP** — "ADR file [path] not found. Run `/architecture-decision` to create it, or correct the filename in the story's ADR field." Also STOP if its `## Status` is `Proposed` — "ADR [path] is still Proposed. Accept it with `/architecture-decision accept [ADR-id]` before implementing." A story whose ADR field reads `N/A` (`N/A — [reason]`) references none — proceed. | **STOP only if the story references an ADR** and its file is missing/Proposed/Deprecated/Superseded; if it references none, proceed | no ADR required — proceed; **STOP only if the story references an ADR** whose file is missing/Proposed/Deprecated/Superseded | -| Control manifest | `docs/architecture/control-manifest.md` | **WARN and continue** — "Control manifest not found — layer rules cannot be checked. Run `/create-control-manifest`." | WARN and continue | skip — not expected | - -At `full`, if the TR registry is missing, or a referenced governing ADR is missing or `Proposed`, set the story status to **BLOCKED** in the session state and do not spawn any programmer agent. At `standard`/`minimal`, only a story that references an ADR whose file is **missing, `Proposed`, `Deprecated` or `Superseded`** is set BLOCKED; a missing TR registry, or an absent-by-design ADR, does **not** block — implement against the story's acceptance criteria + the GDD/brief. - -Read the story file and the TR registry simultaneously — these two are -genuinely independent, unconditional reads. **The governing ADR is not part -of this batch — do not include it in the same parallel tool-call group as -these two.** Its own section below is a gate, not a read: whether the ADR -gets opened at all depends on a freshness check that itself depends on the -story file already being read. Do not start implementation until this phase -is fully resolved: - -### The story file -Extract and hold: -- **Story title, ID, layer, type** (Logic / Integration / Visual/Feel / UI / Config/Data) -- **TR-ID** — the GDD requirement identifier -- **Governing ADR** reference -- **ADR Version** stamp embedded in story header (absent on pre-stamp stories) -- **ADR Decision Summary** and **Implementation Notes** — the distilled ADR - guidance; this is the primary source for what the ADR decided -- **Manifest Version** embedded in story header -- **Acceptance Criteria** — every checkbox item, verbatim -- **Implementation Notes** — the ADR guidance section in the story -- **Out of Scope** boundaries -- **Test Evidence** — the required test file path -- **Dependencies** — what must be DONE before this story - -### The TR registry -Grep the story's TR-ID from `docs/architecture/tr-registry.yaml` -(`Grep pattern="id: " path="docs/architecture/tr-registry.yaml" output_mode="content" -A 6`) -rather than reading the whole cross-system registry. Read the matched entry's current -`requirement` text — this is the source of truth for what the GDD requires now. Do not -rely on any inline text in the story file (may be stale). - -### The governing ADR - -**Do not open the ADR by default.** `/create-stories` already distilled it into -this story's `**ADR Decision Summary**` + `## Implementation Notes`, and its -template states the contract outright: *"This is what the programmer reads -instead of the ADR."* Re-reading the source here discards that work and, on an -ADR past the 25k `Read` cap, costs a failed read plus offset/limit retries -before implementation even starts. - -**Check status and freshness with one line, not one file.** Resolve the ADR path -from the story, then: - -``` -Grep pattern="^## (Status|Last Verified|Date)" path="docs/architecture/[adr-file].md" output_mode="content" -A 2 -``` - -The `## Status` line decides first: if it reads `Proposed`, the story is BLOCKED -per the file-check table above — stop here, before any freshness comparison. -`Deprecated` or `Superseded by ADR-XXXX` blocks the same way, at every tier: -"ADR [path] is [status]; point the story at [successor] (edit its ADR field — -`/create-stories` never rewrites an existing story) before implementing." - -Then resolve the ADR's **current version** the way `/create-stories` stamped it: -its `## Last Verified` date, else its `## Date`, else `unversioned`. Compare that -value against the story's `**ADR Version**` field: - -| Result | Meaning | Action | -|---|---|---| -| Versions **match** (a date on both sides) | The summary was distilled from the ADR as it stands. | **Trust the story.** Do not read the ADR. | -| Story has **no `ADR Version`** field | A story written before the stamp existed — *not* evidence of staleness. | **Trust the story**, and note in the Phase 6 summary: "Story predates the ADR Version stamp; summary trusted unverified." | -| Both read `unversioned` | The ADR has neither `## Last Verified` nor `## Date`. Consistent, not stale — but nothing to compare. | **Trust the story**; note "ADR carries no date; summary trusted unverified." in the Phase 6 summary, and recommend `/architecture-decision retrofit [file]`, which adds a missing `## Date`. | -| The ADR resolves to `unversioned` but the story names a date | Ambiguous — the ADR lost the field the story was stamped from. | Treat as **mismatch** (below). | -| Versions **differ** | The ADR changed after this story was written. | **Mismatch** — resolve below. | - -**Never treat an absent stamp as a stale one.** A missing field means "unknown", -and the fallback for unknown is the story, not a 35k-token re-read — the two -staleness gates that already exist (`/story-readiness` on Manifest Version, -`/code-review` post-implementation) are what make that safe. - -**On mismatch**, use `AskUserQuestion` — same shape as the Manifest Version -check below: -- Prompt: "Story was written against ADR v[story-date]. The ADR is now - v[current-date]. Its decision may have changed. How do you want to proceed?" -- Options: - - `[A] Re-read the changed ADR sections, implement against current guidance, and refresh this story's ADR summary and ADR Version (Recommended)` - - `[B] Implement from the story's summary — I accept the drift risk` - - `[C] Stop — I want to review the ADR diff first` - -If **[A]**: first check the ADR's size — `Bash: wc -c "docs/architecture/[adr-file].md"`: - -- **Under ~50KB** — read the whole file with one `Read` call. At this size one - read is *cheaper* than the multi-grep path — per-call overhead outweighs the - content saved. Targeted reading only pays for itself on files big enough - to threaten the 25k-token `Read` cap. -- **~50KB or larger** — read *only* the sections that govern implementation, - never the whole file: - ``` - Grep pattern="^## (Decision|Engine Compatibility|ADR Dependencies)" path="docs/architecture/[adr-file].md" output_mode="content" -A 40 - ``` - Escalate to a bounded `Read(offset, limit)` on one section only if a scanned - section cross-references material outside itself. - -Then make the story edit that option [A] names: set its `ADR Version` to the ADR's -current version resolved above — not today's date, or the next run mismatches -again — and replace its `**ADR Decision Summary**` and `## Implementation Notes` -with the guidance you just read, so a later run that trusts the stamp is trusting -current guidance. -If **[B]**: proceed on the summary; record it in the Phase 6 "Deviations" summary. -If **[C]**: stop. Do not spawn any agent. - -### The control manifest -Read only this story's layer from `docs/architecture/control-manifest.md` — grep that one -section (`Grep pattern="^## Layer Rules" path="docs/architecture/control-manifest.md" output_mode="content" -A 40`) rather than a full read of every layer. Extract the rules for this story's layer: -- Required patterns -- Forbidden patterns -- Performance guardrails - -Check: does the story's embedded Manifest Version match the current manifest header date? -If they differ, use `AskUserQuestion` before proceeding: -- Prompt: "Story was written against manifest v[story-date]. Current manifest is v[current-date]. New rules may apply. How do you want to proceed?" -- Options: - - `[A] Update story manifest version and implement with current rules (Recommended)` - - `[B] Implement with old rules — I accept the risk of non-compliance (the story records the current Manifest Version and a Manifest-Note)` - - `[C] Stop here — I want to review the manifest diff first` - -If [A]: edit the story file's `Manifest Version:` field to the current manifest date before spawning the programmer. Then read the manifest carefully for new rules. -If [B]: edit the story file's `Manifest Version:` field to the current manifest date AND add a `Manifest-Note: Proceeded with old manifest rules on [date] — non-compliance risk accepted.` line to the story header. Read the manifest for new rules anyway. Note the decision in the Phase 6 summary under "Deviations". `/story-done` will include the Manifest-Note in its deviations section without re-checking staleness. -If [C]: stop. Do not spawn any agent. Let the user review and re-run `/dev-story`. - -### Dependency validation - -After extracting the **Dependencies** list from the story file, validate each: - -1. Glob `production/epics/**/*.md` to find each dependency story file. -2. Read its `Status:` field. -3. If any dependency has Status other than `Complete` or `Done`: - - Use `AskUserQuestion`: - - Prompt: "Story '[current story]' depends on '[dependency title]' which is currently [status], not Complete. How do you want to proceed?" - - Options: - - `[A] Proceed anyway — I accept the dependency risk` - - `[B] Stop — I'll complete the dependency first` - - `[C] The dependency is done but status wasn't updated — mark it Complete and continue` - - If [B]: set story status to **BLOCKED** in session state and stop. Do not spawn any programmer agent. - - If [C]: ask "May I update [dependency path] Status to Complete?" before continuing. - - If [A]: note in Phase 6 summary under "Deviations": "Implemented with incomplete dependency: [dependency title] — [status]." - -If a dependency file cannot be found: warn "Dependency story not found: [path]. Verify the path or create the story file." - ---- - -### Engine reference -Read from `project.yaml` first, falling back to `.claude/docs/technical-preferences.md` for any key absent or empty: -- `specialists.*` — the project's chosen specialist agents; **read before** - `engine.name` when selecting an agent (see Phase 3) -- `engine.name` (else the `Engine:` value) — the generic engine specialist, and - the fallback when `specialists` is absent -- `naming.*` (else Naming conventions) — class names, file names, signal/event names -- `performance.*` (else Performance budgets) — frame budget, memory ceiling -- Forbidden patterns — from `.claude/docs/technical-preferences.md` (not migrated to project.yaml) - -### Mark Story In Progress - -Before spawning any agent, mark the story In Progress. In `collaborative` mode -ask once first — "May I mark this story In Progress? This sets `Status:` and -`Last Updated:` in `[story-path]` and its entry in `production/sprint-status.yaml`." -(leave the sprint-status file out of the question when it does not exist); -`guided` and `autonomous` update these existing files without asking -(`.claude/docs/automation-modes.md`). If the user declines, change neither file, -print `Story not marked In Progress — declined` in the Phase 6 summary, and -continue. Otherwise update two things: - -1. **`production/sprint-status.yaml`** (if it exists): find the entry matching this story's file path and set `status: in-progress`. Update the top-level `updated` field to today's date. If the file does not exist, say so in one line — `Sprint status not updated: production/sprint-status.yaml absent` — and continue. Do not skip silently: `/sprint-status` reads that file to report progress, so a story that never gets marked `in-progress` is invisible to the very command a producer uses to ask what is moving. - -2. **The story file itself**: set the story header's `Status:` field to `In Progress`, and edit its `Last Updated:` field to today's date (format: `YYYY-MM-DD`; if the field does not exist, add it after the `Status:` line). Setting `Status:` here is what actually marks the story In Progress — at `minimal` the `sprint-status.yaml` in step 1 is absent, so the story file is the only record of progress at that tier. - ---- +**Read `references/2-load-context.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 3: Route to the Right Programmer -Based on the story's **Layer**, **Type**, and **system name**, determine which -specialist to spawn via `Agent`. - -**Config/Data stories — skip agent spawning entirely:** -If the story's Type is `Config/Data`, no programmer agent or engine specialist is needed. Jump directly to Phase 4 (Config/Data note). The implementation is a data file edit — no routing table evaluation, no engine specialist. - -### Primary agent routing table - -| Story context | Primary agent | -|---|---| -| Foundation layer — any type | `engine-programmer` | -| Any layer — Type: UI | `ui-programmer` | -| Any layer — Type: Visual/Feel | `gameplay-programmer` (implements) | -| Core or Feature — gameplay mechanics | `gameplay-programmer` | -| Core or Feature — AI behaviour, pathfinding | `ai-programmer` | -| Core or Feature — networking, replication | `network-programmer` | -| Config/Data — no code | No agent needed (see Phase 4 Config note) | - -### Engine specialist — always spawn as secondary for code stories - -**Read the `specialists` block from `project.yaml` directly — it is not in -the `resolve_config` output at the top of this skill..** `resolve_config` does not emit -`specialists.*`; the five skills that already consume it (`/adopt`, -`/code-review`, `/design-system`, `/gate-check`, `/team-ui`) all read the block -out of `project.yaml` themselves, and so does this one. Adding it to the -frontmatter key list would fail the gate that asserts every requested key is one -`resolve_config` actually emits. - -`/setup-engine` writes the block, and it is the project's own answer to "which -specialist implements here" — resolved from the engine *and the language*, which -`engine.name` alone cannot tell you. Resolve in this order: - -1. **`specialists.code`** — the language/code specialist, and the right secondary - for an implementation story. This is the value that distinguishes a Godot C# - project (`godot-csharp-specialist`) from a Godot GDScript one - (`godot-gdscript-specialist`); `engine.name` is `Godot` for both. -2. **`specialists.shader`** when the story touches shaders or materials, and - **`specialists.ui`** when the story's Type is `UI` — in addition to, not - instead of, `specialists.code`. -3. **The generic `-specialist`** — derived from `engine.name` - (Godot→`godot-specialist`, Unity→`unity-specialist`, - Unreal→`unreal-specialist`) — for architecture-level and broad engine - concerns, and as the fallback when the `specialists` block is absent. -4. If `engine.name` is also absent or empty, read the Primary line of the - `## Engine Specialists` section of `.claude/docs/technical-preferences.md`. - -**A value of `null` means UNSET — treat that key as absent and fall through to -the generic specialist. Never spawn it as an agent name.** The config reader -returns the four-character string `"null"`, which is not empty and therefore -reads as configured; `null`, empty and missing are the same state here. (This is -the same caveat `/code-review` Phase 2 carries, for the same reason.) - -Spawn the resolved specialist alongside the primary agent when the story involves -engine-specific APIs, patterns, or the ADR has HIGH engine risk. - -The full roster, for reference when no `specialists` block exists: - -| Engine | Specialist agents available | -|--------|----------------------------| -| Godot 4 | `godot-specialist`, `godot-gdscript-specialist`, `godot-csharp-specialist`, `godot-shader-specialist`, `godot-gdextension-specialist` | -| Unity | `unity-specialist`, `unity-ui-specialist`, `unity-shader-specialist`, `unity-dots-specialist`, `unity-addressables-specialist` | -| Unreal Engine | `unreal-specialist`, `ue-gas-specialist`, `ue-blueprint-specialist`, `ue-umg-specialist`, `ue-replication-specialist` | - -> **Do not pick from this table when `specialists` is set.** The table lists what -> *exists* for an engine; the block records what this project *chose*. Reading the -> table instead of the block is how a Godot C# project ends up reviewed by the -> GDScript specialist. - -**When engine risk is HIGH** (from the ADR or VERSION.md): always spawn the engine -specialist, even for non-engine-facing stories. High risk means the ADR records -assumptions about post-cutoff engine APIs that need expert verification. - -> **Read the risk, do not trust the story card alone.** If the story's `Risk` -> field is absent, or says `NOT ASSESSED`, **or disagrees with -> `docs/engine-reference//VERSION.md`, the VERSION.md rating wins** and an -> unknown counts as HIGH. At `minimal` there is no ADR, so VERSION.md is the only -> source; a story card carrying an improvised `MEDIUM` against a VERSION.md -> rating of HIGH would skip this spawn without saying so. `/create-stories` now derives the field -> from the same file, so the two should agree; this check is what catches it when -> they do not. - ---- +**Read `references/3-route.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 4: Implement -Spawn the chosen programmer agent(s) via `Agent` with the full context package: - -Brief the agent with file paths and targeted reading instructions — do not serialize document content into the `Agent` prompt. The agent reads what it needs directly. - -> **Tier note (from Phase 2):** items 2–4 below assume the `full` baseline. At -> `standard`, include the TR registry only if it exists and the governing ADR -> only where the story references one — at any tier, a story whose ADR field -> reads `N/A` has no item 3. At `minimal`, the TR registry, ADR, and -> control manifest are typically absent — **omit items 2–4 and brief the agent to -> implement against the story's Acceptance Criteria and the GDD/brief** (the -> story file from item 1). Never instruct the agent to read a file Phase 2 -> confirmed missing. -> -> **Say which items you dropped, and say it to both readers.** The rule item 7 -> already carries applies unchanged to items 2–4: *an omitted item and a -> forgotten one are indistinguishable to the agent.* They are equally -> indistinguishable to the user reading the Phase 6 summary. -> - **To the agent**, in the prompt: *"No TR registry entry is passed for this -> story — `docs/architecture/tr-registry.yaml` does not exist at this tier. -> Implement against the story's Acceptance Criteria and the GDD/brief. Do not -> go looking for it."* Same form for an absent ADR or control manifest. -> - **To the user**, one line before spawning: `Briefing omits: TR registry -> (absent), ADR guidance (story references no ADR), control manifest -> (absent) — implementing against acceptance criteria + GDD.` -> -> Without this, a `standard` run where the registry legitimately does not exist -> and one where `/architecture-review` was supposed to bootstrap it and nobody -> did produce **identical output**. - -1. **Story file**: `[story-path]` — the agent reads this one file; it carries the acceptance criteria, Out of Scope boundaries, and QA test cases -2. **GDD requirement**: look up TR-ID `[TR-XXX-NNN]` in `docs/architecture/tr-registry.yaml` — use the `requirement` field as source of truth -3. **ADR guidance**: pass the story's `**ADR Decision Summary**` and `## Implementation Notes` **inline in the prompt** — do not pass the ADR path. Phase 2 already established that this summary is current; handing the agent a path makes it re-read the whole ADR in its own context, paying the cost this skill just avoided. After mismatch option `[A]`, pass the guidance freshly read from the ADR's `## Decision` (the text [A] just wrote into the story), never the stale summary the story carried before; after `[B]`, pass the story's summary and tell the agent it predates the current ADR. -4. **Control manifest**: `docs/architecture/control-manifest.md` — read rules for the **[layer]** layer only -5. **Engine preferences**: `naming.*` and `performance.*` from `project.yaml` (for any key absent or empty, fall back to `.claude/docs/technical-preferences.md`) -6. **Test file path**: `[path from story's Test Evidence section]` — this file must be created as part of implementation -7. **Test requirement** (Logic and Integration stories only; **omit this entire item at `qa.level: minimal`** — tests are not required there. When you omit it for a Logic or Integration story, tell the agent so explicitly — never a UI, Visual/Feel or Config/Data story, which this item never covered: *"Do not write a test file for this story — test evidence is waived at `qa.level: minimal`."* An omitted item and a forgotten one are indistinguishable to the agent, and a programmer briefed with no test instruction may write tests anyway, or may silently assume they were meant to): The test file MUST be created at `[path from the story's Test Evidence section]`. Write the test alongside the implementation — do not defer it. At `qa.level: standard`/`full` the story cannot be closed via `/story-done` without this file present. Each acceptance criterion must have at least one test function covering it. Test naming per engine, from `.claude/rules/test-standards.md`: Godot `test_[scenario]_[expected]` in `[system]_[feature]_test.gd`; Unity `[Scenario]_[Expected]` in a `[System]Tests` class; Unreal `.[System].[Scenario]`. No random seeds, no time-dependent assertions, no external I/O. -8. **Explicit instruction**: implement this story following the ADR guidelines, respect the manifest rules, stay within the story's Out of Scope boundaries. Write clean, doc-commented public APIs. - -The agent should: -- Create or modify files under the **resolved code root** following the ADR guidelines. Resolve it per `.claude/docs/code-root-resolution.md` — `src/` is the Godot row, `Assets/Scripts//` is Unity's, `Source///` is Unreal's. **If the code root cannot be resolved, do not write: report it and stop.** Selecting the engine specialist above is NOT the same as resolving the code root -- Respect all Required and Forbidden patterns from the control manifest -- Stay within the story's Out of Scope boundaries (do not touch unrelated files) -- Write clean, doc-commented public APIs - -### Config/Data stories (no agent needed) - -For Type: Config/Data stories, no programmer agent is required. The implementation -is editing a data file. Read the story's acceptance criteria, show the specified -changes as from → to values, and ask "May I write to [data file path]?" before -editing it directly. Note which values were changed and what they changed from/to. - -### Visual/Feel stories - -Spawn `gameplay-programmer` to implement the code/animation calls. The *look* -half of the acceptance criteria — layout, clipping, presence, colour — is -verified in Phase 6 step 4 by launching the build and retaining a screenshot; -it is not deferred. The *feel* half — timing, weight, responsiveness — is not -something a still can show: say which half the run covered, and leave feel to -`/team-qa`. - ---- +**Read `references/4-implement.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 5: Test Evidence Requirements -The test requirement was included in the Phase 4 programmer agent brief (item 7). This phase summarizes what evidence each story type requires — used when collecting the Phase 6 summary. - -**Skip this phase at `qa.level: minimal`** (resolved earlier) — no test evidence -is required, so there is nothing to gate; do not flag the story unverifiable for a -missing test. **The Visual/Feel and UI screenshot line at the end of this phase -still applies** — `qa.level` waives tests, never the look. - -> **Say so in the Phase 6 summary.** A skipped phase must announce itself in the -> output, not only in this file (`.claude/rules/skill-authoring.md`, obligation -> 3). For a Logic or Integration story — the types Phase 4 item 7 briefs a test -> for — emit the line: -> -> > *Test evidence: **waived** at `qa.level: minimal` — no test was required or -> > written for this story.* -> -> Without it, a minimal-tier summary that simply lacks a tests row is -> indistinguishable from a `standard`-tier run where the programmer forgot to -> write them — and the permissive reading is the one that gets believed. - -Otherwise: - -**Resolve the gate level for this story's type** from `testing.strict` in -`project.yaml`. BLOCKING means a missing test marks the story unverifiable; -ADVISORY means a missing test is noted but does not block: - -1. Map the Story Type to a `testing.strict` key — Logic→`logic`, - Integration→`integration`, Visual/Feel→`visual`, UI→`ui`, Config/Data→`config`. - Take `testing.strict.` from the **the resolved-config block at the top of this skill**, not from - `project.yaml` directly. If its value is `true` (case-insensitive) → - BLOCKING; if `false` → ADVISORY; `unset` → fall through. - -> `testing.strict.*` is locally overridable (`/settings --local -> testing.strict.logic=false`). Reading `project.yaml` on its own ignores -> `project.local.yaml` entirely, so the override is accepted and then does -> nothing. `resolve_config` merges the two. -2. Else read `testing.strict` as a plain boolean (legacy single-value form) — if - its value is `true` or `false`, it applies to every type. -3. Else use the **Default Gate Level** column below. - -Only `true` and `false` (case-insensitive) are recognized at steps 1–2. A key -that is present but holds any other value — `maybe`, `1`, `yes`, etc. — is -treated as unset: continue to the next step, and surface the unrecognized value -to the user. - -| Story Type | Required Evidence | Default Gate Level | -|---|---|---| -| **Logic** | Automated unit test at path from story's Test Evidence section | BLOCKING | -| **Integration** | Integration test OR documented playtest record | BLOCKING | -| **Visual/Feel** | Retained screenshot + evidence doc at `production/qa/evidence/[slug]-evidence.md` | BLOCKING | -| **UI** | Retained screenshot of each screen touched, in `production/qa/evidence/` | BLOCKING | -| **Config/Data** | None — smoke check serves as evidence | ADVISORY | - -The test is written alongside the implementation (Phase 4, item 7) regardless of -the gate level — strictness controls only how a *missing* test is reported in the -Phase 6 summary. At a BLOCKING level, a missing test is flagged "story -unverifiable — test required before `/story-done`". At an ADVISORY level it is -noted as a recommendation. The **Default Gate Level** column applies when -`testing.strict` is unset. - -Visual/Feel and UI default to **BLOCKING**: for a game the rendered result is the -product, and an advisory visual gate gets deferred in favour of whatever does -block. A project that genuinely does not need it sets `testing.strict.visual` or -`testing.strict.ui` to `false`. - -For Visual/Feel and UI stories, include in the Phase 6 summary: "Retained screenshot required under `production/qa/evidence/[story-slug]/` before this story can be closed — at the default BLOCKING level a story with no screenshot on disk is unverifiable." For Visual/Feel, add that the sign-off in `production/qa/evidence/[slug]-evidence.md` is also required. - ---- +**Read `references/5-test-evidence.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 6: Collect and Summarise -### First: did the agent actually finish? - -**Do not assume completion.** A programmer agent can stop at its turn limit -mid-edit, and the work it leaves behind can be syntactically broken — a helper -called but never defined, an import half-moved. Its partial report reads like -progress, and this phase's summary would print "Implementation Complete" over -code that does not load. - -Before collecting anything: - -1. **Check the agent's own terminal state.** If it reported stopping early, hit a - turn/step limit, or its report ends mid-task, treat the story as **INCOMPLETE**. -2. **Verify the output parses.** Run the check whose **exit code** answers the - question — an exit 0 from a command that does not check is how broken code - gets reported as clean: - - **Godot:** `godot --headless --path . --import` once (it builds the class - cache), then one run over every `.gd` the story added or changed: - `godot --headless --path . -s res://.claude/scripts/godot-parse-check.gd -- res://.gd …`. - For `godot`, use the executable `commands.test` names, else the editor - `engine.path` records, else `godot` on `PATH`; if none resolves, write - `parse NOT VERIFIED — Godot executable not found`. - Exit 1 means a script did not load — its `PARSE FAIL:` line names it, with - Godot's error above. Do not use `--check-only`: it fails valid code that - names an autoload. `--import` and `--quit-after` on their own exit 0 on a - parse error — they are not parse checks. - - **Unity:** `commands.smoke` (`-batchmode -quit -projectPath . -logFile -`) - — exit 1 with `error CS…` lines when a script does not compile. - - **Unreal:** build the editor target — - `"/Engine/Binaries/DotNET/UnrealBuildTool/UnrealBuildTool.exe" Editor Win64 Development -Project="/.uproject"` - on Windows; on Linux `"/Engine/Build/BatchFiles/Linux/Build.sh" Editor Linux Development -Project=…`, - on macOS `…/Mac/Build.sh Editor Mac Development -Project=…` (from Epic's - documentation — `docs/engine-reference/unreal/current-best-practices.md`, "Command Line"). - A compile error fails the build (`Result: Failed`, non-zero exit). - Report what you ran, its exit code, and any error lines. -3. If the engine binary is unavailable, write **`parse NOT VERIFIED — engine - binary not available`**. Do not infer that the code is fine because it reads - correctly; that inference is exactly what this step exists to replace. -4. **Run it and look.** A parse check is not a run. For every story that - changes something a player can see — every Visual/Feel and UI story, and any - Logic, Integration or Config/Data story with a surface — launch the build - via `commands.run`, straight into the scene or map the story touched, and - retain a screenshot under `production/qa/evidence/[story-slug]/`. Then - `Read` the image and compare it to the acceptance criteria: clipped text, - an overflowing panel, a missing element are defects, and this is the only - step that finds them. Procedure per engine, including how to capture - unattended in Godot, Unity and Unreal: `.claude/docs/run-and-observe.md`. - **On Unity** the capture needs the `ScreenshotOnArg.cs` script that file gives - verbatim. If the project has none (Glob `Assets/**/ScreenshotOnArg.cs`), ask - "May I write `Assets/Scripts/ScreenshotOnArg.cs`?" and write it exactly as - given there before launching; if the user declines, nothing can capture — - report `Run result: NOT VERIFIED — ScreenshotOnArg.cs not written`. - Report exactly one line — `Run result: OBSERVED — ` - with the retained path, `Run result: NOT VERIFIED — `, or - `Run result: N/A — ` for a story with genuinely nothing observable. - **`NOT VERIFIED` is a blocker at the default gate level for Visual/Feel and - UI, not a note** — `/story-done` reads this line. This step is **not waived - at `qa.level: minimal`**; tests are, the look is not. - -**If INCOMPLETE:** say so as the headline, list what exists so far, name the -specific breakage, and offer to resume the agent. Do **not** emit -"Implementation Complete", and do not advance the story's status. - -### Then collect: - -- Files created or modified (with paths) -- **Verification result** — what was run, and its outcome (or why it could not run) -- Test file created (path and number of test functions written) — **or**, at - `qa.level: minimal`, the waiver line from Phase 5 -- Any deviations from the story's Out of Scope boundary (flag these) -- Any questions or blockers the agent surfaced -- Any engine-specific risks the specialist flagged - -Present a concise implementation summary: - -``` -## Implementation Complete: [Story Title] - -**Files changed**: -- `/[path]` — created / modified ([brief description]) -- `tests/[path]` — test file ([N] test functions) — *omit this line at - `qa.level: minimal` and print the Phase 5 waiver line instead (Logic/Integration)* - -**Verification**: [what was run] — [result, or `NOT VERIFIED — `] -**Run result**: [`OBSERVED — ` + retained path | `NOT VERIFIED — ` | `N/A — `] — see `.claude/docs/run-and-observe.md` - -**Acceptance criteria covered**: -- [x] [criterion] — implemented in [file:function] -- [x] [criterion] — covered by test [test_name] -- [x] [criterion] — OBSERVED in `production/qa/evidence/[slug]/01-[what].png` (Visual/UI look) -- [ ] [criterion] — DEFERRED: requires playtest (Visual/Feel *feel* — timing, weight; a still cannot show it) - -**Deviations from scope**: [None] or [list files touched outside story boundary] -**Engine risks flagged**: [None] or [specialist finding] -**Blockers**: [None] or [describe] - -**Before running `/story-done`:** run your test suite locally and confirm the tests you wrote pass. *(At `qa.level: minimal` no tests were written — print the Phase 5 waiver line here instead of this paragraph for a Logic or Integration story, and omit both for any other type. Telling a user to confirm the passing of tests that do not exist is worse than saying nothing.)* **`/story-done` does NOT re-run them** — its Phase 3 checks that the test FILE exists, with `Glob`, and nothing executes it. A test that exists and fails satisfies that gate. Nothing downstream makes the local run safe to skip. Pass/fail is established by `/gate-check` and `/smoke-check`, both of which execute a suite — and both come later than story closure. - -Ready for: `/story-done [story-path]` — at `standard`/`full`, `/code-review [file1] [file2]` first -``` - ---- +**Read `references/6-collect.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 7: Update Session State -Silently update the checkpoint in `production/session-state/active.md` — -**overwrite the `` … `` block, never -append** (schema: `.claude/docs/templates/session-state.md`). `session-start.sh` -shows exactly that block when the next session opens, so it is what a cold -resume starts from: - -``` - -**Updated:** [date] -**Branch:** `[current git branch]` -**Current task:** /dev-story — [story-path] ([story title]) -**Next step:** /story-done [story-path] (at standard/full: /code-review [files] first) -**Blocked on:** [nothing, or the blocker] -**Files in progress:** [files changed, comma-separated; test file included] -**Run result:** [the Phase 6 `Run result:` line, verbatim — `/story-done` reads it here] -**Open questions:** [none, or one line each] - -``` - -**Next step** follows the Phase 6 result — the line above is the Implementation -Complete one. On **INCOMPLETE** write -`**Next step:** /dev-story [story-path] — resume: [the breakage Phase 6 named]`. -On **BLOCKED** (Phase 2) write the unblocking action instead — -`/architecture-decision accept ADR-NNNN`, the dependency story to finish, the -manifest diff to review — and fill **Blocked on**. `/help` reads this line: a -checkpoint that says `/story-done` tells it the work is written. - -If `active.md` does not exist, create it from the template. If it exists with no -markers (a file from before the schema), insert the template's STATUS and -CHECKPOINT blocks at the top and leave the rest untouched. Confirm: "Session -state updated." - ---- +**Read `references/7-session-state.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Error Recovery Protocol diff --git a/.claude/skills/dev-story/references/2-load-context.md b/.claude/skills/dev-story/references/2-load-context.md new file mode 100644 index 00000000..9f328302 --- /dev/null +++ b/.claude/skills/dev-story/references/2-load-context.md @@ -0,0 +1,193 @@ +# /dev-story — Phase 2: Load Full Context + +> Part of `/dev-story`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 2: Load Full Context + +**In this file:** + +- The story file +- The TR registry +- The governing ADR +- The control manifest +- Dependency validation +- Engine reference +- Mark Story In Progress + +**Before loading any context, resolve the workflow tier for this story's system** (see the Workflow tier note above), then **verify required files exist.** Extract the ADR path from the story's `ADR Governing Implementation` field. The "If missing — `full`" column is the baseline; the tier columns relax it: + +| File | Path | If missing — `full` | `standard` | `minimal` | +|------|------|---------------------|-----------|-----------| +| TR registry | `docs/architecture/tr-registry.yaml` | **STOP** — "TR registry not found at `docs/architecture/tr-registry.yaml`. Run `/architecture-review` to bootstrap the registry from your GDDs and ADRs." | optional — proceed without it | not expected — proceed | +| Governing ADR | path from story's ADR field | **STOP** — "ADR file [path] not found. Run `/architecture-decision` to create it, or correct the filename in the story's ADR field." Also STOP if its `## Status` is `Proposed` — "ADR [path] is still Proposed. Accept it with `/architecture-decision accept [ADR-id]` before implementing." A story whose ADR field reads `N/A` (`N/A — [reason]`) references none — proceed. | **STOP only if the story references an ADR** and its file is missing/Proposed/Deprecated/Superseded; if it references none, proceed | no ADR required — proceed; **STOP only if the story references an ADR** whose file is missing/Proposed/Deprecated/Superseded | +| Control manifest | `docs/architecture/control-manifest.md` | **WARN and continue** — "Control manifest not found — layer rules cannot be checked. Run `/create-control-manifest`." | WARN and continue | skip — not expected | + +At `full`, if the TR registry is missing, or a referenced governing ADR is missing or `Proposed`, set the story status to **BLOCKED** in the session state and do not spawn any programmer agent. At `standard`/`minimal`, only a story that references an ADR whose file is **missing, `Proposed`, `Deprecated` or `Superseded`** is set BLOCKED; a missing TR registry, or an absent-by-design ADR, does **not** block — implement against the story's acceptance criteria + the GDD/brief. + +Read the story file and the TR registry simultaneously — these two are +genuinely independent, unconditional reads. **The governing ADR is not part +of this batch — do not include it in the same parallel tool-call group as +these two.** Its own section below is a gate, not a read: whether the ADR +gets opened at all depends on a freshness check that itself depends on the +story file already being read. Do not start implementation until this phase +is fully resolved: + +### The story file +Extract and hold: +- **Story title, ID, layer, type** (Logic / Integration / Visual/Feel / UI / Config/Data) +- **TR-ID** — the GDD requirement identifier +- **Governing ADR** reference +- **ADR Version** stamp embedded in story header (absent on pre-stamp stories) +- **ADR Decision Summary** and **Implementation Notes** — the distilled ADR + guidance; this is the primary source for what the ADR decided +- **Manifest Version** embedded in story header +- **Acceptance Criteria** — every checkbox item, verbatim +- **Implementation Notes** — the ADR guidance section in the story +- **Out of Scope** boundaries +- **Test Evidence** — the required test file path +- **Dependencies** — what must be DONE before this story + +### The TR registry +Grep the story's TR-ID from `docs/architecture/tr-registry.yaml` +(`Grep pattern="id: \s*$" path="docs/architecture/tr-registry.yaml" output_mode="content" -A 6`) +rather than reading the whole cross-system registry. Read the matched entry's current +`requirement` text — this is the source of truth for what the GDD requires now. Do not +rely on any inline text in the story file (may be stale). + +### The governing ADR + +**Do not open the ADR by default.** `/create-stories` already distilled it into +this story's `**ADR Decision Summary**` + `## Implementation Notes`, and its +template states the contract outright: *"This is what the programmer reads +instead of the ADR."* Re-reading the source here discards that work and, on an +ADR past the 25k `Read` cap, costs a failed read plus offset/limit retries +before implementation even starts. + +**Check status and freshness with one line, not one file.** Resolve the ADR path +from the story, then: + +``` +Grep pattern="^## (Status|Last Verified|Date)" path="docs/architecture/[adr-file].md" output_mode="content" -A 2 +``` + +The `## Status` line decides first: if it reads `Proposed`, the story is BLOCKED +per the file-check table above — stop here, before any freshness comparison. +`Deprecated` or `Superseded by ADR-XXXX` blocks the same way, at every tier: +"ADR [path] is [status]; point the story at [successor] (edit its ADR field — +`/create-stories` never rewrites an existing story) before implementing." + +Then resolve the ADR's **current version** the way `/create-stories` stamped it: +its `## Last Verified` date, else its `## Date`, else `unversioned`. Compare that +value against the story's `**ADR Version**` field: + +| Result | Meaning | Action | +|---|---|---| +| Versions **match** (a date on both sides) | The summary was distilled from the ADR as it stands. | **Trust the story.** Do not read the ADR. | +| Story has **no `ADR Version`** field | A story written before the stamp existed — *not* evidence of staleness. | **Trust the story**, and note in the Phase 6 summary: "Story predates the ADR Version stamp; summary trusted unverified." | +| Both read `unversioned` | The ADR has neither `## Last Verified` nor `## Date`. Consistent, not stale — but nothing to compare. | **Trust the story**; note "ADR carries no date; summary trusted unverified." in the Phase 6 summary, and recommend `/architecture-decision retrofit [file]`, which adds a missing `## Date`. | +| The ADR resolves to `unversioned` but the story names a date | Ambiguous — the ADR lost the field the story was stamped from. | Treat as **mismatch** (below). | +| Versions **differ** | The ADR changed after this story was written. | **Mismatch** — resolve below. | + +**Never treat an absent stamp as a stale one.** A missing field means "unknown", +and the fallback for unknown is the story, not a 35k-token re-read — the two +staleness gates that already exist (`/story-readiness` on Manifest Version, +`/code-review` post-implementation) are what make that safe. + +**On mismatch**, use `AskUserQuestion` — same shape as the Manifest Version +check below: +- Prompt: "Story was written against ADR v[story-date]. The ADR is now + v[current-date]. Its decision may have changed. How do you want to proceed?" +- Options: + - `[A] Re-read the changed ADR sections, implement against current guidance, and refresh this story's ADR summary and ADR Version (Recommended)` + - `[B] Implement from the story's summary — I accept the drift risk` + - `[C] Stop — I want to review the ADR diff first` + +If **[A]**: first check the ADR's size — `Bash: wc -c "docs/architecture/[adr-file].md"`: + +- **Under ~50KB** — read the whole file with one `Read` call. At this size one + read is *cheaper* than the multi-grep path — per-call overhead outweighs the + content saved. Targeted reading only pays for itself on files big enough + to threaten the 25k-token `Read` cap. +- **~50KB or larger** — read *only* the sections that govern implementation, + never the whole file: + ``` + Grep pattern="^## (Decision|Engine Compatibility|ADR Dependencies)" path="docs/architecture/[adr-file].md" output_mode="content" -A 40 + ``` + Escalate to a bounded `Read(offset, limit)` on one section only if a scanned + section cross-references material outside itself. + +Then make the story edit that option [A] names: set its `ADR Version` to the ADR's +current version resolved above — not today's date, or the next run mismatches +again — and replace its `**ADR Decision Summary**` and `## Implementation Notes` +with the guidance you just read, so a later run that trusts the stamp is trusting +current guidance. +If **[B]**: proceed on the summary; record it in the Phase 6 "Deviations" summary. +If **[C]**: stop. Do not spawn any agent. + +### The control manifest +Read only this story's layer from `docs/architecture/control-manifest.md` — grep that one +section (`Grep pattern="^## Layer Rules" path="docs/architecture/control-manifest.md" output_mode="content" -A 40`) rather than a full read of every layer. Extract the rules for this story's layer: +- Required patterns +- Forbidden patterns +- Performance guardrails + +Check: does the story's embedded Manifest Version match the current manifest header date? +If they differ, use `AskUserQuestion` before proceeding: +- Prompt: "Story was written against manifest v[story-date]. Current manifest is v[current-date]. New rules may apply. How do you want to proceed?" +- Options: + - `[A] Update story manifest version and implement with current rules (Recommended)` + - `[B] Implement with old rules — I accept the risk of non-compliance (the story records the current Manifest Version and a Manifest-Note)` + - `[C] Stop here — I want to review the manifest diff first` + +If [A]: edit the story file's `Manifest Version:` field to the current manifest date before spawning the programmer. Then read the manifest carefully for new rules. +If [B]: edit the story file's `Manifest Version:` field to the current manifest date AND add a `Manifest-Note: Proceeded with old manifest rules on [date] — non-compliance risk accepted.` line to the story header. Read the manifest for new rules anyway. Note the decision in the Phase 6 summary under "Deviations". `/story-done` will include the Manifest-Note in its deviations section without re-checking staleness. +If [C]: stop. Do not spawn any agent. Let the user review and re-run `/dev-story`. + +### Dependency validation + +After extracting the **Dependencies** list from the story file, validate each: + +1. Glob `production/epics/**/*.md` to find each dependency story file. +2. Read its `Status:` field. +3. If any dependency has Status other than `Complete` or `Done`: + - Use `AskUserQuestion`: + - Prompt: "Story '[current story]' depends on '[dependency title]' which is currently [status], not Complete. How do you want to proceed?" + - Options: + - `[A] Proceed anyway — I accept the dependency risk` + - `[B] Stop — I'll complete the dependency first` + - `[C] The dependency is done but status wasn't updated — mark it Complete and continue` + - If [B]: set story status to **BLOCKED** in session state and stop. Do not spawn any programmer agent. + - If [C]: ask "May I update [dependency path] Status to Complete?" before continuing. + - If [A]: note in Phase 6 summary under "Deviations": "Implemented with incomplete dependency: [dependency title] — [status]." + +If a dependency file cannot be found: warn "Dependency story not found: [path]. Verify the path or create the story file." + +--- + +### Engine reference +Read from `project.yaml` first, falling back to `.claude/docs/technical-preferences.md` for any key absent or empty: +- `specialists.*` — the project's chosen specialist agents; **read before** + `engine.name` when selecting an agent (see Phase 3) +- `engine.name` (else the `Engine:` value) — the generic engine specialist, and + the fallback when `specialists` is absent +- `naming.*` (else Naming conventions) — class names, file names, signal/event names +- `performance.*` (else Performance budgets) — frame budget, memory ceiling +- Forbidden patterns — from `.claude/docs/technical-preferences.md` (not migrated to project.yaml) + +### Mark Story In Progress + +Before spawning any agent, mark the story In Progress. In `collaborative` mode +ask once first — "May I mark this story In Progress? This sets `Status:` and +`Last Updated:` in `[story-path]` and its entry in `production/sprint-status.yaml`." +(leave the sprint-status file out of the question when it does not exist); +`guided` and `autonomous` update these existing files without asking +(`.claude/docs/automation-modes.md`). If the user declines, change neither file, +print `Story not marked In Progress — declined` in the Phase 6 summary, and +continue. Otherwise update two things: + +1. **`production/sprint-status.yaml`** (if it exists): find the entry matching this story's file path and set `status: in-progress`. Update the top-level `updated` field to today's date. If the file does not exist, say so in one line — `Sprint status not updated: production/sprint-status.yaml absent` — and continue. Do not skip silently: `/sprint-status` reads that file to report progress, so a story that never gets marked `in-progress` is invisible to the very command a producer uses to ask what is moving. + +2. **The story file itself**: set the story header's `Status:` field to `In Progress`, and edit its `Last Updated:` field to today's date (format: `YYYY-MM-DD`; if the field does not exist, add it after the `Status:` line). Setting `Status:` here is what actually marks the story In Progress — at `minimal` the `sprint-status.yaml` in step 1 is absent, so the story file is the only record of progress at that tier. + +--- diff --git a/.claude/skills/dev-story/references/3-route.md b/.claude/skills/dev-story/references/3-route.md new file mode 100644 index 00000000..0a6be1b3 --- /dev/null +++ b/.claude/skills/dev-story/references/3-route.md @@ -0,0 +1,89 @@ +# /dev-story — Phase 3: Route to the Right Programmer + +> Part of `/dev-story`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 3: Route to the Right Programmer + +Based on the story's **Layer**, **Type**, and **system name**, determine which +specialist to spawn via `Agent`. + +**Config/Data stories — skip agent spawning entirely:** +If the story's Type is `Config/Data`, no programmer agent or engine specialist is needed. Jump directly to Phase 4 (Config/Data note). The implementation is a data file edit — no routing table evaluation, no engine specialist. + +### Primary agent routing table + +| Story context | Primary agent | +|---|---| +| Foundation layer — any type | `engine-programmer` | +| Any layer — Type: UI | `ui-programmer` | +| Any layer — Type: Visual/Feel | `gameplay-programmer` (implements) | +| Core or Feature — gameplay mechanics | `gameplay-programmer` | +| Core or Feature — AI behaviour, pathfinding | `ai-programmer` | +| Core or Feature — networking, replication | `network-programmer` | +| Config/Data — no code | No agent needed (see Phase 4 Config note) | + +### Engine specialist — always spawn as secondary for code stories + +**Read the `specialists` block from `project.yaml` directly — it is not in +the `resolve_config` output at the top of this skill..** `resolve_config` does not emit +`specialists.*`; the five skills that already consume it (`/adopt`, +`/code-review`, `/design-system`, `/gate-check`, `/team-ui`) all read the block +out of `project.yaml` themselves, and so does this one. Adding it to the +frontmatter key list would fail the gate that asserts every requested key is one +`resolve_config` actually emits. + +`/setup-engine` writes the block, and it is the project's own answer to "which +specialist implements here" — resolved from the engine *and the language*, which +`engine.name` alone cannot tell you. Resolve in this order: + +1. **`specialists.code`** — the language/code specialist, and the right secondary + for an implementation story. This is the value that distinguishes a Godot C# + project (`godot-csharp-specialist`) from a Godot GDScript one + (`godot-gdscript-specialist`); `engine.name` is `Godot` for both. +2. **`specialists.shader`** when the story touches shaders or materials, and + **`specialists.ui`** when the story's Type is `UI` — in addition to, not + instead of, `specialists.code`. +3. **The generic `-specialist`** — derived from `engine.name` + (Godot→`godot-specialist`, Unity→`unity-specialist`, + Unreal→`unreal-specialist`) — for architecture-level and broad engine + concerns, and as the fallback when the `specialists` block is absent. +4. If `engine.name` is also absent or empty, read the Primary line of the + `## Engine Specialists` section of `.claude/docs/technical-preferences.md`. + +**A value of `null` means UNSET — treat that key as absent and fall through to +the generic specialist. Never spawn it as an agent name.** The config reader +returns the four-character string `"null"`, which is not empty and therefore +reads as configured; `null`, empty and missing are the same state here. (This is +the same caveat `/code-review` Phase 2 carries, for the same reason.) + +Spawn the resolved specialist alongside the primary agent when the story involves +engine-specific APIs, patterns, or the ADR has HIGH engine risk. + +The full roster, for reference when no `specialists` block exists: + +| Engine | Specialist agents available | +|--------|----------------------------| +| Godot 4 | `godot-specialist`, `godot-gdscript-specialist`, `godot-csharp-specialist`, `godot-shader-specialist`, `godot-gdextension-specialist` | +| Unity | `unity-specialist`, `unity-ui-specialist`, `unity-shader-specialist`, `unity-dots-specialist`, `unity-addressables-specialist` | +| Unreal Engine | `unreal-specialist`, `ue-gas-specialist`, `ue-blueprint-specialist`, `ue-umg-specialist`, `ue-replication-specialist` | + +> **Do not pick from this table when `specialists` is set.** The table lists what +> *exists* for an engine; the block records what this project *chose*. Reading the +> table instead of the block is how a Godot C# project ends up reviewed by the +> GDScript specialist. + +**When engine risk is HIGH** (from the ADR or VERSION.md): always spawn the engine +specialist, even for non-engine-facing stories. High risk means the ADR records +assumptions about post-cutoff engine APIs that need expert verification. + +> **Read the risk, do not trust the story card alone.** If the story's `Risk` +> field is absent, or says `NOT ASSESSED`, **or disagrees with +> `docs/engine-reference//VERSION.md`, the VERSION.md rating wins** and an +> unknown counts as HIGH. At `minimal` there is no ADR, so VERSION.md is the only +> source; a story card carrying an improvised `MEDIUM` against a VERSION.md +> rating of HIGH would skip this spawn without saying so. `/create-stories` now derives the field +> from the same file, so the two should agree; this check is what catches it when +> they do not. + +--- diff --git a/.claude/skills/dev-story/references/4-implement.md b/.claude/skills/dev-story/references/4-implement.md new file mode 100644 index 00000000..e9230cd4 --- /dev/null +++ b/.claude/skills/dev-story/references/4-implement.md @@ -0,0 +1,68 @@ +# /dev-story — Phase 4: Implement + +> Part of `/dev-story`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 4: Implement + +Spawn the chosen programmer agent(s) via `Agent` with the full context package: + +Brief the agent with file paths and targeted reading instructions — do not serialize document content into the `Agent` prompt. The agent reads what it needs directly. + +> **Tier note (from Phase 2):** items 2–4 below assume the `full` baseline. At +> `standard`, include the TR registry only if it exists and the governing ADR +> only where the story references one — at any tier, a story whose ADR field +> reads `N/A` has no item 3. At `minimal`, the TR registry, ADR, and +> control manifest are typically absent — **omit items 2–4 and brief the agent to +> implement against the story's Acceptance Criteria and the GDD/brief** (the +> story file from item 1). Never instruct the agent to read a file Phase 2 +> confirmed missing. +> +> **Say which items you dropped, and say it to both readers.** The rule item 7 +> already carries applies unchanged to items 2–4: *an omitted item and a +> forgotten one are indistinguishable to the agent.* They are equally +> indistinguishable to the user reading the Phase 6 summary. +> - **To the agent**, in the prompt: *"No TR registry entry is passed for this +> story — `docs/architecture/tr-registry.yaml` does not exist at this tier. +> Implement against the story's Acceptance Criteria and the GDD/brief. Do not +> go looking for it."* Same form for an absent ADR or control manifest. +> - **To the user**, one line before spawning: `Briefing omits: TR registry +> (absent), ADR guidance (story references no ADR), control manifest +> (absent) — implementing against acceptance criteria + GDD.` +> +> Without this, a `standard` run where the registry legitimately does not exist +> and one where `/architecture-review` was supposed to bootstrap it and nobody +> did produce **identical output**. + +1. **Story file**: `[story-path]` — the agent reads this one file; it carries the acceptance criteria, Out of Scope boundaries, and QA test cases +2. **GDD requirement**: look up TR-ID `[TR-XXX-NNN]` in `docs/architecture/tr-registry.yaml` — use the `requirement` field as source of truth +3. **ADR guidance**: pass the story's `**ADR Decision Summary**` and `## Implementation Notes` **inline in the prompt** — do not pass the ADR path. Phase 2 already established that this summary is current; handing the agent a path makes it re-read the whole ADR in its own context, paying the cost this skill just avoided. After mismatch option `[A]`, pass the guidance freshly read from the ADR's `## Decision` (the text [A] just wrote into the story), never the stale summary the story carried before; after `[B]`, pass the story's summary and tell the agent it predates the current ADR. +4. **Control manifest**: `docs/architecture/control-manifest.md` — read rules for the **[layer]** layer only +5. **Engine preferences**: `naming.*` and `performance.*` from `project.yaml` (for any key absent or empty, fall back to `.claude/docs/technical-preferences.md`) +6. **Test file path**: `[path from story's Test Evidence section]` — this file must be created as part of implementation +7. **Test requirement** (Logic and Integration stories only; **omit this entire item at `qa.level: minimal`** — tests are not required there. When you omit it for a Logic or Integration story, tell the agent so explicitly — never a UI, Visual/Feel or Config/Data story, which this item never covered: *"Do not write a test file for this story — test evidence is waived at `qa.level: minimal`."* An omitted item and a forgotten one are indistinguishable to the agent, and a programmer briefed with no test instruction may write tests anyway, or may silently assume they were meant to): The test file MUST be created at `[path from the story's Test Evidence section]`. Write the test alongside the implementation — do not defer it. At `qa.level: standard`/`full` the story cannot be closed via `/story-done` without this file present. Each acceptance criterion must have at least one test function covering it. Test naming per engine, from `.claude/rules/test-standards.md`: Godot `test_[scenario]_[expected]` in `[system]_[feature]_test.gd`; Unity `[Scenario]_[Expected]` in a `[System]Tests` class; Unreal `.[System].[Scenario]`. No random seeds, no time-dependent assertions, no external I/O. +8. **Explicit instruction**: implement this story following the ADR guidelines, respect the manifest rules, stay within the story's Out of Scope boundaries. Write clean, doc-commented public APIs. + +The agent should: +- Create or modify files under the **resolved code root** following the ADR guidelines. Resolve it per `.claude/docs/code-root-resolution.md` — `src/` is the Godot row, `Assets/Scripts//` is Unity's, `Source///` is Unreal's. **If the code root cannot be resolved, do not write: report it and stop.** Selecting the engine specialist above is NOT the same as resolving the code root +- Respect all Required and Forbidden patterns from the control manifest +- Stay within the story's Out of Scope boundaries (do not touch unrelated files) +- Write clean, doc-commented public APIs + +### Config/Data stories (no agent needed) + +For Type: Config/Data stories, no programmer agent is required. The implementation +is editing a data file. Read the story's acceptance criteria, show the specified +changes as from → to values, and ask "May I write to [data file path]?" before +editing it directly. Note which values were changed and what they changed from/to. + +### Visual/Feel stories + +Spawn `gameplay-programmer` to implement the code/animation calls. The *look* +half of the acceptance criteria — layout, clipping, presence, colour — is +verified in Phase 6 step 4 by launching the build and retaining a screenshot; +it is not deferred. The *feel* half — timing, weight, responsiveness — is not +something a still can show: say which half the run covered, and leave feel to +`/team-qa`. + +--- diff --git a/.claude/skills/dev-story/references/5-test-evidence.md b/.claude/skills/dev-story/references/5-test-evidence.md new file mode 100644 index 00000000..acf67ee9 --- /dev/null +++ b/.claude/skills/dev-story/references/5-test-evidence.md @@ -0,0 +1,74 @@ +# /dev-story — Phase 5: Test Evidence Requirements + +> Part of `/dev-story`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 5: Test Evidence Requirements + +The test requirement was included in the Phase 4 programmer agent brief (item 7). This phase summarizes what evidence each story type requires — used when collecting the Phase 6 summary. + +**Skip this phase at `qa.level: minimal`** (resolved earlier) — no test evidence +is required, so there is nothing to gate; do not flag the story unverifiable for a +missing test. **The Visual/Feel and UI screenshot line at the end of this phase +still applies** — `qa.level` waives tests, never the look. + +> **Say so in the Phase 6 summary.** A skipped phase must announce itself in the +> output, not only in this file (`.claude/rules/skill-authoring.md`, obligation +> 3). For a Logic or Integration story — the types Phase 4 item 7 briefs a test +> for — emit the line: +> +> > *Test evidence: **waived** at `qa.level: minimal` — no test was required or +> > written for this story.* +> +> Without it, a minimal-tier summary that simply lacks a tests row is +> indistinguishable from a `standard`-tier run where the programmer forgot to +> write them — and the permissive reading is the one that gets believed. + +Otherwise: + +**Resolve the gate level for this story's type** from `testing.strict` in +`project.yaml`. BLOCKING means a missing test marks the story unverifiable; +ADVISORY means a missing test is noted but does not block: + +1. Map the Story Type to a `testing.strict` key — Logic→`logic`, + Integration→`integration`, Visual/Feel→`visual`, UI→`ui`, Config/Data→`config`. + Take `testing.strict.` from the **the resolved-config block at the top of this skill**, not from + `project.yaml` directly. If its value is `true` (case-insensitive) → + BLOCKING; if `false` → ADVISORY; `unset` → fall through. + +> `testing.strict.*` is locally overridable (`/settings --local +> testing.strict.logic=false`). Reading `project.yaml` on its own ignores +> `project.local.yaml` entirely, so the override is accepted and then does +> nothing. `resolve_config` merges the two. +2. Else read `testing.strict` as a plain boolean (legacy single-value form) — if + its value is `true` or `false`, it applies to every type. +3. Else use the **Default Gate Level** column below. + +Only `true` and `false` (case-insensitive) are recognized at steps 1–2. A key +that is present but holds any other value — `maybe`, `1`, `yes`, etc. — is +treated as unset: continue to the next step, and surface the unrecognized value +to the user. + +| Story Type | Required Evidence | Default Gate Level | +|---|---|---| +| **Logic** | Automated unit test at path from story's Test Evidence section | BLOCKING | +| **Integration** | Integration test OR documented playtest record | BLOCKING | +| **Visual/Feel** | Retained screenshot + evidence doc at `production/qa/evidence/[slug]-evidence.md` | BLOCKING | +| **UI** | Retained screenshot of each screen touched, in `production/qa/evidence/` | BLOCKING | +| **Config/Data** | None — smoke check serves as evidence | ADVISORY | + +The test is written alongside the implementation (Phase 4, item 7) regardless of +the gate level — strictness controls only how a *missing* test is reported in the +Phase 6 summary. At a BLOCKING level, a missing test is flagged "story +unverifiable — test required before `/story-done`". At an ADVISORY level it is +noted as a recommendation. The **Default Gate Level** column applies when +`testing.strict` is unset. + +Visual/Feel and UI default to **BLOCKING**: for a game the rendered result is the +product, and an advisory visual gate gets deferred in favour of whatever does +block. A project that genuinely does not need it sets `testing.strict.visual` or +`testing.strict.ui` to `false`. + +For Visual/Feel and UI stories, include in the Phase 6 summary: "Retained screenshot required under `production/qa/evidence/[story-slug]/` before this story can be closed — at the default BLOCKING level a story with no screenshot on disk is unverifiable." For Visual/Feel, add that the sign-off in `production/qa/evidence/[slug]-evidence.md` is also required. + +--- diff --git a/.claude/skills/dev-story/references/6-collect.md b/.claude/skills/dev-story/references/6-collect.md new file mode 100644 index 00000000..faaa937d --- /dev/null +++ b/.claude/skills/dev-story/references/6-collect.md @@ -0,0 +1,113 @@ +# /dev-story — Phase 6: Collect and Summarise + +> Part of `/dev-story`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 6: Collect and Summarise + +**In this file:** + +- First: did the agent actually finish? +- Then collect: + +### First: did the agent actually finish? + +**Do not assume completion.** A programmer agent can stop at its turn limit +mid-edit, and the work it leaves behind can be syntactically broken — a helper +called but never defined, an import half-moved. Its partial report reads like +progress, and this phase's summary would print "Implementation Complete" over +code that does not load. + +Before collecting anything: + +1. **Check the agent's own terminal state.** If it reported stopping early, hit a + turn/step limit, or its report ends mid-task, treat the story as **INCOMPLETE**. +2. **Verify the output parses.** Run the check whose **exit code** answers the + question — an exit 0 from a command that does not check is how broken code + gets reported as clean: + - **Godot:** `godot --headless --path . --import` once (it builds the class + cache), then one run over every `.gd` the story added or changed: + `godot --headless --path . -s res://.claude/scripts/godot-parse-check.gd -- res://.gd …`. + For `godot`, use the executable `commands.test` names, else the editor + `engine.path` records, else `godot` on `PATH`; if none resolves, write + `parse NOT VERIFIED — Godot executable not found`. + Exit 1 means a script did not load — its `PARSE FAIL:` line names it, with + Godot's error above. Do not use `--check-only`: it fails valid code that + names an autoload. `--import` and `--quit-after` on their own exit 0 on a + parse error — they are not parse checks. + - **Unity:** `commands.smoke` (`-batchmode -quit -projectPath . -logFile -`) + — exit 1 with `error CS…` lines when a script does not compile. + - **Unreal:** build the editor target — + `"/Engine/Binaries/DotNET/UnrealBuildTool/UnrealBuildTool.exe" Editor Win64 Development -Project="/.uproject"` + on Windows; on Linux `"/Engine/Build/BatchFiles/Linux/Build.sh" Editor Linux Development -Project=…`, + on macOS `…/Mac/Build.sh Editor Mac Development -Project=…` (from Epic's + documentation — `docs/engine-reference/unreal/current-best-practices.md`, "Command Line"). + A compile error fails the build (`Result: Failed`, non-zero exit). + Report what you ran, its exit code, and any error lines. +3. If the engine binary is unavailable, write **`parse NOT VERIFIED — engine + binary not available`**. Do not infer that the code is fine because it reads + correctly; that inference is exactly what this step exists to replace. +4. **Run it and look.** A parse check is not a run. For every story that + changes something a player can see — every Visual/Feel and UI story, and any + Logic, Integration or Config/Data story with a surface — launch the build + via `commands.run`, straight into the scene or map the story touched, and + retain a screenshot under `production/qa/evidence/[story-slug]/`. Then + `Read` the image and compare it to the acceptance criteria: clipped text, + an overflowing panel, a missing element are defects, and this is the only + step that finds them. Procedure per engine, including how to capture + unattended in Godot, Unity and Unreal: `.claude/docs/run-and-observe.md`. + **On Unity** the capture needs the `ScreenshotOnArg.cs` script that file gives + verbatim. If the project has none (Glob `Assets/**/ScreenshotOnArg.cs`), ask + "May I write `Assets/Scripts/ScreenshotOnArg.cs`?" and write it exactly as + given there before launching; if the user declines, nothing can capture — + report `Run result: NOT VERIFIED — ScreenshotOnArg.cs not written`. + Report exactly one line — `Run result: OBSERVED — ` + with the retained path, `Run result: NOT VERIFIED — `, or + `Run result: N/A — ` for a story with genuinely nothing observable. + **`NOT VERIFIED` is a blocker at the default gate level for Visual/Feel and + UI, not a note** — `/story-done` reads this line. This step is **not waived + at `qa.level: minimal`**; tests are, the look is not. + +**If INCOMPLETE:** say so as the headline, list what exists so far, name the +specific breakage, and offer to resume the agent. Do **not** emit +"Implementation Complete", and do not advance the story's status. + +### Then collect: + +- Files created or modified (with paths) +- **Verification result** — what was run, and its outcome (or why it could not run) +- Test file created (path and number of test functions written) — **or**, at + `qa.level: minimal`, the waiver line from Phase 5 +- Any deviations from the story's Out of Scope boundary (flag these) +- Any questions or blockers the agent surfaced +- Any engine-specific risks the specialist flagged + +Present a concise implementation summary: + +``` +## Implementation Complete: [Story Title] + +**Files changed**: +- `/[path]` — created / modified ([brief description]) +- `tests/[path]` — test file ([N] test functions) — *omit this line at + `qa.level: minimal` and print the Phase 5 waiver line instead (Logic/Integration)* + +**Verification**: [what was run] — [result, or `NOT VERIFIED — `] +**Run result**: [`OBSERVED — ` + retained path | `NOT VERIFIED — ` | `N/A — `] — see `.claude/docs/run-and-observe.md` + +**Acceptance criteria covered**: +- [x] [criterion] — implemented in [file:function] +- [x] [criterion] — covered by test [test_name] +- [x] [criterion] — OBSERVED in `production/qa/evidence/[slug]/01-[what].png` (Visual/UI look) +- [ ] [criterion] — DEFERRED: requires playtest (Visual/Feel *feel* — timing, weight; a still cannot show it) + +**Deviations from scope**: [None] or [list files touched outside story boundary] +**Engine risks flagged**: [None] or [specialist finding] +**Blockers**: [None] or [describe] + +**Before running `/story-done`:** run your test suite locally and confirm the tests you wrote pass. *(At `qa.level: minimal` no tests were written — print the Phase 5 waiver line here instead of this paragraph for a Logic or Integration story, and omit both for any other type. Telling a user to confirm the passing of tests that do not exist is worse than saying nothing.)* **`/story-done` does NOT re-run them** — its Phase 3 checks that the test FILE exists, with `Glob`, and nothing executes it. A test that exists and fails satisfies that gate. Nothing downstream makes the local run safe to skip. Pass/fail is established by `/gate-check` and `/smoke-check`, both of which execute a suite — and both come later than story closure. + +Ready for: `/story-done [story-path]` — at `standard`/`full`, `/code-review [file1] [file2]` first +``` + +--- diff --git a/.claude/skills/dev-story/references/7-session-state.md b/.claude/skills/dev-story/references/7-session-state.md new file mode 100644 index 00000000..62943c93 --- /dev/null +++ b/.claude/skills/dev-story/references/7-session-state.md @@ -0,0 +1,40 @@ +# /dev-story — Phase 7: Update Session State + +> Part of `/dev-story`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 7: Update Session State + +Silently update the checkpoint in `production/session-state/active.md` — +**overwrite the `` … `` block, never +append** (schema: `.claude/docs/templates/session-state.md`). `session-start.sh` +shows exactly that block when the next session opens, so it is what a cold +resume starts from: + +``` + +**Updated:** [date] +**Branch:** `[current git branch]` +**Current task:** /dev-story — [story-path] ([story title]) +**Next step:** /story-done [story-path] (at standard/full: /code-review [files] first) +**Blocked on:** [nothing, or the blocker] +**Files in progress:** [files changed, comma-separated; test file included] +**Run result:** [the Phase 6 `Run result:` line, verbatim — `/story-done` reads it here] +**Open questions:** [none, or one line each] + +``` + +**Next step** follows the Phase 6 result — the line above is the Implementation +Complete one. On **INCOMPLETE** write +`**Next step:** /dev-story [story-path] — resume: [the breakage Phase 6 named]`. +On **BLOCKED** (Phase 2) write the unblocking action instead — +`/architecture-decision accept ADR-NNNN`, the dependency story to finish, the +manifest diff to review — and fill **Blocked on**. `/help` reads this line: a +checkpoint that says `/story-done` tells it the work is written. + +If `active.md` does not exist, create it from the template. If it exists with no +markers (a file from before the schema), insert the template's STATUS and +CHECKPOINT blocks at the top and leave the rest untouched. Confirm: "Session +state updated." + +--- diff --git a/.claude/skills/estimate/SKILL.md b/.claude/skills/estimate/SKILL.md index c3f2f72d..1b0723f9 100644 --- a/.claude/skills/estimate/SKILL.md +++ b/.claude/skills/estimate/SKILL.md @@ -7,6 +7,8 @@ allowed-tools: Read, Glob, Grep model: sonnet --- +# Estimate + ## Phase 1: Understand the Task Read the task description from the argument. If the description is too vague to estimate meaningfully, ask for clarification before proceeding. @@ -125,7 +127,7 @@ This skill is read-only — no files are written. Verdict: **COMPLETE** — esti - If confidence is Low: recommend a time-boxed spike (`/prototype`) before committing. - If the task is > 10 days: recommend breaking it into smaller stories via `/create-stories`. -- To schedule the task: run `/sprint-plan update` to add it to the next sprint. +- To schedule the task: run `/sprint-plan update` to add it to the next sprint (if the project has no sprint plan, as on the default minimal workflow, add it to the brief's build order instead). ### Guidelines diff --git a/.claude/skills/gate-check/SKILL.md b/.claude/skills/gate-check/SKILL.md index c94d4446..565c2065 100644 --- a/.claude/skills/gate-check/SKILL.md +++ b/.claude/skills/gate-check/SKILL.md @@ -12,7 +12,6 @@ model: opus Resolved above — use as-is; `--review` overrides `review_mode`. No block → defaults in `.claude/docs/config-resolution.md`. - # Phase Gate Validation This skill validates whether the project is ready to advance to the next development @@ -41,7 +40,6 @@ The project progresses through these stages: **Target phase:** `$ARGUMENTS` with any `--review ` pair removed (blank = auto-detect current stage, then validate next transition). `/gate-check --review full` names no phase. - Note: in `solo` mode, director spawns (CD-PHASE-GATE, TD-PHASE-GATE, PR-PHASE-GATE, AD-PHASE-GATE) are skipped — gate-check becomes artifact-existence checks only. In `lean` mode, the phase-gate directors still run (phase gates are the purpose of lean mode); how many of them run is set by `workflow` below. **`workflow`** (per `.claude/docs/workflow-modes.md`): @@ -104,770 +102,39 @@ transition; never load the others.** | Gate | Definition file | |------|-----------------| -| Concept → Systems Design | `.claude/skills/gate-check/references/gate-systems-design.md` | -| Systems Design → Technical Setup | `.claude/skills/gate-check/references/gate-technical-setup.md` | -| Technical Setup → Pre-Production | `.claude/skills/gate-check/references/gate-pre-production.md` | -| Pre-Production → Production | `.claude/skills/gate-check/references/gate-production.md` | -| Production → Polish | `.claude/skills/gate-check/references/gate-polish.md` | -| Polish → Release | `.claude/skills/gate-check/references/gate-release.md` | +| Concept → Systems Design | `references/gate-systems-design.md` | +| Systems Design → Technical Setup | `references/gate-technical-setup.md` | +| Technical Setup → Pre-Production | `references/gate-pre-production.md` | +| Pre-Production → Production | `references/gate-production.md` | +| Production → Polish | `references/gate-polish.md` | +| Polish → Release | `references/gate-release.md` | Each file states the `full` baseline first, then the `standard` and `minimal` reductions for that gate. Apply the tier resolved in Section 1. ## 2b. Workflow Tier Adjustment -Each gate file carries its own tier reductions (see Section 2). Two rules apply -across all of them: - -> **How to apply:** run the loaded gate's checklist, then apply that file's tier -> reduction for the tier resolved in Section 1. **drop** = not checked at this -> tier; **→ recommended** = absent surfaces as CONCERNS, never a Blocker; items -> not named keep their baseline status. Reductions only ever *relax* a -> requirement — the only thing that adds one is `workflow_overrides` (below). -> -> **`qa.level` (Section 1) further relaxes the test items independently of the -> tier:** at `qa.level: minimal` the test-evidence / unit-test items become -> non-required at every workflow tier (so even `workflow: full` does not require -> them); the Section 3 `testing.strict` check is then a no-op. -> -> **It relaxes tests, not the look.** A UI story's retained screenshots, and a -> Visual/Feel story's screenshots plus lead sign-off, are required at every -> `qa.level` wherever the gate file asks for story evidence -> (`.claude/docs/coding-standards.md`: tests are waived at `minimal`, the look -> is not). -> -> **The smoke check is excluded from that relaxation, and is the floor.** -> `qa.level` relaxes *per-story test evidence*; a smoke check is **build health**, -> not story evidence, and the two are already held apart on exactly this basis in -> `.claude/docs/coding-standards.md` ("`/smoke-check` is a build-health gate, not -> a per-story evidence gate ... This divergence is intentional"). So a gate file -> that requires a smoke report keeps requiring it at every `qa.level`. -> -> Without that exclusion the Production → Polish gate had **zero required -> artifacts at `rigor: minimal`** and could not fail on artifacts by -> construction: `minimal` reduced the gate to the smoke check alone, `qa.level` -> then dropped the smoke check too, and one `modes.rigor` setting fires both. - -> **A gate with no required artifacts left must say so, and may not return -> PASS.** After applying the tier reduction and the `qa.level` relaxation, count -> what remains required. If the count is zero, report -> **NOT ASSESSED** naming both reducers and the gate — *"Production → Polish at -> `workflow: minimal` + `qa.level: minimal` leaves no required artifact; this -> gate verified nothing"* — rather than a PASS earned by having nothing to check. -> Per `.claude/rules/skill-authoring.md` obligation 1, a run that could not -> assess its scope has not established that the scope is good, and obligation 3 -> requires the emptiness to be visible in the output rather than inferable from -> a silent green. -> -> **The one exception: a gate its tier reference file marks "not applicable" at -> this tier** (Systems Design → Technical Setup at `workflow: minimal`). That is -> not a gate with nothing left to check but a transition the tier does not have: -> it PASSes with that file's note, printed in the report. The director panel -> does not run for it — note "Director Panel skipped — gate not applicable at -> `workflow: [tier]`" — and the Section 6 stage write still asks first. -> -> **`performance.enforce` is likewise independent of the tier, and a tier -> reduction never suppresses it.** The performance check in Section 3 runs at -> every workflow tier, and `block` makes a breach a Blocker at every workflow -> tier. Do **not** read a gate file's *"everything else drops"* as dropping it: -> `off` is the only thing that makes budgets informational, and it is a -> deliberate choice the user makes on the same key. -> -> Without this, `performance.enforce: block` is **inert on every `rigor: minimal` -> project** — the Polish gate's `minimal` reduction drops everything outside its -> floor, and "Performance is within budget" sits in the dropped remainder. A -> setting that works only when a rule is disregarded is not wired. - -### Per-system overrides (`workflow_overrides.system_overrides`) - -Independent of the project-level tier above, and applied **only** on the gates -that validate MVP GDDs (Systems Design → Technical Setup, and the GDD-completeness -checks at Pre-Production → Production). For each system, resolve its effective -tier: - -1. If the block's `system_overrides` lists `` → that tier -2. Else the project-level `workflow` - -**Before applying any of them, check the block the other way round: does every -KEY match a system?** `` is the GDD filename stem -(`.claude/docs/workflow-modes.md`), so for each key in `system_overrides`, look -for `design/gdd/.md`. Any key with no matching stem is reported, naming the -key and listing the stems that do exist: - -> `system_overrides key 'no-such-system' matches no GDD in design/gdd/. Available stems: combat, inventory, hammer-heat-system. This override is doing nothing.` - -Surface it as a **CONCERNS**-level finding, not a Blocker — the project is still -gateable, but an override the user believes is in force and is not is exactly how -a documented escape hatch silently stops working. - -> **This is the one site that performs the check.** `workflow-modes.md:72` says -> *"a key that matches no system is an error, not a no-op"*, and this is the only -> skill that implements it — the three story skills resolve only in the -> system → override direction, so an orphan key is never looked up and -> never noticed. `/gate-check` is the right home: it already resolves the whole -> block, and it is the project-wide audit rather than a per-story one. - -Validate each GDD against its own effective tier's section count: - -- A system pinned **higher** than the project (e.g. `system_overrides.combat: - full` on a `standard` project) **blocks the gate** until that system's GDD - meets the higher bar (combat → all 8 sections). This is the one case where a - per-system setting makes the gate *stricter* than the project tier. -- A system pinned **lower** (e.g. `inventory: minimal`) relaxes only that system - — its GDD is checked at the lower tier; every other system stays at the project - level. A system pinned **`minimal` imposes no GDD section requirement at all** - (`minimal` = "game brief replaces GDDs" — `.claude/docs/workflow-modes.md`): it - never blocks the gate on a missing or incomplete GDD. Do not invent an - "acceptance-criteria-only" floor for it — there is none. - -> **Additive overrides (the only things that make the gate stricter).** -> - `workflow_overrides.art_bible_strict: true` forces the complete (9-section) -> art bible at the Technical Setup → Pre-Production and Pre-Production → -> Production gates regardless of tier or whether visual-asset stories exist. -> - `workflow_overrides.edge_cases: true` and `workflow_overrides.tuning_knobs: -> true` force those GDD sections required when validating GDD completeness, -> additive on top of the resolved tier (e.g. at `standard`, `tuning_knobs: true` -> makes the otherwise-optional Tuning Knobs section blocking). These never -> relax — a `false` value is the default/no-op, never a way to drop a section -> the tier already requires. - ---- +**Read `references/2b-workflow-tier.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 3. Run the Gate Check -**Before running artifact checks**, read `docs/consistency-failures.md` if it exists. -Extract entries whose Domain matches the target phase (e.g., if checking -Systems Design → Technical Setup, pull entries in Economy, Combat, or any GDD domain; -if checking Technical Setup → Pre-Production, pull entries in Architecture, Engine). -Carry these as context — recurring conflict patterns in the target domain warrant -increased scrutiny on those specific checks. - -For each item in the target gate: - -### Artifact Checks - -**Resolve existence and counts deterministically — do not open files to find out -what exists:** - -``` -Bash: bash .claude/scripts/artifact-check.sh --phase [source-phase] -``` - -Pass the phase being advanced *from* (its steps are the work that must be -complete): `systems-design` for the Systems Design → Technical Setup gate, -`pre-production` for Pre-Production → Production, and so on. - -At `workflow: minimal`, also run -`bash .claude/scripts/artifact-check.sh --path minimal`: the brief and stories -live on that path, not on any phase, and its `game-brief` and `create-stories` -rows are this tier's floor. - -It reads `workflow-catalog.yaml` — which already encodes each step's `glob`, -`pattern`, `min_count` and `any_of` — and reports per step: - -| status | Meaning | -|---|---| -| `PRESENT` | glob matched, `min_count` met, `pattern` found where specified | -| `ABSENT` | nothing matched | -| `SHORT` | matched but fewer than `min_count` (`count=` and `min=` given) | -| `PATTERN_MISS` | files exist but none contains the required marker | -| `NO_CHECK` | the step declares no artifact — **not detectable from disk** | - -It emits observations, never a verdict: **you** apply the workflow tier and the -required/optional split from Section 2. An `ABSENT` required artifact is a -blocker at `full` and frequently not one at `minimal`; the script does not know -that and does not decide it. - -**`NO_CHECK` is not `PRESENT`.** The header prints a `NO_CHECK:` count before any -row precisely so this cannot be skimmed past. Those steps were *scanned*, not -*satisfied* — carry each into Section 4 (Collaborative Assessment) and ask, or -mark MANUAL CHECK NEEDED. A gate that reports PASS because most of its checklist -was undetectable is the failure mode this count exists to prevent. - -**Existence is not adequacy.** The script cannot tell a real document from a -template skeleton. So: for any artifact the verdict actually turns on, spot-read -it and confirm it has real content — the same escalation rule the -`gdd-structure-check.sh` step below uses. Do not spot-read artifacts the verdict -does not turn on. - -> **A smoke report is always an artifact the verdict turns on — spot-reading it -> is mandatory, not discretionary.** At `minimal` it is frequently the *only* -> required artifact, so the whole gate rests on one file that nothing generated -> and nothing verifies. Check its claims against the repo, and raise any that the -> tree contradicts: -> -> - It reports a passing automated suite → the engine's test root must actually -> contain test files and the project must have a runner. "24 passed, 0 failed" -> in a repo with no test files under that root — `tests/unit/` and -> `tests/integration/` on Godot, `Assets/Tests/` on Unity, -> `Source//Private/Tests/` on Unreal — and no runner is a finding, not -> evidence. -> - It marks a critical path PASS → the code for that path must exist in the code -> root. A PASS on "banking ends the run" with no banking code is a finding. -> - It carries no date, or predates the newest commit touching the code root → -> say so; a stale smoke report describes a build that no longer exists. -> -> Report a contradiction at the same level the artifact was required at: a -> Blocker where the smoke check is required, CONCERNS where it is recommended. -> Existence plus a verdict-line grep would clear a fabricated report. - -For code checks, verify directory structure and file counts. - -**Systems Design → Technical Setup gate — cross-GDD review check**: -Use `Glob('design/gdd/gdd-cross-review-*.md')` to find the `/review-all-gdds` report. -If no file matches: at `full` mark the "cross-GDD review report exists" artifact as -**FAIL** and surface it prominently ("No `/review-all-gdds` report found in -`design/gdd/`. Run `/review-all-gdds` before advancing to Technical Setup."); at -`standard` the report is recommended, so mark it **CONCERNS**, not a blocker; at -`minimal` this gate is not applicable (see the gate file). If a file is found, read it and -check the verdict line: a FAIL verdict means the cross-GDD consistency check failed -and must be resolved before advancing. A NOT ASSESSED verdict means that review -could not compare the GDDs, so it satisfies nothing here: mark the item NOT -ASSESSED for this gate, never passed. - -### Quality Checks -- For test checks: Run the test suite via `Bash` if a test runner is configured. - **If no runner is configured, that is `NOT ASSESSED`, not a silent skip** — see - the trigger in the verdict section. A gate that ran no tests found no test - failures, which is not the same as passing. - A test failure's effect on the verdict depends on the `testing.strict` block - **resolved in Phase 1** (`resolve_config` merges `project.local.yaml` over - `project.yaml`; reading the file directly would drop a local override), per - test type: - - **Logic** — unit-level failures (`tests/unit/` on Godot, Edit Mode on - Unity), gated by `testing.strict.logic`. - - **Integration** — failures in `tests/integration/` on Godot, Play Mode on - Unity, gated by `testing.strict.integration`. On Unreal, where one root - (`Source//Private/Tests/`) holds both, classify a failure by its - story's Type, or apply the stricter of the two levels when that is unknown. - - For each type: take `testing.strict.` from that block; use it only - if its value is `true` or `false` (case-insensitive). If the key is absent, - empty, or holds any other value, read `testing.strict` as a plain boolean - (legacy single-value form); if that too is absent or invalid, default to - `true` (Logic and Integration are both strict by default — behavior unchanged - from before this setting existed). Surface any unrecognized value to the user. - - At a strict (`true`) gate level, failures of that type are **Blockers** - (verdict FAIL). At an advisory (`false`) level, they are **Concerns** - (verdict minimum CONCERNS, not FAIL) — list them under Recommendations, not - Blockers. -- For design review checks, gather section presence **deterministically** — do not - read the GDDs to count headings: - - ``` - Bash: bash .claude/scripts/gdd-structure-check.sh - ``` - - It prints a `PRESENT:` / `ABSENT:` pair per GDD and already accepts - `## Detailed Design` as satisfying the `Detailed Rules` requirement. It reports - presence only and makes no REQUIRED/ADVISORY judgment. - - Then apply each GDD's **effective tier** (per-system resolution below) to those - lists — all 8 sections at `full`, the 5 standard sections (+ conditional - Formulas) at `standard`. A missing *required* section blocks; a missing section - that is optional at the effective tier is advisory. A section reported PRESENT - can still fail review if it is an empty heading — spot-read any section the - verdict actually turns on. -- For performance checks: read the budgets (`performance.target_framerate`, - `frame_budget_ms`, `draw_call_limit`, `memory_ceiling_mb`) from `project.yaml` - (else technical-preferences.md) and compare against any profiling data in - `tests/performance/` or recent `/perf-profile` output. What a breach *means* - is set by `performance.enforce`, taken from the Phase 1 resolved block (it is - locally overridable, so do not read the file for this one): - - `warn` (default) — breaches are **CONCERNS**, never Blockers. - - `block` — breaches are **Blockers** from the Polish gate onward. - - `off` — budgets are informational; do not surface breaches in the verdict. - - Only these three values are recognized. Surface anything else to the user and - fall back to `warn` rather than guessing. -- For localization checks: `Grep` for hardcoded strings in the **code root** (resolve per `.claude/docs/code-root-resolution.md`). **If the code root is unresolved, report `NOT ASSESSED — code root unresolved` rather than zero hits.** - -### Cross-Reference Checks -- Compare `design/gdd/` documents against implementations in the **code root** -- Check that every system referenced in architecture docs has corresponding code -- Verify sprint plans reference real work items - ---- +**Read `references/3-run-gate-check.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 4. Collaborative Assessment -For items that can't be automatically verified, **ask the user**: - -- "I can't automatically verify that the core loop plays well. Has it been playtested?" -- "No playtest report found. Has informal testing been done?" -- "Performance profiling data isn't available. Would you like to run `/perf-profile`?" - -**Never assume PASS for unverifiable items.** Mark them as MANUAL CHECK NEEDED. -An answer resolves the item: "no" or "not yet" is a checked, failed item -(CONCERNS or FAIL, naming the skill that closes it — `/design-review [doc]` for -an unreviewed concept or GDD) — except a play question at the Production gate -(a human has played the Vertical Slice; at `minimal`, the core loop is fun on -the current build), where "not yet" means nobody has played it: NOT ASSESSED -(`gate-production.md`). Only an unanswered item or "I don't know" stays -MANUAL CHECK NEEDED, which Section 5 turns into NOT ASSESSED. - -This applies to questions about the project's state. Declining an offer to -produce missing data (e.g. `/perf-profile`) leaves the item NOT ASSESSED; at -`performance.enforce: off` it stays out of the verdict. - ---- - -## 4b. Director Panel Assessment - -The panel is set by **two independent axes**, both resolved in Phase 1: `review_mode` -decides *whether* the panel runs, `workflow` decides *how wide* it is. - -**Axis 1 — `review_mode` decides whether any director spawns:** -- `solo` → skip the panel entirely. Note in output: "Director Panel skipped — Solo mode. Gate verdict based on artifact and quality checks only." Proceed to Phase 5. -- `lean` → run the panel (phase gates always run in lean mode — this is their purpose). -- `full` → run the panel. - -**Axis 2 — `workflow` decides the panel width.** Directors are Opus-tier, so a -fixed four-director panel costs a two-system jam exactly what it costs a -thirty-system commercial project. The gate still runs at every tier; only its -breadth scales: - -| `workflow` | Panel | Directors | -|---|---|---| -| `minimal` | 1 | `producer` | -| `standard` | 2 | `technical-director`, `producer` | -| `full` | 4 | `creative-director`, `technical-director`, `producer`, `art-director` | - -`producer` is in every panel — scope and schedule readiness is the one judgment -no tier makes optional. `technical-director` joins at `standard` because that is -the first tier requiring architecture artifacts. `creative-director` and -`art-director` join at `full`, the only tier requiring the full art bible and -UX spec set for them to assess. - -> **Width is not the same as strictness.** A narrower panel does not soften the -> verdict: the escalation rule in `.claude/docs/director-gates.md` is unchanged — -> the strictest verdict returned by *whoever ran* still wins. Do not infer PASS -> from a perspective that was never consulted. - -Before generating the final verdict, spawn the directors for the resolved tier as **parallel subagents** via `Agent` using the parallel gate protocol from `.claude/docs/director-gates.md`. Issue all the `Agent` calls simultaneously — do not wait for one before starting the next. - -**Gate IDs:** - -1. **`creative-director`** — gate **CD-PHASE-GATE** (`.claude/docs/director-gates/cd-phase-gate.md`) -2. **`technical-director`** — gate **TD-PHASE-GATE** (`.claude/docs/director-gates/td-phase-gate.md`) -3. **`producer`** — gate **PR-PHASE-GATE** (`.claude/docs/director-gates/pr-phase-gate.md`) -4. **`art-director`** — gate **AD-PHASE-GATE** (`.claude/docs/director-gates/ad-phase-gate.md`) - -Pass to each the target phase name, the resolved `workflow` tier, the target -gate's required and recommended artifacts at the resolved tier (the loaded gate -file's checklist after its tier reduction and the `qa.level` relaxation — what -this gate asks for, not what a later one will), the list of artifacts present, -and its gate's own context — named here, so this session never has to read the -gate files: -- **CD-PHASE-GATE**: the game pillars and core fantasy (from - `design/gdd/game-concept.md`, else `design/game-brief.md`). -- **TD-PHASE-GATE**: the architecture document path, the engine reference path - (`docs/engine-reference//VERSION.md`), and the ADR list. -- **PR-PHASE-GATE**: the sprint and milestone artifacts present, `team.size` as - resolved above (with the current sprint plan's capacity, if a plan exists), and - the number of stories under `production/epics/` whose status is `Blocked`. At - `workflow: minimal`, pass the Build order in `design/game-brief.md` as the plan — that - tier has no sprint plan. -- **AD-PHASE-GATE**: the art and visual artifacts present, the Visual Identity - Anchor (from `design/gdd/game-concept.md`, else the "Art & audio direction" - line of `design/game-brief.md`), and the art bible path. - -Pass each context item as one of three things, so no director has to guess: -- **Present** — its path or value (`0` blocked stories is a value). -- **"none"** — the target gate (or an earlier one) requires or recommends it at - this tier and it does not exist (no architecture document at - `/gate-check pre-production`). For the director that is a fact about the - project to judge, not a missing input. -- **"not expected before [phase]"** — the target gate does not ask for it yet; - name the phase whose gate first does (the architecture document and ADRs - before Pre-Production, the sprint plan before Production). One this tier never - requires is "not required at `workflow: [tier]`" (any sprint plan at - `minimal`). Neither is ever passed as "none", and neither is a finding — a - director judges readiness for the phase being entered, not a later one. - -**Name the omissions in the output.** Below the Director Panel summary, when the -panel ran narrower than four, state which perspectives did not run and how to get -them — e.g. "Panel: 2 of 4 (`workflow: standard`). Creative and Art perspectives -not consulted. Raise `modes.rigor` to `full` (or set `modes.workflow: full`) for -the complete panel." Name the setting the config block shows as `workflow`'s -source: when `modes.workflow` is set on its own, raising `modes.rigor` does not -change it. Never point to `--review full` for this — `--review` decides whether -the panel runs, not how wide it is. A silently narrow panel reads as a clean bill -of health from reviewers who never looked. - -**Collect every response from the directors that ran, then present the Director Panel summary** (one row per director that ran; name the ones `workflow` left out): - -``` -## Director Panel Assessment - -Creative Director: [READY / CONCERNS / NOT READY / NOT ASSESSED] - [feedback] - -Technical Director: [READY / CONCERNS / NOT READY / NOT ASSESSED] - [feedback] - -Producer: [READY / CONCERNS / NOT READY / NOT ASSESSED] - [feedback] - -Art Director: [READY / CONCERNS / NOT READY / NOT ASSESSED] - [feedback] -``` - -**Apply to the verdict:** -- Any director returns NOT READY → verdict is minimum FAIL (no override turns a FAIL into a stage change — Section 6) -- Any director returns CONCERNS → verdict is minimum CONCERNS -- Any director returns NOT ASSESSED (and none returned NOT READY or CONCERNS) → verdict at best NOT ASSESSED; name the input that director said was missing — it never counts as READY -- Every director that ran returns READY → eligible for PASS (still subject to artifact and quality checks from Section 3) - ---- +**Read `references/4-assessment.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 5. Output the Verdict -``` -## Gate Check: [Current Phase] → [Target Phase] - -**Date**: [date] -**Checked by**: gate-check skill - -### Required Artifacts: [X/Y present] -- [x] design/gdd/game-concept.md (design/game-brief.md at `minimal`) — exists, 2.4KB -- [ ] docs/architecture/ — MISSING (no ADRs found) -- [x] production/sprints/ — exists, 1 sprint plan - -### Quality Checks: [X/Y passing] -- [x] GDD has 8/8 required sections -- [ ] Tests — FAILED (3 failures in tests/unit/) -- [?] Core loop playtested — MANUAL CHECK NEEDED - -### Blockers -1. **No Architecture Decision Records** — Run `/architecture-decision` to create one - covering core system architecture before entering production. -2. **3 test failures** — Fix failing tests in tests/unit/ before advancing. - -### Recommendations -- [Priority actions to resolve blockers] -- [Optional improvements that aren't blocking] - -### Verdict: [PASS / NOT ASSESSED / CONCERNS / FAIL] -- **PASS**: All required artifacts present, all quality checks passing -- **CONCERNS**: Minor gaps exist but can be addressed during the next phase — - the stage advances only if the user explicitly accepts them (Section 6) -- **FAIL**: Critical blockers must be resolved before advancing -- **NOT ASSESSED**: One or more required checks could not be run at all — name - which, and why, in the Blockers section - -### Accepted Risks (only when the user advanced on CONCERNS) -- [each concern, as listed above] — accepted by the user, [date] -``` - -**`NOT ASSESSED` — when the gate could not look.** Rank: it **outranks PASS** -(a gate that could not check part of its scope has not established the phase is -ready) and **ranks below CONCERNS and FAIL** (a known blocker is more actionable -than an unknown, and demoting it behind an access problem buries it). It is not a -softer FAIL: "I checked and found a blocker" and "I could not check" need -different fixes — one needs work done, the other needs the input produced or made -readable. - -**Verdict precedence — first matching rule wins**, evaluated in this order: -**FAIL**, then **CONCERNS**, then **NOT ASSESSED**, then **PASS**. A gate with -both a real blocker and an unassessable check is FAIL: the blocker is the -actionable finding. Stating the order mechanically removes the inference — the -rank sentence above says what outranks what, but only an ordered list says what -to do when two conditions hold at once. - -Emit it when any of: - -- A **required artifact exists but cannot be assessed** — empty, unreadable, or - still entirely `[TO BE CONFIGURED]` / template placeholders. Present-but-empty - is the case that most looks like present. -- A **quality check's input carries no measured data**. Section 3 compares the - performance budgets against "profiling data in `tests/performance/` or recent - `/perf-profile` output" — and `/perf-profile`'s report template pre-fills - `[16.67ms]` as the budget, so it can render ">99% headroom" from zero profiler - data. Placeholder numbers are not measurements: a budget nobody set is not a - budget that was met. Absent data already prompts (Section 4 offers to run - `/perf-profile`); this covers data that is *present and hollow*, which is the - case that looks like a measurement. -- A **test check the tier requires could not be executed** — no test runner is - configured, or the runner is configured but failed to start. Section 3 runs the - suite "if a test runner is configured", and an unconfigured runner produced no - failures, so the test check contributed nothing to the verdict and the gate - could still reach PASS. Meanwhile `testing.strict.logic` and - `.integration` both default to `true`, so the project's own configuration - called those gates BLOCKING. A blocking gate that never ran is the unknown this - verdict exists to name. Remediation is already listed under Common Gaps - (`/test-setup`); this is what the verdict does with it. - - > **Scope this to tiers that require tests.** At `qa.level: minimal` no test - > gates apply at all (see the config block above), so a missing runner there is - > the configured posture, not a hole — firing the trigger would make every - > `minimal` gate permanently NOT ASSESSED and stop stage advancement, the same - > over-broad reading the director trigger below warns against. Fires only where - > the resolved tier actually asked for the test check. -- A **`MANUAL CHECK NEEDED` item the user never resolved**. Section 4 already - refuses to assume PASS for unverifiable items and marks them this way — but - until now the verdict vocabulary had nowhere to put one, so an unresolved - manual check had to land inside PASS, CONCERNS or FAIL anyway. This is where it - goes. -- A director the **resolved tier was supposed to spawn** did not return — it - errored, produced no verdict, or was interrupted. - - > **Scope this narrowly, and do not read it as "fewer than four directors ran".** - > Section 4b narrows the panel *by design* — 1 director at `minimal`, 2 at - > `standard`, 4 at `full`, and none in `solo` — and that narrowing is a - > deliberate, announced reduction, not a failure to assess. The broad reading - > makes every `minimal`, `standard` and `solo` gate permanently NOT ASSESSED, - > which means the verdict can never be PASS and Section 6 can never advance - > `project.stage`. **That would break stage advancement for most projects,** - > since those are the common tiers. The trigger fires only when a director the - > tier *did* call for fails to come back — a hole in the panel you expected, - > never the panel you deliberately chose. -- A referenced upstream verdict is itself `NOT ASSESSED` — it propagates upward - rather than resolving to a pass. - -Never resolve an unknown by assuming the permissive reading. If the check could -not run, that fact is the finding. - ---- - -## 5a. Chain-of-Verification - -After drafting the verdict in Phase 5, challenge it before finalising. - -**Step 1 — Generate 5 challenge questions** designed to disprove the verdict: - -> **Tool-action requirement**: At least 2 of the 5 challenge questions below must be answered by re-reading a specific file (Read tool) or re-running a specific check (Grep tool) — not by reflection alone. Mark these with [TOOL ACTION] to indicate a tool was used. - -For a **PASS** draft: -- "Which quality checks did I verify by actually reading a file, vs. inferring they passed?" -- "Are there MANUAL CHECK NEEDED items I marked PASS without user confirmation? [TOOL ACTION] Re-scan the checklist for any [?] or MANUAL CHECK items." -- "Did I confirm all listed artifacts have real content, not just empty headers? [TOOL ACTION] Re-read the file and check it has non-placeholder content." -- "Could any blocker I dismissed as minor actually prevent the phase from succeeding?" -- "Which single check am I least confident in, and why?" - -For a **CONCERNS** draft: -- "Could any listed CONCERN be elevated to a blocker given the project's current state?" -- "Is the concern resolvable within the next phase, or does it compound over time?" -- "Did I soften any FAIL condition into a CONCERN to avoid a harder verdict?" -- "Are there artifacts I didn't check that could reveal additional blockers?" -- "Do all the CONCERNS together create a blocking problem even if each is minor alone?" - -For a **FAIL** draft: -- "Have I accurately separated hard blockers from strong recommendations?" -- "Are there any PASS items I was too lenient about?" -- "Am I missing any additional blockers the user should know about?" -- "Can I provide a minimal path to PASS — the specific 3 things that must change?" -- "Is the fail condition resolvable, or does it indicate a deeper design problem?" - -**Step 2 — Answer each question** independently. -Do NOT reference the draft verdict text — re-check specific files or ask the user. - -**Step 3 — Revise if needed:** -- If any answer reveals a missed blocker → upgrade verdict (PASS→CONCERNS or CONCERNS→FAIL) -- If any answer reveals a check that **could not be run** rather than one that - ran and passed → PASS→NOT ASSESSED. The first two PASS-draft questions above - ("verified by actually reading a file, vs. inferring", "MANUAL CHECK NEEDED - items I marked PASS") exist to find exactly this, and until now a yes to either - had no verdict to move to -- If any answer reveals an over-stated blocker → downgrade only if citing specific evidence -- Never revise NOT ASSESSED down to PASS by re-reasoning about the missing input. - Only obtaining the input clears it -- If answers are consistent → confirm verdict unchanged - -**Step 4 — Note the verification** in the final report output: -`Chain-of-Verification: [N] questions checked — verdict [unchanged | revised from X to Y]` - ---- +**Read `references/5-verdict.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 6. Update Stage on PASS -When the verdict is **PASS** and the user confirms they want to advance, write the -new stage to BOTH `project.yaml` and the legacy `production/stage.txt`. - -**On CONCERNS, the user may override — explicitly.** Do not offer the stage -write by default. If the user asks to advance anyway, list every concern and -ask: "The gate returned CONCERNS. Accept these risks — [list] — and may I update -`project.stage` in `project.yaml` to '[stage]' (and the legacy -`production/stage.txt`)?" Only on an explicit yes, add the `### Accepted Risks` -section to the gate report (each concern, accepted by the user, with the date) -and write the stage as below. **A FAIL is never overridden into a stage change, and -neither is NOT ASSESSED** — the blockers must be fixed, or the missing input -produced, and the gate re-run. - -### 6.1 Primary write — `project.yaml` - -Set `project.stage` to the new stage name in `project.yaml` at the repo root. - -- **If a `project:` block already exists**: Read `project.yaml` first (the Edit - tool requires the file to have been read in this session), then use the Edit - tool to change its `stage:` value. -- **If `project.yaml` exists but has no `project:` block**: Read `project.yaml` - first, then use the Edit tool to insert the block immediately after the - `framework:` block (before `modes:`). Insert exactly (replace ``): - ```yaml - project: - stage: - ``` -- **If `project.yaml` does not exist at all**: create it with the Write tool using - this v1.1 minimal template (replace `` and the date): - ```yaml - # CCGS project configuration — single source of truth for project settings. - # Schema: grep the `## ` section of .claude/docs/effects-map.md — - # it is ~31k tokens whole, ~900 per section. Do not open it entire. - - schema_version: 1 - - framework: - version: 1.1.2 - last_upgraded: - - project: - stage: - ``` - Do not seed `modes.review_mode` here. It is a rigor-fronted knob — `modes.rigor` - supplies its value, so an explicit value would shadow the rigor expansion and pin - the review mode regardless of the project's rigor. - -### 6.2 Legacy fallback write — `production/stage.txt` - -Also write the single-line stage name (no trailing newline) so hooks that have not -migrated still work. Ensure the `production/` directory exists first: -```bash -mkdir -p production && printf '%s' "Production" > production/stage.txt -``` - -### 6.3 Verify both writes - -After both writes, Read `project.yaml` and `production/stage.txt` and confirm both -show the new stage. If they diverge, report the discrepancy to the user and stop — -a split stage indicator corrupts future auto-detection. - -**Always ask before writing**: "Gate passed. May I update `project.stage` in `project.yaml` to 'Production' (and the legacy `production/stage.txt`)?" — on an accepted CONCERNS override, the explicit yes above is that ask. - -### 6.4 Rigor-fit check (advisory — never affects the verdict) - -After the stage advance is confirmed, apply the raise trigger in -`.claude/docs/settings-guidance.md § 4`: if the new stage is **Production** (or -later) while the resolved `modes.workflow` is `minimal` (the `rigor: minimal` -posture, from the config block above), add one line: - -> "You're entering [stage] on `rigor: minimal` — most projects this size run -> `standard`. Revisit with `/settings modes.rigor=standard`?" - -Offer it **once**, here at the gate. Route to `/settings` — never change the -setting yourself. - ---- +**Read `references/6-update-stage.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 7. Closing Next-Step Widget -After the verdict is presented and any stage update is complete (project.yaml + stage.txt), close with a structured next-step prompt using `AskUserQuestion`. - -**Tailor the options to the gate that just ran.** The argument names the phase -being entered, so `/gate-check systems-design` is the Concept → Systems Design gate. - -**At `workflow: minimal`, skip the menus below.** They walk the phase ladder, and -the minimal route is not the ladder: offer the first incomplete step of -`paths.minimal` instead (the `--path minimal` rows from Section 3): -`/setup-engine`, then `/brainstorm`, then `/create-stories`, then `/dev-story` -on the next story — the route `/help` gives. - -For **Concept → Systems Design** (`/gate-check systems-design`) PASS — option [A] is -`/map-systems` when `design/gdd/systems-index.md` does not exist yet (many -projects write it during Concept, as the workflow catalog orders it), otherwise -`/design-system [first system in the index's design order]`: -``` -Gate passed. What would you like to do next? -[A] Run /map-systems — decompose the concept into systems and a design order (recommended next step) - — or, when the systems index already exists: Run /design-system [first system] — author its GDD -[B] Revisit the concept first — return here when it is settled -[C] Stop here for this session -``` - -For **Systems Design → Technical Setup** (`/gate-check technical-setup`) PASS: -``` -Gate passed. What would you like to do next? -[A] Run /create-architecture — produce your master architecture blueprint and ADR work plan (recommended next step) -[B] Design more GDDs first — return here when all MVP systems are complete -[C] Stop here for this session -``` - -> **Note for the Systems Design → Technical Setup PASS**: `/create-architecture` is the required next step before writing any ADRs. It produces the master architecture document and a prioritized list of ADRs to write. Running `/architecture-decision` without this step means writing ADRs without a blueprint — skip it at your own risk. - -For **Technical Setup → Pre-Production** (`/gate-check pre-production`) PASS: -``` -Gate passed. What would you like to do next? -[A] Run /create-control-manifest — generate the layer rules manifest from your Accepted ADRs (first, if docs/architecture/control-manifest.md does not exist yet) -[B] Run /vertical-slice — build the Vertical Slice (do this before writing epics — validate fun first) -[C] Write more ADRs first — run /architecture-decision [next-system] -[D] Stop here for this session -``` - -> **Note for the Technical Setup → Pre-Production PASS**: The Pre-Production sequence is deliberately ordered -> to validate fun before committing to detailed planning: -> -> 1. `/create-control-manifest` — extract technical rules from Accepted ADRs, if not done yet (`/create-epics` requires it at `full`) -> 2. `/vertical-slice` — build the Vertical Slice **FIRST**, before writing epics or stories -> 3. Playtest → `/playtest-report` — at least 1 documented session, 3+ better before committing the full team. `/gate-check production` treats the slice as recommended: skipped → CONCERNS, unplayed → NOT ASSESSED -> 4. `/ux-design [screen]` — UX specs for main menu, core HUD, pause menu (if not done) -> 5. `/create-epics layer:foundation` then `/create-epics layer:core` — plan after fun is validated -> 6. `/create-stories [epic-slug]` for each epic -> 7. `/sprint-plan new` -> -> **Why prototype before epics?** If the prototype reveals the core loop needs to change, -> epics written before that discovery will be partially wrong. Validate fun cheaply first, -> then plan in detail. This is the #1 lesson from GDC postmortem data. - -For all other gates, offer the two most logical next steps for that phase plus "Stop here". - ---- - -## 8. Follow-Up Actions - -Based on the verdict, suggest specific next steps: - -- **No art bible?** → `/art-bible` to create the visual identity specification -- **Art bible exists but no asset specs?** → `/asset-spec system:[name]` to generate per-asset visual specs and generation prompts from approved GDDs -- **No game concept?** → `/brainstorm` to create one -- **No systems index?** → `/map-systems` to decompose the concept into systems -- **Missing design docs?** → `/reverse-document` or delegate to `game-designer` -- **Small design change needed?** → `/quick-design` for changes under about one week of implementation (bypasses full GDD pipeline) -- **No UX specs?** → `/ux-design [screen name]` to author specs, or `/team-ui [feature]` for full pipeline -- **UX specs not reviewed?** → `/ux-review [file]` or `/ux-review all` to validate -- **No accessibility requirements doc?** → run `/ux-design` which creates both `design/accessibility-requirements.md` and `design/ux/interaction-patterns.md` in one step -- **No interaction pattern library?** → `/ux-design patterns` to initialize it -- **Concept or a GDD not reviewed?** → `/design-review [doc]` -- **GDDs not cross-reviewed?** → `/review-all-gdds` (run after all MVP GDDs are individually approved) -- **Cross-GDD consistency issues?** → fix flagged GDDs, then re-run `/review-all-gdds` -- **No test framework?** → `/test-setup` to scaffold the framework for your engine -- **No QA plan for current sprint?** → `/qa-plan sprint` to generate one before implementation begins -- **Missing ADRs?** → `/architecture-decision` for individual decisions -- **No master architecture doc?** → `/create-architecture` for the full blueprint -- **ADRs missing engine compatibility sections?** → Re-run `/architecture-decision` - or manually add Engine Compatibility sections to existing ADRs -- **Missing control manifest?** → `/create-control-manifest` (requires Accepted ADRs) -- **Missing epics?** → `/create-epics layer: foundation` then `/create-epics layer: core` (requires control manifest) -- **Missing stories for an epic?** → `/create-stories [epic-slug]` (run after each epic is created) -- **Stories not implementation-ready?** → `/story-readiness` to validate stories before developers pick them up -- **Tests failing?** → delegate to `lead-programmer` or `qa-tester` -- **No playtest data?** → `/playtest-report` -- **No playtest sessions beyond the minimum?** → Additional sessions give more reliable signal. 3+ total is recommended before committing the full team. Use `/playtest-report` to structure findings. -- **No Difficulty Curve doc?** → Author `design/difficulty-curve.md` by hand from the template at `.claude/docs/templates/difficulty-curve.md`. (`/quick-design` is a related session but writes to `design/quick-specs/`, not to this path — use it to think the curve through, then copy the outcome here.) -- **No player journey map?** → Author `design/player-journey.md` by hand from the template at `.claude/docs/templates/player-journey.md`. - -> **Neither of these has a skill that writes it — the remediations must not imply -> otherwise.** Naming "`/ux-design` Phase 2b" would point at the step that *reads* -> `design/player-journey.md`, landing the user back at the check that just -> failed. Naming `/quick-design` would point at a skill that writes -> `design/quick-specs/[name]-[date].md` and would leave this gate still failing. -> Both docs are hand-authored from their templates; say so plainly rather than -> naming a skill that cannot produce them. -- **Need a quick sprint check?** → `/sprint-status` for current sprint progress snapshot -- **Performance unknown?** → `/perf-profile` -- **Not localized?** → `/localize` -- **No security audit, or open CRITICAL/HIGH findings?** → `/security-audit` (after fixes, `/security-audit quick` to confirm) -- **Ready for release?** → `/launch-checklist` - ---- +**Read `references/7-next-steps.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Collaborative Protocol diff --git a/.claude/skills/gate-check/references/2b-workflow-tier.md b/.claude/skills/gate-check/references/2b-workflow-tier.md new file mode 100644 index 00000000..432c3df1 --- /dev/null +++ b/.claude/skills/gate-check/references/2b-workflow-tier.md @@ -0,0 +1,129 @@ +# /gate-check — Section 2b: Workflow Tier Adjustment + +> Part of `/gate-check`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 2b. Workflow Tier Adjustment + +**In this file:** + +- How to apply a gate file's tier reductions +- `qa.level` and the test items; the smoke check is the floor +- A gate with no required artifacts left is NOT ASSESSED, with one exception +- `performance.enforce` +- Per-system overrides (`workflow_overrides.system_overrides`), and the additive overrides + +Each gate file carries its own tier reductions (see Section 2). Two rules apply +across all of them: + +> **How to apply:** run the loaded gate's checklist, then apply that file's tier +> reduction for the tier resolved in Section 1. **drop** = not checked at this +> tier; **→ recommended** = absent surfaces as CONCERNS, never a Blocker; items +> not named keep their baseline status. Reductions only ever *relax* a +> requirement — the only thing that adds one is `workflow_overrides` (below). +> +> **`qa.level` (Section 1) further relaxes the test items independently of the +> tier:** at `qa.level: minimal` the test-evidence / unit-test items become +> non-required at every workflow tier (so even `workflow: full` does not require +> them); the Section 3 `testing.strict` check is then a no-op. +> +> **It relaxes tests, not the look.** A UI story's retained screenshots, and a +> Visual/Feel story's screenshots plus lead sign-off, are required at every +> `qa.level` wherever the gate file asks for story evidence +> (`.claude/docs/coding-standards.md`: tests are waived at `minimal`, the look +> is not). +> +> **The smoke check is excluded from that relaxation, and is the floor.** +> `qa.level` relaxes *per-story test evidence*; a smoke check is **build health**, +> not story evidence, and the two are already held apart on exactly this basis in +> `.claude/docs/coding-standards.md` ("`/smoke-check` is a build-health gate, not +> a per-story evidence gate ... This divergence is intentional"). So a gate file +> that requires a smoke report keeps requiring it at every `qa.level`. +> +> Without that exclusion the Production → Polish gate had **zero required +> artifacts at `rigor: minimal`** and could not fail on artifacts by +> construction: `minimal` reduced the gate to the smoke check alone, `qa.level` +> then dropped the smoke check too, and one `modes.rigor` setting fires both. + +> **A gate with no required artifacts left must say so, and may not return +> PASS.** After applying the tier reduction and the `qa.level` relaxation, count +> what remains required. If the count is zero, report +> **NOT ASSESSED** naming both reducers and the gate — *"Production → Polish at +> `workflow: minimal` + `qa.level: minimal` leaves no required artifact; this +> gate verified nothing"* — rather than a PASS earned by having nothing to check. +> Per `.claude/rules/skill-authoring.md` obligation 1, a run that could not +> assess its scope has not established that the scope is good, and obligation 3 +> requires the emptiness to be visible in the output rather than inferable from +> a silent green. +> +> **The one exception: a gate its tier reference file marks "not applicable" at +> this tier** (Systems Design → Technical Setup at `workflow: minimal`). That is +> not a gate with nothing left to check but a transition the tier does not have: +> it PASSes with that file's note, printed in the report. The director panel +> does not run for it — note "Director Panel skipped — gate not applicable at +> `workflow: [tier]`" — and the Section 6 stage write still asks first. +> +> **`performance.enforce` is likewise independent of the tier, and a tier +> reduction never suppresses it.** The performance check in Section 3 runs at +> every workflow tier, and `block` makes a breach a Blocker at every workflow +> tier. Do **not** read a gate file's *"everything else drops"* as dropping it: +> `off` is the only thing that makes budgets informational, and it is a +> deliberate choice the user makes on the same key. +> +> Without this, `performance.enforce: block` is **inert on every `rigor: minimal` +> project** — the Polish gate's `minimal` reduction drops everything outside its +> floor, and "Performance is within budget" sits in the dropped remainder. A +> setting that works only when a rule is disregarded is not wired. + +### Per-system overrides (`workflow_overrides.system_overrides`) + +Independent of the project-level tier above, and applied **only** on the gates +that validate MVP GDDs (Systems Design → Technical Setup, and the GDD-completeness +checks at Pre-Production → Production). For each system, resolve its effective +tier: + +1. If the block's `system_overrides` lists `` → that tier +2. Else the project-level `workflow` + +**Before applying any of them, check the block the other way round: does every +KEY match a system?** `` is the GDD filename stem +(`.claude/docs/workflow-modes.md`), so for each key in `system_overrides`, look +for `design/gdd/.md`. Any key with no matching stem is reported, naming the +key and listing the stems that do exist: + +> `system_overrides key 'no-such-system' matches no GDD in design/gdd/. Available stems: combat, inventory, forge-heat-system. This override is doing nothing.` + +Surface it as a **CONCERNS**-level finding, not a Blocker — the project is still +gateable, but an override the user believes is in force and is not is exactly how +a documented escape hatch silently stops working. + +This is the rule in `.claude/docs/workflow-modes.md`: a key that matches no +system is an error, not a no-op. The story skills resolve only in the system → +override direction, so an orphan key is invisible to them; `/gate-check`, which +resolves the whole block, is where it is caught. + +Validate each GDD against its own effective tier's section count: + +- A system pinned **higher** than the project (e.g. `system_overrides.combat: + full` on a `standard` project) **blocks the gate** until that system's GDD + meets the higher bar (combat → all 8 sections). This is the one case where a + per-system setting makes the gate *stricter* than the project tier. +- A system pinned **lower** (e.g. `inventory: minimal`) relaxes only that system + — its GDD is checked at the lower tier; every other system stays at the project + level. A system pinned **`minimal` imposes no GDD section requirement at all** + (`minimal` = "game brief replaces GDDs" — `.claude/docs/workflow-modes.md`): it + never blocks the gate on a missing or incomplete GDD. Do not invent an + "acceptance-criteria-only" floor for it — there is none. + +> **Additive overrides (the only things that make the gate stricter).** +> - `workflow_overrides.art_bible_strict: true` forces the complete (9-section) +> art bible at the Technical Setup → Pre-Production and Pre-Production → +> Production gates regardless of tier or whether visual-asset stories exist. +> - `workflow_overrides.edge_cases: true` and `workflow_overrides.tuning_knobs: +> true` force those GDD sections required when validating GDD completeness, +> additive on top of the resolved tier (e.g. at `standard`, `tuning_knobs: true` +> makes the otherwise-optional Tuning Knobs section blocking). These never +> relax — a `false` value is the default/no-op, never a way to drop a section +> the tier already requires. + +--- diff --git a/.claude/skills/gate-check/references/3-run-gate-check.md b/.claude/skills/gate-check/references/3-run-gate-check.md new file mode 100644 index 00000000..97db9669 --- /dev/null +++ b/.claude/skills/gate-check/references/3-run-gate-check.md @@ -0,0 +1,165 @@ +# /gate-check — Section 3: Run the Gate Check + +> Part of `/gate-check`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 3. Run the Gate Check + +**In this file:** + +- Artifact Checks +- Quality Checks +- Cross-Reference Checks + +**Before running artifact checks**, read `docs/consistency-failures.md` if it exists. +Extract entries whose Domain matches the target phase (e.g., if checking +Systems Design → Technical Setup, pull entries in Economy, Combat, or any GDD domain; +if checking Technical Setup → Pre-Production, pull entries in Architecture, Engine). +Carry these as context — recurring conflict patterns in the target domain warrant +increased scrutiny on those specific checks. + +For each item in the target gate: + +### Artifact Checks + +**Resolve existence and counts deterministically — do not open files to find out +what exists:** + +``` +Bash: bash .claude/scripts/artifact-check.sh --phase [source-phase] +``` + +Pass the phase being advanced *from* (its steps are the work that must be +complete): `systems-design` for the Systems Design → Technical Setup gate, +`pre-production` for Pre-Production → Production, and so on. + +At `workflow: minimal`, also run +`bash .claude/scripts/artifact-check.sh --path minimal`: the brief and stories +live on that path, not on any phase, and its `game-brief` and `create-stories` +rows are this tier's floor. + +It reads `workflow-catalog.yaml` — which already encodes each step's `glob`, +`pattern`, `min_count` and `any_of` — and reports per step: + +| status | Meaning | +|---|---| +| `PRESENT` | glob matched, `min_count` met, `pattern` found where specified | +| `ABSENT` | nothing matched | +| `SHORT` | matched but fewer than `min_count` (`count=` and `min=` given) | +| `PATTERN_MISS` | files exist but none contains the required marker | +| `NO_CHECK` | the step declares no artifact — **not detectable from disk** | + +It emits observations, never a verdict: **you** apply the workflow tier and the +required/optional split from Section 2. An `ABSENT` required artifact is a +blocker at `full` and frequently not one at `minimal`; the script does not know +that and does not decide it. + +**`NO_CHECK` is not `PRESENT`.** The header prints a `NO_CHECK:` count before any +row precisely so this cannot be skimmed past. Those steps were *scanned*, not +*satisfied* — carry each into Section 4 (Collaborative Assessment) and ask, or +mark MANUAL CHECK NEEDED. A gate that reports PASS because most of its checklist +was undetectable is the failure mode this count exists to prevent. + +**Existence is not adequacy.** The script cannot tell a real document from a +template skeleton. So: for any artifact the verdict actually turns on, spot-read +it and confirm it has real content — the same escalation rule the +`gdd-structure-check.sh` step below uses. Do not spot-read artifacts the verdict +does not turn on. + +> **A smoke report is always an artifact the verdict turns on — spot-reading it +> is mandatory, not discretionary.** At `minimal` it is frequently the *only* +> required artifact, so the whole gate rests on one file that nothing generated +> and nothing verifies. Check its claims against the repo, and raise any that the +> tree contradicts: +> +> - It reports a passing automated suite → the engine's test root must actually +> contain test files and the project must have a runner. "24 passed, 0 failed" +> in a repo with no test files under that root — `tests/unit/` and +> `tests/integration/` on Godot, `Assets/Tests/` on Unity, +> `Source//Private/Tests/` on Unreal — and no runner is a finding, not +> evidence. +> - It marks a critical path PASS → the code for that path must exist in the code +> root. A PASS on "banking ends the run" with no banking code is a finding. +> - It carries no date, or predates the newest commit touching the code root → +> say so; a stale smoke report describes a build that no longer exists. +> +> Report a contradiction at the same level the artifact was required at: a +> Blocker where the smoke check is required, CONCERNS where it is recommended. +> Existence plus a verdict-line grep would clear a fabricated report. + +For code checks, verify directory structure and file counts. + +**Systems Design → Technical Setup gate — cross-GDD review check**: +Use `Glob('design/gdd/gdd-cross-review-*.md')` to find the `/review-all-gdds` report. +If no file matches: at `full` mark the "cross-GDD review report exists" artifact as +**FAIL** and surface it prominently ("No `/review-all-gdds` report found in +`design/gdd/`. Run `/review-all-gdds` before advancing to Technical Setup."); at +`standard` the report is recommended, so mark it **CONCERNS**, not a blocker; at +`minimal` this gate is not applicable (see the gate file). If a file is found, read it and +check the verdict line: a FAIL verdict means the cross-GDD consistency check failed +and must be resolved before advancing. A NOT ASSESSED verdict means that review +could not compare the GDDs, so it satisfies nothing here: mark the item NOT +ASSESSED for this gate, never passed. + +### Quality Checks +- For test checks: Run the test suite via `Bash` if a test runner is configured. + **If no runner is configured, that is `NOT ASSESSED`, not a silent skip** — see + the trigger in the verdict section. A gate that ran no tests found no test + failures, which is not the same as passing. + A test failure's effect on the verdict depends on the `testing.strict` block + **resolved in Phase 1** (`resolve_config` merges `project.local.yaml` over + `project.yaml`; reading the file directly would drop a local override), per + test type: + - **Logic** — unit-level failures (`tests/unit/` on Godot, Edit Mode on + Unity), gated by `testing.strict.logic`. + - **Integration** — failures in `tests/integration/` on Godot, Play Mode on + Unity, gated by `testing.strict.integration`. On Unreal, where one root + (`Source//Private/Tests/`) holds both, classify a failure by its + story's Type, or apply the stricter of the two levels when that is unknown. + - For each type: take `testing.strict.` from that block; use it only + if its value is `true` or `false` (case-insensitive). If the key is absent, + empty, or holds any other value, read `testing.strict` as a plain boolean + (legacy single-value form); if that too is absent or invalid, default to + `true` (Logic and Integration are both strict by default — behavior unchanged + from before this setting existed). Surface any unrecognized value to the user. + - At a strict (`true`) gate level, failures of that type are **Blockers** + (verdict FAIL). At an advisory (`false`) level, they are **Concerns** + (verdict minimum CONCERNS, not FAIL) — list them under Recommendations, not + Blockers. +- For design review checks, gather section presence **deterministically** — do not + read the GDDs to count headings: + + ``` + Bash: bash .claude/scripts/gdd-structure-check.sh + ``` + + It prints a `PRESENT:` / `ABSENT:` pair per GDD and already accepts + `## Detailed Design` as satisfying the `Detailed Rules` requirement. It reports + presence only and makes no REQUIRED/ADVISORY judgment. + + Then apply each GDD's **effective tier** (per-system resolution below) to those + lists — all 8 sections at `full`, the 5 standard sections (+ conditional + Formulas) at `standard`. A missing *required* section blocks; a missing section + that is optional at the effective tier is advisory. A section reported PRESENT + can still fail review if it is an empty heading — spot-read any section the + verdict actually turns on. +- For performance checks: read the budgets (`performance.target_framerate`, + `frame_budget_ms`, `draw_call_limit`, `memory_ceiling_mb`) from `project.yaml` + (else technical-preferences.md) and compare against any profiling data in + `tests/performance/` or recent `/perf-profile` output. What a breach *means* + is set by `performance.enforce`, taken from the Phase 1 resolved block (it is + locally overridable, so do not read the file for this one): + - `warn` (default) — breaches are **CONCERNS**, never Blockers. + - `block` — breaches are **Blockers** from the Polish gate onward. + - `off` — budgets are informational; do not surface breaches in the verdict. + + Only these three values are recognized. Surface anything else to the user and + fall back to `warn` rather than guessing. +- For localization checks: `Grep` for hardcoded strings in the **code root** (resolve per `.claude/docs/code-root-resolution.md`). **If the code root is unresolved, report `NOT ASSESSED — code root unresolved` rather than zero hits.** + +### Cross-Reference Checks +- Compare `design/gdd/` documents against implementations in the **code root** +- Check that every system referenced in architecture docs has corresponding code +- Verify sprint plans reference real work items + +--- diff --git a/.claude/skills/gate-check/references/4-assessment.md b/.claude/skills/gate-check/references/4-assessment.md new file mode 100644 index 00000000..23d803f4 --- /dev/null +++ b/.claude/skills/gate-check/references/4-assessment.md @@ -0,0 +1,142 @@ +# /gate-check — Sections 4 and 4b: Assessment and Director Panel + +> Part of `/gate-check`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 4. Collaborative Assessment + +**In this file:** + +- 4. Collaborative Assessment: unverifiable items are never PASS +- 4b. Director Panel Assessment: `review_mode` decides whether directors spawn, `workflow` decides the panel width +- Gate IDs +- Naming the omissions, and applying the panel to the verdict + +For items that can't be automatically verified, **ask the user**: + +- "I can't automatically verify that the core loop plays well. Has it been playtested?" +- "No playtest report found. Has informal testing been done?" +- "Performance profiling data isn't available. Would you like to run `/perf-profile`?" + +**Never assume PASS for unverifiable items.** Mark them as MANUAL CHECK NEEDED. +An answer resolves the item: "no" or "not yet" is a checked, failed item +(CONCERNS or FAIL, naming the skill that closes it — `/design-review [doc]` for +an unreviewed concept or GDD) — except a play question at the Production gate +(a human has played the Vertical Slice; at `minimal`, the core loop is fun on +the current build), where "not yet" means nobody has played it: NOT ASSESSED +(`gate-production.md`). Only an unanswered item or "I don't know" stays +MANUAL CHECK NEEDED, which Section 5 turns into NOT ASSESSED. + +This applies to questions about the project's state. Declining an offer to +produce missing data (e.g. `/perf-profile`) leaves the item NOT ASSESSED; at +`performance.enforce: off` it stays out of the verdict. + +--- + +## 4b. Director Panel Assessment + +The panel is set by **two independent axes**, both resolved in Phase 1: `review_mode` +decides *whether* the panel runs, `workflow` decides *how wide* it is. + +**Axis 1 — `review_mode` decides whether any director spawns:** +- `solo` → skip the panel entirely. Note in output: "Director Panel skipped — Solo mode. Gate verdict based on artifact and quality checks only." Proceed to Phase 5. +- `lean` → run the panel (phase gates always run in lean mode — this is their purpose). +- `full` → run the panel. + +**Axis 2 — `workflow` decides the panel width.** Directors are Opus-tier, so the +panel is sized to the project rather than fixed at four. The gate still runs at +every tier; only its breadth scales: + +| `workflow` | Panel | Directors | +|---|---|---| +| `minimal` | 1 | `producer` | +| `standard` | 2 | `technical-director`, `producer` | +| `full` | 4 | `creative-director`, `technical-director`, `producer`, `art-director` | + +`producer` is in every panel — scope and schedule readiness is the one judgment +no tier makes optional. `technical-director` joins at `standard` because that is +the first tier requiring architecture artifacts. `creative-director` and +`art-director` join at `full`, the only tier requiring the full art bible and +UX spec set for them to assess. + +> **Width is not the same as strictness.** A narrower panel does not soften the +> verdict: the escalation rule in `.claude/docs/director-gates.md` is unchanged — +> the strictest verdict returned by *whoever ran* still wins. Do not infer PASS +> from a perspective that was never consulted. + +Before generating the final verdict, spawn the directors for the resolved tier as **parallel subagents** via `Agent` using the parallel gate protocol from `.claude/docs/director-gates.md`. Issue all the `Agent` calls simultaneously — do not wait for one before starting the next. + +**Gate IDs:** + +1. **`creative-director`** — gate **CD-PHASE-GATE** (`.claude/docs/director-gates/cd-phase-gate.md`) +2. **`technical-director`** — gate **TD-PHASE-GATE** (`.claude/docs/director-gates/td-phase-gate.md`) +3. **`producer`** — gate **PR-PHASE-GATE** (`.claude/docs/director-gates/pr-phase-gate.md`) +4. **`art-director`** — gate **AD-PHASE-GATE** (`.claude/docs/director-gates/ad-phase-gate.md`) + +Pass to each the target phase name, the resolved `workflow` tier, the target +gate's required and recommended artifacts at the resolved tier (the loaded gate +file's checklist after its tier reduction and the `qa.level` relaxation — what +this gate asks for, not what a later one will), the list of artifacts present, +and its gate's own context — named here, so this session never has to read the +gate files: +- **CD-PHASE-GATE**: the game pillars and core fantasy (from + `design/gdd/game-concept.md`, else `design/game-brief.md`). +- **TD-PHASE-GATE**: the architecture document path, the engine reference path + (`docs/engine-reference//VERSION.md`), and the ADR list. +- **PR-PHASE-GATE**: the sprint and milestone artifacts present, `team.size` as + resolved above (with the current sprint plan's capacity, if a plan exists), and + the number of stories under `production/epics/` whose status is `Blocked`. At + `workflow: minimal`, pass the Build order in `design/game-brief.md` as the plan — that + tier has no sprint plan. +- **AD-PHASE-GATE**: the art and visual artifacts present, the Visual Identity + Anchor (from `design/gdd/game-concept.md`, else the "Art & audio direction" + line of `design/game-brief.md`), and the art bible path. + +Pass each context item as one of three things, so no director has to guess: +- **Present** — its path or value (`0` blocked stories is a value). +- **"none"** — the target gate (or an earlier one) requires or recommends it at + this tier and it does not exist (no architecture document at + `/gate-check pre-production`). For the director that is a fact about the + project to judge, not a missing input. +- **"not expected before [phase]"** — the target gate does not ask for it yet; + name the phase whose gate first does (the architecture document and ADRs + before Pre-Production, the sprint plan before Production). One this tier never + requires is "not required at `workflow: [tier]`" (any sprint plan at + `minimal`). Neither is ever passed as "none", and neither is a finding — a + director judges readiness for the phase being entered, not a later one. + +**Name the omissions in the output.** Below the Director Panel summary, when the +panel ran narrower than four, state which perspectives did not run and how to get +them — e.g. "Panel: 2 of 4 (`workflow: standard`). Creative and Art perspectives +not consulted. Raise `modes.rigor` to `full` (or set `modes.workflow: full`) for +the complete panel." Name the setting the config block shows as `workflow`'s +source: when `modes.workflow` is set on its own, raising `modes.rigor` does not +change it. Never point to `--review full` for this — `--review` decides whether +the panel runs, not how wide it is. A silently narrow panel reads as a clean bill +of health from reviewers who never looked. + +**Collect every response from the directors that ran, then present the Director Panel summary** (one row per director that ran; name the ones `workflow` left out): + +``` +## Director Panel Assessment + +Creative Director: [READY / CONCERNS / NOT READY / NOT ASSESSED] + [feedback] + +Technical Director: [READY / CONCERNS / NOT READY / NOT ASSESSED] + [feedback] + +Producer: [READY / CONCERNS / NOT READY / NOT ASSESSED] + [feedback] + +Art Director: [READY / CONCERNS / NOT READY / NOT ASSESSED] + [feedback] +``` + +**Apply to the verdict:** +- Any director returns NOT READY → verdict is minimum FAIL (no override turns a FAIL into a stage change — Section 6) +- Any director returns CONCERNS → verdict is minimum CONCERNS +- Any director returns NOT ASSESSED (and none returned NOT READY or CONCERNS) → verdict at best NOT ASSESSED; name the input that director said was missing — it never counts as READY +- Every director that ran returns READY → eligible for PASS (still subject to artifact and quality checks from Section 3) + +--- diff --git a/.claude/skills/gate-check/references/5-verdict.md b/.claude/skills/gate-check/references/5-verdict.md new file mode 100644 index 00000000..03d914b6 --- /dev/null +++ b/.claude/skills/gate-check/references/5-verdict.md @@ -0,0 +1,167 @@ +# /gate-check — Sections 5 and 5a: Verdict and Chain-of-Verification + +> Part of `/gate-check`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 5. Output the Verdict + +**In this file:** + +- 5. Output the Verdict: the report, `NOT ASSESSED`, verdict precedence +- 5a. Chain-of-Verification: Steps 1-4 + +``` +## Gate Check: [Current Phase] → [Target Phase] + +**Date**: [date] +**Checked by**: gate-check skill + +### Required Artifacts: [X/Y present] +- [x] design/gdd/game-concept.md (design/game-brief.md at `minimal`) — exists, 2.4KB +- [ ] docs/architecture/ — MISSING (no ADRs found) +- [x] production/sprints/ — exists, 1 sprint plan + +### Quality Checks: [X/Y passing] +- [x] GDD has 8/8 required sections +- [ ] Tests — FAILED (3 failures in tests/unit/) +- [?] Core loop playtested — MANUAL CHECK NEEDED + +### Blockers +1. **No Architecture Decision Records** — Run `/architecture-decision` to create one + covering core system architecture before entering production. +2. **3 test failures** — Fix failing tests in tests/unit/ before advancing. + +### Recommendations +- [Priority actions to resolve blockers] +- [Optional improvements that aren't blocking] + +### Verdict: [PASS / NOT ASSESSED / CONCERNS / FAIL] +- **PASS**: All required artifacts present, all quality checks passing +- **CONCERNS**: Minor gaps exist but can be addressed during the next phase — + the stage advances only if the user explicitly accepts them (Section 6) +- **FAIL**: Critical blockers must be resolved before advancing +- **NOT ASSESSED**: One or more required checks could not be run at all — name + which, and why, in the Blockers section + +### Accepted Risks (only when the user advanced on CONCERNS) +- [each concern, as listed above] — accepted by the user, [date] +``` + +**`NOT ASSESSED` — when the gate could not look.** Rank: it **outranks PASS** +(a gate that could not check part of its scope has not established the phase is +ready) and **ranks below CONCERNS and FAIL** (a known blocker is more actionable +than an unknown, and demoting it behind an access problem buries it). It is not a +softer FAIL: "I checked and found a blocker" and "I could not check" need +different fixes — one needs work done, the other needs the input produced or made +readable. + +**Verdict precedence — first matching rule wins**, evaluated in this order: +**FAIL**, then **CONCERNS**, then **NOT ASSESSED**, then **PASS**. A gate with +both a real blocker and an unassessable check is FAIL: the blocker is the +actionable finding. Stating the order mechanically removes the inference — the +rank sentence above says what outranks what, but only an ordered list says what +to do when two conditions hold at once. + +Emit it when any of: + +- A **required artifact exists but cannot be assessed** — empty, unreadable, or + still entirely `[TO BE CONFIGURED]` / template placeholders. Present-but-empty + is the case that most looks like present. +- A **quality check's input carries no measured data**. Section 3 compares the + performance budgets against "profiling data in `tests/performance/` or recent + `/perf-profile` output" — and `/perf-profile`'s report template pre-fills + `[16.67ms]` as the budget, so it can render ">99% headroom" from zero profiler + data. Placeholder numbers are not measurements: a budget nobody set is not a + budget that was met. Absent data already prompts (Section 4 offers to run + `/perf-profile`); this covers data that is *present and hollow*, which is the + case that looks like a measurement. +- A **test check the tier requires could not be executed** — no test runner is + configured, or the runner is configured but failed to start. Section 3 runs the + suite "if a test runner is configured", and an unconfigured runner produced no + failures, so the test check contributed nothing to the verdict and the gate + could still reach PASS. Meanwhile `testing.strict.logic` and + `.integration` both default to `true`, so the project's own configuration + called those gates BLOCKING. A blocking gate that never ran is the unknown this + verdict exists to name. Remediation is already listed under Common Gaps + (`/test-setup`); this is what the verdict does with it. + + > **Scope this to tiers that require tests.** At `qa.level: minimal` no test + > gates apply at all (see the config block above), so a missing runner there is + > the configured posture, not a hole — firing the trigger would make every + > `minimal` gate permanently NOT ASSESSED and stop stage advancement, the same + > over-broad reading the director trigger below warns against. Fires only where + > the resolved tier actually asked for the test check. +- A **`MANUAL CHECK NEEDED` item the user never resolved**. Section 4 already + refuses to assume PASS for unverifiable items and marks them this way — but + until now the verdict vocabulary had nowhere to put one, so an unresolved + manual check had to land inside PASS, CONCERNS or FAIL anyway. This is where it + goes. +- A director the **resolved tier was supposed to spawn** did not return — it + errored, produced no verdict, or was interrupted. + + > **Scope this narrowly, and do not read it as "fewer than four directors ran".** + > Section 4b narrows the panel *by design* — 1 director at `minimal`, 2 at + > `standard`, 4 at `full`, and none in `solo` — and that narrowing is a + > deliberate, announced reduction, not a failure to assess. The broad reading + > makes every `minimal`, `standard` and `solo` gate permanently NOT ASSESSED, + > which means the verdict can never be PASS and Section 6 can never advance + > `project.stage`. **That would break stage advancement for most projects,** + > since those are the common tiers. The trigger fires only when a director the + > tier *did* call for fails to come back — a hole in the panel you expected, + > never the panel you deliberately chose. +- A referenced upstream verdict is itself `NOT ASSESSED` — it propagates upward + rather than resolving to a pass. + +Never resolve an unknown by assuming the permissive reading. If the check could +not run, that fact is the finding. + +--- + +## 5a. Chain-of-Verification + +After drafting the verdict in Phase 5, challenge it before finalising. + +**Step 1 — Generate 5 challenge questions** designed to disprove the verdict: + +> **Tool-action requirement**: At least 2 of the 5 challenge questions below must be answered by re-reading a specific file (Read tool) or re-running a specific check (Grep tool) — not by reflection alone. Mark these with [TOOL ACTION] to indicate a tool was used. + +For a **PASS** draft: +- "Which quality checks did I verify by actually reading a file, vs. inferring they passed?" +- "Are there MANUAL CHECK NEEDED items I marked PASS without user confirmation? [TOOL ACTION] Re-scan the checklist for any [?] or MANUAL CHECK items." +- "Did I confirm all listed artifacts have real content, not just empty headers? [TOOL ACTION] Re-read the file and check it has non-placeholder content." +- "Could any blocker I dismissed as minor actually prevent the phase from succeeding?" +- "Which single check am I least confident in, and why?" + +For a **CONCERNS** draft: +- "Could any listed CONCERN be elevated to a blocker given the project's current state?" +- "Is the concern resolvable within the next phase, or does it compound over time?" +- "Did I soften any FAIL condition into a CONCERN to avoid a harder verdict?" +- "Are there artifacts I didn't check that could reveal additional blockers?" +- "Do all the CONCERNS together create a blocking problem even if each is minor alone?" + +For a **FAIL** draft: +- "Have I accurately separated hard blockers from strong recommendations?" +- "Are there any PASS items I was too lenient about?" +- "Am I missing any additional blockers the user should know about?" +- "Can I provide a minimal path to PASS — the specific 3 things that must change?" +- "Is the fail condition resolvable, or does it indicate a deeper design problem?" + +**Step 2 — Answer each question** independently. +Do NOT reference the draft verdict text — re-check specific files or ask the user. + +**Step 3 — Revise if needed:** +- If any answer reveals a missed blocker → upgrade verdict (PASS→CONCERNS or CONCERNS→FAIL) +- If any answer reveals a check that **could not be run** rather than one that + ran and passed → PASS→NOT ASSESSED. The first two PASS-draft questions above + ("verified by actually reading a file, vs. inferring", "MANUAL CHECK NEEDED + items I marked PASS") exist to find exactly this, and until now a yes to either + had no verdict to move to +- If any answer reveals an over-stated blocker → downgrade only if citing specific evidence +- Never revise NOT ASSESSED down to PASS by re-reasoning about the missing input. + Only obtaining the input clears it +- If answers are consistent → confirm verdict unchanged + +**Step 4 — Note the verification** in the final report output: +`Chain-of-Verification: [N] questions checked — verdict [unchanged | revised from X to Y]` + +--- diff --git a/.claude/skills/gate-check/references/6-update-stage.md b/.claude/skills/gate-check/references/6-update-stage.md new file mode 100644 index 00000000..62e4fc04 --- /dev/null +++ b/.claude/skills/gate-check/references/6-update-stage.md @@ -0,0 +1,84 @@ +# /gate-check — Section 6: Update Stage on PASS + +> Part of `/gate-check`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 6. Update Stage on PASS + +When the verdict is **PASS** and the user confirms they want to advance, write the +new stage to BOTH `project.yaml` and the legacy `production/stage.txt`. + +**On CONCERNS, the user may override — explicitly.** Do not offer the stage +write by default. If the user asks to advance anyway, list every concern and +ask: "The gate returned CONCERNS. Accept these risks — [list] — and may I update +`project.stage` in `project.yaml` to '[stage]' (and the legacy +`production/stage.txt`)?" Only on an explicit yes, add the `### Accepted Risks` +section to the gate report (each concern, accepted by the user, with the date) +and write the stage as below. **A FAIL is never overridden into a stage change, and +neither is NOT ASSESSED** — the blockers must be fixed, or the missing input +produced, and the gate re-run. + +### 6.1 Primary write — `project.yaml` + +Set `project.stage` to the new stage name in `project.yaml` at the repo root. + +- **If a `project:` block already exists**: Read `project.yaml` first (the Edit + tool requires the file to have been read in this session), then use the Edit + tool to change its `stage:` value. +- **If `project.yaml` exists but has no `project:` block**: Read `project.yaml` + first, then use the Edit tool to insert the block immediately after the + `framework:` block (before `modes:`). Insert exactly (replace ``): + ```yaml + project: + stage: + ``` +- **If `project.yaml` does not exist at all**: create it with the Write tool using + this v1.1 minimal template (replace `` and the date): + ```yaml + # CCGS project configuration — single source of truth for project settings. + # Schema: grep the `## ` section of .claude/docs/effects-map.md — + # it is ~31k tokens whole, ~900 per section. Do not open it entire. + + schema_version: 1 + + framework: + version: 1.1.3 + last_upgraded: + + project: + stage: + ``` + Do not seed `modes.review_mode` here. It is a rigor-fronted knob — `modes.rigor` + supplies its value, so an explicit value would shadow the rigor expansion and pin + the review mode regardless of the project's rigor. + +### 6.2 Legacy fallback write — `production/stage.txt` + +Also write the single-line stage name (no trailing newline) so hooks that have not +migrated still work. Ensure the `production/` directory exists first: +```bash +mkdir -p production && printf '%s' "Production" > production/stage.txt +``` + +### 6.3 Verify both writes + +After both writes, Read `project.yaml` and `production/stage.txt` and confirm both +show the new stage. If they diverge, report the discrepancy to the user and stop — +a split stage indicator corrupts future auto-detection. + +**Always ask before writing**: "Gate passed. May I update `project.stage` in `project.yaml` to 'Production' (and the legacy `production/stage.txt`)?" — on an accepted CONCERNS override, the explicit yes above is that ask. + +### 6.4 Rigor-fit check (advisory — never affects the verdict) + +After the stage advance is confirmed, apply the raise trigger in +`.claude/docs/settings-guidance.md § 4`: if the new stage is **Production** (or +later) while the resolved `modes.workflow` is `minimal` (the `rigor: minimal` +posture, from the config block above), add one line: + +> "You're entering [stage] on `rigor: minimal` — most projects this size run +> `standard`. Revisit with `/settings modes.rigor=standard`?" + +Offer it **once**, here at the gate. Route to `/settings` — never change the +setting yourself. + +--- diff --git a/.claude/skills/gate-check/references/7-next-steps.md b/.claude/skills/gate-check/references/7-next-steps.md new file mode 100644 index 00000000..fa939b0a --- /dev/null +++ b/.claude/skills/gate-check/references/7-next-steps.md @@ -0,0 +1,120 @@ +# /gate-check — Sections 7 and 8: Next Step and Follow-Up + +> Part of `/gate-check`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 7. Closing Next-Step Widget + +**In this file:** + +- 7. Closing Next-Step Widget: per gate, and the `workflow: minimal` route +- 8. Follow-Up Actions + +After the verdict is presented and any stage update is complete (project.yaml + stage.txt), close with a structured next-step prompt using `AskUserQuestion`. + +**Tailor the options to the gate that just ran.** The argument names the phase +being entered, so `/gate-check systems-design` is the Concept → Systems Design gate. + +**At `workflow: minimal`, skip the menus below.** They walk the phase ladder, and +the minimal route is not the ladder: offer the first incomplete step of +`paths.minimal` instead (the `--path minimal` rows from Section 3): +`/setup-engine`, then `/brainstorm`, then `/create-stories`, then `/dev-story` +on the next story — the route `/help` gives. + +For **Concept → Systems Design** (`/gate-check systems-design`) PASS — option [A] is +`/map-systems` when `design/gdd/systems-index.md` does not exist yet (many +projects write it during Concept, as the workflow catalog orders it), otherwise +`/design-system [first system in the index's design order]`: +``` +Gate passed. What would you like to do next? +[A] Run /map-systems — decompose the concept into systems and a design order (recommended next step) + — or, when the systems index already exists: Run /design-system [first system] — author its GDD +[B] Revisit the concept first — return here when it is settled +[C] Stop here for this session +``` + +For **Systems Design → Technical Setup** (`/gate-check technical-setup`) PASS: +``` +Gate passed. What would you like to do next? +[A] Run /create-architecture — produce your master architecture blueprint and ADR work plan (recommended next step) +[B] Design more GDDs first — return here when all MVP systems are complete +[C] Stop here for this session +``` + +> **Note for the Systems Design → Technical Setup PASS**: `/create-architecture` is the required next step before writing any ADRs. It produces the master architecture document and a prioritized list of ADRs to write. Running `/architecture-decision` without this step means writing ADRs without a blueprint — skip it at your own risk. + +For **Technical Setup → Pre-Production** (`/gate-check pre-production`) PASS: +``` +Gate passed. What would you like to do next? +[A] Run /create-control-manifest — generate the layer rules manifest from your Accepted ADRs (first, if docs/architecture/control-manifest.md does not exist yet) +[B] Run /vertical-slice — build the Vertical Slice (do this before writing epics — validate fun first) +[C] Write more ADRs first — run /architecture-decision [next-system] +[D] Stop here for this session +``` + +> **Note for the Technical Setup → Pre-Production PASS**: The Pre-Production sequence is deliberately ordered +> to validate fun before committing to detailed planning: +> +> 1. `/create-control-manifest` — extract technical rules from Accepted ADRs, if not done yet (`/create-epics` requires it at `full`) +> 2. `/vertical-slice` — build the Vertical Slice **FIRST**, before writing epics or stories +> 3. Playtest → `/playtest-report` — at least 1 documented session, 3+ better before committing the full team. `/gate-check production` treats the slice as recommended: skipped → CONCERNS, unplayed → NOT ASSESSED +> 4. `/ux-design [screen]` — UX specs for main menu, core HUD, pause menu (if not done) +> 5. `/create-epics layer:foundation` then `/create-epics layer:core` — plan after fun is validated +> 6. `/create-stories [epic-slug]` for each epic +> 7. `/sprint-plan new` +> +> **Why prototype before epics?** If the prototype reveals the core loop needs to change, +> epics written before that discovery will be partially wrong. Validate fun cheaply first, +> then plan in detail. This is the #1 lesson from GDC postmortem data. + +For all other gates, offer the two most logical next steps for that phase plus "Stop here". + +--- + +## 8. Follow-Up Actions + +Based on the verdict, suggest specific next steps: + +- **No art bible?** → `/art-bible` to create the visual identity specification +- **Art bible exists but no asset specs?** → `/asset-spec system:[name]` to generate per-asset visual specs and generation prompts from approved GDDs +- **No game concept?** → `/brainstorm` to create one +- **No systems index?** → `/map-systems` to decompose the concept into systems +- **Missing design docs?** → `/reverse-document` or delegate to `game-designer` +- **Small design change needed?** → `/quick-design` for changes under about one week of implementation (bypasses full GDD pipeline) +- **No UX specs?** → `/ux-design [screen name]` to author specs, or `/team-ui [feature]` for full pipeline +- **UX specs not reviewed?** → `/ux-review [file]` or `/ux-review all` to validate +- **No accessibility requirements doc?** → run `/ux-design` which creates both `design/accessibility-requirements.md` and `design/ux/interaction-patterns.md` in one step +- **No interaction pattern library?** → `/ux-design patterns` to initialize it +- **Concept or a GDD not reviewed?** → `/design-review [doc]` +- **GDDs not cross-reviewed?** → `/review-all-gdds` (run after all MVP GDDs are individually approved) +- **Cross-GDD consistency issues?** → fix flagged GDDs, then re-run `/review-all-gdds` +- **No test framework?** → `/test-setup` to scaffold the framework for your engine +- **No QA plan for current sprint?** → `/qa-plan sprint` to generate one before implementation begins +- **Missing ADRs?** → `/architecture-decision` for individual decisions +- **No master architecture doc?** → `/create-architecture` for the full blueprint +- **ADRs missing engine compatibility sections?** → Re-run `/architecture-decision` + or manually add Engine Compatibility sections to existing ADRs +- **Missing control manifest?** → `/create-control-manifest` (requires Accepted ADRs) +- **Missing epics?** → `/create-epics layer: foundation` then `/create-epics layer: core` (requires control manifest) +- **Missing stories for an epic?** → `/create-stories [epic-slug]` (run after each epic is created) +- **Stories not implementation-ready?** → `/story-readiness` to validate stories before developers pick them up +- **Tests failing?** → delegate to `lead-programmer` or `qa-tester` +- **No playtest data?** → `/playtest-report` +- **No playtest sessions beyond the minimum?** → Additional sessions give more reliable signal. 3+ total is recommended before committing the full team. Use `/playtest-report` to structure findings. +- **No Difficulty Curve doc?** → Author `design/difficulty-curve.md` by hand from the template at `.claude/docs/templates/difficulty-curve.md`. (`/quick-design` is a related session but writes to `design/quick-specs/`, not to this path — use it to think the curve through, then copy the outcome here.) +- **No player journey map?** → Author `design/player-journey.md` by hand from the template at `.claude/docs/templates/player-journey.md`. + +> **Neither of these has a skill that writes it — the remediations must not imply +> otherwise.** Naming "`/ux-design` Phase 2b" would point at the step that *reads* +> `design/player-journey.md`, landing the user back at the check that just +> failed. Naming `/quick-design` would point at a skill that writes +> `design/quick-specs/[name]-[date].md` and would leave this gate still failing. +> Both docs are hand-authored from their templates; say so plainly rather than +> naming a skill that cannot produce them. +- **Need a quick sprint check?** → `/sprint-status` for current sprint progress snapshot +- **Performance unknown?** → `/perf-profile` +- **Not localized?** → `/localize` +- **No security audit, or open CRITICAL/HIGH findings?** → `/security-audit` (after fixes, `/security-audit quick` to confirm) +- **Ready for release?** → `/launch-checklist` + +--- diff --git a/.claude/skills/hotfix/SKILL.md b/.claude/skills/hotfix/SKILL.md index f60603bb..00272624 100644 --- a/.claude/skills/hotfix/SKILL.md +++ b/.claude/skills/hotfix/SKILL.md @@ -8,6 +8,8 @@ allowed-tools: Read, Glob, Grep, Write, Edit, Bash, Agent, AskUserQuestion model: sonnet --- +# Hotfix + > **Explicit invocation only**: This skill should only run when the user explicitly requests it with `/hotfix`. Do not auto-invoke based on context matching. ## Phase 1: Assess Severity diff --git a/.claude/skills/launch-checklist/SKILL.md b/.claude/skills/launch-checklist/SKILL.md index 6f7d8460..6eb71c91 100644 --- a/.claude/skills/launch-checklist/SKILL.md +++ b/.claude/skills/launch-checklist/SKILL.md @@ -16,6 +16,8 @@ every file write follows `.claude/docs/automation-modes.md` Resolved above — use as-is. No block → defaults in `.claude/docs/config-resolution.md`. +# Launch Checklist + **Scope this checklist to the project.** Emitting every item for every platform trains the reader to skip the list, which defeats the gate: diff --git a/.claude/skills/map-systems/SKILL.md b/.claude/skills/map-systems/SKILL.md index 2785e112..78b1a566 100644 --- a/.claude/skills/map-systems/SKILL.md +++ b/.claude/skills/map-systems/SKILL.md @@ -12,6 +12,8 @@ model: sonnet Resolved above — use as-is; `--review` overrides `review_mode`. No block → defaults in `.claude/docs/config-resolution.md`. +# Map Systems + When this skill is invoked: diff --git a/.claude/skills/milestone-review/SKILL.md b/.claude/skills/milestone-review/SKILL.md index 2265123f..5d071d5d 100644 --- a/.claude/skills/milestone-review/SKILL.md +++ b/.claude/skills/milestone-review/SKILL.md @@ -12,6 +12,8 @@ model: sonnet Resolved above — use as-is; `--review` overrides `review_mode` for this run. No block → defaults in `.claude/docs/config-resolution.md`. +# Milestone Review + ## Insufficient input — check this before producing any report @@ -32,11 +34,10 @@ not a filled-in report.** Check first, and stop if the check fails. **A verdict of `NOT ASSESSED` is a success.** It is the correct, useful answer to "what does the data say?" when there is no data. The failure mode this prevents is -specific and has been observed in practice: report templates whose verdict -enum had no "could not run" state produced **false clean passes** — an asset audit -returning COMPLIANT on a project with no assets and no standards, and a -performance profile reporting ">99% headroom against a 16.67ms budget" with zero -profiler data and no budget ever set. +specific: a report whose verdict enum has no "could not run" state produces +**false clean passes** — an asset audit returning COMPLIANT on a project with no +assets and no standards, or a performance profile reporting ">99% headroom against +a 16.67ms budget" with zero profiler data and no budget ever set. **Absence of evidence is never evidence of absence.** A scan that finds no matches because there are no files to scan has not verified anything. Say which of diff --git a/.claude/skills/onboard/SKILL.md b/.claude/skills/onboard/SKILL.md index d179a787..d2645820 100644 --- a/.claude/skills/onboard/SKILL.md +++ b/.claude/skills/onboard/SKILL.md @@ -15,6 +15,8 @@ every file write follows `.claude/docs/automation-modes.md` (collaborative asks always · guided major-only · autonomous logs and proceeds; `automation_always_ask` categories always prompt). +# Onboard + ## Insufficient input — check this before producing any report **If the inputs this skill needs do not exist, the answer is "could not run" — @@ -33,11 +35,10 @@ not a filled-in report.** Check first, and stop if the check fails. **A verdict of `NOT ASSESSED` is a success.** It is the correct, useful answer to "what does the data say?" when there is no data. The failure mode this prevents is -specific and has been observed in practice: report templates whose verdict -enum had no "could not run" state produced **false clean passes** — an asset audit -returning COMPLIANT on a project with no assets and no standards, and a -performance profile reporting ">99% headroom against a 16.67ms budget" with zero -profiler data and no budget ever set. +specific: a report whose verdict enum has no "could not run" state produces +**false clean passes** — an asset audit returning COMPLIANT on a project with no +assets and no standards, or a performance profile reporting ">99% headroom against +a 16.67ms budget" with zero profiler data and no budget ever set. **Absence of evidence is never evidence of absence.** A scan that finds no matches because there are no files to scan has not verified anything. Say which of diff --git a/.claude/skills/patch-notes/SKILL.md b/.claude/skills/patch-notes/SKILL.md index 1d342a91..bd6a16b1 100644 --- a/.claude/skills/patch-notes/SKILL.md +++ b/.claude/skills/patch-notes/SKILL.md @@ -15,6 +15,8 @@ every file write follows `.claude/docs/automation-modes.md` (collaborative asks always · guided major-only · autonomous logs and proceeds; `automation_always_ask` categories always prompt). +# Patch Notes + ## Provenance check — before reading any history **Confirm the history you are about to read belongs to THIS game.** Run this diff --git a/.claude/skills/perf-profile/SKILL.md b/.claude/skills/perf-profile/SKILL.md index 7911cf31..554caf1e 100644 --- a/.claude/skills/perf-profile/SKILL.md +++ b/.claude/skills/perf-profile/SKILL.md @@ -7,11 +7,13 @@ allowed-tools: Read, Glob, Grep, Write, Bash, Bash(bash "*/.claude/skills/perf-p model: sonnet --- -!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys performance.enforce,automation` +!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys performance.enforce,automation,workflow` Resolved above — use as-is. No block → defaults in `.claude/docs/config-resolution.md`. +# Performance Profile + Every `AskUserQuestion` call follows `.claude/docs/automation-modes.md` (collaborative asks always · guided major-only · autonomous logs and proceeds; `automation_always_ask` categories always prompt). @@ -34,11 +36,10 @@ not a filled-in report.** Check first, and stop if the check fails. **A verdict of `NOT ASSESSED` is a success.** It is the correct, useful answer to "what does the data say?" when there is no data. The failure mode this prevents is -specific and has been observed in practice: report templates whose verdict -enum had no "could not run" state produced **false clean passes** — an asset audit -returning COMPLIANT on a project with no assets and no standards, and a -performance profile reporting ">99% headroom against a 16.67ms budget" with zero -profiler data and no budget ever set. +specific: a report whose verdict enum has no "could not run" state produces +**false clean passes** — an asset audit returning COMPLIANT on a project with no +assets and no standards, or a performance profile reporting ">99% headroom against +a 16.67ms budget" with zero profiler data and no budget ever set. **Absence of evidence is never evidence of absence.** A scan that finds no matches because there are no files to scan has not verified anything. Say which of @@ -81,13 +82,17 @@ Read the argument: record of what it agreed to, and design docs are the fallback, not the source: ```bash -source "${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/yaml-helper.sh" 2>/dev/null -get_effective_yaml_key performance.target_framerate -get_effective_yaml_key performance.frame_budget_ms -get_effective_yaml_key performance.draw_call_limit -get_effective_yaml_key performance.memory_ceiling_mb +(cd "${CLAUDE_SKILL_DIR}/../../.." && source .claude/hooks/yaml-helper.sh 2>/dev/null && + echo "performance.target_framerate: $(get_effective_yaml_key performance.target_framerate)" && + echo "performance.frame_budget_ms: $(get_effective_yaml_key performance.frame_budget_ms)" && + echo "performance.draw_call_limit: $(get_effective_yaml_key performance.draw_call_limit)" && + echo "performance.memory_ceiling_mb: $(get_effective_yaml_key performance.memory_ceiling_mb)") ``` +Run it as one command: it loads the helper from the project root, so it works +when the session was started in a subfolder. An empty value after a key means +that budget is not set. + > Written as four literal keys rather than a loop over leaf names, deliberately. > The dead-settings audit matches the **full dotted key**, so a loop building > `performance.$k` leaves three of the four spelled nowhere and the audit @@ -206,7 +211,7 @@ Activate this phase only if any hotspot has Fix Effort rated M or L. Present significant-effort items and ask the user to choose for each: -- **A) Implement the optimization** (proceed with fix now or schedule it) +- **A) Implement the optimization** (proceed with fix now or schedule it — at `workflow: minimal`, which has no sprints, add it to the brief's build order) - **B) Reduce feature scope** (run `/scope-check [feature]` to analyze trade-offs) - **C) Accept the performance hit and defer to Polish phase** (log as known issue) - **D) Escalate to technical-director for an architectural decision** (run `/architecture-decision`) @@ -228,7 +233,7 @@ other outcome is the `NOT ASSESSED — NO DATA` path above. - If bottlenecks require architectural change: run `/architecture-decision`. - If scope reduction is needed: run `/scope-check [feature]`. -- To schedule optimizations: run `/sprint-plan update`. +- To schedule optimizations: run `/sprint-plan update` (at `workflow: minimal`, which has no sprints, add them to the brief's build order instead). ### Rules - Never optimize without measuring first — gut feelings about performance are unreliable diff --git a/.claude/skills/playtest-report/SKILL.md b/.claude/skills/playtest-report/SKILL.md index 442ea985..aa418a24 100644 --- a/.claude/skills/playtest-report/SKILL.md +++ b/.claude/skills/playtest-report/SKILL.md @@ -12,6 +12,8 @@ model: sonnet Resolved above — use as-is; `--review` overrides `review_mode` for this run. No block → defaults in `.claude/docs/config-resolution.md`. +# Playtest Report + ## Phase 1: Parse Arguments diff --git a/.claude/skills/prototype/SKILL.md b/.claude/skills/prototype/SKILL.md index d332d3fc..056d63e4 100644 --- a/.claude/skills/prototype/SKILL.md +++ b/.claude/skills/prototype/SKILL.md @@ -12,7 +12,7 @@ model: sonnet Resolved above — use as-is; `--review` overrides `review_mode` for this run. No block → defaults in `.claude/docs/config-resolution.md`. - +# Prototype ## Purpose @@ -34,581 +34,45 @@ before committing to Production, run `/vertical-slice` instead. ## Phase 1: Define the Question - -Every `AskUserQuestion` call follows `.claude/docs/automation-modes.md` -(collaborative asks always · guided major-only · autonomous logs and proceeds; -`automation_always_ask` categories always prompt). - -**Check for spike mode:** If `--spike` was passed, skip to the **Spike Mode** section -at the bottom of this skill. - -**Check for a carry-forward note:** Glob `prototypes/*/PIVOT-NOTE.md`. If one -exists for this concept (or an earlier version of it), read it and start from its -revised hypothesis instead of forming one from scratch — say which note you used. - -Then, unless `--spike` sent you to Spike Mode, use `AskUserQuestion` to confirm -intent before proceeding — with or without a carry-forward note: - -- **Prompt**: "How would you like to use this prototype session?" -- **Options**: - - `Prototype this concept` — build a throwaway build to validate the core idea is fun before writing GDDs (1–3 days) - - `Skip — concept already proven` — I have enough evidence this works; log it and proceed directly to design - - `Mid-production spike` — I'm already in Production and want to test a specific mechanic or technical question quickly (~4 hours, no phase gate implications) - -**If "Skip — concept already proven":** -Ask (plain text, not a widget): "What evidence do you have that the concept works?" -Record the one-line answer, then stop. Note: "Concept prototype skipped — evidence: -[answer]." Suggest next step: `/map-systems` or `/design-system [mechanic]`. - -**If "Mid-production spike"**: skip to the **Spike Mode** section below. - -**If "Prototype this concept"**: continue with Phase 1 below. - ---- - -**A note on prototype strategy:** The research on successful indie development -is consistent — building 2-3 concept variants and letting the best one win is -far more likely to succeed than iterating one concept until it works. This is -your first prototype, not necessarily your only one. If this prototype produces -a PIVOT verdict, consider whether to refine this concept OR start fresh with a -different angle on the same game idea and prototype that instead. - -**Game jam as a prototype vehicle:** If you're planning a concept prototype anyway, -consider timing it to a game jam (Ludum Dare, GMTK Game Jam, Global Game Jam). Jams -provide a forced timebox (48-72 hours), instant distribution to thousands of players -who rate and review early builds, and a deadline that prevents scope creep by design. -Many shipped games (Celeste, VVVVVV) began as jam prototypes. Not required — but -worth considering if the timing is right. - -Read the concept description from the argument. Before building anything, define -the **falsifiable hypothesis** this prototype must answer: - -> *"If the player [does X], they will feel [Y] — we will know this is true if [measurable signal Z]."* - -Good: "If the player swings on grapple hooks, traversal will feel fluid — we'll know if -players chain 3+ swings without stopping within 2 minutes of picking it up." - -Bad: "Does this feel fun?" ← not testable, not falsifiable. - -**If the concept is too vague to form a hypothesis, stop here.** Ask the user to -narrow the question before proceeding. A prototype without a clear question wastes time. - -Also ask: **"What is the riskiest assumption in this concept?"** That is the first -thing the prototype should test — not the easiest part, the riskiest. - ---- +**Read `references/1-question.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 2: Load Concept Context -Read `design/gdd/game-concept.md` — or `design/game-brief.md`, the one-page brief -that replaces it at `rigor: minimal` — if either exists. Extract: -- Core fantasy (what the player is supposed to feel) -- Core loop (the moment-to-moment action being tested) - -Determine the engine and language in use: read `engine.name` and -`engine.language` from `project.yaml`. For each field, if its key is absent or -empty (including when `project.yaml` has no `engine:` block), fall back to -`CLAUDE.md` and `.claude/docs/technical-preferences.md`. Treat a -`[TO BE CONFIGURED]` value as not set. - ---- +**Read `references/2-load-context.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 3: Choose the Prototype Path -Select the prototype path. If `--path [html|engine|paper]` was passed, use that. -Otherwise, use this quick-reference first, then read the full path details below: - -| Genre | Recommended path | Key reason | -|-------|-----------------|------------| -| Platformer / action / fighter | **Engine** | Feel IS the hypothesis; browser latency produces false results | -| Racing / sports | **Engine** | Same — timing and physics feedback are the point | -| Top-down shooter / twin-stick | **Engine** | Aim feel is timing-sensitive | -| Puzzle (logic) | **HTML** or **Paper** | Timing is not the point; logic and clarity are | -| Card game | **Paper** first | Fastest iteration by hand before touching code | -| Narrative / visual novel | **Paper** (Twine / Ink / Yarn Spinner) | Story is the mechanic — test it without code overhead | -| Strategy / 4X / city builder | **Paper** (spreadsheet sim) | Validate economy and progression rules before building | -| Roguelike (systems-heavy) | **Paper** → Engine | Validate that the ruleset is interesting before building | -| Idle / clicker / incremental | **HTML** | Turn-based logic, no feel sensitivity required | -| Rhythm game | **Paper** first (design levels in audio) | Design levels before the engine exists | -| RPG / open world | **Paper** → Engine | Systems complexity: validate rules, then validate feel | -| Horror / atmospheric | **Engine** | Atmosphere requires real rendering | - -**Rule of thumb:** "Does this feel right?" → Engine. "Are these rules interesting?" → Paper. "Is this logic correct?" → HTML or Paper. - -### Path: HTML (browser-playable) - -**Best for:** Puzzle games, card games, turn-based strategy, word games, idle games, -top-down logic games. Anything where timing precision doesn't matter. - -**Reliability:** ~85–90% one-shot. The agent writes a single self-contained HTML -file the user opens in a browser — no install required. - -**Limitation — browser latency lies about game feel.** Browsers introduce -50–133ms of rendering variance. This makes HTML prototypes fundamentally unreliable -for action games, platformers, fighting games, or anything where input timing, -jump arcs, or collision feel are what you're testing. If feel is the hypothesis, -use the Engine path instead. - -**Alternative tools for this path:** PICO-8 (extreme constraints, great for retro -arcade concepts, web-export in one command), Phaser.js (more capable browser game -framework, still no install needed), or Twine (narrative/choice-based games). -These are faster than raw HTML for their respective genres — suggest them if appropriate. - -**Output:** A single `prototype.html` (or PICO-8/Phaser equivalent) the user opens in any browser. - -**Distribution — the HTML path's biggest advantage:** Unlike Engine prototypes, this -build can reach real players globally in minutes. Use this actively: -- **itch.io** — upload the file, share the link, get play counts and written feedback - within hours. Free. The indie community plays rough builds here without expecting - polish. This is genuine external validation at zero cost. -- **Loom + file share** — share via Google Drive/Dropbox, ask someone to record their - screen + audio with Loom while playing. You get a video of real first-impression - reactions and confusion without synchronous scheduling. -- **r/playmygame or r/WebGames** (Reddit) — active communities that specifically - test early builds and give unsolicited honest feedback. -- **Game dev Discord servers** (GMTK, Brackeys, GameDev.tv) — members test each - other's prototypes routinely; an HTML file is the easiest possible ask. - ---- - -### Path: Engine (engine project) - -**Best for:** Action games, platformers, physics-heavy games, anything where -moment-to-moment feel IS the hypothesis. Use this when HTML latency would lie about -the result. - -**Reliability:** ~50–60% one-shot. Expect 2–4 rounds of iteration — this is -normal, not a failure. - -**Limitation — requires engine installed and running.** This path is a -multi-turn collaborative loop: -1. Agent writes the code -2. User runs it in the engine -3. User reports errors or observations -4. Agent fixes and iterates - -**Sunk cost rule:** If the user has been iterating for more than 2 hours without -reaching a playable state, stop. The scope is too large or the question is wrong. -Reframe the hypothesis and simplify aggressively, or switch to Paper path. - -**Output:** A minimal runnable engine project in `prototypes/[name]-concept/`. - -**Lighter alternative — Love2D (Lua):** If the project engine (Godot, Unity, Unreal) -feels too heavy to stand up for a throwaway build, consider Love2D — a minimal 2D -framework that installs in minutes, requires no project scaffolding, and renders -natively with no browser latency. Used by many indie devs for rapid 2D action and -platformer prototypes (Balatro prototyped in Love2D; Nuclear Throne's early builds -used it). It sits between HTML overhead and full engine overhead: heavier than -opening a browser, lighter than setting up a full engine project. Best for 2D -action/platformer feel validation when the project engine is 3D-first or takes -significant time to configure. - ---- - -### Path: Paper (rules document + play log) - -**Best for:** Strategy games, card games, board game-style mechanics, economy -systems, progression loops, any game where the logic can be simulated by hand. -Works for any genre when you need to validate rules, not feel. - -**Reliability:** 100%. No code, no engine, no install. - -**Limitation — cannot validate moment-to-moment feel.** Paper prototypes prove -that the rules are internally consistent and the decisions are interesting. They -cannot tell you whether jumping feels right or whether explosions feel satisfying. - -**Paper playtest observation protocol (run this with 5+ people):** -1. Brief the rules once. Hand them the rule summary sheet. Then step back. -2. Do NOT explain further. Do NOT help. Do NOT clarify. Confusion is data. -3. Watch silently. Note every moment they slow down, re-read, or ask a question. -4. After the session, ask one question only: "What was confusing?" — not "Did you like it?" -5. Use fresh testers for each iteration. The same person cannot give new first-impression data. -6. If 3+ testers hit the same confusion point, that rule is broken — redesign it before re-testing. - -**Output:** A printable rules document + a completed play log showing one simulated session. - -**Narrative tools for this path:** For dialogue-heavy and story-driven games, skip the -generic rules doc — use a dedicated narrative scripting tool instead: -- **Twine** — zero-code hypertext fiction; ideal for branching structure experiments and choice-impact testing -- **Ink** (Inkle) — plain-text scripting language used in *80 Days*, *Heaven's Vault*, and *Overboard*; exports directly to Unity and Godot -- **Yarn Spinner** — dialogue scripting used in *A Short Hike*, *DREDGE*, and *Night in the Woods*; integrates natively with Unity and Godot - -All three let you write and playtest branching dialogue in minutes. Key metric for -narrative prototypes: **time to first emotional beat** — how many exchanges before -the player feels something? If it takes more than 3-4 exchanges, the opening is too slow. - ---- - -Assess which path best fits the hypothesis, then use `AskUserQuestion` with your -recommendation pre-stated: - -- **Prompt**: "Which prototype path would you like to use? (Based on your concept, I'd recommend [path] — [one sentence reason].)" -- **Options**: - - `HTML — browser prototype` — puzzle, card, turn-based, strategy, idle. Opens by double-clicking, no install. 85–90% reliable. **Not suitable for action games** — browser latency lies about feel. - - `Engine — native prototype` — action, platformer, physics, or anything where feel IS the hypothesis. 50–60% one-shot; 2–4 iteration rounds are normal. Requires engine installed. - - `Paper — rules document + play log` — strategy, economy, logic, board-game-style mechanics. 100% reliable. Cannot validate feel. - ---- +**Read `references/3-choose-path.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 4: Plan the Prototype -Define in 3–5 bullet points the minimum viable prototype: - -- What is the falsifiable hypothesis? -- What is the riskiest assumption — and how does this prototype test it first? -- What is the absolute minimum needed to answer the question? -- What is explicitly cut? (menus, save systems, error handling, polish, architecture — all of it) - -**Scope constraint:** A concept prototype tests ONE mechanic — not the whole game. -If scope covers more than one mechanic, cut it down. When in doubt, cut more. - -Present this plan to the user before building. Get confirmation before proceeding. -Name the checkpoint file in that confirmation: "May I record this plan in -`production/session-state/active.md`?" - -Once confirmed, write a session checkpoint to `production/session-state/active.md` -(create `production/session-state/` if it does not exist). Include: concept name, -hypothesis, path chosen, scope bullet points, and current phase ("Phase 5 — -Implement"). This lets the next session resume without starting over if the session -ends mid-build — especially important for multi-day Engine path work. - ---- +**Read `references/4-plan.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 5: Implement -Ask: "May I create the prototype directory at `prototypes/[concept-name]-concept/` -and begin implementation?" - -If yes, create the directory. Every file must begin with: - -``` -[comment] PROTOTYPE - NOT FOR PRODUCTION -[comment] Question: [Core question being tested] -[comment] Date: [Current date] -``` - -Write `[comment]` in each file's own comment syntax — `#` in GDScript (`.gd`) and -Python, `//` in C#, C++ and JavaScript, `--` in Lua, `` in HTML and -Markdown. A header in another language's syntax is a parse error, not a label. -Files that cannot hold a comment (JSON, engine-generated scene and project -files) are exempt. - -Standards are intentionally relaxed: - -- Hardcode values freely -- Use placeholder assets (colored rectangles, debug shapes) -- Skip error handling entirely -- Use the simplest approach that works -- Copy code rather than importing from production -- No architecture, no patterns, no abstractions - -**Do not add polish.** No menus, no game over screens, no music, no tutorial text -unless the tutorial IS the mechanic being tested. Every addition beyond the -hypothesis is waste. - -**Playtesting tip:** If you have access to anyone who hasn't seen the game — -friends, family, strangers online — watching them play without explanation gives -far better signal than testing it yourself. Watch silently; don't guide them. -Confusion is data. Ask one question after: "What was confusing?" Not "Did you -like it?" - -**No external testers available?** Use rotation: if you built system A, you're a -naive tester for system B. In a two-person team this works well. Solo developer? -Step away for 2-3 days before playing fresh — you won't have perfect first-impression -signal, but you'll surface the worst blockers. Another option: play your own -prototype as a speedrun (force yourself through it in 5 minutes without stopping -to fix things) — the friction you feel is what strangers will hit. - -**Want more granular UX data?** Ask the tester to **think aloud** as they play — -narrate their thoughts in real time: "I'm pressing space... nothing happened... is -that the jump key?" This surfaces confusion the moment it happens rather than -waiting for a post-play debrief. Best for UI/UX and onboarding clarity. Silent -observation is still better for testing raw feel; think-aloud changes how people -play slightly but gives much richer data about why they're confused. - -**HTML prototype?** itch.io, Reddit (r/playmygame), and Discord (GMTK, Brackeys) -let you reach strangers today at zero cost — see the distribution options in the -HTML path section above. - -**Testing AI, NPC, or complex system behavior before writing the code?** Use the -**Wizard of Oz** technique: one person plays normally while a second person secretly -controls the NPC, enemy, or system behavior in real time — making the decisions a -human would make, not an algorithm. The player believes it's automated. This lets -you validate whether your AI design *feels right* before writing a single line of -pathfinding or decision tree code. When you observe what responses the human -controller naturally produces, you learn exactly what the AI needs to do. - -### Engine path: multi-turn loop - -After writing the initial code: - -> "The prototype files are written. Run the project in your engine now. -> If there are errors, paste them here and I'll fix them. If it runs, -> describe what you see and whether it feels like it's answering the question." - -Iterate until the prototype is playable. Each loop: -1. User runs → reports errors or observations -2. Agent fixes errors or adjusts the mechanic -3. Repeat until playable or sunk cost rule triggers - -### HTML path: single output - -Write a single `prototype.html` to `prototypes/[concept-name]-concept/`. Include -all styles, logic, and assets inline. The file must be openable by double-clicking -with no server required. - -### Paper path: document + log - -Write `prototypes/[concept-name]-concept/rules.md` (the game rules) and -`prototypes/[concept-name]-concept/play-log.md` (a simulated session walking -through one complete play cycle step by step with dice rolls, decisions, and -outcomes narrated). - ---- +**Read `references/5-implement.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 6: Playtest Debrief -The prototype is built. Now hand it to the user and capture what they actually -experienced. Do NOT skip to report generation — the report is only as good as the -observations you collect here. - -**For HTML path:** Say exactly this: -> "The prototype is ready. Open `prototypes/[name]-concept/prototype.html` in your -> browser and play it. Take as long as you need. Don't rush through it — try to -> approach it the way a new player would. Come back here when you're done." - -**For Engine path:** The multi-turn iteration loop already captured errors and -behavior. Now ask for the overall assessment: -> "Now that it's running — play through it a few times as if you're the player, -> not the developer. Come back when you have a feel for it." - -**For Paper path:** Say exactly this: -> "Read through `prototypes/[name]-concept/rules.md` and walk through the -> `play-log.md` as if you're playing it for the first time. If you have someone -> nearby, try running the rules with them. Come back when you've seen at least one -> full play cycle." - -**If nobody can play it this session**, do not ask for a verdict and do not infer -one from how the build looks: the recommendation is **NOT ASSESSED — built, not -played**. Write the report with that verdict (Phase 7, asking first) and name the -next step — play it, then re-run this debrief. - -Once the user returns, ask these questions **one at a time** — wait for each answer -before asking the next: - -1. **Hypothesis check:** - > "The hypothesis was: [restate the hypothesis from Phase 1]. Did it hold up — - > CONFIRMED, PARTIALLY CONFIRMED, or REFUTED? Tell me what you saw." - -2. **Best moment:** - > "What was the moment — if any — where it felt like it was working? Be specific." - -3. **Worst moment:** - > "What was the most frustrating, confusing, or broken moment? Be specific — - > not 'it felt slow' but 'the jump took about half a second to respond and it - > felt like I was fighting the controls'." - -4. **Surprise:** - > "Did anything happen that you didn't expect — good or bad?" - -5. **Verdict:** - > "PROCEED, PIVOT, or KILL — and one sentence why." - -Collect all answers before moving to report generation. If any answer is vague -("it felt fine", "pretty good"), ask a follow-up: "Can you be more specific? -What exactly felt fine about it?" Precise observations make the report useful. -Vague ones make it useless. - ---- +**Read `references/6-debrief.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 7: Generate Prototype Report -Read `.claude/docs/templates/prototype-report.md` to get the report structure. -Fill in every section based on what was observed during this session. Replace all -placeholder text with real observations — no generic filler. - -Ask: "May I write this report to `prototypes/[concept-name]-concept/REPORT.md` -and add its row to `prototypes/index.md`?" - -If yes, write the file. Then update `prototypes/index.md` (create if it does not -exist) — append one row to the concept prototype table: concept name, date, path -used, verdict (PROCEED/PIVOT/KILL, or NOT ASSESSED when nobody has played it), and a link to the REPORT.md. If a PIVOT chain -exists (prior PIVOT-NOTE.md in a related concept folder), note the chain. This file -is the project's complete history of what was tried and what was learned. - ---- +**Read `references/7-report.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 8: Creative Director Review -**Review mode check:** -- `solo` → skip. Note: "CD-PLAYTEST skipped — Solo mode." -- `lean` → skip. Note: "CD-PLAYTEST skipped — Lean mode." -- `full` → spawn `creative-director` via `Agent` using gate **CD-PLAYTEST** if - `design/gdd/game-concept.md` exists with game pillars defined, or - `design/game-brief.md` exists (the `rigor: minimal` brief has no pillars — its - pitch and "what they feel" line stand in). If neither is available, note: - "CD-PLAYTEST skipped — game pillars not yet defined at concept prototype stage." - -Pass: the full REPORT.md content, the original hypothesis, and game pillars / -core fantasy from `design/gdd/game-concept.md` (or the brief's pitch and "what -they feel" line from `design/game-brief.md`). - -The creative director evaluates the result against the game's creative vision and -returns one of the gate's verdicts — APPROVE, CONCERNS or REJECT — or NOT -ASSESSED when it could not judge. Apply it to the recommendation: - -- **APPROVE** → the recommendation stands. -- **CONCERNS** → show the concerns alongside the recommendation, then use - `AskUserQuestion`: `Revise the recommendation` / `Accept with noted concerns` / - `Discuss further`. The user decides; the director does not. -- **REJECT** (the core fantasy is not present) → a PROCEED recommendation cannot - stand. Use `AskUserQuestion` to ask the user to choose `PIVOT` or `KILL`, and run - Phase 9 for that choice. A PIVOT or KILL recommendation stands. -- **NOT ASSESSED** (the director lacked an input — `.claude/docs/director-gates.md`) - → not an approval. Name what was missing; supply it and re-run the gate, or - record the review as NOT ASSESSED and let the user decide whether the - recommendation stands unreviewed. - -When the director returned CONCERNS, REJECT or NOT ASSESSED, ask "May I update -`prototypes/[concept-name]-concept/REPORT.md` and its `prototypes/index.md` -row?", then record the director's verdict and reason in REPORT.md, and the final -recommendation in both if it changed. - ---- +**Read `references/8-cd-review.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 9: Summary and Next Steps -Output a summary: the hypothesis, the result, and the final recommendation. -Link to `prototypes/[concept-name]-concept/REPORT.md`. - -**If PROCEED:** -Your concept prototype validated the core idea. Now design it properly, informed by -what you just learned. - -At `workflow: minimal`: `/create-stories` (from the brief), then `/dev-story` -on the first story — the rest of this list is the `standard`/`full` path. - -Recommended path (in order, `standard`/`full`): -1. `/design-review design/gdd/game-concept.md` — validate the concept doc against what the prototype revealed -2. `/gate-check` — confirm readiness to advance to Systems Design -3. `/art-bible` — define visual identity (optional but worth doing before GDDs) -4. `/map-systems` — decompose the concept into all game systems -5. `/design-system [mechanic]` — GDD for each MVP system; use prototype learnings - in the Tuning Knobs and Formulas sections -6. `/review-all-gdds` — cross-system consistency check - -**Note:** If you used the HTML path and feel is still uncertain, consider running -a quick engine path prototype targeting feel before writing GDDs. - -**If PIVOT:** - -Before routing to the next prototype, capture the carry-forward note. Ask these -two questions (plain text, one at a time): - -1. "What specifically worked in this prototype that we should preserve in the next version?" -2. "What is the single most important thing to change?" - -Ask: "May I write this to `prototypes/[concept-name]-concept/PIVOT-NOTE.md`?" - -If yes, write the file with: original hypothesis, what to keep, what to change, and -the revised hypothesis for the next prototype. The next `/prototype` run picks it -up at the start of Phase 1. - -- Run `/prototype [revised-concept]` to test the adjusted direction -- Or `/brainstorm [hint]` if the concept needs more fundamental rethinking - -**If KILL:** - -Before moving on, run this check to confirm the verdict is sound and not temporary frustration: - -- [ ] Core mechanic still unclear to testers after 2+ playtests? -- [ ] No "fun moment" (smile, laugh, or retry by choice) observed in any session? -- [ ] 3+ PIVOT iterations on the same concept with no clear improvement? -- [ ] Concept only works when heavily explained or when the dev guides the player? -- [ ] Building this feels like obligation, not excitement? - -If 2+ boxes apply → KILL verdict is sound. If 0–1 apply → consider one more focused PIVOT before killing. - -**Document the kill in `prototypes/GRAVEYARD.md`** (create if it doesn't exist). -Ask: "May I append this concept to `prototypes/GRAVEYARD.md`?" If yes, add one entry: - -``` -## [Concept Name] — YYYY-MM-DD -- **Kill reason:** [specific blocker — not "it was boring" but "players never understood the core action"] -- **What worked:** [2-3 things worth carrying forward to future concepts] -- **What failed:** [the specific mechanic, design decision, or scope issue] -- **Next time:** [one explicit action to try differently on a similar concept] -``` - -This file exists so the same mistake doesn't get made twice on the next concept. - -- Run `/brainstorm open` or `/brainstorm [new-hint]` to explore a different concept -- The prototype report is the deliverable — no further action needed - -**If NOT ASSESSED (nobody has played it):** - -There is no fun evidence yet, so PROCEED, PIVOT and KILL are all unreachable — -report NOT ASSESSED and stop here rather than guess. - -- Play it, then run `/prototype [same concept]` again -- The report and the concept index row read NOT ASSESSED until a playtest happens - ---- - ---- +**Read `references/9-summary.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Spike Mode **Triggered by:** `--spike` flag OR "Mid-production spike" entry choice in Phase 1. -**Purpose:** Test a specific technical or design question mid-production, without -the overhead of a full concept prototype workflow. No GDD prerequisites. No phase -gate implications. Hard cap: ~4 hours. - -**When to use:** -- You're in Production and want to test whether a new mechanic should be added -- You're unsure if a technical approach will work before building it properly -- A design change is being considered and you want a quick before/after comparison -- A GDD system is proving harder than expected and you want to prototype the hard part -- You need to confirm target hardware can sustain the required framerate before writing gameplay code (**performance spike** — see below) - -**Spike Mode workflow (replaces Phases 1–9):** - -1. **Define the spike question** (plain text, not a widget): "What specific question does this spike answer? Give me one sentence: 'Can we [do X] using [approach Y]?'" - -2. **Choose path** — same AskUserQuestion widget as Phase 3 (HTML / Engine / Paper). - -3. **Scope** — maximum 2-3 bullet points. One mechanic, one technical question, nothing else. - -4. **Build** — first ask "May I create `prototypes/[concept-name]-spike-[date]/` and build the spike there?" Same relaxed standards and header as the concept prototype. Hard cap: 4 hours. If not demonstrable in 4 hours, the question is too large. Split it. - -5. **Observe and decide** — no formal playtest debrief. Ask: "Did the spike answer the question? YES or NO, and why in one sentence." - -6. **Write a spike note** (not a full report) to `prototypes/[concept-name]-spike-[date]/SPIKE-NOTE.md` — first ask once for this step and the next, naming both files: "May I write `prototypes/[concept-name]-spike-[date]/SPIKE-NOTE.md` and clear the spike from `production/session-state/active.md`?" The note holds: - - Question tested - - Result (YES it works / NO it doesn't / PARTIAL — needs more investigation) - - What to do next (add to current sprint / investigate further / abandon the idea) - -7. **Update `production/session-state/active.md`** to clear the spike and return to the current sprint state. - -**No CD gate. No phase gate. No PROCEED/PIVOT/KILL.** Spike results inform decisions; they don't make them. The developer decides whether to add the mechanic/approach to the sprint backlog based on what the spike revealed. - -**Performance spike (special case):** If the game involves demanding rendering — -large open worlds, hundreds of simultaneous physics bodies, heavy particle systems, -complex shaders — run a performance spike before writing gameplay code to confirm -the target hardware can sustain the required framerate. This is distinct from other -spikes in two ways: -- The question is "can the engine render [scene X] at 60fps on [minimum spec hardware]?" - not "does this mechanic feel good?" -- The output is a benchmark number, not a feel verdict -- No gameplay logic is needed — just the maximum intended scene load (terrain, draw - calls, physics objects, particles) running at once -- Build time stays within the ~4-hour cap; the spike is setting up the rendering - load, not the game -- If the answer is NO at this scope, this is an architecture or scope constraint - that affects everything downstream — better to surface it now than during Sprint 8 - ---- +**Read `references/spike-mode.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ### Important Constraints diff --git a/.claude/skills/prototype/references/1-question.md b/.claude/skills/prototype/references/1-question.md new file mode 100644 index 00000000..3fb2e521 --- /dev/null +++ b/.claude/skills/prototype/references/1-question.md @@ -0,0 +1,69 @@ +# /prototype — Phase 1: Define the Question + +> Part of `/prototype`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 1: Define the Question + +Every `AskUserQuestion` call follows `.claude/docs/automation-modes.md` +(collaborative asks always · guided major-only · autonomous logs and proceeds; +`automation_always_ask` categories always prompt). + +**Check for spike mode:** If `--spike` was passed, skip to the **Spike Mode** section +at the bottom of this skill. + +**Check for a carry-forward note:** Glob `prototypes/*/PIVOT-NOTE.md`. If one +exists for this concept (or an earlier version of it), read it and start from its +revised hypothesis instead of forming one from scratch — say which note you used. + +Then, unless `--spike` sent you to Spike Mode, use `AskUserQuestion` to confirm +intent before proceeding — with or without a carry-forward note: + +- **Prompt**: "How would you like to use this prototype session?" +- **Options**: + - `Prototype this concept` — build a throwaway build to validate the core idea is fun before writing GDDs (1–3 days) + - `Skip — concept already proven` — I have enough evidence this works; log it and proceed directly to design + - `Mid-production spike` — I'm already in Production and want to test a specific mechanic or technical question quickly (~4 hours, no phase gate implications) + +**If "Skip — concept already proven":** +Ask (plain text, not a widget): "What evidence do you have that the concept works?" +Record the one-line answer, then stop. Note: "Concept prototype skipped — evidence: +[answer]." Suggest next step: `/map-systems` or `/design-system [mechanic]`. + +**If "Mid-production spike"**: skip to the **Spike Mode** section below. + +**If "Prototype this concept"**: continue with Phase 1 below. + +--- + +**A note on prototype strategy:** The research on successful indie development +is consistent — building 2-3 concept variants and letting the best one win is +far more likely to succeed than iterating one concept until it works. This is +your first prototype, not necessarily your only one. If this prototype produces +a PIVOT verdict, consider whether to refine this concept OR start fresh with a +different angle on the same game idea and prototype that instead. + +**Game jam as a prototype vehicle:** If you're planning a concept prototype anyway, +consider timing it to a game jam (Ludum Dare, GMTK Game Jam, Global Game Jam). Jams +provide a forced timebox (48-72 hours), instant distribution to thousands of players +who rate and review early builds, and a deadline that prevents scope creep by design. +Many shipped games (Celeste, VVVVVV) began as jam prototypes. Not required — but +worth considering if the timing is right. + +Read the concept description from the argument. Before building anything, define +the **falsifiable hypothesis** this prototype must answer: + +> *"If the player [does X], they will feel [Y] — we will know this is true if [measurable signal Z]."* + +Good: "If the player swings on grapple hooks, traversal will feel fluid — we'll know if +players chain 3+ swings without stopping within 2 minutes of picking it up." + +Bad: "Does this feel fun?" ← not testable, not falsifiable. + +**If the concept is too vague to form a hypothesis, stop here.** Ask the user to +narrow the question before proceeding. A prototype without a clear question wastes time. + +Also ask: **"What is the riskiest assumption in this concept?"** That is the first +thing the prototype should test — not the easiest part, the riskiest. + +--- diff --git a/.claude/skills/prototype/references/2-load-context.md b/.claude/skills/prototype/references/2-load-context.md new file mode 100644 index 00000000..23c9de60 --- /dev/null +++ b/.claude/skills/prototype/references/2-load-context.md @@ -0,0 +1,19 @@ +# /prototype — Phase 2: Load Concept Context + +> Part of `/prototype`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 2: Load Concept Context + +Read `design/gdd/game-concept.md` — or `design/game-brief.md`, the one-page brief +that replaces it at `rigor: minimal` — if either exists. Extract: +- Core fantasy (what the player is supposed to feel) +- Core loop (the moment-to-moment action being tested) + +Determine the engine and language in use: read `engine.name` and +`engine.language` from `project.yaml`. For each field, if its key is absent or +empty (including when `project.yaml` has no `engine:` block), fall back to +`CLAUDE.md` and `.claude/docs/technical-preferences.md`. Treat a +`[TO BE CONFIGURED]` value as not set. + +--- diff --git a/.claude/skills/prototype/references/3-choose-path.md b/.claude/skills/prototype/references/3-choose-path.md new file mode 100644 index 00000000..12cade3b --- /dev/null +++ b/.claude/skills/prototype/references/3-choose-path.md @@ -0,0 +1,147 @@ +# /prototype — Phase 3: Choose the Prototype Path + +> Part of `/prototype`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 3: Choose the Prototype Path + +**In this file:** + +- Path: HTML (browser-playable) +- Path: Engine (engine project) +- Path: Paper (rules document + play log) + +Select the prototype path. If `--path [html|engine|paper]` was passed, use that. +Otherwise, use this quick-reference first, then read the full path details below: + +| Genre | Recommended path | Key reason | +|-------|-----------------|------------| +| Platformer / action / fighter | **Engine** | Feel IS the hypothesis; browser latency produces false results | +| Racing / sports | **Engine** | Same — timing and physics feedback are the point | +| Top-down shooter / twin-stick | **Engine** | Aim feel is timing-sensitive | +| Puzzle (logic) | **HTML** or **Paper** | Timing is not the point; logic and clarity are | +| Card game | **Paper** first | Fastest iteration by hand before touching code | +| Narrative / visual novel | **Paper** (Twine / Ink / Yarn Spinner) | Story is the mechanic — test it without code overhead | +| Strategy / 4X / city builder | **Paper** (spreadsheet sim) | Validate economy and progression rules before building | +| Roguelike (systems-heavy) | **Paper** → Engine | Validate that the ruleset is interesting before building | +| Idle / clicker / incremental | **HTML** | Turn-based logic, no feel sensitivity required | +| Rhythm game | **Paper** first (design levels in audio) | Design levels before the engine exists | +| RPG / open world | **Paper** → Engine | Systems complexity: validate rules, then validate feel | +| Horror / atmospheric | **Engine** | Atmosphere requires real rendering | + +**Rule of thumb:** "Does this feel right?" → Engine. "Are these rules interesting?" → Paper. "Is this logic correct?" → HTML or Paper. + +### Path: HTML (browser-playable) + +**Best for:** Puzzle games, card games, turn-based strategy, word games, idle games, +top-down logic games. Anything where timing precision doesn't matter. + +**Reliability:** ~85–90% one-shot. The agent writes a single self-contained HTML +file the user opens in a browser — no install required. + +**Limitation — browser latency lies about game feel.** Browsers introduce +50–133ms of rendering variance. This makes HTML prototypes fundamentally unreliable +for action games, platformers, fighting games, or anything where input timing, +jump arcs, or collision feel are what you're testing. If feel is the hypothesis, +use the Engine path instead. + +**Alternative tools for this path:** PICO-8 (extreme constraints, great for retro +arcade concepts, web-export in one command), Phaser.js (more capable browser game +framework, still no install needed), or Twine (narrative/choice-based games). +These are faster than raw HTML for their respective genres — suggest them if appropriate. + +**Output:** A single `prototype.html` (or PICO-8/Phaser equivalent) the user opens in any browser. + +**Distribution — the HTML path's biggest advantage:** Unlike Engine prototypes, this +build can reach real players globally in minutes. Use this actively: +- **itch.io** — upload the file, share the link, get play counts and written feedback + within hours. Free. The indie community plays rough builds here without expecting + polish. This is genuine external validation at zero cost. +- **Loom + file share** — share via Google Drive/Dropbox, ask someone to record their + screen + audio with Loom while playing. You get a video of real first-impression + reactions and confusion without synchronous scheduling. +- **r/playmygame or r/WebGames** (Reddit) — active communities that specifically + test early builds and give unsolicited honest feedback. +- **Game dev Discord servers** (GMTK, Brackeys, GameDev.tv) — members test each + other's prototypes routinely; an HTML file is the easiest possible ask. + +--- + +### Path: Engine (engine project) + +**Best for:** Action games, platformers, physics-heavy games, anything where +moment-to-moment feel IS the hypothesis. Use this when HTML latency would lie about +the result. + +**Reliability:** ~50–60% one-shot. Expect 2–4 rounds of iteration — this is +normal, not a failure. + +**Limitation — requires engine installed and running.** This path is a +multi-turn collaborative loop: +1. Agent writes the code +2. User runs it in the engine +3. User reports errors or observations +4. Agent fixes and iterates + +**Sunk cost rule:** If the user has been iterating for more than 2 hours without +reaching a playable state, stop. The scope is too large or the question is wrong. +Reframe the hypothesis and simplify aggressively, or switch to Paper path. + +**Output:** A minimal runnable engine project in `prototypes/[name]-concept/`. + +**Lighter alternative — Love2D (Lua):** If the project engine (Godot, Unity, Unreal) +feels too heavy to stand up for a throwaway build, consider Love2D — a minimal 2D +framework that installs in minutes, requires no project scaffolding, and renders +natively with no browser latency. Used by many indie devs for rapid 2D action and +platformer prototypes (Balatro prototyped in Love2D; Nuclear Throne's early builds +used it). It sits between HTML overhead and full engine overhead: heavier than +opening a browser, lighter than setting up a full engine project. Best for 2D +action/platformer feel validation when the project engine is 3D-first or takes +significant time to configure. + +--- + +### Path: Paper (rules document + play log) + +**Best for:** Strategy games, card games, board game-style mechanics, economy +systems, progression loops, any game where the logic can be simulated by hand. +Works for any genre when you need to validate rules, not feel. + +**Reliability:** 100%. No code, no engine, no install. + +**Limitation — cannot validate moment-to-moment feel.** Paper prototypes prove +that the rules are internally consistent and the decisions are interesting. They +cannot tell you whether jumping feels right or whether explosions feel satisfying. + +**Paper playtest observation protocol (run this with 5+ people):** +1. Brief the rules once. Hand them the rule summary sheet. Then step back. +2. Do NOT explain further. Do NOT help. Do NOT clarify. Confusion is data. +3. Watch silently. Note every moment they slow down, re-read, or ask a question. +4. After the session, ask one question only: "What was confusing?" — not "Did you like it?" +5. Use fresh testers for each iteration. The same person cannot give new first-impression data. +6. If 3+ testers hit the same confusion point, that rule is broken — redesign it before re-testing. + +**Output:** A printable rules document + a completed play log showing one simulated session. + +**Narrative tools for this path:** For dialogue-heavy and story-driven games, skip the +generic rules doc — use a dedicated narrative scripting tool instead: +- **Twine** — zero-code hypertext fiction; ideal for branching structure experiments and choice-impact testing +- **Ink** (Inkle) — plain-text scripting language used in *80 Days*, *Heaven's Vault*, and *Overboard*; exports directly to Unity and Godot +- **Yarn Spinner** — dialogue scripting used in *A Short Hike*, *DREDGE*, and *Night in the Woods*; integrates natively with Unity and Godot + +All three let you write and playtest branching dialogue in minutes. Key metric for +narrative prototypes: **time to first emotional beat** — how many exchanges before +the player feels something? If it takes more than 3-4 exchanges, the opening is too slow. + +--- + +Assess which path best fits the hypothesis, then use `AskUserQuestion` with your +recommendation pre-stated: + +- **Prompt**: "Which prototype path would you like to use? (Based on your concept, I'd recommend [path] — [one sentence reason].)" +- **Options**: + - `HTML — browser prototype` — puzzle, card, turn-based, strategy, idle. Opens by double-clicking, no install. 85–90% reliable. **Not suitable for action games** — browser latency lies about feel. + - `Engine — native prototype` — action, platformer, physics, or anything where feel IS the hypothesis. 50–60% one-shot; 2–4 iteration rounds are normal. Requires engine installed. + - `Paper — rules document + play log` — strategy, economy, logic, board-game-style mechanics. 100% reliable. Cannot validate feel. + +--- diff --git a/.claude/skills/prototype/references/4-plan.md b/.claude/skills/prototype/references/4-plan.md new file mode 100644 index 00000000..08b11503 --- /dev/null +++ b/.claude/skills/prototype/references/4-plan.md @@ -0,0 +1,28 @@ +# /prototype — Phase 4: Plan the Prototype + +> Part of `/prototype`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 4: Plan the Prototype + +Define in 3–5 bullet points the minimum viable prototype: + +- What is the falsifiable hypothesis? +- What is the riskiest assumption — and how does this prototype test it first? +- What is the absolute minimum needed to answer the question? +- What is explicitly cut? (menus, save systems, error handling, polish, architecture — all of it) + +**Scope constraint:** A concept prototype tests ONE mechanic — not the whole game. +If scope covers more than one mechanic, cut it down. When in doubt, cut more. + +Present this plan to the user before building. Get confirmation before proceeding. +Name the checkpoint file in that confirmation: "May I record this plan in +`production/session-state/active.md`?" + +Once confirmed, write a session checkpoint to `production/session-state/active.md` +(create `production/session-state/` if it does not exist). Include: concept name, +hypothesis, path chosen, scope bullet points, and current phase ("Phase 5 — +Implement"). This lets the next session resume without starting over if the session +ends mid-build — especially important for multi-day Engine path work. + +--- diff --git a/.claude/skills/prototype/references/5-implement.md b/.claude/skills/prototype/references/5-implement.md new file mode 100644 index 00000000..a6c886e2 --- /dev/null +++ b/.claude/skills/prototype/references/5-implement.md @@ -0,0 +1,96 @@ +# /prototype — Phase 5: Implement + +> Part of `/prototype`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 5: Implement + +Ask: "May I create the prototype directory at `prototypes/[concept-name]-concept/` +and begin implementation?" + +If yes, create the directory. Every file must begin with: + +``` +[comment] PROTOTYPE - NOT FOR PRODUCTION +[comment] Question: [Core question being tested] +[comment] Date: [Current date] +``` + +Write `[comment]` in each file's own comment syntax — `#` in GDScript (`.gd`) and +Python, `//` in C#, C++ and JavaScript, `--` in Lua, `` in HTML and +Markdown. A header in another language's syntax is a parse error, not a label. +Files that cannot hold a comment (JSON, engine-generated scene and project +files) are exempt. + +Standards are intentionally relaxed: + +- Hardcode values freely +- Use placeholder assets (colored rectangles, debug shapes) +- Skip error handling entirely +- Use the simplest approach that works +- Copy code rather than importing from production +- No architecture, no patterns, no abstractions + +**Do not add polish.** No menus, no game over screens, no music, no tutorial text +unless the tutorial IS the mechanic being tested. Every addition beyond the +hypothesis is waste. + +**Playtesting tip:** If you have access to anyone who hasn't seen the game — +friends, family, strangers online — watching them play without explanation gives +far better signal than testing it yourself. Watch silently; don't guide them. +Confusion is data. Ask one question after: "What was confusing?" Not "Did you +like it?" + +**No external testers available?** Use rotation: if you built system A, you're a +naive tester for system B. In a two-person team this works well. Solo developer? +Step away for 2-3 days before playing fresh — you won't have perfect first-impression +signal, but you'll surface the worst blockers. Another option: play your own +prototype as a speedrun (force yourself through it in 5 minutes without stopping +to fix things) — the friction you feel is what strangers will hit. + +**Want more granular UX data?** Ask the tester to **think aloud** as they play — +narrate their thoughts in real time: "I'm pressing space... nothing happened... is +that the jump key?" This surfaces confusion the moment it happens rather than +waiting for a post-play debrief. Best for UI/UX and onboarding clarity. Silent +observation is still better for testing raw feel; think-aloud changes how people +play slightly but gives much richer data about why they're confused. + +**HTML prototype?** itch.io, Reddit (r/playmygame), and Discord (GMTK, Brackeys) +let you reach strangers today at zero cost — see the distribution options in the +HTML path section above. + +**Testing AI, NPC, or complex system behavior before writing the code?** Use the +**Wizard of Oz** technique: one person plays normally while a second person secretly +controls the NPC, enemy, or system behavior in real time — making the decisions a +human would make, not an algorithm. The player believes it's automated. This lets +you validate whether your AI design *feels right* before writing a single line of +pathfinding or decision tree code. When you observe what responses the human +controller naturally produces, you learn exactly what the AI needs to do. + +### Engine path: multi-turn loop + +After writing the initial code: + +> "The prototype files are written. Run the project in your engine now. +> If there are errors, paste them here and I'll fix them. If it runs, +> describe what you see and whether it feels like it's answering the question." + +Iterate until the prototype is playable. Each loop: +1. User runs → reports errors or observations +2. Agent fixes errors or adjusts the mechanic +3. Repeat until playable or sunk cost rule triggers + +### HTML path: single output + +Write a single `prototype.html` to `prototypes/[concept-name]-concept/`. Include +all styles, logic, and assets inline. The file must be openable by double-clicking +with no server required. + +### Paper path: document + log + +Write `prototypes/[concept-name]-concept/rules.md` (the game rules) and +`prototypes/[concept-name]-concept/play-log.md` (a simulated session walking +through one complete play cycle step by step with dice rolls, decisions, and +outcomes narrated). + +--- diff --git a/.claude/skills/prototype/references/6-debrief.md b/.claude/skills/prototype/references/6-debrief.md new file mode 100644 index 00000000..a1235045 --- /dev/null +++ b/.claude/skills/prototype/references/6-debrief.md @@ -0,0 +1,59 @@ +# /prototype — Phase 6: Playtest Debrief + +> Part of `/prototype`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 6: Playtest Debrief + +The prototype is built. Now hand it to the user and capture what they actually +experienced. Do NOT skip to report generation — the report is only as good as the +observations you collect here. + +**For HTML path:** Say exactly this: +> "The prototype is ready. Open `prototypes/[name]-concept/prototype.html` in your +> browser and play it. Take as long as you need. Don't rush through it — try to +> approach it the way a new player would. Come back here when you're done." + +**For Engine path:** The multi-turn iteration loop already captured errors and +behavior. Now ask for the overall assessment: +> "Now that it's running — play through it a few times as if you're the player, +> not the developer. Come back when you have a feel for it." + +**For Paper path:** Say exactly this: +> "Read through `prototypes/[name]-concept/rules.md` and walk through the +> `play-log.md` as if you're playing it for the first time. If you have someone +> nearby, try running the rules with them. Come back when you've seen at least one +> full play cycle." + +**If nobody can play it this session**, do not ask for a verdict and do not infer +one from how the build looks: the recommendation is **NOT ASSESSED — built, not +played**. Write the report with that verdict (Phase 7, asking first) and name the +next step — play it, then re-run this debrief. + +Once the user returns, ask these questions **one at a time** — wait for each answer +before asking the next: + +1. **Hypothesis check:** + > "The hypothesis was: [restate the hypothesis from Phase 1]. Did it hold up — + > CONFIRMED, PARTIALLY CONFIRMED, or REFUTED? Tell me what you saw." + +2. **Best moment:** + > "What was the moment — if any — where it felt like it was working? Be specific." + +3. **Worst moment:** + > "What was the most frustrating, confusing, or broken moment? Be specific — + > not 'it felt slow' but 'the jump took about half a second to respond and it + > felt like I was fighting the controls'." + +4. **Surprise:** + > "Did anything happen that you didn't expect — good or bad?" + +5. **Verdict:** + > "PROCEED, PIVOT, or KILL — and one sentence why." + +Collect all answers before moving to report generation. If any answer is vague +("it felt fine", "pretty good"), ask a follow-up: "Can you be more specific? +What exactly felt fine about it?" Precise observations make the report useful. +Vague ones make it useless. + +--- diff --git a/.claude/skills/prototype/references/7-report.md b/.claude/skills/prototype/references/7-report.md new file mode 100644 index 00000000..65846162 --- /dev/null +++ b/.claude/skills/prototype/references/7-report.md @@ -0,0 +1,21 @@ +# /prototype — Phase 7: Generate Prototype Report + +> Part of `/prototype`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 7: Generate Prototype Report + +Read `.claude/docs/templates/prototype-report.md` to get the report structure. +Fill in every section based on what was observed during this session. Replace all +placeholder text with real observations — no generic filler. + +Ask: "May I write this report to `prototypes/[concept-name]-concept/REPORT.md` +and add its row to `prototypes/index.md`?" + +If yes, write the file. Then update `prototypes/index.md` (create if it does not +exist) — append one row to the concept prototype table: concept name, date, path +used, verdict (PROCEED/PIVOT/KILL, or NOT ASSESSED when nobody has played it), and a link to the REPORT.md. If a PIVOT chain +exists (prior PIVOT-NOTE.md in a related concept folder), note the chain. This file +is the project's complete history of what was tried and what was learned. + +--- diff --git a/.claude/skills/prototype/references/8-cd-review.md b/.claude/skills/prototype/references/8-cd-review.md new file mode 100644 index 00000000..acc9500f --- /dev/null +++ b/.claude/skills/prototype/references/8-cd-review.md @@ -0,0 +1,42 @@ +# /prototype — Phase 8: Creative Director Review + +> Part of `/prototype`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 8: Creative Director Review + +**Review mode check:** +- `solo` → skip. Note: "CD-PLAYTEST skipped — Solo mode." +- `lean` → skip. Note: "CD-PLAYTEST skipped — Lean mode." +- `full` → spawn `creative-director` via `Agent` using gate **CD-PLAYTEST** if + `design/gdd/game-concept.md` exists with game pillars defined, or + `design/game-brief.md` exists (the `rigor: minimal` brief has no pillars — its + pitch and "what they feel" line stand in). If neither is available, note: + "CD-PLAYTEST skipped — game pillars not yet defined at concept prototype stage." + +Pass: the full REPORT.md content, the original hypothesis, and game pillars / +core fantasy from `design/gdd/game-concept.md` (or the brief's pitch and "what +they feel" line from `design/game-brief.md`). + +The creative director evaluates the result against the game's creative vision and +returns one of the gate's verdicts — APPROVE, CONCERNS or REJECT — or NOT +ASSESSED when it could not judge. Apply it to the recommendation: + +- **APPROVE** → the recommendation stands. +- **CONCERNS** → show the concerns alongside the recommendation, then use + `AskUserQuestion`: `Revise the recommendation` / `Accept with noted concerns` / + `Discuss further`. The user decides; the director does not. +- **REJECT** (the core fantasy is not present) → a PROCEED recommendation cannot + stand. Use `AskUserQuestion` to ask the user to choose `PIVOT` or `KILL`, and run + Phase 9 for that choice. A PIVOT or KILL recommendation stands. +- **NOT ASSESSED** (the director lacked an input — `.claude/docs/director-gates.md`) + → not an approval. Name what was missing; supply it and re-run the gate, or + record the review as NOT ASSESSED and let the user decide whether the + recommendation stands unreviewed. + +When the director returned CONCERNS, REJECT or NOT ASSESSED, ask "May I update +`prototypes/[concept-name]-concept/REPORT.md` and its `prototypes/index.md` +row?", then record the director's verdict and reason in REPORT.md, and the final +recommendation in both if it changed. + +--- diff --git a/.claude/skills/prototype/references/9-summary.md b/.claude/skills/prototype/references/9-summary.md new file mode 100644 index 00000000..8b03e44c --- /dev/null +++ b/.claude/skills/prototype/references/9-summary.md @@ -0,0 +1,85 @@ +# /prototype — Phase 9: Summary and Next Steps + +> Part of `/prototype`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 9: Summary and Next Steps + +Output a summary: the hypothesis, the result, and the final recommendation. +Link to `prototypes/[concept-name]-concept/REPORT.md`. + +**If PROCEED:** +Your concept prototype validated the core idea. Now design it properly, informed by +what you just learned. + +At `workflow: minimal`: `/create-stories` (from the brief), then `/dev-story` +on the first story — the rest of this list is the `standard`/`full` path. + +Recommended path (in order, `standard`/`full`): +1. `/design-review design/gdd/game-concept.md` — validate the concept doc against what the prototype revealed +2. `/gate-check` — confirm readiness to advance to Systems Design +3. `/art-bible` — define visual identity (optional but worth doing before GDDs) +4. `/map-systems` — decompose the concept into all game systems +5. `/design-system [mechanic]` — GDD for each MVP system; use prototype learnings + in the Tuning Knobs and Formulas sections +6. `/review-all-gdds` — cross-system consistency check + +**Note:** If you used the HTML path and feel is still uncertain, consider running +a quick engine path prototype targeting feel before writing GDDs. + +**If PIVOT:** + +Before routing to the next prototype, capture the carry-forward note. Ask these +two questions (plain text, one at a time): + +1. "What specifically worked in this prototype that we should preserve in the next version?" +2. "What is the single most important thing to change?" + +Ask: "May I write this to `prototypes/[concept-name]-concept/PIVOT-NOTE.md`?" + +If yes, write the file with: original hypothesis, what to keep, what to change, and +the revised hypothesis for the next prototype. The next `/prototype` run picks it +up at the start of Phase 1. + +- Run `/prototype [revised-concept]` to test the adjusted direction +- Or `/brainstorm [hint]` if the concept needs more fundamental rethinking + +**If KILL:** + +Before moving on, run this check to confirm the verdict is sound and not temporary frustration: + +- [ ] Core mechanic still unclear to testers after 2+ playtests? +- [ ] No "fun moment" (smile, laugh, or retry by choice) observed in any session? +- [ ] 3+ PIVOT iterations on the same concept with no clear improvement? +- [ ] Concept only works when heavily explained or when the dev guides the player? +- [ ] Building this feels like obligation, not excitement? + +If 2+ boxes apply → KILL verdict is sound. If 0–1 apply → consider one more focused PIVOT before killing. + +**Document the kill in `prototypes/GRAVEYARD.md`** (create if it doesn't exist). +Ask: "May I append this concept to `prototypes/GRAVEYARD.md`?" If yes, add one entry: + +``` +## [Concept Name] — YYYY-MM-DD +- **Kill reason:** [specific blocker — not "it was boring" but "players never understood the core action"] +- **What worked:** [2-3 things worth carrying forward to future concepts] +- **What failed:** [the specific mechanic, design decision, or scope issue] +- **Next time:** [one explicit action to try differently on a similar concept] +``` + +This file exists so the same mistake doesn't get made twice on the next concept. + +- Run `/brainstorm open` or `/brainstorm [new-hint]` to explore a different concept +- The prototype report is the deliverable — no further action needed + +**If NOT ASSESSED (nobody has played it):** + +There is no fun evidence yet, so PROCEED, PIVOT and KILL are all unreachable — +report NOT ASSESSED and stop here rather than guess. + +- Play it, then run `/prototype [same concept]` again +- The report and the concept index row read NOT ASSESSED until a playtest happens + +--- + +--- diff --git a/.claude/skills/prototype/references/spike-mode.md b/.claude/skills/prototype/references/spike-mode.md new file mode 100644 index 00000000..c8135df6 --- /dev/null +++ b/.claude/skills/prototype/references/spike-mode.md @@ -0,0 +1,55 @@ +# /prototype — Spike Mode + +> Part of `/prototype`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +**Triggered by:** `--spike` flag OR "Mid-production spike" entry choice in Phase 1. + +**Purpose:** Test a specific technical or design question mid-production, without +the overhead of a full concept prototype workflow. No GDD prerequisites. No phase +gate implications. Hard cap: ~4 hours. + +**When to use:** +- You're in Production and want to test whether a new mechanic should be added +- You're unsure if a technical approach will work before building it properly +- A design change is being considered and you want a quick before/after comparison +- A GDD system is proving harder than expected and you want to prototype the hard part +- You need to confirm target hardware can sustain the required framerate before writing gameplay code (**performance spike** — see below) + +**Spike Mode workflow (replaces Phases 1–9):** + +1. **Define the spike question** (plain text, not a widget): "What specific question does this spike answer? Give me one sentence: 'Can we [do X] using [approach Y]?'" + +2. **Choose path** — same AskUserQuestion widget as Phase 3 (HTML / Engine / Paper). + +3. **Scope** — maximum 2-3 bullet points. One mechanic, one technical question, nothing else. + +4. **Build** — first ask "May I create `prototypes/[concept-name]-spike-[date]/` and build the spike there?" Same relaxed standards and header as the concept prototype. Hard cap: 4 hours. If not demonstrable in 4 hours, the question is too large. Split it. + +5. **Observe and decide** — no formal playtest debrief. Ask: "Did the spike answer the question? YES or NO, and why in one sentence." + +6. **Write a spike note** (not a full report) to `prototypes/[concept-name]-spike-[date]/SPIKE-NOTE.md` — first ask once for this step and the next, naming both files: "May I write `prototypes/[concept-name]-spike-[date]/SPIKE-NOTE.md` and clear the spike from `production/session-state/active.md`?" The note holds: + - Question tested + - Result (YES it works / NO it doesn't / PARTIAL — needs more investigation) + - What to do next (add to current sprint — at `workflow: minimal`, the brief's build order — / investigate further / abandon the idea) + +7. **Update `production/session-state/active.md`** to clear the spike and return to the current sprint state (at `workflow: minimal`, the story in progress). + +**No CD gate. No phase gate. No PROCEED/PIVOT/KILL.** Spike results inform decisions; they don't make them. The developer decides whether to add the mechanic/approach to the sprint backlog (at `workflow: minimal`, to the brief's build order) based on what the spike revealed. + +**Performance spike (special case):** If the game involves demanding rendering — +large open worlds, hundreds of simultaneous physics bodies, heavy particle systems, +complex shaders — run a performance spike before writing gameplay code to confirm +the target hardware can sustain the required framerate. This is distinct from other +spikes in two ways: +- The question is "can the engine render [scene X] at 60fps on [minimum spec hardware]?" + not "does this mechanic feel good?" +- The output is a benchmark number, not a feel verdict +- No gameplay logic is needed — just the maximum intended scene load (terrain, draw + calls, physics objects, particles) running at once +- Build time stays within the ~4-hour cap; the spike is setting up the rendering + load, not the game +- If the answer is NO at this scope, this is an architecture or scope constraint + that affects everything downstream — better to surface it now than during Sprint 8 + +--- diff --git a/.claude/skills/regression-suite/SKILL.md b/.claude/skills/regression-suite/SKILL.md index 7cd016ae..63ed888d 100644 --- a/.claude/skills/regression-suite/SKILL.md +++ b/.claude/skills/regression-suite/SKILL.md @@ -303,6 +303,8 @@ After writing (if approved): - If coverage drift detected: "Regression suite may be drifting. Consider running `/regression-suite audit` at the next sprint boundary." +At `workflow: minimal`, which has no sprints, say "next story" for "next sprint" in the three lines above. + Verdict, first match wins: - **NOT ASSESSED** — the Section 1 stop at `qa.level: minimal`: "Regression suite not generated at qa.level minimal". Tests are not required at this diff --git a/.claude/skills/release-checklist/SKILL.md b/.claude/skills/release-checklist/SKILL.md index d0f7c63f..8fa713a0 100644 --- a/.claude/skills/release-checklist/SKILL.md +++ b/.claude/skills/release-checklist/SKILL.md @@ -16,6 +16,8 @@ every file write follows `.claude/docs/automation-modes.md` Resolved above — use as-is. No block → defaults in `.claude/docs/config-resolution.md`. +# Release Checklist + **Scope this checklist to the project.** Emitting every item for every platform trains the reader to skip the list, which defeats the gate: diff --git a/.claude/skills/retrospective/SKILL.md b/.claude/skills/retrospective/SKILL.md index bf485ade..213445c1 100644 --- a/.claude/skills/retrospective/SKILL.md +++ b/.claude/skills/retrospective/SKILL.md @@ -9,6 +9,8 @@ model: sonnet !`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys automation,workflow,qa.level` +# Retrospective + Every `AskUserQuestion` call follows `.claude/docs/automation-modes.md` @@ -33,11 +35,10 @@ not a filled-in report.** Check first, and stop if the check fails. **A verdict of `NOT ASSESSED` is a success.** It is the correct, useful answer to "what does the data say?" when there is no data. The failure mode this prevents is -specific and has been observed in practice: report templates whose verdict -enum had no "could not run" state produced **false clean passes** — an asset audit -returning COMPLIANT on a project with no assets and no standards, and a -performance profile reporting ">99% headroom against a 16.67ms budget" with zero -profiler data and no budget ever set. +specific: a report whose verdict enum has no "could not run" state produces +**false clean passes** — an asset audit returning COMPLIANT on a project with no +assets and no standards, or a performance profile reporting ">99% headroom against +a 16.67ms budget" with zero profiler data and no budget ever set. **Absence of evidence is never evidence of absence.** A scan that finds no matches because there are no files to scan has not verified anything. Say which of @@ -262,7 +263,11 @@ If no, stop here. Verdict: **BLOCKED** — user declined write. ## Phase 6: Next Steps -Use `AskUserQuestion`: +At `workflow: minimal` (resolved above), which has no sprints, skip this question: +point to the retrospective file and say its action items go into the brief's build +order. + +Otherwise, use `AskUserQuestion`: - Prompt: "Retrospective complete. The action items and velocity data are ready. Would you like to start sprint planning now with this data pre-loaded?" - Options: - `[A] Yes — open sprint planning with retro action items and velocity delta pre-populated` diff --git a/.claude/skills/review-all-gdds/SKILL.md b/.claude/skills/review-all-gdds/SKILL.md index 9ffa0e02..4769a5f6 100644 --- a/.claude/skills/review-all-gdds/SKILL.md +++ b/.claude/skills/review-all-gdds/SKILL.md @@ -9,8 +9,6 @@ model: opus !`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys automation,workflow,system_overrides` - - # Review All GDDs This skill reads every system GDD simultaneously and performs two complementary @@ -55,108 +53,7 @@ surfaced as advisory only. At `minimal`, this skill is not applicable (no GDDs). ## Phase 1: Load Everything -### Phase 1a — L0: Summary Scan (fast, low tokens) - -Before reading any full document, use Grep to extract `## Summary` sections -from all GDD files: - -``` -Grep pattern="## Summary" glob="design/gdd/*.md" output_mode="content" -A 5 -``` - -**Fail open on a missing Summary.** Establish the denominator: glob -`design/gdd/*.md` and count **N**. A scan matching fewer than N means those GDDs -predate `## Summary` — never treat an absent Summary as a system out of scope. -A zero-match scan means "no GDD carries a Summary yet", not "nothing to review". -This review is holistic and loads its in-scope GDDs regardless (see Phase 1c); -the Summary scan only builds the manifest and narrows `since-last-review`, it -never shrinks the review set. - -Display a manifest to the user: -``` -Found [N] GDDs. Summaries: - • combat.md — [summary text] - • inventory.md — [summary text] - ... -``` - -For `since-last-review` mode, compute the scope deterministically instead of -reasoning through git history: - -``` -Bash: bash .claude/scripts/review-scope.sh -``` - -It prints `PRIOR_REVIEW:`, a `CHANGED:` list, and a `DEPS ...:` list of each -changed GDD's declared dependencies. Use those lists as the scope — the -dependency lines are already the "Key deps" expansion, so no second pass is -needed. If `PRIOR_REVIEW: NONE`, a full review is required; fall back to `full` -mode. - -Show the user which GDDs are in scope based on summaries before doing any full -reads. Only proceed to L1 for the `CHANGED` set plus the GDDs named on the -`DEPS` lines. - -### Phase 1b — Registry Pre-Load (fast baseline) - -Before full-reading any GDD, check for the entity registry: - -``` -Read path="design/registry/entities.yaml" -``` - -If the registry exists and has entries, use it as a **pre-built conflict -baseline**: known entities, items, formulas, and constants with their -authoritative values and source GDDs. In Phase 2, grep GDDs for registered -names first — this is faster than reading all GDDs in full before knowing -what to look for. - -If the registry is empty or absent: proceed without it. Note in the report: -"Entity registry is empty — consistency checks rely on full GDD reads only. -Run `/consistency-check` after this review to populate the registry." - -### Phase 1c — L1/L2: Section Load - -Read whole (small, and every part is used): - -1. `design/gdd/game-concept.md` — game vision, core loop, MVP definition (or - `design/game-brief.md`, the one-page brief that replaces it at `rigor: minimal` — - pitch, core loop, MVP list) -2. `design/gdd/game-pillars.md` if it exists — design pillars and anti-pillars -3. `design/gdd/systems-index.md` — authoritative system list, layers, dependencies, status - -Then, for **every in-scope system GDD**, load the sections this review actually -consumes — **not the whole file**: - -``` -Grep pattern="^## (Dependencies|Detailed Rules|Detailed Design|Formulas|Tuning Knobs|Acceptance Criteria|Player Fantasy)" glob="design/gdd/*.md" output_mode="content" -A 40 -``` - -That list is not a guess — it is exactly the union the Parallel Execution -contract below already enumerates: Phase 2 needs Dependencies, Detailed -Design/Rules, Formulas, Tuning Knobs and Acceptance Criteria; Phase 3 needs -Player Fantasy and progression/reward structure. Overview is narrative restated -by the Summary this skill already scanned in Phase 1a, and Edge Cases feeds no -checklist item here (`/design-review` owns per-GDD completeness). Loading them -put content in three context windows — this one and both sub-agents' — that no -checklist item ever read. - -Accept **either** `## Detailed Rules` or `## Detailed Design`; the design standard -and the GDD template disagree on the name and they denote the same section. - -**Escalate to a full read of one GDD** when a scanned section cross-references -material outside itself, or when a GDD matched **zero** sections — that GDD -predates the template, and a zero-match there means "unstructured", not "empty". -Never let a zero-match silently drop a system: the scan narrows the *read*, it -never shrinks the *review set*. - -Report: "Loaded [N] system GDDs covering [M] systems. Pillars: [list]. Anti-pillars: [list]." - -If fewer than 2 system GDDs exist (count the files present; an empty one is handled under NOT ASSESSED in Phase 5, not here), stop: -> "Cross-GDD review requires at least 2 system GDDs. Write more GDDs first, -> then re-run `/review-all-gdds`." - ---- +**Read `references/1-load.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ### Parallel Execution @@ -176,7 +73,7 @@ consistency and design-theory review is its domain. Dependencies, Detailed Design/Rules, Formulas, Tuning Knobs and Acceptance Criteria; Phase 3 (design theory) needs Player Fantasy, progression/reward structure and the game pillars. -- The full TR registry contents if loaded in Phase 1b (paste the registry text, not just a file path) +- The full entity registry contents (`design/registry/entities.yaml`) if loaded in Phase 1b (paste the registry text, not just a file path) - The specific checklist items assigned to that agent's phase (Phase 2 gets 2a–2f; Phase 3 gets 3a–3g) - The engine name and version — `engine.name` and `engine.version` from `project.yaml`, resolving each field independently (if its key is absent or empty, use `.claude/docs/technical-preferences.md`) — plus `docs/engine-reference/[engine]/VERSION.md` @@ -186,569 +83,27 @@ Do not rely on the subagent to re-read these files — it has its own context wi ## Phase 2: Cross-GDD Consistency -Work through every pair and group of GDDs to find contradictions and gaps. - -### 2a: Dependency Bidirectionality - -For every GDD's Dependencies section, check that every listed dependency is -reciprocal: -- If GDD-A lists "depends on GDD-B", check that GDD-B lists GDD-A as a dependent -- If GDD-A lists "depended on by GDD-C", check that GDD-C lists GDD-A as a dependency -- Flag any one-directional dependency as a consistency issue - -``` -⚠️ Dependency Asymmetry -[system-a].md lists: Depends On → [system-b].md -[system-b].md does NOT list [system-a].md as a dependent -→ One of these documents has a stale dependency section -``` - -### 2b: Rule Contradictions - -For each game rule, mechanic, or constraint defined in any GDD, check whether -any other GDD defines a contradicting rule for the same situation: - -Categories to scan: -- **Floor/ceiling rules**: Does any GDD define a minimum value for an output? Does any other say a different system can bypass that floor? These contradict. -- **Resource ownership**: If two GDDs both define how a shared resource accumulates or depletes, do they agree? -- **State transitions**: If GDD-A describes what happens when a character dies, - does GDD-B's description of the same event agree? -- **Timing**: If GDD-A says "X happens on the same frame", does GDD-B assume - it happens asynchronously? -- **Stacking rules**: If GDD-A says status effects stack, does GDD-B assume - they don't? - -``` -🔴 Rule Contradiction -[system-a].md: "Minimum [output] after reduction is [floor_value]" -[system-b].md: "[mechanic] bypasses [system-a]'s rules and can reduce [output] to 0" -→ These rules directly contradict. Which GDD is authoritative? -``` - -### 2c: Stale References - -**Start from the `## Cross-References` table where a GDD has one.** That table is -the document's own declaration of what it depends on — `templates/game-design-document.md` -tells authors it is machine-checked here, and `/design-system` requires it -whenever Dependencies names another GDD. For each row, confirm the `Target GDD` -exists and the `Specific Element Referenced` is still present in it under that -name, with the declared `Nature` still accurate. - -A table that is absent, or still holding the template's bracketed examples, is -itself reportable: say the GDD declares no cross-references and that the prose -scan below was the only check applied. Do not treat an absent table as "no -dependencies" — it far more often means the section was never authored. - -**Then scan the prose regardless**, table or no table: a declared table catches -what the author remembered, and the scan below catches what they did not. - -For every cross-document reference (GDD-A mentions a mechanic, value, or -system name from GDD-B), verify the referenced element still exists in GDD-B -with the same name and behaviour: - -- If GDD-A says "combo multiplier from the combat system feeds into score", check - that the combat GDD actually defines a combo multiplier that outputs to score -- If GDD-A references "the progression curve defined in [system].md", check that - [system].md actually has that curve, not a different progression model -- If GDD-A was written before GDD-B and assumed a mechanic that GDD-B later - designed differently, flag GDD-A as containing a stale reference. Severity: a - reference to a mechanic or formula that **does not exist** is **Blocking** — the - architecture would inherit a rule nobody defined; one that exists but was - designed differently is a **Warning**, unless the difference changes a rule the - referencing GDD depends on (then Blocking) -- If the **target GDD is not written yet** (no file in `design/gdd/`): when - `systems-index.md` lists that system (e.g. `Status: Not Started`), it is a - **Warning** — a dependency on planned work, to re-check when that GDD is - written; when neither a GDD nor a systems-index entry exists for it, it is - **Blocking** — nothing will ever define it - -``` -🔴 Stale Reference -inventory.md (written first): "Item weight uses the encumbrance formula - from movement.md" -movement.md (written later): Defines no encumbrance formula — uses a flat - carry limit instead -→ inventory.md references a formula that doesn't exist — Blocking -``` - -### 2d: Data and Tuning Knob Ownership Conflicts - -Two GDDs should not both claim to own the same data or tuning knob. Scan all -Tuning Knobs sections across all GDDs and flag duplicates: - -``` -⚠️ Ownership Conflict -[system-a].md Tuning Knobs: "[multiplier_name] — controls [output] scaling" -[system-b].md Tuning Knobs: "[multiplier_name] — scales [output] with [factor]" -→ Two GDDs define multipliers on the same output. Which owns the final value? - This will produce either a double-application bug or a design conflict. -``` - -### 2e: Formula Compatibility - -For GDDs whose formulas are connected (output of one feeds input of another), -check that the output range of the upstream formula is within the expected -input range of the downstream formula: - -- If [system-a].md outputs values between [min]–[max], and [system-b].md is - designed to receive values between [min2]–[max2], is the mismatch intentional? -- If an economy GDD expects resource acquisition in range X, and the - progression GDD generates it at range Y, the economy will be trivial or - inaccessible — is that intended? - -Flag incompatibilities as CONCERNS (design judgment needed, not necessarily wrong): - -``` -⚠️ Formula Range Mismatch -[system-a].md: Max [output] = [value_a] (at max [condition]) -[system-b].md: Base [input] = [value_b], max [input] = [value_c] -→ Late-[stage] [scenario] can resolve in a single [event]. - Is this intentional? If not, either [system-a]'s ceiling or [system-b]'s ceiling needs adjustment. -``` - -### 2f: Acceptance Criteria Cross-Check - -Scan Acceptance Criteria sections across all GDDs for contradictions: - -- GDD-A criteria: "Player cannot die from a single hit" -- GDD-B criteria: "Boss attack deals 150% of player max health" -These acceptance criteria cannot both pass simultaneously. - ---- +**Read `references/2-consistency.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 3: Game Design Holism -Review all GDDs together through the lens of game design theory and player -psychology. These are issues that individual GDD reviews cannot catch because -they require seeing all systems at once. - -### 3a: Progression Loop Competition - -A game should have one dominant progression loop that players feel is "the -point" of the game, with supporting loops that feed into it. When multiple -systems compete equally as the primary progression driver, players don't know -what the game is about. - -Scan all GDDs for systems that: -- Award the player's primary resource (XP, levels, prestige, unlocks) -- Define themselves as the "core" or "main" loop -- Have comparable depth and time investment to other systems doing the same - -``` -⚠️ Competing Progression Loops -combat.md: Awards XP, unlocks abilities, is described as "the core loop" -crafting.md: Awards XP, unlocks recipes, is described as "the primary activity" -exploration.md: Awards XP, unlocks map areas, described as "the main driver" -→ Three systems all claim to be the primary progression loop and all award - the same primary currency. Players will optimise one and ignore the others. - Consider: one primary loop with the others as support systems. -``` - -### 3b: Player Attention Budget - -Count how many systems require active player attention simultaneously during -a typical session. Each actively-managed system costs attention: - -- Active = player must make decisions about this system regularly during play -- Passive = system runs automatically, player sees results but doesn't manage it - -More than 3-4 simultaneously active systems creates cognitive overload for most -players. Present the count and flag if it exceeds 4 concurrent active systems: - -``` -⚠️ Cognitive Load Risk -Simultaneously active systems during [core loop moment]: - 1. [system-a].md — [decision type] (active) - 2. [system-b].md — [resource management] (active) - 3. [system-c].md — [tracking] (active) - 4. [system-d].md — [item/action use] (active) - 5. [system-e].md — [cooldown/timer management] (active) - 6. [system-f].md — [coordination decisions] (active) -→ 6 simultaneously active systems during the core loop. - Research suggests 3-4 is the comfortable limit for most players. - Consider: which of these can be made passive or simplified? -``` - -### 3c: Dominant Strategy Detection - -A dominant strategy makes other strategies irrelevant — players discover it, -use it exclusively, and find the rest of the game boring. Look for: - -- **Resource monopolies**: One strategy generates a resource significantly - faster than all others -- **Risk-free power**: A strategy that is both high-reward and low-risk - (if high-risk strategies exist, they need proportionally higher reward) -- **No trade-offs**: An option that is superior in all dimensions to all others -- **Obvious optimal path**: If any progression choice is "clearly correct", - the others aren't real choices - -``` -⚠️ Potential Dominant Strategy -combat.md: Ranged attacks deal 80% of melee damage with no risk -combat.md: Melee attacks deal 100% damage but require close range -→ Unless melee has a significant compensating advantage (AOE, stagger, - resource regeneration), ranged is dominant — higher safety, only 20% less - damage. Consider what melee offers that ranged cannot. -``` - -### 3d: Economic Loop Analysis - -Identify all resources across all GDDs (gold, XP, crafting materials, stamina, -health, mana, etc.). For each resource, map its **sources** (how players gain -it) and **sinks** (how players spend it). - -Flag dangerous economic conditions: - -| Condition | Sign | Risk | -|-----------|------|------| -| **Infinite source, no sink** | Resource accumulates indefinitely | Late game becomes trivially easy | -| **Sink, no source** | Resource drains to zero | System becomes unavailable | -| **Source >> Sink** | Surplus accumulates | Resource becomes meaningless | -| **Sink >> Source** | Constant scarcity | Frustration and gatekeeping | -| **Positive feedback loop** | More resource → easier to earn more | Runaway leader, snowball | -| **No catch-up** | Falling behind accelerates deficit | Unrecoverable states | - -``` -🔴 Economic Imbalance: Unbounded Positive Feedback -gold economy: - Sources: monster drops (scales with player power), merchant selling (unlimited) - Sinks: equipment purchase (one-time), ability upgrades (finite count) -→ After equipment and abilities are purchased, gold has no sink. - Infinite surplus. Gold becomes meaningless mid-game. - Add ongoing gold sinks (upkeep, consumables, cosmetics, gambling). -``` - -### 3e: Difficulty Curve Consistency - -When multiple systems scale with player progression, they must scale in -compatible directions and at compatible rates. Mismatched scaling curves -create unintended difficulty spikes or trivialisations. - -For each system that scales over time, extract: -- What scales (enemy health, player damage, resource cost, area size) -- How it scales (linear, exponential, stepped) -- When it scales (level, time, area) - -Compare all scaling curves. Flag mismatches: - -``` -⚠️ Difficulty Curve Mismatch -combat.md: Enemy health scales exponentially with area (×2 per area) -progression.md: Player damage scales linearly with level (+10% per level) -→ By area 5, enemies have 32× base health; player deals ~1.5× base damage. - The gap widens indefinitely. Late areas will become inaccessibly difficult - unless the curves are reconciled. -``` - -### 3f: Pillar Alignment - -Every system should clearly serve at least one design pillar. A system that -serves no pillar is "scope creep by design" — it's in the game but not in -service of what the game is trying to be. - -For each GDD system, check its Player Fantasy section against the design pillars. -Flag any system whose stated fantasy doesn't map to any pillar: - -``` -⚠️ Pillar Drift -fishing-system.md: Player Fantasy — "peaceful, meditative activity" -Pillars: "Brutal Combat", "Tense Survival", "Emergent Stories" -→ The fishing system serves none of the three pillars. Either add a pillar - that covers it, redesign it to serve an existing pillar, or cut it. -``` - -Also check anti-pillars — flag any system that does what an anti-pillar -explicitly says the game will NOT do: - -``` -🔴 Anti-Pillar Violation -Anti-Pillar: "We will NOT have linear story progression — player defines their path" -main-quest.md: Defines a 12-chapter linear story with mandatory sequence -→ This system directly violates the defined anti-pillar. -``` - -### 3g: Player Fantasy Coherence - -The player fantasies across all systems should be compatible — they should -reinforce a consistent identity for what the player IS in this game. Conflicting -player fantasies create identity confusion. - -``` -⚠️ Player Fantasy Conflict -combat.md: "You are a ruthless, precise warrior — every kill is earned" -dialogue.md: "You are a charismatic diplomat — violence is always avoidable" -exploration.md: "You are a reckless adventurer — diving in without a plan" -→ Three systems present incompatible identities. Players will feel the game - doesn't know what it wants them to be. Consider: do these fantasies serve - the same core identity from different angles, or do they genuinely conflict? -``` - ---- +**Read `references/3-design-holism.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 4: Cross-System Scenario Walkthrough -Walk through the game from the player's perspective to find problems that only -appear at the interaction boundary between multiple systems — things static -analysis of individual GDDs cannot surface. - -### 4a: Identify Key Multi-System Moments - -Scan all GDDs and identify the 3–5 most important player-facing moments where -multiple systems activate simultaneously. Look specifically for: - -- **Combat + Economy overlap**: killing enemies that drop resources, spending - resources during combat, death/respawn interacting with economy state -- **Progression + Difficulty overlap**: level-up triggering mid-fight, ability - unlocks changing combat viability, difficulty scaling at progression milestones -- **Narrative + Gameplay overlap**: dialogue choices locking/unlocking mechanics, - story beats interrupting resource loops, quest completion triggering system - state changes -- **3+ system chains**: any player action that triggers System A, which feeds - into System B, which triggers System C (these are highest-risk interaction paths) - -List each identified scenario with a one-line description before proceeding. - -### 4b: Walk Through Each Scenario - -For each scenario, step through the sequence explicitly: - -1. **Trigger** — what player action or game event starts this? -2. **Activation order** — which systems activate, in what sequence? -3. **Data flow** — what does each system output, and is that output a valid - input for the next system in the chain? -4. **Player experience** — what does the player see, hear, or feel at each step? -5. **Failure modes** — are there any of the following? - - **Race conditions**: two systems trying to modify the same state simultaneously - - **Feedback loops**: System A amplifies System B which re-amplifies System A - with no cap or dampener - - **Broken state transitions**: a system assumes a state that a previous - system may have changed (e.g., "player is alive" assumption after a combat - step that could have caused death) - - **Contradictory messaging**: player receives conflicting feedback from two - systems reacting to the same event (e.g., "success" sound + "failure" UI) - - **Compounding difficulty spikes**: two systems both scaling up at the same - progression point, multiplying the intended difficulty increase - - **Reward conflicts**: two systems both reacting to the same trigger with - rewards that together exceed the intended value (double-dipping) - - **Undefined behavior**: the GDDs don't specify what happens in this combined - state (neither system's rules cover it) - -``` -Example walkthrough: -Scenario: Player kills elite enemy at level-up threshold during active quest - -Trigger: Player lands killing blow on elite enemy -→ combat.md: awards kill XP (100 pts) -→ progression.md: XP total crosses level threshold → triggers level-up - Output: new level, stat increases, ability unlock popup -→ quest.md: kill-count criterion met → triggers quest completion event - Output: quest reward XP (500 pts), completion fanfare -→ progression.md (again): quest XP added → triggers SECOND level-up in same frame - ⚠️ Data flow issue: quest.md awards XP without checking if a level-up - is already in progress. progression.md has no guard against concurrent - level-up events. Undefined behavior: does the player level up once or twice? - Does the ability popup fire twice? Does the second level use the updated or - pre-update stat baseline? -``` - -### 4c: Flag Scenario Issues - -For each problem found during the walkthrough, categorize severity: - -- **BLOCKER**: undefined behavior, broken state transition, or contradictory - player messaging — the experience is broken or incoherent in this scenario -- **WARNING**: compounding spikes, feedback loops without caps, reward conflicts — - the experience works but produces unintended outcomes -- **INFO**: minor ordering ambiguity or messaging overlap — worth noting but - unlikely to cause player-visible problems - -Add all findings to the output report under **"Cross-System Scenario Issues"**. -Each finding must cite: the scenario name, the specific systems involved, the -step where the issue occurs, and the nature of the failure mode. - ---- +**Read `references/4-scenarios.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 5: Output the Review Report -``` -## Cross-GDD Review Report -Date: [date] -GDDs Reviewed: [N] of [M] present -Not read: [each GDD that could not be read or is present but empty, by file name — or "none"] -Systems Covered: [list] - ---- - -### Consistency Issues - -#### Blocking (must resolve before architecture begins) -🔴 [Issue title] -[What GDDs are involved, what the contradiction is, what needs to change] - -#### Warnings (should resolve, but won't block) -⚠️ [Issue title] -[What GDDs are involved, what the concern is] - ---- - -### Game Design Issues - -#### Blocking -🔴 [Issue title] -[What the problem is, which GDDs are involved, design recommendation] - -#### Warnings -⚠️ [Issue title] -[What the concern is, which GDDs are affected, recommendation] - ---- - -### Cross-System Scenario Issues - -Scenarios walked: [N] -[List scenario names] - -#### Blockers -🔴 [Scenario name] — [Systems involved] -[Step where failure occurs, nature of the failure mode, what must be resolved] - -#### Warnings -⚠️ [Scenario name] — [Systems involved] -[What the unintended outcome is, recommendation] - -#### Info -ℹ️ [Scenario name] — [Systems involved] -[Minor ordering ambiguity or note] - ---- - -### GDDs Flagged for Revision - -| GDD | Reason | Type | Priority | -|-----|--------|------|----------| -| [system-a].md | Rule contradiction with [system-b].md | Consistency | Blocking | -| [system-b].md | Rule contradiction with [system-a].md | Consistency | Blocking | -| [system-c].md | Stale reference to nonexistent mechanic | Consistency | Blocking | -| [system-d].md | No pillar alignment | Design Theory | Warning | - ---- - -### Verdict: [PASS / NOT ASSESSED / CONCERNS / FAIL] - -PASS: No blocking issues and no warnings. -NOT ASSESSED: One or more review phases could not run — named below. -CONCERNS: Warnings present that should be resolved, but nothing blocking. -FAIL: One or more blocking issues must be resolved before architecture begins. - -### If NOT ASSESSED — what could not be reviewed, and why: -[Name each phase that did not run and the input it needed, and each GDD that could not be read or is present but empty, by file name] - -### If FAIL — required actions before re-running: -[Specific list of what must change in which GDD] -``` - -**`NOT ASSESSED` — a cross-review is only as wide as what it could read.** Rank: -**above PASS**, **below CONCERNS and FAIL**. This skill's whole value is -comparing systems *against each other*, so it is unusually easy for it to look -thorough while covering a fraction of the surface. Emit it when any of: - -- **Fewer than two GDDs were readable.** Contradiction-hunting across one document - is not a cross-review; a clean result there means only that nothing was - compared. This is the single most important trigger in this skill. -- **A whole review phase did not run** — consistency, design theory, economy, - pillar drift. A parallel phase that returned nothing has to be distinguished - from one that returned no findings; if a spawned agent produced no report, that - phase is NOT ASSESSED, not clean — an agent can return a fluent sentence, - write nothing, and consume a phase. -- **The design pillars are undefined**, so pillar-drift has no reference to drift - from — the same shape as an accessibility gate with no committed tier. -- **A GDD is present but empty** (headings only, or all placeholders), **or - could not be read**. Present is not the same as reviewable, and a stub - contradicts nothing. - -Report the covered set explicitly either way: `GDDs reviewed: [N] of [M] present` -(`[M]` counts the system GDDs present — the Phase 1c set, not `game-concept.md`, -`game-pillars.md`, `systems-index.md` or an earlier `gdd-cross-review-*.md`), -and the `Not read:` line naming every GDD that could not be read or is present but empty, whatever the -verdict — a FAIL found in the GDDs that were read does not make the unread ones -reviewed. -A cross-review that silently skipped half the systems is indistinguishable from -one that found them consistent. - ---- +**Read `references/5-report.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 6: Write Report and Flag GDDs -Use `AskUserQuestion` for write permission: -- Prompt: "May I write this review to `design/gdd/gdd-cross-review-[date].md`?" -- Options: `[A] Yes — write the report` / `[B] No — skip` - -> **`[date]` here means ISO 8601 — `YYYY-MM-DD`, e.g. -> `gdd-cross-review-2026-08-19.md`. This is not a style preference.** -> `.claude/scripts/review-scope.sh` picks the prior review with -> `sort | tail -1`, so lexical order IS chronological order only for ISO dates. -> Written as `aug-19-2026` or `19-08-2026`, the wrong file is chosen as the -> baseline, the changed-set is computed from it, and GDDs modified since the -> real last review silently escape the next one. That is the same -> quiet-escape failure the three fixes documented at the top of that script -> exist to prevent. - -If any GDDs are flagged for revision, use a second `AskUserQuestion`: -- Prompt: "Should I update the systems index to mark these GDDs as needing revision? ([list of flagged GDDs])" -- Options: `[A] Yes — update systems index` / `[B] No — leave as-is` -- If yes: update each flagged GDD's Status field in systems-index.md to "Needs Revision". - (Do NOT append parentheticals to the status value — other skills match "Needs Revision" - as an exact string and parentheticals break that match.) - -### Session State Update - -After writing the report (and updating systems index if approved), silently -append to `production/session-state/active.md`: - - ## Session Extract — /review-all-gdds [date] - - Verdict: [PASS / NOT ASSESSED / CONCERNS / FAIL] - - GDDs reviewed: [N of M present] - - Phases not run: [names, or "None"] - - Flagged for revision: [comma-separated list, or "None"] - - Blocking issues: [N — brief one-line descriptions, or "None"] - - Recommended next: [the Phase 7 handoff action, condensed to one line] - - Report: design/gdd/gdd-cross-review-[date].md ← only if user approved the write - - Report: (not written — user declined at [date]) ← only if user declined the write - -Use the appropriate line based on the user's response to the write-permission widget in Phase 6. - -If `active.md` does not exist, create it with this block as the initial content. -Confirm in conversation: "Session state updated." - ---- +**Read `references/6-write.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 7: Handoff -After all file writes are complete, use `AskUserQuestion` for a closing widget. - -Before building options, check project state: -- Are there any Warning-level items that are simple edits (flagged with "30-second edit", "brief addition", or similar)? → offer inline quick-fix option -- Are any GDDs in the "Flagged for Revision" table? → offer /design-review option for each -- Read systems-index.md for the next system with Status: Not Started → offer /design-system option -- Is the verdict PASS or CONCERNS? → offer /gate-check or /create-architecture - -Build the option list dynamically — only include options that apply: - -**Option pool:** -- `[_] Apply quick fix: [W-XX description] in [gdd-name].md — [effort estimate]` (one option per simple-edit warning; only for Warning-level, not Blocking) -- `[_] Run /design-review [flagged-gdd-path] — address flagged warnings` (one per flagged GDD, if any) -- `[_] Run /design-system [next-system] — next in design order` (always include, name the actual system) -- `[_] Run /create-architecture — begin architecture (verdict is PASS/CONCERNS)` (include only if the verdict is PASS or CONCERNS — never on FAIL or NOT ASSESSED) -- `[_] Run /gate-check — validate Systems Design phase gate` (include if verdict is PASS) -- `[_] Stop here` - -Assign letters A, B, C… only to included options. Mark the most pipeline-advancing option as `(recommended)`. - -In collaborative and guided modes, never end the skill with plain text — always -close with this widget. In autonomous mode, print the verdict and recommended -next step, then record via `log_decision` (no widget). - ---- +**Read `references/7-handoff.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Error Recovery Protocol diff --git a/.claude/skills/review-all-gdds/references/1-load.md b/.claude/skills/review-all-gdds/references/1-load.md new file mode 100644 index 00000000..963b6760 --- /dev/null +++ b/.claude/skills/review-all-gdds/references/1-load.md @@ -0,0 +1,115 @@ +# /review-all-gdds — Phase 1: Load Everything + +> Part of `/review-all-gdds`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 1: Load Everything + +**In this file:** + +- Phase 1a — L0: Summary Scan (fast, low tokens) +- Phase 1b — Registry Pre-Load (fast baseline) +- Phase 1c — L1/L2: Section Load + +### Phase 1a — L0: Summary Scan (fast, low tokens) + +Before reading any full document, use Grep to extract `## Summary` sections +from all GDD files: + +``` +Grep pattern="## Summary" glob="design/gdd/*.md" output_mode="content" -A 5 +``` + +**Fail open on a missing Summary.** Establish the denominator: glob +`design/gdd/*.md` and count **N**. A scan matching fewer than N means those GDDs +predate `## Summary` — never treat an absent Summary as a system out of scope. +A zero-match scan means "no GDD carries a Summary yet", not "nothing to review". +This review is holistic and loads its in-scope GDDs regardless (see Phase 1c); +the Summary scan only builds the manifest and narrows `since-last-review`, it +never shrinks the review set. + +Display a manifest to the user: +``` +Found [N] GDDs. Summaries: + • combat.md — [summary text] + • inventory.md — [summary text] + ... +``` + +For `since-last-review` mode, compute the scope deterministically instead of +reasoning through git history: + +``` +Bash: bash .claude/scripts/review-scope.sh +``` + +It prints `PRIOR_REVIEW:`, a `CHANGED:` list, and a `DEPS ...:` list of each +changed GDD's declared dependencies. Use those lists as the scope — the +dependency lines are already the "Key deps" expansion, so no second pass is +needed. If `PRIOR_REVIEW: NONE`, a full review is required; fall back to `full` +mode. + +Show the user which GDDs are in scope based on summaries before doing any full +reads. Only proceed to L1 for the `CHANGED` set plus the GDDs named on the +`DEPS` lines. + +### Phase 1b — Registry Pre-Load (fast baseline) + +Before full-reading any GDD, check for the entity registry: + +``` +Read path="design/registry/entities.yaml" +``` + +If the registry exists and has entries, use it as a **pre-built conflict +baseline**: known entities, items, formulas, and constants with their +authoritative values and source GDDs. In Phase 2, grep GDDs for registered +names first — this is faster than reading all GDDs in full before knowing +what to look for. + +If the registry is empty or absent: proceed without it. Note in the report: +"Entity registry is empty — consistency checks rely on full GDD reads only. +Run `/consistency-check` after this review to populate the registry." + +### Phase 1c — L1/L2: Section Load + +Read whole (small, and every part is used): + +1. `design/gdd/game-concept.md` — game vision, core loop, MVP definition (or + `design/game-brief.md`, the one-page brief that replaces it at `rigor: minimal` — + pitch, core loop, MVP list) +2. `design/gdd/game-pillars.md` if it exists — design pillars and anti-pillars +3. `design/gdd/systems-index.md` — authoritative system list, layers, dependencies, status + +Then, for **every in-scope system GDD**, load the sections this review actually +consumes — **not the whole file**: + +``` +Grep pattern="^## (Dependencies|Detailed Rules|Detailed Design|Formulas|Tuning Knobs|Acceptance Criteria|Player Fantasy)" glob="design/gdd/*.md" output_mode="content" -A 40 +``` + +That list is not a guess — it is exactly the union the Parallel Execution +contract below already enumerates: Phase 2 needs Dependencies, Detailed +Design/Rules, Formulas, Tuning Knobs and Acceptance Criteria; Phase 3 needs +Player Fantasy and progression/reward structure. Overview is narrative restated +by the Summary this skill already scanned in Phase 1a, and Edge Cases feeds no +checklist item here (`/design-review` owns per-GDD completeness). Loading them +put content in three context windows — this one and both sub-agents' — that no +checklist item ever read. + +Accept **either** `## Detailed Rules` or `## Detailed Design`; the design standard +and the GDD template disagree on the name and they denote the same section. + +**Escalate to a full read of one GDD** when a scanned section cross-references +material outside itself, or when a GDD matched **zero** sections — that GDD +predates the template, and a zero-match there means "unstructured", not "empty". +Never let a zero-match silently drop a system: the scan narrows the *read*, it +never shrinks the *review set*. + +Report: "Loaded [N] system GDDs covering [M] systems. Pillars: [list]. Anti-pillars: [list]." + +If fewer than 2 system GDDs exist (count the files present; an empty one is handled under NOT ASSESSED in Phase 5, not here), stop: +> "Cross-GDD review requires at least 2 system GDDs. Write more GDDs first, +> then re-run `/review-all-gdds`." + +--- diff --git a/.claude/skills/review-all-gdds/references/2-consistency.md b/.claude/skills/review-all-gdds/references/2-consistency.md new file mode 100644 index 00000000..630e1390 --- /dev/null +++ b/.claude/skills/review-all-gdds/references/2-consistency.md @@ -0,0 +1,145 @@ +# /review-all-gdds — Phase 2: Cross-GDD Consistency + +> Part of `/review-all-gdds`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 2: Cross-GDD Consistency + +**In this file:** + +- 2a: Dependency Bidirectionality +- 2b: Rule Contradictions +- 2c: Stale References +- 2d: Data and Tuning Knob Ownership Conflicts +- 2e: Formula Compatibility +- 2f: Acceptance Criteria Cross-Check + +Work through every pair and group of GDDs to find contradictions and gaps. + +### 2a: Dependency Bidirectionality + +For every GDD's Dependencies section, check that every listed dependency is +reciprocal: +- If GDD-A lists "depends on GDD-B", check that GDD-B lists GDD-A as a dependent +- If GDD-A lists "depended on by GDD-C", check that GDD-C lists GDD-A as a dependency +- Flag any one-directional dependency as a consistency issue + +``` +⚠️ Dependency Asymmetry +[system-a].md lists: Depends On → [system-b].md +[system-b].md does NOT list [system-a].md as a dependent +→ One of these documents has a stale dependency section +``` + +### 2b: Rule Contradictions + +For each game rule, mechanic, or constraint defined in any GDD, check whether +any other GDD defines a contradicting rule for the same situation: + +Categories to scan: +- **Floor/ceiling rules**: Does any GDD define a minimum value for an output? Does any other say a different system can bypass that floor? These contradict. +- **Resource ownership**: If two GDDs both define how a shared resource accumulates or depletes, do they agree? +- **State transitions**: If GDD-A describes what happens when a character dies, + does GDD-B's description of the same event agree? +- **Timing**: If GDD-A says "X happens on the same frame", does GDD-B assume + it happens asynchronously? +- **Stacking rules**: If GDD-A says status effects stack, does GDD-B assume + they don't? + +``` +🔴 Rule Contradiction +[system-a].md: "Minimum [output] after reduction is [floor_value]" +[system-b].md: "[mechanic] bypasses [system-a]'s rules and can reduce [output] to 0" +→ These rules directly contradict. Which GDD is authoritative? +``` + +### 2c: Stale References + +**Start from the `## Cross-References` table where a GDD has one.** That table is +the document's own declaration of what it depends on — `templates/game-design-document.md` +tells authors it is machine-checked here, and `/design-system` requires it +whenever Dependencies names another GDD. For each row, confirm the `Target GDD` +exists and the `Specific Element Referenced` is still present in it under that +name, with the declared `Nature` still accurate. + +A table that is absent, or still holding the template's bracketed examples, is +itself reportable: say the GDD declares no cross-references and that the prose +scan below was the only check applied. Do not treat an absent table as "no +dependencies" — it far more often means the section was never authored. + +**Then scan the prose regardless**, table or no table: a declared table catches +what the author remembered, and the scan below catches what they did not. + +For every cross-document reference (GDD-A mentions a mechanic, value, or +system name from GDD-B), verify the referenced element still exists in GDD-B +with the same name and behaviour: + +- If GDD-A says "combo multiplier from the combat system feeds into score", check + that the combat GDD actually defines a combo multiplier that outputs to score +- If GDD-A references "the progression curve defined in [system].md", check that + [system].md actually has that curve, not a different progression model +- If GDD-A was written before GDD-B and assumed a mechanic that GDD-B later + designed differently, flag GDD-A as containing a stale reference. Severity: a + reference to a mechanic or formula that **does not exist** is **Blocking** — the + architecture would inherit a rule nobody defined; one that exists but was + designed differently is a **Warning**, unless the difference changes a rule the + referencing GDD depends on (then Blocking) +- If the **target GDD is not written yet** (no file in `design/gdd/`): when + `systems-index.md` lists that system (e.g. `Status: Not Started`), it is a + **Warning** — a dependency on planned work, to re-check when that GDD is + written; when neither a GDD nor a systems-index entry exists for it, it is + **Blocking** — nothing will ever define it + +``` +🔴 Stale Reference +inventory.md (written first): "Item weight uses the encumbrance formula + from movement.md" +movement.md (written later): Defines no encumbrance formula — uses a flat + carry limit instead +→ inventory.md references a formula that doesn't exist — Blocking +``` + +### 2d: Data and Tuning Knob Ownership Conflicts + +Two GDDs should not both claim to own the same data or tuning knob. Scan all +Tuning Knobs sections across all GDDs and flag duplicates: + +``` +⚠️ Ownership Conflict +[system-a].md Tuning Knobs: "[multiplier_name] — controls [output] scaling" +[system-b].md Tuning Knobs: "[multiplier_name] — scales [output] with [factor]" +→ Two GDDs define multipliers on the same output. Which owns the final value? + This will produce either a double-application bug or a design conflict. +``` + +### 2e: Formula Compatibility + +For GDDs whose formulas are connected (output of one feeds input of another), +check that the output range of the upstream formula is within the expected +input range of the downstream formula: + +- If [system-a].md outputs values between [min]–[max], and [system-b].md is + designed to receive values between [min2]–[max2], is the mismatch intentional? +- If an economy GDD expects resource acquisition in range X, and the + progression GDD generates it at range Y, the economy will be trivial or + inaccessible — is that intended? + +Flag incompatibilities as CONCERNS (design judgment needed, not necessarily wrong): + +``` +⚠️ Formula Range Mismatch +[system-a].md: Max [output] = [value_a] (at max [condition]) +[system-b].md: Base [input] = [value_b], max [input] = [value_c] +→ Late-[stage] [scenario] can resolve in a single [event]. + Is this intentional? If not, either [system-a]'s ceiling or [system-b]'s ceiling needs adjustment. +``` + +### 2f: Acceptance Criteria Cross-Check + +Scan Acceptance Criteria sections across all GDDs for contradictions: + +- GDD-A criteria: "Player cannot die from a single hit" +- GDD-B criteria: "Boss attack deals 150% of player max health" +These acceptance criteria cannot both pass simultaneously. + +--- diff --git a/.claude/skills/review-all-gdds/references/3-design-holism.md b/.claude/skills/review-all-gdds/references/3-design-holism.md new file mode 100644 index 00000000..510f7b00 --- /dev/null +++ b/.claude/skills/review-all-gdds/references/3-design-holism.md @@ -0,0 +1,183 @@ +# /review-all-gdds — Phase 3: Game Design Holism + +> Part of `/review-all-gdds`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 3: Game Design Holism + +**In this file:** + +- 3a: Progression Loop Competition +- 3b: Player Attention Budget +- 3c: Dominant Strategy Detection +- 3d: Economic Loop Analysis +- 3e: Difficulty Curve Consistency +- 3f: Pillar Alignment +- 3g: Player Fantasy Coherence + +Review all GDDs together through the lens of game design theory and player +psychology. These are issues that individual GDD reviews cannot catch because +they require seeing all systems at once. + +### 3a: Progression Loop Competition + +A game should have one dominant progression loop that players feel is "the +point" of the game, with supporting loops that feed into it. When multiple +systems compete equally as the primary progression driver, players don't know +what the game is about. + +Scan all GDDs for systems that: +- Award the player's primary resource (XP, levels, prestige, unlocks) +- Define themselves as the "core" or "main" loop +- Have comparable depth and time investment to other systems doing the same + +``` +⚠️ Competing Progression Loops +combat.md: Awards XP, unlocks abilities, is described as "the core loop" +crafting.md: Awards XP, unlocks recipes, is described as "the primary activity" +exploration.md: Awards XP, unlocks map areas, described as "the main driver" +→ Three systems all claim to be the primary progression loop and all award + the same primary currency. Players will optimise one and ignore the others. + Consider: one primary loop with the others as support systems. +``` + +### 3b: Player Attention Budget + +Count how many systems require active player attention simultaneously during +a typical session. Each actively-managed system costs attention: + +- Active = player must make decisions about this system regularly during play +- Passive = system runs automatically, player sees results but doesn't manage it + +More than 3-4 simultaneously active systems creates cognitive overload for most +players. Present the count and flag if it exceeds 4 concurrent active systems: + +``` +⚠️ Cognitive Load Risk +Simultaneously active systems during [core loop moment]: + 1. [system-a].md — [decision type] (active) + 2. [system-b].md — [resource management] (active) + 3. [system-c].md — [tracking] (active) + 4. [system-d].md — [item/action use] (active) + 5. [system-e].md — [cooldown/timer management] (active) + 6. [system-f].md — [coordination decisions] (active) +→ 6 simultaneously active systems during the core loop. + Research suggests 3-4 is the comfortable limit for most players. + Consider: which of these can be made passive or simplified? +``` + +### 3c: Dominant Strategy Detection + +A dominant strategy makes other strategies irrelevant — players discover it, +use it exclusively, and find the rest of the game boring. Look for: + +- **Resource monopolies**: One strategy generates a resource significantly + faster than all others +- **Risk-free power**: A strategy that is both high-reward and low-risk + (if high-risk strategies exist, they need proportionally higher reward) +- **No trade-offs**: An option that is superior in all dimensions to all others +- **Obvious optimal path**: If any progression choice is "clearly correct", + the others aren't real choices + +``` +⚠️ Potential Dominant Strategy +combat.md: Ranged attacks deal 80% of melee damage with no risk +combat.md: Melee attacks deal 100% damage but require close range +→ Unless melee has a significant compensating advantage (AOE, stagger, + resource regeneration), ranged is dominant — higher safety, only 20% less + damage. Consider what melee offers that ranged cannot. +``` + +### 3d: Economic Loop Analysis + +Identify all resources across all GDDs (gold, XP, crafting materials, stamina, +health, mana, etc.). For each resource, map its **sources** (how players gain +it) and **sinks** (how players spend it). + +Flag dangerous economic conditions: + +| Condition | Sign | Risk | +|-----------|------|------| +| **Infinite source, no sink** | Resource accumulates indefinitely | Late game becomes trivially easy | +| **Sink, no source** | Resource drains to zero | System becomes unavailable | +| **Source >> Sink** | Surplus accumulates | Resource becomes meaningless | +| **Sink >> Source** | Constant scarcity | Frustration and gatekeeping | +| **Positive feedback loop** | More resource → easier to earn more | Runaway leader, snowball | +| **No catch-up** | Falling behind accelerates deficit | Unrecoverable states | + +``` +🔴 Economic Imbalance: Unbounded Positive Feedback +gold economy: + Sources: monster drops (scales with player power), merchant selling (unlimited) + Sinks: equipment purchase (one-time), ability upgrades (finite count) +→ After equipment and abilities are purchased, gold has no sink. + Infinite surplus. Gold becomes meaningless mid-game. + Add ongoing gold sinks (upkeep, consumables, cosmetics, gambling). +``` + +### 3e: Difficulty Curve Consistency + +When multiple systems scale with player progression, they must scale in +compatible directions and at compatible rates. Mismatched scaling curves +create unintended difficulty spikes or trivialisations. + +For each system that scales over time, extract: +- What scales (enemy health, player damage, resource cost, area size) +- How it scales (linear, exponential, stepped) +- When it scales (level, time, area) + +Compare all scaling curves. Flag mismatches: + +``` +⚠️ Difficulty Curve Mismatch +combat.md: Enemy health scales exponentially with area (×2 per area) +progression.md: Player damage scales linearly with level (+10% per level) +→ By area 5, enemies have 32× base health; player deals ~1.5× base damage. + The gap widens indefinitely. Late areas will become inaccessibly difficult + unless the curves are reconciled. +``` + +### 3f: Pillar Alignment + +Every system should clearly serve at least one design pillar. A system that +serves no pillar is "scope creep by design" — it's in the game but not in +service of what the game is trying to be. + +For each GDD system, check its Player Fantasy section against the design pillars. +Flag any system whose stated fantasy doesn't map to any pillar: + +``` +⚠️ Pillar Drift +fishing-system.md: Player Fantasy — "peaceful, meditative activity" +Pillars: "Brutal Combat", "Tense Survival", "Emergent Stories" +→ The fishing system serves none of the three pillars. Either add a pillar + that covers it, redesign it to serve an existing pillar, or cut it. +``` + +Also check anti-pillars — flag any system that does what an anti-pillar +explicitly says the game will NOT do: + +``` +🔴 Anti-Pillar Violation +Anti-Pillar: "We will NOT have linear story progression — player defines their path" +main-quest.md: Defines a 12-chapter linear story with mandatory sequence +→ This system directly violates the defined anti-pillar. +``` + +### 3g: Player Fantasy Coherence + +The player fantasies across all systems should be compatible — they should +reinforce a consistent identity for what the player IS in this game. Conflicting +player fantasies create identity confusion. + +``` +⚠️ Player Fantasy Conflict +combat.md: "You are a ruthless, precise warrior — every kill is earned" +dialogue.md: "You are a charismatic diplomat — violence is always avoidable" +exploration.md: "You are a reckless adventurer — diving in without a plan" +→ Three systems present incompatible identities. Players will feel the game + doesn't know what it wants them to be. Consider: do these fantasies serve + the same core identity from different angles, or do they genuinely conflict? +``` + +--- diff --git a/.claude/skills/review-all-gdds/references/4-scenarios.md b/.claude/skills/review-all-gdds/references/4-scenarios.md new file mode 100644 index 00000000..91ba4cde --- /dev/null +++ b/.claude/skills/review-all-gdds/references/4-scenarios.md @@ -0,0 +1,87 @@ +# /review-all-gdds — Phase 4: Cross-System Scenario Walkthrough + +> Part of `/review-all-gdds`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 4: Cross-System Scenario Walkthrough + +Walk through the game from the player's perspective to find problems that only +appear at the interaction boundary between multiple systems — things static +analysis of individual GDDs cannot surface. + +### 4a: Identify Key Multi-System Moments + +Scan all GDDs and identify the 3–5 most important player-facing moments where +multiple systems activate simultaneously. Look specifically for: + +- **Combat + Economy overlap**: killing enemies that drop resources, spending + resources during combat, death/respawn interacting with economy state +- **Progression + Difficulty overlap**: level-up triggering mid-fight, ability + unlocks changing combat viability, difficulty scaling at progression milestones +- **Narrative + Gameplay overlap**: dialogue choices locking/unlocking mechanics, + story beats interrupting resource loops, quest completion triggering system + state changes +- **3+ system chains**: any player action that triggers System A, which feeds + into System B, which triggers System C (these are highest-risk interaction paths) + +List each identified scenario with a one-line description before proceeding. + +### 4b: Walk Through Each Scenario + +For each scenario, step through the sequence explicitly: + +1. **Trigger** — what player action or game event starts this? +2. **Activation order** — which systems activate, in what sequence? +3. **Data flow** — what does each system output, and is that output a valid + input for the next system in the chain? +4. **Player experience** — what does the player see, hear, or feel at each step? +5. **Failure modes** — are there any of the following? + - **Race conditions**: two systems trying to modify the same state simultaneously + - **Feedback loops**: System A amplifies System B which re-amplifies System A + with no cap or dampener + - **Broken state transitions**: a system assumes a state that a previous + system may have changed (e.g., "player is alive" assumption after a combat + step that could have caused death) + - **Contradictory messaging**: player receives conflicting feedback from two + systems reacting to the same event (e.g., "success" sound + "failure" UI) + - **Compounding difficulty spikes**: two systems both scaling up at the same + progression point, multiplying the intended difficulty increase + - **Reward conflicts**: two systems both reacting to the same trigger with + rewards that together exceed the intended value (double-dipping) + - **Undefined behavior**: the GDDs don't specify what happens in this combined + state (neither system's rules cover it) + +``` +Example walkthrough: +Scenario: Player kills elite enemy at level-up threshold during active quest + +Trigger: Player lands killing blow on elite enemy +→ combat.md: awards kill XP (100 pts) +→ progression.md: XP total crosses level threshold → triggers level-up + Output: new level, stat increases, ability unlock popup +→ quest.md: kill-count criterion met → triggers quest completion event + Output: quest reward XP (500 pts), completion fanfare +→ progression.md (again): quest XP added → triggers SECOND level-up in same frame + ⚠️ Data flow issue: quest.md awards XP without checking if a level-up + is already in progress. progression.md has no guard against concurrent + level-up events. Undefined behavior: does the player level up once or twice? + Does the ability popup fire twice? Does the second level use the updated or + pre-update stat baseline? +``` + +### 4c: Flag Scenario Issues + +For each problem found during the walkthrough, categorize severity: + +- **BLOCKER**: undefined behavior, broken state transition, or contradictory + player messaging — the experience is broken or incoherent in this scenario +- **WARNING**: compounding spikes, feedback loops without caps, reward conflicts — + the experience works but produces unintended outcomes +- **INFO**: minor ordering ambiguity or messaging overlap — worth noting but + unlikely to cause player-visible problems + +Add all findings to the output report under **"Cross-System Scenario Issues"**. +Each finding must cite: the scenario name, the specific systems involved, the +step where the issue occurs, and the nature of the failure mode. + +--- diff --git a/.claude/skills/review-all-gdds/references/5-report.md b/.claude/skills/review-all-gdds/references/5-report.md new file mode 100644 index 00000000..83c6a0af --- /dev/null +++ b/.claude/skills/review-all-gdds/references/5-report.md @@ -0,0 +1,118 @@ +# /review-all-gdds — Phase 5: Output the Review Report + +> Part of `/review-all-gdds`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 5: Output the Review Report + +**In this file:** + +- The report template +- `NOT ASSESSED` and where it ranks + +``` +## Cross-GDD Review Report +Date: [date] +GDDs Reviewed: [N] of [M] present +Not read: [each GDD that could not be read or is present but empty, by file name — or "none"] +Systems Covered: [list] + +--- + +### Consistency Issues + +#### Blocking (must resolve before architecture begins) +🔴 [Issue title] +[What GDDs are involved, what the contradiction is, what needs to change] + +#### Warnings (should resolve, but won't block) +⚠️ [Issue title] +[What GDDs are involved, what the concern is] + +--- + +### Game Design Issues + +#### Blocking +🔴 [Issue title] +[What the problem is, which GDDs are involved, design recommendation] + +#### Warnings +⚠️ [Issue title] +[What the concern is, which GDDs are affected, recommendation] + +--- + +### Cross-System Scenario Issues + +Scenarios walked: [N] +[List scenario names] + +#### Blockers +🔴 [Scenario name] — [Systems involved] +[Step where failure occurs, nature of the failure mode, what must be resolved] + +#### Warnings +⚠️ [Scenario name] — [Systems involved] +[What the unintended outcome is, recommendation] + +#### Info +ℹ️ [Scenario name] — [Systems involved] +[Minor ordering ambiguity or note] + +--- + +### GDDs Flagged for Revision + +| GDD | Reason | Type | Priority | +|-----|--------|------|----------| +| [system-a].md | Rule contradiction with [system-b].md | Consistency | Blocking | +| [system-b].md | Rule contradiction with [system-a].md | Consistency | Blocking | +| [system-c].md | Stale reference to nonexistent mechanic | Consistency | Blocking | +| [system-d].md | No pillar alignment | Design Theory | Warning | + +--- + +### Verdict: [PASS / NOT ASSESSED / CONCERNS / FAIL] + +PASS: No blocking issues and no warnings. +NOT ASSESSED: One or more review phases could not run — named below. +CONCERNS: Warnings present that should be resolved, but nothing blocking. +FAIL: One or more blocking issues must be resolved before architecture begins. + +### If NOT ASSESSED — what could not be reviewed, and why: +[Name each phase that did not run and the input it needed, and each GDD that could not be read or is present but empty, by file name] + +### If FAIL — required actions before re-running: +[Specific list of what must change in which GDD] +``` + +**`NOT ASSESSED` — a cross-review is only as wide as what it could read.** Rank: +**above PASS**, **below CONCERNS and FAIL**. This skill's whole value is +comparing systems *against each other*, so it is unusually easy for it to look +thorough while covering a fraction of the surface. Emit it when any of: + +- **Fewer than two GDDs were readable.** Contradiction-hunting across one document + is not a cross-review; a clean result there means only that nothing was + compared. This is the single most important trigger in this skill. +- **A whole review phase did not run** — consistency, design theory, economy, + pillar drift. A parallel phase that returned nothing has to be distinguished + from one that returned no findings; if a spawned agent produced no report, that + phase is NOT ASSESSED, not clean — an agent can return a fluent sentence, + write nothing, and consume a phase. +- **The design pillars are undefined**, so pillar-drift has no reference to drift + from — the same shape as an accessibility gate with no committed tier. +- **A GDD is present but empty** (headings only, or all placeholders), **or + could not be read**. Present is not the same as reviewable, and a stub + contradicts nothing. + +Report the covered set explicitly either way: `GDDs reviewed: [N] of [M] present` +(`[M]` counts the system GDDs present — the Phase 1c set, not `game-concept.md`, +`game-pillars.md`, `systems-index.md` or an earlier `gdd-cross-review-*.md`), +and the `Not read:` line naming every GDD that could not be read or is present but empty, whatever the +verdict — a FAIL found in the GDDs that were read does not make the unread ones +reviewed. +A cross-review that silently skipped half the systems is indistinguishable from +one that found them consistent. + +--- diff --git a/.claude/skills/review-all-gdds/references/6-write.md b/.claude/skills/review-all-gdds/references/6-write.md new file mode 100644 index 00000000..dc4b31c0 --- /dev/null +++ b/.claude/skills/review-all-gdds/references/6-write.md @@ -0,0 +1,49 @@ +# /review-all-gdds — Phase 6: Write Report and Flag GDDs + +> Part of `/review-all-gdds`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 6: Write Report and Flag GDDs + +Use `AskUserQuestion` for write permission: +- Prompt: "May I write this review to `design/gdd/gdd-cross-review-[date].md`?" +- Options: `[A] Yes — write the report` / `[B] No — skip` + +> **`[date]` here means ISO 8601 — `YYYY-MM-DD`, e.g. +> `gdd-cross-review-2026-08-19.md`. This is not a style preference.** +> `.claude/scripts/review-scope.sh` picks the prior review with +> `sort | tail -1`, so lexical order IS chronological order only for ISO dates. +> Written as `aug-19-2026` or `19-08-2026`, the wrong file is chosen as the +> baseline, the changed-set is computed from it, and GDDs modified since the +> real last review silently escape the next one. That is the same +> quiet-escape failure the three fixes documented at the top of that script +> exist to prevent. + +If any GDDs are flagged for revision, use a second `AskUserQuestion`: +- Prompt: "Should I update the systems index to mark these GDDs as needing revision? ([list of flagged GDDs])" +- Options: `[A] Yes — update systems index` / `[B] No — leave as-is` +- If yes: update each flagged GDD's Status field in systems-index.md to "Needs Revision". + (Do NOT append parentheticals to the status value — other skills match "Needs Revision" + as an exact string and parentheticals break that match.) + +### Session State Update + +After writing the report (and updating systems index if approved), silently +append to `production/session-state/active.md`: + + ## Session Extract — /review-all-gdds [date] + - Verdict: [PASS / NOT ASSESSED / CONCERNS / FAIL] + - GDDs reviewed: [N of M present] + - Phases not run: [names, or "None"] + - Flagged for revision: [comma-separated list, or "None"] + - Blocking issues: [N — brief one-line descriptions, or "None"] + - Recommended next: [the Phase 7 handoff action, condensed to one line] + - Report: design/gdd/gdd-cross-review-[date].md ← only if user approved the write + - Report: (not written — user declined at [date]) ← only if user declined the write + +Use the appropriate line based on the user's response to the write-permission widget in Phase 6. + +If `active.md` does not exist, create it with this block as the initial content. +Confirm in conversation: "Session state updated." + +--- diff --git a/.claude/skills/review-all-gdds/references/7-handoff.md b/.claude/skills/review-all-gdds/references/7-handoff.md new file mode 100644 index 00000000..faaf6d49 --- /dev/null +++ b/.claude/skills/review-all-gdds/references/7-handoff.md @@ -0,0 +1,32 @@ +# /review-all-gdds — Phase 7: Handoff + +> Part of `/review-all-gdds`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 7: Handoff + +After all file writes are complete, use `AskUserQuestion` for a closing widget. + +Before building options, check project state: +- Are there any Warning-level items that are simple edits (flagged with "30-second edit", "brief addition", or similar)? → offer inline quick-fix option +- Are any GDDs in the "Flagged for Revision" table? → offer /design-review option for each +- Read systems-index.md for the next system with Status: Not Started → offer /design-system option +- Is the verdict PASS or CONCERNS? → offer /gate-check or /create-architecture + +Build the option list dynamically — only include options that apply: + +**Option pool:** +- `[_] Apply quick fix: [W-XX description] in [gdd-name].md — [effort estimate]` (one option per simple-edit warning; only for Warning-level, not Blocking) +- `[_] Run /design-review [flagged-gdd-path] — address flagged warnings` (one per flagged GDD, if any) +- `[_] Run /design-system [next-system] — next in design order` (always include, name the actual system) +- `[_] Run /create-architecture — begin architecture (verdict is PASS/CONCERNS)` (include only if the verdict is PASS or CONCERNS — never on FAIL or NOT ASSESSED) +- `[_] Run /gate-check — validate Systems Design phase gate` (include if verdict is PASS) +- `[_] Stop here` + +Assign letters A, B, C… only to included options. Mark the most pipeline-advancing option as `(recommended)`. + +In collaborative and guided modes, never end the skill with plain text — always +close with this widget. In autonomous mode, print the verdict and recommended +next step, then record via `log_decision` (no widget). + +--- diff --git a/.claude/skills/scope-check/SKILL.md b/.claude/skills/scope-check/SKILL.md index e7d113b4..8f7b6174 100644 --- a/.claude/skills/scope-check/SKILL.md +++ b/.claude/skills/scope-check/SKILL.md @@ -102,8 +102,8 @@ Assign a canonical verdict based on net scope change: | Net Change | Verdict | Meaning | |-----------|---------|---------| | ≤10% | **PASS** | On Track — within acceptable variance | -| 10–25% | **CONCERNS** | Minor Creep — manageable with targeted cuts | -| 25–50% | **FAIL** | Significant Creep — must cut or formally extend timeline | +| >10–25% | **CONCERNS** | Minor Creep — manageable with targeted cuts | +| >25–50% | **FAIL** | Significant Creep — must cut or formally extend timeline | | >50% | **FAIL** | Out of Control — stop, re-plan, escalate to producer | **Before applying that table, check that the percentage means something.** Emit @@ -144,8 +144,8 @@ After presenting the report, offer concrete follow-up: the baseline document, or point the skill at where the work actually lives). Do not offer a re-run against the same inputs — it will produce the same non-answer. -- **CONCERNS** → offer to identify the 2–3 additions with best cut ratio. Reference `/sprint-plan update` to formally re-scope. -- **FAIL** → recommend escalating to producer. Reference `/sprint-plan update` for re-planning or `/estimate` to re-baseline timeline. +- **CONCERNS** → offer to identify the 2–3 additions with best cut ratio. Reference `/sprint-plan update` to formally re-scope (if the project has no sprint plan, as on the default minimal workflow, re-scope by editing the brief's build order). +- **FAIL** → recommend escalating to producer. Reference `/sprint-plan update` for re-planning (if the project has no sprint plan, as on the default minimal workflow, edit the brief's build order) or `/estimate` to re-baseline timeline. End every verdict except NOT ASSESSED with: > "Run `/scope-check [name]` again after cuts are made to verify the verdict improves." diff --git a/.claude/skills/settings/SKILL.md b/.claude/skills/settings/SKILL.md index 45314ab4..1ab52c0f 100644 --- a/.claude/skills/settings/SKILL.md +++ b/.claude/skills/settings/SKILL.md @@ -46,18 +46,26 @@ Anything else that doesn't match the four forms above → Phase 6 (usage). ## Phase 1: Load Helper -All four subcommands need `yaml-helper.sh`. Source it once via Bash: +All four subcommands need `yaml-helper.sh`. Each Bash call starts a fresh +shell, so load it **in the same command as every helper call**, from the project +root, in parentheses so the session's working directory does not change: ```bash -source "${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/yaml-helper.sh" +(cd "${CLAUDE_SKILL_DIR}/../../.." && source .claude/hooks/yaml-helper.sh && ) ``` +`` is the function each phase below names, for example +`resolve_setting modes.review_mode` or `validate_yaml_enum project.yaml`. +Running from the root is what makes those `project.yaml` and +`project.local.yaml` arguments resolve when the session was started in a +subfolder. + If `.claude/hooks/yaml-helper.sh` is missing, this is not a CCGS project. Report the error and exit. ## Phase 1b: Reserved-setting detection -Some settings are fully documented, enum-validated and settable, and **no skill +Some settings are fully documented and settable, and **no skill or hook reads them** — setting one changes nothing. **This skill must say so.** Returning an ordinary success lets a user reasonably believe the behaviour the setting describes is now enforced — an accessibility tier being the case that @@ -156,7 +164,7 @@ legitimate; storing it *silently* is the defect. print this line with the legend below the block: ``` - reserved = stored and validated, but nothing reads it. Setting it changes + reserved = stored, but nothing reads it. Setting it changes no behaviour today. ``` @@ -185,7 +193,7 @@ Schema validation: ok Effective config: framework: - version: 1.1.2 (project.yaml, locked) + version: 1.1.3 (project.yaml, locked) modes: review_mode: lean (project.yaml) @@ -241,8 +249,8 @@ Schema validation: ERRORS **If `` is in `RESERVED_SET`, print this BEFORE the value block** — above, not below. A caveat under a value reads as a footnote on a working setting: -> **`` is RESERVED — nothing reads it.** The value below is stored and -> validated; it changes no behaviour today. +> **`` is RESERVED — nothing reads it.** The value below is stored; it +> changes no behaviour today. Let `` be the argument. Perform four reads: diff --git a/.claude/skills/setup-engine/SKILL.md b/.claude/skills/setup-engine/SKILL.md index 73ffeaa4..83326c7f 100644 --- a/.claude/skills/setup-engine/SKILL.md +++ b/.claude/skills/setup-engine/SKILL.md @@ -7,6 +7,8 @@ allowed-tools: Read, Glob, Grep, Write, Edit, Bash, WebSearch, WebFetch, Agent, model: sonnet --- +# Engine Setup + When this skill is invoked: !`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys workflow` @@ -36,1171 +38,39 @@ Four modes: ## 2. Guided Mode (No Arguments) -If no engine is specified, run an interactive engine selection process: - -### Check for existing game concept -Read the design artifact for the resolved tier (see **Tier awareness** above): -- **`standard` / `full`**: read `design/gdd/game-concept.md` if it exists — - extract genre, scope, platform targets, art style, team size, and any engine - recommendation from `/brainstorm`. -- **`minimal`**: read `design/game-brief.md` if it exists — extract genre, - scope, platform, and art direction from its fields. Its absence is **expected** - at `minimal` (the brief is authored *after* engine setup in the minimal path), so - do not treat a missing brief as a gap — proceed straight to guided selection. -- If no concept **or** brief exists, inform the user: - > "No game concept found. Consider running `/brainstorm` first to discover what - > you want to build — it will also recommend an engine. Or tell me about your - > game and I can help you pick." - - (At `minimal` this is optional, not a prerequisite — you can pick an engine now - and write the brief next.) - -### If the user wants to pick without a concept, ask in this order: - -**Question 1 — Prior experience** (ask this first, always, via `AskUserQuestion`): -- Prompt: "Have you worked in any of these engines before?" -- Options: `Godot` / `Unity` / `Unreal Engine 5` / `Multiple — I'll explain` / `None of them` -- If they pick a specific engine → recommend that engine. Prior experience outweighs all other factors. Confirm with them and skip the matrix. -- If "None" or "Multiple" → continue to the questions below. - -**Questions 2-6 — Decision matrix inputs** (only if no prior engine experience): - -**Question 2 — Target platform** (ask this second, always, via `AskUserQuestion` — platform eliminates or heavily weights engines before any other factor): -- Prompt: "What platforms are you targeting for this game?" -- Options: `PC (Steam / Epic)` / `Mobile (iOS / Android)` / `Console` / `Web / Browser` / `Multiple platforms` -- Platform rules that feed directly into the recommendation: - - Mobile → Unity strongly preferred; Unreal is a poor fit; Godot is viable for simple mobile - - Console → Unity or Unreal; Godot console support requires third-party publishers or significant extra work - - Web → Godot exports cleanly to web; Unity WebGL is functional; Unreal has poor web support - - PC only → all engines viable; other factors decide - - Multiple → Unity is the most portable across PC/mobile/console - -1. **What kind of game?** (2D, 3D, or both?) -2. **Primary input method?** (keyboard/mouse, gamepad, touch, or mixed?) -3. **Team size and experience?** (solo beginner, solo experienced, small team?) -4. **Any strong language preferences?** (GDScript, C#, C++, visual scripting?) -5. **Budget for engine licensing?** (free only, or commercial licenses OK?) - -### Produce a recommendation - -Do NOT use a simple scoring matrix that eliminates engines. Instead, reason through the user's profile against the honest tradeoffs below, then present 1-2 recommendations with full context. Always end with the user choosing — never force a verdict. - -**Engine honest tradeoffs:** - -**Godot 4** -- Genuine strengths: 2D (best in class), stylized/indie 3D, rapid iteration, free forever (MIT), open source, gentlest learning curve, best for solo devs who want full control -- Real limitations: 3D ecosystem is thin compared to Unity/Unreal (fewer tutorials, assets, community answers for 3D-specific problems); large open-world 3D is very hard and largely untested in Godot; console export requires third-party publishers or significant extra work; smaller professional job market -- Licensing reality: Truly free with no revenue thresholds ever. MIT license means you own everything. -- Best fit: 2D games of any scope; stylized/atmospheric 3D; contained 3D worlds (not open-world); first game projects where learning curve matters; projects where budget is a hard constraint at any scale - -**Unity** -- Genuine strengths: Industry standard for mid-scope 3D and mobile; massive asset store and tutorial ecosystem; C# is a professional language; best console certification support for indie; strong community for almost every genre -- Real limitations: Licensing controversy in 2023 damaged trust (runtime fee was proposed then walked back — the risk of policy changes remains real); C# has a steeper initial curve than GDScript; heavier editor than Godot for simple projects -- Licensing reality: Free under $200K revenue AND 200K installs (Unity Personal/Plus). Only becomes costly if the game is genuinely successful — most indie games never hit this threshold. The 2023 controversy is worth knowing about but the actual current terms are reasonable for most indie developers. -- Best fit: Mobile games; mid-scope 3D; games targeting console; developers with C# background; projects needing large asset store; teams of 2-5 - -**Unreal Engine 5** -- Genuine strengths: Best-in-class 3D visuals (Lumen, Nanite, Chaos physics); industry standard for AAA and photorealistic 3D; large open-world support is mature and production-tested; Blueprint visual scripting lowers C++ barrier; strong for games targeting high-end PC or console -- Real limitations: Steepest learning curve; heaviest editor (slow compile times, large project sizes); overkill for stylized/2D/small-scope games; C++ is genuinely hard; not suitable for mobile or web; 5% royalty past $1M gross revenue -- Licensing reality: 5% royalty only applies AFTER $1M gross revenue per title. For a first game or any game that doesn't reach $1M, it costs nothing. This threshold is high enough that most indie developers will never pay it. -- Best fit: AAA-quality 3D; large open-world games; photorealistic visuals; developers with C++ experience or willing to use Blueprint; games targeting high-end PC/console where visual fidelity is a core selling point - -**Genre-specific guidance** (factor this into the recommendation): -- 2D any style → Godot strongly preferred -- 3D stylized / atmospheric / contained world → Godot viable, Unity solid alternative -- 3D open world (large, seamless) → Unity or Unreal; Godot is not production-proven for this -- 3D photorealistic / AAA-quality → Unreal -- Mobile-first → Unity strongly preferred -- Console-first → Unity or Unreal; Godot console support requires extra work -- Horror / narrative / walking sim → any engine; match to art style and team experience -- Action RPG / Soulslike → Unity or Unreal for 3D; community support and assets matter here -- Platformer 2D → Godot -- Strategy / top-down / RTS → Godot or Unity depending on 2D vs 3D - -**Recommendation format:** -1. Show a comparison table with the user's specific factors as rows -2. Give a primary recommendation with honest reasoning -3. Name the best alternative and when to choose it instead -4. Explicitly state: "This is a starting point, not a verdict — you can always migrate engines, and many developers switch between projects." -5. Use `AskUserQuestion` to confirm: "Does this recommendation feel right, or would you like to explore a different engine?" - - Options: `[Primary engine] (Recommended)` / `[Alternative engine]` / `[Third engine]` / `Explore further` / `Type something` - -**If the user picks "Explore further":** -Use `AskUserQuestion` with concept-specific deep-dive topics. Always generate these options from the user's actual concept — do not use generic options. Always include at minimum: -- The primary engine's specific limitations for this concept (e.g., "How far can Godot 3D actually go for [genre]?") -- The alternative engine's specific tradeoffs for this concept -- Language choice impact on this concept's technical challenges -- Any concept-specific technical concern (e.g., adaptive audio, open-world streaming, multiplayer netcode) - -The user can select multiple topics. Answer each selected topic in depth before returning to the engine confirmation question. - ---- +**Read `references/2-guided-mode.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 3. Look Up Current Version -Once the engine is chosen: - -- If version was provided, use it -- If no version provided, use WebSearch to find the latest stable release: - - Search: `"[engine] latest stable version [current year]"` - - Confirm with the user: "The latest stable [engine] is [version]. Use this?" - -### Check the chosen version against what is actually installed - -A version found by web search is what exists, not what the developer has. Pinning -one they cannot run means every later instruction — build, test, smoke, the -engine reference docs — targets an engine that is not on the machine. - -Probe for the binary (Bash), and treat failure as unknown, never as absent: - -| Engine | Probe | -|--------|-------| -| Godot | `godot --version`, else look for `godot`/`Godot_v*` on PATH or in the platform's usual install location (macOS: the binary inside the bundle, `Godot.app/Contents/MacOS/Godot`) | -| Unity | The Hub's editor directory, then that editor's `-version` — `C:/Program Files/Unity/Hub/Editor//Editor/Unity.exe` on Windows, `/Applications/Unity/Hub/Editor//Unity.app/Contents/MacOS/Unity` on macOS, `/home//Unity/Hub/Editor//Editor/Unity` on Linux. Not bare `Unity`: on `PATH` it may be Unity's separate CLI, which rejects `-version` | -| Unreal | The launcher's install directory (`UE_` folders under `C:/Program Files/Epic Games/` on Windows); elsewhere, ask where the engine was built or installed. The editor is not on `PATH` by default | - -Keep the executable the probe found (for Godot, whether bare `godot --version` -ran — that is, `godot` is on `PATH`): Section 5.5.1 writes it into `commands.*` -and `engine.path`. - -Then: -- **Match** — say so in one line and continue. -- **Mismatch** — state both versions and ask, offering three options: pin the - installed version, pin the newer one and upgrade later, or pin the newer one - deliberately. Record the answer; do not pick silently. -- **Not found / probe failed** — report `installed version NOT DETERMINED` and - continue with the chosen version. Do **not** report this as "no engine - installed": a probe that could not run has not established absence. - -Whatever the outcome, write it into Section 7's `VERSION.md` as an -`Installed at pin time` row, so a later reader can tell a deliberate -version-ahead pin from an accident. - ---- +**Read `references/3-version.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 4. Update CLAUDE.md Technology Stack -### Language Selection (Godot only) - -If Godot was chosen, ask the user which language to use **before** showing the proposed Technology Stack: - -> "Godot supports two primary languages: -> -> **A) GDScript** — Python-like, Godot-native, fastest iteration. Best for beginners, solo devs, and teams coming from Python or Lua. -> **B) C#** — .NET 8+, familiar to Unity developers, stronger IDE tooling (Rider / Visual Studio), slight performance advantage on heavy logic. -> **C) Both** — GDScript for gameplay/UI scripting, C# for performance-critical systems. Advanced setup — requires .NET SDK alongside Godot. -> -> Which will this project primarily use?" - -Record the choice. It determines the CLAUDE.md template, naming conventions, specialist routing, and which agent is spawned for code files throughout the project. - -### Primary Language (Unreal) - -If Unreal was chosen, ask via `AskUserQuestion`: "Will most gameplay logic live in -C++ or in Blueprints?" — `[A] C++ (Blueprints for tuning and prototyping)` / -`[B] Blueprint-primary (C++ only where needed)`. Default to C++ if the user has no -preference. The answer sets `engine.language` (`"C++"` or `"Blueprint"`). - ---- - -Read `CLAUDE.md` and show the user the proposed Technology Stack changes. -Ask: "May I write these engine settings to `CLAUDE.md`?" - -Wait for confirmation before making any edits. - -Update the Technology Stack section, replacing the `[CHOOSE]` placeholders with the actual values: - -**For Godot** — use the template matching the language chosen above. See `.claude/skills/setup-engine/references/godot-language-config.md` (**A1**) for all three variants (GDScript, C#, Both). - -**For Unity:** -```markdown -- **Engine**: Unity [version] -- **Language**: C# -- **Build System**: Unity Build Pipeline -- **Asset Pipeline**: Unity Asset Import Pipeline + Addressables -``` - -**For Unreal:** -```markdown -- **Engine**: Unreal Engine [version] -- **Language**: [C++ (primary), Blueprint (gameplay prototyping) | Blueprint (primary), C++ where needed] -- **Build System**: Unreal Build Tool (UBT) -- **Asset Pipeline**: Unreal Content Pipeline -``` -The Language line follows the primary-language answer above: the first form for -`[A]` (`engine.language: "C++"`), the second for `[B]` (`"Blueprint"`). - -### Engine reference import - -In the same CLAUDE.md write, set the **Engine Version Reference** import to the -chosen engine. Find the line marked `ENGINE-REFERENCE-IMPORT` (an -`@docs/engine-reference//VERSION.md` line under its comment) and Edit it -to point at the configured engine: -- Godot → `@docs/engine-reference/godot/VERSION.md` -- Unity → `@docs/engine-reference/unity/VERSION.md` -- Unreal → `@docs/engine-reference/unreal/VERSION.md` - -This is why a fresh Unity or Unreal project no longer loads the Godot reference in -every session. It is idempotent — re-running `/setup-engine` for a different -engine rewrites the same line. (The target `docs/engine-reference//` -directory is created in Section 8 below if it does not yet exist.) - ---- +**Read `references/4-claude-md-stack.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 5. Populate Technical Preferences -After updating CLAUDE.md, create or update `.claude/docs/technical-preferences.md` with -engine-appropriate defaults. Read the existing template first, then fill in: - -### Engine & Language Section -- Fill from the engine choice made in step 4 - -### Naming Conventions (engine defaults) - -**For Godot** — see `.claude/skills/setup-engine/references/godot-language-config.md` (**A2**) for GDScript, C#, and Both variants. - -**For Unity (C#):** -- Classes: PascalCase (e.g., `PlayerController`) -- Public fields/properties: PascalCase (e.g., `MoveSpeed`) -- Private fields: _camelCase (e.g., `_moveSpeed`) -- Methods: PascalCase (e.g., `TakeDamage()`) -- Files: PascalCase matching class (e.g., `PlayerController.cs`) -- Constants: PascalCase or UPPER_SNAKE_CASE - -**For Unreal (C++):** -- Classes: Prefixed PascalCase (`A` for Actor, `U` for UObject, `F` for struct) -- Variables: PascalCase (e.g., `MoveSpeed`) -- Functions: PascalCase (e.g., `TakeDamage()`) -- Booleans: `b` prefix (e.g., `bIsAlive`) -- Files: Match class without prefix (e.g., `PlayerController.h`) - -### Input & Platform Section - -Populate `## Input & Platform` using the answers gathered in Section 2 (or extracted -from the game concept). Derive the values using this mapping: - -| Platform target | Gamepad Support | Touch Support | -|-----------------|-----------------|---------------| -| PC only | Partial (recommended) | None | -| Console | Full | None | -| Mobile | None | Full | -| PC + Console | Full | None | -| PC + Mobile | Partial | Full | -| Web | Partial | Partial | - -For **Primary Input**, use the dominant input for the game genre: -- Action/RPG/platformer targeting console → Gamepad -- Strategy/point-and-click/RTS → Keyboard/Mouse -- Mobile game → Touch -- Cross-platform → ask the user - -> **Genre may not exist yet — check before deriving from it.** At `minimal` the -> design artifact is `design/game-brief.md`, and it is authored *after* this -> skill runs (Section 2 says so explicitly). There is no genre to map. The same -> is true at any tier when `/setup-engine` is run before the concept exists. -> -> When genre is unavailable, **ask** — do not infer one from the platform, and do -> not leave the field silently blank: -> - Prompt: "Primary input for a [2D/3D] [platform] game? Genre isn't established -> yet — the brief comes next — so this can't be derived." -> - Options: the plausible inputs for that platform, plus -> `Leave as [TO BE CONFIGURED]` — a legitimate answer here, revisited via -> `/settings` once the brief exists. -> -> Gamepad Support and Touch Support still come from the platform table above; -> only Primary Input depends on genre. - -Present the derived values and ask the user to confirm or adjust before writing. - -Example filled section: -```markdown -## Input & Platform -- **Target Platforms**: PC, Console -- **Input Methods**: Keyboard/Mouse, Gamepad -- **Primary Input**: Gamepad -- **Gamepad Support**: Full -- **Touch Support**: None -- **Platform Notes**: All UI must support d-pad navigation. No hover-only interactions. -``` - -### Remaining Sections -- **Performance Budgets**: Use `AskUserQuestion`: - - Prompt: "Should I set default performance budgets now, or leave them for later?" - - Options: `[A] Set defaults now (60fps, 16.6ms frame budget, engine-appropriate draw call limit)` / `[B] Leave as [TO BE CONFIGURED] — I'll set these when I know my target hardware` - - If [A]: populate with the suggested defaults. If [B]: leave as placeholder. -- **Testing**: Suggest the engine-appropriate framework — **gdUnit4** for Godot, - NUnit for Unity, Automation Spec for Unreal — and ask before adding. - > **Must match `commands.test` in Section 5.5.1, which writes gdUnit4's own - > runner (`res://addons/gdUnit4/bin/GdUnitCmdTool.gd`), and - > `.claude/docs/coding-standards.md`, which names the same runner.** Naming GUT - > here would have the skill recommend one framework and configure another in the - > same run. -- **Forbidden Patterns**: Leave as placeholder — do NOT pre-populate. -- **Allowed Libraries**: Leave as placeholder — do NOT pre-populate dependencies the project does not currently need. Only add a library here when it is actively being integrated, not speculatively. - -> **Guardrail**: Never add speculative dependencies to Allowed Libraries. For example, do NOT add GodotSteam unless Steam integration is actively beginning in this session. Post-launch integrations should be added to Allowed Libraries when that work begins, not during engine setup. - -### Engine Specialists Routing - -Also populate the `## Engine Specialists` section in `technical-preferences.md` with the correct routing for the chosen engine: - -**For Godot** — see `.claude/skills/setup-engine/references/godot-language-config.md` (**A3**) for the routing table matching the language chosen. - -**For Unity:** -```markdown -## Engine Specialists -- **Primary**: unity-specialist -- **Language/Code Specialist**: unity-specialist (C# review — primary covers it) -- **Shader Specialist**: unity-shader-specialist (Shader Graph, HLSL, URP/HDRP materials) -- **UI Specialist**: unity-ui-specialist (UI Toolkit UXML/USS, UGUI Canvas, runtime UI) -- **Additional Specialists**: unity-dots-specialist (ECS, Jobs system, Burst compiler), unity-addressables-specialist (asset loading, memory management, content catalogs) -- **Routing Notes**: Invoke primary for architecture and general C# code review. Invoke DOTS specialist for any ECS/Jobs/Burst code. Invoke shader specialist for rendering and visual effects. Invoke UI specialist for all interface implementation. Invoke Addressables specialist for asset management systems. - -### File Extension Routing - -| File Extension / Type | Specialist to Spawn | -|-----------------------|---------------------| -| Game code (.cs files) | unity-specialist | -| Shader / material files (.shader, .shadergraph, .mat) | unity-shader-specialist | -| UI / screen files (.uxml, .uss, Canvas prefabs) | unity-ui-specialist | -| Scene / prefab / level files (.unity, .prefab) | unity-specialist | -| Native extension / plugin files (.dll, native plugins) | unity-specialist | -| General architecture review | unity-specialist | -``` - -**For Unreal:** -```markdown -## Engine Specialists -- **Primary**: unreal-specialist -- **Language/Code Specialist**: ue-blueprint-specialist (Blueprint graphs) or unreal-specialist (C++) -- **Shader Specialist**: unreal-specialist (no dedicated shader specialist — primary covers materials) -- **UI Specialist**: ue-umg-specialist (UMG widgets, CommonUI, input routing, widget styling) -- **Additional Specialists**: ue-gas-specialist (Gameplay Ability System, attributes, gameplay effects), ue-replication-specialist (property replication, RPCs, client prediction, netcode) -- **Routing Notes**: Invoke primary for C++ architecture and broad engine decisions. Invoke Blueprint specialist for Blueprint graph architecture and BP/C++ boundary design. Invoke GAS specialist for all ability and attribute code. Invoke replication specialist for any multiplayer or networked systems. Invoke UMG specialist for all UI implementation. - -### File Extension Routing - -| File Extension / Type | Specialist to Spawn | -|-----------------------|---------------------| -| Game code (.cpp, .h files) | unreal-specialist | -| Shader / material files (.usf, .ush, Material assets) | unreal-specialist | -| UI / screen files (.umg, UMG Widget Blueprints) | ue-umg-specialist | -| Scene / prefab / level files (.umap, .uasset) | unreal-specialist | -| Native extension / plugin files (Plugin .uplugin, modules) | unreal-specialist | -| Blueprint graphs (.uasset BP classes) | ue-blueprint-specialist | -| General architecture review | unreal-specialist | -``` - -### Collaborative Step -Present the filled-in preferences to the user. For Godot, include the chosen language and note where the full naming conventions and routing tables live: -> "Here are the default technical preferences for [engine] ([language if Godot]). The naming conventions and specialist routing are in this skill's references directory — I'll apply the [GDScript/C#/Both] variant. Want to customize any of these, or may I save them to `.claude/docs/technical-preferences.md`?" - -For all other engines, present the defaults directly without referencing the appendix. - -Wait for approval before writing the file. - ---- +**Read `references/5-technical-preferences.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 5.5 Populate `project.yaml` (Primary Config Store) -> **v1.1:** `project.yaml` at the repo root is the **primary** store for project -> configuration. The `.claude/docs/technical-preferences.md` file written in -> Section 5 is kept as a **legacy mirror** for backward compatibility. This step -> is a **dual-write** — the same engine facts go into both files, and -> `project.yaml` wins when a skill reads a key present in both. - -After `technical-preferences.md` is written and approved, dual-write the -structured config into `project.yaml`. Four blocks are written: `engine`, -`specialists`, `naming`, and `commands`. - -### 5.5.1 Build the four blocks - -Derive every value from the engine and language already chosen in Sections 3–4. -Do NOT re-ask for the **engine, version or language** — reuse those decisions. - -> **That is not a blanket "never ask".** `rendering` and `physics` below depend on -> two further inputs — target platform and 2D-vs-3D — which **Section 2 collects on -> only one of the four entry paths**. When they were never collected, ask; the -> unavailable-branch under the project-shape table says how. - -**`engine` block:** - -```yaml -engine: - name: "" - version: "" - language: "" - rendering: "" - physics: "" -``` - -**On Godot these two values depend on the answers Section 2 already collected — -the target platform and 2D-vs-3D — so do not pick them from the engine name -alone.** On Unity and Unreal the table has a single `any` row and the engine name -*is* sufficient; take those rows directly. - -| Engine | Project shape | `rendering` default | `physics` default | -|--------|---------------|---------------------|-------------------| -| Godot 4.x | 2D · web target | Compatibility | Godot Physics 2D | -| Godot 4.x | 2D · non-web | Forward+ | Godot Physics 2D | -| Godot 4.x | 3D · web target | Compatibility | Jolt | -| Godot 4.x | 3D · non-web | Forward+ | Jolt | -| Unity | any | URP | PhysX | -| Unreal | any | Lumen + Nanite (deferred) | Chaos | - -> **Why this table has a shape column and the others do not.** Both Godot -> defaults were wrong for a 2D browser game, and both were wrong from data this -> skill had already collected and then discarded. -> - **Jolt is Godot's default *3D* engine.** `docs/engine-reference/godot/modules/physics.md`: -> "Jolt Physics is the DEFAULT 3D engine" and "2D physics UNCHANGED (still -> Godot Physics 2D)". Writing `Jolt` on a 2D project sends the implementer to -> tune a backend their game does not use. -> - **Forward+ is desktop-focused.** `docs/engine-reference/godot/modules/rendering.md`: -> Forward+ is "Full featured, desktop-focused"; Compatibility is -> "OpenGL 3.3 / WebGL 2, broadest hardware support" — the browser path. -> -> If Section 2's platform answer was `Multiple platforms` **including** web, use -> the web row: the renderer must work everywhere the game ships. - -> **Godot only — Unity and Unreal have one row each, keyed `any`.** Shape cannot -> change `rendering` or `physics` for those two, so do **not** run the resolution -> below for them: asking an operator a question whose answer you will discard is -> exactly what §5.5.1 opens by forbidding. On Unity write `URP`/`PhysX` and on -> Unreal write `Lumen + Nanite (deferred)`/`Chaos` straight from the table. -> -> **Section 2 did not necessarily run — check before reading its answers.** -> Target platform and 2D-vs-3D are collected under *Questions 2–6, only if no -> prior engine experience*. **Three of the four entry paths never reach them:** -> `/setup-engine ` and `/setup-engine ` skip Section 2 -> outright, and guided mode skips the matrix as soon as the user names an engine -> they have worked in before. Only guided mode answered `None` or `Multiple` -> collects both. -> -> Resolve each input in this order and stop at the first that answers: -> 1. **Section 2's answers**, if that path ran. -> 2. **The design artifact** — `design/gdd/game-concept.md` at `standard`/`full`, -> `design/game-brief.md` at `minimal`. Section 2 already extracts platform -> targets from these; extract 2D-vs-3D the same way when it is stated. -> 3. **Ask.** Do not infer the shape from the engine name, and do not write a row -> you could not justify: -> - Prompt: "`rendering` and `physics` depend on the project's shape, which -> hasn't been established yet. Is this 2D or 3D, and does it ship to web?" -> - Options: `2D · non-web` / `2D · web` / `3D · non-web` / `3D · web`, plus -> `Leave as [TO BE CONFIGURED]` — a legitimate answer here, revisited via -> `/settings` once the concept exists. -> -> `[TO BE CONFIGURED]` is a valid value for both keys. A wrong `Jolt` on a 2D -> project is worse than an unset one, because nothing downstream questions it. - -- `rendering` and `physics` are engine-typical defaults — tell the user they can - be changed later via `/settings` if the project uses a different setup. -- For Godot **Both**, write `language: "GDScript"` (the primary gameplay - language); the C# usage is recorded in `technical-preferences.md`. -- For Unreal, write `language: "C++"` — or `"Blueprint"` only if the project is - Blueprint-primary. Blueprint as a secondary tool does not change this value. - -**`specialists` block** — copy directly from the routing table chosen in -Section 5 (**A3** in `.claude/skills/setup-engine/references/godot-language-config.md` for Godot): - -| Engine / language | `code` | `shader` | `ui` | `additional` | -|-------------------|--------|----------|------|--------------| -| Godot — GDScript | godot-gdscript-specialist | godot-shader-specialist | godot-specialist | [godot-gdextension-specialist] | -| Godot — C# | godot-csharp-specialist | godot-shader-specialist | godot-specialist | [godot-gdextension-specialist] | -| Godot — Both | godot-gdscript-specialist | godot-shader-specialist | godot-specialist | [godot-csharp-specialist, godot-gdextension-specialist] | -| Unity | unity-specialist | unity-shader-specialist | unity-ui-specialist | [unity-dots-specialist, unity-addressables-specialist] | -| Unreal | unreal-specialist | unreal-specialist | ue-umg-specialist | [ue-gas-specialist, ue-blueprint-specialist, ue-replication-specialist] | - -```yaml -specialists: - code: "" - shader: "" - ui: "" - additional: ["<...>"] -``` - -**`naming` block** — enum values (NOT the prose form used in -`technical-preferences.md`). Use the column matching the engine and, for Godot, -the language: - -| Field | Godot GDScript | Godot C# | Unity | Unreal | -|-------|----------------|----------|-------|--------| -| `classes` | PascalCase | PascalCase | PascalCase | PascalCase | -| `variables` | snake_case | camelCase | camelCase | **PascalCase** | -| `constants` | SCREAMING_SNAKE | PascalCase | SCREAMING_SNAKE | SCREAMING_SNAKE | -| `signals` | past_tense | on_event_name | **PascalCase `On`** | **PascalCase `On`** | -| `files` | snake_case | PascalCase | PascalCase | PascalCase | -| `scenes` | snake_case | PascalCase | PascalCase | PascalCase | - -> **The Unreal column is sourced, not inherited from the table's generic shape.** -> `variables: camelCase` and `signals: on_event_name` are the two rows that shape -> would produce, and both are wrong for Unreal. Checked against this repo's -> pinned reference: `docs/engine-reference/unreal/` contains **zero** camelCase -> variable declarations and uses PascalCase throughout (`int32 Health;`, -> `FVector ServerPosition;`), and the word "signal" **never appears in it at all** — -> it is Godot vocabulary. Unreal has delegates and events, and the reference's -> handlers are PascalCase `On`. -> -> Two caveats kept rather than smoothed over. (1) `classes: PascalCase` is -> **incomplete** for Unreal, not wrong: UE requires a mandatory type prefix -> (`U`/`A`/`F`/`E`/`I`/`T`) that this enum cannot express, so an Unreal project's -> coding standards must state it separately. (2) `scenes` is a **category -> mismatch** — Unreal has Levels and Maps under World Partition, not scenes — left -> in place because the key is shared across engines and renaming it is a schema -> change, not a value fix. -> -> The blast radius is limited: `naming.*` is currently a -> **documented-but-unread** setting, so wrong values misinform a human reading -> `project.yaml` rather than driving any automated check — today. That is a -> reason to get them right now, while it is cheap. - -> **Three further rules for this table.** -> -> **The Unity `build` row must not hardcode `-buildTarget StandaloneLinux64`.** -> A hardcoded target gives every Unity project a **Linux** build command, whatever -> platform it actually ships on. The row reads ``: **ask the operator for -> the build target and write the value they give.** The correct `-buildTarget` identifiers -> are not sourceable from `docs/engine-reference/unity/`, so this skill must not -> emit one from recall — the same call made for `/security-audit`'s save -> patterns and for Unity's release dates. A wrong-but-plausible default is worse -> than an explicit question: it produces a `commands.build` that runs, succeeds, -> and builds the wrong artifact. -> -> **`-buildTarget` alone builds nothing.** It switches the active platform and -> exits 0 (verified on 6000.3.23f1). The row also needs a player-build flag, -> `-buildPlayer ` — for Windows 64-bit, -> `-buildWindows64Player Builds/Win64/.exe` (verified: exit 0 and an -> `.exe`; exit 1 on a compile error or when no scene is in the build settings). -> Ask which platform, and confirm any other platform's flag against Unity's -> command-line documentation rather than recalling one. -> -> **The Godot `build` row must not hardcode `'Linux/X11'` either — same defect, -> same remedy.** A Godot export preset name is **project-defined**: it is whatever -> string the operator typed into `export_presets.cfg`, and the shipped defaults are -> per-platform (`Windows Desktop`, `macOS`, `Web`, `Linux/X11`). Writing -> `'Linux/X11'` gives a Windows-targeting project a build command that fails with -> `Unknown export preset`, and gives a project that *does* have a Linux preset a -> command that silently builds the wrong platform. The row reads ``: -> **ask the operator which export preset to build and write the value they give**, -> exactly as the Unity row does. If no presets exist yet — common, since -> `/setup-engine` usually runs before the Godot project has any — write -> `[TO BE CONFIGURED]` and say so, rather than guessing a name that does not exist. -> -> **The `constants` row must not contradict this skill's own prose.** The table says -> `SCREAMING_SNAKE` for Unity; the Unity section of this same file says -> "Constants: PascalCase or UPPER_SNAKE_CASE". Both cannot be authoritative, and -> an agent following one produces config the other rejects. The row is **left -> unchanged pending sourcing** rather than picked by preference — neither -> `docs/engine-reference/unity/` nor `unreal/` contains a SCREAMING_SNAKE constant -> to confirm or refute it, and the Unreal run flagged the same row as wrong for -> Unreal on the same grounds. Resolve by adding a naming section to the engine -> references, then correct table and prose together. Until then, treat -> `naming.constants` as unverified for Unity and Unreal. -> -> **Write that caveat into `project.yaml`, do not leave it here.** On Unity and -> Unreal, emit the `constants` line with a trailing comment: -> ```yaml -> naming: -> constants: SCREAMING_SNAKE # UNVERIFIED — not sourceable from -> # docs/engine-reference//; confirm before relying on it -> ``` -> Without it, a value the skill *knows* is unsourced is recorded as flatly as -> `classes: PascalCase`, which is sourced, and the reader of the primary config -> store cannot tell them apart. The `commands` block nine lines below already does -> exactly this with its `# TODO: confirm these` line — this is the same pattern, -> applied to the value that needs it just as much. - -For Godot **Both**, use the GDScript column — `.gd` files dominate gameplay -scripting; `.cs` files follow C# conventions per-file (see **A2** in `.claude/skills/setup-engine/references/godot-language-config.md`). - -```yaml -naming: - classes: - variables: - constants: - signals: - files: - scenes: -``` - -**`commands` block** — engine-default shell commands, simple-string form: - -| Engine | `build` | `test` | `run` | `smoke` | -|--------|---------|--------|-------|---------| -| Godot | `godot --headless --export-debug ''` **(ASK — do not default)** | `godot --headless -s -d --remote-debug tcp://127.0.0.1:0 res://addons/gdUnit4/bin/GdUnitCmdTool.gd -a res://tests --ignoreHeadlessMode` | `godot --path . --windowed --resolution 1280x720` | `godot --headless --quit-after 5` | -| Unity | `"" -batchmode -quit -projectPath . -buildTarget -buildPlayer Builds//.exe` **(ASK — do not default)** | `"" -batchmode -runTests -projectPath . -testPlatform EditMode -testResults test-results/editmode.xml` | `Builds//.exe -screen-width 1280 -screen-height 720 -screen-fullscreen 0` | `"" -batchmode -quit -projectPath . -logFile -` | - -> **What each exit code proves — every row verified on the pinned engines.** -> Godot `test` exits 0 when all pass, 100 on a failure, 101 when all pass but -> nodes leaked (a warning, not a failure), 105 when a test script does not -> parse, and 103 / 104 when gdUnit4 cannot run at all (headless refused, Godot -> older than 4.3). Keep `--remote-debug tcp://127.0.0.1:0`: without it a script -> error opens Godot's interactive debugger and the run waits at a `debug>` -> prompt forever instead of exiting. Run `godot --headless --path . --import` -> before it on a fresh clone: with no `.godot/` class cache, -> `GdUnitCmdTool.gd` did not load and the run exits 1 having run nothing. Unity `test` -> exits 0 / 2, and a results file with `testcasecount="0"` means no test was -> compiled — not a pass. It runs Edit Mode only: Play Mode tests under -> `Assets/Tests/PlayMode/` need a second run into their own results file -> (`-testPlatform PlayMode -testResults test-results/playmode.xml`), which -> `/smoke-check` makes whenever that folder holds tests and CI runs as its own -> step. Unity `smoke` exits 1 on a compile error, 0 when clean. -> **Godot `smoke` exits 0 even on a parse error** — it is a boot check: read its -> output for `SCRIPT ERROR`. It also needs `run/main_scene` set: without one it -> prints `Can't run project: no main scene defined` and never exits, so run it -> under a timeout. Unity `smoke` compiles only the editor-side assemblies; an -> error that exists only in a player build (an `Editor/` script without its own -> assembly) shows up in `build`, not here. The real Godot parse check is -> `godot --headless --path . --import`, then -> `godot --headless --path . -s res://.claude/scripts/godot-parse-check.gd -- res://.gd …` -> (exit 1 when a script does not load). `--check-only` is not one: it fails -> valid code that names an autoload. `` is the **editor** -> executable's full path, quoted. Never write bare `Unity`: on `PATH` that name -> may be Unity's separate CLI, which rejects `-batchmode` with exit 2 — the same -> code as a failed test. - -> **`commands.run` is the one the run-and-observe step depends on.** It must -> launch the **game**, windowed, at a fixed resolution — never the editor, and -> never with a headless / batch / null-RHI flag, which exist to skip rendering. -> `/dev-story` Phase 6 step 4 appends the per-engine capture flags to it -> (`.claude/docs/run-and-observe.md`). `smoke` is Unity's parse check, `test` -> feeds `/smoke-check`; `build` is the one row you must ask for. - -> **YAML quoting rule — applies to EVERY command value.** `yaml-helper.sh` — the -> parser every config read in this framework goes through — decodes **no** -> escape sequences: neither `\"` inside a double-quoted scalar nor `''` inside a -> single-quoted scalar. It takes the first matching quote character as the end of -> the value and discards the rest, so `"he said \"hi\" now"` parses as -> `he said \`. Verified against the parser, not inferred. The rule is -> load-bearing: `/smoke-check` and `/dev-story` run these values, `/settings` -> reads and writes them through this parser, and the same holds for every other -> quoted value in `project.yaml`. -> Pick the quote style that needs **no escaping**: -> - value contains a single quote `'` (e.g. the Godot `build` above) → wrap it in -> a **double-quoted** YAML scalar: `"... 'Linux/X11' ..."` -> - value contains a double quote `"` (e.g. the Unreal `test`/`smoke` below) → -> wrap it in a **single-quoted** YAML scalar: `'... "Quit" ...'` -> - value contains neither → use a double-quoted scalar for consistency. -> Never use a quote style that forces an escape (`\"` or `''`) — the parser -> truncates the value at the escape. A value containing BOTH quote types cannot -> be represented for this parser; rewrite the command to drop one. - -**Godot / Unity** — write the table values directly, substituting the operator's -answer for `` / `` / ``, and the editor's full path for -``. Godot's `build` contains a single quote, so it -takes a double-quoted scalar (`Windows Desktop` below is the *example* answer, not -a default — write what the operator said): - -```yaml -commands: - build: "godot --headless --export-debug 'Windows Desktop'" - test: "godot --headless -s -d --remote-debug tcp://127.0.0.1:0 res://addons/gdUnit4/bin/GdUnitCmdTool.gd -a res://tests --ignoreHeadlessMode" - run: "godot --path . --windowed --resolution 1280x720" - smoke: "godot --headless --quit-after 5" -``` - -**Write bare `godot` only when Section 3's `godot --version` ran** — that is, -`godot` is on `PATH`. Otherwise (the usual case on Windows and macOS) -substitute the executable the probe found or the user gave — a Windows -`Godot_v-stable_win64.exe`, macOS `/Applications/Godot.app/Contents/MacOS/Godot` -— as its full path, in double quotes, for the leading `godot` in all four -values, exactly as `` is. The value then holds double quotes, so it -takes a single-quoted scalar, and `build` quotes its preset with double quotes -too, so no value holds both quote types. Godot not on PATH, installed under -`C:/Program Files/Godot/`: - -```yaml -commands: - build: '"C:/Program Files/Godot/Godot_v4.6.1-stable_win64.exe" --headless --export-debug "Windows Desktop"' - test: '"C:/Program Files/Godot/Godot_v4.6.1-stable_win64.exe" --headless -s -d --remote-debug tcp://127.0.0.1:0 res://addons/gdUnit4/bin/GdUnitCmdTool.gd -a res://tests --ignoreHeadlessMode' - run: '"C:/Program Files/Godot/Godot_v4.6.1-stable_win64.exe" --path . --windowed --resolution 1280x720' - smoke: '"C:/Program Files/Godot/Godot_v4.6.1-stable_win64.exe" --headless --quit-after 5' -``` - -If the probe found no executable and the user does not know where it is, keep -bare `godot`, put `# TODO: godot is not on PATH here — set the editor's full -path via /settings` above the block, and say so: those commands will not run -until one of the two is fixed. - -For Unity, probe the Hub install (`C:/Program Files/Unity/Hub/Editor//Editor/Unity.exe` -on Windows, `/Applications/Unity/Hub/Editor//Unity.app/Contents/MacOS/Unity` -on macOS, `/home//Unity/Hub/Editor//Editor/Unity` on Linux) or ask. -Write the expanded absolute path — a `~` inside quotes is not expanded, and the -command then exits 127. The -quoted path puts double quotes in the command, so the value takes a -single-quoted scalar: - -```yaml -commands: - test: '"C:/Program Files/Unity/Hub/Editor/6000.3.23f1/Editor/Unity.exe" -batchmode -runTests -projectPath . -testPlatform EditMode -testResults test-results/editmode.xml' - smoke: '"C:/Program Files/Unity/Hub/Editor/6000.3.23f1/Editor/Unity.exe" -batchmode -quit -projectPath . -logFile -' -``` - -> **Also write `engine.path` if the editor is not on `PATH`.** Agents and -> `/smoke-check` read it to find the editor, but a command is run as written — -> `engine.path` is never spliced into `commands.*` at run time, which is why the -> full path goes into the commands above — and on Windows and macOS none of -> the three engines installs onto `PATH` by default (on macOS the editor is inside an app -> bundle, e.g. `/Applications/Godot.app/Contents/MacOS/Godot`). Ask for or probe the -> install location and record it — the editor executable for Godot and Unity, -> the engine folder (``) for Unreal: -> -> ```yaml -> engine: -> path: "C:/Program Files/Epic Games/UE_5.7" # omit if the editor is on PATH -> ``` -> -> **This is not cosmetic.** Without it, an agent reports *"no editor on this -> machine"* and ships C++ it never compiled — on a machine where that engine WAS -> installed. Nothing in the project told it where to look, so absence of a path read -> as absence of an engine. - -For **Unreal**, UE build/test commands vary by version and project setup. Write -best-effort values and add a `# TODO` comment so the user knows to confirm them. -Substitute the engine's install folder for `` (the value you record as -`engine.path`) — none of the editor binaries is on `PATH`. The commands embed -double quotes, so they take single-quoted scalars. Write the block for the -machine the project is developed on (`uname -s`: `Linux`, `Darwin` = macOS, -anything else = Windows). The Windows block was run on UE 5.7; the Linux and -macOS lines come from Epic's documentation, recorded with their sources in -`docs/engine-reference/unreal/current-best-practices.md` ("Command Line"). - -Windows: - -```yaml -commands: - # TODO: confirm these for your UE version and project — adjust via /settings - build: '"/Engine/Binaries/DotNET/AutomationTool/AutomationTool.exe" BuildCookRun -project="$(pwd -W 2>/dev/null || pwd)/.uproject" -platform=Win64 -build -cook' - test: '"/Engine/Binaries/Win64/UnrealEditor-Cmd.exe" "$(pwd -W 2>/dev/null || pwd)/.uproject" -ExecCmds="Automation RunTests .; Quit" -unattended -nullrhi -stdout -FullStdOutLogOutput' - run: '"/Engine/Binaries/Win64/UnrealEditor.exe" "$(pwd -W 2>/dev/null || pwd)/.uproject" -game -windowed -ResX=1280 -ResY=720' - smoke: '"/Engine/Binaries/Win64/UnrealEditor-Cmd.exe" "$(pwd -W 2>/dev/null || pwd)/.uproject" -game -nullrhi -unattended -stdout -ExecCmds="Quit"' -``` - -Linux — the editor binary is `Engine/Binaries/Linux/UnrealEditor`, the build -scripts are shell scripts: - -```yaml -commands: - # TODO: confirm these for your UE version and project — adjust via /settings - build: '"/Engine/Build/BatchFiles/RunUAT.sh" BuildCookRun -project="$(pwd -W 2>/dev/null || pwd)/.uproject" -platform=Linux -build -cook' - test: '"/Engine/Binaries/Linux/UnrealEditor" "$(pwd -W 2>/dev/null || pwd)/.uproject" -ExecCmds="Automation RunTests .; Quit" -unattended -nullrhi -stdout -FullStdOutLogOutput' - run: '"/Engine/Binaries/Linux/UnrealEditor" "$(pwd -W 2>/dev/null || pwd)/.uproject" -game -windowed -ResX=1280 -ResY=720' - smoke: '"/Engine/Binaries/Linux/UnrealEditor" "$(pwd -W 2>/dev/null || pwd)/.uproject" -game -nullrhi -unattended -stdout -ExecCmds="Quit"' -``` - -macOS — only the build is sourced. Epic documents the `UnrealEditor.app` -bundle but no command-line editor inside it, so write `build` and leave the -other three as TODO lines rather than a guessed path; `/smoke-check` reports -NOT ASSESSED for tests until the user sets `commands.test`: - -```yaml -commands: - # TODO: confirm this for your UE version and project — adjust via /settings - build: '"/Engine/Build/BatchFiles/RunUAT.sh" BuildCookRun -project="$(pwd -W 2>/dev/null || pwd)/.uproject" -platform=Mac -build -cook' - # TODO: test, run and smoke — no documented command-line editor on macOS. - # Set them via /settings to the editor command you run for this project. -``` - -On Windows, `build` calls AutomationTool directly: from Git Bash, `RunUAT.bat` fails -(`'C:\Program' is not recognized`) whenever the project path has a space. -AutomationTool.exe runs on the machine's .NET 8 runtime; `RunUAT.bat` brings -its own SDK, so with no space in the path and no .NET 8 installed, use it. -`-build` builds the editor target too (verified on 5.7). - -**Three details are load-bearing.** The project path is absolute: UE 5.7 -does not find a relative `.uproject` and exits 1 (`Project file not -found`) before anything runs. `$(pwd -W 2>/dev/null || pwd)` gives the `C:/…` -form in Git Bash and the plain path elsewhere, run from the project root; -`$PWD` alone fails when `MSYS_NO_PATHCONV` is set. `smoke` needs `-game`: without it -`UnrealEditor-Cmd` boots the *editor*, where a bare `Quit` console command only -ends a play-in-editor session — the process stays resident and the command -never returns; with `-game` the same line boots headless and exits in seconds. -`test` needs the `; Quit` inside the `Automation` string: the automation -runner handles that trailing `Quit` itself and exits the editor once the tests -finish, and without it the run also never returns. Its filter runs every test -whose full name *contains* `.` — a substring match, not a prefix — so -name tests `.[System].[Scenario]` as `qa-tester` does. If the -project's name is also an engine area — `Audio`, `Core`, `Input`, `Test`, -`System`, `Engine`, `Editor`, `AI`, `Math` — `.` also runs hundreds -to thousands of the engine's own tests; give the tests a distinct root (say -`Game.`) and put the same root in the filter. This form exits 255 on -a failing test AND on a filter that matches nothing (`No automation tests -matched`, verified on 5.7), so `/smoke-check` reads the output, not the exit -code. `smoke` carries `-stdout` for the same reason: without it a failed boot -prints nothing. Do not swap in -`-TestExit="Automation Test Queue Empty"`: that form exits **0** on a failing -test unless its report JSON is parsed. - -### 5.5.2 Write the blocks to `project.yaml` - -Show the user the full set of four blocks and ask: - -> "May I write the `engine`, `specialists`, `naming`, and `commands` blocks to `project.yaml`?" - -Wait for confirmation, then apply based on the file's current state: - -- **`project.yaml` does not exist** — create it with the Write tool using this - v1.1 template (the four blocks appended after `framework`; replace `<...>` and - the date): - - ```yaml - # CCGS project configuration — single source of truth for project settings. - # Schema: grep the `## ` section of .claude/docs/effects-map.md — - # it is ~31k tokens whole, ~900 per section. Do not open it entire. - - schema_version: 1 - - framework: - version: 1.1.2 - last_upgraded: - - engine: - name: "<...>" - version: "<...>" - language: "<...>" - rendering: "<...>" - physics: "<...>" - - specialists: - code: "<...>" - shader: "<...>" - ui: "<...>" - additional: ["<...>"] - - naming: - classes: <...> - variables: <...> - constants: <...> - signals: <...> - files: <...> - scenes: <...> - - commands: - build: "<...>" - test: "<...>" - run: "<...>" - smoke: "<...>" - ``` - - Do not seed `modes.review_mode` here. It is a rigor-fronted knob — `modes.rigor` - supplies its value, so an explicit value would shadow the rigor expansion and pin - the review mode regardless of the project's rigor. - -- **`project.yaml` exists** — Read it first (the Edit tool requires the file to - have been read this session), then, processing the blocks in the order - `engine` → `specialists` → `naming` → `commands`, for each block: - - **Block absent** — insert the whole block, appended after the last existing - top-level block. - - **Block already present** (a re-run of `/setup-engine`) — Edit the existing - keys in place, and add any keys the block is missing (a partial block must - end up with its full key set). Do NOT add a second copy of the block. - -**Unreal on macOS is the exception in both cases:** `commands.test`, `run` and -`smoke` are written as the TODO comment lines from the macOS block — never as -`<...>` placeholders or a guessed path — and a re-run leaves them unset until the -user sets them. - -Preserve all other content in `project.yaml` (`schema_version`, `framework`, -`modes`, `project`, etc.) — only the four blocks are touched. - -### 5.5.3 Verify the dual-write - -Read `project.yaml` back and confirm the four blocks are present and that -`engine.name`, `engine.language`, and the naming values match what was written -to `technical-preferences.md`. If they diverge, report the discrepancy to the -user and stop — a split config corrupts skill and hook reads. - ---- +**Read `references/5.5-project-yaml.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 6. Determine Knowledge Gap -Check whether the engine version is likely beyond the LLM's training data. - -**Known approximate coverage** — the same figures the shipped -`docs/engine-reference/*/VERSION.md` files record: -- LLM knowledge cutoff: **May 2025** -- Godot: training data likely covers up to ~4.3 -- Unity: training data likely covers up to ~2022 LTS (2022.3) -- Unreal: training data likely covers up to ~5.3 - -> **This table goes stale silently, and a stale table fails in the dangerous -> direction only if it is too *new*.** A cutoff left unchanged for a year after -> it stopped being true over-classifies risk — safe, but every project then pays -> for full reference docs it may not have needed. -> The opposite error is the harmful one: a cutoff claimed *later* than the model's -> actual one marks post-cutoff versions LOW RISK and suppresses the reference -> docs that exist to stop invented APIs. -> -> **If the model running this skill states an earlier training cutoff than the -> one above, do not trust the table.** Say so, and treat the engine version as -> `HIGH RISK` regardless of the comparison — a cutoff the model does not have is -> not a cutoff that was met. - -Compare the user's chosen version against these baselines: - -- **Within training data** → `LOW RISK` — reference docs optional but recommended -- **Near the edge** → `MEDIUM RISK` — reference docs recommended -- **Beyond training data** → `HIGH RISK` — reference docs required - -Inform the user which category they're in and why. - ---- +**Read `references/6-knowledge-gap.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 7. Populate Engine Reference Docs -### First: does a reference set already exist for this engine? - -**Check before doing anything else.** The template ships -`docs/engine-reference/godot/`, `unity/` and `unreal/` **already populated**, so -"the directory exists and pins a version" is the state of *every* fresh project, -not an edge case. Both branches below say "create", and following either one -literally on a pre-populated directory either overwrites curated content or -leaves `project.yaml` and the CLAUDE.md-imported reference disagreeing. - -Read `docs/engine-reference//VERSION.md` and compare its -**Engine Version** to the version chosen in Section 3: - -- **No directory, or no `VERSION.md`** → create, using the risk branch below. -- **Same version** → nothing to regenerate. Refresh `Last Docs Verified` only if you - actually re-verified against the docs this run. Do not restamp a date you did - not check. The one row still written is `Installed at pin time`, from - Section 3 — its probe result is recorded whatever the outcome, after asking - "May I record `Installed at pin time: [result]` in - `docs/engine-reference//VERSION.md`?" (it is a tracked file). -- **Directory pins an OLDER version than the one chosen** → **update, do not - replace.** This is the common case. Show the changes below, then ask "May I - update the `docs/engine-reference//` files for [version]?" before editing. - 1. Edit `VERSION.md` in place: new **Engine Version**, new **Project Pinned** - and **Last Docs Verified**, the `Installed at pin time` row from Section 3, - and a new row in the post-cutoff timeline for each version added. - 2. **Append** to `breaking-changes.md`, `deprecated-apis.md` and - `current-best-practices.md` under a heading naming the version span - (`## 4.6 → 4.7`). Never truncate the older spans — a project migrating - across two versions still needs the earlier one. - 3. Re-grade the older timeline rows if the cutoff moved past them. -- **Directory pins a NEWER version than the one chosen** → stop and ask. Someone - pinned forward deliberately, or the version choice is wrong. Do not silently - downgrade a curated reference. - -### Sourcing rule for everything written in this section - -**Never fill a gap from training data. Write the gap down instead.** - -The whole purpose of these files is to be the thing agents consult *instead of* -their training data. A confidently wrong entry here is worse than no entry: it -produces work that looks verified and is not. - -- Every claim must come from a page you fetched this run. Record the URL. -- If the official docs do not state something the template asks for — a release - date, a subsystem's behaviour, web-export specifics — write - **`NOT SOURCEABLE — , not stated at `** and move on. -- A `NOT SOURCEABLE` line is a successful outcome, not a failure to finish. -- Do not infer one fact from an adjacent one. "The migration guide lists no - physics change" is not "the physics default is unchanged"; if you record the - inference, label it as an inference and name what it rests on. - -### If WITHIN training data (LOW RISK): - -Ask: "May I create `docs/engine-reference//VERSION.md`?" Wait for -confirmation, then create this minimal file: - -```markdown -# [Engine] — Version Reference - -| Field | Value | -|-------|-------| -| **Engine Version** | [version] | -| **Project Pinned** | [today's date] | -| **Installed at pin time** | [Section 3 result — the installed version, or NOT DETERMINED] | -| **LLM Knowledge Cutoff** | [the cutoff from the Section 6 coverage table] | -| **Risk Level** | LOW — version is within LLM training data | - -## Note - -This engine version is within the LLM's training data. Engine reference -docs are optional but can be added later if agents suggest incorrect APIs. - -Run `/setup-engine refresh` to populate full reference docs at any time. -``` - -Do NOT create breaking-changes.md, deprecated-apis.md, etc. — they would -add context cost with minimal value. - -### If BEYOND training data (MEDIUM or HIGH RISK): - -Create the full reference doc set by searching the web: - -1. **Search for the official migration/upgrade guide**: - - `"[engine] [old version] to [new version] migration guide"` - - `"[engine] [version] breaking changes"` - - `"[engine] [version] changelog"` - - `"[engine] [version] deprecated API"` - -2. **Fetch and extract** from official documentation: - - Breaking changes between each version from the training cutoff to current - - Deprecated APIs with replacements - - New features and best practices - -Ask: "May I create the engine reference docs under `docs/engine-reference//`?" - -Wait for confirmation before writing any files. - -3. **Create the full reference directory**: - ``` - docs/engine-reference// - ├── VERSION.md # Version pin + knowledge gap analysis - ├── breaking-changes.md # Version-by-version breaking changes - ├── deprecated-apis.md # "Don't use X → Use Y" tables - ├── current-best-practices.md # New practices since training cutoff - └── modules/ # Per-subsystem references (create as needed) - ``` - -4. **Populate each file** using real data from the web searches, following - the format established in existing reference docs. Every file must have - a "Last verified: [date]" header. - -5. **For module files**: Only create modules for subsystems where significant - changes occurred. Don't create empty or minimal module files. - ---- +**Read `references/7-reference-docs.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 7.5 Scaffold the Engine Project -**Without this step the framework produces source files no engine can open.** -`/dev-story` writes `.gd`/`.cs`/`.cpp` under the resolved code root, and the `minimal` path -advertises "four steps to running code" — but nothing anywhere created a project -for the engine to load. Verified by grep across every skill: no `project.godot`, -no Unity project, no `.uproject` was ever written. The files were real and -orphaned. - -### Godot — write `project.godot` if one is absent - -**Never overwrite an existing `project.godot`.** If the file is already there, -say so and skip to Section 8 — the developer has a project and its settings are -theirs. - -Show the proposed file, then ask: *"May I create `project.godot` at the repo -root?"* On approval, write: - -```ini -config_version=5 - -[application] - -config/name="" -config/features=PackedStringArray("", "") - -[rendering] - -renderer/rendering_method="" -``` - -Fill it from decisions already made — do not ask again: - -| Field | Source | -|-------|--------| -| `config/name` | the brief's working title, else the repo directory name | -| `` | `engine.version` from Section 3, major and minor only (`4.7.2` → `4.7`) | -| `` / `` | the `rendering` value chosen in Section 5.5.1 — Compatibility → `"GL Compatibility"` / `gl_compatibility`; Forward+ → `"Forward Plus"` / `forward_plus`; Mobile → `"Mobile"` / `mobile` | - -**Leave `run/main_scene` unset.** There is no scene yet at engine-setup time. -Add a comment saying `/dev-story` or the developer sets it once a scene exists; -an empty project with no main scene opens fine in the editor. - -**Then verify, and report what the verification actually was.** If the engine -binary was found in Section 3, run its headless import -(`godot --headless --path . --import`) and report the result — read the output -for `ERROR`, because the import exits 0 even when something in the project -fails to load. If the binary was -not found, or its version differs from the pinned one, write -**`project.godot NOT VERIFIED — `**. The `config_version` and feature -strings are stable across Godot 4.x, but "stable in the versions I know" is not -the same as "checked against the version you pinned", and only the run -establishes the latter. - -### Unity and Unreal — instruct, do not fabricate - -A Unity project and an `.uproject` are editor-generated and span many files, -several of them binary or machine-specific. This repo cannot source their -correct contents, and a hand-written scaffold would be the exact failure -Section 7's sourcing rule forbids — something that looks finished and is quietly -wrong. - -Tell the user, in one short block, that CCGS does not create the project for -these engines and they should create it first: - -- **Unity** — create the project in Unity Hub at the repo root, choosing the - template matching the 2D/3D answer from Section 2, then re-run `/setup-engine`. -- **Unreal** — create the project in the Epic launcher or via `UnrealEditor`, - then re-run. - -Report the outcome in the Section 12 summary either way — created, already -present, or "not created, engine requires the editor" — so the user leaves this -skill knowing whether a runnable project exists. - -> **Deliberately not a `project.yaml` key.** An `engine.project_scaffolded` flag -> would be written here and read by nothing, which is a dead setting — the same -> writer-without-reader defect the config gates exist to catch. The filesystem is -> the source of truth: any skill that needs to know globs for `project.godot`, -> `*.uproject`, or `ProjectSettings/ProjectVersion.txt`. - ---- +**Read `references/7.5-scaffold.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 8. Verify the CLAUDE.md Import -**This import was already written in Section 4 — do not edit it again and do not -ask again.** Section 4 sets it as part of the same CLAUDE.md write, anchored to -the `ENGINE-REFERENCE-IMPORT` marker. This step only confirms the result. - -Read `CLAUDE.md` and confirm the line under the marker reads: - -```markdown -@docs/engine-reference//VERSION.md -``` - -with `` the engine just configured. If it still points at a different -engine, Section 4 did not complete — go back and finish it rather than patching -the line here. - -> **Why this is a check and not a second write.** Repeating the edit here with -> its own approval prompt would ask the user twice for one change, and the second -> ask would be for work already done. Locate the line by its marker, never by the -> `## Engine Version Reference` heading — the marker exists precisely so the line -> can still be found when the heading moves or is reworded. - ---- - -## 8.5 Read Back What You Just Wrote - -This section exists because prose did not hold. Section 5.5.1's rendering/physics -table already carries an emphatic, source-cited warning naming the two mistakes -most often made here -- and it is still entirely possible to make **both** of -them anyway, writing `Forward+` and `Jolt` for a 2D browser game. Section 3's -`Installed at pin time` row is just as easy to drop silently, because a missing -row leaves no trace. - -Neither is fixed by adding more instructions. They are fixed by verifying the -files after writing them: - -```bash -bash .claude/scripts/project-coherence.sh -``` - -It compares `project.yaml` against `docs/engine-reference//VERSION.md`, -against `project.godot`, and against the engine binary actually on PATH, and it -checks that the files `commands.build` and `commands.test` name exist. - -**Report every `[DIFFERS]` line to the user and resolve it before finishing.** -Each one means two files this skill just wrote disagree, or describe something -that is not there. - -**`[NOT CHECKED]` is not a pass.** Each such line names why a comparison could -not be made -- an absent binary, a missing `project.godot`. Say which ones -applied. A comparison that could not run has not established agreement. - -The script emits observations and never a verdict, per the convention in -CLAUDE.md. The judgement is yours and the user's. - ---- +**Read `references/8-verify.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 9. Update Agent Instructions @@ -1236,156 +106,11 @@ If invoked as `/setup-engine refresh`: ## 11. Upgrade Subcommand -If invoked as `/setup-engine upgrade [old-version] [new-version]`: - -### Step 1 — Read Current Version State - -Read `docs/engine-reference//VERSION.md` to confirm the current pinned -version, risk level, and any migration note URLs already recorded. If -`old-version` was not provided as an argument, use the pinned version from this -file. - -### Step 2 — Fetch Migration Guide - -Use WebSearch and WebFetch to locate the official migration guide between -`old-version` and `new-version`: - -- Search: `"[engine] [old-version] to [new-version] migration guide"` -- Search: `"[engine] [new-version] breaking changes changelog"` -- Fetch the migration guide URL from VERSION.md if one is already recorded, - or use the URL found via search. - -Extract: renamed APIs, removed APIs, changed defaults, behavior changes, and -any "must migrate" items. - -### Step 3 — Pre-Upgrade Audit - -Scan the **code root** (resolve per `.claude/docs/code-root-resolution.md`) for code that uses APIs known to be deprecated or changed in the -target version: - -- Use Grep to search for deprecated API names extracted from the migration - guide (e.g., old function names, removed node types, changed property names) -- List each file that matches, with the specific API reference found - -Present the audit results as a table: - -``` -Pre-Upgrade Audit: [engine] [old-version] → [new-version] -========================================================== - -Files requiring changes: - File | Deprecated API Found | Effort - --------------------------------- | -------------------------- | ------ - src/gameplay/player_movement.gd | old_api_name | Low - src/ui/hud.gd | removed_node_type | Medium - -Breaking changes to watch for: - - [change description from migration guide] - - [change description from migration guide] - -Recommended migration order (dependency-sorted): - 1. [system/layer with fewest dependencies first] - 2. [next system] - ... -``` - -If no deprecated APIs are found in the code root, report: "No deprecated API usage -found in the code root — upgrade may be low-risk." - -### Step 4 — Confirm Before Updating - -Ask the user before making any changes: - -> "Pre-upgrade audit complete. Found [N] files using deprecated APIs. -> Proceed with upgrading VERSION.md to [new-version]? -> (This will update the pinned version and add migration notes — it does NOT -> change any source files. Source migration is done manually or via stories.)" - -Wait for explicit confirmation before continuing. - -### Step 5 — Update VERSION.md - -After confirmation: - -1. Update `docs/engine-reference//VERSION.md`: - - `Engine Version` → `[new-version]` - - `Project Pinned` → today's date - - `Last Docs Verified` → today's date - - Re-evaluate and update the `Risk Level` and `Post-Cutoff Version Timeline` - table if the new version falls beyond the LLM knowledge cutoff - - Add a `## Migration Notes — [old-version] → [new-version]` section - containing: migration guide URL, key breaking changes, deprecated APIs - found in this project, and recommended migration order from the audit - -2. If `breaking-changes.md` or `deprecated-apis.md` exist in the engine - reference directory, append the new version's changes to those files. - -3. If `project.yaml` exists at the repo root and has an `engine` block, Read it - first, then update `engine.version` to `[new-version]` so the primary config - store stays in sync with VERSION.md. - -### Step 6 — Post-Upgrade Reminder - -After updating VERSION.md, output: - -``` -VERSION.md updated: [engine] [old-version] → [new-version] - -Next steps: -1. Migrate deprecated API usages in the [N] files listed above -2. Run /setup-engine refresh after upgrading the actual engine binary to - verify no new deprecations were missed -3. Run /architecture-review — the engine upgrade may invalidate ADRs that - reference specific APIs or engine capabilities -4. If any ADRs are invalidated, run /propagate-design-change to update - downstream stories -``` - ---- +**Read `references/11-upgrade.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 12. Output Summary -After setup is complete, output: - -``` -Engine Setup Complete -===================== -Engine: [name] [version] -Language: [GDScript | C# | GDScript + C# | C# | C++ + Blueprint | Blueprint + C++] -Knowledge Risk: [LOW/MEDIUM/HIGH] -Reference Docs: [created/skipped] -CLAUDE.md: [updated] -Tech Prefs: [created/updated] -project.yaml: [created/updated] -Agent Config: [verified] - -Next Steps: -1. Review docs/engine-reference//VERSION.md -``` - -Then print **one** Next-Steps list, matching the resolved `workflow` tier: - -**`minimal` — the lean 4-step floor (you are on step 1):** -``` -2. Run /brainstorm to produce your one-page design/game-brief.md (the lean-tier design artifact) -3. Run /create-stories to turn the brief's MVP list into stories -4. Run /dev-story — first line of game code -``` -(No `/map-systems`, `/design-system`, `/prototype`, or `/sprint-plan` at -`minimal` — the brief replaces the GDDs and its build order is the plan.) - -**`standard` / `full` — the full pipeline:** -``` -2. [If from /brainstorm] Run /map-systems to decompose your concept into individual systems -3. [If from /brainstorm] Run /design-system to author per-system GDDs (guided, section-by-section) -4. [If from /brainstorm] Run /prototype [core-mechanic] to validate the core idea before writing GDDs -5. [If fresh start] Run /brainstorm to discover your game concept -6. Create your first milestone: /sprint-plan new -``` - ---- - -Verdict: **COMPLETE** — engine configured and reference docs populated. +**Read `references/12-output-summary.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Guardrails @@ -1397,7 +122,7 @@ Verdict: **COMPLETE** — engine configured and reference docs populated. - If reference docs already exist for a different engine, ask before replacing - Always show the user what you're about to change before making CLAUDE.md edits - If WebSearch returns ambiguous results, show the user and let them decide -- When the user chose **GDScript**: copy the GDScript CLAUDE.md template from **A1** in `.claude/skills/setup-engine/references/godot-language-config.md` exactly. NEVER add "C++ via GDExtension" to the Language field. GDScript projects may use GDExtension, but it is not a primary project language. The `godot-gdextension-specialist` in the routing table is available for when native extensions are needed — it does not make C++ a project language. +- When the user chose **GDScript**: copy the GDScript CLAUDE.md template from **A1** in `references/godot-language-config.md` exactly. NEVER add "C++ via GDExtension" to the Language field. GDScript projects may use GDExtension, but it is not a primary project language. The `godot-gdextension-specialist` in the routing table is available for when native extensions are needed — it does not make C++ a project language. --- @@ -1406,7 +131,7 @@ Verdict: **COMPLETE** — engine configured and reference docs populated. Moved out of this file so it costs nothing on non-Godot runs. **When the chosen engine is Godot, read** -`.claude/skills/setup-engine/references/godot-language-config.md` +`references/godot-language-config.md` and use the subsection for the chosen language: - **A1** — CLAUDE.md Technology Stack templates (GDScript / C# / Both) diff --git a/.claude/skills/setup-engine/references/11-upgrade.md b/.claude/skills/setup-engine/references/11-upgrade.md new file mode 100644 index 00000000..14bc6842 --- /dev/null +++ b/.claude/skills/setup-engine/references/11-upgrade.md @@ -0,0 +1,122 @@ +# /setup-engine — Section 11: Upgrade Subcommand + +> Part of `/setup-engine`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 11. Upgrade Subcommand + +**In this file:** + +- Step 1 — Read Current Version State +- Step 2 — Fetch Migration Guide +- Step 3 — Pre-Upgrade Audit +- Step 4 — Confirm Before Updating +- Step 5 — Update VERSION.md +- Step 6 — Post-Upgrade Reminder + +If invoked as `/setup-engine upgrade [old-version] [new-version]`: + +### Step 1 — Read Current Version State + +Read `docs/engine-reference//VERSION.md` to confirm the current pinned +version, risk level, and any migration note URLs already recorded. If +`old-version` was not provided as an argument, use the pinned version from this +file. + +### Step 2 — Fetch Migration Guide + +Use WebSearch and WebFetch to locate the official migration guide between +`old-version` and `new-version`: + +- Search: `"[engine] [old-version] to [new-version] migration guide"` +- Search: `"[engine] [new-version] breaking changes changelog"` +- Fetch the migration guide URL from VERSION.md if one is already recorded, + or use the URL found via search. + +Extract: renamed APIs, removed APIs, changed defaults, behavior changes, and +any "must migrate" items. + +### Step 3 — Pre-Upgrade Audit + +Scan the **code root** (resolve per `.claude/docs/code-root-resolution.md`) for code that uses APIs known to be deprecated or changed in the +target version: + +- Use Grep to search for deprecated API names extracted from the migration + guide (e.g., old function names, removed node types, changed property names) +- List each file that matches, with the specific API reference found + +Present the audit results as a table: + +``` +Pre-Upgrade Audit: [engine] [old-version] → [new-version] +========================================================== + +Files requiring changes: + File | Deprecated API Found | Effort + --------------------------------- | -------------------------- | ------ + src/gameplay/player_movement.gd | old_api_name | Low + src/ui/hud.gd | removed_node_type | Medium + +Breaking changes to watch for: + - [change description from migration guide] + - [change description from migration guide] + +Recommended migration order (dependency-sorted): + 1. [system/layer with fewest dependencies first] + 2. [next system] + ... +``` + +If no deprecated APIs are found in the code root, report: "No deprecated API usage +found in the code root — upgrade may be low-risk." + +### Step 4 — Confirm Before Updating + +Ask the user before making any changes: + +> "Pre-upgrade audit complete. Found [N] files using deprecated APIs. +> Proceed with upgrading VERSION.md to [new-version]? +> (This will update the pinned version and add migration notes — it does NOT +> change any source files. Source migration is done manually or via stories.)" + +Wait for explicit confirmation before continuing. + +### Step 5 — Update VERSION.md + +After confirmation: + +1. Update `docs/engine-reference//VERSION.md`: + - `Engine Version` → `[new-version]` + - `Project Pinned` → today's date + - `Last Docs Verified` → today's date + - Re-evaluate and update the `Risk Level` and `Post-Cutoff Version Timeline` + table if the new version falls beyond the LLM knowledge cutoff + - Add a `## Migration Notes — [old-version] → [new-version]` section + containing: migration guide URL, key breaking changes, deprecated APIs + found in this project, and recommended migration order from the audit + +2. If `breaking-changes.md` or `deprecated-apis.md` exist in the engine + reference directory, append the new version's changes to those files. + +3. If `project.yaml` exists at the repo root and has an `engine` block, Read it + first, then update `engine.version` to `[new-version]` so the primary config + store stays in sync with VERSION.md. + +### Step 6 — Post-Upgrade Reminder + +After updating VERSION.md, output: + +``` +VERSION.md updated: [engine] [old-version] → [new-version] + +Next steps: +1. Migrate deprecated API usages in the [N] files listed above +2. Run /setup-engine refresh after upgrading the actual engine binary to + verify no new deprecations were missed +3. Run /architecture-review — the engine upgrade may invalidate ADRs that + reference specific APIs or engine capabilities +4. If any ADRs are invalidated, run /propagate-design-change to update + downstream stories +``` + +--- diff --git a/.claude/skills/setup-engine/references/12-output-summary.md b/.claude/skills/setup-engine/references/12-output-summary.md new file mode 100644 index 00000000..b84d69df --- /dev/null +++ b/.claude/skills/setup-engine/references/12-output-summary.md @@ -0,0 +1,48 @@ +# /setup-engine — Section 12: Output Summary + +> Part of `/setup-engine`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 12. Output Summary + +After setup is complete, output: + +``` +Engine Setup Complete +===================== +Engine: [name] [version] +Language: [GDScript | C# | GDScript + C# | C# | C++ + Blueprint | Blueprint + C++] +Knowledge Risk: [LOW/MEDIUM/HIGH] +Reference Docs: [created/skipped] +CLAUDE.md: [updated] +Tech Prefs: [created/updated] +project.yaml: [created/updated] +Agent Config: [verified] + +Next Steps: +1. Review docs/engine-reference//VERSION.md +``` + +Then print **one** Next-Steps list, matching the resolved `workflow` tier: + +**`minimal` — the lean 4-step floor (you are on step 1):** +``` +2. Run /brainstorm to produce your one-page design/game-brief.md (the lean-tier design artifact) +3. Run /create-stories to turn the brief's MVP list into stories +4. Run /dev-story — first line of game code +``` +(No `/map-systems`, `/design-system`, `/prototype`, or `/sprint-plan` at +`minimal` — the brief replaces the GDDs and its build order is the plan.) + +**`standard` / `full` — the full pipeline:** +``` +2. [If from /brainstorm] Run /map-systems to decompose your concept into individual systems +3. [If from /brainstorm] Run /design-system to author per-system GDDs (guided, section-by-section) +4. [If from /brainstorm] Run /prototype [core-mechanic] to validate the core idea before writing GDDs +5. [If fresh start] Run /brainstorm to discover your game concept +6. Create your first milestone: /sprint-plan new +``` + +--- + +Verdict: **COMPLETE** — engine configured and reference docs populated. diff --git a/.claude/skills/setup-engine/references/2-guided-mode.md b/.claude/skills/setup-engine/references/2-guided-mode.md new file mode 100644 index 00000000..e5e0ef9f --- /dev/null +++ b/.claude/skills/setup-engine/references/2-guided-mode.md @@ -0,0 +1,112 @@ +# /setup-engine — Section 2: Guided Mode + +> Part of `/setup-engine`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 2. Guided Mode (No Arguments) + +**In this file:** + +- Check for existing game concept +- If the user wants to pick without a concept, ask in this order +- Produce a recommendation + +If no engine is specified, run an interactive engine selection process: + +### Check for existing game concept +Read the design artifact for the resolved tier (see **Tier awareness** above): +- **`standard` / `full`**: read `design/gdd/game-concept.md` if it exists — + extract genre, scope, platform targets, art style, team size, and any engine + recommendation from `/brainstorm`. +- **`minimal`**: read `design/game-brief.md` if it exists — extract genre, + scope, platform, and art direction from its fields. Its absence is **expected** + at `minimal` (the brief is authored *after* engine setup in the minimal path), so + do not treat a missing brief as a gap — proceed straight to guided selection. +- If no concept **or** brief exists, inform the user: + > "No game concept found. Consider running `/brainstorm` first to discover what + > you want to build — it will also recommend an engine. Or tell me about your + > game and I can help you pick." + + (At `minimal` this is optional, not a prerequisite — you can pick an engine now + and write the brief next.) + +### If the user wants to pick without a concept, ask in this order: + +**Question 1 — Prior experience** (ask this first, always, via `AskUserQuestion`): +- Prompt: "Have you worked in any of these engines before?" +- Options: `Godot` / `Unity` / `Unreal Engine 5` / `Multiple — I'll explain` / `None of them` +- If they pick a specific engine → recommend that engine. Prior experience outweighs all other factors. Confirm with them and skip the matrix. +- If "None" or "Multiple" → continue to the questions below. + +**Questions 2-6 — Decision matrix inputs** (only if no prior engine experience): + +**Question 2 — Target platform** (ask this second, always, via `AskUserQuestion` — platform eliminates or heavily weights engines before any other factor): +- Prompt: "What platforms are you targeting for this game?" +- Options: `PC (Steam / Epic)` / `Mobile (iOS / Android)` / `Console` / `Web / Browser` / `Multiple platforms` +- Platform rules that feed directly into the recommendation: + - Mobile → Unity strongly preferred; Unreal is a poor fit; Godot is viable for simple mobile + - Console → Unity or Unreal; Godot console support requires third-party publishers or significant extra work + - Web → Godot exports cleanly to web; Unity WebGL is functional; Unreal has poor web support + - PC only → all engines viable; other factors decide + - Multiple → Unity is the most portable across PC/mobile/console + +1. **What kind of game?** (2D, 3D, or both?) +2. **Primary input method?** (keyboard/mouse, gamepad, touch, or mixed?) +3. **Team size and experience?** (solo beginner, solo experienced, small team?) +4. **Any strong language preferences?** (GDScript, C#, C++, visual scripting?) +5. **Budget for engine licensing?** (free only, or commercial licenses OK?) + +### Produce a recommendation + +Do NOT use a simple scoring matrix that eliminates engines. Instead, reason through the user's profile against the honest tradeoffs below, then present 1-2 recommendations with full context. Always end with the user choosing — never force a verdict. + +**Engine honest tradeoffs:** + +**Godot 4** +- Genuine strengths: 2D (best in class), stylized/indie 3D, rapid iteration, free forever (MIT), open source, gentlest learning curve, best for solo devs who want full control +- Real limitations: 3D ecosystem is thin compared to Unity/Unreal (fewer tutorials, assets, community answers for 3D-specific problems); large open-world 3D is very hard and largely untested in Godot; console export requires third-party publishers or significant extra work; smaller professional job market +- Licensing reality: Truly free with no revenue thresholds ever. MIT license means you own everything. +- Best fit: 2D games of any scope; stylized/atmospheric 3D; contained 3D worlds (not open-world); first game projects where learning curve matters; projects where budget is a hard constraint at any scale + +**Unity** +- Genuine strengths: Industry standard for mid-scope 3D and mobile; massive asset store and tutorial ecosystem; C# is a professional language; best console certification support for indie; strong community for almost every genre +- Real limitations: Licensing controversy in 2023 damaged trust (runtime fee was proposed then walked back — the risk of policy changes remains real); C# has a steeper initial curve than GDScript; heavier editor than Godot for simple projects +- Licensing reality: Free under $200K revenue AND 200K installs (Unity Personal/Plus). Only becomes costly if the game is genuinely successful — most indie games never hit this threshold. The 2023 controversy is worth knowing about but the actual current terms are reasonable for most indie developers. +- Best fit: Mobile games; mid-scope 3D; games targeting console; developers with C# background; projects needing large asset store; teams of 2-5 + +**Unreal Engine 5** +- Genuine strengths: Best-in-class 3D visuals (Lumen, Nanite, Chaos physics); industry standard for AAA and photorealistic 3D; large open-world support is mature and production-tested; Blueprint visual scripting lowers C++ barrier; strong for games targeting high-end PC or console +- Real limitations: Steepest learning curve; heaviest editor (slow compile times, large project sizes); overkill for stylized/2D/small-scope games; C++ is genuinely hard; not suitable for mobile or web; 5% royalty past $1M gross revenue +- Licensing reality: 5% royalty only applies AFTER $1M gross revenue per title. For a first game or any game that doesn't reach $1M, it costs nothing. This threshold is high enough that most indie developers will never pay it. +- Best fit: AAA-quality 3D; large open-world games; photorealistic visuals; developers with C++ experience or willing to use Blueprint; games targeting high-end PC/console where visual fidelity is a core selling point + +**Genre-specific guidance** (factor this into the recommendation): +- 2D any style → Godot strongly preferred +- 3D stylized / atmospheric / contained world → Godot viable, Unity solid alternative +- 3D open world (large, seamless) → Unity or Unreal; Godot is not production-proven for this +- 3D photorealistic / AAA-quality → Unreal +- Mobile-first → Unity strongly preferred +- Console-first → Unity or Unreal; Godot console support requires extra work +- Horror / narrative / walking sim → any engine; match to art style and team experience +- Action RPG / Soulslike → Unity or Unreal for 3D; community support and assets matter here +- Platformer 2D → Godot +- Strategy / top-down / RTS → Godot or Unity depending on 2D vs 3D + +**Recommendation format:** +1. Show a comparison table with the user's specific factors as rows +2. Give a primary recommendation with honest reasoning +3. Name the best alternative and when to choose it instead +4. Explicitly state: "This is a starting point, not a verdict — you can always migrate engines, and many developers switch between projects." +5. Use `AskUserQuestion` to confirm: "Does this recommendation feel right, or would you like to explore a different engine?" + - Options: `[Primary engine] (Recommended)` / `[Alternative engine]` / `[Third engine]` / `Explore further` / `Type something` + +**If the user picks "Explore further":** +Use `AskUserQuestion` with concept-specific deep-dive topics. Always generate these options from the user's actual concept — do not use generic options. Always include at minimum: +- The primary engine's specific limitations for this concept (e.g., "How far can Godot 3D actually go for [genre]?") +- The alternative engine's specific tradeoffs for this concept +- Language choice impact on this concept's technical challenges +- Any concept-specific technical concern (e.g., adaptive audio, open-world streaming, multiplayer netcode) + +The user can select multiple topics. Answer each selected topic in depth before returning to the engine confirmation question. + +--- diff --git a/.claude/skills/setup-engine/references/3-version.md b/.claude/skills/setup-engine/references/3-version.md new file mode 100644 index 00000000..1dc04bc4 --- /dev/null +++ b/.claude/skills/setup-engine/references/3-version.md @@ -0,0 +1,46 @@ +# /setup-engine — Section 3: Look Up Current Version + +> Part of `/setup-engine`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 3. Look Up Current Version + +Once the engine is chosen: + +- If version was provided, use it +- If no version provided, use WebSearch to find the latest stable release: + - Search: `"[engine] latest stable version [current year]"` + - Confirm with the user: "The latest stable [engine] is [version]. Use this?" + +### Check the chosen version against what is actually installed + +A version found by web search is what exists, not what the developer has. Pinning +one they cannot run means every later instruction — build, test, smoke, the +engine reference docs — targets an engine that is not on the machine. + +Probe for the binary (Bash), and treat failure as unknown, never as absent: + +| Engine | Probe | +|--------|-------| +| Godot | `godot --version`, else look for `godot`/`Godot_v*` on PATH or in the platform's usual install location (macOS: the binary inside the bundle, `Godot.app/Contents/MacOS/Godot`) | +| Unity | The Hub's editor directory, then that editor's `-version` — `C:/Program Files/Unity/Hub/Editor//Editor/Unity.exe` on Windows, `/Applications/Unity/Hub/Editor//Unity.app/Contents/MacOS/Unity` on macOS, `/home//Unity/Hub/Editor//Editor/Unity` on Linux. Not bare `Unity`: on `PATH` it may be Unity's separate CLI, which rejects `-version` | +| Unreal | The launcher's install directory (`UE_` folders under `C:/Program Files/Epic Games/` on Windows); elsewhere, ask where the engine was built or installed. The editor is not on `PATH` by default | + +Keep the executable the probe found (for Godot, whether bare `godot --version` +ran — that is, `godot` is on `PATH`): Section 5.5.1 writes it into `commands.*` +and `engine.path`. + +Then: +- **Match** — say so in one line and continue. +- **Mismatch** — state both versions and ask, offering three options: pin the + installed version, pin the newer one and upgrade later, or pin the newer one + deliberately. Record the answer; do not pick silently. +- **Not found / probe failed** — report `installed version NOT DETERMINED` and + continue with the chosen version. Do **not** report this as "no engine + installed": a probe that could not run has not established absence. + +Whatever the outcome, write it into Section 7's `VERSION.md` as an +`Installed at pin time` row, so a later reader can tell a deliberate +version-ahead pin from an accident. + +--- diff --git a/.claude/skills/setup-engine/references/4-claude-md-stack.md b/.claude/skills/setup-engine/references/4-claude-md-stack.md new file mode 100644 index 00000000..ae791656 --- /dev/null +++ b/.claude/skills/setup-engine/references/4-claude-md-stack.md @@ -0,0 +1,73 @@ +# /setup-engine — Section 4: Update CLAUDE.md Technology Stack + +> Part of `/setup-engine`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 4. Update CLAUDE.md Technology Stack + +### Language Selection (Godot only) + +If Godot was chosen, ask the user which language to use **before** showing the proposed Technology Stack: + +> "Godot supports two primary languages: +> +> **A) GDScript** — Python-like, Godot-native, fastest iteration. Best for beginners, solo devs, and teams coming from Python or Lua. +> **B) C#** — .NET 8+, familiar to Unity developers, stronger IDE tooling (Rider / Visual Studio), slight performance advantage on heavy logic. +> **C) Both** — GDScript for gameplay/UI scripting, C# for performance-critical systems. Advanced setup — requires .NET SDK alongside Godot. +> +> Which will this project primarily use?" + +Record the choice. It determines the CLAUDE.md template, naming conventions, specialist routing, and which agent is spawned for code files throughout the project. + +### Primary Language (Unreal) + +If Unreal was chosen, ask via `AskUserQuestion`: "Will most gameplay logic live in +C++ or in Blueprints?" — `[A] C++ (Blueprints for tuning and prototyping)` / +`[B] Blueprint-primary (C++ only where needed)`. Default to C++ if the user has no +preference. The answer sets `engine.language` (`"C++"` or `"Blueprint"`). + +--- + +Read `CLAUDE.md` and show the user the proposed Technology Stack changes. +Ask: "May I write these engine settings to `CLAUDE.md`?" + +Wait for confirmation before making any edits. + +Update the Technology Stack section, replacing the `[CHOOSE]` placeholders with the actual values: + +**For Godot** — use the template matching the language chosen above. See `references/godot-language-config.md` (**A1**) for all three variants (GDScript, C#, Both). + +**For Unity:** +```markdown +- **Engine**: Unity [version] +- **Language**: C# +- **Build System**: Unity Build Pipeline +- **Asset Pipeline**: Unity Asset Import Pipeline + Addressables +``` + +**For Unreal:** +```markdown +- **Engine**: Unreal Engine [version] +- **Language**: [C++ (primary), Blueprint (gameplay prototyping) | Blueprint (primary), C++ where needed] +- **Build System**: Unreal Build Tool (UBT) +- **Asset Pipeline**: Unreal Content Pipeline +``` +The Language line follows the primary-language answer above: the first form for +`[A]` (`engine.language: "C++"`), the second for `[B]` (`"Blueprint"`). + +### Engine reference import + +In the same CLAUDE.md write, set the **Engine Version Reference** import to the +chosen engine. Find the line marked `ENGINE-REFERENCE-IMPORT` (an +`@docs/engine-reference//VERSION.md` line under its comment) and Edit it +to point at the configured engine: +- Godot → `@docs/engine-reference/godot/VERSION.md` +- Unity → `@docs/engine-reference/unity/VERSION.md` +- Unreal → `@docs/engine-reference/unreal/VERSION.md` + +This is why a fresh Unity or Unreal project no longer loads the Godot reference in +every session. It is idempotent — re-running `/setup-engine` for a different +engine rewrites the same line. (The target `docs/engine-reference//` +directory is created in Section 8 below if it does not yet exist.) + +--- diff --git a/.claude/skills/setup-engine/references/5-technical-preferences.md b/.claude/skills/setup-engine/references/5-technical-preferences.md new file mode 100644 index 00000000..b3a64b34 --- /dev/null +++ b/.claude/skills/setup-engine/references/5-technical-preferences.md @@ -0,0 +1,167 @@ +# /setup-engine — Section 5: Populate Technical Preferences + +> Part of `/setup-engine`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 5. Populate Technical Preferences + +**In this file:** + +- Engine & Language Section +- Naming Conventions (engine defaults) +- Input & Platform Section +- Remaining Sections +- Engine Specialists Routing +- Collaborative Step + +After updating CLAUDE.md, create or update `.claude/docs/technical-preferences.md` with +engine-appropriate defaults. Read the existing template first, then fill in: + +### Engine & Language Section +- Fill from the engine choice made in step 4 + +### Naming Conventions (engine defaults) + +**For Godot** — see `references/godot-language-config.md` (**A2**) for GDScript, C#, and Both variants. + +**For Unity (C#):** +- Classes: PascalCase (e.g., `PlayerController`) +- Public fields/properties: PascalCase (e.g., `MoveSpeed`) +- Private fields: _camelCase (e.g., `_moveSpeed`) +- Methods: PascalCase (e.g., `TakeDamage()`) +- Files: PascalCase matching class (e.g., `PlayerController.cs`) +- Constants: PascalCase or UPPER_SNAKE_CASE + +**For Unreal (C++):** +- Classes: Prefixed PascalCase (`A` for Actor, `U` for UObject, `F` for struct) +- Variables: PascalCase (e.g., `MoveSpeed`) +- Functions: PascalCase (e.g., `TakeDamage()`) +- Booleans: `b` prefix (e.g., `bIsAlive`) +- Files: Match class without prefix (e.g., `PlayerController.h`) + +### Input & Platform Section + +Populate `## Input & Platform` using the answers gathered in Section 2 (or extracted +from the game concept). Derive the values using this mapping: + +| Platform target | Gamepad Support | Touch Support | +|-----------------|-----------------|---------------| +| PC only | Partial (recommended) | None | +| Console | Full | None | +| Mobile | None | Full | +| PC + Console | Full | None | +| PC + Mobile | Partial | Full | +| Web | Partial | Partial | + +For **Primary Input**, use the dominant input for the game genre: +- Action/RPG/platformer targeting console → Gamepad +- Strategy/point-and-click/RTS → Keyboard/Mouse +- Mobile game → Touch +- Cross-platform → ask the user + +> **Genre may not exist yet — check before deriving from it.** At `minimal` the +> design artifact is `design/game-brief.md`, and it is authored *after* this +> skill runs (Section 2 says so explicitly). There is no genre to map. The same +> is true at any tier when `/setup-engine` is run before the concept exists. +> +> When genre is unavailable, **ask** — do not infer one from the platform, and do +> not leave the field silently blank: +> - Prompt: "Primary input for a [2D/3D] [platform] game? Genre isn't established +> yet — the brief comes next — so this can't be derived." +> - Options: the plausible inputs for that platform, plus +> `Leave as [TO BE CONFIGURED]` — a legitimate answer here, revisited via +> `/settings` once the brief exists. +> +> Gamepad Support and Touch Support still come from the platform table above; +> only Primary Input depends on genre. + +Present the derived values and ask the user to confirm or adjust before writing. + +Example filled section: +```markdown +## Input & Platform +- **Target Platforms**: PC, Console +- **Input Methods**: Keyboard/Mouse, Gamepad +- **Primary Input**: Gamepad +- **Gamepad Support**: Full +- **Touch Support**: None +- **Platform Notes**: All UI must support d-pad navigation. No hover-only interactions. +``` + +### Remaining Sections +- **Performance Budgets**: Use `AskUserQuestion`: + - Prompt: "Should I set default performance budgets now, or leave them for later?" + - Options: `[A] Set defaults now (60fps, 16.6ms frame budget, engine-appropriate draw call limit)` / `[B] Leave as [TO BE CONFIGURED] — I'll set these when I know my target hardware` + - If [A]: populate with the suggested defaults. If [B]: leave as placeholder. +- **Testing**: Suggest the engine-appropriate framework — **gdUnit4** for Godot, + NUnit for Unity, Automation Spec for Unreal — and ask before adding. + > **Must match `commands.test` in Section 5.5.1, which writes gdUnit4's own + > runner (`res://addons/gdUnit4/bin/GdUnitCmdTool.gd`), and + > `.claude/docs/coding-standards.md`, which names the same runner.** Naming GUT + > here would have the skill recommend one framework and configure another in the + > same run. +- **Forbidden Patterns**: Leave as placeholder — do NOT pre-populate. +- **Allowed Libraries**: Leave as placeholder — do NOT pre-populate dependencies the project does not currently need. Only add a library here when it is actively being integrated, not speculatively. + +> **Guardrail**: Never add speculative dependencies to Allowed Libraries. For example, do NOT add GodotSteam unless Steam integration is actively beginning in this session. Post-launch integrations should be added to Allowed Libraries when that work begins, not during engine setup. + +### Engine Specialists Routing + +Also populate the `## Engine Specialists` section in `technical-preferences.md` with the correct routing for the chosen engine: + +**For Godot** — see `references/godot-language-config.md` (**A3**) for the routing table matching the language chosen. + +**For Unity:** +```markdown +## Engine Specialists +- **Primary**: unity-specialist +- **Language/Code Specialist**: unity-specialist (C# review — primary covers it) +- **Shader Specialist**: unity-shader-specialist (Shader Graph, HLSL, URP/HDRP materials) +- **UI Specialist**: unity-ui-specialist (UI Toolkit UXML/USS, UGUI Canvas, runtime UI) +- **Additional Specialists**: unity-dots-specialist (ECS, Jobs system, Burst compiler), unity-addressables-specialist (asset loading, memory management, content catalogs) +- **Routing Notes**: Invoke primary for architecture and general C# code review. Invoke DOTS specialist for any ECS/Jobs/Burst code. Invoke shader specialist for rendering and visual effects. Invoke UI specialist for all interface implementation. Invoke Addressables specialist for asset management systems. + +### File Extension Routing + +| File Extension / Type | Specialist to Spawn | +|-----------------------|---------------------| +| Game code (.cs files) | unity-specialist | +| Shader / material files (.shader, .shadergraph, .mat) | unity-shader-specialist | +| UI / screen files (.uxml, .uss, Canvas prefabs) | unity-ui-specialist | +| Scene / prefab / level files (.unity, .prefab) | unity-specialist | +| Native extension / plugin files (.dll, native plugins) | unity-specialist | +| General architecture review | unity-specialist | +``` + +**For Unreal:** +```markdown +## Engine Specialists +- **Primary**: unreal-specialist +- **Language/Code Specialist**: ue-blueprint-specialist (Blueprint graphs) or unreal-specialist (C++) +- **Shader Specialist**: unreal-specialist (no dedicated shader specialist — primary covers materials) +- **UI Specialist**: ue-umg-specialist (UMG widgets, CommonUI, input routing, widget styling) +- **Additional Specialists**: ue-gas-specialist (Gameplay Ability System, attributes, gameplay effects), ue-replication-specialist (property replication, RPCs, client prediction, netcode) +- **Routing Notes**: Invoke primary for C++ architecture and broad engine decisions. Invoke Blueprint specialist for Blueprint graph architecture and BP/C++ boundary design. Invoke GAS specialist for all ability and attribute code. Invoke replication specialist for any multiplayer or networked systems. Invoke UMG specialist for all UI implementation. + +### File Extension Routing + +| File Extension / Type | Specialist to Spawn | +|-----------------------|---------------------| +| Game code (.cpp, .h files) | unreal-specialist | +| Shader / material files (.usf, .ush, Material assets) | unreal-specialist | +| UI / screen files (.umg, UMG Widget Blueprints) | ue-umg-specialist | +| Scene / prefab / level files (.umap, .uasset) | unreal-specialist | +| Native extension / plugin files (Plugin .uplugin, modules) | unreal-specialist | +| Blueprint graphs (.uasset BP classes) | ue-blueprint-specialist | +| General architecture review | unreal-specialist | +``` + +### Collaborative Step +Present the filled-in preferences to the user. For Godot, include the chosen language and note where the full naming conventions and routing tables live: +> "Here are the default technical preferences for [engine] ([language if Godot]). The naming conventions and specialist routing are in this skill's references directory — I'll apply the [GDScript/C#/Both] variant. Want to customize any of these, or may I save them to `.claude/docs/technical-preferences.md`?" + +For all other engines, present the defaults directly without referencing the appendix. + +Wait for approval before writing the file. + +--- diff --git a/.claude/skills/setup-engine/references/5.5-project-yaml.md b/.claude/skills/setup-engine/references/5.5-project-yaml.md new file mode 100644 index 00000000..4b152400 --- /dev/null +++ b/.claude/skills/setup-engine/references/5.5-project-yaml.md @@ -0,0 +1,520 @@ +# /setup-engine — Section 5.5: Populate project.yaml + +> Part of `/setup-engine`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 5.5 Populate `project.yaml` (Primary Config Store) + +**In this file:** + +- 5.5.1 Build the four blocks +- 5.5.2 Write the blocks to `project.yaml` +- 5.5.3 Verify the dual-write + +> **v1.1:** `project.yaml` at the repo root is the **primary** store for project +> configuration. The `.claude/docs/technical-preferences.md` file written in +> Section 5 is kept as a **legacy mirror** for backward compatibility. This step +> is a **dual-write** — the same engine facts go into both files, and +> `project.yaml` wins when a skill reads a key present in both. + +After `technical-preferences.md` is written and approved, dual-write the +structured config into `project.yaml`. Four blocks are written: `engine`, +`specialists`, `naming`, and `commands`. + +### 5.5.1 Build the four blocks + +Derive every value from the engine and language already chosen in Sections 3–4. +Do NOT re-ask for the **engine, version or language** — reuse those decisions. + +> **That is not a blanket "never ask".** `rendering` and `physics` below depend on +> two further inputs — target platform and 2D-vs-3D — which **Section 2 collects on +> only one of the four entry paths**. When they were never collected, ask; the +> unavailable-branch under the project-shape table says how. + +**`engine` block:** + +```yaml +engine: + name: "" + version: "" + language: "" + rendering: "" + physics: "" +``` + +**On Godot these two values depend on the answers Section 2 already collected — +the target platform and 2D-vs-3D — so do not pick them from the engine name +alone.** On Unity and Unreal the table has a single `any` row and the engine name +*is* sufficient; take those rows directly. + +| Engine | Project shape | `rendering` default | `physics` default | +|--------|---------------|---------------------|-------------------| +| Godot 4.x | 2D · web target | Compatibility | Godot Physics 2D | +| Godot 4.x | 2D · non-web | Forward+ | Godot Physics 2D | +| Godot 4.x | 3D · web target | Compatibility | Jolt | +| Godot 4.x | 3D · non-web | Forward+ | Jolt | +| Unity | any | URP | PhysX | +| Unreal | any | Lumen + Nanite (deferred) | Chaos | + +> **Why this table has a shape column and the others do not.** Both Godot +> defaults were wrong for a 2D browser game, and both were wrong from data this +> skill had already collected and then discarded. +> - **Jolt is Godot's default *3D* engine.** `docs/engine-reference/godot/modules/physics.md`: +> "Jolt Physics is the DEFAULT 3D engine" and "2D physics UNCHANGED (still +> Godot Physics 2D)". Writing `Jolt` on a 2D project sends the implementer to +> tune a backend their game does not use. +> - **Forward+ is desktop-focused.** `docs/engine-reference/godot/modules/rendering.md`: +> Forward+ is "Full featured, desktop-focused"; Compatibility is +> "OpenGL 3.3 / WebGL 2, broadest hardware support" — the browser path. +> +> If Section 2's platform answer was `Multiple platforms` **including** web, use +> the web row: the renderer must work everywhere the game ships. + +> **Godot only — Unity and Unreal have one row each, keyed `any`.** Shape cannot +> change `rendering` or `physics` for those two, so do **not** run the resolution +> below for them: asking an operator a question whose answer you will discard is +> exactly what §5.5.1 opens by forbidding. On Unity write `URP`/`PhysX` and on +> Unreal write `Lumen + Nanite (deferred)`/`Chaos` straight from the table. +> +> **Section 2 did not necessarily run — check before reading its answers.** +> Target platform and 2D-vs-3D are collected under *Questions 2–6, only if no +> prior engine experience*. **Three of the four entry paths never reach them:** +> `/setup-engine ` and `/setup-engine ` skip Section 2 +> outright, and guided mode skips the matrix as soon as the user names an engine +> they have worked in before. Only guided mode answered `None` or `Multiple` +> collects both. +> +> Resolve each input in this order and stop at the first that answers: +> 1. **Section 2's answers**, if that path ran. +> 2. **The design artifact** — `design/gdd/game-concept.md` at `standard`/`full`, +> `design/game-brief.md` at `minimal`. Section 2 already extracts platform +> targets from these; extract 2D-vs-3D the same way when it is stated. +> 3. **Ask.** Do not infer the shape from the engine name, and do not write a row +> you could not justify: +> - Prompt: "`rendering` and `physics` depend on the project's shape, which +> hasn't been established yet. Is this 2D or 3D, and does it ship to web?" +> - Options: `2D · non-web` / `2D · web` / `3D · non-web` / `3D · web`, plus +> `Leave as [TO BE CONFIGURED]` — a legitimate answer here, revisited via +> `/settings` once the concept exists. +> +> `[TO BE CONFIGURED]` is a valid value for both keys. A wrong `Jolt` on a 2D +> project is worse than an unset one, because nothing downstream questions it. + +- `rendering` and `physics` are engine-typical defaults — tell the user they can + be changed later via `/settings` if the project uses a different setup. +- For Godot **Both**, write `language: "GDScript"` (the primary gameplay + language); the C# usage is recorded in `technical-preferences.md`. +- For Unreal, write `language: "C++"` — or `"Blueprint"` only if the project is + Blueprint-primary. Blueprint as a secondary tool does not change this value. + +**`specialists` block** — copy directly from the routing table chosen in +Section 5 (**A3** in `references/godot-language-config.md` for Godot): + +| Engine / language | `code` | `shader` | `ui` | `additional` | +|-------------------|--------|----------|------|--------------| +| Godot — GDScript | godot-gdscript-specialist | godot-shader-specialist | godot-specialist | [godot-gdextension-specialist] | +| Godot — C# | godot-csharp-specialist | godot-shader-specialist | godot-specialist | [godot-gdextension-specialist] | +| Godot — Both | godot-gdscript-specialist | godot-shader-specialist | godot-specialist | [godot-csharp-specialist, godot-gdextension-specialist] | +| Unity | unity-specialist | unity-shader-specialist | unity-ui-specialist | [unity-dots-specialist, unity-addressables-specialist] | +| Unreal | unreal-specialist | unreal-specialist | ue-umg-specialist | [ue-gas-specialist, ue-blueprint-specialist, ue-replication-specialist] | + +```yaml +specialists: + code: "" + shader: "" + ui: "" + additional: ["<...>"] +``` + +**`naming` block** — enum values (NOT the prose form used in +`technical-preferences.md`). Use the column matching the engine and, for Godot, +the language: + +| Field | Godot GDScript | Godot C# | Unity | Unreal | +|-------|----------------|----------|-------|--------| +| `classes` | PascalCase | PascalCase | PascalCase | PascalCase | +| `variables` | snake_case | camelCase | camelCase | **PascalCase** | +| `constants` | SCREAMING_SNAKE | PascalCase | SCREAMING_SNAKE | SCREAMING_SNAKE | +| `signals` | past_tense | on_event_name | **PascalCase `On`** | **PascalCase `On`** | +| `files` | snake_case | PascalCase | PascalCase | PascalCase | +| `scenes` | snake_case | PascalCase | PascalCase | PascalCase | + +> **The Unreal column is sourced, not inherited from the table's generic shape.** +> `variables: camelCase` and `signals: on_event_name` are the two rows that shape +> would produce, and both are wrong for Unreal. Checked against this repo's +> pinned reference: `docs/engine-reference/unreal/` contains **zero** camelCase +> variable declarations and uses PascalCase throughout (`int32 Health;`, +> `FVector ServerPosition;`), and the word "signal" **never appears in it at all** — +> it is Godot vocabulary. Unreal has delegates and events, and the reference's +> handlers are PascalCase `On`. +> +> Two caveats kept rather than smoothed over. (1) `classes: PascalCase` is +> **incomplete** for Unreal, not wrong: UE requires a mandatory type prefix +> (`U`/`A`/`F`/`E`/`I`/`T`) that this enum cannot express, so an Unreal project's +> coding standards must state it separately. (2) `scenes` is a **category +> mismatch** — Unreal has Levels and Maps under World Partition, not scenes — left +> in place because the key is shared across engines and renaming it is a schema +> change, not a value fix. +> +> The blast radius is limited: `naming.*` is currently a +> **documented-but-unread** setting, so wrong values misinform a human reading +> `project.yaml` rather than driving any automated check — today. That is a +> reason to get them right now, while it is cheap. + +> **Three further rules for this table.** +> +> **The Unity `build` row must not hardcode `-buildTarget StandaloneLinux64`.** +> A hardcoded target gives every Unity project a **Linux** build command, whatever +> platform it actually ships on. The row reads ``: **ask the operator for +> the build target and write the value they give.** The correct `-buildTarget` identifiers +> are not sourceable from `docs/engine-reference/unity/`, so this skill must not +> emit one from recall — the same call made for `/security-audit`'s save +> patterns and for Unity's release dates. A wrong-but-plausible default is worse +> than an explicit question: it produces a `commands.build` that runs, succeeds, +> and builds the wrong artifact. +> +> **`-buildTarget` alone builds nothing.** It switches the active platform and +> exits 0 (verified on 6000.3.23f1). The row also needs a player-build flag, +> `-buildPlayer ` — for Windows 64-bit, +> `-buildWindows64Player Builds/Win64/.exe` (verified: exit 0 and an +> `.exe`; exit 1 on a compile error or when no scene is in the build settings). +> Ask which platform, and confirm any other platform's flag against Unity's +> command-line documentation rather than recalling one. +> +> **The Godot `build` row must not hardcode `'Linux/X11'` either — same defect, +> same remedy.** A Godot export preset name is **project-defined**: it is whatever +> string the operator typed into `export_presets.cfg`, and the shipped defaults are +> per-platform (`Windows Desktop`, `macOS`, `Web`, `Linux/X11`). Writing +> `'Linux/X11'` gives a Windows-targeting project a build command that fails with +> `Unknown export preset`, and gives a project that *does* have a Linux preset a +> command that silently builds the wrong platform. The row reads ``: +> **ask the operator which export preset to build and write the value they give**, +> exactly as the Unity row does. If no presets exist yet — common, since +> `/setup-engine` usually runs before the Godot project has any — write +> `[TO BE CONFIGURED]` and say so, rather than guessing a name that does not exist. +> +> **The `constants` row must not contradict this skill's own prose.** The table says +> `SCREAMING_SNAKE` for Unity; the Unity section of this same file says +> "Constants: PascalCase or UPPER_SNAKE_CASE". Both cannot be authoritative, and +> an agent following one produces config the other rejects. The row is **left +> unchanged pending sourcing** rather than picked by preference — neither +> `docs/engine-reference/unity/` nor `unreal/` contains a SCREAMING_SNAKE constant +> to confirm or refute it, and the Unreal run flagged the same row as wrong for +> Unreal on the same grounds. Resolve by adding a naming section to the engine +> references, then correct table and prose together. Until then, treat +> `naming.constants` as unverified for Unity and Unreal. +> +> **Write that caveat into `project.yaml`, do not leave it here.** On Unity and +> Unreal, emit the `constants` line with a trailing comment: +> ```yaml +> naming: +> constants: SCREAMING_SNAKE # UNVERIFIED — not sourceable from +> # docs/engine-reference//; confirm before relying on it +> ``` +> Without it, a value the skill *knows* is unsourced is recorded as flatly as +> `classes: PascalCase`, which is sourced, and the reader of the primary config +> store cannot tell them apart. The `commands` block nine lines below already does +> exactly this with its `# TODO: confirm these` line — this is the same pattern, +> applied to the value that needs it just as much. + +For Godot **Both**, use the GDScript column — `.gd` files dominate gameplay +scripting; `.cs` files follow C# conventions per-file (see **A2** in `references/godot-language-config.md`). + +```yaml +naming: + classes: + variables: + constants: + signals: + files: + scenes: +``` + +**`commands` block** — engine-default shell commands, simple-string form: + +| Engine | `build` | `test` | `run` | `smoke` | +|--------|---------|--------|-------|---------| +| Godot | `godot --headless --export-debug ''` **(ASK — do not default)** | `godot --headless -s -d --remote-debug tcp://127.0.0.1:0 res://addons/gdUnit4/bin/GdUnitCmdTool.gd -a res://tests --ignoreHeadlessMode` | `godot --path . --windowed --resolution 1280x720` | `godot --headless --quit-after 5` | +| Unity | `"" -batchmode -quit -projectPath . -buildTarget -buildPlayer Builds//.exe` **(ASK — do not default)** | `"" -batchmode -runTests -projectPath . -testPlatform EditMode -testResults test-results/editmode.xml` | `Builds//.exe -screen-width 1280 -screen-height 720 -screen-fullscreen 0` | `"" -batchmode -quit -projectPath . -logFile -` | + +> **What each exit code proves — every row verified on the pinned engines.** +> Godot `test` exits 0 when all pass, 100 on a failure, 101 when all pass but +> nodes leaked (a warning, not a failure), 105 when a test script does not +> parse, and 103 / 104 when gdUnit4 cannot run at all (headless refused, Godot +> older than 4.3). Keep `--remote-debug tcp://127.0.0.1:0`: without it a script +> error opens Godot's interactive debugger and the run waits at a `debug>` +> prompt forever instead of exiting. Run `godot --headless --path . --import` +> before it on a fresh clone: with no `.godot/` class cache, +> `GdUnitCmdTool.gd` did not load and the run exits 1 having run nothing. Unity `test` +> exits 0 / 2, and a results file with `testcasecount="0"` means no test was +> compiled — not a pass. It runs Edit Mode only: Play Mode tests under +> `Assets/Tests/PlayMode/` need a second run into their own results file +> (`-testPlatform PlayMode -testResults test-results/playmode.xml`), which +> `/smoke-check` makes whenever that folder holds tests and CI runs as its own +> step. Unity `smoke` exits 1 on a compile error, 0 when clean. +> **Godot `smoke` exits 0 even on a parse error** — it is a boot check: read its +> output for `SCRIPT ERROR`. It also needs `run/main_scene` set: without one it +> prints `Can't run project: no main scene defined` and never exits, so run it +> under a timeout. Unity `smoke` compiles only the editor-side assemblies; an +> error that exists only in a player build (an `Editor/` script without its own +> assembly) shows up in `build`, not here. The real Godot parse check is +> `godot --headless --path . --import`, then +> `godot --headless --path . -s res://.claude/scripts/godot-parse-check.gd -- res://.gd …` +> (exit 1 when a script does not load). `--check-only` is not one: it fails +> valid code that names an autoload. `` is the **editor** +> executable's full path, quoted. Never write bare `Unity`: on `PATH` that name +> may be Unity's separate CLI, which rejects `-batchmode` with exit 2 — the same +> code as a failed test. + +> **`commands.run` is the one the run-and-observe step depends on.** It must +> launch the **game**, windowed, at a fixed resolution — never the editor, and +> never with a headless / batch / null-RHI flag, which exist to skip rendering. +> `/dev-story` Phase 6 step 4 appends the per-engine capture flags to it +> (`.claude/docs/run-and-observe.md`). `smoke` is Unity's parse check, `test` +> feeds `/smoke-check`; `build` is the one row you must ask for. + +> **YAML quoting rule — applies to EVERY command value.** `yaml-helper.sh` — the +> parser every config read in this framework goes through — decodes **no** +> escape sequences: neither `\"` inside a double-quoted scalar nor `''` inside a +> single-quoted scalar. It takes the first matching quote character as the end of +> the value and discards the rest, so `"he said \"hi\" now"` parses as +> `he said \`. Verified against the parser, not inferred. The rule is +> load-bearing: `/smoke-check` and `/dev-story` run these values, `/settings` +> reads and writes them through this parser, and the same holds for every other +> quoted value in `project.yaml`. +> Pick the quote style that needs **no escaping**: +> - value contains a single quote `'` (e.g. the Godot `build` above) → wrap it in +> a **double-quoted** YAML scalar: `"... 'Linux/X11' ..."` +> - value contains a double quote `"` (e.g. the Unreal `test`/`smoke` below) → +> wrap it in a **single-quoted** YAML scalar: `'... "Quit" ...'` +> - value contains neither → use a double-quoted scalar for consistency. +> Never use a quote style that forces an escape (`\"` or `''`) — the parser +> truncates the value at the escape. A value containing BOTH quote types cannot +> be represented for this parser; rewrite the command to drop one. + +**Godot / Unity** — write the table values directly, substituting the operator's +answer for `` / `` / ``, and the editor's full path for +``. Godot's `build` contains a single quote, so it +takes a double-quoted scalar (`Windows Desktop` below is the *example* answer, not +a default — write what the operator said): + +```yaml +commands: + build: "godot --headless --export-debug 'Windows Desktop'" + test: "godot --headless -s -d --remote-debug tcp://127.0.0.1:0 res://addons/gdUnit4/bin/GdUnitCmdTool.gd -a res://tests --ignoreHeadlessMode" + run: "godot --path . --windowed --resolution 1280x720" + smoke: "godot --headless --quit-after 5" +``` + +**Write bare `godot` only when Section 3's `godot --version` ran** — that is, +`godot` is on `PATH`. Otherwise (the usual case on Windows and macOS) +substitute the executable the probe found or the user gave — a Windows +`Godot_v-stable_win64.exe`, macOS `/Applications/Godot.app/Contents/MacOS/Godot` +— as its full path, in double quotes, for the leading `godot` in all four +values, exactly as `` is. The value then holds double quotes, so it +takes a single-quoted scalar, and `build` quotes its preset with double quotes +too, so no value holds both quote types. Godot not on PATH, installed under +`C:/Program Files/Godot/`: + +```yaml +commands: + build: '"C:/Program Files/Godot/Godot_v4.6.1-stable_win64.exe" --headless --export-debug "Windows Desktop"' + test: '"C:/Program Files/Godot/Godot_v4.6.1-stable_win64.exe" --headless -s -d --remote-debug tcp://127.0.0.1:0 res://addons/gdUnit4/bin/GdUnitCmdTool.gd -a res://tests --ignoreHeadlessMode' + run: '"C:/Program Files/Godot/Godot_v4.6.1-stable_win64.exe" --path . --windowed --resolution 1280x720' + smoke: '"C:/Program Files/Godot/Godot_v4.6.1-stable_win64.exe" --headless --quit-after 5' +``` + +If the probe found no executable and the user does not know where it is, keep +bare `godot`, put `# TODO: godot is not on PATH here — set the editor's full +path via /settings` above the block, and say so: those commands will not run +until one of the two is fixed. + +For Unity, probe the Hub install (`C:/Program Files/Unity/Hub/Editor//Editor/Unity.exe` +on Windows, `/Applications/Unity/Hub/Editor//Unity.app/Contents/MacOS/Unity` +on macOS, `/home//Unity/Hub/Editor//Editor/Unity` on Linux) or ask. +Write the expanded absolute path — a `~` inside quotes is not expanded, and the +command then exits 127. The +quoted path puts double quotes in the command, so the value takes a +single-quoted scalar: + +```yaml +commands: + test: '"C:/Program Files/Unity/Hub/Editor/6000.3.23f1/Editor/Unity.exe" -batchmode -runTests -projectPath . -testPlatform EditMode -testResults test-results/editmode.xml' + smoke: '"C:/Program Files/Unity/Hub/Editor/6000.3.23f1/Editor/Unity.exe" -batchmode -quit -projectPath . -logFile -' +``` + +> **Also write `engine.path` if the editor is not on `PATH`.** Agents and +> `/smoke-check` read it to find the editor, but a command is run as written — +> `engine.path` is never spliced into `commands.*` at run time, which is why the +> full path goes into the commands above — and on Windows and macOS none of +> the three engines installs onto `PATH` by default (on macOS the editor is inside an app +> bundle, e.g. `/Applications/Godot.app/Contents/MacOS/Godot`). Ask for or probe the +> install location and record it — the editor executable for Godot and Unity, +> the engine folder (``) for Unreal: +> +> ```yaml +> engine: +> path: "C:/Program Files/Epic Games/UE_5.7" # omit if the editor is on PATH +> ``` +> +> **This is not cosmetic.** Without it, an agent reports *"no editor on this +> machine"* and ships C++ it never compiled — on a machine where that engine WAS +> installed. Nothing in the project told it where to look, so absence of a path read +> as absence of an engine. + +For **Unreal**, UE build/test commands vary by version and project setup. Write +best-effort values and add a `# TODO` comment so the user knows to confirm them. +Substitute the engine's install folder for `` (the value you record as +`engine.path`) — none of the editor binaries is on `PATH`. The commands embed +double quotes, so they take single-quoted scalars. Write the block for the +machine the project is developed on (`uname -s`: `Linux`, `Darwin` = macOS, +anything else = Windows). The Windows block was run on UE 5.7; the Linux and +macOS lines come from Epic's documentation, recorded with their sources in +`docs/engine-reference/unreal/current-best-practices.md` ("Command Line"). + +Windows: + +```yaml +commands: + # TODO: confirm these for your UE version and project — adjust via /settings + build: '"/Engine/Binaries/DotNET/AutomationTool/AutomationTool.exe" BuildCookRun -project="$(pwd -W 2>/dev/null || pwd)/.uproject" -platform=Win64 -build -cook' + test: '"/Engine/Binaries/Win64/UnrealEditor-Cmd.exe" "$(pwd -W 2>/dev/null || pwd)/.uproject" -ExecCmds="Automation RunTests .; Quit" -unattended -nullrhi -stdout -FullStdOutLogOutput' + run: '"/Engine/Binaries/Win64/UnrealEditor.exe" "$(pwd -W 2>/dev/null || pwd)/.uproject" -game -windowed -ResX=1280 -ResY=720' + smoke: '"/Engine/Binaries/Win64/UnrealEditor-Cmd.exe" "$(pwd -W 2>/dev/null || pwd)/.uproject" -game -nullrhi -unattended -stdout -ExecCmds="Quit"' +``` + +Linux — the editor binary is `Engine/Binaries/Linux/UnrealEditor`, the build +scripts are shell scripts: + +```yaml +commands: + # TODO: confirm these for your UE version and project — adjust via /settings + build: '"/Engine/Build/BatchFiles/RunUAT.sh" BuildCookRun -project="$(pwd -W 2>/dev/null || pwd)/.uproject" -platform=Linux -build -cook' + test: '"/Engine/Binaries/Linux/UnrealEditor" "$(pwd -W 2>/dev/null || pwd)/.uproject" -ExecCmds="Automation RunTests .; Quit" -unattended -nullrhi -stdout -FullStdOutLogOutput' + run: '"/Engine/Binaries/Linux/UnrealEditor" "$(pwd -W 2>/dev/null || pwd)/.uproject" -game -windowed -ResX=1280 -ResY=720' + smoke: '"/Engine/Binaries/Linux/UnrealEditor" "$(pwd -W 2>/dev/null || pwd)/.uproject" -game -nullrhi -unattended -stdout -ExecCmds="Quit"' +``` + +macOS — only the build is sourced. Epic documents the `UnrealEditor.app` +bundle but no command-line editor inside it, so write `build` and leave the +other three as TODO lines rather than a guessed path; `/smoke-check` reports +NOT ASSESSED for tests until the user sets `commands.test`: + +```yaml +commands: + # TODO: confirm this for your UE version and project — adjust via /settings + build: '"/Engine/Build/BatchFiles/RunUAT.sh" BuildCookRun -project="$(pwd -W 2>/dev/null || pwd)/.uproject" -platform=Mac -build -cook' + # TODO: test, run and smoke — no documented command-line editor on macOS. + # Set them via /settings to the editor command you run for this project. +``` + +On Windows, `build` calls AutomationTool directly: from Git Bash, `RunUAT.bat` fails +(`'C:\Program' is not recognized`) whenever the project path has a space. +AutomationTool.exe runs on the machine's .NET 8 runtime; `RunUAT.bat` brings +its own SDK, so with no space in the path and no .NET 8 installed, use it. +`-build` builds the editor target too (verified on 5.7). + +**Three details are load-bearing.** The project path is absolute: UE 5.7 +does not find a relative `.uproject` and exits 1 (`Project file not +found`) before anything runs. `$(pwd -W 2>/dev/null || pwd)` gives the `C:/…` +form in Git Bash and the plain path elsewhere, run from the project root; +`$PWD` alone fails when `MSYS_NO_PATHCONV` is set. `smoke` needs `-game`: without it +`UnrealEditor-Cmd` boots the *editor*, where a bare `Quit` console command only +ends a play-in-editor session — the process stays resident and the command +never returns; with `-game` the same line boots headless and exits in seconds. +`test` needs the `; Quit` inside the `Automation` string: the automation +runner handles that trailing `Quit` itself and exits the editor once the tests +finish, and without it the run also never returns. Its filter runs every test +whose full name *contains* `.` — a substring match, not a prefix — so +name tests `.[System].[Scenario]` as `qa-tester` does. If the +project's name is also an engine area — `Audio`, `Core`, `Input`, `Test`, +`System`, `Engine`, `Editor`, `AI`, `Math` — `.` also runs hundreds +to thousands of the engine's own tests; give the tests a distinct root (say +`Game.`) and put the same root in the filter. This form exits 255 on +a failing test AND on a filter that matches nothing (`No automation tests +matched`, verified on 5.7), so `/smoke-check` reads the output, not the exit +code. `smoke` carries `-stdout` for the same reason: without it a failed boot +prints nothing. Do not swap in +`-TestExit="Automation Test Queue Empty"`: that form exits **0** on a failing +test unless its report JSON is parsed. + +### 5.5.2 Write the blocks to `project.yaml` + +Show the user the full set of four blocks and ask: + +> "May I write the `engine`, `specialists`, `naming`, and `commands` blocks to `project.yaml`?" + +Wait for confirmation, then apply based on the file's current state: + +- **`project.yaml` does not exist** — create it with the Write tool using this + v1.1 template (the four blocks appended after `framework`; replace `<...>` and + the date): + + ```yaml + # CCGS project configuration — single source of truth for project settings. + # Schema: grep the `## ` section of .claude/docs/effects-map.md — + # it is ~31k tokens whole, ~900 per section. Do not open it entire. + + schema_version: 1 + + framework: + version: 1.1.3 + last_upgraded: + + engine: + name: "<...>" + version: "<...>" + language: "<...>" + rendering: "<...>" + physics: "<...>" + + specialists: + code: "<...>" + shader: "<...>" + ui: "<...>" + additional: ["<...>"] + + naming: + classes: <...> + variables: <...> + constants: <...> + signals: <...> + files: <...> + scenes: <...> + + commands: + build: "<...>" + test: "<...>" + run: "<...>" + smoke: "<...>" + ``` + + Do not seed `modes.review_mode` here. It is a rigor-fronted knob — `modes.rigor` + supplies its value, so an explicit value would shadow the rigor expansion and pin + the review mode regardless of the project's rigor. + +- **`project.yaml` exists** — Read it first (the Edit tool requires the file to + have been read this session), then, processing the blocks in the order + `engine` → `specialists` → `naming` → `commands`, for each block: + - **Block absent** — insert the whole block, appended after the last existing + top-level block. + - **Block already present** (a re-run of `/setup-engine`) — Edit the existing + keys in place, and add any keys the block is missing (a partial block must + end up with its full key set). Do NOT add a second copy of the block. + +**Unreal on macOS is the exception in both cases:** `commands.test`, `run` and +`smoke` are written as the TODO comment lines from the macOS block — never as +`<...>` placeholders or a guessed path — and a re-run leaves them unset until the +user sets them. + +Preserve all other content in `project.yaml` (`schema_version`, `framework`, +`modes`, `project`, etc.) — only the four blocks are touched. + +### 5.5.3 Verify the dual-write + +Read `project.yaml` back and confirm the four blocks are present and that +`engine.name`, `engine.language`, and the naming values match what was written +to `technical-preferences.md`. If they diverge, report the discrepancy to the +user and stop — a split config corrupts skill and hook reads. + +--- diff --git a/.claude/skills/setup-engine/references/6-knowledge-gap.md b/.claude/skills/setup-engine/references/6-knowledge-gap.md new file mode 100644 index 00000000..d4996b4a --- /dev/null +++ b/.claude/skills/setup-engine/references/6-knowledge-gap.md @@ -0,0 +1,38 @@ +# /setup-engine — Section 6: Determine Knowledge Gap + +> Part of `/setup-engine`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 6. Determine Knowledge Gap + +Check whether the engine version is likely beyond the LLM's training data. + +**Known approximate coverage** — the same figures the shipped +`docs/engine-reference/*/VERSION.md` files record: +- LLM knowledge cutoff: **May 2025** +- Godot: training data likely covers up to ~4.3 +- Unity: training data likely covers up to ~2022 LTS (2022.3) +- Unreal: training data likely covers up to ~5.3 + +> **This table goes stale silently, and a stale table fails in the dangerous +> direction only if it is too *new*.** A cutoff left unchanged for a year after +> it stopped being true over-classifies risk — safe, but every project then pays +> for full reference docs it may not have needed. +> The opposite error is the harmful one: a cutoff claimed *later* than the model's +> actual one marks post-cutoff versions LOW RISK and suppresses the reference +> docs that exist to stop invented APIs. +> +> **If the model running this skill states an earlier training cutoff than the +> one above, do not trust the table.** Say so, and treat the engine version as +> `HIGH RISK` regardless of the comparison — a cutoff the model does not have is +> not a cutoff that was met. + +Compare the user's chosen version against these baselines: + +- **Within training data** → `LOW RISK` — reference docs optional but recommended +- **Near the edge** → `MEDIUM RISK` — reference docs recommended +- **Beyond training data** → `HIGH RISK` — reference docs required + +Inform the user which category they're in and why. + +--- diff --git a/.claude/skills/setup-engine/references/7-reference-docs.md b/.claude/skills/setup-engine/references/7-reference-docs.md new file mode 100644 index 00000000..73bbb602 --- /dev/null +++ b/.claude/skills/setup-engine/references/7-reference-docs.md @@ -0,0 +1,129 @@ +# /setup-engine — Section 7: Populate Engine Reference Docs + +> Part of `/setup-engine`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 7. Populate Engine Reference Docs + +**In this file:** + +- First: does a reference set already exist for this engine? +- Sourcing rule for everything written in this section +- If WITHIN training data (LOW RISK): +- If BEYOND training data (MEDIUM or HIGH RISK): + +### First: does a reference set already exist for this engine? + +**Check before doing anything else.** The template ships +`docs/engine-reference/godot/`, `unity/` and `unreal/` **already populated**, so +"the directory exists and pins a version" is the state of *every* fresh project, +not an edge case. Both branches below say "create", and following either one +literally on a pre-populated directory either overwrites curated content or +leaves `project.yaml` and the CLAUDE.md-imported reference disagreeing. + +Read `docs/engine-reference//VERSION.md` and compare its +**Engine Version** to the version chosen in Section 3: + +- **No directory, or no `VERSION.md`** → create, using the risk branch below. +- **Same version** → nothing to regenerate. Refresh `Last Docs Verified` only if you + actually re-verified against the docs this run. Do not restamp a date you did + not check. The one row still written is `Installed at pin time`, from + Section 3 — its probe result is recorded whatever the outcome, after asking + "May I record `Installed at pin time: [result]` in + `docs/engine-reference//VERSION.md`?" (it is a tracked file). +- **Directory pins an OLDER version than the one chosen** → **update, do not + replace.** This is the common case. Show the changes below, then ask "May I + update the `docs/engine-reference//` files for [version]?" before editing. + 1. Edit `VERSION.md` in place: new **Engine Version**, new **Project Pinned** + and **Last Docs Verified**, the `Installed at pin time` row from Section 3, + and a new row in the post-cutoff timeline for each version added. + 2. **Append** to `breaking-changes.md`, `deprecated-apis.md` and + `current-best-practices.md` under a heading naming the version span + (`## 4.6 → 4.7`). Never truncate the older spans — a project migrating + across two versions still needs the earlier one. + 3. Re-grade the older timeline rows if the cutoff moved past them. +- **Directory pins a NEWER version than the one chosen** → stop and ask. Someone + pinned forward deliberately, or the version choice is wrong. Do not silently + downgrade a curated reference. + +### Sourcing rule for everything written in this section + +**Never fill a gap from training data. Write the gap down instead.** + +The whole purpose of these files is to be the thing agents consult *instead of* +their training data. A confidently wrong entry here is worse than no entry: it +produces work that looks verified and is not. + +- Every claim must come from a page you fetched this run. Record the URL. +- If the official docs do not state something the template asks for — a release + date, a subsystem's behaviour, web-export specifics — write + **`NOT SOURCEABLE — , not stated at `** and move on. +- A `NOT SOURCEABLE` line is a successful outcome, not a failure to finish. +- Do not infer one fact from an adjacent one. "The migration guide lists no + physics change" is not "the physics default is unchanged"; if you record the + inference, label it as an inference and name what it rests on. + +### If WITHIN training data (LOW RISK): + +Ask: "May I create `docs/engine-reference//VERSION.md`?" Wait for +confirmation, then create this minimal file: + +```markdown +# [Engine] — Version Reference + +| Field | Value | +|-------|-------| +| **Engine Version** | [version] | +| **Project Pinned** | [today's date] | +| **Installed at pin time** | [Section 3 result — the installed version, or NOT DETERMINED] | +| **LLM Knowledge Cutoff** | [the cutoff from the Section 6 coverage table] | +| **Risk Level** | LOW — version is within LLM training data | + +## Note + +This engine version is within the LLM's training data. Engine reference +docs are optional but can be added later if agents suggest incorrect APIs. + +Run `/setup-engine refresh` to populate full reference docs at any time. +``` + +Do NOT create breaking-changes.md, deprecated-apis.md, etc. — they would +add context cost with minimal value. + +### If BEYOND training data (MEDIUM or HIGH RISK): + +Create the full reference doc set by searching the web: + +1. **Search for the official migration/upgrade guide**: + - `"[engine] [old version] to [new version] migration guide"` + - `"[engine] [version] breaking changes"` + - `"[engine] [version] changelog"` + - `"[engine] [version] deprecated API"` + +2. **Fetch and extract** from official documentation: + - Breaking changes between each version from the training cutoff to current + - Deprecated APIs with replacements + - New features and best practices + +Ask: "May I create the engine reference docs under `docs/engine-reference//`?" + +Wait for confirmation before writing any files. + +3. **Create the full reference directory**: + ``` + docs/engine-reference// + ├── VERSION.md # Version pin + knowledge gap analysis + ├── breaking-changes.md # Version-by-version breaking changes + ├── deprecated-apis.md # "Don't use X → Use Y" tables + ├── current-best-practices.md # New practices since training cutoff + └── modules/ # Per-subsystem references (create as needed) + ``` + +4. **Populate each file** using real data from the web searches, following + the format established in existing reference docs. Every file must have + a "Last verified: [date]" header. + +5. **For module files**: Only create modules for subsystems where significant + changes occurred. Don't create empty or minimal module files. + +--- diff --git a/.claude/skills/setup-engine/references/7.5-scaffold.md b/.claude/skills/setup-engine/references/7.5-scaffold.md new file mode 100644 index 00000000..6af1a194 --- /dev/null +++ b/.claude/skills/setup-engine/references/7.5-scaffold.md @@ -0,0 +1,86 @@ +# /setup-engine — Section 7.5: Scaffold the Engine Project + +> Part of `/setup-engine`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 7.5 Scaffold the Engine Project + +**Without this step the framework produces source files no engine can open.** +`/dev-story` writes `.gd`/`.cs`/`.cpp` under the resolved code root, and the `minimal` path +advertises "four steps to running code" — but nothing anywhere created a project +for the engine to load. Verified by grep across every skill: no `project.godot`, +no Unity project, no `.uproject` was ever written. The files were real and +orphaned. + +### Godot — write `project.godot` if one is absent + +**Never overwrite an existing `project.godot`.** If the file is already there, +say so and skip to Section 8 — the developer has a project and its settings are +theirs. + +Show the proposed file, then ask: *"May I create `project.godot` at the repo +root?"* On approval, write: + +```ini +config_version=5 + +[application] + +config/name="" +config/features=PackedStringArray("", "") + +[rendering] + +renderer/rendering_method="" +``` + +Fill it from decisions already made — do not ask again: + +| Field | Source | +|-------|--------| +| `config/name` | the brief's working title, else the repo directory name | +| `` | `engine.version` from Section 3, major and minor only (`4.7.2` → `4.7`) | +| `` / `` | the `rendering` value chosen in Section 5.5.1 — Compatibility → `"GL Compatibility"` / `gl_compatibility`; Forward+ → `"Forward Plus"` / `forward_plus`; Mobile → `"Mobile"` / `mobile` | + +**Leave `run/main_scene` unset.** There is no scene yet at engine-setup time. +Add a comment saying `/dev-story` or the developer sets it once a scene exists; +an empty project with no main scene opens fine in the editor. + +**Then verify, and report what the verification actually was.** If the engine +binary was found in Section 3, run its headless import +(`godot --headless --path . --import`) and report the result — read the output +for `ERROR`, because the import exits 0 even when something in the project +fails to load. If the binary was +not found, or its version differs from the pinned one, write +**`project.godot NOT VERIFIED — `**. The `config_version` and feature +strings are stable across Godot 4.x, but "stable in the versions I know" is not +the same as "checked against the version you pinned", and only the run +establishes the latter. + +### Unity and Unreal — instruct, do not fabricate + +A Unity project and an `.uproject` are editor-generated and span many files, +several of them binary or machine-specific. This repo cannot source their +correct contents, and a hand-written scaffold would be the exact failure +Section 7's sourcing rule forbids — something that looks finished and is quietly +wrong. + +Tell the user, in one short block, that CCGS does not create the project for +these engines and they should create it first: + +- **Unity** — create the project in Unity Hub at the repo root, choosing the + template matching the 2D/3D answer from Section 2, then re-run `/setup-engine`. +- **Unreal** — create the project in the Epic launcher or via `UnrealEditor`, + then re-run. + +Report the outcome in the Section 12 summary either way — created, already +present, or "not created, engine requires the editor" — so the user leaves this +skill knowing whether a runnable project exists. + +> **Deliberately not a `project.yaml` key.** An `engine.project_scaffolded` flag +> would be written here and read by nothing, which is a dead setting — the same +> writer-without-reader defect the config gates exist to catch. The filesystem is +> the source of truth: any skill that needs to know globs for `project.godot`, +> `*.uproject`, or `ProjectSettings/ProjectVersion.txt`. + +--- diff --git a/.claude/skills/setup-engine/references/8-verify.md b/.claude/skills/setup-engine/references/8-verify.md new file mode 100644 index 00000000..8a90c4f3 --- /dev/null +++ b/.claude/skills/setup-engine/references/8-verify.md @@ -0,0 +1,61 @@ +# /setup-engine — Sections 8 and 8.5: Verify and Read Back + +> Part of `/setup-engine`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 8. Verify the CLAUDE.md Import + +**This import was already written in Section 4 — do not edit it again and do not +ask again.** Section 4 sets it as part of the same CLAUDE.md write, anchored to +the `ENGINE-REFERENCE-IMPORT` marker. This step only confirms the result. + +Read `CLAUDE.md` and confirm the line under the marker reads: + +```markdown +@docs/engine-reference//VERSION.md +``` + +with `` the engine just configured. If it still points at a different +engine, Section 4 did not complete — go back and finish it rather than patching +the line here. + +> **Why this is a check and not a second write.** Repeating the edit here with +> its own approval prompt would ask the user twice for one change, and the second +> ask would be for work already done. Locate the line by its marker, never by the +> `## Engine Version Reference` heading — the marker exists precisely so the line +> can still be found when the heading moves or is reworded. + +--- + +## 8.5 Read Back What You Just Wrote + +This section exists because prose did not hold. Section 5.5.1's rendering/physics +table already carries an emphatic, source-cited warning naming the two mistakes +most often made here -- and it is still entirely possible to make **both** of +them anyway, writing `Forward+` and `Jolt` for a 2D browser game. Section 3's +`Installed at pin time` row is just as easy to drop silently, because a missing +row leaves no trace. + +Neither is fixed by adding more instructions. They are fixed by verifying the +files after writing them: + +```bash +bash .claude/scripts/project-coherence.sh +``` + +It compares `project.yaml` against `docs/engine-reference//VERSION.md`, +against `project.godot`, and against the engine binary actually on PATH, and it +checks that the files `commands.build` and `commands.test` name exist. + +**Report every `[DIFFERS]` line to the user and resolve it before finishing.** +Each one means two files this skill just wrote disagree, or describe something +that is not there. + +**`[NOT CHECKED]` is not a pass.** Each such line names why a comparison could +not be made -- an absent binary, a missing `project.godot`. Say which ones +applied. A comparison that could not run has not established agreement. + +The script emits observations and never a verdict, per the convention in +CLAUDE.md. The judgement is yours and the user's. + +--- diff --git a/.claude/skills/setup-engine/references/godot-language-config.md b/.claude/skills/setup-engine/references/godot-language-config.md index 16ebd6b3..ea7aa845 100644 --- a/.claude/skills/setup-engine/references/godot-language-config.md +++ b/.claude/skills/setup-engine/references/godot-language-config.md @@ -4,8 +4,14 @@ Lookup tables for `/setup-engine`, split out of the skill body so they cost nothing on invocations that are not Godot. Read this file only when the chosen engine is Godot, and then only the subsection for the chosen language. -Referenced from Sections 4, 5 and 5.5 of -`.claude/skills/setup-engine/SKILL.md` by the names A1, A2 and A3. +Referenced from Sections 4, 5 and 5.5 of `/setup-engine` by the names A1, A2 +and A3. + +**In this file:** + +- A1. CLAUDE.md Technology Stack Templates +- A2. Naming Conventions +- A3. Engine Specialists Routing --- diff --git a/.claude/skills/skill-improve/SKILL.md b/.claude/skills/skill-improve/SKILL.md index 629dcc52..de3cd8a0 100644 --- a/.claude/skills/skill-improve/SKILL.md +++ b/.claude/skills/skill-improve/SKILL.md @@ -85,7 +85,9 @@ NOT ASSESSED — stop: ## Phase 3: Diagnose -Read the full skill file at `.claude/skills/[name]/SKILL.md`. +Read the full skill: `.claude/skills/[name]/SKILL.md` and every file in its `references/` folder, +if it has one — the longest skills keep each phase there. Name the file each +gap is in. For each failing or warning **static** check, identify the exact gap: @@ -114,7 +116,9 @@ Show the full combined diagnosis to the user before proposing any changes. Write a targeted fix for each failure and warning. Show the proposed changes as clearly marked before/after blocks. Only change what is failing — do not -rewrite sections that are passing. +rewrite sections that are passing. In a skill with a `references/` folder, a +fix to a phase's steps goes in that phase's `references/` file, not back into +`SKILL.md`; the question below then names each file the fix changes. Ask: "May I write this improved version to `.claude/skills/[name]/SKILL.md`?" @@ -124,10 +128,11 @@ If the user says no, stop here. ## Phase 5: Write and Retest -Record the current content of the skill file — the exact text, kept in this -conversation — so Phase 6 can restore it. +Record the current content of each file the fix changes — the exact text, kept +in this conversation — so Phase 6 can restore it. -Write the improved skill to `.claude/skills/[name]/SKILL.md`. +Write the improved skill to `.claude/skills/[name]/SKILL.md`, and to each +`references/` file the fix changes. Re-run `/skill-test static [name]` and record the new static score — measured by that run, never stated from the edit. If a category was assigned, also re-run `/skill-test category [name]` and record the new category score. @@ -159,7 +164,8 @@ Show a summary of what was fixed in each dimension. Report: "Combined score did not improve." Show what changed and why it may not have helped. Ask: "May I restore `.claude/skills/[name]/SKILL.md` to the content it had before this run?" -If yes: write the content recorded in Phase 5 back to the file with Write; if no, leave the file as written. Never +— naming every file Phase 5 wrote. +If yes: write the content recorded in Phase 5 back to each file with Write; if no, leave the files as written. Never `git checkout` it — that returns the last *committed* version and discards any edits made before this run that were not yet committed. diff --git a/.claude/skills/skill-test/SKILL.md b/.claude/skills/skill-test/SKILL.md index 6635efef..6583d98b 100644 --- a/.claude/skills/skill-test/SKILL.md +++ b/.claude/skills/skill-test/SKILL.md @@ -62,7 +62,9 @@ missing. ## Phase 2A: Static Mode — Structural Linter -For each skill being tested, read its `SKILL.md` fully and run all 7 checks: +For each skill being tested, read its `SKILL.md` and every file in its `references/` folder +fully, and run all 7 checks on them as one skill — the longest skills keep each +phase in `references/`. The frontmatter checks (1, 6 and 7) read `SKILL.md`. ### Check 1 — Required Frontmatter Fields The file must contain all of these in the YAML frontmatter block: @@ -218,7 +220,8 @@ If either is missing: ### Step 2 — Read Both Files -Read the skill or agent file and the test spec file completely. +Read the skill — its `SKILL.md` and every file in its `references/` folder — or +the agent file, and the test spec file, completely. ### Step 3 — Evaluate Assertions @@ -257,7 +260,8 @@ Code loads into the agent at launch: place of the four skill checks below. **For a skill**, check each of the spec's **Static Assertions** against the -`SKILL.md` frontmatter and body the same way; a literal value is an exact +skill's frontmatter and body (`SKILL.md` and its `references/` files) the same +way; a literal value is an exact comparison. `/skill-test static` runs only its 7 fixed checks, so a spec's own static lines — a verdict keyword, a phase, "May I write" before a named file — are evaluated here or nowhere. @@ -294,7 +298,7 @@ Mark each assertion: to replace. For a skill's **Protocol Compliance** section (always present), evaluate each line -of the spec's own list against the `SKILL.md` exactly as you evaluate a case +of the spec's own list against the skill's files exactly as you evaluate a case assertion — PASS, PARTIAL, FAIL or NOT ASSESSED. Specs put rules there that no case repeats ("covered by the protocol compliance assertions above"), so a list that is not evaluated is a set of rules nobody checks. These four checks are @@ -390,7 +394,8 @@ name the missing section, and never borrow another category's metrics. ### Step 3 — Read Skill -Read the skill's `SKILL.md` or the agent's `.claude/agents/[name].md` fully, +Read the skill's `SKILL.md` and every file in its `references/` folder, or the +agent's `.claude/agents/[name].md`, fully, and the project context Phase 2B Step 3 describes — a metric met by a rule in `CLAUDE.md` or a file it imports is met, citing that file. Its rule for redirect and escalation cases decides the domain, deferral and escalation diff --git a/.claude/skills/smoke-check/SKILL.md b/.claude/skills/smoke-check/SKILL.md index d585dc8d..74d515a7 100644 --- a/.claude/skills/smoke-check/SKILL.md +++ b/.claude/skills/smoke-check/SKILL.md @@ -9,8 +9,6 @@ model: sonnet !`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys automation,workflow,qa.level,testing.strict` - - # Smoke Check This skill is the gate between "implementation done" and "ready for QA @@ -59,688 +57,27 @@ Phase 5 outputs a per-platform verdict table in addition to the overall verdict. ## Phase 1: Detect Test Setup -Before running anything, understand the environment: - -0. **Config coherence**: run `bash .claude/scripts/project-coherence.sh`. - - It compares what `project.yaml` declares against the real project file, the - installed engine binary, and the files `commands.*` name. This runs first - because two of its checks are about *this skill's own inputs*: a - `commands.test` naming a runner that does not exist, or a `commands.build` - naming an export preset with no `export_presets.cfg`, will fail here and read - as a broken build rather than as broken config. - - Report any `[DIFFERS]` lines in the report's Environment section. They do not - by themselves decide the verdict -- but a smoke check run against a project - whose declared engine is not the installed one is worth saying out loud. - -1. **Test framework check**: verify that **game** test files exist — not merely - that `tests/` does. Check the engine's **test root** (from step 3; the table - is in `.claude/docs/directory-structure.md` — Godot `tests/unit/` and - `tests/integration/`, Unity `Assets/Tests/`, Unreal - `Source/*/Private/Tests/`) and `tests/smoke/` for actual test files. A - **test file** is one the engine's test runner executes — a `*_test.gd` suite, - a C# test class, an Unreal automation test source. Markdown checklists do not - count: `/test-setup` always writes `tests/smoke/critical-paths.md`, and - counting it would hide exactly the zero-test state this step exists to catch. - If none are found **at `qa.level: minimal`**, tests are waived at this level: - record the automated row as `WAIVED — qa.level: minimal, no game tests`, skip - the test run in Phase 2 and all of Phase 3 (say so in one line each), run - Phase 2's **build check**, and go on to Phase 4 — the build check and the - launch and critical-path checks are the smoke check at this level, so - a project with no tests can still reach PASS, but never without a run: a - Batch 1 answer that the build was not launched this session leaves the - verdict NOT ASSESSED. - If none are found **at `standard` or `full`**, **deliver a NOT ASSESSED verdict — do not merely stop.** - "Smoke check: **NOT ASSESSED — no game tests found** under - [the test root] or `tests/smoke/`. Run `/test-setup` to scaffold the testing - infrastructure, or point me at where tests live." Then stop. - - > A bare halt is the wrong shape here. - > This is the state with the **least** information about build health, so it is - > the last one that should exit without a verdict: the caller gets no - > machine-readable outcome, and "the skill said nothing" is easy to read as - > "nothing was wrong". Replacing a *wrong* verdict with *no* verdict is not an - > improvement either — the honest result is the one that names what could not - > be established. - - > **Do not gate on `tests/` existing.** `/test-setup` creates `tests/unit/` - > and `tests/integration/` with placeholder files, so the directory tree is - > present on any project that ran setup — whether or not a single game test - > was ever written. Count actual test files instead; gated on the directory, - > a project with no build and zero game tests passes this step. - -2. **CI check**: check whether `.github/workflows/` contains a workflow file - referencing tests. Note in the report whether CI is configured. - -3. **Engine detection**: read `engine.name` from `project.yaml`; if that key - is absent or empty (including when `project.yaml` has no `engine:` block), - fall back to the `Engine:` value in `.claude/docs/technical-preferences.md` - (a `[TO BE CONFIGURED]` value means not configured). Store this for test - command selection in Phase 2. - - Then find the **editor executable** — none of the three engines installs - onto `PATH` by default on Windows or macOS, so a bare `godot` that does not - resolve says nothing about whether the engine is installed. Take the first - that resolves (the file exists, or `command -v` finds it): the executable - `commands.test` names (its quoted path or first word), else the editor - `engine.path` records, else the engine's name on `PATH` (`godot`). Use it - wherever Phase 2 writes `godot` or `""`, quoting a path with a - space; on Unreal, `` is `engine.path`. If none resolves, the test - runner is not available (Phase 2) — on Godot, - `NOT ASSESSED — Godot executable not found (commands.test, engine.path, PATH)`. - -4. **Smoke test list**: check whether `production/qa/smoke-tests.md` or - `tests/smoke/` exists. If a smoke test list is found, load it for use in - Phase 4. If neither exists, smoke tests will be drawn from the current QA - plan (Phase 4 fallback). - -5. **QA plan check**: glob `production/qa/qa-plan-*.md` and take the most - recently modified file. If found, note the path — it will be used in - Phase 3 and Phase 4. If not found, note: "No QA plan found. Run - `/qa-plan sprint` before smoke-checking for best results." (At `workflow: minimal`, - which has no sprints, a QA plan is optional — say so rather than recommend one.) - -Report findings before proceeding: "Environment: [engine]. Editor: [the -resolved executable / not found]. Test directory: -[found / not found]. CI configured: [yes / no]. QA plan: [path / not found]." - ---- +**Read `references/1-detect-setup.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 2: Run Automated Tests -**Run `commands.test` from `project.yaml` when it is set** — it is the -project's own test command, the one `/setup-engine` wrote and CI runs. Use the -per-engine default below only when `commands.test` is absent, and say in the -report which of the two you ran. Wrap it in a timeout (`timeout 900 …`): **a -timeout (exit 124) is a gate FAILURE, never a pass** — the run never completed -and nothing was verified. macOS has no `timeout`: use `gtimeout 900 …` from -Homebrew's `coreutils` (same exit 124), or, with nothing installed, -`perl -e 'alarm shift; exec @ARGV' 900 …`, which exits 142 when time runs out — -a FAILURE the same way. Then read the result for the engine. On every engine -one outcome looks like success and is not; each is named below. - -**Godot 4** — first check that `addons/gdUnit4/bin/GdUnitCmdTool.gd` exists — -the folder has a **capital U**. If it does not, report -`NOT ASSESSED — gdUnit4 not installed at addons/gdUnit4/` instead of running -anything. Then import, whether you run `commands.test` or the -default. A fresh clone has no `.godot/` class cache, and without it gdUnit4's -runner does not load; a cache that predates a new `class_name` fails valid -code with 105. The import takes seconds when nothing changed (`godot` below is -the executable Phase 1 step 3 resolved): -```bash -godot --headless --path . --import -godot --headless -s -d --remote-debug tcp://127.0.0.1:0 res://addons/gdUnit4/bin/GdUnitCmdTool.gd -a res://tests --ignoreHeadlessMode 2>&1 -``` -gdUnit4's exit code gives the verdict (6.1.3): -- **0** — every test passed: PASS. **But exit 0 over zero tests is not a pass:** - gdUnit4 aborts and still exits 0, so if the output says `No test cases found`, - the verdict is `NOT ASSESSED — no tests found`. -- **101** — every test passed but a test leaked nodes (orphans): PASS WITH - WARNINGS, naming the orphan count from the output. Not a failure. -- **100** — a test failed: FAIL. **105** — a test script does not parse: FAIL. -- **103** — gdUnit4 refused to run headless (`--ignoreHeadlessMode` missing); - **104** — Godot older than 4.3: `NOT ASSESSED`, with that reason. -- **1** — Godot's own error: `GdUnitCmdTool.gd` did not load (`Failed to load - script`), so no test ran. Usually the import above was skipped; after it, - exit 1 is a FAIL. - -Every run opens with two `ERROR:` lines about the remote port -(`127.0.0.1:0`) — that is the `--remote-debug` flag working, not a failure. -Never drop the flag: without it a script error opens Godot's interactive -debugger and the run hangs at a `debug>` prompt until the timeout. - -**Unity:** -Unity **can** run tests headlessly via shell. Do not skip to reading artifacts. - -First confirm the Unity Test Framework is installed. A project without it does -not fail cleanly — it **hangs** until something kills it, which is the -observation the old "Unity cannot test headlessly" advice was generalised from: -```bash -grep -q 'com.unity.test-framework' Packages/manifest.json && echo present || echo ABSENT -``` -If ABSENT, report `NOT ASSESSED — Unity Test Framework not installed` and -give the one-line fix (add `com.unity.test-framework` to `Packages/manifest.json`). -**Do not fall through to reading stale artifacts** — an unknown-age XML -reported as a pass is worse than no gate. - -If present, the default is (the **editor** executable — `Unity` on `PATH` may be -Unity's separate CLI). Delete the old results file first, whether you run -`commands.test` or this default: -```bash -rm -f test-results/editmode.xml -timeout 900 "" -batchmode -runTests -projectPath . -testPlatform EditMode -testResults test-results/editmode.xml -``` -Exit 0 when every test passes, 2 on a failure. **Exit 1 or 3 is a FAIL**: 1 -means the project did not compile (the editor log has the `error CS…` lines), -3 that the run itself failed; 4 (an unknown `-testPlatform`) or any other -non-zero exit is a FAIL too. A compile error writes no results file — which -is why the old one is deleted first: left in place, the last run's pass is read -as this run's. After any exit, no results file is a FAIL. Parse the `` -element of the results file for `testcasecount`, `passed` and `failed`. **`testcasecount="0"` -is NOT ASSESSED, never a pass**: tests outside `Assets/` are never compiled, and -Unity then reports `result="Passed"` with exit 0 over zero tests. - -**Play Mode is a second run.** `-testPlatform EditMode` — this default, and -`commands.test` as `/setup-engine` writes it — never runs the integration tests -`/test-setup` scaffolds under `Assets/Tests/PlayMode/`. When that folder holds a -test file and the command you ran did not already pass `-testPlatform PlayMode`, -run Play Mode the same way, into its own results file, and read it by the same -rules: -```bash -rm -f test-results/playmode.xml -timeout 900 "" -batchmode -runTests -projectPath . -testPlatform PlayMode -testResults test-results/playmode.xml -``` -Report each platform on its own line — `EditMode: PASS (12/12)`, -`PlayMode: FAIL (1 failure)`. A Play Mode run that could not be made is -reported by name, `PlayMode: NOT RUN — [reason]`: the Edit Mode result does not -cover those tests, so it cannot make the automated-test row a PASS. - -**Unreal Engine** — build the editor target first, whether you then run -`commands.test` or the default. `Binaries/` is not committed, and without a -built game module the editor stops with "The game module could not be found", -exit 1, before running any test. The build is incremental — seconds when -nothing changed; a failed build is a FAIL. - -**Pick the commands for this machine** with `uname -s`: `Linux` → Linux, -`Darwin` → macOS, anything else (`MINGW*`, `MSYS*`, `CYGWIN*`) → Windows. The -Windows forms below were run on UE 5.7; the Linux and macOS forms come from -Epic's documentation — `docs/engine-reference/unreal/current-best-practices.md`, -"Command Line", has them with their sources. On Windows use -`UnrealBuildTool.exe`, not `Build.bat`: run from bash, `Build.bat` fails on an -engine path with spaces. -```bash -# Windows -timeout 1800 "/Engine/Binaries/DotNET/UnrealBuildTool/UnrealBuildTool.exe" Editor Win64 Development -Project="$(pwd -W 2>/dev/null || pwd)/.uproject" 2>&1 -# Linux -timeout 1800 "/Engine/Build/BatchFiles/Linux/Build.sh" Editor Linux Development -Project="$(pwd -W 2>/dev/null || pwd)/.uproject" 2>&1 -# macOS (timeout: see the macOS note above) -gtimeout 1800 "/Engine/Build/BatchFiles/Mac/Build.sh" Editor Mac Development -Project="$(pwd -W 2>/dev/null || pwd)/.uproject" 2>&1 -``` -Then the default. Keep `-stdout -FullStdOutLogOutput`; when `commands.test` -lacks them, add them to the command for this run only: without them the editor -prints nothing, and the lines below are only in `Saved/Logs/.log`. -Give the project as an **absolute** path — when `commands.test` passes a -relative one, run it with the absolute path instead: UE 5.7 -does not find a relative `.uproject` and exits 1 (`Project file not -found`). `$(pwd -W 2>/dev/null || pwd)` gives the `C:/…` form in Git Bash and -the plain path elsewhere; `$PWD` alone fails when `MSYS_NO_PATHCONV` is set. -Either way, say in the report what you changed and tell the user to fix -`commands.test` in `project.yaml` — never edit `project.yaml` without asking. -`.` in the filter is the root the tests are named under: the project -name, or the distinct root `/setup-engine` chose when the project's name is -also an engine area — read one test's name string under -`Source/*/Private/Tests/` if unsure. -```bash -# Windows -timeout 1800 "/Engine/Binaries/Win64/UnrealEditor-Cmd.exe" "$(pwd -W 2>/dev/null || pwd)/.uproject" -ExecCmds="Automation RunTests .; Quit" -unattended -nullrhi -stdout -FullStdOutLogOutput 2>&1 -# Linux -timeout 1800 "/Engine/Binaries/Linux/UnrealEditor" "$(pwd -W 2>/dev/null || pwd)/.uproject" -ExecCmds="Automation RunTests .; Quit" -unattended -nullrhi -stdout -FullStdOutLogOutput 2>&1 -``` -**macOS has no sourced test command.** Epic documents only the -`UnrealEditor.app` bundle, not a command-line editor inside it. Run a -`commands.test` the user has set and confirmed; with none, report -`NOT ASSESSED — Unreal test command on macOS not sourced; set commands.test to the editor command you use` -instead of guessing a path. -Read the output, not the exit code: a failing test and a run that matched nothing both exit 255. -- `Result={Fail}` on any line → FAIL. -- `No automation tests matched` → `NOT ASSESSED — no tests found` (tests - outside `Source//` are never built), not FAIL. -- Exit 0 with `Result={Success}` lines → PASS. -- Any other non-zero exit (`Project file not found`, `The game module … could - not be found`) → FAIL: no test ran. The exception: the editor never started (exit 126 or 127, `command not found`) — that is the runner not being - available, below, and `NOT ASSESSED`. - -**Unknown engine / not configured:** -"Engine not configured in `project.yaml` or -`.claude/docs/technical-preferences.md`. Run `/setup-engine` to specify the -engine, then re-run `/smoke-check`." - -**If the test runner is not available in this environment** (no editor -executable resolved in Phase 1 step 3, runner script not found, etc.), report -clearly: - -"Automated tests could not be executed — engine executable not found (checked -`commands.test`, `engine.path` and `PATH`; set `engine.path`, or put the -editor's full path in `commands.test`). Status will be recorded as NOT RUN. -Confirm test results from your local IDE -or CI pipeline. Until you do, the verdict is NOT ASSESSED — not FAIL, and not -a pass either: nothing has been observed about this build yet." - -Do not treat NOT RUN as an automatic FAIL. Record it, and let the developer's -manual confirmation in Phase 4 resolve it. Until that confirmation arrives the -verdict is **NOT ASSESSED** (see the verdict rules in Phase 5), which ranks -above both pass values and below FAIL. An unrun suite is not a healthy build; it -is an unknown one, and the two need different follow-ups. - -Parse runner output and extract: -- Total tests run -- Passing count -- Failing count -- Names of any failing tests (up to 10; if more, note the count) -- Any crash or error output from the runner itself - -**Build check — the WAIVED path only** (`qa.level: minimal`, no game tests; -Phase 1 step 1). With no suite to run, run the project's own boot check: -`commands.smoke` when set, else `commands.build` when set, with the executable -Phase 1 step 3 resolved, under the same timeout rules (`timeout 900`, or -`timeout 1800` for `commands.build`; a timeout is a FAIL). On Godot, run the -import line above first. Read the result as `/setup-engine` documents it: -Godot `smoke` exits 0 even on a parse error, so a `SCRIPT ERROR` line in its -output is a FAIL, and so is `Can't run project: no main scene defined` — the -game cannot launch; Unity `smoke` exits 1 on a compile error; any other -non-zero exit is a FAIL. Record `Build check: PASS — [command] exit 0`, -`FAIL — [reason]`, or `NOT RUN — [commands.smoke and commands.build unset | -executable not found]`. A build check that did not run is named in the report -and leaves the launch in Batch 1 to carry the verdict; it never passes on its -own. - ---- +**Read `references/2-run-tests.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 3: Check Test Coverage -Draw the story list from, in priority order: -1. The QA plan found in Phase 1 (its Test Summary table lists expected test - file paths per story) -2. The current sprint plan from `production/sprints/` (most recently modified - file) -3. If the `quick` argument was passed, skip this phase entirely and note: - "Coverage scan skipped — run `/smoke-check sprint` for full coverage - analysis." - -For each story in scope: - -1. Extract the system slug from the story's file path - (e.g., `production/epics/combat/story-001.md` → `combat`) -2. Glob `tests/unit/[system]/` and `tests/integration/[system]/` for files - whose name contains the story slug or a closely related term -3. Check the story file itself for a `Test file:` header field or a - "Test Evidence" section - -Assign a coverage status to each story: - -| Status | Meaning | -|--------|---------| -| **COVERED** | A test file was found matching this story's system and scope | -| **MANUAL** | Story type is Visual/Feel or UI; a test evidence document was found | -| **MISSING** | Logic or Integration story with no matching test file | -| **EXPECTED** | Config/Data story — no test file required; spot-check is sufficient | -| **UNKNOWN** | Story file missing or unreadable | - -MISSING entries are advisory gaps. They do not cause a FAIL verdict but must -appear prominently in the report and must be resolved before `/story-done` can -fully close those stories. - ---- +**Read `references/3-coverage.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 4: Run Manual Smoke Checks -Draw the smoke test checklist from, in priority order (and name the one you used in the report): -1. The QA plan's "Smoke Test Scope" section (if QA plan was found in Phase 1) -2. `production/qa/smoke-tests.md` (if it exists) -3. `tests/smoke/` directory contents (if it exists) -4. The standard fallback list below (used only when none of the above exist) - -**Name the source you used in the report**, on its own line — *"Checklist source: -`production/qa/smoke-tests.md`"*, or *"Checklist source: standard fallback list — -no QA plan scope, no `production/qa/smoke-tests.md`, no `tests/smoke/`."* The -fallback is a real fallback, so nothing is silently skipped here; what was -missing is that a report drawn from the generic list and one drawn from this -project's own smoke definitions were indistinguishable. `/gate-check` now -validates a smoke report's claims against the repo, and it cannot weigh them -without knowing what the checklist was drawn from. - -Tailor batches 2 and 3 to the actual systems identified from the sprint or QA -plan. Replace bracketed placeholders with real mechanic names from the current -sprint's stories. - -Use `AskUserQuestion` to batch-verify. Keep to at most 3 calls. - -**Batch 1 — Core stability (always run):** one call, two questions — an empty -failure list means nothing unless somebody launched the build. -``` -question: "Did you launch the current build this session?" -multiSelect: false -options: - - "Yes — I launched it and checked the items below" - - "No — I have not launched the current build this session" - -question: "Core stability — select any items that FAILED (leave all unselected if everything passed):" -multiSelect: true -options: - - "Game does not launch or crashes before reaching the main menu" - - "New game / session fails to start" - - "Main menu does not respond to inputs" - - "Crash or hang observed during basic navigation" -``` - -For any selected item, ask the user to briefly describe what failed before generating the report. - -If the build was **not launched**, the Batch 1 checks could not be executed: -record them as `NOT RUN — build not launched this session`, skip Batches 2 and -3 and any platform batch (say so — they need a running build), and ignore the -unselected failure list. The verdict is then NOT ASSESSED unless something else -FAILED. - -**Batch 2 — Sprint changes and regression (always run):** -``` -question: "Sprint changes and regression — select any items that FAILED (leave all unselected if everything passed):" -multiSelect: true -options: - - "[Primary mechanic this sprint] — FAILED" - - "[Second notable change this sprint, if any] — FAILED" - - "Regression in a previous sprint's feature — FAILED" - - "Other unexpected breakage observed — FAILED" -``` - -For any selected item, ask the user to briefly describe what broke before generating the report. - -**Batch 3 — Data integrity and performance (run unless `quick` argument):** -``` -question: "Data integrity and performance — select any items that FAILED or were skipped (leave all unselected if everything passed):" -multiSelect: true -options: - - "Save / load — FAILED (data loss or corruption observed)" - - "Save / load — N/A (save system not yet implemented)" - - "Frame rate drops or hitches observed — FAILED" - - "Performance not checked this session" -``` - -For any FAILED item selected, ask the user to describe what broke before generating the report. - -Record each response verbatim for the Phase 5 report. - -**Platform Batches** *(run only if `--platform` argument was provided)*: - -**PC platform** (`--platform pc` or `--platform all`): -``` -question: "PC Platform — select any items that FAILED (leave all unselected if everything passed):" -multiSelect: true -options: - - "Keyboard controls — FAILED (describe issue after)" - - "Mouse input or cursor visibility — FAILED (describe issue after)" - - "Windowed / fullscreen mode — FAILED (describe issue after)" - - "Resolution change — FAILED (describe issue after)" -``` - -For any selected item, ask the user to briefly describe what failed before generating the report. - -**Console platform** (`--platform console` or `--platform all`): -``` -question: "Console Platform — select any items that FAILED (leave all unselected if everything passed):" -multiSelect: true -options: - - "Gamepad input — FAILED (describe issue after)" - - "UI outside TV safe zone / text clipped — FAILED (describe what is clipped after)" - - "Keyboard/mouse fallback shown to gamepad user — FAILED (describe after)" - - "Cold start (no prior save) — FAILED (describe issue after)" -``` - -For any selected item, ask the user to briefly describe what failed before generating the report. - -**Mobile platform** (`--platform mobile` or `--platform all`): -``` -question: "Mobile Platform — select any items that FAILED (leave all unselected if everything passed):" -multiSelect: true -options: - - "Touch controls — FAILED (describe issue after)" - - "Orientation change (portrait ↔ landscape) — FAILED (describe what breaks after)" - - "Background / foreground transition (home button) — FAILED (describe issue after)" - - "Performance / thermal throttling on target device — FAILED (describe after)" -``` - -For any selected item, ask the user to briefly describe what failed before generating the report. - ---- +**Read `references/4-manual-checks.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 5: Generate Report -Assemble the full smoke check report: - -````markdown -## Smoke Check Report -**Date**: [date] -**Sprint**: [sprint name / number, or "Not identified"] -**Engine**: [engine] -**QA Plan**: [path, or "Not found — run /qa-plan first"] -**Argument**: [sprint | quick | blank] - ---- - -### Automated Tests - -**Status**: [PASS ([N] tests, [N] passing) | PASS WITH WARNINGS ([N] tests -passing; [the runner's warning, e.g. [N] orphan nodes leaked]) | FAIL ([N] -failures, or did not complete: [timeout | compile, parse or build error | no -results file]) | NOT ASSESSED ([reason, e.g. zero tests executed, runner could -not run]) | NOT RUN ([reason]) | WAIVED (qa.level: minimal — no game tests)] - -[Unity: one Status line per test platform — `EditMode:` and `PlayMode:`.] - -[WAIVED only:] **Build check**: [PASS — `[command]` exit 0 | FAIL — [reason] | -NOT RUN — [commands.smoke and commands.build unset | executable not found]] - -[If FAIL, list failing tests:] -- `[test name]` — [brief failure description from runner output] - -[If NOT RUN:] -"Manual confirmation required: did tests pass in your local IDE or CI? This -will determine whether the automated test row contributes to a FAIL verdict." - ---- - -### Test Coverage - -| Story | Type | Test File | Coverage Status | -|-------|------|-----------|----------------| -| [title] | Logic | `tests/unit/[system]/[slug]_test.[ext]` | COVERED | -| [title] | Visual/Feel | `production/qa/evidence/[slug]-screenshots.md` | MANUAL | -| [title] | Logic | — | MISSING ⚠ | -| [title] | Config/Data | — | EXPECTED | - -**Summary**: [N] covered, [N] manual, [N] missing, [N] expected. - ---- - -### Manual Smoke Checks - -- [x] Build launched this session — yes [or: `NOT RUN — build not launched this session`; the batches below were not asked] -- [x] Game launches without crash — PASS -- [x] New game starts — PASS -- [x] [Core mechanic] — PASS -- [ ] [Other check] — FAIL: [user's description] -- [x] Save / load — PASS -- [-] Performance — not checked this session - ---- - -### Missing Test Evidence - -Stories that must have test evidence before they can be marked COMPLETE via -`/story-done`: - -- **[story title]** (`[path]`) — Logic story has no test file. - Expected location: `tests/unit/[system]/[story-slug]_test.[ext]` - -[If none:] "All Logic and Integration stories have test coverage." - ---- - -### Platform-Specific Results *(only if `--platform` was provided)* - -| Platform | Checks Run | Passed | Failed | Platform Verdict | -|----------|-----------|--------|--------|-----------------| -| PC | [N] | [N] | [N] | PASS / FAIL | -| Console | [N] | [N] | [N] | PASS / FAIL | -| Mobile | [N] | [N] | [N] | PASS / FAIL | - -**Platform notes**: [any platform-specific observations not captured in pass/fail] - -Any platform with one or more FAIL checks contributes to the overall FAIL verdict. - ---- - -### Verdict: [PASS | PASS WITH WARNINGS | NOT ASSESSED | FAIL] - -[Verdict rules — first matching rule wins:] - -**FAIL** if ANY of: -- Automated test suite ran and reported one or more test failures -- The automated suite did not complete: a timeout, a compile, parse or build - error, or no results file after the run (Phase 2 names each engine's form) -- The build check (WAIVED path) failed: a non-zero exit, a timeout, or a Godot - `SCRIPT ERROR` or no-main-scene line -- Any Batch 1 (core stability) check returned FAIL -- Any Batch 2 (primary sprint mechanic or regression check) returned FAIL - -**NOT ASSESSED** if ANY of: -- The automated suite is **unconfirmed NOT RUN** — nobody has reported a result -- The runner could not run (gdUnit4 103 or 104, gdUnit4 or the Unity Test - Framework not installed), or it ran and executed zero tests - (`No test cases found`, `testcasecount="0"`, `No automation tests matched`) -- Unity Play Mode tests exist and are `PlayMode: NOT RUN`, unconfirmed — the - Edit Mode result does not cover them -- A Batch 1 or Batch 2 check could not be executed (no build, engine not - configured, platform unavailable) as opposed to executing and failing — - including a Batch 1 answer that the build was not launched this session -- **Any story's coverage row is `UNKNOWN`** (Phase 3: story file missing or - unreadable). A story nobody could read is not a story with no gaps — without - this line, a run where *every* row is UNKNOWN and the suite passes matches - **PASS**, because PASS only requires "no MISSING entries" -- **Batch 3 was offered and skipped** ("Performance not checked this session"). - It is not a FAIL, not an execution failure, and not "PASS or N/A", so without - this line it matches no rule at all and renders as `[-]` beside a PASS - -**PASS WITH WARNINGS** if ALL of: -- Automated tests PASS or PASS WITH WARNINGS, WAIVED at `qa.level: minimal`, or - NOT RUN **and the developer has confirmed the result from their local IDE or CI** -- All Batch 1 and Batch 2 smoke checks PASS -- At least one warning: a Logic/Integration story with MISSING test evidence, - a runner warning on a passing suite (gdUnit4 101 — orphan nodes leaked), or - a NOT RUN suite the developer confirmed - -**PASS** if ALL of: -- Automated tests PASS, or WAIVED (`qa.level: minimal` and no game tests exist — - the build check, when `commands.smoke` or `commands.build` is set, and the - launch and critical-path batches below then carry the verdict) -- All smoke checks in all batches PASS or N/A -- No MISSING test evidence entries -```` - -**`NOT ASSESSED` — the build nobody could check.** Rank: it **outranks PASS and -PASS WITH WARNINGS** and **ranks below FAIL**. A suite that never ran has not -shown the build is healthy; a suite that ran and failed is the more actionable -finding and must not be demoted behind one that did not run. - -This is a change in where unconfirmed `NOT RUN` lands, and it is deliberate. The -rule below — **never treat NOT RUN as an automatic FAIL** — is unchanged and -still correct: NOT ASSESSED is not a FAIL, and it ranks below one. What changes -is that an unrun suite no longer resolves to a *pass* verdict while waiting for a -confirmation that may never come. Confirmed NOT RUN (the developer reports the -result from their own IDE or CI) still lands at PASS WITH WARNINGS, because -somebody did look. - ---- +**Read `references/5-report.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 6: Write and Gate -Present the full report in conversation, then ask: - -"May I write this smoke check report to `production/qa/smoke-[date].md`?" - -Write only after approval. - -**First apply `qa.level` (resolved earlier).** At `qa.level: minimal`, a FAIL is -**advisory** regardless of `testing.strict.config` — skip the resolution below and -deliver the advisory-FAIL outcome (smoke-check is optional at minimal and never -blocks hand-off). Otherwise: - -**Resolve the gate enforcement level.** A FAIL verdict either *blocks* QA -hand-off or is *flagged while hand-off proceeds*, governed by the -`testing.strict` block **resolved in the resolved-config block at the top of this skill** (which merges -`project.local.yaml` over `project.yaml` — read that block, not the file, or a -developer's local override is silently ignored): - -1. Take `testing.strict.config` from that resolved block. If its value is `true` - (case-insensitive) → blocking; if `false` → advisory; `unset` → fall through. -2. Else read `testing.strict` as a plain boolean (legacy single-value form) — if - its value is `true` or `false`, it applies. -3. Else default to **blocking** — an unset `testing.strict.config` keeps - smoke-check's FAIL gate blocking (behavior unchanged from before this setting - existed). Smoke check is a build-health gate, so its unset default is strict - even though the `config` test type defaults to advisory elsewhere. The - reciprocal carve-out is recorded in `.claude/skills/story-done/SKILL.md` and - `.claude/docs/coding-standards.md`, which own the per-story evidence table. - -Only `true` and `false` (case-insensitive) are recognized at steps 1–2. A key -that is present but holds any other value — `maybe`, `1`, `yes`, etc. — is -treated as unset: continue to the next step, and surface the unrecognized value -to the user. - -After writing, deliver the gate verdict: - -**If verdict is FAIL and the gate is blocking:** - -"The smoke check failed. Do not hand off to QA until these failures are -resolved: - -[List each failing automated test or smoke check with a one-line description] - -Fix the failures and run `/smoke-check` again to re-gate before QA hand-off." - -**If verdict is FAIL and the gate is advisory** (`testing.strict.config: false`): - -"The smoke check failed, but `testing.strict.config` is set to advisory — QA -hand-off is not blocked. Resolve these before release: - -[List each failing automated test or smoke check with a one-line description] - -QA hand-off: share `production/qa/qa-plan-[sprint].md` with the qa-tester -agent to begin manual verification. Re-run `/smoke-check` once the failures -are fixed." - -**If verdict is NOT ASSESSED:** - -"The smoke check could not establish build health — it did not fail, it did not -run. Do not hand off to QA on this result: - -[Name each check that could not execute, and why: suite unconfirmed NOT RUN, -`PlayMode: NOT RUN`, zero tests executed, runner not installed, engine -executable not found, no build, build not launched this session, platform -unavailable] - -[For each, the one thing that would make it runnable — e.g. 'confirm the suite -result from your IDE or CI', 'run `/setup-engine`', 'set `engine.path`', -'produce a build', 'launch the build and play the checks'.] - -Re-run `/smoke-check` once any of those is resolved." - -This outcome is **not governed by `testing.strict.config`**. That setting decides -whether a *failure* blocks hand-off; it has nothing to say about a check that -never produced a result, and reading an unrun check as advisory-therefore-fine is -the exact substitution this verdict exists to prevent. Say what could not be -checked and let the user decide — do not resolve it to either pass or FAIL on -their behalf. - -**If verdict is PASS WITH WARNINGS:** - -"Smoke check passed with warnings. The build is ready for manual QA. - -Advisory items to resolve before running `/story-done` on affected stories: -[list MISSING test evidence entries, and any runner warning — e.g. the orphan -count] - -QA hand-off: share `production/qa/qa-plan-[sprint].md` with the qa-tester -agent to begin manual verification." - -**If verdict is PASS:** - -"Smoke check passed cleanly. The build is ready for manual QA. - -QA hand-off: share `production/qa/qa-plan-[sprint].md` with the qa-tester -agent to begin manual verification." - ---- +**Read `references/6-write-gate.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Collaborative Protocol diff --git a/.claude/skills/smoke-check/references/1-detect-setup.md b/.claude/skills/smoke-check/references/1-detect-setup.md new file mode 100644 index 00000000..a4c72ea6 --- /dev/null +++ b/.claude/skills/smoke-check/references/1-detect-setup.md @@ -0,0 +1,94 @@ +# /smoke-check — Phase 1: Detect Test Setup + +> Part of `/smoke-check`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 1: Detect Test Setup + +Before running anything, understand the environment: + +0. **Config coherence**: run `bash .claude/scripts/project-coherence.sh`. + + It compares what `project.yaml` declares against the real project file, the + installed engine binary, and the files `commands.*` name. This runs first + because two of its checks are about *this skill's own inputs*: a + `commands.test` naming a runner that does not exist, or a `commands.build` + naming an export preset with no `export_presets.cfg`, will fail here and read + as a broken build rather than as broken config. + + Report any `[DIFFERS]` lines in the report's Environment section. They do not + by themselves decide the verdict -- but a smoke check run against a project + whose declared engine is not the installed one is worth saying out loud. + +1. **Test framework check**: verify that **game** test files exist — not merely + that `tests/` does. Check the engine's **test root** (from step 3; the table + is in `.claude/docs/directory-structure.md` — Godot `tests/unit/` and + `tests/integration/`, Unity `Assets/Tests/`, Unreal + `Source/*/Private/Tests/`) and `tests/smoke/` for actual test files. A + **test file** is one the engine's test runner executes — a `*_test.gd` suite, + a C# test class, an Unreal automation test source. Markdown checklists do not + count: `/test-setup` always writes `tests/smoke/critical-paths.md`, and + counting it would hide exactly the zero-test state this step exists to catch. + If none are found **at `qa.level: minimal`**, tests are waived at this level: + record the automated row as `WAIVED — qa.level: minimal, no game tests`, skip + the test run in Phase 2 and all of Phase 3 (say so in one line each), run + Phase 2's **build check**, and go on to Phase 4 — the build check and the + launch and critical-path checks are the smoke check at this level, so + a project with no tests can still reach PASS, but never without a run: a + Batch 1 answer that the build was not launched this session leaves the + verdict NOT ASSESSED. + If none are found **at `standard` or `full`**, **deliver a NOT ASSESSED verdict — do not merely stop.** + "Smoke check: **NOT ASSESSED — no game tests found** under + [the test root] or `tests/smoke/`. Run `/test-setup` to scaffold the testing + infrastructure, or point me at where tests live." Then stop. + + > A bare halt is the wrong shape here. + > This is the state with the **least** information about build health, so it is + > the last one that should exit without a verdict: the caller gets no + > machine-readable outcome, and "the skill said nothing" is easy to read as + > "nothing was wrong". Replacing a *wrong* verdict with *no* verdict is not an + > improvement either — the honest result is the one that names what could not + > be established. + + > **Do not gate on `tests/` existing.** `/test-setup` creates `tests/unit/` + > and `tests/integration/` with placeholder files, so the directory tree is + > present on any project that ran setup — whether or not a single game test + > was ever written. Count actual test files instead; gated on the directory, + > a project with no build and zero game tests passes this step. + +2. **CI check**: check whether `.github/workflows/` contains a workflow file + referencing tests. Note in the report whether CI is configured. + +3. **Engine detection**: read `engine.name` from `project.yaml`; if that key + is absent or empty (including when `project.yaml` has no `engine:` block), + fall back to the `Engine:` value in `.claude/docs/technical-preferences.md` + (a `[TO BE CONFIGURED]` value means not configured). Store this for test + command selection in Phase 2. + + Then find the **editor executable** — none of the three engines installs + onto `PATH` by default on Windows or macOS, so a bare `godot` that does not + resolve says nothing about whether the engine is installed. Take the first + that resolves (the file exists, or `command -v` finds it): the executable + `commands.test` names (its quoted path or first word), else the editor + `engine.path` records, else the engine's name on `PATH` (`godot`). Use it + wherever Phase 2 writes `godot` or `""`, quoting a path with a + space; on Unreal, `` is `engine.path`. If none resolves, the test + runner is not available (Phase 2) — on Godot, + `NOT ASSESSED — Godot executable not found (commands.test, engine.path, PATH)`. + +4. **Smoke test list**: check whether `production/qa/smoke-tests.md` or + `tests/smoke/` exists. If a smoke test list is found, load it for use in + Phase 4. If neither exists, smoke tests will be drawn from the current QA + plan (Phase 4 fallback). + +5. **QA plan check**: glob `production/qa/qa-plan-*.md` and take the most + recently modified file. If found, note the path — it will be used in + Phase 3 and Phase 4. If not found, note: "No QA plan found. Run + `/qa-plan sprint` before smoke-checking for best results." (At `workflow: minimal`, + which has no sprints, a QA plan is optional — say so rather than recommend one.) + +Report findings before proceeding: "Environment: [engine]. Editor: [the +resolved executable / not found]. Test directory: +[found / not found]. CI configured: [yes / no]. QA plan: [path / not found]." + +--- diff --git a/.claude/skills/smoke-check/references/2-run-tests.md b/.claude/skills/smoke-check/references/2-run-tests.md new file mode 100644 index 00000000..36948ce4 --- /dev/null +++ b/.claude/skills/smoke-check/references/2-run-tests.md @@ -0,0 +1,204 @@ +# /smoke-check — Phase 2: Run Automated Tests + +> Part of `/smoke-check`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 2: Run Automated Tests + +**In this file:** + +- `commands.test` first +- Godot 4 +- Unity: Edit Mode, then Play Mode as a second run +- Unreal Engine: build first, commands per OS, macOS +- Unknown engine / not configured +- Test runner not available here +- Build check (the WAIVED path only) + +**Run `commands.test` from `project.yaml` when it is set** — it is the +project's own test command, the one `/setup-engine` wrote and CI runs. Use the +per-engine default below only when `commands.test` is absent, and say in the +report which of the two you ran. Wrap it in a timeout (`timeout 900 …`): **a +timeout (exit 124) is a gate FAILURE, never a pass** — the run never completed +and nothing was verified. macOS has no `timeout`: use `gtimeout 900 …` from +Homebrew's `coreutils` (same exit 124), or, with nothing installed, +`perl -e 'alarm shift; exec @ARGV' 900 …`, which exits 142 when time runs out — +a FAILURE the same way. Then read the result for the engine. On every engine +one outcome looks like success and is not; each is named below. + +**Godot 4** — first check that `addons/gdUnit4/bin/GdUnitCmdTool.gd` exists — +the folder has a **capital U**. If it does not, report +`NOT ASSESSED — gdUnit4 not installed at addons/gdUnit4/` instead of running +anything. Then import, whether you run `commands.test` or the +default. A fresh clone has no `.godot/` class cache, and without it gdUnit4's +runner does not load; a cache that predates a new `class_name` fails valid +code with 105. The import takes seconds when nothing changed (`godot` below is +the executable Phase 1 step 3 resolved): +```bash +godot --headless --path . --import +godot --headless -s -d --remote-debug tcp://127.0.0.1:0 res://addons/gdUnit4/bin/GdUnitCmdTool.gd -a res://tests --ignoreHeadlessMode 2>&1 +``` +gdUnit4's exit code gives the verdict (6.1.3): +- **0** — every test passed: PASS. **But exit 0 over zero tests is not a pass:** + gdUnit4 aborts and still exits 0, so if the output says `No test cases found`, + the verdict is `NOT ASSESSED — no tests found`. +- **101** — every test passed but a test leaked nodes (orphans): PASS WITH + WARNINGS, naming the orphan count from the output. Not a failure. +- **100** — a test failed: FAIL. **105** — a test script does not parse: FAIL. +- **103** — gdUnit4 refused to run headless (`--ignoreHeadlessMode` missing); + **104** — Godot older than 4.3: `NOT ASSESSED`, with that reason. +- **1** — Godot's own error: `GdUnitCmdTool.gd` did not load (`Failed to load + script`), so no test ran. Usually the import above was skipped; after it, + exit 1 is a FAIL. + +Every run opens with two `ERROR:` lines about the remote port +(`127.0.0.1:0`) — that is the `--remote-debug` flag working, not a failure. +Never drop the flag: without it a script error opens Godot's interactive +debugger and the run hangs at a `debug>` prompt until the timeout. + +**Unity:** +Unity **can** run tests headlessly via shell. Do not skip to reading artifacts. + +First confirm the Unity Test Framework is installed. A project without it does +not fail cleanly — it **hangs** until something kills it, which is the +observation the old "Unity cannot test headlessly" advice was generalised from: +```bash +grep -q 'com.unity.test-framework' Packages/manifest.json && echo present || echo ABSENT +``` +If ABSENT, report `NOT ASSESSED — Unity Test Framework not installed` and +give the one-line fix (add `com.unity.test-framework` to `Packages/manifest.json`). +**Do not fall through to reading stale artifacts** — an unknown-age XML +reported as a pass is worse than no gate. + +If present, the default is (the **editor** executable — `Unity` on `PATH` may be +Unity's separate CLI). Delete the old results file first, whether you run +`commands.test` or this default: +```bash +rm -f test-results/editmode.xml +timeout 900 "" -batchmode -runTests -projectPath . -testPlatform EditMode -testResults test-results/editmode.xml +``` +Exit 0 when every test passes, 2 on a failure. **Exit 1 or 3 is a FAIL**: 1 +means the project did not compile (the editor log has the `error CS…` lines), +3 that the run itself failed; 4 (an unknown `-testPlatform`) or any other +non-zero exit is a FAIL too. A compile error writes no results file — which +is why the old one is deleted first: left in place, the last run's pass is read +as this run's. After any exit, no results file is a FAIL. Parse the `` +element of the results file for `testcasecount`, `passed` and `failed`. **`testcasecount="0"` +is NOT ASSESSED, never a pass**: tests outside `Assets/` are never compiled, and +Unity then reports `result="Passed"` with exit 0 over zero tests. + +**Play Mode is a second run.** `-testPlatform EditMode` — this default, and +`commands.test` as `/setup-engine` writes it — never runs the integration tests +`/test-setup` scaffolds under `Assets/Tests/PlayMode/`. When that folder holds a +test file and the command you ran did not already pass `-testPlatform PlayMode`, +run Play Mode the same way, into its own results file, and read it by the same +rules: +```bash +rm -f test-results/playmode.xml +timeout 900 "" -batchmode -runTests -projectPath . -testPlatform PlayMode -testResults test-results/playmode.xml +``` +Report each platform on its own line — `EditMode: PASS (12/12)`, +`PlayMode: FAIL (1 failure)`. A Play Mode run that could not be made is +reported by name, `PlayMode: NOT RUN — [reason]`: the Edit Mode result does not +cover those tests, so it cannot make the automated-test row a PASS. + +**Unreal Engine** — build the editor target first, whether you then run +`commands.test` or the default. `Binaries/` is not committed, and without a +built game module the editor stops with "The game module could not be found", +exit 1, before running any test. The build is incremental — seconds when +nothing changed; a failed build is a FAIL. + +**Pick the commands for this machine** with `uname -s`: `Linux` → Linux, +`Darwin` → macOS, anything else (`MINGW*`, `MSYS*`, `CYGWIN*`) → Windows. The +Windows forms below were run on UE 5.7; the Linux and macOS forms come from +Epic's documentation — `docs/engine-reference/unreal/current-best-practices.md`, +"Command Line", has them with their sources. On Windows use +`UnrealBuildTool.exe`, not `Build.bat`: run from bash, `Build.bat` fails on an +engine path with spaces. +```bash +# Windows +timeout 1800 "/Engine/Binaries/DotNET/UnrealBuildTool/UnrealBuildTool.exe" Editor Win64 Development -Project="$(pwd -W 2>/dev/null || pwd)/.uproject" 2>&1 +# Linux +timeout 1800 "/Engine/Build/BatchFiles/Linux/Build.sh" Editor Linux Development -Project="$(pwd -W 2>/dev/null || pwd)/.uproject" 2>&1 +# macOS (timeout: see the macOS note above) +gtimeout 1800 "/Engine/Build/BatchFiles/Mac/Build.sh" Editor Mac Development -Project="$(pwd -W 2>/dev/null || pwd)/.uproject" 2>&1 +``` +Then the default. Keep `-stdout -FullStdOutLogOutput`; when `commands.test` +lacks them, add them to the command for this run only: without them the editor +prints nothing, and the lines below are only in `Saved/Logs/.log`. +Give the project as an **absolute** path — when `commands.test` passes a +relative one, run it with the absolute path instead: UE 5.7 +does not find a relative `.uproject` and exits 1 (`Project file not +found`). `$(pwd -W 2>/dev/null || pwd)` gives the `C:/…` form in Git Bash and +the plain path elsewhere; `$PWD` alone fails when `MSYS_NO_PATHCONV` is set. +Either way, say in the report what you changed and tell the user to fix +`commands.test` in `project.yaml` — never edit `project.yaml` without asking. +`.` in the filter is the root the tests are named under: the project +name, or the distinct root `/setup-engine` chose when the project's name is +also an engine area — read one test's name string under +`Source/*/Private/Tests/` if unsure. +```bash +# Windows +timeout 1800 "/Engine/Binaries/Win64/UnrealEditor-Cmd.exe" "$(pwd -W 2>/dev/null || pwd)/.uproject" -ExecCmds="Automation RunTests .; Quit" -unattended -nullrhi -stdout -FullStdOutLogOutput 2>&1 +# Linux +timeout 1800 "/Engine/Binaries/Linux/UnrealEditor" "$(pwd -W 2>/dev/null || pwd)/.uproject" -ExecCmds="Automation RunTests .; Quit" -unattended -nullrhi -stdout -FullStdOutLogOutput 2>&1 +``` +**macOS has no sourced test command.** Epic documents only the +`UnrealEditor.app` bundle, not a command-line editor inside it. Run a +`commands.test` the user has set and confirmed; with none, report +`NOT ASSESSED — Unreal test command on macOS not sourced; set commands.test to the editor command you use` +instead of guessing a path. +Read the output, not the exit code: a failing test and a run that matched nothing both exit 255. +- `Result={Fail}` on any line → FAIL. +- `No automation tests matched` → `NOT ASSESSED — no tests found` (tests + outside `Source//` are never built), not FAIL. +- Exit 0 with `Result={Success}` lines → PASS. +- Any other non-zero exit (`Project file not found`, `The game module … could + not be found`) → FAIL: no test ran. The exception: the editor never started (exit 126 or 127, `command not found`) — that is the runner not being + available, below, and `NOT ASSESSED`. + +**Unknown engine / not configured:** +"Engine not configured in `project.yaml` or +`.claude/docs/technical-preferences.md`. Run `/setup-engine` to specify the +engine, then re-run `/smoke-check`." + +**If the test runner is not available in this environment** (no editor +executable resolved in Phase 1 step 3, runner script not found, etc.), report +clearly: + +"Automated tests could not be executed — engine executable not found (checked +`commands.test`, `engine.path` and `PATH`; set `engine.path`, or put the +editor's full path in `commands.test`). Status will be recorded as NOT RUN. +Confirm test results from your local IDE +or CI pipeline. Until you do, the verdict is NOT ASSESSED — not FAIL, and not +a pass either: nothing has been observed about this build yet." + +Do not treat NOT RUN as an automatic FAIL. Record it, and let the developer's +manual confirmation in Phase 4 resolve it. Until that confirmation arrives the +verdict is **NOT ASSESSED** (see the verdict rules in Phase 5), which ranks +above both pass values and below FAIL. An unrun suite is not a healthy build; it +is an unknown one, and the two need different follow-ups. + +Parse runner output and extract: +- Total tests run +- Passing count +- Failing count +- Names of any failing tests (up to 10; if more, note the count) +- Any crash or error output from the runner itself + +**Build check — the WAIVED path only** (`qa.level: minimal`, no game tests; +Phase 1 step 1). With no suite to run, run the project's own boot check: +`commands.smoke` when set, else `commands.build` when set, with the executable +Phase 1 step 3 resolved, under the same timeout rules (`timeout 900`, or +`timeout 1800` for `commands.build`; a timeout is a FAIL). On Godot, run the +import line above first. Read the result as `/setup-engine` documents it: +Godot `smoke` exits 0 even on a parse error, so a `SCRIPT ERROR` line in its +output is a FAIL, and so is `Can't run project: no main scene defined` — the +game cannot launch; Unity `smoke` exits 1 on a compile error; any other +non-zero exit is a FAIL. Record `Build check: PASS — [command] exit 0`, +`FAIL — [reason]`, or `NOT RUN — [commands.smoke and commands.build unset | +executable not found]`. A build check that did not run is named in the report +and leaves the launch in Batch 1 to carry the verdict; it never passes on its +own. + +--- diff --git a/.claude/skills/smoke-check/references/3-coverage.md b/.claude/skills/smoke-check/references/3-coverage.md new file mode 100644 index 00000000..b33a718c --- /dev/null +++ b/.claude/skills/smoke-check/references/3-coverage.md @@ -0,0 +1,40 @@ +# /smoke-check — Phase 3: Check Test Coverage + +> Part of `/smoke-check`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 3: Check Test Coverage + +Draw the story list from, in priority order: +1. The QA plan found in Phase 1 (its Test Summary table lists expected test + file paths per story) +2. The current sprint plan from `production/sprints/` (most recently modified + file) +3. If the `quick` argument was passed, skip this phase entirely and note: + "Coverage scan skipped — run `/smoke-check sprint` for full coverage + analysis." + +For each story in scope: + +1. Extract the system slug from the story's file path + (e.g., `production/epics/combat/story-001.md` → `combat`) +2. Glob `tests/unit/[system]/` and `tests/integration/[system]/` for files + whose name contains the story slug or a closely related term +3. Check the story file itself for a `Test file:` header field or a + "Test Evidence" section + +Assign a coverage status to each story: + +| Status | Meaning | +|--------|---------| +| **COVERED** | A test file was found matching this story's system and scope | +| **MANUAL** | Story type is Visual/Feel or UI; a test evidence document was found | +| **MISSING** | Logic or Integration story with no matching test file | +| **EXPECTED** | Config/Data story — no test file required; spot-check is sufficient | +| **UNKNOWN** | Story file missing or unreadable | + +MISSING entries are advisory gaps. They do not cause a FAIL verdict but must +appear prominently in the report and must be resolved before `/story-done` can +fully close those stories. + +--- diff --git a/.claude/skills/smoke-check/references/4-manual-checks.md b/.claude/skills/smoke-check/references/4-manual-checks.md new file mode 100644 index 00000000..ee5e74e7 --- /dev/null +++ b/.claude/skills/smoke-check/references/4-manual-checks.md @@ -0,0 +1,132 @@ +# /smoke-check — Phase 4: Run Manual Smoke Checks + +> Part of `/smoke-check`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 4: Run Manual Smoke Checks + +**In this file:** + +- Checklist source: name it in the report +- Batch 1 — Core stability +- Batch 2 — Sprint changes and regression +- Batch 3 — Data integrity and performance +- Platform batches: PC, console, mobile + +Draw the smoke test checklist from, in priority order (and name the one you used in the report): +1. The QA plan's "Smoke Test Scope" section (if QA plan was found in Phase 1) +2. `production/qa/smoke-tests.md` (if it exists) +3. `tests/smoke/` directory contents (if it exists) +4. The standard fallback list below (used only when none of the above exist) + +**Name the source you used in the report**, on its own line — *"Checklist source: +`production/qa/smoke-tests.md`"*, or *"Checklist source: standard fallback list — +no QA plan scope, no `production/qa/smoke-tests.md`, no `tests/smoke/`."* The +fallback is a real fallback, so nothing is silently skipped here; what was +missing is that a report drawn from the generic list and one drawn from this +project's own smoke definitions were indistinguishable. `/gate-check` now +validates a smoke report's claims against the repo, and it cannot weigh them +without knowing what the checklist was drawn from. + +Tailor batches 2 and 3 to the actual systems identified from the sprint or QA +plan. Replace bracketed placeholders with real mechanic names from the current +sprint's stories. + +Use `AskUserQuestion` to batch-verify. Keep to at most 3 calls. + +**Batch 1 — Core stability (always run):** one call, two questions — an empty +failure list means nothing unless somebody launched the build. +``` +question: "Did you launch the current build this session?" +multiSelect: false +options: + - "Yes — I launched it and checked the items below" + - "No — I have not launched the current build this session" + +question: "Core stability — select any items that FAILED (leave all unselected if everything passed):" +multiSelect: true +options: + - "Game does not launch or crashes before reaching the main menu" + - "New game / session fails to start" + - "Main menu does not respond to inputs" + - "Crash or hang observed during basic navigation" +``` + +For any selected item, ask the user to briefly describe what failed before generating the report. + +If the build was **not launched**, the Batch 1 checks could not be executed: +record them as `NOT RUN — build not launched this session`, skip Batches 2 and +3 and any platform batch (say so — they need a running build), and ignore the +unselected failure list. The verdict is then NOT ASSESSED unless something else +FAILED. + +**Batch 2 — Sprint changes and regression (always run):** +``` +question: "Sprint changes and regression — select any items that FAILED (leave all unselected if everything passed):" +multiSelect: true +options: + - "[Primary mechanic this sprint] — FAILED" + - "[Second notable change this sprint, if any] — FAILED" + - "Regression in a previous sprint's feature — FAILED" + - "Other unexpected breakage observed — FAILED" +``` + +For any selected item, ask the user to briefly describe what broke before generating the report. + +**Batch 3 — Data integrity and performance (run unless `quick` argument):** +``` +question: "Data integrity and performance — select any items that FAILED or were skipped (leave all unselected if everything passed):" +multiSelect: true +options: + - "Save / load — FAILED (data loss or corruption observed)" + - "Save / load — N/A (save system not yet implemented)" + - "Frame rate drops or hitches observed — FAILED" + - "Performance not checked this session" +``` + +For any FAILED item selected, ask the user to describe what broke before generating the report. + +Record each response verbatim for the Phase 5 report. + +**Platform Batches** *(run only if `--platform` argument was provided)*: + +**PC platform** (`--platform pc` or `--platform all`): +``` +question: "PC Platform — select any items that FAILED (leave all unselected if everything passed):" +multiSelect: true +options: + - "Keyboard controls — FAILED (describe issue after)" + - "Mouse input or cursor visibility — FAILED (describe issue after)" + - "Windowed / fullscreen mode — FAILED (describe issue after)" + - "Resolution change — FAILED (describe issue after)" +``` + +For any selected item, ask the user to briefly describe what failed before generating the report. + +**Console platform** (`--platform console` or `--platform all`): +``` +question: "Console Platform — select any items that FAILED (leave all unselected if everything passed):" +multiSelect: true +options: + - "Gamepad input — FAILED (describe issue after)" + - "UI outside TV safe zone / text clipped — FAILED (describe what is clipped after)" + - "Keyboard/mouse fallback shown to gamepad user — FAILED (describe after)" + - "Cold start (no prior save) — FAILED (describe issue after)" +``` + +For any selected item, ask the user to briefly describe what failed before generating the report. + +**Mobile platform** (`--platform mobile` or `--platform all`): +``` +question: "Mobile Platform — select any items that FAILED (leave all unselected if everything passed):" +multiSelect: true +options: + - "Touch controls — FAILED (describe issue after)" + - "Orientation change (portrait ↔ landscape) — FAILED (describe what breaks after)" + - "Background / foreground transition (home button) — FAILED (describe issue after)" + - "Performance / thermal throttling on target device — FAILED (describe after)" +``` + +For any selected item, ask the user to briefly describe what failed before generating the report. + +--- diff --git a/.claude/skills/smoke-check/references/5-report.md b/.claude/skills/smoke-check/references/5-report.md new file mode 100644 index 00000000..d3e4d6e6 --- /dev/null +++ b/.claude/skills/smoke-check/references/5-report.md @@ -0,0 +1,158 @@ +# /smoke-check — Phase 5: Generate Report + +> Part of `/smoke-check`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 5: Generate Report + +**In this file:** + +- The report template, with the verdict rules +- `NOT ASSESSED` and where it ranks + +Assemble the full smoke check report: + +````markdown +## Smoke Check Report +**Date**: [date] +**Sprint**: [sprint name / number, or "Not identified"] +**Engine**: [engine] +**QA Plan**: [path, or "Not found — run /qa-plan first"] +**Argument**: [sprint | quick | blank] + +--- + +### Automated Tests + +**Status**: [PASS ([N] tests, [N] passing) | PASS WITH WARNINGS ([N] tests +passing; [the runner's warning, e.g. [N] orphan nodes leaked]) | FAIL ([N] +failures, or did not complete: [timeout | compile, parse or build error | no +results file]) | NOT ASSESSED ([reason, e.g. zero tests executed, runner could +not run]) | NOT RUN ([reason]) | WAIVED (qa.level: minimal — no game tests)] + +[Unity: one Status line per test platform — `EditMode:` and `PlayMode:`.] + +[WAIVED only:] **Build check**: [PASS — `[command]` exit 0 | FAIL — [reason] | +NOT RUN — [commands.smoke and commands.build unset | executable not found]] + +[If FAIL, list failing tests:] +- `[test name]` — [brief failure description from runner output] + +[If NOT RUN:] +"Manual confirmation required: did tests pass in your local IDE or CI? This +will determine whether the automated test row contributes to a FAIL verdict." + +--- + +### Test Coverage + +| Story | Type | Test File | Coverage Status | +|-------|------|-----------|----------------| +| [title] | Logic | `tests/unit/[system]/[slug]_test.[ext]` | COVERED | +| [title] | Visual/Feel | `production/qa/evidence/[slug]-screenshots.md` | MANUAL | +| [title] | Logic | — | MISSING ⚠ | +| [title] | Config/Data | — | EXPECTED | + +**Summary**: [N] covered, [N] manual, [N] missing, [N] expected. + +--- + +### Manual Smoke Checks + +- [x] Build launched this session — yes [or: `NOT RUN — build not launched this session`; the batches below were not asked] +- [x] Game launches without crash — PASS +- [x] New game starts — PASS +- [x] [Core mechanic] — PASS +- [ ] [Other check] — FAIL: [user's description] +- [x] Save / load — PASS +- [-] Performance — not checked this session + +--- + +### Missing Test Evidence + +Stories that must have test evidence before they can be marked COMPLETE via +`/story-done`: + +- **[story title]** (`[path]`) — Logic story has no test file. + Expected location: `tests/unit/[system]/[story-slug]_test.[ext]` + +[If none:] "All Logic and Integration stories have test coverage." + +--- + +### Platform-Specific Results *(only if `--platform` was provided)* + +| Platform | Checks Run | Passed | Failed | Platform Verdict | +|----------|-----------|--------|--------|-----------------| +| PC | [N] | [N] | [N] | PASS / FAIL | +| Console | [N] | [N] | [N] | PASS / FAIL | +| Mobile | [N] | [N] | [N] | PASS / FAIL | + +**Platform notes**: [any platform-specific observations not captured in pass/fail] + +Any platform with one or more FAIL checks contributes to the overall FAIL verdict. + +--- + +### Verdict: [PASS | PASS WITH WARNINGS | NOT ASSESSED | FAIL] + +[Verdict rules — first matching rule wins:] + +**FAIL** if ANY of: +- Automated test suite ran and reported one or more test failures +- The automated suite did not complete: a timeout, a compile, parse or build + error, or no results file after the run (Phase 2 names each engine's form) +- The build check (WAIVED path) failed: a non-zero exit, a timeout, or a Godot + `SCRIPT ERROR` or no-main-scene line +- Any Batch 1 (core stability) check returned FAIL +- Any Batch 2 (primary sprint mechanic or regression check) returned FAIL + +**NOT ASSESSED** if ANY of: +- The automated suite is **unconfirmed NOT RUN** — nobody has reported a result +- The runner could not run (gdUnit4 103 or 104, gdUnit4 or the Unity Test + Framework not installed), or it ran and executed zero tests + (`No test cases found`, `testcasecount="0"`, `No automation tests matched`) +- Unity Play Mode tests exist and are `PlayMode: NOT RUN`, unconfirmed — the + Edit Mode result does not cover them +- A Batch 1 or Batch 2 check could not be executed (no build, engine not + configured, platform unavailable) as opposed to executing and failing — + including a Batch 1 answer that the build was not launched this session +- **Any story's coverage row is `UNKNOWN`** (Phase 3: story file missing or + unreadable). A story nobody could read is not a story with no gaps — without + this line, a run where *every* row is UNKNOWN and the suite passes matches + **PASS**, because PASS only requires "no MISSING entries" +- **Batch 3 was offered and skipped** ("Performance not checked this session"). + It is not a FAIL, not an execution failure, and not "PASS or N/A", so without + this line it matches no rule at all and renders as `[-]` beside a PASS + +**PASS WITH WARNINGS** if ALL of: +- Automated tests PASS or PASS WITH WARNINGS, WAIVED at `qa.level: minimal`, or + NOT RUN **and the developer has confirmed the result from their local IDE or CI** +- All Batch 1 and Batch 2 smoke checks PASS +- At least one warning: a Logic/Integration story with MISSING test evidence, + a runner warning on a passing suite (gdUnit4 101 — orphan nodes leaked), or + a NOT RUN suite the developer confirmed + +**PASS** if ALL of: +- Automated tests PASS, or WAIVED (`qa.level: minimal` and no game tests exist — + the build check, when `commands.smoke` or `commands.build` is set, and the + launch and critical-path batches below then carry the verdict) +- All smoke checks in all batches PASS or N/A +- No MISSING test evidence entries +```` + +**`NOT ASSESSED` — the build nobody could check.** Rank: it **outranks PASS and +PASS WITH WARNINGS** and **ranks below FAIL**. A suite that never ran has not +shown the build is healthy; a suite that ran and failed is the more actionable +finding and must not be demoted behind one that did not run. + +This is a change in where unconfirmed `NOT RUN` lands, and it is deliberate. The +rule below — **never treat NOT RUN as an automatic FAIL** — is unchanged and +still correct: NOT ASSESSED is not a FAIL, and it ranks below one. What changes +is that an unrun suite no longer resolves to a *pass* verdict while waiting for a +confirmation that may never come. Confirmed NOT RUN (the developer reports the +result from their own IDE or CI) still lands at PASS WITH WARNINGS, because +somebody did look. + +--- diff --git a/.claude/skills/smoke-check/references/6-write-gate.md b/.claude/skills/smoke-check/references/6-write-gate.md new file mode 100644 index 00000000..1fde829d --- /dev/null +++ b/.claude/skills/smoke-check/references/6-write-gate.md @@ -0,0 +1,110 @@ +# /smoke-check — Phase 6: Write and Gate + +> Part of `/smoke-check`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 6: Write and Gate + +**In this file:** + +- `qa.level` first +- Resolve the gate enforcement level +- Per verdict: FAIL (blocking or advisory), NOT ASSESSED, PASS WITH WARNINGS, PASS + +Present the full report in conversation, then ask: + +"May I write this smoke check report to `production/qa/smoke-[date].md`?" + +Write only after approval. + +**First apply `qa.level` (resolved earlier).** At `qa.level: minimal`, a FAIL is +**advisory** regardless of `testing.strict.config` — skip the resolution below and +deliver the advisory-FAIL outcome (smoke-check is optional at minimal and never +blocks hand-off). Otherwise: + +**Resolve the gate enforcement level.** A FAIL verdict either *blocks* QA +hand-off or is *flagged while hand-off proceeds*, governed by the +`testing.strict` block **resolved in the resolved-config block at the top of this skill** (which merges +`project.local.yaml` over `project.yaml` — read that block, not the file, or a +developer's local override is silently ignored): + +1. Take `testing.strict.config` from that resolved block. If its value is `true` + (case-insensitive) → blocking; if `false` → advisory; `unset` → fall through. +2. Else read `testing.strict` as a plain boolean (legacy single-value form) — if + its value is `true` or `false`, it applies. +3. Else default to **blocking** — an unset `testing.strict.config` keeps + smoke-check's FAIL gate blocking (behavior unchanged from before this setting + existed). Smoke check is a build-health gate, so its unset default is strict + even though the `config` test type defaults to advisory elsewhere. The + reciprocal carve-out is recorded in `.claude/skills/story-done/SKILL.md` and + `.claude/docs/coding-standards.md`, which own the per-story evidence table. + +Only `true` and `false` (case-insensitive) are recognized at steps 1–2. A key +that is present but holds any other value — `maybe`, `1`, `yes`, etc. — is +treated as unset: continue to the next step, and surface the unrecognized value +to the user. + +After writing, deliver the gate verdict: + +**If verdict is FAIL and the gate is blocking:** + +"The smoke check failed. Do not hand off to QA until these failures are +resolved: + +[List each failing automated test or smoke check with a one-line description] + +Fix the failures and run `/smoke-check` again to re-gate before QA hand-off." + +**If verdict is FAIL and the gate is advisory** (`testing.strict.config: false`): + +"The smoke check failed, but `testing.strict.config` is set to advisory — QA +hand-off is not blocked. Resolve these before release: + +[List each failing automated test or smoke check with a one-line description] + +QA hand-off: share `production/qa/qa-plan-[sprint].md` with the qa-tester +agent to begin manual verification. Re-run `/smoke-check` once the failures +are fixed." + +**If verdict is NOT ASSESSED:** + +"The smoke check could not establish build health — it did not fail, it did not +run. Do not hand off to QA on this result: + +[Name each check that could not execute, and why: suite unconfirmed NOT RUN, +`PlayMode: NOT RUN`, zero tests executed, runner not installed, engine +executable not found, no build, build not launched this session, platform +unavailable] + +[For each, the one thing that would make it runnable — e.g. 'confirm the suite +result from your IDE or CI', 'run `/setup-engine`', 'set `engine.path`', +'produce a build', 'launch the build and play the checks'.] + +Re-run `/smoke-check` once any of those is resolved." + +This outcome is **not governed by `testing.strict.config`**. That setting decides +whether a *failure* blocks hand-off; it has nothing to say about a check that +never produced a result, and reading an unrun check as advisory-therefore-fine is +the exact substitution this verdict exists to prevent. Say what could not be +checked and let the user decide — do not resolve it to either pass or FAIL on +their behalf. + +**If verdict is PASS WITH WARNINGS:** + +"Smoke check passed with warnings. The build is ready for manual QA. + +Advisory items to resolve before running `/story-done` on affected stories: +[list MISSING test evidence entries, and any runner warning — e.g. the orphan +count] + +QA hand-off: share `production/qa/qa-plan-[sprint].md` with the qa-tester +agent to begin manual verification." + +**If verdict is PASS:** + +"Smoke check passed cleanly. The build is ready for manual QA. + +QA hand-off: share `production/qa/qa-plan-[sprint].md` with the qa-tester +agent to begin manual verification." + +--- diff --git a/.claude/skills/soak-test/SKILL.md b/.claude/skills/soak-test/SKILL.md index b95dd9b9..0b443ae2 100644 --- a/.claude/skills/soak-test/SKILL.md +++ b/.claude/skills/soak-test/SKILL.md @@ -7,7 +7,7 @@ allowed-tools: Read, Glob, Grep, Write, Bash(bash "*/.claude/skills/soak-test/.. model: sonnet --- -!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys automation` +!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys automation,workflow` **Automation mode**: Resolve `modes.automation` (`project.local.yaml` → `project.yaml` → default `collaborative`). Every `AskUserQuestion` call and @@ -322,7 +322,7 @@ After writing: 2. Record each checkpoint as you play 3. Complete the Post-Session Analysis section when done 4. File bugs from 'Issues Found' to `production/qa/bugs/` -5. Run `/bug-triage sprint` after the session to integrate any S1/S2 issues +5. Run `/bug-triage sprint` after the session to integrate any S1/S2 issues (at `workflow: minimal`, which has no sprints: `/bug-triage full`) If the verdict is FAIL, run `/smoke-check` again after fixing the issues." diff --git a/.claude/skills/sprint-plan/SKILL.md b/.claude/skills/sprint-plan/SKILL.md index fe7b35e0..fe79e48c 100644 --- a/.claude/skills/sprint-plan/SKILL.md +++ b/.claude/skills/sprint-plan/SKILL.md @@ -12,6 +12,8 @@ model: sonnet Resolved above — use as-is; `--review` overrides `review_mode`. No block → defaults in `.claude/docs/config-resolution.md`. +# Sprint Plan + ## Existing Sprints diff --git a/.claude/skills/start/SKILL.md b/.claude/skills/start/SKILL.md index d98880f8..d1d76638 100644 --- a/.claude/skills/start/SKILL.md +++ b/.claude/skills/start/SKILL.md @@ -174,7 +174,7 @@ In `project.yaml`, ensure a `project:` block exists with `stage: [value]`. schema_version: 1 framework: - version: 1.1.2 + version: 1.1.3 last_upgraded: project: @@ -249,8 +249,11 @@ Value mapping (ignore any ` (Recommended)` suffix on the first option): Write `modes.rigor` to `project.yaml` immediately after the user selects — no separate "May I write?" needed, as the write is a direct consequence of the -selection. Use the Edit tool to add it under the `modes:` block. There is **no -legacy mirror file** for this setting, so this is a single write, not a dual-write. +selection. Use the Edit tool. The Phase 3c template has no `modes:` block: if +`project.yaml` has none, add one with `rigor:` under it; if it has one, add +`rigor:` under it. Never add a second `modes:` line — YAML allows one block per +key. There is **no legacy mirror file** for this setting, so this is a single +write, not a dual-write. If the Phase 3c `project.yaml` write was declined, do not write this one either — carry the answer forward and say it was not saved. @@ -288,7 +291,9 @@ Value mapping: `Collaborative` → `collaborative`, `Guided (recommended)` → Write `modes.automation` to `project.yaml` immediately after the user selects — no separate "May I write?" needed, as the write is a direct consequence of the -selection. Use the Edit tool to add it under the `modes:` block. There is **no +selection. Use the Edit tool to add `automation:` under the `modes:` block +(Phase 3d creates it); if `project.yaml` has none, add one. +Never add a second `modes:` line — YAML allows one block per key. There is **no legacy mirror file** for this setting. If the Phase 3c `project.yaml` write was declined, do not write this one either — say it was not saved. diff --git a/.claude/skills/story-done/SKILL.md b/.claude/skills/story-done/SKILL.md index 0f1cbe54..e03cdb05 100644 --- a/.claude/skills/story-done/SKILL.md +++ b/.claude/skills/story-done/SKILL.md @@ -13,7 +13,6 @@ model: sonnet Resolved above — use as-is; `--review` overrides `review_mode`. No block → defaults in `.claude/docs/config-resolution.md`. - # Story Done This skill closes the loop between design and implementation. Run it at the end @@ -28,740 +27,35 @@ forgotten, and the story file reflects actual completion status. ## Phase 1: Find the Story - -See `.claude/docs/director-gates.md` for the full check pattern. Individual gate definitions live in `.claude/docs/director-gates/[gate-id].md` — the spawned agent reads its own gate file; do not read it in the parent session. - - -Every `AskUserQuestion` call follows `.claude/docs/automation-modes.md` -(collaborative asks always · guided major-only · autonomous logs and proceeds; -`automation_always_ask` categories always prompt). - -**Workflow tier**: resolved per the story's system (per -`.claude/docs/workflow-modes.md`) — **the GDD filename stem** of the story's -`GDD:` path (`design/gdd/.md` → ``), with the `[system]` segment of -its `TR-[system]-NNN` ID accepted only as a fallback alias: use the -`system_overrides` row for that system if the block lists one, else the -project value. It governs which Phase 4 deviation checks run — see Phase 4. - -**Workflow companion — `modes.story_granularity`** (resolved above — supplied by -`modes.rigor` unless set explicitly): cadence expectation only — story-done fires **every 3–5 days** at -`coarse`, **every 1–2 days** at `balanced`, **multiple times/day** at `fine`. It -does not change any completion check. - -**`qa.level`**: controls whether test *evidence is required*, where -`testing.strict` controls whether a failure blocks and `workflow` controls which -docs exist. `modes.rigor` sets `qa.level` and `workflow` together; set either -explicitly to vary it alone. `testing.strict` is not fronted by `rigor` at all. -At `minimal`, no *test* evidence is required → skip the Logic, Integration and -Config/Data evidence checks (Phase 3), the >50%-untested traceability escalation, -and the Phase 4b QA gate; the acceptance-criteria verification still runs, and so -do the Visual/Feel and UI screenshot gate and the `Run result:` check for other -story types — the look is never waived. At -`standard`, the story's own type requires evidence; at `full`, every type does. -`testing.strict` then decides whether present-but-failing evidence blocks. -(`rigor: minimal` sets both; `qa.level: minimal` on its own leaves the workflow -tier where it was.) - -**If a file path is provided** (e.g., `/story-done production/epics/core/story-damage-calculator.md`): -read that file directly. - -**If no argument is provided:** - -1. Check `production/session-state/active.md` for the currently active story. -2. If not found there, read the most recent file in `production/sprints/` and - look for stories marked IN PROGRESS. -3. If multiple in-progress stories are found, use `AskUserQuestion`: - - "Which story are we completing?" - - Options: list the in-progress story file names. -4. If no story can be found, ask the user to provide the path. - ---- +**Read `references/1-find-story.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 2: Read the Story -Read the full story file. Extract and hold in context: - -- **Story name and ID** -- **GDD Requirement TR-ID(s)** referenced (e.g., `TR-combat-001`) -- **Manifest Version** embedded in the story header (e.g., `2026-03-10`) -- **ADR reference(s)** referenced -- **Acceptance Criteria** — the complete list (every checkbox item) -- **Implementation files** — files listed under "files to create/modify" -- **Story Type** — the `Type:` field from the story header (Logic / Integration / Visual/Feel / UI / Config/Data) -- **Engine notes** — any engine-specific constraints noted -- **Definition of Done** — if present, the story-level DoD -- **Estimated vs actual scope** — if an estimate was noted - -Also read: -- `docs/architecture/tr-registry.yaml` — grep the story's TR-IDs - (`Grep pattern="id: " path="docs/architecture/tr-registry.yaml" output_mode="content" -A 6`), - not a full read of the registry. Read the *current* `requirement` text from each - matched entry. This is the source of truth for what the GDD required — do not use any - requirement text that may be quoted inline in the story (it may be stale). -- The referenced GDD section — just the acceptance criteria and key rules, not - the full document. Use this to cross-check the registry text is still accurate. -- The referenced ADR(s) — **just the `## Decision` and `## Consequences` - sections, never an unbounded full read.** Map headings first - (`Grep pattern="^## " path="docs/architecture/[adr-file].md" output_mode="content" -n`), - then bounded-`Read` only those two spans. This is the exact same content - Phase 4 item 3's ADR constraints check needs — hold it here, do not - re-read it there. -- `docs/architecture/control-manifest.md` header — extract the current - `Manifest Version:` date (used in Phase 4 staleness check) - ---- +**Read `references/2-read-story.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 3: Verify Acceptance Criteria -For each acceptance criterion in the story, attempt verification using one of -three methods: - -### Automatic verification (run without asking) - -- **File existence check**: `Glob` for files the story said would be created. -- **Test file check**: if a test file path is mentioned, confirm the file exists - with `Glob`. Do not run it — this skill establishes existence only (see the - note under Test Evidence Requirement), so report "test file present", never - "test passes". -- **No hardcoded values check**: `Grep` for numeric literals in gameplay code - paths that should be in config files. -- **No hardcoded strings check**: `Grep` for player-facing strings in the **code root** (resolve per `.claude/docs/code-root-resolution.md`). **If the code root is unresolved, report `NOT ASSESSED — code root unresolved` rather than zero hits.** - that should be in localization files. -- **Dependency check**: if a criterion says "depends on X", check that X exists. - -### Manual verification with confirmation (use `AskUserQuestion`) - -- Criteria about subjective qualities ("feels responsive", "animations play correctly") -- Criteria about gameplay behaviour ("player takes damage when...", "enemy responds to...") - — these are asked, never marked verified from reading the code: the code says - what should happen, not what the build does -- Performance criteria ("completes within Xms") — ask if profiled or accept as assumed - -Batch up to 4 manual verification questions into a single `AskUserQuestion` call: - -``` -question: "Does [criterion]?" -options: "Yes — passes", "No — fails", "Not tested yet" -``` - -Map each answer: `Yes — passes` → confirmed; `No — fails` → FAILS; -`Not tested yet` → not evaluated — UNTESTED in the traceability table below, and -the verdict is NOT ASSESSED (Phase 6) until someone checks it. If the criterion -genuinely needs a full-build playtest, mark it `DEFERRED — requires playtest -session` instead. - -### Unverifiable (flag without blocking) - -- Criteria that require a full game build to test (end-to-end gameplay scenarios) -- Mark as: `DEFERRED — requires playtest session` - -### Test-Criterion Traceability - -After completing the pass/fail/deferred check above, map each acceptance -criterion to the test that covers it: - -For each acceptance criterion in the story: - -1. Ask: is there a test — unit, integration, or confirmed manual playtest — that - directly verifies this criterion? - - **Unit test**: check `tests/unit/` for a test file or function name that - matches the criterion's subject (use `Glob` and `Grep`) - - **Integration test**: check `tests/integration/` similarly - - **Manual confirmation**: if the criterion was verified via `AskUserQuestion` - above with a "Yes — passes" answer, count that as a manual test - - **Retained screenshot**: if the criterion names something on screen and a - retained image under `production/qa/evidence/[story-slug]/` shows it (the - `Run result: OBSERVED` from `/dev-story` Phase 6 step 4), count that as - covered — put the image path in the Test column. A visual criterion - verified by looking is not UNTESTED; without this row every UI story - reads as >50% untested and false-escalates. "Shows it" means you opened - the image with `Read` and saw it; a checkpoint's `Run result: OBSERVED — - ` is `/dev-story`'s description, to quote as such, not yours. - **Never describe an image you have not opened.** - -2. Produce a traceability table: - -``` -| Criterion | Test | Status | -|-----------|------|--------| -| AC-1: [criterion text] | tests/unit/test_foo.gd::test_bar | COVERED | -| AC-2: [criterion text] | Manual playtest confirmation | COVERED | -| AC-3: [criterion text] | production/qa/evidence/[slug]/01-shop-open.png | COVERED | -| AC-4: [criterion text] | — | UNTESTED | -``` - -3. Apply these escalation rules (skip entirely at `qa.level: minimal` — no - evidence is required, so untested criteria never escalate): - - - If **>50% of criteria are UNTESTED**: escalate to **BLOCKING** — test - coverage is insufficient to confirm the story is actually done. The verdict - in Phase 6 cannot be COMPLETE until coverage improves. - - If **some (≤50%) criteria are UNTESTED**: remain ADVISORY — does not block - completion, but must appear in Completion Notes. - - If **all criteria are COVERED**: no action needed beyond including the - table in the report. - -4. For any ADVISORY untested criteria, add to the Completion Notes in Phase 7: - `"Untested criteria: [AC-N list]. Recommend adding tests in a follow-up story."` - -### Test Evidence Requirement - -**First apply `qa.level` (resolved in Phase 1).** At `minimal`, no *test* -evidence is required — skip the Logic, Integration and Config/Data checks below. -But still run the Visual/Feel and UI check and the `Run result:` check: the look -is not waived at minimal, only the tests are. At `standard`, require evidence -for the story's own type. At `full`, require evidence for every story type. The -`testing.strict` resolution below applies to every check that runs. - -Based on the Story Type extracted in Phase 2, check for required evidence. - -**Resolve the gate level for this story's type.** A gate level is either -BLOCKING (a gap prevents the COMPLETE verdict in Phase 6) or ADVISORY (a gap is -noted in the Completion Notes but does not block). Resolve it from the -`testing.strict` block **already resolved in the resolved-config block at the top of this skill** — not by reading -`project.yaml` yourself: - -1. Map the Story Type to a `testing.strict` key — Logic→`logic`, - Integration→`integration`, Visual/Feel→`visual`, UI→`ui`, Config/Data→`config`. - Take `testing.strict.` from that resolved block. If its value is `true` - (case-insensitive) → BLOCKING; if `false` → ADVISORY; `unset` → fall through. -2. Else read `testing.strict` as a plain boolean (legacy single-value form). If - its value is `true` → BLOCKING or `false` → ADVISORY, it applies to every type. -3. Else use the default in the table below. - -> **Use that resolved block, never `project.yaml` directly.** `testing.strict.*` is -> on the `/settings --local` whitelist, so a developer can set -> `testing.strict.logic=false` in `project.local.yaml` for fast WIP commits — -> `effects-map.md` specifies exactly this ("stricter dev's local `/story-done` -> blocks earlier"). Reading `project.yaml` alone silently ignores that file: the -> setting is accepted, displayed by `/settings`, and has no effect. The -> `resolve_config` block at the top of this skill already merges local over base. - -Only `true` and `false` (case-insensitive) are recognized at steps 1–2. A key -that is present but holds any other value — `maybe`, `1`, `yes`, etc. — is -treated as unset: continue to the next step, and surface the unrecognized value -to the user. - -| Story Type | Required Evidence | Default Gate Level | -|---|---|---| -| **Logic** | Automated unit test in `tests/unit/[system]/` — must exist and pass (this skill verifies **existence**; see the note below Phase 3) | BLOCKING | -| **Integration** | Integration test in `tests/integration/[system]/` OR playtest doc | BLOCKING | -| **Visual/Feel** | Retained screenshot + sign-off in `production/qa/evidence/` | BLOCKING | -| **UI** | Retained screenshot of each screen touched, in `production/qa/evidence/` | BLOCKING | -| **Config/Data** | Smoke check pass report in `production/qa/smoke-*.md` | ADVISORY | - -The **Default Gate Level** column applies when `testing.strict` is unset (the -common case). When `testing.strict` is configured, the resolved value from -steps 1–2 overrides it. Visual/Feel and UI default to BLOCKING because for a -game the rendered result is the product; set `testing.strict.visual` or -`testing.strict.ui` to `false` for an advisory gate. - -> **Exception — `/smoke-check`.** The ADVISORY default for **Config/Data** above -> governs *per-story evidence* gates, which is what this skill checks. -> `/smoke-check` is a build-health gate, not a per-story evidence gate, so its own -> unset default for `testing.strict.config` is **BLOCKING** — see -> `.claude/skills/smoke-check/SKILL.md` § "Resolve the gate enforcement level". -> The divergence is intentional; do not "fix" either side to match the other. - -> **This phase checks that evidence EXISTS. It does not run anything.** The -> `Default Gate Level` table above, and `.claude/docs/coding-standards.md`, both -> say a Logic story's test "must exist **and pass**". The checks below establish -> only the first half — every one of them is a `Glob` or a `Grep`. A unit test -> that exists and fails, or that contains no assertions, satisfies them. -> -> Say which half you verified when you report. "Test file present at ``" -> is the honest claim; "tests pass" is not one this phase can make. Pass/fail is -> established by `/gate-check` (runs the suite at a phase gate) and -> `/smoke-check` (runs it before QA hand-off), both of which do execute. -> -> Unlike `/regression-suite` and `/launch-checklist`, which stop at existence -> because their `allowed-tools` has no `Bash`, this skill HAS `Bash` — the limit -> here is the instruction, not the grant. Running the story's own test before -> closing it is a live option; it is not enabled because it needs a configured -> runner and a decision about what a missing runner should mean. - -**For Logic stories**: first read the story's **Test Evidence** section to extract the -exact required file path. Use `Glob` to check that exact path. If the exact path is not -found, also search `tests/unit/[system]/` broadly (the file may have been placed at a -slightly different location). If no test file is found at either location: -- Flag at the resolved gate level: "Logic story has no unit test file. Story - requires it at `[exact-path-from-Test-Evidence-section]`. Create and run the - test before marking this story Complete." - -**For Integration stories**: read the story's **Test Evidence** section for the exact -required path. Use `Glob` to check that exact path first, then search -`tests/integration/[system]/` broadly, then check `production/session-logs/` for a -playtest record referencing this story. -If none found: flag at the resolved gate level (same rule as Logic). - -**For Visual/Feel and UI stories**: glob `production/qa/evidence/` for a -retained screenshot for this story (`*.png`, `*.jpg`, `*.gif`) and for an -evidence doc referencing it. What closes the story follows the evidence table -in `.claude/docs/coding-standards.md`, the same at every `qa.level`: -- A **UI** story is satisfied by the retained screenshot of each screen it - touched. No evidence doc or sign-off is required; note one if it exists. -- A **Visual/Feel** story also needs the sign-off: the evidence doc - (`production/qa/evidence/[story-slug]-evidence.md`, from the test-evidence - template) with every sign-off row `[x] Approved`. - -Flag at the resolved gate level: -- No screenshot: "No visual evidence found. Capture a screenshot of each screen or effect this story touched and save it under `production/qa/evidence/` before final closure." For Visual/Feel add: "then record sign-off in `production/qa/evidence/[story-slug]-evidence.md` using the test-evidence template." -- An evidence doc but no screenshot retained beside it: "Evidence doc found at `[path]` but no screenshot is retained. A described check is an assertion, not evidence — capture the screen and save the image under `production/qa/evidence/` before final closure." -- Visual/Feel with a screenshot but no evidence doc: "Screenshot found but no sign-off is recorded. Create `production/qa/evidence/[story-slug]-evidence.md` using the test-evidence template and obtain sign-off before final closure." -- Visual/Feel sign-off rows still unchecked — grep the doc for `| .* | .* | .* | \[ \] Approved`: "Evidence file found at `[path]` but [N] sign-off(s) are still pending (shown as `[ ] Approved` in the sign-off table). Obtain required sign-offs before final closure. Note: for solo developers, all roles may be signed off by the same person." - -Otherwise note "Retained screenshot found[, sign-offs complete] — gate satisfied." - -The retained image **is** the `Run result: OBSERVED` from `/dev-story` Phase 6 -step 4 (`.claude/docs/run-and-observe.md`); its absence means the run was -`NOT VERIFIED` or never happened, and the flag above is the consequence. The -run is not waived at `qa.level: minimal`. - -**For every other story type**, read the `Run result:` line from the -`/dev-story` checkpoint in `production/session-state/active.md` — only when its -**Current task** names this story; a later `/dev-story` overwrites it — or from -the story's `## Completion Notes`. `OBSERVED` with a retained path: note -it. `N/A — `: accept only if the reason names why nothing is -observable — "it's a Logic story" is not a reason. `NOT VERIFIED — ` -on a story whose acceptance criteria name anything on screen: flag at the -resolved gate level for the story's type. No `Run result:` line at all: flag -as ADVISORY — "the implementation summary carries no run result; confirm the -build was launched and looked at before closure." The exception: when the -acceptance criteria name something on screen and no retained image for this -story is under `production/qa/evidence/`, nothing observed the story — a user's -`Yes — passes` to such a criterion is an assertion, not the retained observation -`.claude/docs/run-and-observe.md` requires — so flag it at the resolved gate -level for the story's type, as for `NOT VERIFIED`. - -**For Config/Data stories**: check for any `production/qa/smoke-*.md` file. -If none: flag at the resolved gate level — "No smoke check report found. Run `/smoke-check`." - -**If no Story Type is set**: flag as **ADVISORY** — -"Story Type not declared. Add `Type: [Logic|Integration|Visual/Feel|UI|Config/Data]` -to the story header to enable test evidence gate enforcement in future stories." - -Any BLOCKING test evidence gap prevents the COMPLETE verdict in Phase 6. - ---- +**Read `references/3-verify-criteria.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 4: Check for Deviations -Compare the implementation against the design documents. - -> **Workflow tier adjustment** (resolved in Phase 1, per the story's system). -> Checks 1 (GDD rules) and 3 (ADR constraints) below are the `full` baseline: -> - **`full`** — run both: full GDD traceability against the current TR text + -> the ADR constraints check. -> - **`standard`** — run the GDD rules check against the **5 required sections**; -> run the ADR constraints check only where a **critical ADR** governs the story. -> - **`minimal`** — **acceptance-criteria check only**: skip checks 1 and 3 (no -> GDD/ADR traceability expected). Checks 2 (manifest), 4 (hardcoded values), and -> 5 (scope) still run as written. -> -> This adjustment governs only the Phase 4 *deviation* checks. The test-evidence -> gates (Phase 3 traceability, Phase 4b QA coverage) are governed by `qa.level` -> and `testing.strict`, not `workflow` — they run independently of the tier here. - -Run these checks automatically: - -1. **GDD rules check**: Using the current requirement text from `tr-registry.yaml` - (looked up by the story's TR-ID), check that the implementation reflects what - the GDD actually requires now — not what it required when the story was written. - `Grep` the implemented files for key function names, data structures, or class - names mentioned in the current GDD section. - -2. **Manifest version staleness check**: Compare the `Manifest Version:` date - embedded in the story header against the `Manifest Version:` date in the - current `docs/architecture/control-manifest.md` header. - - If they match → pass silently. - - If the story's version is older → flag as ADVISORY: - `ADVISORY: Story was written against manifest v[story-date]; current manifest - is v[current-date]. New rules may apply. Run /story-readiness to check.` - - If control-manifest.md does not exist → skip this check. - -3. **ADR constraints check**: Use the ADR's `## Decision` section already - loaded in Phase 2 — do not read the ADR file again. Check for forbidden - patterns from `docs/architecture/control-manifest.md` (if it exists). - `Grep` for patterns explicitly forbidden in the ADR. - -4. **Hardcoded values check**: `Grep` the implemented files for numeric literals - in gameplay logic that should be in data files. - -5. **Scope check**: Did the implementation touch files outside the story's stated - scope? (files not listed in "files to create/modify") - -For each deviation found, categorize: - -- **BLOCKING** — implementation contradicts the GDD or ADR (must fix before - marking complete) -- **ADVISORY** — implementation drifts slightly from spec but is functionally - equivalent (document, user decides) -- **OUT OF SCOPE** — additional files were touched beyond the story's stated - boundary (flag for awareness — may be valid or scope creep) - ---- - -## Phase 4b: QA Coverage Gate - -**Skip this phase entirely at `qa.level: minimal`** (resolved in Phase 1) — no -test evidence is required, so there is no coverage to review. Note: "QL-TEST-COVERAGE -skipped — qa.level minimal." Proceed to Phase 5. - -**Review mode check** — apply before spawning QL-TEST-COVERAGE: -- `solo` → skip. Note: "QL-TEST-COVERAGE skipped — Solo mode." Proceed to Phase 5. -- `lean` → skip (not a PHASE-GATE). Note: "QL-TEST-COVERAGE skipped — Lean mode." Proceed to Phase 5. -- `full` → spawn as normal. - -After completing the deviation checks in Phase 4, spawn `qa-lead` via `Agent` using gate **QL-TEST-COVERAGE** (`.claude/docs/director-gates/ql-test-coverage.md`). - -Pass: -- The story file path and story type -- Test file paths found during Phase 3 (exact paths, or "none found") -- The story's `## QA Test Cases` section (the pre-written test specs from story creation) -- The story's `## Acceptance Criteria` list -- The GDD acceptance criteria and Edge Cases for the story's system, from the GDD - section read in Phase 2 — or "no GDD for this system" when there is none (at - `workflow: minimal` the story's own criteria are the spec); an absent GDD is - information for the gate, not a missing input - -The qa-lead reviews whether the tests actually cover what was specified — not just whether files exist. - -Apply the verdict: -- **ADEQUATE** → proceed to Phase 5 -- **GAPS** → flag as **ADVISORY**: "QA lead identified coverage gaps: [list]. Story can complete but gaps should be addressed in a follow-up story." -- **INADEQUATE** → flag as **BLOCKING**: "QA lead: critical logic is untested. Verdict cannot be COMPLETE until coverage improves. Specific gaps: [list]." -- **NOT ASSESSED [missing input]** → no judgement was made; never read it as ADEQUATE. Name the missing input — supply it and re-run the gate, or carry it to Phase 6, where it keeps the verdict at best NOT ASSESSED. - -Skip this phase for Config/Data stories (no code tests required). - ---- +**Read `references/4-deviations.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 5: Lead Programmer Code Review Gate -**Review mode check** — apply before spawning LP-CODE-REVIEW: -- `solo` → skip. Note: "LP-CODE-REVIEW skipped — Solo mode." Proceed to Phase 6 (completion report). -- `lean` → use `AskUserQuestion` before proceeding: - - Prompt: "Code review is skipped in lean mode. Did you run `/code-review` on the implemented files?" - - Options: - - `Yes — /code-review passed or was approved with suggestions` - - `No — skipping code review for this story` - - `No — I'll run /code-review before the sprint close-out` - - Record the answer in the completion notes (Phase 7). All three options proceed to Phase 6. -- `full` → spawn as normal. - -Spawn `lead-programmer` via `Agent` using gate **LP-CODE-REVIEW** (`.claude/docs/director-gates/lp-code-review.md`). - -Pass: implementation file paths, story file path, relevant GDD section, governing ADR. - -Present the verdict to the user. If CONCERNS, surface them via `AskUserQuestion`: -- Options: `Revise flagged issues` / `Accept and proceed` / `Discuss further` -If REJECT, do not proceed to Phase 6 verdict until the issues are resolved. -If NOT ASSESSED, name the input the gate said was missing and never treat it as APPROVE: supply it and re-run the gate, or carry it to Phase 6, where it keeps the verdict at best NOT ASSESSED. - -If the story has no implementation files yet (verdict is being run before coding is done), skip this phase and note: "LP-CODE-REVIEW skipped — no implementation files found. Run after implementation is complete." - ---- +**Read `references/5-code-review-gate.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 6: Present the Completion Report -Before updating any files, present the full report: - -```markdown -## Story Done: [Story Name] -**Story**: [file path] -**Date**: [today] - -### Acceptance Criteria: [X/Y passing] -- [x] [Criterion 1] — auto-verified (test file present) -- [x] [Criterion 2] — confirmed -- [ ] [Criterion 3] — FAILS: [reason] -- [?] [Criterion 4] — DEFERRED: requires playtest - -### Test-Criterion Traceability -| Criterion | Test | Status | -|-----------|------|--------| -| AC-1: [text] | [test file::test name] | COVERED | -| AC-2: [text] | Manual confirmation | COVERED | -| AC-3: [text] | — | UNTESTED | - -### Test Evidence -**Story Type**: [Logic | Integration | Visual/Feel | UI | Config/Data | Not declared] -**Required evidence**: [unit test file | integration test or playtest | screenshot + sign-off | screenshot of each screen touched | smoke check pass] -**Evidence found**: [YES — `[path]` | NO — BLOCKING | NO — ADVISORY] - -### Deviations -[NONE] OR: -- BLOCKING: [description] — [GDD/ADR reference] -- ADVISORY: [description] — user accepted / flagged for tech debt - -### Scope -[All changes within stated scope] OR: -- Extra files touched: [list] — [note whether valid or scope creep] - -### Verdict: COMPLETE / COMPLETE WITH NOTES / NOT ASSESSED / BLOCKED -``` - -**Verdict definitions:** -- **COMPLETE**: all criteria pass, no blocking deviations -- **COMPLETE WITH NOTES**: every criterion passes or is `DEFERRED` (Phase 3 — - evaluable, awaiting a playtest), with advisory deviations or deferred criteria - documented — list each DEFERRED criterion so it is not lost -- **NOT ASSESSED**: one or more acceptance criteria could not be evaluated at - all — name which, and why -- **BLOCKED**: failing criteria or blocking deviations must be resolved first - -**`NOT ASSESSED` — the story nobody could verify.** Rank: it **outranks COMPLETE -and COMPLETE WITH NOTES** (a review that could not evaluate a criterion has not -shown the criterion is met) and **ranks below BLOCKED** (a criterion known to -fail is more actionable than one nobody could check, and demoting it would bury -it). It is not a gentler BLOCKED: "this acceptance criterion fails" and "I could -not tell whether it passes" send the reader to different fixes. - -**Verdict precedence — first matching rule wins**, evaluated in this order: -**BLOCKED**, then **NOT ASSESSED**, then **COMPLETE WITH NOTES**, then -**COMPLETE**. A run with both a failing criterion and an unassessable one is -BLOCKED. Stating the order mechanically, rather than leaving it to be inferred -from the rank sentence, is what keeps two reviewers from grading the same story -differently. - -Emit it when any of: - -- An acceptance criterion **cannot be evaluated at all** — it names no observable - outcome, so no evidence could settle it either way. - > **Not the same as Phase 3's `DEFERRED`.** A criterion that is evaluable but - > needs a playtest is `DEFERRED — requires playtest session`, it does **not** - > block, and Phase 3 keeps ownership of it. This trigger is for a criterion no - > session could ever settle as written. If Phase 3 already marked it DEFERRED, - > that classification stands and this trigger does not fire. -- A criterion the user answered **`Not tested yet`** (Phase 3) — it could be - checked, but nobody has. Name it and what would settle it: launch the build, - check it, then re-run `/story-done`. -- QL-TEST-COVERAGE or LP-CODE-REVIEW returned **NOT ASSESSED** and the input it - named was not supplied. -- The **test evidence is present but unreadable or unclassifiable** — corrupt, - empty, or of a type that cannot be determined. - > **Absent evidence is Phase 3's, not this trigger's.** Phase 3 resolves a - > missing file through `testing.strict`: BLOCKING types produce **BLOCKED**, - > ADVISORY types produce **COMPLETE WITH NOTES**. Both outrank or are already - > decided, so re-routing "absent" here would silently override an explicit - > advisory ruling. *Unreadable* is the genuinely unassessable case, and it is - > the only one this trigger claims. -- **`/test-evidence-review` returned `NOT ASSESSED`** for this story — applicable - only when that skill was actually run against it, which this skill does not do - itself. It - propagates: that skill's whole point is that "could not check" is not - "checked and fine", and collapsing its unknown into a COMPLETE here would undo - the distinction one skill downstream. `coding-standards.md` marks Logic and - Integration evidence BLOCKING, so this is the path where an unverifiable story - would otherwise acquire a verdict saying somebody verified it. -- A **deviation's severity cannot be determined** because the GDD or ADR it - would be judged against is missing. - -A `NOT ASSESSED` verdict takes the same Phase 7 path as BLOCKED: do not -automatically proceed, list what could not be checked and what would make it -checkable. Closing anyway remains the user's explicit call, and stays gated by -Phase 7's `scope_changes` always-ask rule. - -If the verdict is **BLOCKED**: do not *automatically* proceed to Phase 7. List -what must be fixed and offer to help fix the blocking items. This is the -default path, not an absolute stop — the user may still explicitly ask to -close the story anyway despite the blockers. That request is what routes to -Phase 7's menu below, and Phase 7's own `scope_changes` always-ask rule is -exactly what stands between that request and a silent close in autonomous -mode. Do not treat "do not automatically proceed" as "Phase 7 is now -unreachable" — it is reachable, on request, and gated when reached. - ---- +**Read `references/6-completion-report.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 7: Update Story Status -**Reached one of two ways**: normally, immediately after a COMPLETE or -COMPLETE-WITH-NOTES verdict in Phase 6; or, after a BLOCKED **or NOT ASSESSED** -verdict, only if the user explicitly asks to close the story despite the -blockers (Phase 6 does not advance here on its own in either case). - -**Automation note**: This is the story-completion gate. Closing a story whose -verdict is BLOCKED (failing acceptance criteria) **or NOT ASSESSED** (criteria -nobody could evaluate) — the "Accept deviations as-is and close anyway" option — -is a `scope_changes` decision. Call -`is_always_ask_category scope_changes`; when it returns 0 (the default), this -gate prompts via `AskUserQuestion` **regardless of `modes.automation`** — -autonomous mode must NOT silently close a BLOCKED story, even when the user's -own request is what got you here. For a COMPLETE or COMPLETE-WITH-NOTES -verdict, autonomous mode may pick "Close the story (Recommended)" and record -it via `log_decision`. - -Use `AskUserQuestion` before writing anything: -- Prompt: "Verification complete. How do you want to proceed?" -- Options: - - `Close the story — update file, mark Complete, log notes (Recommended)` - - `Close and log advisory deviations as tech debt in docs/tech-debt-register.md` - - `There are issues I want to fix first — don't close yet` - - `Accept deviations as-is and close anyway` - -If "Close", "Close and log tech debt", or "Accept deviations": edit the story file. -If "Close and log tech debt": after updating the story file, also append the advisory deviations to `docs/tech-debt-register.md` (create the file if it does not exist). -If "Fix first": stop here and list what the user flagged. Do not write any files. - -1. Update the status field: `Status: Complete` -2. Update the `Last Updated:` field in the story header to today's date (format: `YYYY-MM-DD`). If the field does not exist, add it after the `Status:` line. -3. Add a `## Completion Notes` section at the bottom: - -```markdown -## Completion Notes -**Completed**: [date] -**Criteria**: [X/Y passing] ([any deferred items listed]) -**Deviations**: [None] or [list of advisory deviations] -**Test Evidence**: [Logic: test file at path | Visual/Feel: evidence doc at path | None required (Config/Data)] -**Code Review**: [Pending / Complete / Skipped] -``` - -4. If the user chose "Close and log tech debt": append each advisory deviation to `docs/tech-debt-register.md` as one row of `/tech-debt`'s register table — the format under "Debt Register Format" in `.claude/skills/tech-debt/SKILL.md` — so `/tech-debt report` can date it from its `Added` column: - ``` - | TD-[next free NNN] | [category] | [deviation description] — from [story file path] | [files] | [S/M/L/XL] | [Low/Med/High/Critical] | — | Open | [YYYY-MM-DD] | Backlog | - ``` - Category is one of `/tech-debt`'s six (Architecture, Code Quality, Test, Documentation, Dependency, Performance); Effort and Impact are your estimate from the deviation; Priority stays `—` until `/tech-debt prioritize` scores it; `Added` is today. If the file does not exist, create it with that format's heading, `Last updated:` and `Total items:` lines and table header; if it exists, update those two lines (and add the table header first if the file has none yet). - -5. **Update `production/sprint-status.yaml`** (if it exists): - - Find the entry matching this story's file path or ID - - Set `status: done` and `completed: [today's date]` - - Update the top-level `updated` field - - This is a silent update — no extra approval needed (already approved in step above) - -6. **Suggest a git commit**: Output a ready-to-use commit command covering the implementation files from the dev-story summary and the updated story file: - -``` -Suggested commit: -git add [code-root and test-root files changed during implementation] [story-file-path] -git commit -m "feat: [story title] ([TR-ID])" -``` - -The `validate-commit.sh` hook will verify design doc references and check for hardcoded values automatically. - -### Session State Update - -After updating the story file, silently update the checkpoint in -`production/session-state/active.md` — **overwrite the `` … -`` block, never append** (schema: -`.claude/docs/templates/session-state.md`). `session-start.sh` shows exactly -that block when the next session opens. Fill **Next step** from Phase 8, so it -names the same next story the user is shown: - - - **Updated:** [date] - **Branch:** `[current git branch]` - **Current task:** /story-done — [story file path] closed: [COMPLETE / COMPLETE WITH NOTES / NOT ASSESSED / BLOCKED] - **Next step:** [/story-done [next story path] for an In Review story, else /dev-story [next story path] — or "build order done: play the build" — or the blocker to clear when every unfinished story is blocked — or the sprint's next step] - **Blocked on:** [nothing, or what blocked this verdict] - **Files in progress:** none - **Open questions:** [tech debt logged: N items, or none] - - -If `active.md` does not exist, create it from the template. If it exists with no -markers (a file from before the schema), insert the template's STATUS and -CHECKPOINT blocks at the top and leave the rest untouched. -Confirm in conversation: "Session state updated." - ---- +**Read `references/7-update-status.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 8: Surface the Next Story -After completion, help the developer keep momentum. Which branch applies depends -on whether there is a sprint at all. - -### No sprint plan — the minimal path - -**At `workflow: minimal`, or whenever `production/sprints/` holds no sprint -plan, there is no sprint to close out.** The brief's build order is the plan and -the story files carry it: - -1. Run `bash .claude/scripts/story-status.sh`, from the project root — after - Phase 7's story-file write, so this story's new status is in it. It prints - every unfinished story under `production/epics/`, whatever Status form its - file uses, **already in the route's order** — `IN_REVIEW`, then `IN_PROGRESS`, then `TODO` (a `Ready` or - `Not Started` story) in build (file-name) order — then `BLOCKED`, `OTHER`, - `NO_STATUS` and the `COMPLETE` count. It is the list `/help` and - `/sprint-status` read, so the three name the same next story; do not re-read - or re-rank the story files. -2. The first `In Review` story is next (recommend `/story-done [path]` for it — - its work is written, and closing it first keeps finished work from piling - up); else the first `In Progress` one; else the first `Ready` or - `Not Started` one — the story on the script's first `IN_REVIEW`, - `IN_PROGRESS` or `TODO` line. Name any `Blocked` story with its blocker and pass - over it. - - ``` - ### Next Up - **[Story NNN: title]** — [1-line description] - Run `/story-done [path]` to close it (In Review) — else `/dev-story [path]` to implement it. - ``` - - At `minimal` recommend `/dev-story` directly (or `/story-done` for an In Review - story) — `/story-readiness` is not on - the minimal path (engine → brief → stories → code), and it checks fields the - minimal story template does not carry. With no sprint plan at a higher tier, - add the `/story-readiness [path]` line from the sprint branch below. -3. **No unfinished story — only `COMPLETE N of N`** → every story is built — - at `minimal`, the brief's build order is done. Say so, and offer three ways on: - - play the build and note what feels wrong - - add the next stories from the brief with `/create-stories` - - if the game has outgrown a one-page brief, `/settings` to raise `modes.rigor` -4. **No `IN_REVIEW`, `IN_PROGRESS` or `TODO` line, but `BLOCKED`, `OTHER` or - `NO_STATUS` lines remain** — every unfinished story is `Blocked`, `Draft`, or - has no status line. There is no Next Up, and the - build order is **not** done — never say it is. Name each such story with its - blocker (or `Draft` / `no status`), and suggest clearing the blocker first. For - a Draft or unstatused story: at `minimal`, finish it and set its Status to - `Ready`; at a higher tier, `/story-readiness [path]` shows what it still needs. - -**Never print the Sprint Close-Out Sequence on this branch** (`/smoke-check -sprint`, `/team-qa sprint`, `/retrospective`, `/gate-check`, `/sprint-plan new`) -— it closes a sprint, and there is none. Each of those still runs if the user -asks for it; do not present them as required. - -### With a sprint plan - -1. Read the current sprint plan from `production/sprints/`. -2. Find stories that are: - - Status: READY or NOT STARTED - - Not blocked by other incomplete stories - - In the Must Have or Should Have tier - -Present: - -``` -### Next Up -The following stories are ready to pick up: -1. [Story name] — [1-line description] — Est: [X hrs] -2. [Story name] — [1-line description] — Est: [X hrs] - -Run `/story-readiness [path]` to confirm a story is implementation-ready -before starting. -``` - -If no more Must Have stories remain in this sprint (all are Complete or Blocked): - -``` -### Sprint Close-Out Sequence - -All Must Have stories are complete. QA sign-off is required before advancing. -Run these in order: - -1. `/smoke-check sprint` — verify the critical path still works end-to-end -2. `/team-qa sprint` — full QA cycle: test case execution, bug triage, sign-off report -3. `/retrospective` — capture what went well, what didn't, and action items for the next sprint -4. `/gate-check` — advance to the next phase once QA approves (only if advancing a phase) -5. `/sprint-plan new` — plan the next sprint, incorporating velocity data and retrospective action items - -Do not run `/gate-check` until `/team-qa` returns APPROVED or APPROVED WITH CONDITIONS. -``` - -If there are Should Have stories still unstarted, surface them alongside the close-out sequence so the user can choose: close the sprint now, or pull in more work first. - -If no more stories are ready but Must Have stories are still In Progress (not Complete): -"No more stories ready to start — [N] Must Have stories still in progress. Continue implementing those before sprint close-out." - ---- +**Read `references/8-next-story.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Collaborative Protocol diff --git a/.claude/skills/story-done/references/1-find-story.md b/.claude/skills/story-done/references/1-find-story.md new file mode 100644 index 00000000..4bbb1b59 --- /dev/null +++ b/.claude/skills/story-done/references/1-find-story.md @@ -0,0 +1,54 @@ +# /story-done — Phase 1: Find the Story + +> Part of `/story-done`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 1: Find the Story + +See `.claude/docs/director-gates.md` for the full check pattern. Individual gate definitions live in `.claude/docs/director-gates/[gate-id].md` — the spawned agent reads its own gate file; do not read it in the parent session. + + +Every `AskUserQuestion` call follows `.claude/docs/automation-modes.md` +(collaborative asks always · guided major-only · autonomous logs and proceeds; +`automation_always_ask` categories always prompt). + +**Workflow tier**: resolved per the story's system (per +`.claude/docs/workflow-modes.md`) — **the GDD filename stem** of the story's +`GDD:` path (`design/gdd/.md` → ``), with the `[system]` segment of +its `TR-[system]-NNN` ID accepted only as a fallback alias: use the +`system_overrides` row for that system if the block lists one, else the +project value. It governs which Phase 4 deviation checks run — see Phase 4. + +**Workflow companion — `modes.story_granularity`** (resolved above — supplied by +`modes.rigor` unless set explicitly): cadence expectation only — story-done fires **every 3–5 days** at +`coarse`, **every 1–2 days** at `balanced`, **multiple times/day** at `fine`. It +does not change any completion check. + +**`qa.level`**: controls whether test *evidence is required*, where +`testing.strict` controls whether a failure blocks and `workflow` controls which +docs exist. `modes.rigor` sets `qa.level` and `workflow` together; set either +explicitly to vary it alone. `testing.strict` is not fronted by `rigor` at all. +At `minimal`, no *test* evidence is required → skip the Logic, Integration and +Config/Data evidence checks (Phase 3), the >50%-untested traceability escalation, +and the Phase 4b QA gate; the acceptance-criteria verification still runs, and so +do the Visual/Feel and UI screenshot gate and the `Run result:` check for other +story types — the look is never waived. At +`standard`, the story's own type requires evidence; at `full`, every type does. +`testing.strict` then decides whether present-but-failing evidence blocks. +(`rigor: minimal` sets both; `qa.level: minimal` on its own leaves the workflow +tier where it was.) + +**If a file path is provided** (e.g., `/story-done production/epics/core/story-damage-calculator.md`): +read that file directly. + +**If no argument is provided:** + +1. Check `production/session-state/active.md` for the currently active story. +2. If not found there, read the most recent file in `production/sprints/` and + look for stories marked IN PROGRESS. +3. If multiple in-progress stories are found, use `AskUserQuestion`: + - "Which story are we completing?" + - Options: list the in-progress story file names. +4. If no story can be found, ask the user to provide the path. + +--- diff --git a/.claude/skills/story-done/references/2-read-story.md b/.claude/skills/story-done/references/2-read-story.md new file mode 100644 index 00000000..e1f3e742 --- /dev/null +++ b/.claude/skills/story-done/references/2-read-story.md @@ -0,0 +1,38 @@ +# /story-done — Phase 2: Read the Story + +> Part of `/story-done`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 2: Read the Story + +Read the full story file. Extract and hold in context: + +- **Story name and ID** +- **GDD Requirement TR-ID(s)** referenced (e.g., `TR-combat-001`) +- **Manifest Version** embedded in the story header (e.g., `2026-03-10`) +- **ADR reference(s)** referenced +- **Acceptance Criteria** — the complete list (every checkbox item) +- **Implementation files** — files listed under "files to create/modify" +- **Story Type** — the `Type:` field from the story header (Logic / Integration / Visual/Feel / UI / Config/Data) +- **Engine notes** — any engine-specific constraints noted +- **Definition of Done** — if present, the story-level DoD +- **Estimated vs actual scope** — if an estimate was noted + +Also read: +- `docs/architecture/tr-registry.yaml` — grep the story's TR-IDs + (`Grep pattern="id: \s*$" path="docs/architecture/tr-registry.yaml" output_mode="content" -A 6`), + not a full read of the registry. Read the *current* `requirement` text from each + matched entry. This is the source of truth for what the GDD required — do not use any + requirement text that may be quoted inline in the story (it may be stale). +- The referenced GDD section — just the acceptance criteria and key rules, not + the full document. Use this to cross-check the registry text is still accurate. +- The referenced ADR(s) — **just the `## Decision` and `## Consequences` + sections, never an unbounded full read.** Map headings first + (`Grep pattern="^## " path="docs/architecture/[adr-file].md" output_mode="content" -n`), + then bounded-`Read` only those two spans. This is the exact same content + Phase 4 item 3's ADR constraints check needs — hold it here, do not + re-read it there. +- `docs/architecture/control-manifest.md` header — extract the current + `Manifest Version:` date (used in Phase 4 staleness check) + +--- diff --git a/.claude/skills/story-done/references/3-verify-criteria.md b/.claude/skills/story-done/references/3-verify-criteria.md new file mode 100644 index 00000000..f2400a1e --- /dev/null +++ b/.claude/skills/story-done/references/3-verify-criteria.md @@ -0,0 +1,246 @@ +# /story-done — Phase 3: Verify Acceptance Criteria + +> Part of `/story-done`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 3: Verify Acceptance Criteria + +**In this file:** + +- Automatic verification (run without asking) +- Manual verification with confirmation (use `AskUserQuestion`) +- Unverifiable (flag without blocking) +- Test-Criterion Traceability +- Test Evidence Requirement + +For each acceptance criterion in the story, attempt verification using one of +three methods: + +### Automatic verification (run without asking) + +- **File existence check**: `Glob` for files the story said would be created. +- **Test file check**: if a test file path is mentioned, confirm the file exists + with `Glob`. Do not run it — this skill establishes existence only (see the + note under Test Evidence Requirement), so report "test file present", never + "test passes". +- **No hardcoded values check**: `Grep` for numeric literals in gameplay code + paths that should be in config files. +- **No hardcoded strings check**: `Grep` for player-facing strings in the **code root** (resolve per `.claude/docs/code-root-resolution.md`). **If the code root is unresolved, report `NOT ASSESSED — code root unresolved` rather than zero hits.** + that should be in localization files. +- **Dependency check**: if a criterion says "depends on X", check that X exists. + +### Manual verification with confirmation (use `AskUserQuestion`) + +- Criteria about subjective qualities ("feels responsive", "animations play correctly") +- Criteria about gameplay behaviour ("player takes damage when...", "enemy responds to...") + — these are asked, never marked verified from reading the code: the code says + what should happen, not what the build does +- Performance criteria ("completes within Xms") — ask if profiled or accept as assumed + +Batch up to 4 manual verification questions into a single `AskUserQuestion` call: + +``` +question: "Does [criterion]?" +options: "Yes — passes", "No — fails", "Not tested yet" +``` + +Map each answer: `Yes — passes` → confirmed; `No — fails` → FAILS; +`Not tested yet` → not evaluated — UNTESTED in the traceability table below, and +the verdict is NOT ASSESSED (Phase 6) until someone checks it. If the criterion +genuinely needs a full-build playtest, mark it `DEFERRED — requires playtest +session` instead. + +### Unverifiable (flag without blocking) + +- Criteria that require a full game build to test (end-to-end gameplay scenarios) +- Mark as: `DEFERRED — requires playtest session` + +### Test-Criterion Traceability + +After completing the pass/fail/deferred check above, map each acceptance +criterion to the test that covers it: + +For each acceptance criterion in the story: + +1. Ask: is there a test — unit, integration, or confirmed manual playtest — that + directly verifies this criterion? + - **Unit test**: check `tests/unit/` for a test file or function name that + matches the criterion's subject (use `Glob` and `Grep`) + - **Integration test**: check `tests/integration/` similarly + - **Manual confirmation**: if the criterion was verified via `AskUserQuestion` + above with a "Yes — passes" answer, count that as a manual test + - **Retained screenshot**: if the criterion names something on screen and a + retained image under `production/qa/evidence/[story-slug]/` shows it (the + `Run result: OBSERVED` from `/dev-story` Phase 6 step 4), count that as + covered — put the image path in the Test column. A visual criterion + verified by looking is not UNTESTED; without this row every UI story + reads as >50% untested and false-escalates. "Shows it" means you opened + the image with `Read` and saw it; a checkpoint's `Run result: OBSERVED — + ` is `/dev-story`'s description, to quote as such, not yours. + **Never describe an image you have not opened.** + +2. Produce a traceability table: + +``` +| Criterion | Test | Status | +|-----------|------|--------| +| AC-1: [criterion text] | tests/unit/test_foo.gd::test_bar | COVERED | +| AC-2: [criterion text] | Manual playtest confirmation | COVERED | +| AC-3: [criterion text] | production/qa/evidence/[slug]/01-shop-open.png | COVERED | +| AC-4: [criterion text] | — | UNTESTED | +``` + +3. Apply these escalation rules (skip entirely at `qa.level: minimal` — no + evidence is required, so untested criteria never escalate): + + - If **>50% of criteria are UNTESTED**: escalate to **BLOCKING** — test + coverage is insufficient to confirm the story is actually done. The verdict + in Phase 6 cannot be COMPLETE until coverage improves. + - If **some (≤50%) criteria are UNTESTED**: remain ADVISORY — does not block + completion, but must appear in Completion Notes. + - If **all criteria are COVERED**: no action needed beyond including the + table in the report. + +4. For any ADVISORY untested criteria, add to the Completion Notes in Phase 7: + `"Untested criteria: [AC-N list]. Recommend adding tests in a follow-up story."` + +### Test Evidence Requirement + +**First apply `qa.level` (resolved in Phase 1).** At `minimal`, no *test* +evidence is required — skip the Logic, Integration and Config/Data checks below. +But still run the Visual/Feel and UI check and the `Run result:` check: the look +is not waived at minimal, only the tests are. At `standard`, require evidence +for the story's own type. At `full`, require evidence for every story type. The +`testing.strict` resolution below applies to every check that runs. + +Based on the Story Type extracted in Phase 2, check for required evidence. + +**Resolve the gate level for this story's type.** A gate level is either +BLOCKING (a gap prevents the COMPLETE verdict in Phase 6) or ADVISORY (a gap is +noted in the Completion Notes but does not block). Resolve it from the +`testing.strict` block **already resolved in the resolved-config block at the top of this skill** — not by reading +`project.yaml` yourself: + +1. Map the Story Type to a `testing.strict` key — Logic→`logic`, + Integration→`integration`, Visual/Feel→`visual`, UI→`ui`, Config/Data→`config`. + Take `testing.strict.` from that resolved block. If its value is `true` + (case-insensitive) → BLOCKING; if `false` → ADVISORY; `unset` → fall through. +2. Else read `testing.strict` as a plain boolean (legacy single-value form). If + its value is `true` → BLOCKING or `false` → ADVISORY, it applies to every type. +3. Else use the default in the table below. + +> **Use that resolved block, never `project.yaml` directly.** `testing.strict.*` is +> on the `/settings --local` whitelist, so a developer can set +> `testing.strict.logic=false` in `project.local.yaml` for fast WIP commits — +> `effects-map.md` specifies exactly this ("stricter dev's local `/story-done` +> blocks earlier"). Reading `project.yaml` alone silently ignores that file: the +> setting is accepted, displayed by `/settings`, and has no effect. The +> `resolve_config` block at the top of this skill already merges local over base. + +Only `true` and `false` (case-insensitive) are recognized at steps 1–2. A key +that is present but holds any other value — `maybe`, `1`, `yes`, etc. — is +treated as unset: continue to the next step, and surface the unrecognized value +to the user. + +| Story Type | Required Evidence | Default Gate Level | +|---|---|---| +| **Logic** | Automated unit test in `tests/unit/[system]/` — must exist and pass (this skill verifies **existence**; see the note below Phase 3) | BLOCKING | +| **Integration** | Integration test in `tests/integration/[system]/` OR playtest doc | BLOCKING | +| **Visual/Feel** | Retained screenshot + sign-off in `production/qa/evidence/` | BLOCKING | +| **UI** | Retained screenshot of each screen touched, in `production/qa/evidence/` | BLOCKING | +| **Config/Data** | Smoke check pass report in `production/qa/smoke-*.md` | ADVISORY | + +The **Default Gate Level** column applies when `testing.strict` is unset (the +common case). When `testing.strict` is configured, the resolved value from +steps 1–2 overrides it. Visual/Feel and UI default to BLOCKING because for a +game the rendered result is the product; set `testing.strict.visual` or +`testing.strict.ui` to `false` for an advisory gate. + +> **Exception — `/smoke-check`.** The ADVISORY default for **Config/Data** above +> governs *per-story evidence* gates, which is what this skill checks. +> `/smoke-check` is a build-health gate, not a per-story evidence gate, so its own +> unset default for `testing.strict.config` is **BLOCKING** — see +> `.claude/skills/smoke-check/SKILL.md` § "Resolve the gate enforcement level". +> The divergence is intentional; do not "fix" either side to match the other. + +> **This phase checks that evidence EXISTS. It does not run anything.** The +> `Default Gate Level` table above, and `.claude/docs/coding-standards.md`, both +> say a Logic story's test "must exist **and pass**". The checks below establish +> only the first half — every one of them is a `Glob` or a `Grep`. A unit test +> that exists and fails, or that contains no assertions, satisfies them. +> +> Say which half you verified when you report. "Test file present at ``" +> is the honest claim; "tests pass" is not one this phase can make. Pass/fail is +> established by `/gate-check` (runs the suite at a phase gate) and +> `/smoke-check` (runs it before QA hand-off), both of which do execute. +> +> Unlike `/regression-suite` and `/launch-checklist`, which stop at existence +> and carry no general `Bash` pre-approval, this skill has `Bash` pre-approved — +> the limit here is the instruction, not the grant (a pre-approval never +> restricts). Running the story's own test before closing it is a live option; +> it is not enabled because it needs a configured runner and a decision about +> what a missing runner should mean. + +**For Logic stories**: first read the story's **Test Evidence** section to extract the +exact required file path. Use `Glob` to check that exact path. If the exact path is not +found, also search `tests/unit/[system]/` broadly (the file may have been placed at a +slightly different location). If no test file is found at either location: +- Flag at the resolved gate level: "Logic story has no unit test file. Story + requires it at `[exact-path-from-Test-Evidence-section]`. Create and run the + test before marking this story Complete." + +**For Integration stories**: read the story's **Test Evidence** section for the exact +required path. Use `Glob` to check that exact path first, then search +`tests/integration/[system]/` broadly, then check `production/session-logs/` for a +playtest record referencing this story. +If none found: flag at the resolved gate level (same rule as Logic). + +**For Visual/Feel and UI stories**: glob `production/qa/evidence/` for a +retained screenshot for this story (`*.png`, `*.jpg`, `*.gif`) and for an +evidence doc referencing it. What closes the story follows the evidence table +in `.claude/docs/coding-standards.md`, the same at every `qa.level`: +- A **UI** story is satisfied by the retained screenshot of each screen it + touched. No evidence doc or sign-off is required; note one if it exists. +- A **Visual/Feel** story also needs the sign-off: the evidence doc + (`production/qa/evidence/[story-slug]-evidence.md`, from the test-evidence + template) with every sign-off row `[x] Approved`. + +Flag at the resolved gate level: +- No screenshot: "No visual evidence found. Capture a screenshot of each screen or effect this story touched and save it under `production/qa/evidence/` before final closure." For Visual/Feel add: "then record sign-off in `production/qa/evidence/[story-slug]-evidence.md` using the test-evidence template." +- An evidence doc but no screenshot retained beside it: "Evidence doc found at `[path]` but no screenshot is retained. A described check is an assertion, not evidence — capture the screen and save the image under `production/qa/evidence/` before final closure." +- Visual/Feel with a screenshot but no evidence doc: "Screenshot found but no sign-off is recorded. Create `production/qa/evidence/[story-slug]-evidence.md` using the test-evidence template and obtain sign-off before final closure." +- Visual/Feel sign-off rows still unchecked — grep the doc for `| .* | .* | .* | \[ \] Approved`: "Evidence file found at `[path]` but [N] sign-off(s) are still pending (shown as `[ ] Approved` in the sign-off table). Obtain required sign-offs before final closure. Note: for solo developers, all roles may be signed off by the same person." + +Otherwise note "Retained screenshot found[, sign-offs complete] — gate satisfied." + +The retained image **is** the `Run result: OBSERVED` from `/dev-story` Phase 6 +step 4 (`.claude/docs/run-and-observe.md`); its absence means the run was +`NOT VERIFIED` or never happened, and the flag above is the consequence. The +run is not waived at `qa.level: minimal`. + +**For every other story type**, read the `Run result:` line from the +`/dev-story` checkpoint in `production/session-state/active.md` — only when its +**Current task** names this story; a later `/dev-story` overwrites it — or from +the story's `## Completion Notes`. `OBSERVED` with a retained path: note +it. `N/A — `: accept only if the reason names why nothing is +observable — "it's a Logic story" is not a reason. `NOT VERIFIED — ` +on a story whose acceptance criteria name anything on screen: flag at the +resolved gate level for the story's type. No `Run result:` line at all: flag +as ADVISORY — "the implementation summary carries no run result; confirm the +build was launched and looked at before closure." The exception: when the +acceptance criteria name something on screen and no retained image for this +story is under `production/qa/evidence/`, nothing observed the story — a user's +`Yes — passes` to such a criterion is an assertion, not the retained observation +`.claude/docs/run-and-observe.md` requires — so flag it at the resolved gate +level for the story's type, as for `NOT VERIFIED`. + +**For Config/Data stories**: check for any `production/qa/smoke-*.md` file. +If none: flag at the resolved gate level — "No smoke check report found. Run `/smoke-check`." + +**If no Story Type is set**: flag as **ADVISORY** — +"Story Type not declared. Add `Type: [Logic|Integration|Visual/Feel|UI|Config/Data]` +to the story header to enable test evidence gate enforcement in future stories." + +Any BLOCKING test evidence gap prevents the COMPLETE verdict in Phase 6. + +--- diff --git a/.claude/skills/story-done/references/4-deviations.md b/.claude/skills/story-done/references/4-deviations.md new file mode 100644 index 00000000..1149d6b8 --- /dev/null +++ b/.claude/skills/story-done/references/4-deviations.md @@ -0,0 +1,96 @@ +# /story-done — Phases 4 and 4b: Deviations and QA Coverage Gate + +> Part of `/story-done`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 4: Check for Deviations + +Compare the implementation against the design documents. + +> **Workflow tier adjustment** (resolved in Phase 1, per the story's system). +> Checks 1 (GDD rules) and 3 (ADR constraints) below are the `full` baseline: +> - **`full`** — run both: full GDD traceability against the current TR text + +> the ADR constraints check. +> - **`standard`** — run the GDD rules check against the **5 required sections**; +> run the ADR constraints check only where a **critical ADR** governs the story. +> - **`minimal`** — **acceptance-criteria check only**: skip checks 1 and 3 (no +> GDD/ADR traceability expected). Checks 2 (manifest), 4 (hardcoded values), and +> 5 (scope) still run as written. +> +> This adjustment governs only the Phase 4 *deviation* checks. The test-evidence +> gates (Phase 3 traceability, Phase 4b QA coverage) are governed by `qa.level` +> and `testing.strict`, not `workflow` — they run independently of the tier here. + +Run these checks automatically: + +1. **GDD rules check**: Using the current requirement text from `tr-registry.yaml` + (looked up by the story's TR-ID), check that the implementation reflects what + the GDD actually requires now — not what it required when the story was written. + `Grep` the implemented files for key function names, data structures, or class + names mentioned in the current GDD section. + +2. **Manifest version staleness check**: Compare the `Manifest Version:` date + embedded in the story header against the `Manifest Version:` date in the + current `docs/architecture/control-manifest.md` header. + - If they match → pass silently. + - If the story's version is older → flag as ADVISORY: + `ADVISORY: Story was written against manifest v[story-date]; current manifest + is v[current-date]. New rules may apply. Run /story-readiness to check.` + - If control-manifest.md does not exist → skip this check. + +3. **ADR constraints check**: Use the ADR's `## Decision` section already + loaded in Phase 2 — do not read the ADR file again. Check for forbidden + patterns from `docs/architecture/control-manifest.md` (if it exists). + `Grep` for patterns explicitly forbidden in the ADR. + +4. **Hardcoded values check**: `Grep` the implemented files for numeric literals + in gameplay logic that should be in data files. + +5. **Scope check**: Did the implementation touch files outside the story's stated + scope? (files not listed in "files to create/modify") + +For each deviation found, categorize: + +- **BLOCKING** — implementation contradicts the GDD or ADR (must fix before + marking complete) +- **ADVISORY** — implementation drifts slightly from spec but is functionally + equivalent (document, user decides) +- **OUT OF SCOPE** — additional files were touched beyond the story's stated + boundary (flag for awareness — may be valid or scope creep) + +--- + +## Phase 4b: QA Coverage Gate + +**Skip this phase entirely at `qa.level: minimal`** (resolved in Phase 1) — no +test evidence is required, so there is no coverage to review. Note: "QL-TEST-COVERAGE +skipped — qa.level minimal." Proceed to Phase 5. + +**Review mode check** — apply before spawning QL-TEST-COVERAGE: +- `solo` → skip. Note: "QL-TEST-COVERAGE skipped — Solo mode." Proceed to Phase 5. +- `lean` → skip (not a PHASE-GATE). Note: "QL-TEST-COVERAGE skipped — Lean mode." Proceed to Phase 5. +- `full` → spawn as normal. + +After completing the deviation checks in Phase 4, spawn `qa-lead` via `Agent` using gate **QL-TEST-COVERAGE** (`.claude/docs/director-gates/ql-test-coverage.md`). + +Pass: +- The story file path and story type +- Test file paths found during Phase 3 (exact paths, or "none found") +- The story's `## QA Test Cases` section (the pre-written test specs from story creation) +- The story's `## Acceptance Criteria` list +- The GDD acceptance criteria and Edge Cases for the story's system, from the GDD + section read in Phase 2 — or "no GDD for this system" when there is none (at + `workflow: minimal` the story's own criteria are the spec); an absent GDD is + information for the gate, not a missing input + +The qa-lead reviews whether the tests actually cover what was specified — not just whether files exist. + +Apply the verdict: +- **ADEQUATE** → proceed to Phase 5 +- **GAPS** → flag as **ADVISORY**: "QA lead identified coverage gaps: [list]. Story can complete but gaps should be addressed in a follow-up story." +- **INADEQUATE** → flag as **BLOCKING**: "QA lead: critical logic is untested. Verdict cannot be COMPLETE until coverage improves. Specific gaps: [list]." +- **NOT ASSESSED [missing input]** → no judgement was made; never read it as ADEQUATE. Name the missing input — supply it and re-run the gate, or carry it to Phase 6, where it keeps the verdict at best NOT ASSESSED. + +Skip this phase for Config/Data stories (no code tests required). + +--- diff --git a/.claude/skills/story-done/references/5-code-review-gate.md b/.claude/skills/story-done/references/5-code-review-gate.md new file mode 100644 index 00000000..f0565c55 --- /dev/null +++ b/.claude/skills/story-done/references/5-code-review-gate.md @@ -0,0 +1,30 @@ +# /story-done — Phase 5: Lead Programmer Code Review Gate + +> Part of `/story-done`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 5: Lead Programmer Code Review Gate + +**Review mode check** — apply before spawning LP-CODE-REVIEW: +- `solo` → skip. Note: "LP-CODE-REVIEW skipped — Solo mode." Proceed to Phase 6 (completion report). +- `lean` → use `AskUserQuestion` before proceeding: + - Prompt: "Code review is skipped in lean mode. Did you run `/code-review` on the implemented files?" + - Options: + - `Yes — /code-review passed or was approved with suggestions` + - `No — skipping code review for this story` + - `No — I'll run /code-review before the sprint close-out` + - Record the answer in the completion notes (Phase 7). All three options proceed to Phase 6. +- `full` → spawn as normal. + +Spawn `lead-programmer` via `Agent` using gate **LP-CODE-REVIEW** (`.claude/docs/director-gates/lp-code-review.md`). + +Pass: implementation file paths, story file path, relevant GDD section, governing ADR. + +Present the verdict to the user. If CONCERNS, surface them via `AskUserQuestion`: +- Options: `Revise flagged issues` / `Accept and proceed` / `Discuss further` +If REJECT, do not proceed to Phase 6 verdict until the issues are resolved. +If NOT ASSESSED, name the input the gate said was missing and never treat it as APPROVE: supply it and re-run the gate, or carry it to Phase 6, where it keeps the verdict at best NOT ASSESSED. + +If the story has no implementation files yet (verdict is being run before coding is done), skip this phase and note: "LP-CODE-REVIEW skipped — no implementation files found. Run after implementation is complete." + +--- diff --git a/.claude/skills/story-done/references/6-completion-report.md b/.claude/skills/story-done/references/6-completion-report.md new file mode 100644 index 00000000..d06f5011 --- /dev/null +++ b/.claude/skills/story-done/references/6-completion-report.md @@ -0,0 +1,121 @@ +# /story-done — Phase 6: Present the Completion Report + +> Part of `/story-done`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 6: Present the Completion Report + +**In this file:** + +- The completion report template +- Verdict definitions +- `NOT ASSESSED` and verdict precedence + +Before updating any files, present the full report: + +```markdown +## Story Done: [Story Name] +**Story**: [file path] +**Date**: [today] + +### Acceptance Criteria: [X/Y passing] +- [x] [Criterion 1] — auto-verified (test file present) +- [x] [Criterion 2] — confirmed +- [ ] [Criterion 3] — FAILS: [reason] +- [?] [Criterion 4] — DEFERRED: requires playtest + +### Test-Criterion Traceability +| Criterion | Test | Status | +|-----------|------|--------| +| AC-1: [text] | [test file::test name] | COVERED | +| AC-2: [text] | Manual confirmation | COVERED | +| AC-3: [text] | — | UNTESTED | + +### Test Evidence +**Story Type**: [Logic | Integration | Visual/Feel | UI | Config/Data | Not declared] +**Required evidence**: [unit test file | integration test or playtest | screenshot + sign-off | screenshot of each screen touched | smoke check pass] +**Evidence found**: [YES — `[path]` | NO — BLOCKING | NO — ADVISORY] + +### Deviations +[NONE] OR: +- BLOCKING: [description] — [GDD/ADR reference] +- ADVISORY: [description] — user accepted / flagged for tech debt + +### Scope +[All changes within stated scope] OR: +- Extra files touched: [list] — [note whether valid or scope creep] + +### Verdict: COMPLETE / COMPLETE WITH NOTES / NOT ASSESSED / BLOCKED +``` + +**Verdict definitions:** +- **COMPLETE**: all criteria pass, no blocking deviations +- **COMPLETE WITH NOTES**: every criterion passes or is `DEFERRED` (Phase 3 — + evaluable, awaiting a playtest), with advisory deviations or deferred criteria + documented — list each DEFERRED criterion so it is not lost +- **NOT ASSESSED**: one or more acceptance criteria could not be evaluated at + all — name which, and why +- **BLOCKED**: failing criteria or blocking deviations must be resolved first + +**`NOT ASSESSED` — the story nobody could verify.** Rank: it **outranks COMPLETE +and COMPLETE WITH NOTES** (a review that could not evaluate a criterion has not +shown the criterion is met) and **ranks below BLOCKED** (a criterion known to +fail is more actionable than one nobody could check, and demoting it would bury +it). It is not a gentler BLOCKED: "this acceptance criterion fails" and "I could +not tell whether it passes" send the reader to different fixes. + +**Verdict precedence — first matching rule wins**, evaluated in this order: +**BLOCKED**, then **NOT ASSESSED**, then **COMPLETE WITH NOTES**, then +**COMPLETE**. A run with both a failing criterion and an unassessable one is +BLOCKED. Stating the order mechanically, rather than leaving it to be inferred +from the rank sentence, is what keeps two reviewers from grading the same story +differently. + +Emit it when any of: + +- An acceptance criterion **cannot be evaluated at all** — it names no observable + outcome, so no evidence could settle it either way. + > **Not the same as Phase 3's `DEFERRED`.** A criterion that is evaluable but + > needs a playtest is `DEFERRED — requires playtest session`, it does **not** + > block, and Phase 3 keeps ownership of it. This trigger is for a criterion no + > session could ever settle as written. If Phase 3 already marked it DEFERRED, + > that classification stands and this trigger does not fire. +- A criterion the user answered **`Not tested yet`** (Phase 3) — it could be + checked, but nobody has. Name it and what would settle it: launch the build, + check it, then re-run `/story-done`. +- QL-TEST-COVERAGE or LP-CODE-REVIEW returned **NOT ASSESSED** and the input it + named was not supplied. +- The **test evidence is present but unreadable or unclassifiable** — corrupt, + empty, or of a type that cannot be determined. + > **Absent evidence is Phase 3's, not this trigger's.** Phase 3 resolves a + > missing file through `testing.strict`: BLOCKING types produce **BLOCKED**, + > ADVISORY types produce **COMPLETE WITH NOTES**. Both outrank or are already + > decided, so re-routing "absent" here would silently override an explicit + > advisory ruling. *Unreadable* is the genuinely unassessable case, and it is + > the only one this trigger claims. +- **`/test-evidence-review` returned `NOT ASSESSED`** for this story — applicable + only when that skill was actually run against it, which this skill does not do + itself. It + propagates: that skill's whole point is that "could not check" is not + "checked and fine", and collapsing its unknown into a COMPLETE here would undo + the distinction one skill downstream. `coding-standards.md` marks Logic and + Integration evidence BLOCKING, so this is the path where an unverifiable story + would otherwise acquire a verdict saying somebody verified it. +- A **deviation's severity cannot be determined** because the GDD or ADR it + would be judged against is missing. + +A `NOT ASSESSED` verdict takes the same Phase 7 path as BLOCKED: do not +automatically proceed, list what could not be checked and what would make it +checkable. Closing anyway remains the user's explicit call, and stays gated by +Phase 7's `scope_changes` always-ask rule. + +If the verdict is **BLOCKED**: do not *automatically* proceed to Phase 7. List +what must be fixed and offer to help fix the blocking items. This is the +default path, not an absolute stop — the user may still explicitly ask to +close the story anyway despite the blockers. That request is what routes to +Phase 7's menu below, and Phase 7's own `scope_changes` always-ask rule is +exactly what stands between that request and a silent close in autonomous +mode. Do not treat "do not automatically proceed" as "Phase 7 is now +unreachable" — it is reachable, on request, and gated when reached. + +--- diff --git a/.claude/skills/story-done/references/7-update-status.md b/.claude/skills/story-done/references/7-update-status.md new file mode 100644 index 00000000..c0f059ec --- /dev/null +++ b/.claude/skills/story-done/references/7-update-status.md @@ -0,0 +1,95 @@ +# /story-done — Phase 7: Update Story Status + +> Part of `/story-done`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 7: Update Story Status + +**Reached one of two ways**: normally, immediately after a COMPLETE or +COMPLETE-WITH-NOTES verdict in Phase 6; or, after a BLOCKED **or NOT ASSESSED** +verdict, only if the user explicitly asks to close the story despite the +blockers (Phase 6 does not advance here on its own in either case). + +**Automation note**: This is the story-completion gate. Closing a story whose +verdict is BLOCKED (failing acceptance criteria) **or NOT ASSESSED** (criteria +nobody could evaluate) — the "Accept deviations as-is and close anyway" option — +is a `scope_changes` decision. Call +`is_always_ask_category scope_changes`; when it returns 0 (the default), this +gate prompts via `AskUserQuestion` **regardless of `modes.automation`** — +autonomous mode must NOT silently close a BLOCKED story, even when the user's +own request is what got you here. For a COMPLETE or COMPLETE-WITH-NOTES +verdict, autonomous mode may pick "Close the story (Recommended)" and record +it via `log_decision`. + +Use `AskUserQuestion` before writing anything: +- Prompt: "Verification complete. How do you want to proceed?" +- Options: + - `Close the story — update file, mark Complete, log notes (Recommended)` + - `Close and log advisory deviations as tech debt in docs/tech-debt-register.md` + - `There are issues I want to fix first — don't close yet` + - `Accept deviations as-is and close anyway` + +If "Close", "Close and log tech debt", or "Accept deviations": edit the story file. +If "Close and log tech debt": after updating the story file, also append the advisory deviations to `docs/tech-debt-register.md` (create the file if it does not exist). +If "Fix first": stop here and list what the user flagged. Do not write any files. + +1. Update the status field: `Status: Complete` +2. Update the `Last Updated:` field in the story header to today's date (format: `YYYY-MM-DD`). If the field does not exist, add it after the `Status:` line. +3. Add a `## Completion Notes` section at the bottom: + +```markdown +## Completion Notes +**Completed**: [date] +**Criteria**: [X/Y passing] ([any deferred items listed]) +**Deviations**: [None] or [list of advisory deviations] +**Test Evidence**: [Logic: test file at path | Visual/Feel: evidence doc at path | None required (Config/Data)] +**Code Review**: [Pending / Complete / Skipped] +``` + +4. If the user chose "Close and log tech debt": append each advisory deviation to `docs/tech-debt-register.md` as one row of `/tech-debt`'s register table — the format under "Debt Register Format" in `.claude/skills/tech-debt/SKILL.md` — so `/tech-debt report` can date it from its `Added` column: + ``` + | TD-[next free NNN] | [category] | [deviation description] — from [story file path] | [files] | [S/M/L/XL] | [Low/Med/High/Critical] | — | Open | [YYYY-MM-DD] | Backlog | + ``` + Category is one of `/tech-debt`'s six (Architecture, Code Quality, Test, Documentation, Dependency, Performance); Effort and Impact are your estimate from the deviation; Priority stays `—` until `/tech-debt prioritize` scores it; `Added` is today. If the file does not exist, create it with that format's heading, `Last updated:` and `Total items:` lines and table header; if it exists, update those two lines (and add the table header first if the file has none yet). + +5. **Update `production/sprint-status.yaml`** (if it exists): + - Find the entry matching this story's file path or ID + - Set `status: done` and `completed: [today's date]` + - Update the top-level `updated` field + - This is a silent update — no extra approval needed (already approved in step above) + +6. **Suggest a git commit**: Output a ready-to-use commit command covering the implementation files from the dev-story summary and the updated story file: + +``` +Suggested commit: +git add [code-root and test-root files changed during implementation] [story-file-path] +git commit -m "feat: [story title] ([TR-ID])" +``` + +The `validate-commit.sh` hook blocks invalid data JSON and warns on hardcoded gameplay values and TODOs without an owner. It does not read the commit message: the story and design references go there from you. + +### Session State Update + +After updating the story file, silently update the checkpoint in +`production/session-state/active.md` — **overwrite the `` … +`` block, never append** (schema: +`.claude/docs/templates/session-state.md`). `session-start.sh` shows exactly +that block when the next session opens. Fill **Next step** from Phase 8, so it +names the same next story the user is shown: + + + **Updated:** [date] + **Branch:** `[current git branch]` + **Current task:** /story-done — [story file path] closed: [COMPLETE / COMPLETE WITH NOTES / NOT ASSESSED / BLOCKED] + **Next step:** [/story-done [next story path] for an In Review story, else /dev-story [next story path] — or "build order done: play the build" — or the blocker to clear when every unfinished story is blocked — or the sprint's next step] + **Blocked on:** [nothing, or what blocked this verdict] + **Files in progress:** none + **Open questions:** [tech debt logged: N items, or none] + + +If `active.md` does not exist, create it from the template. If it exists with no +markers (a file from before the schema), insert the template's STATUS and +CHECKPOINT blocks at the top and leave the rest untouched. +Confirm in conversation: "Session state updated." + +--- diff --git a/.claude/skills/story-done/references/8-next-story.md b/.claude/skills/story-done/references/8-next-story.md new file mode 100644 index 00000000..f624fe68 --- /dev/null +++ b/.claude/skills/story-done/references/8-next-story.md @@ -0,0 +1,108 @@ +# /story-done — Phase 8: Surface the Next Story + +> Part of `/story-done`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 8: Surface the Next Story + +**In this file:** + +- No sprint plan — the minimal path +- With a sprint plan + +After completion, help the developer keep momentum. Which branch applies depends +on whether there is a sprint at all. + +### No sprint plan — the minimal path + +**At `workflow: minimal`, or whenever `production/sprints/` holds no sprint +plan, there is no sprint to close out.** The brief's build order is the plan and +the story files carry it: + +1. Run `bash .claude/scripts/story-status.sh`, from the project root — after + Phase 7's story-file write, so this story's new status is in it. It prints + every unfinished story under `production/epics/`, whatever Status form its + file uses, **already in the route's order** — `IN_REVIEW`, then `IN_PROGRESS`, then `TODO` (a `Ready` or + `Not Started` story) in build (file-name) order — then `BLOCKED`, `OTHER`, + `NO_STATUS` and the `COMPLETE` count. It is the list `/help` and + `/sprint-status` read, so the three name the same next story; do not re-read + or re-rank the story files. +2. The first `In Review` story is next (recommend `/story-done [path]` for it — + its work is written, and closing it first keeps finished work from piling + up); else the first `In Progress` one; else the first `Ready` or + `Not Started` one — the story on the script's first `IN_REVIEW`, + `IN_PROGRESS` or `TODO` line. Name any `Blocked` story with its blocker and pass + over it. + + ``` + ### Next Up + **[Story NNN: title]** — [1-line description] + Run `/story-done [path]` to close it (In Review) — else `/dev-story [path]` to implement it. + ``` + + At `minimal` recommend `/dev-story` directly (or `/story-done` for an In Review + story) — `/story-readiness` is not on + the minimal path (engine → brief → stories → code), and it checks fields the + minimal story template does not carry. With no sprint plan at a higher tier, + add the `/story-readiness [path]` line from the sprint branch below. +3. **No unfinished story — only `COMPLETE N of N`** → every story is built — + at `minimal`, the brief's build order is done. Say so, and offer three ways on: + - play the build and note what feels wrong + - add the next stories from the brief with `/create-stories` + - if the game has outgrown a one-page brief, `/settings` to raise `modes.rigor` +4. **No `IN_REVIEW`, `IN_PROGRESS` or `TODO` line, but `BLOCKED`, `OTHER` or + `NO_STATUS` lines remain** — every unfinished story is `Blocked`, `Draft`, or + has no status line. There is no Next Up, and the + build order is **not** done — never say it is. Name each such story with its + blocker (or `Draft` / `no status`), and suggest clearing the blocker first. For + a Draft or unstatused story: at `minimal`, finish it and set its Status to + `Ready`; at a higher tier, `/story-readiness [path]` shows what it still needs. + +**Never print the Sprint Close-Out Sequence on this branch** (`/smoke-check +sprint`, `/team-qa sprint`, `/retrospective`, `/gate-check`, `/sprint-plan new`) +— it closes a sprint, and there is none. Each of those still runs if the user +asks for it; do not present them as required. + +### With a sprint plan + +1. Read the current sprint plan from `production/sprints/`. +2. Find stories that are: + - Status: READY or NOT STARTED + - Not blocked by other incomplete stories + - In the Must Have or Should Have tier + +Present: + +``` +### Next Up +The following stories are ready to pick up: +1. [Story name] — [1-line description] — Est: [X hrs] +2. [Story name] — [1-line description] — Est: [X hrs] + +Run `/story-readiness [path]` to confirm a story is implementation-ready +before starting. +``` + +If no more Must Have stories remain in this sprint (all are Complete or Blocked): + +``` +### Sprint Close-Out Sequence + +All Must Have stories are complete. QA sign-off is required before advancing. +Run these in order: + +1. `/smoke-check sprint` — verify the critical path still works end-to-end +2. `/team-qa sprint` — full QA cycle: test case execution, bug triage, sign-off report +3. `/retrospective` — capture what went well, what didn't, and action items for the next sprint +4. `/gate-check` — advance to the next phase once QA approves (only if advancing a phase) +5. `/sprint-plan new` — plan the next sprint, incorporating velocity data and retrospective action items + +Do not run `/gate-check` until `/team-qa` returns APPROVED or APPROVED WITH CONDITIONS. +``` + +If there are Should Have stories still unstarted, surface them alongside the close-out sequence so the user can choose: close the sprint now, or pull in more work first. + +If no more stories are ready but Must Have stories are still In Progress (not Complete): +"No more stories ready to start — [N] Must Have stories still in progress. Continue implementing those before sprint close-out." + +--- diff --git a/.claude/skills/story-readiness/SKILL.md b/.claude/skills/story-readiness/SKILL.md index 1cd91efc..f2f15da8 100644 --- a/.claude/skills/story-readiness/SKILL.md +++ b/.claude/skills/story-readiness/SKILL.md @@ -237,7 +237,8 @@ items pass or are explicitly marked N/A with a stated reason. - [ ] **TR-ID is valid and active**: If the story contains a `TR-[system]-NNN` reference, look it up in the TR registry loaded in Section 2. - If the ID exists and `status: active` → pass. - - If the ID exists and `status: deprecated` or `status: superseded-by: ...` → + - If the ID exists and `status: deprecated` or `status: "superseded-by: ..."` + (quoted or not) → NEEDS WORK: the requirement was removed or replaced. Fix: update the story to reference the current requirement ID or remove if no longer applicable. - If the ID does not exist in the registry → NEEDS WORK: ID was not registered diff --git a/.claude/skills/team-audio/SKILL.md b/.claude/skills/team-audio/SKILL.md index 59ee2be0..dc3410e5 100644 --- a/.claude/skills/team-audio/SKILL.md +++ b/.claude/skills/team-audio/SKILL.md @@ -7,6 +7,8 @@ allowed-tools: Read, Glob, Grep, Write, Edit, Bash, Agent, AskUserQuestion, Task model: sonnet --- +# Team Audio + If no argument is provided, output usage guidance and exit without spawning any agents: > Usage: `/team-audio [feature or area to design audio for] [--review full|lean|solo]` — specify the feature or area to design audio for (e.g., `combat`, `main menu`, `forest biome`, `boss encounter`). Do not use `AskUserQuestion` here; output the guidance directly. diff --git a/.claude/skills/team-combat/SKILL.md b/.claude/skills/team-combat/SKILL.md index 2d3a677a..c2d7df5a 100644 --- a/.claude/skills/team-combat/SKILL.md +++ b/.claude/skills/team-combat/SKILL.md @@ -6,6 +6,8 @@ user-invocable: true allowed-tools: Read, Glob, Grep, Write, Edit, Bash, Agent, AskUserQuestion, TaskCreate, TaskGet, TaskList, TaskUpdate, Bash(bash "*/.claude/skills/team-combat/../../hooks/yaml-helper.sh" resolve_config *) model: sonnet --- +# Team Combat + **Argument check:** If no combat feature description is provided, output: > "Usage: `/team-combat [combat feature description] [--review full|lean|solo]` — Provide a description of the combat feature to design and implement (e.g., `melee parry system`, `ranged weapon spread`)." Then stop immediately without spawning any subagents or reading any files. diff --git a/.claude/skills/team-level/SKILL.md b/.claude/skills/team-level/SKILL.md index 5527dc63..a71bd02d 100644 --- a/.claude/skills/team-level/SKILL.md +++ b/.claude/skills/team-level/SKILL.md @@ -7,6 +7,8 @@ allowed-tools: Read, Glob, Grep, Write, Edit, Bash, Agent, AskUserQuestion, Task model: sonnet --- +# Team Level + If no argument is provided, output usage guidance and exit without spawning any agents or reading any design files: > Usage: `/team-level [level name or area to design] [--review full|lean|solo]` — specify the level or area to design (e.g., `forest temple`, `tutorial village`, `final boss arena`). Do not use `AskUserQuestion` here; output the guidance directly. diff --git a/.claude/skills/team-live-ops/SKILL.md b/.claude/skills/team-live-ops/SKILL.md index 261ef735..e9b14596 100644 --- a/.claude/skills/team-live-ops/SKILL.md +++ b/.claude/skills/team-live-ops/SKILL.md @@ -6,6 +6,8 @@ user-invocable: true allowed-tools: Read, Glob, Grep, Write, Edit, Bash, Agent, AskUserQuestion, TaskCreate, TaskGet, TaskList, TaskUpdate, Bash(bash "*/.claude/skills/team-live-ops/../../hooks/yaml-helper.sh" resolve_config *) model: sonnet --- +# Team Live Ops + **Argument check:** If no season name or event description is provided, output: > "Usage: `/team-live-ops [season name or event description] [--review full|lean|solo]` — Provide the name or description of the season or live event to plan." Then stop immediately without spawning any subagents or reading any files. @@ -24,7 +26,7 @@ in `autonomous` mode it runs end to end, recording each phase outcome via ## Phase 0: Resolve Config -!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys review_mode,automation,team.size` +!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys review_mode,automation,team.size,workflow` Resolved above — use as-is; `--review` overrides `review_mode`. No block → defaults in `.claude/docs/config-resolution.md`. @@ -233,7 +235,7 @@ Verdict: **COMPLETE** — season plan produced and handed off for production. ## Next Steps - Run `/design-review` on the season design document for consistency validation. -- Run `/sprint-plan` to schedule content creation work for the season. +- Run `/sprint-plan` to schedule content creation work for the season (at `workflow: minimal`, which has no sprints, add it to the brief's build order instead). - Run `/team-release` when the season content is ready to deploy. - If the run ended **BLOCKED** on an ethics flag: revise the economy design against `design/live-ops/ethics-policy.md` and re-run `/team-live-ops`; the three steps diff --git a/.claude/skills/team-narrative/SKILL.md b/.claude/skills/team-narrative/SKILL.md index 3fb158bf..369a9181 100644 --- a/.claude/skills/team-narrative/SKILL.md +++ b/.claude/skills/team-narrative/SKILL.md @@ -6,6 +6,8 @@ user-invocable: true allowed-tools: Read, Glob, Grep, Write, Edit, Agent, AskUserQuestion, TaskCreate, TaskGet, TaskList, TaskUpdate, Bash(bash "*/.claude/skills/team-narrative/../../hooks/yaml-helper.sh" resolve_config *) model: sonnet --- +# Team Narrative + If no argument is provided, output usage guidance and exit without spawning any agents: > Usage: `/team-narrative [narrative content description] [--review full|lean|solo]` — describe the story content, scene, or narrative area to work on (e.g., `boss encounter cutscene`, `faction intro dialogue`, `tutorial narrative`). Do not use `AskUserQuestion` here; output the guidance directly. diff --git a/.claude/skills/team-polish/SKILL.md b/.claude/skills/team-polish/SKILL.md index 8f97bc03..b4bf0855 100644 --- a/.claude/skills/team-polish/SKILL.md +++ b/.claude/skills/team-polish/SKILL.md @@ -6,6 +6,8 @@ user-invocable: true allowed-tools: Read, Glob, Grep, Write, Edit, Bash, Agent, AskUserQuestion, TaskCreate, TaskGet, TaskList, TaskUpdate, Bash(bash "*/.claude/skills/team-polish/../../hooks/yaml-helper.sh" resolve_config *) model: sonnet --- +# Team Polish + If no argument is provided, output usage guidance and exit without spawning any agents: > Usage: `/team-polish [feature or area to polish] [--review full|lean|solo]` — specify the feature or area to polish (e.g., `combat`, `main menu`, `inventory system`, `level-1`). Do not use `AskUserQuestion` here; output the guidance directly. @@ -23,7 +25,7 @@ in `autonomous` mode it runs end to end, recording each phase outcome via ## Phase 0: Resolve Config -!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys review_mode,automation,team.size` +!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys review_mode,automation,team.size,workflow` Resolved above — use as-is; `--review` overrides `review_mode`. No block → defaults in `.claude/docs/config-resolution.md`. @@ -67,8 +69,6 @@ This is the same rule as the skipped-check reporting elsewhere in this file: **a indistinguishable, to the person reading the output, from one that was never enforced.** -**Director gate skip rule**: Before spawning any Tier 1 director or lead for review (outside of PHASE-GATE triggers), apply the resolved mode: skip if solo mode; skip if lean mode and this is not a PHASE-GATE. - ## Team Composition - **performance-analyst** — Profiling, memory analysis, frame budget, and the optimisation list — it writes no game code - **engine-programmer** — Implements the optimisation list's engine-level items: rendering pipeline, memory, resource loading, hot paths (invoke when performance-analyst identifies low-level root causes) @@ -234,7 +234,7 @@ A summary report covering: performance before/after metrics, visual polish chang ## Next Steps - If READY FOR RELEASE: run `/release-checklist` for the final pre-release validation. -- If NEEDS MORE WORK: schedule remaining issues in `/sprint-plan update` and re-run `/team-polish` after fixes. +- If NEEDS MORE WORK: schedule remaining issues in `/sprint-plan update` (at `workflow: minimal`, which has no sprints, add them to the brief's build order) and re-run `/team-polish` after fixes. - If NOT ASSESSED: supply what was missing — commit the unset `performance.*` budgets in `project.yaml` (`/settings`), or run the phases that did not run (raise `team.size`) — then re-run `/team-polish`. Do not treat the area as release-ready. - If the report handed an optimisation list to `/dev-story`: implement those items there, then re-run `/team-polish` to measure the gain. - Run `/gate-check` for a formal phase gate verdict before handing off to release. diff --git a/.claude/skills/team-qa/SKILL.md b/.claude/skills/team-qa/SKILL.md index 0d7d3acb..38ebbb2b 100644 --- a/.claude/skills/team-qa/SKILL.md +++ b/.claude/skills/team-qa/SKILL.md @@ -7,6 +7,8 @@ allowed-tools: Read, Glob, Grep, Write, Agent, AskUserQuestion, Bash(bash "*/.cl model: sonnet --- +# Team QA + When this skill is invoked, orchestrate the QA team through a structured testing cycle. **Decision Points:** At each phase transition, use `AskUserQuestion` to present diff --git a/.claude/skills/team-release/SKILL.md b/.claude/skills/team-release/SKILL.md index e040f46d..d46a984c 100644 --- a/.claude/skills/team-release/SKILL.md +++ b/.claude/skills/team-release/SKILL.md @@ -6,6 +6,8 @@ user-invocable: true allowed-tools: Read, Glob, Grep, Write, Edit, Bash, Agent, AskUserQuestion, TaskCreate, TaskGet, TaskList, TaskUpdate, Bash(bash "*/.claude/skills/team-release/../../hooks/yaml-helper.sh" resolve_config *) model: sonnet --- +# Team Release + **Argument check:** If no version number is provided: 1. Read `production/session-state/active.md` and the most recent file in `production/milestones/` (if they exist) to infer the target version. 2. If a version is found: report "No version argument provided — inferred [version] from milestone data. Proceeding." Then confirm with `AskUserQuestion`: "Releasing [version]. Is this correct?" diff --git a/.claude/skills/team-ui/SKILL.md b/.claude/skills/team-ui/SKILL.md index bc53936f..824d50f2 100644 --- a/.claude/skills/team-ui/SKILL.md +++ b/.claude/skills/team-ui/SKILL.md @@ -6,6 +6,8 @@ user-invocable: true allowed-tools: Read, Glob, Grep, Write, Edit, Bash, Agent, AskUserQuestion, TaskCreate, TaskGet, TaskList, TaskUpdate, Bash(bash "*/.claude/skills/team-ui/../../hooks/yaml-helper.sh" resolve_config *) model: sonnet --- +# Team UI + If no argument is provided, output usage guidance and exit without spawning any agents or reading any design files: > Usage: `/team-ui [UI feature description] [--review full|lean|solo]` — describe the screen or UI feature to build (e.g., `inventory screen`, `main menu`, `combat HUD`). Do not use `AskUserQuestion` here; output the guidance directly. @@ -67,8 +69,6 @@ This is the same rule as the skipped-check reporting elsewhere in this file: **a indistinguishable, to the person reading the output, from one that was never enforced.** -**Director gate skip rule**: Before spawning creative-director, art-director, or any other Tier 1/2 director for review (outside of PHASE-GATE triggers), apply the resolved mode: skip if solo mode; skip if lean mode and this is not a PHASE-GATE. - ## Team Composition - **ux-designer** — User flows, wireframes, accessibility, input handling - **ui-programmer** — UI framework, screens, widgets, data binding, implementation diff --git a/.claude/skills/tech-debt/SKILL.md b/.claude/skills/tech-debt/SKILL.md index 22a5c871..2b45d159 100644 --- a/.claude/skills/tech-debt/SKILL.md +++ b/.claude/skills/tech-debt/SKILL.md @@ -7,7 +7,9 @@ allowed-tools: Read, Glob, Grep, Write, Edit, AskUserQuestion, Bash(bash "*/.cla model: sonnet --- -!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys automation` +!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys automation,workflow` + +# Tech Debt @@ -135,7 +137,7 @@ one decimal and written to Priority. Higher scores first; ties go to the older `Added` date. An item whose Impact or Effort is `—` gets no score: list it after the scored items as "not scored — [column] not judged" rather than guessing one. -Re-sort the register by priority score and recommend which items to include in the next sprint. +Re-sort the register by priority score and recommend which items to include in the next sprint (at `workflow: minimal`, which has no sprints, which to build next). Present the re-prioritized register to the user. @@ -167,7 +169,7 @@ Output the report to the user. This mode is read-only — no files are written. ## Phase 3: Next Steps -- Run `/sprint-plan` to schedule high-priority debt items into the next sprint. +- Run `/sprint-plan` to schedule high-priority debt items into the next sprint (at `workflow: minimal`, which has no sprints, add them to the brief's build order instead). - Run `/tech-debt report` at the start of each sprint to track debt trends over time. ### Debt Register Format diff --git a/.claude/skills/test-setup/SKILL.md b/.claude/skills/test-setup/SKILL.md index e779eeb7..8f51e334 100644 --- a/.claude/skills/test-setup/SKILL.md +++ b/.claude/skills/test-setup/SKILL.md @@ -32,560 +32,27 @@ A test framework installed at sprint four costs 3 sprints. ## Phase 1: Detect Engine and Existing State -1. **Read engine config**: - - Read `engine.name` from `project.yaml`; if that key is absent or empty - (including when `project.yaml` has no `engine:` block), fall back to the - `Engine:` value in `.claude/docs/technical-preferences.md`. - - If neither source yields a configured engine (project.yaml `engine.name` - absent/empty and technical-preferences.md shows `[TO BE CONFIGURED]` or is - missing), stop: - "Engine not configured. Run `/setup-engine` first, then re-run `/test-setup`." - -2. **Check for existing test infrastructure**: - - Glob `tests/` — does the directory exist? - - Glob `tests/unit/` and `tests/integration/` — do subdirectories exist? - - Glob `.github/workflows/` — does a CI workflow file exist? - - Glob `addons/gdUnit4/bin/GdUnitCmdTool.gd` (Godot — note the capital U) or - `Assets/Tests/EditMode/` (Unity) or `Source/*/Private/Tests/` (Unreal) for - engine-specific artifacts. These are the **test roots** in - `.claude/docs/directory-structure.md`; tests anywhere else are never compiled - on Unity or Unreal. - -3. **Report findings**: - - "Engine: [engine]. Test directory: [found / not found]. CI workflow: [found / not found]." - - If everything already exists AND `force` argument was not passed: - "Test infrastructure appears to be in place. Re-run with `/test-setup force` - to regenerate. Proceeding will not overwrite existing test files." - -If the `force` argument is passed, skip the "already exists" early-exit and -proceed — but still do not overwrite files that already exist at a given path. -Only create files that are missing. - ---- +**Read `references/1-detect.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 2: Present Plan -Based on the engine detected and the existing state, present a plan: - -``` -## Test Setup Plan — [Engine] - -I will create the following (skipping any that already exist): - -tests/ - unit/ — Isolated unit tests for formulas, state, and logic (Godot only) - integration/ — Cross-system tests and save/load round-trips (Godot only) - smoke/ — Critical path test list (15-minute manual gate) - README.md — Test framework documentation - -[Unity/Unreal: unit and integration tests go under the engine's test root - instead — Unity Assets/Tests/EditMode|PlayMode/, Unreal - Source//Private/Tests/ — because neither compiles code in tests/] - -production/qa/ - evidence/ — Screenshot and manual test sign-off records - -[Engine-specific files — see per-engine details below] - -.github/workflows/tests.yml — CI: run tests on every push to main - -Estimated time: ~5 minutes to create all files. -``` - -Ask: "May I create these files? I will not overwrite any test files that -already exist at these paths." - -**At `collaborative` and `guided`** — do not proceed without approval. These are -**new** files, and `automation-modes.md:81` gates new-file writes in `guided` too, -so the answer is the same in both modes. **At `autonomous`** — create them and log -the decision; do not block. An unconditional gate here would read as "block even -in autonomous" and contradict this skill's own header. - ---- +**Read `references/2-plan.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 3: Create Directory Structure -After approval, create the following files: - -### `tests/README.md` - -````markdown -# Test Infrastructure - -**Engine**: [engine name + version] -**Test Framework**: [GdUnit4 | Unity Test Framework | UE Automation] -**CI**: `.github/workflows/tests.yml` -**Setup date**: [date] - -## Directory Layout - -``` -tests/ - unit/ # Isolated unit tests (formulas, state machines, logic) - integration/ # Cross-system and save/load tests - smoke/ # Critical path test list for /smoke-check gate -``` - -[Unity/Unreal — replace the unit/integration lines: unit and integration tests -live under the engine's test root, `Assets/Tests/EditMode|PlayMode/[System]/` -or `Source//Private/Tests/[System]/`; `tests/` keeps this README and -`smoke/`. Every `tests/unit/` path below means that test root.] - -``` -production/qa/ - evidence/ # Screenshot logs and manual test sign-off records -``` - -> **Manual evidence lives under `production/qa/evidence/`, not `tests/`** — that -> is where every consumer reads it. - -## Running Tests - -[Engine-specific command — see below] - -## Test Naming - -Names follow the engine's language (`.claude/rules/test-standards.md`): -- **Godot**: file `[system]_[feature]_test.gd`, function `test_[scenario]_[expected]` - — `combat_damage_test.gd` → `test_base_attack_returns_expected_damage()` -- **Unity**: class `[System]Tests` in `[System]Tests.cs`, method `[Scenario]_[Expected]` - — `CombatTests.cs` → `BaseAttack_ReturnsExpectedDamage()` -- **Unreal**: class `F[System][Scenario]Test`, test name `.[System].[Scenario]` - — `FCombatBaseAttackTest` → `.Combat.BaseAttack` - [`` is the root the filter in `commands.test` uses — write it out: - the project name, or the distinct root `/setup-engine` chose] - -## Story Type → Test Evidence - -| Story Type | Required Evidence | Location | -|---|---|---| -| Logic | Automated unit test — must pass | `tests/unit/[system]/` | -| Integration | Integration test OR playtest doc | `tests/integration/[system]/` | -| Visual/Feel | Screenshot + lead sign-off | `production/qa/evidence/` | -| UI | Retained screenshot of each screen touched | `production/qa/evidence/` | -| Config/Data | Smoke check pass | `production/qa/smoke-*.md` | - -## CI - -Tests run automatically on every push to `main` and on every pull request. -A failed test suite blocks merging. -```` - -The README and this skill's completion summary name the same evidence path — -`production/qa/evidence/` is where `/smoke-check`, `/test-evidence-review`, -`/qa-plan` and the evidence table in `.claude/docs/coding-standards.md` read, -so a `tests/evidence/` would be a directory nothing reads. - -### `production/qa/evidence/.gitkeep` - -Create it empty. Git does not keep an empty directory, and this is where -`/story-done`, `/smoke-check` and `/test-evidence-review` look for screenshots and -sign-off records — the completion summary lists it, so it must exist. - -### Engine-specific files - -#### Godot 4 (`Engine: Godot`) - -**Do not write a runner script.** gdUnit4 ships its own command-line runner, -`res://addons/gdUnit4/bin/GdUnitCmdTool.gd`. The command CI, `/smoke-check` -and `commands.test` use is: - -```bash -godot --headless --path . --import -godot --headless -s -d --remote-debug tcp://127.0.0.1:0 res://addons/gdUnit4/bin/GdUnitCmdTool.gd -a res://tests --ignoreHeadlessMode -``` - -Run the import first. A fresh clone has no `.godot/` class cache, and a run -without one exits **1** — `GdUnitCmdTool.gd` did not load (`Failed to load -script`), so no test ran. A cache older than a new `class_name` fails valid -code with 105. The CI action imports on its own. - -Exit code **0** when every test passes and **100** when any fails — verified -on Godot 4.6.1 with gdUnit4 6.1.3. **101** means every test passed but a test -leaked nodes: a warning, not a failure. 103 and 104 mean gdUnit4 could not run -(headless refused, Godot older than 4.3); 105 means a test script does not parse. `-a res://tests` runs every suite -under `tests/`; `--ignoreHeadlessMode` is required because gdUnit4 otherwise -refuses to run headless. `--remote-debug tcp://127.0.0.1:0` is required too — -it is what gdUnit4's own `runtest` script passes. Without it a script error -opens Godot's interactive debugger, and the run waits at a `debug>` prompt -forever instead of exiting 105. The flag makes every run print two `ERROR:` -lines about the remote port (`127.0.0.1:0`); they are expected, not a failure. -A run that finds no tests prints `No test cases found` and exits 0 — that is -not a pass. The folder is `addons/gdUnit4/` with a **capital U**. - -Create `tests/unit/.gdignore_placeholder` with content: -`# Unit tests go here — one subdirectory per system (e.g., tests/unit/combat/)` - -Create `tests/integration/.gdignore_placeholder` with content: -`# Integration tests go here — one subdirectory per system` - -Note in the README: **Installing GdUnit4** -``` -1. Open Godot → AssetLib → search "GdUnit4" → Download & Install -2. Enable the plugin: Project → Project Settings → Plugins → GdUnit4 ✓ -3. Restart the editor -4. Verify: res://addons/gdUnit4/bin/GdUnitCmdTool.gd exists (capital U) -``` - -#### Unity (`Engine: Unity`) - -Tests live under **`Assets/Tests/`** — Unity compiles only `Assets/` and -`Packages/`. A test under `tests/` is never compiled, and the run then reports -**0 tests, `Passed`, exit 0** (verified on 6000.3.23f1): a false pass. - -First check the Test Framework package: -`grep -q 'com.unity.test-framework' Packages/manifest.json`. Without it -`-runTests` does not fail — it hangs. If absent, ask to add -`"com.unity.test-framework"` to `dependencies` at the version your editor -bundles. Unity 6 releases bundle different ones — 1.6.0 in 6000.3.23f1, 1.5.1 in -6000.1.0f1 — so read it rather than copy a number: on Windows it is the -`version` in `Data/Resources/PackageManager/BuiltInPackages/com.unity.test-framework/package.json` -under the folder that holds `Unity.exe`. - -Create `Assets/Tests/EditMode/EditModeTests.asmdef` — unit tests, no Play Mode: -```json -{ - "name": "EditModeTests", - "references": ["UnityEngine.TestRunner", "UnityEditor.TestRunner"], - "includePlatforms": ["Editor"], - "overrideReferences": true, - "precompiledReferences": ["nunit.framework.dll"], - "autoReferenced": false, - "defineConstraints": ["UNITY_INCLUDE_TESTS"] -} -``` - -Create `Assets/Tests/PlayMode/PlayModeTests.asmdef` — integration tests in a -running scene: the same JSON with `"name": "PlayModeTests"` and -`"includePlatforms": []`. - -> **A test assembly cannot see code in the default `Assembly-CSharp`.** An -> `.asmdef` can reference only other `.asmdef`s. If the game's scripts have no -> `.asmdef` of their own, ask before creating one (e.g. `Assets/Scripts/Game.asmdef`) -> and add `"Game"` to both test assemblies' `references`. Without it the first -> test that names a game class fails to compile. Moving scripts into an -> `.asmdef` changes what they can see, so before creating it: -> -> - **List the packages the scripts use.** `Assembly-CSharp` references every -> package on its own; an `.asmdef` references only what it names. Read the -> scripts' `using` lines and add the matching assemblies — commonly -> `"Unity.InputSystem"`, `"Unity.TextMeshPro"`, `"UnityEngine.UI"`: -> `{ "name": "Game", "references": ["Unity.InputSystem", "Unity.TextMeshPro"] }`. -> Name only packages the project has installed. -> - **Give each `Editor/` folder under it its own `.asmdef`** with -> `"includePlatforms": ["Editor"]` and `"references": ["Game"]`. Otherwise -> editor scripts join the runtime assembly, and `using UnityEditor;` breaks the -> player build. - -Note in the README: **Running Unity tests** (use the editor executable — -`Unity` on `PATH` may be Unity's separate CLI, not the editor) -``` -"" -batchmode -runTests -projectPath . -testPlatform EditMode -testResults test-results/editmode.xml -"" -batchmode -runTests -projectPath . -testPlatform PlayMode -testResults test-results/playmode.xml -``` -Exit **0** when every test passes, **2** when any fails. Exit 1 or 3 is a FAIL -too: 1 is a compile error, which writes no results file, and 3 a failed run. -So is 4 (an unknown `-testPlatform`), and any other non-zero exit. -Delete `test-results/editmode.xml` before each run so an old file is never read -as a new result. Read the `` -element of the results file: `testcasecount="0"` means nothing was compiled or -found — report it as not assessed, never as a pass. Do not add `-quit`; -`-runTests` exits by itself. Play Mode is the second line: a separate run with -its own results file, read the same way, and deleted before each run the same -way. An Edit Mode run never runs the tests in `Assets/Tests/PlayMode/`, so -`/smoke-check` runs both whenever that folder holds tests. - -#### Unreal Engine (`Engine: Unreal` or `Engine: UE5`) - -Tests live **inside the game module**: `Source//Private/Tests/`, where -`` is the primary game module (for a C++ project, the `.uproject` name). -UnrealBuildTool compiles only module folders — a tests folder directly under -`Source/` is not a module, so a test there is silently never built and every -run reports `No automation tests matched`. - -Create `Source//Private/Tests/README.md`. `.` in it — and -`[ProjectName].` in the CI filter below — is the test root the filter in -`commands.test` uses: the project name, or the distinct root `/setup-engine` -chose when the project's name is also an engine area. Write that root: -```markdown -# Unreal Automation Tests -Tests use the UE Automation Testing Framework and compile with this module. -Wrap each test file in `#if WITH_DEV_AUTOMATION_TESTS` … `#endif`. -Flags: `EAutomationTestFlags::EditorContext | EAutomationTestFlags::ProductFilter` -(there is no `GameFilter` flag). - -Run via: Session Frontend → Automation → select "." tests -Or headlessly from the project root, after building the editor target — on a -fresh checkout the editor exits before any test runs: -"/Engine/Binaries/DotNET/UnrealBuildTool/UnrealBuildTool.exe" Editor Win64 Development -Project="$(pwd -W 2>/dev/null || pwd)/.uproject" -"/Engine/Binaries/Win64/UnrealEditor-Cmd.exe" "$(pwd -W 2>/dev/null || pwd)/.uproject" -ExecCmds="Automation RunTests .; Quit" -unattended -nullrhi -stdout -FullStdOutLogOutput -The project path must be absolute: UE does not find a relative one (exit 1, -"Project file not found"). Those two lines are Windows'. On Linux build with -`Engine/Build/BatchFiles/Linux/Build.sh Editor Linux Development -Project="$(pwd -W 2>/dev/null || pwd)/.uproject"` and run -the tests with `Engine/Binaries/Linux/UnrealEditor` and the same arguments; on -macOS build with `Engine/Build/BatchFiles/Mac/Build.sh Editor Mac Development -Project="$(pwd -W 2>/dev/null || pwd)/.uproject"` -— Epic documents no command-line editor inside `UnrealEditor.app` for the test -run (see `docs/engine-reference/unreal/current-best-practices.md`, "Command Line"). - -Read the output, not the exit code: a failing test and a run that matched nothing both exit 255. -`Result={Fail}` is a failure; `No automation tests matched` means no test was -built or named `.…`. - -Test class naming: F[System][Scenario]Test — one class per test; a second -test reusing a class name fails to link -Test name: ".[System].[Scenario]" -``` - ---- +**Read `references/3-directories.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 4: Create CI/CD Workflow -### Godot 4 - -Create `.github/workflows/tests.yml`: - -```yaml -name: Automated Tests - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - test: - name: Run GdUnit4 Tests - runs-on: ubuntu-latest - # The action publishes its results as a check run. A new repository's - # token is read-only, and without checks: write the job fails even when - # every test passes. If you protect main, require the `Run GdUnit4 Tests` job - # check, not `test-results`: that check run concludes success even when a - # test fails. - permissions: - contents: read - checks: write - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - lfs: true - - # godot-version must be a full release such as 4.6.1 (`godot --version` - # shows it); VERSION.md's "4.6" is not one. version: installed runs the - # gdUnit4 committed in addons/ -- without it the action deletes that - # copy and installs the latest release, which may not match your tests. - - name: Run GdUnit4 Tests - uses: godot-gdunit-labs/gdUnit4-action@v1 - with: - godot-version: '[FULL GODOT VERSION, e.g. 4.6.1]' - version: 'installed' - paths: | - tests/unit - tests/integration - report-name: test-results - - - name: Upload Test Results - if: always() - uses: actions/upload-artifact@v4 - with: - name: test-results - path: reports/ -``` - -### Unity - -Create `.github/workflows/tests.yml`: - -```yaml -name: Automated Tests - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - test: - name: Run Unity Tests - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - lfs: true - - - name: Run Edit Mode Tests - uses: game-ci/unity-test-runner@v4 - env: - UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} - with: - testMode: editmode - artifactsPath: test-results/editmode - - - name: Run Play Mode Tests - uses: game-ci/unity-test-runner@v4 - env: - UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} - with: - testMode: playmode - artifactsPath: test-results/playmode - - - name: Upload Test Results - if: always() - uses: actions/upload-artifact@v4 - with: - name: test-results - path: test-results/ -``` - -Note: Unity CI requires a `UNITY_LICENSE` secret. Add to GitHub repository -secrets before the first CI run. - -### Unreal Engine - -Create `.github/workflows/tests.yml`: - -```yaml -name: Automated Tests - -on: - push: - branches: [main] - pull_request: - branches: [main] - -jobs: - test: - name: Run UE Automation Tests - runs-on: [self-hosted, windows] # UE requires a local runner with the editor installed - - # The quoted "{0}" in each `shell:` below: the Windows runner passes bash - # its script path unquoted, so with plain `shell: bash` every step fails - # ("No such file or directory") when the runner's folder has a space. - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - lfs: true - - # Binaries/ is gitignored, so a fresh checkout has no compiled game - # module: without this step the editor stops with "The game module could - # not be found" before running any test. UnrealBuildTool.exe, not - # Build.bat -- from bash, Build.bat fails on an engine path with spaces. - - name: Build Editor Target - run: | - "$UE_ROOT/Engine/Binaries/DotNET/UnrealBuildTool/UnrealBuildTool.exe" [ProjectName]Editor Win64 Development \ - -Project="${{ github.workspace }}/[ProjectName].uproject" - shell: bash --noprofile --norc -eo pipefail "{0}" - - # -stdout -FullStdOutLogOutput: without them the editor prints nothing - # here, and the results are only in Saved/Logs/. - - name: Run Automation Tests - run: | - "$UE_ROOT/Engine/Binaries/Win64/UnrealEditor-Cmd.exe" "${{ github.workspace }}/[ProjectName].uproject" \ - -nullrhi -nosound \ - -ExecCmds="Automation RunTests [ProjectName].; Quit" \ - -unattended -stdout -FullStdOutLogOutput - shell: bash --noprofile --norc -eo pipefail "{0}" - - - name: Upload Logs - if: always() - uses: actions/upload-artifact@v4 - with: - name: test-logs - path: Saved/Logs/ -``` - -Note: UE CI requires a self-hosted Windows runner with Unreal Editor installed. -The `windows` label keeps the job off any Linux self-hosted runner the -repository also has. Set the `UE_ROOT` environment variable on the runner to the engine folder -(e.g. `C:/Program Files/Epic Games/UE_5.7`). `[ProjectName]Editor` is the -editor target in `Source/[ProjectName]Editor.Target.cs`. - ---- +**Read `references/4-ci.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 5: Create Smoke Test Seed -Create `tests/smoke/critical-paths.md`: - -```markdown -# Smoke Test: Critical Paths - -**Purpose**: Run these 10-15 checks in under 15 minutes before any QA hand-off. -**Run via**: `/smoke-check` (which reads this file) -**Update**: Add new entries when new core systems are implemented. - -## Core Stability (always run) - -1. Game launches to main menu without crash -2. New game / session can be started from the main menu -3. Main menu responds to all inputs without freezing - -## Core Mechanic (update per sprint) - - - -4. [Primary mechanic — update when first core system is implemented] - -## Data Integrity - -5. Save game completes without error (once save system is implemented) -6. Load game restores correct state (once load system is implemented) - -## Performance - -7. No visible frame rate drops on target hardware (60fps target) -8. No memory growth over 5 minutes of play (once core loop is implemented) -``` - ---- +**Read `references/5-smoke-seed.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Phase 6: Post-Setup Summary -After writing all files, report: - -``` -Test infrastructure created for [engine]. - -Files created: -- tests/README.md -- tests/unit/ and tests/integration/ (Godot) — or the engine's test root: - Unity Assets/Tests/EditMode/ and PlayMode/, Unreal Source//Private/Tests/ -- tests/smoke/critical-paths.md -- production/qa/evidence/.gitkeep -[engine-specific files] -- .github/workflows/tests.yml - -Next steps: -1. [Engine-specific install step, e.g., "Install GdUnit4 via AssetLib"] -2. Write your first test in the engine's test root: - tests/unit/[system]/[system]_[feature]_test.gd (Godot), - Assets/Tests/EditMode/[System]Tests.cs (Unity), or - Source//Private/Tests/[System]Test.cpp (Unreal) -3. Run `/qa-plan sprint` before your first sprint to classify stories and set - test evidence requirements. At `workflow: minimal` — the default — skip - this: there are no sprints. At `qa.level: minimal`, also the default, tests - are waived, so `/dev-story` writes none. Raise `qa.level` with `/settings` - to have it write them -4. `/smoke-check` before every QA hand-off - -Gate note: /gate-check Technical Setup → Pre-Production now requires: -- the engine's test root: tests/unit/ and tests/integration/ (Godot), - Assets/Tests/EditMode/ and Assets/Tests/PlayMode/ (Unity), or - Source//Private/Tests/ (Unreal) -- .github/workflows/tests.yml -- At least one example test file -Run /test-setup and write one example test before advancing. -(At `workflow: minimal` that gate requires only the engine.) - -Verdict: **COMPLETE** — test framework scaffolded and CI/CD wired up. -``` - ---- +**Read `references/6-summary.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## Collaborative Protocol diff --git a/.claude/skills/test-setup/references/1-detect.md b/.claude/skills/test-setup/references/1-detect.md new file mode 100644 index 00000000..4ae839f0 --- /dev/null +++ b/.claude/skills/test-setup/references/1-detect.md @@ -0,0 +1,37 @@ +# /test-setup — Phase 1: Detect Engine and Existing State + +> Part of `/test-setup`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 1: Detect Engine and Existing State + +1. **Read engine config**: + - Read `engine.name` from `project.yaml`; if that key is absent or empty + (including when `project.yaml` has no `engine:` block), fall back to the + `Engine:` value in `.claude/docs/technical-preferences.md`. + - If neither source yields a configured engine (project.yaml `engine.name` + absent/empty and technical-preferences.md shows `[TO BE CONFIGURED]` or is + missing), stop: + "Engine not configured. Run `/setup-engine` first, then re-run `/test-setup`." + +2. **Check for existing test infrastructure**: + - Glob `tests/` — does the directory exist? + - Glob `tests/unit/` and `tests/integration/` — do subdirectories exist? + - Glob `.github/workflows/` — does a CI workflow file exist? + - Glob `addons/gdUnit4/bin/GdUnitCmdTool.gd` (Godot — note the capital U) or + `Assets/Tests/EditMode/` (Unity) or `Source/*/Private/Tests/` (Unreal) for + engine-specific artifacts. These are the **test roots** in + `.claude/docs/directory-structure.md`; tests anywhere else are never compiled + on Unity or Unreal. + +3. **Report findings**: + - "Engine: [engine]. Test directory: [found / not found]. CI workflow: [found / not found]." + - If everything already exists AND `force` argument was not passed: + "Test infrastructure appears to be in place. Re-run with `/test-setup force` + to regenerate. Proceeding will not overwrite existing test files." + +If the `force` argument is passed, skip the "already exists" early-exit and +proceed — but still do not overwrite files that already exist at a given path. +Only create files that are missing. + +--- diff --git a/.claude/skills/test-setup/references/2-plan.md b/.claude/skills/test-setup/references/2-plan.md new file mode 100644 index 00000000..98c5f167 --- /dev/null +++ b/.claude/skills/test-setup/references/2-plan.md @@ -0,0 +1,44 @@ +# /test-setup — Phase 2: Present Plan + +> Part of `/test-setup`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 2: Present Plan + +Based on the engine detected and the existing state, present a plan: + +``` +## Test Setup Plan — [Engine] + +I will create the following (skipping any that already exist): + +tests/ + unit/ — Isolated unit tests for formulas, state, and logic (Godot only) + integration/ — Cross-system tests and save/load round-trips (Godot only) + smoke/ — Critical path test list (15-minute manual gate) + README.md — Test framework documentation + +[Unity/Unreal: unit and integration tests go under the engine's test root + instead — Unity Assets/Tests/EditMode|PlayMode/, Unreal + Source//Private/Tests/ — because neither compiles code in tests/] + +production/qa/ + evidence/ — Screenshot and manual test sign-off records + +[Engine-specific files — see per-engine details below] + +.github/workflows/tests.yml — CI: run tests on every push to main + +Estimated time: ~5 minutes to create all files. +``` + +Ask: "May I create these files? I will not overwrite any test files that +already exist at these paths." + +**At `collaborative` and `guided`** — do not proceed without approval. These are +**new** files, and `automation-modes.md:81` gates new-file writes in `guided` too, +so the answer is the same in both modes. **At `autonomous`** — create them and log +the decision; do not block. An unconditional gate here would read as "block even +in autonomous" and contradict this skill's own header. + +--- diff --git a/.claude/skills/test-setup/references/3-directories.md b/.claude/skills/test-setup/references/3-directories.md new file mode 100644 index 00000000..20441758 --- /dev/null +++ b/.claude/skills/test-setup/references/3-directories.md @@ -0,0 +1,245 @@ +# /test-setup — Phase 3: Create Directory Structure + +> Part of `/test-setup`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 3: Create Directory Structure + +**In this file:** + +- `tests/README.md` +- `production/qa/evidence/.gitkeep` +- Engine-specific files + +After approval, create the following files: + +### `tests/README.md` + +````markdown +# Test Infrastructure + +**Engine**: [engine name + version] +**Test Framework**: [GdUnit4 | Unity Test Framework | UE Automation] +**CI**: `.github/workflows/tests.yml` +**Setup date**: [date] + +## Directory Layout + +``` +tests/ + unit/ # Isolated unit tests (formulas, state machines, logic) + integration/ # Cross-system and save/load tests + smoke/ # Critical path test list for /smoke-check gate +``` + +[Unity/Unreal — replace the unit/integration lines: unit and integration tests +live under the engine's test root, `Assets/Tests/EditMode|PlayMode/[System]/` +or `Source//Private/Tests/[System]/`; `tests/` keeps this README and +`smoke/`. Every `tests/unit/` path below means that test root.] + +``` +production/qa/ + evidence/ # Screenshot logs and manual test sign-off records +``` + +> **Manual evidence lives under `production/qa/evidence/`, not `tests/`** — that +> is where every consumer reads it. + +## Running Tests + +[Engine-specific command — see below] + +## Test Naming + +Names follow the engine's language (`.claude/rules/test-standards.md`): +- **Godot**: file `[system]_[feature]_test.gd`, function `test_[scenario]_[expected]` + — `combat_damage_test.gd` → `test_base_attack_returns_expected_damage()` +- **Unity**: class `[System]Tests` in `[System]Tests.cs`, method `[Scenario]_[Expected]` + — `CombatTests.cs` → `BaseAttack_ReturnsExpectedDamage()` +- **Unreal**: class `F[System][Scenario]Test`, test name `.[System].[Scenario]` + — `FCombatBaseAttackTest` → `.Combat.BaseAttack` + [`` is the root the filter in `commands.test` uses — write it out: + the project name, or the distinct root `/setup-engine` chose] + +## Story Type → Test Evidence + +| Story Type | Required Evidence | Location | +|---|---|---| +| Logic | Automated unit test — must pass | `tests/unit/[system]/` | +| Integration | Integration test OR playtest doc | `tests/integration/[system]/` | +| Visual/Feel | Screenshot + lead sign-off | `production/qa/evidence/` | +| UI | Retained screenshot of each screen touched | `production/qa/evidence/` | +| Config/Data | Smoke check pass | `production/qa/smoke-*.md` | + +## CI + +Tests run automatically on every push to `main` and on every pull request. +A failed test suite blocks merging. +```` + +The README and this skill's completion summary name the same evidence path — +`production/qa/evidence/` is where `/smoke-check`, `/test-evidence-review`, +`/qa-plan` and the evidence table in `.claude/docs/coding-standards.md` read, +so a `tests/evidence/` would be a directory nothing reads. + +### `production/qa/evidence/.gitkeep` + +Create it empty. Git does not keep an empty directory, and this is where +`/story-done`, `/smoke-check` and `/test-evidence-review` look for screenshots and +sign-off records — the completion summary lists it, so it must exist. + +### Engine-specific files + +#### Godot 4 (`Engine: Godot`) + +**Do not write a runner script.** gdUnit4 ships its own command-line runner, +`res://addons/gdUnit4/bin/GdUnitCmdTool.gd`. The command CI, `/smoke-check` +and `commands.test` use is: + +```bash +godot --headless --path . --import +godot --headless -s -d --remote-debug tcp://127.0.0.1:0 res://addons/gdUnit4/bin/GdUnitCmdTool.gd -a res://tests --ignoreHeadlessMode +``` + +Run the import first. A fresh clone has no `.godot/` class cache, and a run +without one exits **1** — `GdUnitCmdTool.gd` did not load (`Failed to load +script`), so no test ran. A cache older than a new `class_name` fails valid +code with 105. The CI action imports on its own. + +Exit code **0** when every test passes and **100** when any fails — verified +on Godot 4.6.1 with gdUnit4 6.1.3. **101** means every test passed but a test +leaked nodes: a warning, not a failure. 103 and 104 mean gdUnit4 could not run +(headless refused, Godot older than 4.3); 105 means a test script does not parse. `-a res://tests` runs every suite +under `tests/`; `--ignoreHeadlessMode` is required because gdUnit4 otherwise +refuses to run headless. `--remote-debug tcp://127.0.0.1:0` is required too — +it is what gdUnit4's own `runtest` script passes. Without it a script error +opens Godot's interactive debugger, and the run waits at a `debug>` prompt +forever instead of exiting 105. The flag makes every run print two `ERROR:` +lines about the remote port (`127.0.0.1:0`); they are expected, not a failure. +A run that finds no tests prints `No test cases found` and exits 0 — that is +not a pass. The folder is `addons/gdUnit4/` with a **capital U**. + +Create `tests/unit/.gdignore_placeholder` with content: +`# Unit tests go here — one subdirectory per system (e.g., tests/unit/combat/)` + +Create `tests/integration/.gdignore_placeholder` with content: +`# Integration tests go here — one subdirectory per system` + +Note in the README: **Installing GdUnit4** +``` +1. Open Godot → AssetLib → search "GdUnit4" → Download & Install +2. Enable the plugin: Project → Project Settings → Plugins → GdUnit4 ✓ +3. Restart the editor +4. Verify: res://addons/gdUnit4/bin/GdUnitCmdTool.gd exists (capital U) +``` + +#### Unity (`Engine: Unity`) + +Tests live under **`Assets/Tests/`** — Unity compiles only `Assets/` and +`Packages/`. A test under `tests/` is never compiled, and the run then reports +**0 tests, `Passed`, exit 0** (verified on 6000.3.23f1): a false pass. + +First check the Test Framework package: +`grep -q 'com.unity.test-framework' Packages/manifest.json`. Without it +`-runTests` does not fail — it hangs. If absent, ask to add +`"com.unity.test-framework"` to `dependencies` at the version your editor +bundles. Unity 6 releases bundle different ones — 1.6.0 in 6000.3.23f1, 1.5.1 in +6000.1.0f1 — so read it rather than copy a number: on Windows it is the +`version` in `Data/Resources/PackageManager/BuiltInPackages/com.unity.test-framework/package.json` +under the folder that holds `Unity.exe`. + +Create `Assets/Tests/EditMode/EditModeTests.asmdef` — unit tests, no Play Mode: +```json +{ + "name": "EditModeTests", + "references": ["UnityEngine.TestRunner", "UnityEditor.TestRunner"], + "includePlatforms": ["Editor"], + "overrideReferences": true, + "precompiledReferences": ["nunit.framework.dll"], + "autoReferenced": false, + "defineConstraints": ["UNITY_INCLUDE_TESTS"] +} +``` + +Create `Assets/Tests/PlayMode/PlayModeTests.asmdef` — integration tests in a +running scene: the same JSON with `"name": "PlayModeTests"` and +`"includePlatforms": []`. + +> **A test assembly cannot see code in the default `Assembly-CSharp`.** An +> `.asmdef` can reference only other `.asmdef`s. If the game's scripts have no +> `.asmdef` of their own, ask before creating one (e.g. `Assets/Scripts/Game.asmdef`) +> and add `"Game"` to both test assemblies' `references`. Without it the first +> test that names a game class fails to compile. Moving scripts into an +> `.asmdef` changes what they can see, so before creating it: +> +> - **List the packages the scripts use.** `Assembly-CSharp` references every +> package on its own; an `.asmdef` references only what it names. Read the +> scripts' `using` lines and add the matching assemblies — commonly +> `"Unity.InputSystem"`, `"Unity.TextMeshPro"`, `"UnityEngine.UI"`: +> `{ "name": "Game", "references": ["Unity.InputSystem", "Unity.TextMeshPro"] }`. +> Name only packages the project has installed. +> - **Give each `Editor/` folder under it its own `.asmdef`** with +> `"includePlatforms": ["Editor"]` and `"references": ["Game"]`. Otherwise +> editor scripts join the runtime assembly, and `using UnityEditor;` breaks the +> player build. + +Note in the README: **Running Unity tests** (use the editor executable — +`Unity` on `PATH` may be Unity's separate CLI, not the editor) +``` +"" -batchmode -runTests -projectPath . -testPlatform EditMode -testResults test-results/editmode.xml +"" -batchmode -runTests -projectPath . -testPlatform PlayMode -testResults test-results/playmode.xml +``` +Exit **0** when every test passes, **2** when any fails. Exit 1 or 3 is a FAIL +too: 1 is a compile error, which writes no results file, and 3 a failed run. +So is 4 (an unknown `-testPlatform`), and any other non-zero exit. +Delete `test-results/editmode.xml` before each run so an old file is never read +as a new result. Read the `` +element of the results file: `testcasecount="0"` means nothing was compiled or +found — report it as not assessed, never as a pass. Do not add `-quit`; +`-runTests` exits by itself. Play Mode is the second line: a separate run with +its own results file, read the same way, and deleted before each run the same +way. An Edit Mode run never runs the tests in `Assets/Tests/PlayMode/`, so +`/smoke-check` runs both whenever that folder holds tests. + +#### Unreal Engine (`Engine: Unreal` or `Engine: UE5`) + +Tests live **inside the game module**: `Source//Private/Tests/`, where +`` is the primary game module (for a C++ project, the `.uproject` name). +UnrealBuildTool compiles only module folders — a tests folder directly under +`Source/` is not a module, so a test there is silently never built and every +run reports `No automation tests matched`. + +Create `Source//Private/Tests/README.md`. `.` in it — and +`[ProjectName].` in the CI filter below — is the test root the filter in +`commands.test` uses: the project name, or the distinct root `/setup-engine` +chose when the project's name is also an engine area. Write that root: +```markdown +# Unreal Automation Tests +Tests use the UE Automation Testing Framework and compile with this module. +Wrap each test file in `#if WITH_DEV_AUTOMATION_TESTS` … `#endif`. +Flags: `EAutomationTestFlags::EditorContext | EAutomationTestFlags::ProductFilter` +(there is no `GameFilter` flag). + +Run via: Session Frontend → Automation → select "." tests +Or headlessly from the project root, after building the editor target — on a +fresh checkout the editor exits before any test runs: +"/Engine/Binaries/DotNET/UnrealBuildTool/UnrealBuildTool.exe" Editor Win64 Development -Project="$(pwd -W 2>/dev/null || pwd)/.uproject" +"/Engine/Binaries/Win64/UnrealEditor-Cmd.exe" "$(pwd -W 2>/dev/null || pwd)/.uproject" -ExecCmds="Automation RunTests .; Quit" -unattended -nullrhi -stdout -FullStdOutLogOutput +The project path must be absolute: UE does not find a relative one (exit 1, +"Project file not found"). Those two lines are Windows'. On Linux build with +`Engine/Build/BatchFiles/Linux/Build.sh Editor Linux Development -Project="$(pwd -W 2>/dev/null || pwd)/.uproject"` and run +the tests with `Engine/Binaries/Linux/UnrealEditor` and the same arguments; on +macOS build with `Engine/Build/BatchFiles/Mac/Build.sh Editor Mac Development -Project="$(pwd -W 2>/dev/null || pwd)/.uproject"` +— Epic documents no command-line editor inside `UnrealEditor.app` for the test +run (see `docs/engine-reference/unreal/current-best-practices.md`, "Command Line"). + +Read the output, not the exit code: a failing test and a run that matched nothing both exit 255. +`Result={Fail}` is a failure; `No automation tests matched` means no test was +built or named `.…`. + +Test class naming: F[System][Scenario]Test — one class per test; a second +test reusing a class name fails to link +Test name: ".[System].[Scenario]" +``` + +--- diff --git a/.claude/skills/test-setup/references/4-ci.md b/.claude/skills/test-setup/references/4-ci.md new file mode 100644 index 00000000..1ae1ac74 --- /dev/null +++ b/.claude/skills/test-setup/references/4-ci.md @@ -0,0 +1,180 @@ +# /test-setup — Phase 4: Create CI/CD Workflow + +> Part of `/test-setup`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 4: Create CI/CD Workflow + +**In this file:** + +- Godot 4 +- Unity +- Unreal Engine + +### Godot 4 + +Create `.github/workflows/tests.yml`: + +```yaml +name: Automated Tests + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + name: Run GdUnit4 Tests + runs-on: ubuntu-latest + # The action publishes its results as a check run. A new repository's + # token is read-only, and without checks: write the job fails even when + # every test passes. If you protect main, require the `Run GdUnit4 Tests` job + # check, not `test-results`: that check run concludes success even when a + # test fails. + permissions: + contents: read + checks: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + lfs: true + + # godot-version must be a full release such as 4.6.1 (`godot --version` + # shows it); VERSION.md's "4.6" is not one. version: installed runs the + # gdUnit4 committed in addons/ -- without it the action deletes that + # copy and installs the latest release, which may not match your tests. + - name: Run GdUnit4 Tests + uses: godot-gdunit-labs/gdUnit4-action@v1 + with: + godot-version: '[FULL GODOT VERSION, e.g. 4.6.1]' + version: 'installed' + paths: | + tests/unit + tests/integration + report-name: test-results + + - name: Upload Test Results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results + path: reports/ +``` + +### Unity + +Create `.github/workflows/tests.yml`: + +```yaml +name: Automated Tests + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + name: Run Unity Tests + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + lfs: true + + - name: Run Edit Mode Tests + uses: game-ci/unity-test-runner@v4 + env: + UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} + with: + testMode: editmode + artifactsPath: test-results/editmode + + - name: Run Play Mode Tests + uses: game-ci/unity-test-runner@v4 + env: + UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} + with: + testMode: playmode + artifactsPath: test-results/playmode + + - name: Upload Test Results + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results + path: test-results/ +``` + +Note: Unity CI requires a `UNITY_LICENSE` secret. Add to GitHub repository +secrets before the first CI run. + +### Unreal Engine + +Create `.github/workflows/tests.yml`: + +```yaml +name: Automated Tests + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + name: Run UE Automation Tests + runs-on: [self-hosted, windows] # UE requires a local runner with the editor installed + + # The quoted "{0}" in each `shell:` below: the Windows runner passes bash + # its script path unquoted, so with plain `shell: bash` every step fails + # ("No such file or directory") when the runner's folder has a space. + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + lfs: true + + # Binaries/ is gitignored, so a fresh checkout has no compiled game + # module: without this step the editor stops with "The game module could + # not be found" before running any test. UnrealBuildTool.exe, not + # Build.bat -- from bash, Build.bat fails on an engine path with spaces. + - name: Build Editor Target + run: | + "$UE_ROOT/Engine/Binaries/DotNET/UnrealBuildTool/UnrealBuildTool.exe" [ProjectName]Editor Win64 Development \ + -Project="${{ github.workspace }}/[ProjectName].uproject" + shell: bash --noprofile --norc -eo pipefail "{0}" + + # -stdout -FullStdOutLogOutput: without them the editor prints nothing + # here, and the results are only in Saved/Logs/. + - name: Run Automation Tests + run: | + "$UE_ROOT/Engine/Binaries/Win64/UnrealEditor-Cmd.exe" "${{ github.workspace }}/[ProjectName].uproject" \ + -nullrhi -nosound \ + -ExecCmds="Automation RunTests [ProjectName].; Quit" \ + -unattended -stdout -FullStdOutLogOutput + shell: bash --noprofile --norc -eo pipefail "{0}" + + - name: Upload Logs + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-logs + path: Saved/Logs/ +``` + +Note: UE CI requires a self-hosted Windows runner with Unreal Editor installed. +The `windows` label keeps the job off any Linux self-hosted runner the +repository also has. Set the `UE_ROOT` environment variable on the runner to the engine folder +(e.g. `C:/Program Files/Epic Games/UE_5.7`). `[ProjectName]Editor` is the +editor target in `Source/[ProjectName]Editor.Target.cs`. + +--- diff --git a/.claude/skills/test-setup/references/5-smoke-seed.md b/.claude/skills/test-setup/references/5-smoke-seed.md new file mode 100644 index 00000000..7a7a2cc6 --- /dev/null +++ b/.claude/skills/test-setup/references/5-smoke-seed.md @@ -0,0 +1,40 @@ +# /test-setup — Phase 5: Create Smoke Test Seed + +> Part of `/test-setup`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 5: Create Smoke Test Seed + +Create `tests/smoke/critical-paths.md`: + +```markdown +# Smoke Test: Critical Paths + +**Purpose**: Run these 10-15 checks in under 15 minutes before any QA hand-off. +**Run via**: `/smoke-check` (which reads this file) +**Update**: Add new entries when new core systems are implemented. + +## Core Stability (always run) + +1. Game launches to main menu without crash +2. New game / session can be started from the main menu +3. Main menu responds to all inputs without freezing + +## Core Mechanic (update per sprint) + + + +4. [Primary mechanic — update when first core system is implemented] + +## Data Integrity + +5. Save game completes without error (once save system is implemented) +6. Load game restores correct state (once load system is implemented) + +## Performance + +7. No visible frame rate drops on target hardware (60fps target) +8. No memory growth over 5 minutes of play (once core loop is implemented) +``` + +--- diff --git a/.claude/skills/test-setup/references/6-summary.md b/.claude/skills/test-setup/references/6-summary.md new file mode 100644 index 00000000..485f8f2e --- /dev/null +++ b/.claude/skills/test-setup/references/6-summary.md @@ -0,0 +1,47 @@ +# /test-setup — Phase 6: Post-Setup Summary + +> Part of `/test-setup`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## Phase 6: Post-Setup Summary + +After writing all files, report: + +``` +Test infrastructure created for [engine]. + +Files created: +- tests/README.md +- tests/unit/ and tests/integration/ (Godot) — or the engine's test root: + Unity Assets/Tests/EditMode/ and PlayMode/, Unreal Source//Private/Tests/ +- tests/smoke/critical-paths.md +- production/qa/evidence/.gitkeep +[engine-specific files] +- .github/workflows/tests.yml + +Next steps: +1. [Engine-specific install step, e.g., "Install GdUnit4 via AssetLib"] +2. Write your first test in the engine's test root: + tests/unit/[system]/[system]_[feature]_test.gd (Godot), + Assets/Tests/EditMode/[System]Tests.cs (Unity), or + Source//Private/Tests/[System]Test.cpp (Unreal) +3. Run `/qa-plan sprint` before your first sprint to classify stories and set + test evidence requirements. At `workflow: minimal` — the default — skip + this: there are no sprints. At `qa.level: minimal`, also the default, tests + are waived, so `/dev-story` writes none. Raise `qa.level` with `/settings` + to have it write them +4. `/smoke-check` before every QA hand-off + +Gate note: /gate-check Technical Setup → Pre-Production now requires: +- the engine's test root: tests/unit/ and tests/integration/ (Godot), + Assets/Tests/EditMode/ and Assets/Tests/PlayMode/ (Unity), or + Source//Private/Tests/ (Unreal) +- .github/workflows/tests.yml +- At least one example test file +Run /test-setup and write one example test before advancing. +(At `workflow: minimal` that gate requires only the engine.) + +Verdict: **COMPLETE** — test framework scaffolded and CI/CD wired up. +``` + +--- diff --git a/.claude/skills/ux-design/SKILL.md b/.claude/skills/ux-design/SKILL.md index dee2a79c..45b48c54 100644 --- a/.claude/skills/ux-design/SKILL.md +++ b/.claude/skills/ux-design/SKILL.md @@ -12,6 +12,7 @@ model: sonnet Resolved above — use as-is. No block → defaults in `.claude/docs/config-resolution.md`. +# UX Design When this skill is invoked: @@ -76,575 +77,15 @@ for the filename (e.g., "Main Menu" becomes `main-menu`). ## 2. Gather Context (Read Phase) -Read all relevant context **before** asking the user anything. The skill's value -comes from arriving informed. - -### 2a: Required Reads - -- **Game concept**: Read `design/gdd/game-concept.md` — or `design/game-brief.md`, - the one-page brief that replaces it at `rigor: minimal` — if neither exists, warn: - > "No game concept found. Run `/brainstorm` first to establish the game's - > foundation before designing UX." - > Continue anyway if the user asks. - -### 2b: Player Journey - -Read `design/player-journey.md` if it exists. For each relevant section, extract: -- Which journey phase(s) does this screen appear in? -- What is the player's emotional state on arrival at this screen? -- What player need is this screen serving in the journey? -- What critical moments (from the journey map) does this screen deliver? - -If the player journey file does not exist, note the gap and proceed: -> "No player journey map found at `design/player-journey.md`. Designing without it -> means we'll be making assumptions about player context. Consider running a player -> journey session after this spec is drafted." - -Also add to the UX spec's Open Questions section: -> "Player journey map not yet created. Author it from the template at `.claude/docs/templates/player-journey.md` to establish player context for this screen." - -> **Do not tell the user to "run `/ux-design` Phase 2b" to create it.** Phase 2b -> is this step — the one that *reads* the file. That remediation is circular: it -> sends the user back to the check that just reported the gap. No skill -> writes `design/player-journey.md`; it is hand-authored from its template. - -### 2c: GDD UI Requirements - -Glob `design/gdd/*.md` and grep for `UI Requirements` sections. Read any GDD whose -UI Requirements section references this screen by name or category. - -These GDD UI Requirements are the **requirements input** to this spec. Collect them -as a list of constraints the spec must satisfy. - -If designing the HUD, you need the UI Requirements of **every** system — the HUD -aggregates them. Collect them with one scan rather than opening each GDD: - -``` -Grep pattern="^#+ .*UI Requirements" glob="design/gdd/*.md" output_mode="content" -A 20 -``` - -Establish the denominator first (glob `design/gdd/*.md`, count **N**) and check -the match count against it. Count system GDDs only: `game-concept.md`, -`systems-index.md`, `game-pillars.md`, `gameplay-tags.md`, `entity-registry.md`, -`fixture-swap-ledger.md`, `sound-bible.md` and any `gdd-cross-review-*.md` live -there too, but they are not systems and have no UI to aggregate. -**A GDD with no UI Requirements section is not a GDD -with no UI needs** — it may predate the section. List the unmatched ones and -confirm with the user that they are genuinely headless before excluding them -from the HUD's requirement set; a HUD that silently omits a system's readout is -the exact failure this aggregation exists to prevent. - -### 2d: Existing UX Specs - -Glob `design/ux/*.md` and note which screens already have specs. For screens that -will link to or from the current screen, read their navigation/flow sections to -find the entry and exit points this spec must match. - -### 2e: Interaction Pattern Library - -If `design/ux/interaction-patterns.md` exists, read the pattern catalog index -(the list of pattern names and their one-line descriptions). Do not read full -pattern details — just the catalog. This tells you which patterns already exist -so you can reference them rather than reinvent them. - -### 2f: Art Bible - -Check for `design/art/art-bible.md`. If found, read the visual direction -section. UX layout must align with the aesthetic commitments already made. - -### 2g: Accessibility Requirements - -Check for `design/accessibility-requirements.md`. If found, read it. The spec -must satisfy the accessibility tier committed to there. - -### 2h: Input Method (from Project Config) - -Read the `platform` block from `project.yaml`; if `project.yaml` has no -`platform` block, fall back to the `## Input & Platform` section of -`.claude/docs/technical-preferences.md`. Store these values for use throughout -the skill — they drive the Interaction Map and inform accessibility -requirements: - -- **Primary Input** — `platform.primary_input` — the dominant input for this game -- **Gamepad Support** — `platform.gamepad_support` — Full / Partial / None -- **Touch Support** — `platform.touch_support` — Full / Partial / None -- **Target Platforms** — `platform.targets` — for safe zone and aspect ratio decisions -- **Input Methods** — the set of supported methods. When reading from - `project.yaml`, derive it: keyboard/mouse if `PC` or `Web` is in `targets`; - gamepad if gamepad support is Full/Partial; touch if touch support is - Full/Partial; plus the primary input. When falling back to - `technical-preferences.md`, use its explicit Input Methods field. - -If neither source is configured, ask once: -> "Input methods aren't configured yet. What does this game target?" -> Options: "Keyboard/Mouse only", "Gamepad only", "Both (PC + Console)", "Touch (mobile)", "All of the above" -> -> (Run `/setup-engine` to save this permanently so you won't be asked again.) - -Store the answer for the rest of this session. Do **not** ask again per section -or per screen. - -### 2i: Present Context Summary - -Before any design work, present a brief summary to the user: - -> **Designing: [Screen/Flow Name]** -> - Mode: [UX Spec / HUD Design / Pattern Library] -> - Journey phase(s): [from player-journey.md, or "unknown — no journey map"] -> - GDD requirements feeding this spec: [count and names, or "none found"] -> - Related screens already specced: [list, or "none yet"] -> - Known patterns available: [count, or "no pattern library yet"] -> - Accessibility tier: [from requirements doc, or "not yet defined"] -> - Input methods: [derived from the `project.yaml` platform block, or "asked above"] - -Then ask: "Anything else I should read before we start, or shall we proceed?" - ---- - -## 2b. Retrofit Mode Detection - -Before creating a skeleton, check if the target output file already exists. - -Glob the resolved output path from Phase 1 — `design/ux/[filename].md`, or -`design/accessibility-requirements.md` in `accessibility` mode. - -**If the file exists — retrofit mode:** -- Read the file in full -- For each expected section, check whether the body has real content (more than a `[To be designed]` placeholder) or is empty/placeholder -- Present a section status summary to the user: - -> "Found existing UX spec at `design/ux/[filename].md`. Here's what's already done: -> -> | Section | Status | -> |---------|--------| -> | Purpose & Player Need | [Complete / Empty / Placeholder] | -> | Player Context on Arrival | ... | -> | Navigation Position | ... | -> | Entry & Exit Points | ... | -> | Layout Specification | ... | -> | States & Variants | ... | -> | Interaction Map | ... | -> | Data Requirements | ... | -> | Events Fired | ... | -> | Transitions & Animations | ... | -> | Input Method Completeness Checklist | ... | -> | Accessibility | ... | -> | Localization Considerations | ... | -> | Acceptance Criteria | ... | -> | Open Questions | ... | -> -> (Rows are the skeleton's own `##` headings for the active mode — the list above is -> UX spec mode; HUD and accessibility modes list their skeleton's headings.) -> -> I'll work on the [N] incomplete sections only — existing content will not be overwritten." - -- Skip Section 3 (skeleton creation) — the file already exists -- In Phase 4 (Section Authoring), only work on sections with Status: Empty or Placeholder -- Use `Edit` to fill placeholders in-place rather than creating a new skeleton - -**If the file does not exist — fresh authoring mode:** -Proceed to Phase 3 (Create File Skeleton) as normal. - ---- +**Read `references/2-gather-context.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 3. Create File Skeleton -Once the user confirms, **immediately** create the output file with empty section -headers. This ensures incremental writes have a target and work survives interruptions. - -Ask: "May I create the skeleton file at `design/ux/[filename].md`?" — except in -`accessibility` mode, where the path is `design/accessibility-requirements.md` -(see the mode table in Section 1; it is deliberately not under `design/ux/`). - ---- - -### Skeleton for UX Spec (screen or flow) - -```markdown -# UX Spec: [Screen/Flow Name] - -> **Status**: In Design -> **Author**: [user + ux-designer] -> **Last Updated**: [today's date] -> **Journey Phase(s)**: [from context] -> **Platform Target**: [target platforms and input methods from 2h] -> **Template**: UX Spec - ---- - -## Purpose & Player Need - -[To be designed] - ---- - -## Player Context on Arrival - -[To be designed] - ---- - -## Navigation Position - -[To be designed] - ---- - -## Entry & Exit Points - -[To be designed] - ---- - -## Layout Specification - -### ASCII Wireframe - -[To be designed] - -### Layout Zones - -[To be designed] - -### Component Inventory - -[To be designed] - -### Information Hierarchy - -[To be designed] - ---- - -## States & Variants - -[To be designed] - ---- - -## Interaction Map - -[To be designed] - ---- - -## Data Requirements - -[To be designed] - ---- - -## Events Fired - -[To be designed] - ---- - -## Transitions & Animations - -[To be designed] - ---- - -## Input Method Completeness Checklist - -[To be designed] - ---- - -## Accessibility - -[To be designed] - ---- - -## Localization Considerations - -[To be designed] - ---- - -## Acceptance Criteria - -[To be designed] - ---- - -## Open Questions - -[To be designed] -``` - ---- - -### Skeleton for HUD Design - -```markdown -# HUD Design - -> **Status**: In Design -> **Author**: [user + ux-designer] -> **Last Updated**: [today's date] -> **Platform Targets**: [target platforms and input methods from 2h] -> **Template**: HUD Design - ---- - -## HUD Philosophy - -[To be designed] - ---- - -## Information Architecture - -### Full Information Inventory - -[To be designed] - -### Categorization - -[To be designed] - ---- - -## Layout Zones - -[To be designed] - ---- - -## HUD Element Specifications - -[To be designed] - ---- - -## HUD States by Gameplay Context - -[To be designed] - ---- - -## Information Hierarchy - -[To be designed] - ---- - -## Visual Budget - -[To be designed] - ---- - -## Feedback & Notification Systems - -[To be designed] - ---- - -## Platform Adaptation - -[To be designed] - ---- - -## Accessibility - -[To be designed] - ---- - -## Tuning Knobs - -[To be designed] - ---- - -## Acceptance Criteria - -[To be designed] - ---- - -## Open Questions - -[To be designed] -``` - ---- - -### Skeleton for Interaction Pattern Library - -```markdown -# Interaction Pattern Library - -> **Status**: In Design -> **Author**: [user + ux-designer] -> **Last Updated**: [today's date] -> **Template**: Interaction Pattern Library - ---- - -## Overview - -[To be designed] - ---- - -## Pattern Catalog - -[To be designed] - ---- - -## Patterns - -[Individual pattern entries added here as they are defined] - ---- - -## Gaps & Patterns Needed - -[To be designed] - ---- - -## Open Questions - -[To be designed] -``` - ---- - -### Skeleton for Accessibility Requirements - -Section list mirrors `.claude/docs/templates/accessibility-requirements.md` — if -the template gains or loses a section, this skeleton follows it, not the reverse. - -```markdown -# Accessibility Requirements - -> **Status**: In Design -> **Author**: [user + ux-designer] -> **Last Updated**: [today's date] -> **Template**: Accessibility Requirements - -## Accessibility Tier Definition - -[To be designed] - ---- - -## Visual Accessibility - -[To be designed] - ---- - -## Motor Accessibility - -[To be designed] - ---- - -## Cognitive Accessibility - -[To be designed] - ---- - -## Auditory Accessibility - -[To be designed] - ---- - -## Platform Accessibility API Integration - -[To be designed] - ---- - -## Per-Feature Accessibility Matrix - -[To be designed] - ---- - -## Accessibility Test Plan - -[To be designed] - ---- - -## Known Intentional Limitations - -[To be designed] - ---- - -## Audit History - -[To be designed] - ---- - -## External Resources - -[To be designed] - ---- - -## Open Questions - -[To be designed] -``` - -> **The tier commitment is the gated part.** `gate-pre-production.md` requires -> the file to exist *with an accessibility tier committed*, and -> `gate-production.md` checks that tier is addressed in every key screen spec. -> A skeleton whose Tier Definition is still `[To be designed]` satisfies the -> glob but not the gate — author that section first. - ---- - -After writing the skeleton, update `production/session-state/active.md` with: -- Task: Designing [screen/flow name] UX spec -- Current section: Starting (skeleton created) -- File: design/ux/[filename].md (or `design/accessibility-requirements.md` in `accessibility` mode) - ---- +**Read `references/3-file-skeleton.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 4. Section-by-Section Authoring -Walk through each section in order. For **each section**, follow this cycle: - -``` -Context -> Questions -> Options -> Decision -> Draft -> Approval -> Write -``` - -1. **Context**: State what this section needs to contain and surface any relevant - constraints from context gathered in Phase 2. -2. **Questions**: Ask what is needed to draft this section. Use `AskUserQuestion` - for constrained choices, conversational text for open-ended exploration. -3. **Options**: Where design choices exist, present 2-4 approaches with pros/cons. - Explain reasoning in conversation, then use `AskUserQuestion` to capture the decision. -4. **Decision**: User picks an approach or provides custom direction. -5. **Draft**: Write the section content in conversation for review. Flag provisional - assumptions explicitly. -6. **Approval**: Use `AskUserQuestion`: - - "Does this capture the [section name] correctly?" - - Options: "Yes — write it to the file", "Small changes needed (describe below)", "Major rethink needed" - Do not proceed to step 7 until the user selects "Yes". -7. **Write**: Use `AskUserQuestion`: "May I write the [section name] section to `[filepath]`?" - - Options: "Yes, write it", "Wait — one more change" - Once confirmed, use `Edit` to replace the `[To be designed]` placeholder with approved content. - -After writing each section, update `production/session-state/active.md`. - ---- +**Read `references/4-authoring.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ### Section guidance — read the ONE file for the active mode @@ -654,9 +95,9 @@ the other two.** | Mode | Guidance file | |------|---------------| -| UX Spec (screen or flow) | `.claude/skills/ux-design/references/sections-ux-spec.md` | -| HUD Design | `.claude/skills/ux-design/references/sections-hud.md` | -| Interaction Pattern Library | `.claude/skills/ux-design/references/sections-patterns.md` | +| UX Spec (screen or flow) | `references/sections-ux-spec.md` | +| HUD Design | `references/sections-hud.md` | +| Interaction Pattern Library | `references/sections-patterns.md` | | Accessibility Requirements | `.claude/docs/templates/guidance/accessibility-requirements-guide.md` | > The accessibility guidance lives under `templates/guidance/` rather than this @@ -668,80 +109,9 @@ the other two.** Apply `docs.density` (Section 1) to whatever that file tells you to author — it controls the depth of each section, not which sections exist. ---- - ## 5. Cross-Reference Check -Before marking the spec as ready for review, run these checks: - -**1. GDD requirement coverage**: Does every GDD UI Requirement that references -this screen have a corresponding element in this spec? Present any gaps. - -**2. Pattern library alignment**: Are all interaction patterns used in this spec -referenced by name? If a new pattern was invented during this spec session, flag -it for addition to the pattern library: -Use `AskUserQuestion`: -- "This spec uses [pattern name], which isn't in the pattern library yet. What should we do?" -- Options: "Add it to the pattern library now", "Flag it as a gap and continue", "Skip — this pattern is one-off" - -**3. Navigation consistency**: Do the entry/exit points in this spec match the -navigation map in any related specs? Flag mismatches. - -**4. Accessibility coverage**: Does the spec address the accessibility tier -committed to in `design/accessibility-requirements.md`? If not, flag open questions. - -**5. Empty states**: Does every data-dependent element have an empty state defined? -Flag any that don't. - -Present the check results: -> **Cross-Reference Check: [Screen Name]** -> - GDD requirements: [N of M covered / all covered] -> - New patterns to add to library: [list or "none"] -> - Navigation mismatches: [list or "none"] -> - Accessibility gaps: [list or "none"] -> - Missing empty states: [list or "none"] - ---- - -## 6. Handoff - -When all sections are approved and written: - -### 6a: Update Session State - -Update `production/session-state/active.md` with: -- Task: [screen-name] UX spec -- Status: Complete (or In Review) -- File: design/ux/[filename].md -- Sections: All written -- Next: [suggestion] - -### 6b: Suggest Next Step - -Before presenting options, state clearly: - -> "This spec should be validated with `/ux-review` before it enters the -> implementation pipeline. The Production gate (`/gate-check production`) -> requires all key screen specs to have passed `/ux-review` at `workflow: full` -> (recommended at `standard`)." - -Then use `AskUserQuestion`: -- "Run `/ux-review [filename]` now, or do something else first?" - - Options: - - "Run `/ux-review` now — validate this spec" - - "Design another screen first, then review all specs together" - - "Update the interaction pattern library with new patterns from this spec" - - "Stop here for this session" - -If the user picks "Design another screen first", add a note: "Reminder: run -`/ux-review` on all completed specs before running `/gate-check production`." - -### 6c: Cross-Link Related Specs - -If other UX specs link to or from this screen, note which ones should reference -this spec. Do not edit those files without asking — just name them. - ---- +**Read `references/5-crossref-handoff.md` now and follow it** — this phase's steps are in that file, not here. Read it again if the conversation was compacted or resumed during this phase. ## 7. Recovery & Resume diff --git a/.claude/skills/ux-design/references/2-gather-context.md b/.claude/skills/ux-design/references/2-gather-context.md new file mode 100644 index 00000000..82eb59e2 --- /dev/null +++ b/.claude/skills/ux-design/references/2-gather-context.md @@ -0,0 +1,189 @@ +# /ux-design — Sections 2 and 2b: Gather Context and Retrofit Detection + +> Part of `/ux-design`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 2. Gather Context (Read Phase) + +**In this file:** + +- 2a: Required Reads +- 2b: Player Journey +- 2c: GDD UI Requirements +- 2d: Existing UX Specs +- 2e: Interaction Pattern Library +- 2f: Art Bible +- 2g: Accessibility Requirements +- 2h: Input Method (from Project Config) +- 2i: Present Context Summary + +Read all relevant context **before** asking the user anything. The skill's value +comes from arriving informed. + +### 2a: Required Reads + +- **Game concept**: Read `design/gdd/game-concept.md` — or `design/game-brief.md`, + the one-page brief that replaces it at `rigor: minimal` — if neither exists, warn: + > "No game concept found. Run `/brainstorm` first to establish the game's + > foundation before designing UX." + > Continue anyway if the user asks. + +### 2b: Player Journey + +Read `design/player-journey.md` if it exists. For each relevant section, extract: +- Which journey phase(s) does this screen appear in? +- What is the player's emotional state on arrival at this screen? +- What player need is this screen serving in the journey? +- What critical moments (from the journey map) does this screen deliver? + +If the player journey file does not exist, note the gap and proceed: +> "No player journey map found at `design/player-journey.md`. Designing without it +> means we'll be making assumptions about player context. Consider running a player +> journey session after this spec is drafted." + +Also add to the UX spec's Open Questions section: +> "Player journey map not yet created. Author it from the template at `.claude/docs/templates/player-journey.md` to establish player context for this screen." + +> **Do not tell the user to "run `/ux-design` Phase 2b" to create it.** Phase 2b +> is this step — the one that *reads* the file. That remediation is circular: it +> sends the user back to the check that just reported the gap. No skill +> writes `design/player-journey.md`; it is hand-authored from its template. + +### 2c: GDD UI Requirements + +Glob `design/gdd/*.md` and grep for `UI Requirements` sections. Read any GDD whose +UI Requirements section references this screen by name or category. + +These GDD UI Requirements are the **requirements input** to this spec. Collect them +as a list of constraints the spec must satisfy. + +If designing the HUD, you need the UI Requirements of **every** system — the HUD +aggregates them. Collect them with one scan rather than opening each GDD: + +``` +Grep pattern="^#+ .*UI Requirements" glob="design/gdd/*.md" output_mode="content" -A 20 +``` + +Establish the denominator first (glob `design/gdd/*.md`, count **N**) and check +the match count against it. Count system GDDs only: `game-concept.md`, +`systems-index.md`, `game-pillars.md`, `gameplay-tags.md`, `entity-registry.md`, +`fixture-swap-ledger.md`, `sound-bible.md` and any `gdd-cross-review-*.md` live +there too, but they are not systems and have no UI to aggregate. +**A GDD with no UI Requirements section is not a GDD +with no UI needs** — it may predate the section. List the unmatched ones and +confirm with the user that they are genuinely headless before excluding them +from the HUD's requirement set; a HUD that silently omits a system's readout is +the exact failure this aggregation exists to prevent. + +### 2d: Existing UX Specs + +Glob `design/ux/*.md` and note which screens already have specs. For screens that +will link to or from the current screen, read their navigation/flow sections to +find the entry and exit points this spec must match. + +### 2e: Interaction Pattern Library + +If `design/ux/interaction-patterns.md` exists, read the pattern catalog index +(the list of pattern names and their one-line descriptions). Do not read full +pattern details — just the catalog. This tells you which patterns already exist +so you can reference them rather than reinvent them. + +### 2f: Art Bible + +Check for `design/art/art-bible.md`. If found, read the visual direction +section. UX layout must align with the aesthetic commitments already made. + +### 2g: Accessibility Requirements + +Check for `design/accessibility-requirements.md`. If found, read it. The spec +must satisfy the accessibility tier committed to there. + +### 2h: Input Method (from Project Config) + +Read the `platform` block from `project.yaml`; if `project.yaml` has no +`platform` block, fall back to the `## Input & Platform` section of +`.claude/docs/technical-preferences.md`. Store these values for use throughout +the skill — they drive the Interaction Map and inform accessibility +requirements: + +- **Primary Input** — `platform.primary_input` — the dominant input for this game +- **Gamepad Support** — `platform.gamepad_support` — Full / Partial / None +- **Touch Support** — `platform.touch_support` — Full / Partial / None +- **Target Platforms** — `platform.targets` — for safe zone and aspect ratio decisions +- **Input Methods** — the set of supported methods. When reading from + `project.yaml`, derive it: keyboard/mouse if `PC` or `Web` is in `targets`; + gamepad if gamepad support is Full/Partial; touch if touch support is + Full/Partial; plus the primary input. When falling back to + `technical-preferences.md`, use its explicit Input Methods field. + +If neither source is configured, ask once: +> "Input methods aren't configured yet. What does this game target?" +> Options: "Keyboard/Mouse only", "Gamepad only", "Both (PC + Console)", "Touch (mobile)", "All of the above" +> +> (Run `/setup-engine` to save this permanently so you won't be asked again.) + +Store the answer for the rest of this session. Do **not** ask again per section +or per screen. + +### 2i: Present Context Summary + +Before any design work, present a brief summary to the user: + +> **Designing: [Screen/Flow Name]** +> - Mode: [UX Spec / HUD Design / Pattern Library] +> - Journey phase(s): [from player-journey.md, or "unknown — no journey map"] +> - GDD requirements feeding this spec: [count and names, or "none found"] +> - Related screens already specced: [list, or "none yet"] +> - Known patterns available: [count, or "no pattern library yet"] +> - Accessibility tier: [from requirements doc, or "not yet defined"] +> - Input methods: [derived from the `project.yaml` platform block, or "asked above"] + +Then ask: "Anything else I should read before we start, or shall we proceed?" + +--- + +## 2b. Retrofit Mode Detection + +Before creating a skeleton, check if the target output file already exists. + +Glob the resolved output path from Phase 1 — `design/ux/[filename].md`, or +`design/accessibility-requirements.md` in `accessibility` mode. + +**If the file exists — retrofit mode:** +- Read the file in full +- For each expected section, check whether the body has real content (more than a `[To be designed]` placeholder) or is empty/placeholder +- Present a section status summary to the user: + +> "Found existing UX spec at `design/ux/[filename].md`. Here's what's already done: +> +> | Section | Status | +> |---------|--------| +> | Purpose & Player Need | [Complete / Empty / Placeholder] | +> | Player Context on Arrival | ... | +> | Navigation Position | ... | +> | Entry & Exit Points | ... | +> | Layout Specification | ... | +> | States & Variants | ... | +> | Interaction Map | ... | +> | Data Requirements | ... | +> | Events Fired | ... | +> | Transitions & Animations | ... | +> | Input Method Completeness Checklist | ... | +> | Accessibility | ... | +> | Localization Considerations | ... | +> | Acceptance Criteria | ... | +> | Open Questions | ... | +> +> (Rows are the skeleton's own `##` headings for the active mode — the list above is +> UX spec mode; HUD and accessibility modes list their skeleton's headings.) +> +> I'll work on the [N] incomplete sections only — existing content will not be overwritten." + +- Skip Section 3 (skeleton creation) — the file already exists +- In Phase 4 (Section Authoring), only work on sections with Status: Empty or Placeholder +- Use `Edit` to fill placeholders in-place rather than creating a new skeleton + +**If the file does not exist — fresh authoring mode:** +Proceed to Phase 3 (Create File Skeleton) as normal. + +--- diff --git a/.claude/skills/ux-design/references/3-file-skeleton.md b/.claude/skills/ux-design/references/3-file-skeleton.md new file mode 100644 index 00000000..f84c5254 --- /dev/null +++ b/.claude/skills/ux-design/references/3-file-skeleton.md @@ -0,0 +1,381 @@ +# /ux-design — Section 3: Create File Skeleton + +> Part of `/ux-design`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 3. Create File Skeleton + +**In this file:** + +- Skeleton for UX Spec (screen or flow) +- Skeleton for HUD Design +- Skeleton for Interaction Pattern Library +- Skeleton for Accessibility Requirements + +Once the user confirms, **immediately** create the output file with empty section +headers. This ensures incremental writes have a target and work survives interruptions. + +Ask: "May I create the skeleton file at `design/ux/[filename].md`?" — except in +`accessibility` mode, where the path is `design/accessibility-requirements.md` +(see the mode table in Section 1; it is deliberately not under `design/ux/`). + +--- + +### Skeleton for UX Spec (screen or flow) + +```markdown +# UX Spec: [Screen/Flow Name] + +> **Status**: In Design +> **Author**: [user + ux-designer] +> **Last Updated**: [today's date] +> **Journey Phase(s)**: [from context] +> **Platform Target**: [target platforms and input methods from 2h] +> **Template**: UX Spec + +--- + +## Purpose & Player Need + +[To be designed] + +--- + +## Player Context on Arrival + +[To be designed] + +--- + +## Navigation Position + +[To be designed] + +--- + +## Entry & Exit Points + +[To be designed] + +--- + +## Layout Specification + +### ASCII Wireframe + +[To be designed] + +### Layout Zones + +[To be designed] + +### Component Inventory + +[To be designed] + +### Information Hierarchy + +[To be designed] + +--- + +## States & Variants + +[To be designed] + +--- + +## Interaction Map + +[To be designed] + +--- + +## Data Requirements + +[To be designed] + +--- + +## Events Fired + +[To be designed] + +--- + +## Transitions & Animations + +[To be designed] + +--- + +## Input Method Completeness Checklist + +[To be designed] + +--- + +## Accessibility + +[To be designed] + +--- + +## Localization Considerations + +[To be designed] + +--- + +## Acceptance Criteria + +[To be designed] + +--- + +## Open Questions + +[To be designed] +``` + +--- + +### Skeleton for HUD Design + +```markdown +# HUD Design + +> **Status**: In Design +> **Author**: [user + ux-designer] +> **Last Updated**: [today's date] +> **Platform Targets**: [target platforms and input methods from 2h] +> **Template**: HUD Design + +--- + +## HUD Philosophy + +[To be designed] + +--- + +## Information Architecture + +### Full Information Inventory + +[To be designed] + +### Categorization + +[To be designed] + +--- + +## Layout Zones + +[To be designed] + +--- + +## HUD Element Specifications + +[To be designed] + +--- + +## HUD States by Gameplay Context + +[To be designed] + +--- + +## Information Hierarchy + +[To be designed] + +--- + +## Visual Budget + +[To be designed] + +--- + +## Feedback & Notification Systems + +[To be designed] + +--- + +## Platform Adaptation + +[To be designed] + +--- + +## Accessibility + +[To be designed] + +--- + +## Tuning Knobs + +[To be designed] + +--- + +## Acceptance Criteria + +[To be designed] + +--- + +## Open Questions + +[To be designed] +``` + +--- + +### Skeleton for Interaction Pattern Library + +```markdown +# Interaction Pattern Library + +> **Status**: In Design +> **Author**: [user + ux-designer] +> **Last Updated**: [today's date] +> **Template**: Interaction Pattern Library + +--- + +## Overview + +[To be designed] + +--- + +## Pattern Catalog + +[To be designed] + +--- + +## Patterns + +[Individual pattern entries added here as they are defined] + +--- + +## Gaps & Patterns Needed + +[To be designed] + +--- + +## Open Questions + +[To be designed] +``` + +--- + +### Skeleton for Accessibility Requirements + +Section list mirrors `.claude/docs/templates/accessibility-requirements.md` — if +the template gains or loses a section, this skeleton follows it, not the reverse. + +```markdown +# Accessibility Requirements + +> **Status**: In Design +> **Author**: [user + ux-designer] +> **Last Updated**: [today's date] +> **Template**: Accessibility Requirements + +## Accessibility Tier Definition + +[To be designed] + +--- + +## Visual Accessibility + +[To be designed] + +--- + +## Motor Accessibility + +[To be designed] + +--- + +## Cognitive Accessibility + +[To be designed] + +--- + +## Auditory Accessibility + +[To be designed] + +--- + +## Platform Accessibility API Integration + +[To be designed] + +--- + +## Per-Feature Accessibility Matrix + +[To be designed] + +--- + +## Accessibility Test Plan + +[To be designed] + +--- + +## Known Intentional Limitations + +[To be designed] + +--- + +## Audit History + +[To be designed] + +--- + +## External Resources + +[To be designed] + +--- + +## Open Questions + +[To be designed] +``` + +> **The tier commitment is the gated part.** `gate-pre-production.md` requires +> the file to exist *with an accessibility tier committed*, and +> `gate-production.md` checks that tier is addressed in every key screen spec. +> A skeleton whose Tier Definition is still `[To be designed]` satisfies the +> glob but not the gate — author that section first. + +--- + +After writing the skeleton, update `production/session-state/active.md` with: +- Task: Designing [screen/flow name] UX spec +- Current section: Starting (skeleton created) +- File: design/ux/[filename].md (or `design/accessibility-requirements.md` in `accessibility` mode) + +--- diff --git a/.claude/skills/ux-design/references/4-authoring.md b/.claude/skills/ux-design/references/4-authoring.md new file mode 100644 index 00000000..d1b74a38 --- /dev/null +++ b/.claude/skills/ux-design/references/4-authoring.md @@ -0,0 +1,31 @@ +# /ux-design — Section 4: Section-by-Section Authoring + +> Part of `/ux-design`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 4. Section-by-Section Authoring + +Walk through each section in order. For **each section**, follow this cycle: + +``` +Context -> Questions -> Options -> Decision -> Draft -> Approval -> Write +``` + +1. **Context**: State what this section needs to contain and surface any relevant + constraints from context gathered in Phase 2. +2. **Questions**: Ask what is needed to draft this section. Use `AskUserQuestion` + for constrained choices, conversational text for open-ended exploration. +3. **Options**: Where design choices exist, present 2-4 approaches with pros/cons. + Explain reasoning in conversation, then use `AskUserQuestion` to capture the decision. +4. **Decision**: User picks an approach or provides custom direction. +5. **Draft**: Write the section content in conversation for review. Flag provisional + assumptions explicitly. +6. **Approval**: Use `AskUserQuestion`: + - "Does this capture the [section name] correctly?" + - Options: "Yes — write it to the file", "Small changes needed (describe below)", "Major rethink needed" + Do not proceed to step 7 until the user selects "Yes". +7. **Write**: Use `AskUserQuestion`: "May I write the [section name] section to `[filepath]`?" + - Options: "Yes, write it", "Wait — one more change" + Once confirmed, use `Edit` to replace the `[To be designed]` placeholder with approved content. + +After writing each section, update `production/session-state/active.md`. diff --git a/.claude/skills/ux-design/references/5-crossref-handoff.md b/.claude/skills/ux-design/references/5-crossref-handoff.md new file mode 100644 index 00000000..f7df4315 --- /dev/null +++ b/.claude/skills/ux-design/references/5-crossref-handoff.md @@ -0,0 +1,77 @@ +# /ux-design — Sections 5 and 6: Cross-Reference Check and Handoff + +> Part of `/ux-design`. `SKILL.md` names when to read this file; the settings it +> resolved and the rules under its later headings still apply here. + +## 5. Cross-Reference Check + +Before marking the spec as ready for review, run these checks: + +**1. GDD requirement coverage**: Does every GDD UI Requirement that references +this screen have a corresponding element in this spec? Present any gaps. + +**2. Pattern library alignment**: Are all interaction patterns used in this spec +referenced by name? If a new pattern was invented during this spec session, flag +it for addition to the pattern library: +Use `AskUserQuestion`: +- "This spec uses [pattern name], which isn't in the pattern library yet. What should we do?" +- Options: "Add it to the pattern library now", "Flag it as a gap and continue", "Skip — this pattern is one-off" + +**3. Navigation consistency**: Do the entry/exit points in this spec match the +navigation map in any related specs? Flag mismatches. + +**4. Accessibility coverage**: Does the spec address the accessibility tier +committed to in `design/accessibility-requirements.md`? If not, flag open questions. + +**5. Empty states**: Does every data-dependent element have an empty state defined? +Flag any that don't. + +Present the check results: +> **Cross-Reference Check: [Screen Name]** +> - GDD requirements: [N of M covered / all covered] +> - New patterns to add to library: [list or "none"] +> - Navigation mismatches: [list or "none"] +> - Accessibility gaps: [list or "none"] +> - Missing empty states: [list or "none"] + +--- + +## 6. Handoff + +When all sections are approved and written: + +### 6a: Update Session State + +Update `production/session-state/active.md` with: +- Task: [screen-name] UX spec +- Status: Complete (or In Review) +- File: design/ux/[filename].md +- Sections: All written +- Next: [suggestion] + +### 6b: Suggest Next Step + +Before presenting options, state clearly: + +> "This spec should be validated with `/ux-review` before it enters the +> implementation pipeline. The Production gate (`/gate-check production`) +> requires all key screen specs to have passed `/ux-review` at `workflow: full` +> (recommended at `standard`)." + +Then use `AskUserQuestion`: +- "Run `/ux-review [filename]` now, or do something else first?" + - Options: + - "Run `/ux-review` now — validate this spec" + - "Design another screen first, then review all specs together" + - "Update the interaction pattern library with new patterns from this spec" + - "Stop here for this session" + +If the user picks "Design another screen first", add a note: "Reminder: run +`/ux-review` on all completed specs before running `/gate-check production`." + +### 6c: Cross-Link Related Specs + +If other UX specs link to or from this screen, note which ones should reference +this spec. Do not edit those files without asking — just name them. + +--- diff --git a/.claude/skills/ux-design/references/sections-hud.md b/.claude/skills/ux-design/references/sections-hud.md index a9b4cf6c..46b6e802 100644 --- a/.claude/skills/ux-design/references/sections-hud.md +++ b/.claude/skills/ux-design/references/sections-hud.md @@ -3,6 +3,13 @@ # Section Guidance — HUD Design Mode +**In this file:** + +- Section A: HUD Philosophy +- Section B: Information Architecture +- Section C: Layout Zones +- Section D: HUD Element Specifications +- Sections E–L: HUD States, Information Hierarchy, Visual Budget, Feedback & Notification, Platform Adaptation, Accessibility, Tuning Knobs, Acceptance Criteria HUD design follows a different order from UX spec mode. Begin with philosophy; do not touch layout until the information architecture is complete. diff --git a/.claude/skills/ux-design/references/sections-ux-spec.md b/.claude/skills/ux-design/references/sections-ux-spec.md index 6ddf60d1..032c87c9 100644 --- a/.claude/skills/ux-design/references/sections-ux-spec.md +++ b/.claude/skills/ux-design/references/sections-ux-spec.md @@ -3,6 +3,22 @@ # Section Guidance — UX Spec Mode +**In this file:** + +- Section A: Purpose & Player Need +- Section B: Player Context on Arrival +- Section B2: Navigation Position +- Section B3: Entry & Exit Points +- Section C: Layout Specification +- Section D: States & Variants +- Section E: Interaction Map +- Section E2: Events Fired +- Section E3: Transitions & Animations +- Section F: Data Requirements +- Section F2: Input Method Completeness Checklist +- Section G: Accessibility +- Section H: Localization Considerations +- Section I: Acceptance Criteria #### Section A: Purpose & Player Need diff --git a/.claude/skills/ux-review/SKILL.md b/.claude/skills/ux-review/SKILL.md index cb7f5c33..9a37fb93 100644 --- a/.claude/skills/ux-review/SKILL.md +++ b/.claude/skills/ux-review/SKILL.md @@ -12,6 +12,8 @@ model: sonnet Resolved above — use as-is. No block → defaults in `.claude/docs/config-resolution.md`. +# UX Review + ## Overview Validates UX design documents before they enter the implementation pipeline. diff --git a/.claude/skills/vertical-slice/SKILL.md b/.claude/skills/vertical-slice/SKILL.md index db67b616..79892517 100644 --- a/.claude/skills/vertical-slice/SKILL.md +++ b/.claude/skills/vertical-slice/SKILL.md @@ -7,11 +7,13 @@ allowed-tools: Read, Glob, Grep, Write, Edit, Bash, Agent, AskUserQuestion, Bash model: sonnet --- -!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys review_mode,automation` +!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" resolve_config --keys review_mode,automation,workflow` Resolved above — use as-is; `--review` overrides `review_mode` for this run. No block → defaults in `.claude/docs/config-resolution.md`. +# Vertical Slice + ## Purpose @@ -251,7 +253,8 @@ Track velocity throughout the build. Log: - etc. This is the most honest data you will ever have about your production rate. Do not -skip it. It feeds directly into sprint planning. +skip it. It feeds directly into sprint planning (at `workflow: minimal`, which has +no sprints, into the brief's build order). Read `.claude/docs/templates/vertical-slice-report.md` to get the report structure. If the template file is not found, use this fallback structure: @@ -330,7 +333,10 @@ Link to `prototypes/[concept-name]-vertical-slice/REPORT.md`. Your vertical slice validated the full game loop. The project is ready for Production. -Recommended next steps: +At `workflow: minimal`: `/create-stories` (from the brief), then `/dev-story` +on the first story — the rest of this list is the `standard`/`full` path. + +Recommended next steps (`standard`/`full`): - `/create-epics layer:foundation` — plan Foundation layer epics - `/create-epics layer:core` — plan Core layer epics - `/create-stories [epic-slug]` — break each epic into implementable stories diff --git a/CCGS Skill Testing Framework/CLAUDE.md b/CCGS Skill Testing Framework/CLAUDE.md index 3bd7952e..d302563d 100644 --- a/CCGS Skill Testing Framework/CLAUDE.md +++ b/CCGS Skill Testing Framework/CLAUDE.md @@ -75,8 +75,8 @@ A tier is the directory a spec lives in. The rubric category is the agent's 1. Read `catalog.yaml` to get the `spec:` path and `category:` — from the `skills:` entry for a skill, the `agents:` entry for an agent -2. Read the skill at `.claude/skills/[name]/SKILL.md`, or the agent at - `.claude/agents/[name].md` +2. Read the skill at `.claude/skills/[name]/SKILL.md` and every file in its + `references/` folder, or the agent at `.claude/agents/[name].md` 3. Read the project `CLAUDE.md` and the files it imports with `@`: every subagent receives them, so a rule stated there (for example a redirect in `coordination-rules.md`) counts as the skill's or agent's own diff --git a/CCGS Skill Testing Framework/README.md b/CCGS Skill Testing Framework/README.md index e588c1fb..bd1efada 100644 --- a/CCGS Skill Testing Framework/README.md +++ b/CCGS Skill Testing Framework/README.md @@ -14,7 +14,7 @@ you write. Driven by `/skill-test` and `/skill-improve`. > > | Mode | Without this folder | > |------|---------------------| -> | `/skill-test static` | **Works** — the 7 structural checks read `SKILL.md` only | +> | `/skill-test static` | **Works** — the 7 structural checks read only the skill's own files | > | `/skill-test audit` | **Degrades** — reports that no catalog exists | > | `/skill-test spec` | **Breaks** — the behavioral specs live here | > | `/skill-test category` | **Breaks** — reads `quality-rubric.md` from here | diff --git a/CCGS Skill Testing Framework/skills/analysis/scope-check.md b/CCGS Skill Testing Framework/skills/analysis/scope-check.md index e59bf328..ff5ce0b8 100644 --- a/CCGS Skill Testing Framework/skills/analysis/scope-check.md +++ b/CCGS Skill Testing Framework/skills/analysis/scope-check.md @@ -13,7 +13,7 @@ current state (related source files, `git log`, TODO/FIXME comments, the active sprint plan) and produces a comparison report: Original Scope, Current Scope, Scope Additions, Scope Removals, a Bloat Score, a Risk Assessment and Cut / Defer / Keep / Flag recommendations. The verdict follows the net scope -change: ≤10% PASS, 10–25% CONCERNS, >25% FAIL. When the percentage would be +change: ≤10% PASS, >10–25% CONCERNS, >25% FAIL. When the percentage would be meaningless — a baseline that enumerates no items, or a current state that cannot be read — the verdict is NOT ASSESSED and the numeric block is replaced. No files are written and no director gates are invoked. @@ -188,7 +188,7 @@ None. Scope check is a read-only advisory skill; no gates are invoked. - [ ] Locates the baseline document (`design/gdd/`, `production/sprints/`, `production/milestones/`) before any comparison, and stops if it is absent - [ ] Reads the current state from source files, `git log`, TODO/FIXME comments and the active sprint plan -- [ ] Verdict follows the net-change table: ≤10% PASS, 10–25% CONCERNS, >25% FAIL +- [ ] Verdict follows the net-change table: ≤10% PASS, >10–25% CONCERNS, >25% FAIL - [ ] Emits NOT ASSESSED instead of a percentage when the baseline has no items or the current state cannot be read - [ ] Does not write any files - [ ] No director gates are invoked diff --git a/CCGS Skill Testing Framework/skills/authoring/create-architecture.md b/CCGS Skill Testing Framework/skills/authoring/create-architecture.md index f64cc97b..c6db86f1 100644 --- a/CCGS Skill Testing Framework/skills/authoring/create-architecture.md +++ b/CCGS Skill Testing Framework/skills/authoring/create-architecture.md @@ -8,7 +8,7 @@ a prerequisite is missing: the engine reference docs (no engine → `/setup-engi `design/gdd/systems-index.md` (absent at `standard`/`full` → `/map-systems`), and `design/gdd/game-concept.md` (absent → `/brainstorm`; at `minimal` the one-page `design/game-brief.md` stands in). It extracts a Technical Requirements -Baseline (`TR-[gdd-slug]-[NNN]`) from the requirement-bearing sections of every +Baseline (`TR-[system]-[NNN]`) from the requirement-bearing sections of every GDD, inventories existing ADRs from their headers, and shows an Engine Knowledge Gap Inventory with an `AskUserQuestion` before authoring. @@ -94,7 +94,7 @@ skipped — Solo mode." 9. Phase 8 writes a summary to `production/session-state/active.md` and prints the handoff with the headings "Architecture Complete", "Run These ADRs Next", "Gate-Check Readiness"; its **Then:** line names `/architecture-review`, then `/create-control-manifest` once the review passes, and the readiness block names `/gate-check pre-production` **Assertions:** -- [ ] The baseline uses `TR-[gdd-slug]-[NNN]` IDs and is built from the scanned GDD sections, not whole-file reads +- [ ] The baseline uses `TR-[system]-[NNN]` IDs and is built from the scanned GDD sections, not whole-file reads - [ ] The knowledge gap inventory and its three-option `AskUserQuestion` come before Phase 1 - [ ] Each section is shown before its approval is asked - [ ] The master document is written only after the Phase 7 `AskUserQuestion` approval diff --git a/CCGS Skill Testing Framework/skills/utility/setup-engine.md b/CCGS Skill Testing Framework/skills/utility/setup-engine.md index 4068fe23..433454bf 100644 --- a/CCGS Skill Testing Framework/skills/utility/setup-engine.md +++ b/CCGS Skill Testing Framework/skills/utility/setup-engine.md @@ -246,6 +246,29 @@ None. `/setup-engine` is a technical configuration skill. No director gates appl --- +### Case 8: A skipped question is not an answer + +**Fixture:** +- Fresh project: no engine configured, no `project.yaml` engine block +- The engine question comes back skipped: the user closes it, or a headless run + returns every question as skipped + +**Input:** `/setup-engine` + +**Expected behavior:** +1. The skill does not choose an engine, language or version itself +2. It asks again in plain text, saying what is waiting on the answer, and waits +3. Nothing is written to `CLAUDE.md`, `project.yaml`, `technical-preferences.md` + or `VERSION.md` before the user answers +4. In a run where nobody can answer, it stops and reports what is waiting + +**Assertions:** +- [ ] No engine, language or version is picked on the user's behalf +- [ ] The question is asked again in plain text +- [ ] No file is written before an answer arrives + +--- + ## Protocol Compliance - [ ] Presents draft configuration before asking to write diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a2b536e..a3e23e4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,106 @@ existing project on the older config files. --- +## [1.1.3] — 2026-10-08 + +**Long skills keep their later steps through a long session, a question nobody +answered is never taken as an answer, and the shipped permissions approve +less.** A fix release for 1.1.2. + +### Fixed + +- **The 14 longest skills keep their later phases after a compaction.** Claude + Code re-attaches only the first part of an invoked skill after a compaction, + so the later phases of a long skill could drop out in the middle of a session. + `/adopt`, `/architecture-decision`, `/architecture-review`, + `/create-architecture`, `/design-system`, `/dev-story`, `/gate-check`, + `/prototype`, `/review-all-gdds`, `/setup-engine`, `/smoke-check`, + `/story-done`, `/test-setup` and `/ux-design` now keep each phase in its own + file in the skill's `references/` folder, read when the phase starts and + again after a compaction. The steps themselves are unchanged. The files are + named relative to the skill folder, so they are found wherever the skill is + installed, and every reference file over 100 lines opens with a list of what + it holds. `/skill-test` and `/skill-improve` read those files too, so they + judge a split skill whole and put a fix in the file that holds the text. +- **A question that is skipped, dismissed or comes back empty is not an + answer**, in any mode: nothing is written, set or picked on it, and it is + asked again in plain text. Guided mode no longer contradicts itself: a new + file waits for "May I write?", and an update to an existing file goes ahead + after a short summary. +- **Agents return their options as a short list for the skill to ask.** Fourteen + agents were told to use the question tool, which an agent started by a skill + does not have. +- **Settings read from a subfolder use the project root.** Started in `src/`, + per-system overrides read as none, notes about invalid or locked values + disappeared, and the older `review-mode.txt` and `stage.txt` were never + found. `/settings` and `/perf-profile` also work from a subfolder now. +- **Setting values.** A hand-edited local `platform.cert_tier` no longer + overrides the locked value, and an invalid `cert_tier` or `testing.strict` + value counts as unset rather than being used. On Windows the locked-key note + no longer ends each key with a stray carriage return, and an always-ask item + that contains a comma is no longer split in two. +- **The commit check sees files a `git add` in the same command stages** + (`git add -A && git commit`), and no longer asks `systems-index.md`, + `game-concept.md` and the other non-system files in `design/gdd/` for GDD + sections (#133). +- **The commit check works for a project in a subfolder of a larger + repository.** A game in `game/` of a bigger repo got no data, GDD or code + checks at commit; staged paths are now read from the project folder. **A JSON + data file stored with Git LFS** is checked through its working copy instead of + being blocked as invalid, and one with no working copy is named as skipped. +- **`/smoke-check` no longer waits forever on Unreal.** The version check ran + `UnrealEditor-Cmd -version`, which opens the editor and never returns. It now + reads the engine's `Build.version` file. +- **Registry lookups.** `/design-system` finds the entities other systems + reference it from; the requirement lookups in `/create-stories`, `/dev-story` + and `/story-done` no longer match `combat-ai` when asked for `combat`; the + documented superseded status is valid YAML; `/consistency-check` and + `/architecture-review` re-read their registry before writing to it. Your own + registry files are not changed. +- **Next steps at `workflow: minimal`.** Thirteen skills offered only a sprint as + the next step; at minimal they now name the brief's build order. + `gameplay-programmer` no longer asks for an ADR there, and five templates name + `design/game-brief.md` beside the concept doc. +- **`team-polish` and `team-ui` keep their core members at the `lean` review + mode.** +- **`/scope-check`'s verdict bands no longer overlap** at exactly 10% and 25%. +- **`/start` writes a single `modes:` block.** Its rigor and automation + questions could each add one. If your `project.yaml` has two `modes:` blocks, + merge them into one. +- **Every skill opens with a title.** 39 skills had no top-level heading, and in + `/architecture-decision` the first one was the ADR template's placeholder + (#83, reported by @specterslient95-lgtm). +- **A settings line that runs for more than two minutes** reaches the skill as a + task notice instead of the settings; `config-resolution.md` now says what that + notice means and where to read the settings instead. +- **The three writes that need no "May I write?"** — agent memory, appends to + `active.md`, and an agent's new file at the path its skill named — are now + named in `CLAUDE.md`, which named none of them, and in the agent-memory rule, + which named one. +- **Docs corrected**: the settings, workflow and protocol docs, the README, the + setup requirements and the 1.1.0 and 1.1.2 notes on what the default + permission mode covers, and three overstatements in `/story-done`, the + workflow guide and UPGRADING. + +### Security + +- **The shipped allow rules no longer approve deleting a branch or writing files + without asking.** Four allow rules had no space before their `*`, so they + matched any text after the command name: `git branch -D` and `-m`, `git log` + and `git diff` with `--output=`, and `python -m json.tool ` + ran without a prompt, and in auto mode an allow rule also skips the + classifier. Those rules are removed; read-only git commands such as + `git status` and `git log` still run without a prompt. See + [UPGRADING.md](UPGRADING.md#v112--v113) if you merged `settings.json` or + copied these rules into `settings.local.json`. +- **Start Claude Code at the project root.** It loads `.claude/settings.json` + only from the folder it starts in, so a session started in `src/` or `design/` + runs without the project's hooks, deny rules and ask-first mode. The README + says so, and Claude now warns when it was started somewhere else. +- **`.env` files are denied to Edit.** + +--- + ## [1.1.2] — 2026-09-29 **The default path works end to end, Unity and Unreal get the same care as @@ -731,8 +831,10 @@ Code 2.1.281 to 2.1.284, on Windows, Linux (bash 5 and 3.2) and macOS. **If you so the aborting command stopped them at startup with `Shell command permission check failed … Contains expansion`. They keep their preloaded skills and still have no shell access. -- **Config is found from any folder.** Starting Claude Code inside `src/` or - `design/` now reads the project's `project.yaml`, not nothing. +- **Skills find `project.yaml` from any folder.** A skill run in a session + started inside `src/` or `design/` now reads the project's `project.yaml`, not + nothing. Claude Code itself still loads the project's hooks, deny rules and + permission mode only when it is started at the project root. - **`/changelog` works in a repository with no commits yet.** Checked on Claude Code 2.1.277 and 2.1.281, in every permission mode, from the @@ -749,13 +851,13 @@ studio production no longer have to carry the same overhead. ### Added -- **Ask-before-write now holds, whatever your personal settings say.** CCGS - sets Claude Code's permission mode to `default` in the project settings, so - every approval gate in the framework actually fires. If your own Claude Code - config runs in an auto-accept mode, that used to switch the whole - collaboration protocol off silently and agents would write files you never - approved. Override it in `.claude/settings.local.json` if you really want to, - but read `.claude/docs/setup-requirements.md` first. +- **Sessions start in ask-before-write mode.** CCGS sets Claude Code's + permission mode to `default` in the project settings, so a terminal session + started at the project root asks before writing, even if your own Claude Code + config runs in an auto-accept mode. It sets the starting mode only: resuming a + session, switching modes mid-session, the VS Code extension and the Desktop + app can still put you in another one. `.claude/docs/setup-requirements.md` + lists them, and how to change the starting mode. - **`project.yaml` — one place for your project's configuration.** Engine, naming conventions, specialists and process settings all live here. It diff --git a/CLAUDE.md b/CLAUDE.md index f7f869ce..60359288 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -50,9 +50,15 @@ after it runs `project.yaml` holds the real values. Every task follows: **Question -> Options -> Decision -> Draft -> Approval** - Agents MUST ask "May I write this to [filepath]?" before using Write/Edit tools + (exempt: `active.md` appends, agent memory, a subagent's new file at the path + its orchestrating skill named; see `.claude/rules/agent-memory.md`) - Agents MUST show drafts or summaries before requesting approval - Multi-file changes require explicit approval for the full changeset - No commits without user instruction +- A skipped or dismissed question is not an answer: act on nothing, re-ask in + plain text and wait +- Started outside this file's folder? Warn first: hooks, deny rules and the + ask-first mode load only when Claude Code starts here See `docs/COLLABORATIVE-DESIGN-PRINCIPLE.md` for full protocol and examples. diff --git a/README.md b/README.md index fda84646..fe1b1228 100644 --- a/README.md +++ b/README.md @@ -188,10 +188,13 @@ Hooks fail gracefully if optional tools are missing — you just lose validation cd my-game ``` -2. **Open Claude Code** and start a session: +2. **Open Claude Code in the project's root folder** (the one holding + `CLAUDE.md` and `project.yaml`) and start a session: ```bash claude ``` + Starting it in a subfolder such as `src/` skips the project's hooks, deny + rules and ask-first permission mode. 3. **Run `/start`** — the system asks where you are (no idea, vague concept, clear design, existing work) and guides you to the right workflow. No assumptions. @@ -218,11 +221,10 @@ and `team.size`), so `/start` asks it once instead of six times: - **`standard`** — 5 required GDD sections, balanced doc depth, standard QA evidence, lean review. - **`full`** — all 8 GDD sections, thorough docs, full QA evidence on every story type, full director review. -`minimal` is the default because it was measured against the alternatives: the -heavier tier cost several times more to reach working code, was ranked last on -play quality, and returned nothing measurable when a fresh developer inherited -the project. Raise it in one `/settings` call when your project grows — `/help` -and `/gate-check` will suggest it when they see the signs. +`minimal` is the default because the heavier tier costs more to reach working +code without producing a better result, and gives nothing back when someone new +picks the project up. Raise it in one `/settings` call when your project grows +— `/help` and `/gate-check` will suggest it when they see the signs. Two escape hatches keep one setting from being a blunt instrument. **`system_overrides`** holds a single system to a higher standard than the rest @@ -324,6 +326,12 @@ This is **not** an auto-pilot system. Every agent follows a strict collaboration You stay in control. The agents provide structure and expertise, not autonomy. +That is how a terminal session started at the project root behaves out of the +box. The `guided` and `autonomous` automation settings, and Claude Code's own +auto mode, trade some of these prompts for speed; see +[setup-requirements.md](.claude/docs/setup-requirements.md) for the routes into +auto mode. + ### Automated Safety **Hooks** run automatically on every session: @@ -345,7 +353,7 @@ You stay in control. The agents provide structure and expertise, not autonomy. > **Note**: `validate-commit.sh`, `validate-assets.sh`, and `validate-skill-change.sh` fire on every Bash, PowerShell or Write tool call and exit immediately (exit 0) when the command or file path is not relevant. This is normal hook behavior — not a performance concern. -**Permission rules** in `settings.json` auto-allow safe operations (git status, test runs) and block dangerous ones (force push, `rm -rf`, reading `.env` files) in both the Bash and PowerShell tools. The `git` rules match anywhere after `git`, so a git command whose text only mentions `push` followed later by ` +` or ` -f`, `clean` followed by ` -f`, or `reset` followed by `--hard` — a commit message such as `git commit -m "push + pull"` included — is denied too: reword the message. +**Permission rules** in `settings.json` auto-allow test runs and block dangerous operations (force push, `rm -rf`, reading `.env` files) in both the Bash and PowerShell tools. Read-only commands such as `git status`, `git log` and `ls` need no rule: Claude Code runs them without asking. The `git` rules match anywhere after `git`, so a git command whose text only mentions `push` followed later by ` +` or ` -f`, `clean` followed by ` -f`, or `reset` followed by `--hard` — a commit message such as `git commit -m "push + pull"` included — is denied too: reword the message. ### Path-Scoped Rules diff --git a/UPGRADING.md b/UPGRADING.md index 7f554ffc..57669b19 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -3,18 +3,22 @@ This guide covers upgrading your existing game project repo from one version of the template to the next. -**Find your current version** in your git log: -```bash -git log --oneline | grep -i "release\|setup" -``` -Or read `framework.version` in your `project.yaml`, or the newest entry in -`CHANGELOG.md`. +**Find your current version** — use the first of these that applies: + +- **Cloned the template, or merged it:** `git describe --tags --abbrev=0` prints + the newest release tag in your history, for example `v1.1.2`. +- **`framework.version` in `project.yaml`:** the version the file was last stamped + with. It can lag behind after an upgrade that kept your own `project.yaml`, and a + project from before 1.1 has no `project.yaml`. +- **`CHANGELOG.md`:** `grep -m1 '^## \[' CHANGELOG.md` prints the newest release it + lists, which is your version while that file is still the template's. --- ## Table of Contents - [Upgrade Strategies](#upgrade-strategies) +- [v1.1.2 → v1.1.3](#v112--v113) - [v1.1.1 → v1.1.2](#v111--v112) - [v1.1.0 → v1.1.1](#v110--v111) - [v1.0 → v1.1](#v10--v11) @@ -168,6 +172,92 @@ Best when: you didn't use git to set up the template (just downloaded a zip). --- +## v1.1.2 → v1.1.3 + +**Released:** 2026-10-08 +**Commit range:** `v1.1.2..v1.1.3` +**Key themes:** Long skills keep their later phases after a compaction; a +question nobody answered is never an answer; the shipped allow rules approve +less; settings read the same from a subfolder + +### What Changed + +| Category | Changes | +|----------|---------| +| **Long skills (14)** | `/adopt`, `/architecture-decision`, `/architecture-review`, `/create-architecture`, `/design-system`, `/dev-story`, `/gate-check`, `/prototype`, `/review-all-gdds`, `/setup-engine`, `/smoke-check`, `/story-done`, `/test-setup` and `/ux-design` keep each phase in `references/.md`; their steps are unchanged. `/skill-test` and `/skill-improve` read a skill's `references/` files too | +| **Questions** | `automation-modes.md` and `effects-map.md`: a skipped, dismissed or empty answer is never an answer; 14 agents return options as a list for the skill to ask; `CLAUDE.md` and `agent-memory.md` name the three writes that need no "May I write?" | +| **Settings** | `yaml-helper.sh` reads every setting under the project root when started from a subfolder; the local `platform.cert_tier` cannot override the lock; invalid `cert_tier` and `testing.strict` values count as unset | +| **Hooks and scripts** | `validate-commit.sh` checks files a `git add` in the same command stages, skips non-system files in `design/gdd/`, checks a project in a subfolder of a larger repository, and reads Git LFS-stored JSON through its working copy; `project-coherence.sh` reads Unreal's `Build.version` | +| **Permissions** | `settings.json`: seven allow rules removed, the two pytest rules narrowed, `Edit(**/.env*)` denied | +| **Other skills** | Thirteen skills name the minimal route as a next step; registry lookups in `/design-system`, `/create-stories`, `/dev-story`, `/story-done`, `/consistency-check`, `/architecture-review`; `team-polish`, `team-ui`, `/scope-check`; `/start` writes one `modes:` block; every skill opens with a title | + +No setting changes meaning, and nothing is migrated automatically. + +--- + +### Files: Safe to Overwrite + +**Existing files to overwrite (no user content):** +``` +.claude/skills/** ← 14 skills gain a references/ + folder; if you edited one of + them, see Merge Carefully. 39 + skills gain a title line +.claude/hooks/validate-commit.sh, validate-push.sh, yaml-helper.sh, +pre-compact.sh, session-stop.sh +.claude/scripts/project-coherence.sh +.claude/agents/*.md ← 15 agents changed; merge any + you edited +.claude/docs/** ← EXCEPT technical-preferences.md, + which is yours and unchanged in + 1.1.3 +docs/WORKFLOW-GUIDE.md, docs/CLAUDE.md, docs/COLLABORATIVE-DESIGN-PRINCIPLE.md, +docs/engine-reference/unreal/plugins/gameplay-ability-system.md +README.md, CHANGELOG.md, UPGRADING.md ← keep your README if it is your + game's +CCGS Skill Testing Framework/ +``` + +--- + +### Files: Merge Carefully + +**`.claude/settings.json`** — if you have not edited it, overwrite it with the +shipped file. If you have, remove these from `allow`: `Bash(git status*)`, +`Bash(git diff*)`, `Bash(git log*)`, `Bash(git branch*)`, `Bash(git rev-parse*)`, +`Bash(ls *)` and `Bash(python -m json.tool*)`; change `Bash(python -m pytest*)` +and `Bash(py -m pytest*)` to `Bash(python -m pytest *)` and +`Bash(py -m pytest *)`; and add `Edit(**/.env*)` to `deny`. Read-only git +commands still run without a prompt after the change. **If you copied any of +the removed rules into `.claude/settings.local.json`, remove them there too:** a +copy keeps approving `git branch -D`, `--output` files and `json.tool` writes +without asking. + +**`CLAUDE.md`** — if you have not edited it outside the Technology Stack, take +the shipped Collaboration Protocol section. If you have, copy its three new +lines: the exemptions under "May I write", "A skipped or dismissed question is +not an answer", and "Started outside this file's folder? Warn first". + +**`.claude/rules/agent-memory.md`, `.claude/rules/skill-authoring.md`** — if you +have not edited them, overwrite them with the shipped files. + +**One of the 14 long skills, if you edited it** — its `SKILL.md` now holds the +settings line, the always-apply rules and one heading per phase; each phase's +steps moved word for word into `references/.md`. Take the shipped skill, +then make your change again in the phase file that now holds that text. + +**`design/registry/entities.yaml`, `docs/architecture/tr-registry.yaml`** — +these are your project's data; keep yours. Only the header comments changed. +If your TR registry has an unquoted `status: superseded-by: TR-...`, quote the +value (`status: "superseded-by: TR-combat-001"`): unquoted, the second colon +makes the file invalid YAML. `/story-readiness` reads either form. + +**`project.yaml`** — optionally set `framework.version: 1.1.3`. Nothing reads it +for this release. If it has two `modes:` blocks — `/start` could write a second +one — merge them into one. + +--- + ## v1.1.1 → v1.1.2 **Released:** 2026-09-29 @@ -479,10 +569,9 @@ modes: rigor: standard ``` -We changed the default because we measured it. Built both ways, `standard` cost -several times more to reach working code, did not produce a better result, and -gave nothing back when a fresh developer picked the project up. Most projects -were paying for process that did not repay. +We changed the default because `standard` costs more to reach working code +without producing a better result, and gives nothing back when someone new +picks the project up. Most projects were paying for process that did not repay. If yours is one that does -- several interacting systems, or a design someone else has to implement -- `standard` and `full` are one `/settings` call away, and `/help` and `/gate-check` will suggest raising it as your project grows. diff --git a/design/registry/entities.yaml b/design/registry/entities.yaml index b318786c..216ffa67 100644 --- a/design/registry/entities.yaml +++ b/design/registry/entities.yaml @@ -17,6 +17,8 @@ # # WRITTEN BY: /design-system (Phase 5 — after GDD sections are approved) # /consistency-check (when resolving conflicts) +# economy-designer, systems-designer (new cross-system entries, +# after asking) # READ BY: /design-system (Phase 2 — before authoring begins, and after # Section C/D writes to conflict-check new entities/formulas) # /consistency-check (primary input — grep-first, GDD-second) @@ -25,13 +27,18 @@ # /content-audit (Step 2 — planned named-content count) # /balance-check (Phase 3 — intended constant/formula values) # /propagate-design-change (Step 3 — downstream GDD impact via referenced_by) +# /asset-spec (named entities to write specs for) +# economy-designer, systems-designer (before authoring items, +# loot tables and formulas) # # SEARCH PATTERNS (for skills using Grep): # All entity names: Grep pattern="^ - name:" path="design/registry/entities.yaml" # Specific entity: Grep pattern=" - name: goblin" path="design/registry/entities.yaml" # All items: Grep pattern="^ - name:" path="design/registry/entities.yaml" (items section) # What combat.md owns: Grep pattern="source: design/gdd/combat.md" -# What inventory.md uses: Grep pattern="referenced_by.*inventory" +# What inventory.md uses: Grep pattern="design/gdd/inventory.md" -B 8 +# (referenced_by is a block list, so match the +# path; referenced_by.*inventory never matches) # All gold values: Grep pattern="value_gold:" # Deprecated entries: Grep pattern="status: deprecated" # diff --git a/docs/CLAUDE.md b/docs/CLAUDE.md index 1da32592..06f66249 100644 --- a/docs/CLAUDE.md +++ b/docs/CLAUDE.md @@ -14,7 +14,7 @@ ADR Dependencies, Engine Compatibility, GDD Requirements Addressed - Use `/architecture-decision` to create ADRs through the guided flow **TR Registry:** `docs/architecture/tr-registry.yaml` -- Stable requirement IDs (e.g. `TR-MOV-001`) that link GDD requirements to stories +- Stable requirement IDs (e.g. `TR-movement-001`) that link GDD requirements to stories - Never renumber existing IDs — only append new ones - Updated by `/architecture-review` Phase 8 @@ -30,4 +30,4 @@ ADR Dependencies, Engine Compatibility, GDD Requirements Addressed Version-pinned engine API snapshots. **Always check here before using any engine API** — the LLM's training data predates the pinned engine version. -Current engine: see `docs/engine-reference/godot/VERSION.md` +Current engine: see `docs/engine-reference//VERSION.md` (`` is `godot`, `unity` or `unreal`, matching `engine.name` in `project.yaml`) diff --git a/docs/COLLABORATIVE-DESIGN-PRINCIPLE.md b/docs/COLLABORATIVE-DESIGN-PRINCIPLE.md index e47f731c..4e027fb0 100644 --- a/docs/COLLABORATIVE-DESIGN-PRINCIPLE.md +++ b/docs/COLLABORATIVE-DESIGN-PRINCIPLE.md @@ -365,7 +365,11 @@ pattern: ❌ **Don't use it for:** - Open-ended discovery questions ("What excites you about roguelikes?") - Single yes/no confirmations ("May I write to file?") -- When running as a Task subagent (tool may not be available) +- When running as a subagent (spawned through the `Agent` tool), which never gets + the tool: end with the options as a short labeled list and let the caller ask + +A question that comes back skipped, dismissed or empty is not an answer. Act on +nothing; ask again in plain text and wait (`.claude/docs/automation-modes.md`). ### Format Guidelines @@ -678,16 +682,3 @@ WHEN implementing: 2. Flag any deviations from design docs 3. Ask about ambiguities rather than assuming ``` - ---- - -## Implementation Status - -This principle has been fully embedded across the project: - -- **CLAUDE.md** — Collaboration protocol section added -- **All 49 agent definitions** — Updated to enforce question-asking and approval -- **All skills** — Updated to require approval before writing -- **WORKFLOW-GUIDE.md** — Rewritten with collaborative examples -- **README.md** — Clarifies collaborative (not autonomous) design -- **AskUserQuestion tool** — Used by 68 skills (49 declare it) for structured option UI diff --git a/docs/WORKFLOW-GUIDE.md b/docs/WORKFLOW-GUIDE.md index d0787d6d..1de66133 100644 --- a/docs/WORKFLOW-GUIDE.md +++ b/docs/WORKFLOW-GUIDE.md @@ -1408,7 +1408,7 @@ The system has 12 hooks that run automatically: | `pre-compact.sh` | Before compaction | Logs the compaction (its output does not reach Claude) | | `post-compact.sh` | After compaction | Debug-log reminder only (its output does not reach Claude) | | `notify.sh` | Notification event | Shows Windows toast notification via PowerShell | -| `validate-commit.sh` | Before commit | Checks for design doc references, valid JSON, no hardcoded values | +| `validate-commit.sh` | Before commit | Checks design doc sections, valid JSON, hardcoded values, TODO format | | `validate-push.sh` | Before push | Warns on pushes to main, master or release/* | | `validate-assets.sh` | After a file write | Checks data-file JSON, and asset naming in Godot's `assets/` | | `validate-skill-change.sh` | Skill file written | Advises running `/skill-test` after `.claude/skills/` changes | diff --git a/docs/architecture/tr-registry.yaml b/docs/architecture/tr-registry.yaml index 92cab0e2..a9224f6f 100644 --- a/docs/architecture/tr-registry.yaml +++ b/docs/architecture/tr-registry.yaml @@ -10,19 +10,25 @@ # - When a GDD requirement is reworded (same intent): update `requirement` # text and add a `revised` date. The ID stays the same. # - When a requirement is removed from the GDD: set status: deprecated. -# - When a requirement is split or replaced: set status: superseded-by with -# the new TR-ID(s). +# - When a requirement is split or replaced: set +# status: "superseded-by: TR-[system]-NNN" with the new TR-ID(s), quoted: +# unquoted, the second colon makes the file invalid YAML. # # WRITTEN BY: /architecture-review (appends new entries, never overwrites) # READ BY: /create-stories (embed IDs in stories) +# /dev-story (current requirement text before implementing) # /story-done (look up current requirement text at review time) # /story-readiness (validate TR-ID exists and is active) +# /create-epics (trace requirements to ADR coverage) +# /test-helpers (map requirements to tested systems) +# /adopt (brownfield audit: is the registry there) # -# ID FORMAT: TR-[system-slug]-[NNN] -# system-slug = short slug matching the GDD system name +# ID FORMAT: TR-[system]-[NNN] +# [system] = a short lowercase slug for the system. It is an alias: the +# system's key (system_overrides and the like) is its GDD filename stem # NNN = three-digit zero-padded sequence per system, starting at 001 # -# STATUS VALUES: active | deprecated | superseded-by: TR-[system]-NNN +# STATUS VALUES: active | deprecated | "superseded-by: TR-[system]-NNN" version: 1 last_updated: "" @@ -53,4 +59,4 @@ requirements: [] # requirement: "Old damage formula using raw stats" # created: 2026-03-10 # revised: "" -# status: superseded-by: TR-combat-001 +# status: "superseded-by: TR-combat-001" diff --git a/docs/engine-reference/unreal/plugins/gameplay-ability-system.md b/docs/engine-reference/unreal/plugins/gameplay-ability-system.md index 2a2c1120..2da059cc 100644 --- a/docs/engine-reference/unreal/plugins/gameplay-ability-system.md +++ b/docs/engine-reference/unreal/plugins/gameplay-ability-system.md @@ -212,13 +212,12 @@ public: // Tags // ⚠️ UNVERIFIED FOR 5.7 — `AbilityTags` may be deprecated in favour of - // SetAssetTags()/GetAssetTags(). Reported by the `unreal-specialist` - // agent (2026-08-12), which believed the change landed around 5.5 and - // correctly REFUSED to emit code on a symbol it could not verify. - // NOT SOURCEABLE offline: this repo has no 5.7 API dump to check against, - // and the same knowledge-gap warning that governs the agent governs this - // file. Verify against the UE 5.7 docs before using this snippet, and - // correct both occurrences (here and ~line 328) together. + // SetAssetTags()/GetAssetTags(); the change is believed to have landed + // around 5.5. + // NOT SOURCEABLE — the 5.7 tag API for abilities is not covered by + // docs/engine-reference/unreal/ (no 5.7 API dump). Verify against the UE + // 5.7 docs before using this snippet, and correct both occurrences (here + // and in "Use Tags in Abilities") together. AbilityTags.AddTag(FGameplayTag::RequestGameplayTag(FName("Ability.Attack.Fireball"))); } diff --git a/project.yaml b/project.yaml index 9db12c15..6755ad65 100644 --- a/project.yaml +++ b/project.yaml @@ -4,7 +4,7 @@ schema_version: 1 framework: - version: 1.1.2 + version: 1.1.3 last_upgraded: 2026-09-25 # NOTE: this template ships with no `modes:` block, and the six knobs below must