Restructure balancing docs into docs/balancing/
This commit is contained in:
98
docs/balancing/process.md
Normal file
98
docs/balancing/process.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# Balancing Process
|
||||
|
||||
How balancing is done in this project: the pass order, the tuning
|
||||
discipline, and the tools. Refer to this when starting the next
|
||||
balancing round.
|
||||
|
||||
## The pass order
|
||||
|
||||
Each pass depends on the ones before it; a change in an earlier pass
|
||||
invalidates the later ones (but not vice versa). Redo from the earliest
|
||||
pass whose inputs changed.
|
||||
|
||||
1. **Targets** (`targets.md`) — choose the root numbers: run shape,
|
||||
factory curve, threat-cost ladder, fleet size, block roots, combat
|
||||
anchors, pacing anchors. These are design decisions, not
|
||||
measurements. Everything else is derived from them.
|
||||
2. **Tree structure** (`../content_design.md`) — items, chains,
|
||||
what-consumes-what, per the production tree rules (one input per
|
||||
phase transition, generic parts, archetypes, refactorability).
|
||||
Structure only, no quantities.
|
||||
3. **Numbers** (`derived.md`, recipes/materials in the configs) —
|
||||
quantities and durations so every fitted ship sums to its ladder
|
||||
value, the ratio curve is realized, and the belt/buffer guardrails
|
||||
hold. Verified computationally by `tools/threat_report.py`.
|
||||
4. **Calculator/tooling parity** — the game's `ThreatCostCalculator`
|
||||
and `tools/threat_report.py` must produce identical values; the
|
||||
Python tool is the design reference. Any semantic change to
|
||||
REQ-THREAT-* needs both updated plus tests.
|
||||
5. **Combat stats** (arena-driven) — derive stats from the combat
|
||||
anchors, then iterate against the arena suite
|
||||
(`bin/balancing/data/balancing.toml`) until equal-threat matchups are
|
||||
near-draws. Threat costs are stat-independent, so arena ship counts
|
||||
stay valid across stat changes.
|
||||
6. **Pacing** — unlock ladder, `unlock_requires` edges, threat rate,
|
||||
block/artifact/expansion values, per the pacing anchors.
|
||||
|
||||
Then: **full-game playtests**, which are the only check for the pacing
|
||||
pass and feed back into targets.
|
||||
|
||||
## Tuning discipline (learned in arena rounds 1–5)
|
||||
|
||||
- **Change anchors, not symptoms.** When a class of results is off,
|
||||
adjust the anchor that explains all of them (e.g. the concentration
|
||||
tax) rather than individual stats.
|
||||
- **Fewest knobs per round.** Attribution dies when many knobs move at
|
||||
once. Prefer one anchor change plus its mechanical compensations.
|
||||
- **Shared vs. local knobs.** Guns and module stats are shared across
|
||||
many hulls — changing them moves many matchups. Per-hull HP moves
|
||||
exactly one matchup; it is the designated per-ship trim knob on top of
|
||||
the HP-per-threat prior.
|
||||
- **Mind the ride-alongs.** A module buff lands on every default loadout
|
||||
containing it (e.g. an armor buff strengthens the destroyer swarm that
|
||||
opposes the dreadnought). Compute the net effect per matchup before
|
||||
choosing step sizes.
|
||||
- **Two-round signal policy.** Single arena runs re-roll by ~±10% EHP
|
||||
margin; a margin inside ±20% counts as converged for v1. Only act on
|
||||
signals that persist across two rounds.
|
||||
- **Arena geometry is part of the fixture.** Lane width/height changes
|
||||
the results (full engagement vs. fleets slipping past); margins are
|
||||
only comparable within the same geometry.
|
||||
- **Accept mechanical texture.** Not every deviation is a bug: a margin
|
||||
that survives a stat change is mechanical (usually range/kiting under
|
||||
the orbit AI) and may be desirable doctrine texture. Document the
|
||||
acceptance in `targets.md` instead of chasing it.
|
||||
- **Range is the strongest stat** under the orbit AI — free approach
|
||||
fire. Price range modifiers conservatively; station dominance is
|
||||
controlled via range, not HP.
|
||||
|
||||
## Tools
|
||||
|
||||
- `tools/threat_report.py` — item threats, module contributions,
|
||||
hull/fitted ship threats, producer:consumer ratios, belt feasibility;
|
||||
reads the real configs. The design reference for threat semantics.
|
||||
- `tools/verify_recipes.py` — recipe tree closure, visuals coverage,
|
||||
orphans, reprocessing-only items.
|
||||
- `tools/verify_layouts.py` — module footprint gating matrix per hull.
|
||||
- **Balancing tool** (`balancing` target) — parallel arena simulation of
|
||||
`bin/balancing/data/balancing.toml`; logs winner, surviving counts,
|
||||
team EHP %, and fight duration per arena. The suite covers: class
|
||||
mirrors (expect near-mutual annihilation, symmetric winners),
|
||||
equal-threat cross-tier matchups (expect near-draws — power-per-threat
|
||||
made empirical), a 2:1 decisiveness check, doctrine matchups
|
||||
(armored-vs-glass, repair-escort), and station assault.
|
||||
|
||||
## Checklist for the next balancing round
|
||||
|
||||
1. Pull; run `verify_recipes.py`, `verify_layouts.py`,
|
||||
`threat_report.py`; compare against the tables in `derived.md`.
|
||||
2. If recipes/materials changed: re-check fitted threats vs. the ladder
|
||||
in `targets.md`; update arena suite ship counts if fitted values
|
||||
moved.
|
||||
3. Run the arena suite; read EHP margins and durations against the
|
||||
expectations noted in `balancing.toml` and the anchors.
|
||||
4. Apply changes per the tuning discipline (two-round signals only);
|
||||
record the round and its knob changes in `history.md`.
|
||||
5. Update `derived.md` where values moved; if an anchor moved, update
|
||||
`targets.md` and state why.
|
||||
6. Commit and push (the review workflow reads the remote).
|
||||
Reference in New Issue
Block a user