- name
- gate-check
- 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, Edit, Agent, AskUserQuestion, Bash(bash "*/.claude/skills/gate-check/../../hooks/yaml-helper.sh" resolve_config *)
- model
- opus
!`bash "${CLAUDE_SKILL_DIR}/../../hooks/yaml-helper.sh" 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
phase. It checks for required artifacts, quality standards, and blockers.
**Distinct from `/project-stage-detect`**: That skill is diagnostic ("where are we?").
This skill is prescriptive ("are we ready to advance?" with a formal verdict).
## Production Stages (7)
The project progresses through these stages:
1. **Concept** — Brainstorming, game concept document
2. **Systems Design** — Mapping systems, writing GDDs
3. **Technical Setup** — Engine config, architecture decisions
4. **Pre-Production** — Prototyping, vertical slice validation
5. **Production** — Feature development (Epic/Feature/Task tracking active)
6. **Polish** — Performance, playtesting, bug fixing
7. **Release** — Launch prep, certification
**When a gate passes** (or the user explicitly accepts a CONCERNS verdict's risks — Section 6), 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.
---
## 1. Parse Arguments
**Target phase:** `$ARGUMENTS` with any `--review <mode>` 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`):
`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 (the
> Collaborative Protocol section) 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 and unit-test artifact items become non-required and the
Section 3 `testing.strict` check is a no-op; the smoke check is not relaxed (Section 2b) —
but at this level `/smoke-check` runs without game tests (its automated row reads
WAIVED), so the build check (`commands.smoke`, else `commands.build`, when set) and
the launch and critical-path checks are the floor — a build nobody launched is
NOT ASSESSED — and a project with no tests can still pass. 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). The retained screenshots
UI and Visual/Feel stories need are not test items: no `qa.level` relaxes them
(Section 2b).
**`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**:
Use `AskUserQuestion`:
- Prompt: "Detected stage: **[current stage]**. Running gate for [Current] → [Next] transition. Is this correct?"
- Options:
- `[A] Yes — run this gate`
- `[B] No — pick a different gate` (if selected, show a second widget listing all gate options: Concept → Systems Design, Systems Design → Technical Setup, Technical Setup → Pre-Production, Pre-Production → Production, Production → Polish, Polish → Release)
Do not skip this confirmation step when no argument is provided.
---
## 2. Phase Gate Definitions
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.**
| 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` |
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 `<system>` → 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?** `<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:
> `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.
---
## 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/<Module>/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:
View on GitHub