Release 1.1.0 — one config file, and a process weight you choose

`project.yaml` at the repo root is now the single source of truth for a
project's configuration, replacing `production/stage.txt`,
`production/review-mode.txt` and `.claude/docs/technical-preferences.md` (all
three still read as a fallback; nothing is force-deleted).

**`modes.rigor` — one question instead of six.** `minimal`, `standard` or
`full` fronts six knobs: `modes.workflow`, `docs.density`, `qa.level`,
`modes.story_granularity`, `modes.review_mode` and `team.size`. It defaults to
`minimal`, which is a change from 1.0's behaviour: the heavier tier was
measured costing several times more to reach working code without producing a
better result, and returning nothing when a fresh developer inherited the
project. Pin `modes.rigor: standard` to keep 1.0's process level.

Also in this release:

- `/settings` to view or change any setting, and `project.local.yaml` for
  per-developer preferences that should not be committed.
- `system_overrides` to hold one system to a higher standard than the rest of
  the project, and `testing.strict` to set per test type whether missing
  evidence blocks a story or warns.
- A story that changes anything the player sees is not closed until the game
  has been launched, observed, and a screenshot retained in
  `production/qa/evidence/`. A parse check is not a run. This holds at every
  rigor level, including `minimal`, where automated tests are waived but the
  look is not.
- The code root is engine-specific and enforced as such: Godot `src/`, Unity
  `Assets/`, Unreal `Source/<Module>/`. Two of the three will not build a
  project laid out any other way.
- Migration tooling for existing projects: `.claude/scripts/migrate-v1-config.sh`
  converts a 1.0 layout, non-destructively by default, with a report to review
  before `--finalize` deletes anything.
- Ask-before-write holds regardless of personal automation settings.

