Release 1.1.2 — the default path works end to end

Fix release for 1.1.1: the minimal path end to end, engine commands that
run on Godot, Unity and Unreal, hook warnings you can see, and verdicts
that say when they could not check. Details in CHANGELOG.md; upgrade
steps in UPGRADING.md (v1.1.1 → v1.1.2).

Fixes #67
Fixes #131

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WuJn2FdynEybfL5KC697nJ
This commit is contained in:
Donchitos
2026-09-29 21:32:19 +10:00
co-authored by Claude Opus 5.5
parent 7ed2c3e9c4
commit b21fa0f7f2
383 changed files with 22888 additions and 10618 deletions
@@ -2,171 +2,216 @@
## Skill Summary
`/balance-check` reads balance data files (JSON or YAML in `assets/data/`) and
checks each value against the design formulas defined in GDDs under `design/gdd/`.
It produces a findings table with columns: Value → Formula → Deviation → Severity.
No director gates are invoked (read-only analysis). The skill may optionally write
a balance report but asks "May I write" before doing so. Verdicts: BALANCED,
CONCERNS, or OUT OF BALANCE.
`/balance-check [system-name|path-to-data-file]` identifies the balance domain
(combat, economy, progression, loot, or a data file given directly), reads the
domain's data files from `assets/data/` and `design/balance/`, then reads the
intended values — from `design/registry/entities.yaml` first (its `constants:` and
`formulas:` blocks), and from the system's GDD in `design/gdd/` for anything the
registry does not supply. It compares every data value with its target — a
registry constant's `value`, a registry formula's `output_range`, or the GDD's
range — then runs domain-specific checks, and prints a report with
Data Sources Analyzed, a Health Summary, an Outliers Detected table
(Item/Value | Expected Range | Actual | Issue), Degenerate Strategies, Progression
Analysis, a Priority-ranked Recommendations table and Values That Need Attention.
Inputs it cannot find make the affected section `NOT ASSESSED — NO DATA`, naming
the missing source and `/design-system`, never an estimate; a value with no
target is listed as `no stated range — not judged`. After the report, an
`AskUserQuestion` offers [A] fix now, [B] save the report to
`design/balance/balance-check-[system]-[date].md`, [C] stop; it writes only on
[B]. No director gates are invoked. Health Summary, first match wins: CRITICAL
ISSUES, CONCERNS, NOT ASSESSED, HEALTHY.
---
## Static Assertions (Structural)
Verified automatically by `/skill-test static` — no fixture needed.
Checked against the SKILL.md by `/skill-test spec` — no fixture needed.
- [ ] Has required frontmatter fields: `name`, `description`, `argument-hint`, `user-invocable`, `allowed-tools`
- [ ] Has ≥2 phase headings
- [ ] Contains verdict keywords: BALANCED, CONCERNS, OUT OF BALANCE
- [ ] Contains "May I write" language (optional report write)
- [ ] Contains verdict keywords: HEALTHY, CONCERNS, CRITICAL ISSUES, NOT ASSESSED
- [ ] Has ask-before-write language: the save is an `AskUserQuestion` option that names its target path, and the Write happens only when that option is chosen
- [ ] Has a next-step handoff (what to do after findings are reviewed)
---
## Director Gate Checks
None. Balance check is a read-only analysis skill; no gates are invoked.
None. Balance check is an analysis skill; no gates are invoked in any review mode.
---
## Test Cases
### Case 1: Happy Path — All balance values within formula tolerances
### Case 1: Happy Path — All balance values within their intended ranges
**Fixture:**
- `assets/data/combat-balance.json` exists with 6 stat values
- `design/gdd/combat-system.md` contains formulas for all 6 stats with ±10% tolerance
- All 6 values fall within tolerance
- `design/registry/entities.yaml` has no entries (the shipped empty stub)
- `design/gdd/combat-system.md` gives an expected range for all 6 stats
- All 6 values fall inside their ranges; no degenerate strategy exists
**Input:** `/balance-check`
**Input:** `/balance-check combat`
**Expected behavior:**
1. Skill reads all balance data files in `assets/data/`
2. Skill reads GDD formulas from `design/gdd/`
3. Skill computes deviation for each value against its formula
4. All deviations are within ±10% tolerance
5. Skill outputs findings table with all rows showing PASS
6. Verdict is BALANCED
1. Skill identifies the Combat domain from the argument
2. Skill reads `assets/data/combat-balance.json` (and any combat files in `design/balance/`)
3. Registry has no entries, so the skill uses the GDD alone for the intended ranges
4. Each of the 6 values is compared with its GDD range and none falls outside; the combat checks find no dominant option
5. Report lists `assets/data/combat-balance.json` and `design/gdd/combat-system.md` under Data Sources Analyzed; the Outliers Detected table has no rows
6. Health Summary is HEALTHY
7. Phase 6 `AskUserQuestion` offers [A] / [B] / [C]; nothing is written before the user chooses
**Assertions:**
- [ ] Findings table is shown for all checked values
- [ ] Each row shows: stat name, formula target, actual value, deviation percentage
- [ ] All rows show PASS or equivalent when within tolerance
- [ ] Verdict is BALANCED
- [ ] No files are written without user approval
- [ ] Data Sources Analyzed lists every file read, including the data file and the GDD
- [ ] The empty registry is skipped and the GDD supplies the intended ranges
- [ ] The Outliers Detected table has no rows
- [ ] Health Summary is HEALTHY
- [ ] No file is written before the user picks option [B]
---
### Case 2: Out of Balance — Player damage 40% above formula target
### Case 2: Outlier — Player damage far above its intended range
**Fixture:**
- `assets/data/combat-balance.json` has `player_damage_base: 140`
- `design/gdd/combat-system.md` formula specifies `player_damage_base = 100` (±10%)
- All other stats are within tolerance
- `design/gdd/combat-system.md` gives `player_damage_base` an expected range of 90–110
- All other stats are within range
**Input:** `/balance-check`
**Input:** `/balance-check combat`
**Expected behavior:**
1. Skill reads combat-balance.json and computes deviation for `player_damage_base`
2. Deviation is +40% — far outside ±10% tolerance
3. Skill flags this row as severity HIGH in the findings table
4. Verdict is OUT OF BALANCE
5. Skill surfaces the HIGH severity item prominently before the table
1. Skill reads the data file and the GDD range for `player_damage_base`, and compares each value with its range
2. The Outliers Detected table lists `player_damage_base` with Expected Range 90–110, Actual 140 and an Issue description
3. The Recommendations table has a row for it with a Priority, a Suggested Fix and an Impact
4. Values That Need Attention gives a suggested adjustment with rationale
5. Health Summary is CONCERNS — one outlier a tuning pass can fix, with no degenerate strategy, stalled progression or sinkless loop
6. If the user picks [A] and changes `player_damage_base`, which the combat GDD defines, the skill reminds them to run `/propagate-design-change` on that GDD before committing
**Assertions:**
- [ ] `player_damage_base` row shows deviation of +40%
- [ ] Severity is HIGH for deviations exceeding tolerance by more than 2×
- [ ] Verdict is OUT OF BALANCE when any stat has HIGH severity deviation
- [ ] The HIGH severity item is called out explicitly, not buried in table rows
- [ ] `player_damage_base` appears in the Outliers Detected table with Expected Range 90–110 and Actual 140
- [ ] The Recommendations table ranks the fix with a Priority
- [ ] Health Summary is CONCERNS — not HEALTHY, and not CRITICAL ISSUES without a finding of the critical kind
- [ ] On [A], a fix to a GDD-defined value is followed by the `/propagate-design-change` reminder
---
### Case 3: No GDD Formulas — Cannot validate, guidance given
### Case 3: No Design Targets — Data exists but no GDD or registry defines the ranges
**Fixture:**
- `assets/data/economy-balance.yaml` exists with 10 stat values
- No GDD in `design/gdd/` contains formula definitions for economy stats
- `assets/data/economy-balance.yaml` exists with 10 plain stat values (prices and rates, no faucet/sink loop the data alone could show)
- `design/registry/entities.yaml` has no entries
- No GDD in `design/gdd/` covers the economy
**Input:** `/balance-check`
**Input:** `/balance-check economy`
**Expected behavior:**
1. Skill reads balance data files
2. Skill searches GDDs for formula definitions — finds none for economy stats
3. Skill outputs: "Cannot validate economy stats — no formulas defined. Run /design-system first."
4. No findings table is generated for the economy stats
5. Verdict is CONCERNS (data exists but cannot be validated)
1. Skill records its inputs as FOUND / ABSENT: the data file is FOUND; the registry entries and the economy GDD are ABSENT
2. Skill reads the data file and lists it under Data Sources Analyzed
3. The sections that need intended values (Outliers Detected, and Progression Analysis where it needs a target) are marked `NOT ASSESSED — NO DATA`, naming the missing economy GDD and the empty registry, and naming `/design-system` as the skill that writes them
4. No expected range is invented or inferred from the data itself
5. Health Summary is NOT ASSESSED — the report says the values could not be judged, not that they are fine
**Assertions:**
- [ ] Skill does not fabricate formula targets when none exist in GDDs
- [ ] Output explicitly names the missing formula source
- [ ] Output recommends running `/design-system` to define formulas
- [ ] Verdict is CONCERNS (not BALANCED, since validation was impossible)
- [ ] Skill does not fabricate expected ranges when neither the registry nor a GDD supplies them
- [ ] The affected sections are marked `NOT ASSESSED — NO DATA` rather than shown as empty tables
- [ ] Output names the missing design source (economy GDD in `design/gdd/`, empty `design/registry/entities.yaml`) and `/design-system`
- [ ] Health Summary is NOT ASSESSED — not HEALTHY, and not CONCERNS, since nothing was found wrong
---
### Case 4: Orphan Reference — Balance file references an undefined stat
### Case 4: Registry First — The registry value overrides a contradicting GDD
**Fixture:**
- `assets/data/combat-balance.json` contains a stat `legacy_armor_mult: 1.5`
- `design/gdd/combat-system.md` has no formula for `legacy_armor_mult`
- All other stats have formula definitions and pass validation
- `design/registry/entities.yaml` `constants:` lists `player_damage_base` with `value: 100`, `unit: damage`, `source: design/gdd/combat-system.md` (a registry constant carries a value, not a range)
- `design/gdd/combat-system.md` still says `player_damage_base` range 100–130 (stale)
- `assets/data/combat-balance.json` has `player_damage_base: 125`
**Input:** `/balance-check`
**Input:** `/balance-check combat`
**Expected behavior:**
1. Skill reads all stats from combat-balance.json
2. Skill cannot find a formula for `legacy_armor_mult` in any GDD
3. Skill flags `legacy_armor_mult` as ORPHAN REFERENCE in the findings table
4. Other stats are evaluated normally; those within tolerance show PASS
5. Verdict is CONCERNS (orphan reference prevents full validation)
1. Skill greps `design/registry/entities.yaml` (`^ - name:` with context) before reading the GDD
2. The target for `player_damage_base` is the registry constant's `value`, 100, not the GDD's range
3. 125 differs from the registry value 100, so `player_damage_base` appears in the Outliers Detected table with Expected Range 100 (the registry value) and Actual 125 — although it sits inside the stale GDD range
4. The GDD is still read for any value the registry does not list
5. Data Sources Analyzed lists the registry, the GDD and the data file
**Assertions:**
- [ ] `legacy_armor_mult` appears in findings table with status ORPHAN REFERENCE
- [ ] Orphan references are distinguished from formula deviations in the table
- [ ] Verdict is CONCERNS when any orphan references are found
- [ ] Skill does not skip orphan stats silently
- [ ] The registry is read before the GDD
- [ ] `player_damage_base` is judged against the registry value (100), not the GDD range (100–130)
- [ ] `player_damage_base: 125` is reported as an outlier
- [ ] Data Sources Analyzed includes `design/registry/entities.yaml`
---
### Case 5: Gate Compliance — Read-only; no gate; optional report requires approval
### Case 5: No Argument, Gate Compliance and the Save Path
**Fixture:**
- Balance data and GDD formulas exist; 1 stat has CONCERNS-level deviation (15% above target)
- `review-mode.txt` contains `full`
- Combat data, registry and GDD exist; 1 stat is slightly outside its range
- `project.yaml`: `modes.review_mode: full`
- `modes.automation` resolves to `collaborative`
**Input:** `/balance-check`
**Input:** `/balance-check` (no argument)
**Expected behavior:**
1. Skill reads data and GDDs; generates findings table
2. Verdict is CONCERNS (one stat slightly out of range)
1. Skill asks the user which system to check; user answers "combat"
2. Skill reads data and design targets and prints the report
3. No director gate is invoked
4. Skill presents findings table to user
5. Skill offers to write an optional balance report
6. If user says yes: skill asks "May I write to `production/qa/balance-report-[date].md`?"
7. If user says no: skill ends without writing
4. After the report, `AskUserQuestion` offers [A] fix now, [B] save to `design/balance/balance-check-combat-[date].md`, [C] stop
5. On [B]: the report is written to `design/balance/balance-check-combat-[YYYY-MM-DD].md` (directory created if needed), the write is confirmed, and the skill ends with "Re-run `/balance-check` after fixes to verify."
6. On [C]: nothing is written; open issues are summarized and the same re-run line ends the output
**Assertions:**
- [ ] With no argument, the skill asks which system to check before reading data
- [ ] No director gate is invoked in any review mode
- [ ] Findings table is presented without writing anything automatically
- [ ] Optional report write is offered but not forced
- [ ] "May I write" prompt appears only if user opts in to the report
- [ ] The report is presented before the save option, and the save option names `design/balance/balance-check-[system]-[date].md`
- [ ] Option [B] writes to that path with the date in YYYY-MM-DD form; option [C] writes nothing
- [ ] Both [B] and [C] end with "Re-run `/balance-check` after fixes to verify."
---
### Case 6: Orphan Stat — A data value no GDD or registry defines
**Fixture:**
- `assets/data/combat-balance.json` holds 6 stats plus `legacy_armor_mult: 1.5`
- `design/registry/entities.yaml` has no entries
- `design/gdd/combat-system.md` gives a range for the 6 stats and nothing for `legacy_armor_mult`
- The 6 stats are inside their ranges; no degenerate strategy exists
**Input:** `/balance-check combat`
**Expected behavior:**
1. Every value is compared with its target; the 6 stats are in range
2. No target exists for `legacy_armor_mult`, so it is listed under Values That Need Attention as `no stated range — not judged`
3. It is not an Outliers Detected row, and it is not dropped from the report
4. Health Summary is NOT ASSESSED, naming `legacy_armor_mult` as the value that could not be judged
**Assertions:**
- [ ] `legacy_armor_mult` is reported as `no stated range — not judged`, apart from any outlier
- [ ] The orphan stat is not skipped silently and not judged against a range inferred from the data
- [ ] Health Summary is NOT ASSESSED, not HEALTHY, naming the unjudged value
---
## Protocol Compliance
- [ ] Reads both balance data files and GDD formulas before analysis
- [ ] Findings table shows Value, Formula, Deviation, and Severity columns
- [ ] Does not write any files without explicit user approval
- [ ] Reads the domain's data files (Phase 2) and the registry then GDD (Phase 3) before analysis
- [ ] Compares every data value with its target (registry constant `value`, registry formula `output_range`, or GDD range); a value outside it is an Outliers Detected row, a value with none is `no stated range — not judged`
- [ ] Outliers Detected table uses the columns Item/Value, Expected Range, Actual, Issue; Recommendations uses Priority, Issue, Suggested Fix, Impact
- [ ] A section whose inputs are absent is `NOT ASSESSED — NO DATA`, never estimated, and names the missing source and `/design-system`
- [ ] Writes only when the user picks the save option, and only to `design/balance/balance-check-[system]-[date].md`
- [ ] No director gates are invoked
- [ ] Verdict is one of: BALANCED, CONCERNS, OUT OF BALANCE
- [ ] Health Summary, first match: CRITICAL ISSUES, CONCERNS, NOT ASSESSED, HEALTHY — HEALTHY only when every value was judged against a stated target
---
## Coverage Notes
- The case where `assets/data/` is entirely empty is not tested; behavior
follows the CONCERNS pattern with a message that no data files were found.
- Tolerance thresholds (±10%, ±20%) are implementation details of the skill;
the tests verify that deviations are detected and classified, not the
exact threshold values.
- The case where every input is absent (no data files, no registry entries, no
GDD) is not tested separately; the skill then stops and reports
`NOT ASSESSED — NO DATA` as the whole verdict, naming what was missing and
which skill produces it.
- CRITICAL ISSUES (a degenerate strategy, a stalled progression, a loop with no
sink) is not given its own case; Case 2 pins that an outlier alone is CONCERNS.
- A data-file path argument (Phase 1 "File path given") is not tested; the
domain is then inferred from the file's content.