Upgrading from 1.0 or earlier: see UPGRADING.md. Full list of changes:
CHANGELOG.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016xvzG3i7pWQg4LjyDwWMXd
This commit is contained in:
Donchitos
2026-09-23 12:25:11 +10:00
co-authored by Claude Opus 5
parent 984023ddac
commit d05699707f
291 changed files with 24374 additions and 7740 deletions
+456 -219
View File
@@ -1,12 +1,18 @@
---
name: gate-check
description: "Validate readiness to advance between development phases. Produces a PASS/CONCERNS/FAIL verdict with specific blockers and required artifacts. Use when user says 'are we ready to move to X', 'can we advance to production', 'check if we can start the next phase', 'pass the gate'."
description: "Ready to advance between development phases? PASS/CONCERNS/NOT ASSESSED/FAIL with blockers and required artifacts. 'Can we move to production?'"
argument-hint: "[target-phase: systems-design | technical-setup | pre-production | production | polish | release] [--review full|lean|solo]"
user-invocable: true
allowed-tools: Read, Glob, Grep, Bash, Write, Task, AskUserQuestion
allowed-tools: Read, Glob, Grep, Bash, Write, Edit, Agent, AskUserQuestion
model: opus
---
!`source "${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/yaml-helper.sh" 2>/dev/null && resolve_config --keys review_mode,workflow,qa.level,testing.strict,performance.enforce,team.size,project.stage,system_overrides`
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
@@ -27,8 +33,7 @@ The project progresses through these stages:
6. **Polish** — Performance, playtesting, bug fixing
7. **Release** — Launch prep, certification
**When a gate passes**, write the new stage name to `production/stage.txt`
(single line, e.g. `Production`). This updates the status line immediately.
**When a gate passes**, update the stage in both `project.yaml` (set `project.stage: <new-stage>`) AND write the new stage name to `production/stage.txt` (single line, e.g. `Production`). Dual-write keeps backward compatibility with hooks that haven't migrated yet. This updates the status line immediately.
---
@@ -36,13 +41,40 @@ The project progresses through these stages:
**Target phase:** `$ARGUMENTS[0]` (blank = auto-detect current stage, then validate next transition)
Also resolve the review mode (once, store for all gate spawns this run):
1. If `--review [full|lean|solo]` was passed → use that
2. Else read `production/review-mode.txt` → use that value
3. Else → default to `lean`
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, all four directors still run (phase gates are the purpose of lean mode).
**`workflow`** (per `.claude/docs/workflow-modes.md`):
`gate-check` runs project-wide, so it uses the project-level `workflow` for the
gate's overall artifact checklist (the loaded gate file), AND consults
`workflow_overrides.system_overrides.<system>` per-system when validating MVP
GDDs — a system pinned to a higher tier must meet that tier's section count
before the gate passes, regardless of the project-level workflow (see Section 2b,
"Per-system overrides").
> **gate-check honors `workflow` but is exempt from `automation`.** The artifact
> checklist changes per tier; the collaborative prompting protocol (Section 8)
> always applies — a phase gate is a deliberate human checkpoint, never auto-run.
**`qa.level`**: controls test enforcement at phase gates, where `workflow`
controls which artifacts are required. `modes.rigor` sets both together; set
`qa.level` explicitly to vary enforcement alone. At `minimal`, no test gates apply — the
test-evidence / unit-test / smoke artifact items become non-required and the
Section 3 `testing.strict` check is a no-op. At `standard`, Logic + Integration
tests must pass. At `full`, a full coverage check + regression suite are required
(coverage minimum from `qa.coverage_minimum` if set).
**`team.size`**: does not change how many directors spawn at a phase gate — panel
width is `workflow`'s axis (Section 4b). This value affects only the
**specialist depth within each director's review**.
`individual` uses the core specialist set; `small` the standard set; `studio`
adds engine sub-specialists. It never skips a director — skipping directors is
`review_mode`'s job. Both `review_mode` and `team.size` are now fronted by
`modes.rigor` — one rigor choice sets both — and each still overrides that axis
when set explicitly (a full-rigor project gets the `studio` set; lighter tiers
get `individual`).
- **With argument**: `/gate-check production` — validate readiness for that specific phase
- **No argument**: Auto-detect current stage using the same heuristics as
`/project-stage-detect`, then **confirm with the user before running**:
@@ -59,198 +91,129 @@ Note: in `solo` mode, director spawns (CD-PHASE-GATE, TD-PHASE-GATE, PR-PHASE-GA
## 2. Phase Gate Definitions
### Gate: Concept → Systems Design
Each gate's checklist — required artifacts, quality checks, and its workflow-tier
reductions — lives in its own file. **Read only the row for the target phase
transition; never load the others.**
**Required Artifacts:**
- [ ] `design/gdd/game-concept.md` exists and has content
- [ ] Game pillars defined (in concept doc or `design/gdd/game-pillars.md`)
- [ ] Visual Identity Anchor section exists in `design/gdd/game-concept.md` (from brainstorm Phase 4 art-director output)
| 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` |
**Recommended (not blocking):**
- [ ] Concept prototype exists in `prototypes/` with a REPORT.md showing PROCEED verdict
(`/prototype [core-mechanic]`) — skipping this means GDDs may be written for an
idea that hasn't been played. Acceptable if the concept is proven by other means.
Each file states the `full` baseline first, then the `standard` and `minimal`
reductions for that gate. Apply the tier resolved in Section 1.
**Quality Checks:**
- [ ] Game concept has been reviewed (`/design-review` verdict not MAJOR REVISION NEEDED)
- [ ] Core loop is described and understood
- [ ] Target audience is identified
- [ ] Visual Identity Anchor contains a one-line visual rule and at least 2 supporting visual principles
## 2b. Workflow Tier Adjustment
---
Each gate file carries its own tier reductions (see Section 2). Two rules apply
across all of them:
### Gate: Systems Design → Technical Setup
> **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.
>
> **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. Two
> agents found it independently on the same fixture.
**Required Artifacts:**
- [ ] Systems index exists at `design/gdd/systems-index.md` with at least MVP systems enumerated
- [ ] All MVP-tier GDDs exist in `design/gdd/` and individually pass `/design-review`
- [ ] A cross-GDD review report exists in `design/gdd/` (from `/review-all-gdds`)
> **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.
>
> **`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** — `minimal` used to reduce the Polish gate to the smoke check alone, and
> "Performance is within budget" sits in the dropped remainder. Two independent
> agents run against a project breaching three of four budgets both spotted the
> contradiction, both overrode the literal reading to reach FAIL, and both
> flagged it as the call most likely to be wrong. A setting that only works
> because agents disregard a rule is not wired.
**Quality Checks:**
- [ ] All MVP GDDs pass individual design review (8 required sections, no MAJOR REVISION NEEDED verdict)
- [ ] `/review-all-gdds` verdict is not FAIL (cross-GDD consistency and design theory checks pass)
- [ ] All cross-GDD consistency issues flagged by `/review-all-gdds` are resolved or explicitly accepted
- [ ] System dependencies are mapped in the systems index and are bidirectionally consistent
- [ ] MVP priority tier is defined
- [ ] No stale GDD references flagged (older GDDs updated to reflect decisions made in later GDDs)
### 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:
### Gate: Technical Setup → Pre-Production
1. If the block's `system_overrides` lists `<system>` → that tier
2. Else the project-level `workflow`
**Required Artifacts:**
- [ ] Engine chosen (CLAUDE.md Technology Stack is not `[CHOOSE]`)
- [ ] Technical preferences configured (`.claude/docs/technical-preferences.md` populated)
- [ ] Art bible exists at `design/art/art-bible.md` with at least Sections 1–4 (Visual Identity Foundation)
- [ ] At least 3 Architecture Decision Records in `docs/architecture/` covering
Foundation-layer systems (scene management, event architecture, save/load)
- [ ] Engine reference docs exist in `docs/engine-reference/[engine]/`
- [ ] Test framework initialized: `tests/unit/` and `tests/integration/` directories exist
- [ ] CI/CD test workflow exists at `.github/workflows/tests.yml` (or equivalent)
- [ ] At least one example test file exists to confirm the framework is functional
- [ ] Master architecture document exists at `docs/architecture/architecture.md`
- [ ] Architecture traceability index exists at `docs/architecture/requirements-traceability.md`
- [ ] `/architecture-review` has been run (a review report file exists in `docs/architecture/`)
- [ ] `design/accessibility-requirements.md` exists with accessibility tier committed
- [ ] `design/ux/interaction-patterns.md` exists (pattern library initialized, even if minimal)
**Before applying any of them, check the block the other way round: does every
KEY match a system?** `<system>` is the GDD filename stem
(`.claude/docs/workflow-modes.md`), so for each key in `system_overrides`, look
for `design/gdd/<key>.md`. Any key with no matching stem is reported, naming the
key and listing the stems that do exist:
**Quality Checks:**
- [ ] Architecture decisions cover core systems (rendering, input, state management)
- [ ] Technical preferences have naming conventions and performance budgets set
- [ ] Accessibility tier is defined and documented (even "Basic" is acceptable — undefined is not)
- [ ] At least one screen's UX spec started (often the main menu or core HUD is designed during Technical Setup)
- [ ] All ADRs have an **Engine Compatibility section** with engine version stamped
- [ ] All ADRs have a **GDD Requirements Addressed section** with explicit GDD linkage
- [ ] No ADR references APIs listed in `docs/engine-reference/[engine]/deprecated-apis.md`
- [ ] All HIGH RISK engine domains (per VERSION.md) have been explicitly addressed
in the architecture document or flagged as open questions
- [ ] Architecture traceability matrix has **zero Foundation layer gaps**
(all Foundation requirements must have ADR coverage before Pre-Production)
> `system_overrides key 'no-such-system' matches no GDD in design/gdd/. Available stems: combat, inventory, hammer-heat-system. This override is doing nothing.`
**ADR Circular Dependency Check**: For all ADRs in `docs/architecture/`, read each ADR's
"ADR Dependencies" / "Depends On" section. Build a dependency graph (ADR-A → ADR-B means
A depends on B). If any cycle is detected (e.g. A→B→A, or A→B→C→A):
- Flag as **FAIL**: "Circular ADR dependency: [ADR-X] → [ADR-Y] → [ADR-X].
Neither can reach Accepted while the cycle exists. Remove one 'Depends On' edge to
break the cycle."
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.
**Engine Validation** (read `docs/engine-reference/[engine]/VERSION.md` first):
- [ ] ADRs that touch post-cutoff engine APIs are flagged with Knowledge Risk: HIGH/MEDIUM
- [ ] `/architecture-review` engine audit shows no deprecated API usage
- [ ] All ADRs agree on the same engine version (no stale version references)
> **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:
### Gate: Pre-Production → Production
- 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.
**Required Artifacts:**
- [ ] Vertical slice exists in `prototypes/` with a REPORT.md (run `/vertical-slice`) — **recommended, not blocking**; if absent, surface as CONCERNS
- [ ] First sprint plan exists in `production/sprints/`
- [ ] Art bible is complete (all 9 sections) and AD-ART-BIBLE sign-off verdict is recorded in `design/art/art-bible.md`
- [ ] Entity inventory exists at `design/assets/entity-inventory.md` (recommended — run `/asset-spec` with no arguments to generate collaboratively from GDDs + art bible)
- [ ] All MVP-tier GDDs from systems index are complete
- [ ] Master architecture document exists at `docs/architecture/architecture.md`
- [ ] At least 3 ADRs covering Foundation-layer decisions exist in `docs/architecture/`
- [ ] All Foundation and Core layer ADRs have status `Accepted` (not `Proposed`) — stories cannot be unblocked until their governing ADR is accepted
- [ ] Control manifest exists at `docs/architecture/control-manifest.md`
(generated by `/create-control-manifest` from Accepted ADRs)
- [ ] Epics defined in `production/epics/` with at least Foundation and Core
layer epics present (use `/create-epics layer: foundation` and
`/create-epics layer: core` to create them, then `/create-stories [epic-slug]`
for each epic)
- [ ] Vertical Slice build exists and is playable (not just scope-defined) — **recommended, not blocking**; if absent, surface as CONCERNS
- [ ] Vertical Slice has been playtested with at least 1 documented session — **recommended, not blocking**; if absent, surface as CONCERNS
- [ ] Vertical Slice playtest report exists at `production/playtests/` or equivalent — **recommended, not blocking**; if absent, surface as CONCERNS
- [ ] UX specs exist for key screens: main menu, core gameplay HUD (at `design/ux/`), pause menu
- [ ] HUD design document exists at `design/ux/hud.md` (if game has in-game HUD)
- [ ] All key screen UX specs have passed `/ux-review` (verdict APPROVED or NEEDS REVISION accepted)
**Quality Checks:**
- [ ] **Core loop fun is validated** — playtest data confirms the central mechanic is enjoyable, not just functional. Explicitly check the Vertical Slice playtest report.
- [ ] UX specs cover all UI Requirements sections from MVP-tier GDDs
- [ ] Interaction pattern library documents patterns used in key screens
- [ ] Accessibility tier from `design/accessibility-requirements.md` is addressed in all key screen UX specs
- [ ] Sprint plan references real story file paths from `production/epics/`
(not just GDDs — stories must embed GDD req ID + ADR reference)
- [ ] **Vertical Slice is COMPLETE**, not just scoped — the build demonstrates the full core loop end-to-end. At least one complete [start → challenge → resolution] cycle works.
- [ ] Architecture document has no unresolved open questions in Foundation or Core layers
- [ ] All ADRs have Engine Compatibility sections stamped with the engine version
- [ ] All ADRs have ADR Dependencies sections (even if all fields are "None")
- [ ] Manual validation confirms GDDs + architecture + epics are coherent
(run `/review-all-gdds` and `/architecture-review` if not done recently)
- [ ] **Core fantasy is delivered** — at least one playtester independently described an experience that matches the Player Fantasy section of the core system GDDs (without being prompted).
**Vertical Slice Validation** (only run these checks if a Vertical Slice was built):
- [ ] A human has played through the core loop without developer guidance
- [ ] The game communicates what to do within the first 2 minutes of play
- [ ] No critical "fun blocker" bugs exist in the Vertical Slice build
- [ ] The core mechanic feels good to interact with (this is a subjective check — ask the user)
> **Verdict rules for Vertical Slice:**
> - **Slice was built AND any validation item is NO** → verdict is automatically FAIL. A broken
> or unfun vertical slice should not advance to Production.
> - **Slice was not built (skipped)** → downgrade to CONCERNS only, not FAIL. Surface the risk
> clearly: "Advancing without a validated Vertical Slice increases the risk of late-stage design
> pivots. Recommended before committing full production scope." The user decides.
> - Skipping is a valid solo dev or time-constrained call. Shipping a broken one is not.
---
### Gate: Production → Polish
**Required Artifacts:**
- [ ] `src/` has active code organized into subsystems
- [ ] All core mechanics from GDD are implemented (cross-reference `design/gdd/` with `src/`)
- [ ] Main gameplay path is playable end-to-end
- [ ] Test files exist in `tests/unit/` and `tests/integration/` covering Logic and Integration stories
- [ ] All Logic stories from this sprint have corresponding unit test files in `tests/unit/`
- [ ] Smoke check has been run with a PASS or PASS WITH WARNINGS verdict — report exists in `production/qa/`
- [ ] QA plan exists in `production/qa/` (generated by `/qa-plan`) covering this sprint or final production sprint
- [ ] At least one QA plan exists in `production/qa/` covering this production phase — run `/qa-plan` if missing (CONCERNS — advisory, not blocking)
- [ ] QA sign-off report exists in `production/qa/` (generated by `/team-qa`) with verdict APPROVED or APPROVED WITH CONDITIONS
- [ ] At least 3 distinct playtest sessions documented in `production/playtests/`
- [ ] Playtest reports cover: new player experience, mid-game systems, and difficulty curve
- [ ] Fun hypothesis from Game Concept has been explicitly validated or revised
**Quality Checks:**
- [ ] Tests are passing (run test suite via Bash)
- [ ] No critical/blocker bugs in any bug tracker or known issues
- [ ] Core loop plays as designed (compare to GDD acceptance criteria)
- [ ] Performance is within budget (check technical-preferences.md targets)
- [ ] Playtest findings have been reviewed and critical fun issues addressed (not just documented)
- [ ] No "confusion loops" identified — no point in the game where >50% of playtesters got stuck without knowing why
- [ ] Difficulty curve matches the Difficulty Curve design doc (if one exists at `design/difficulty-curve.md`)
- [ ] All implemented screens have corresponding UX specs (no "designed in-code" screens)
- [ ] Interaction pattern library is up-to-date with all patterns used in implementation
- [ ] Accessibility compliance verified against committed tier in `design/accessibility-requirements.md`
---
### Gate: Polish → Release
**Required Artifacts:**
- [ ] All features from milestone plan are implemented
- [ ] Content is complete (all levels, assets, dialogue referenced in design docs exist)
- [ ] Localization strings are externalized (no hardcoded player-facing text in `src/`)
- [ ] QA test plan exists (`/qa-plan` output in `production/qa/`)
- [ ] QA sign-off report exists (`/team-qa` output — APPROVED or APPROVED WITH CONDITIONS)
- [ ] All Must Have story test evidence is present (Logic/Integration: test files pass; Visual/Feel/UI: sign-off docs in `production/qa/evidence/`)
- [ ] Smoke check passes cleanly (PASS verdict) on the release candidate build
- [ ] No test regressions from previous sprint (test suite passes fully)
- [ ] Balance data has been reviewed (`/balance-check` run)
- [ ] Release checklist completed (`/release-checklist` or `/launch-checklist` run)
- [ ] Store metadata prepared (if applicable)
- [ ] Changelog / patch notes drafted
**Quality Checks:**
- [ ] Full QA pass signed off by `qa-lead`
- [ ] All tests passing
- [ ] Performance targets met across all target platforms
- [ ] No known critical, high, or medium-severity bugs
- [ ] Accessibility basics covered (remapping, text scaling if applicable)
- [ ] Localization verified for all target languages
- [ ] Legal requirements met (EULA, privacy policy, age ratings if applicable)
- [ ] Build compiles and packages cleanly
> **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.
---
@@ -266,27 +229,132 @@ increased scrutiny on those specific checks.
For each item in the target gate:
### Artifact Checks
- Use `Glob` and `Read` to verify files exist and have meaningful content
- Don't just check existence — verify the file has real content (not just a template header)
- For code checks, verify directory structure and file counts
**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.
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 → `tests/` must actually contain test
> files and the project must have a runner. "24 passed, 0 failed" in a repo
> with no `tests/unit/`, no `tests/integration/` 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.
> This was found by handing a gate a one-page fabricated smoke report on a
> two-file repo; it cleared on existence plus a verdict-line grep.
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, 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."
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.
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.
### Quality Checks
- For test checks: Run the test suite via `Bash` if a test runner is configured
- For design review checks: `Read` the GDD and check for the 8 required sections
- For performance checks: `Read` technical-preferences.md and compare against any
profiling data in `tests/performance/` or recent `/perf-profile` output
- For localization checks: `Grep` for hardcoded strings in `src/`
- 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** — failures in `tests/unit/`, gated by `testing.strict.logic`.
- **Integration** — failures in `tests/integration/`, gated by `testing.strict.integration`.
- For each type: take `testing.strict.<type>` 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 `src/` implementations
- 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
@@ -306,24 +374,54 @@ For items that can't be automatically verified, **ask the user**:
## 4b. Director Panel Assessment
**Apply review mode before spawning any director:**
- `solo` → skip all four directors. Note in output: "Director Panel skipped — Solo mode. Gate verdict based on artifact and quality checks only." Proceed to Phase 5.
- `lean` → spawn all four directors (phase gates always run in lean mode — this is their purpose).
- `full` → spawn all four directors as normal.
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.
(Review mode was resolved in Phase 1. Use that stored value here.)
**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.
Before generating the final verdict, spawn all four directors as **parallel subagents** via Task using the parallel gate protocol from `.claude/docs/director-gates.md`. Issue all four Task calls simultaneously — do not wait for one before starting the next.
**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:
**Spawn in parallel:**
| `workflow` | Panel | Directors |
|---|---|---|
| `minimal` | 1 | `producer` |
| `standard` | 2 | `technical-director`, `producer` |
| `full` | 4 | `creative-director`, `technical-director`, `producer`, `art-director` |
1. **`creative-director`** — gate **CD-PHASE-GATE** (`.claude/docs/director-gates.md`)
2. **`technical-director`** — gate **TD-PHASE-GATE** (`.claude/docs/director-gates.md`)
3. **`producer`** — gate **PR-PHASE-GATE** (`.claude/docs/director-gates.md`)
4. **`art-director`** — gate **AD-PHASE-GATE** (`.claude/docs/director-gates.md`)
`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: target phase name, list of artifacts present, and the context fields listed in that gate's definition.
**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. Run `/gate-check --review full` or set `modes.workflow: full` for
the complete panel." A silently narrow panel reads as a clean bill of health from
reviewers who never looked.
**Collect all four responses, then present the Director Panel summary:**
```
@@ -376,12 +474,82 @@ Art Director: [READY / CONCERNS / NOT READY]
- [Priority actions to resolve blockers]
- [Optional improvements that aren't blocking]
### Verdict: [PASS / CONCERNS / FAIL]
### 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
- **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
```
**`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
@@ -418,7 +586,14 @@ Do NOT reference the draft verdict text — re-check specific files or ask the u
**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:
@@ -428,23 +603,77 @@ Do NOT reference the draft verdict text — re-check specific files or ask the u
## 6. Update Stage on PASS
When the verdict is **PASS** and the user confirms they want to advance:
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`.
1. Write the new stage name to `production/stage.txt` (single line, no trailing newline)
2. This immediately updates the status line for all future sessions
### 6.1 Primary write — `project.yaml`
Example: if passing the "Pre-Production → Production" gate:
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 `<new-stage>`):
```yaml
project:
stage: <new-stage>
```
- **If `project.yaml` does not exist at all**: create it with the Write tool using
this v1.1 minimal template (replace `<new-stage>` and the date):
```yaml
# CCGS project configuration — single source of truth for project settings.
# Schema: grep the `## <key>` 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.0
last_upgraded: <YYYY-MM-DD>
project:
stage: <new-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. Test Y.6 locks this in.
### 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
echo -n "Production" > production/stage.txt
mkdir -p production && printf '%s' "Production" > production/stage.txt
```
**Always ask before writing**: "Gate passed. May I update `production/stage.txt` to 'Production'?"
### 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`)?"
### 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.
---
## 7. Closing Next-Step Widget
After the verdict is presented and any stage.txt update is complete, close with a structured next-step prompt using `AskUserQuestion`.
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:**
@@ -515,8 +744,16 @@ Based on the verdict, suggest specific next steps:
- **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?** → Create `design/difficulty-curve.md` from the template at `.claude/docs/templates/difficulty-curve.md` — or use `/quick-design "difficulty curve"` for a guided session.
- **No player journey map?** → Create `design/player-journey.md` from the template at `.claude/docs/templates/player-journey.md` — or author it collaboratively using `/ux-design` Phase 2b.
- **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`