Document GP-DOC-19: Balancing
The Balancing Protocol
"Balanced" must be measurable, or the meta gets tuned by feel and solved in a spreadsheet. GENOPOOL's balancing is a written protocol: a harness, nine numeric health metrics with pass/fail thresholds, and for every failure a designated tuning lever.
The simulator IS the engine
The single most important architectural decision of the project: there is no separate
simulation model. The race engine is written once, in TypeScript (Rapier physics,
enhanced-determinism build, fixed 60 Hz timestep, seeded PRNG), and runs in two places:
- in the browser, the game you play;
- in a headless Node harness, the balancing rig.
Balancing a simplified proxy model and then porting the numbers to the real engine means balancing a different game: the physics is hypersensitive (one friction coefficient moves the meta). One source of truth, bit-for-bit. Python is used only to analyze the CSV files the harness produces, never to simulate a race.
Harness scale
Every campaign is identified by a master seed; genome, map and skill seeds derive from it, so any campaign replays identically. Each CSV embeds the engine git SHA, the master seed and the full parameter snapshot in its header.
| Run | Scale | Feeds metrics |
|---|---|---|
| Meta run | ≥ 50,000 sampled genomes × ≥ 200 maps (mono- and multi-biome), optimal pilot | #1 #2 #3 #4 #5 |
| Skill run | ≥ 20,000 field races (12 creatures, pilot skill drawn in [0, 1]) | #7 #9 |
| Breeding run | ≥ 2,000 greedy min-maxer trajectories × ≥ 20 generations, with and without inbreeding constraint | #6 |
| Landscape run | one-allele neighborhood lattice over ≥ 5,000 genomes | #8 |
Genome sampling is uniform over allele space plus an oversample of the "corners" (extreme genomes), to catch degenerate builds that uniform sampling would miss.
Discipline
one lever per iteration
re-run on the same seeds
compare, journal (parameters → metrics), repeat
- All tuning levers live in a single registry (
BALANCE/ECONOMYconstants), stamped with aBALANCE_VERSION; every parameter change bumps the version and invalidates all previous snapshots and golden vectors. - Any formula change in the genome spec invalidates prior snapshots entirely: full re-run; CSVs from different engine versions are never mixed.
- Distributions are inspected, never just means: a meta can be fine on average and broken at the extremes.
- Release discipline: outcome-affecting parameters exist only compiled under a
BALANCE_VERSIONand ship through a versioned deployment with a fresh snapshot; they are never live-tweaked on production.
Because map seeds are published on-chain (Switchboard) and the engine is deterministic and open-source, every one of these measurements is reproducible by the community. The balancing protocol is an auditable claim, not an internal secret.
The nine meta-health metrics
The thresholds below are the design commitments the engine must satisfy before a balancing snapshot ships. They are targets, not a report; measured campaign values are internal working data and are superseded by each new snapshot.
| # | Metric | Definition | Target (pass) | Fail |
|---|---|---|---|---|
| 1 | Viable build diversity | share of archetypes present in the top decile on at least one biome | ≥ 40 % | < 25 % |
| 2 | No global dominant | share of the 200 maps won by the single best-average genome | ≤ 30 % | > 50 % |
| 3 | Per-biome concentration | win-share per archetype per biome, plus global Gini | no archetype > 25 % on any biome, Gini < 0.45 | any archetype > 40 %, or Gini ≥ 0.55 |
| 4 | Intransitivity | cycle rate over archetype triplets (A beats B on a majority of maps; A>B>C>A) | ≥ 15 % | < 5 % |
| 5 | Meta entropy per rotation | normalized Shannon entropy of winning archetypes over a 48-map rotation | ≥ 60 % | < 45 % |
| 6 | Breeding convergence speed | generations for a greedy min-maxer to reach the 95th percentile on a fixed biome; ceiling of a closed inbred line | ≥ 6 generations, inbred line capped < 90th pct | target hit in ≤ 2 generations, or an inbred line reaches the top decile |
| 7 | Skill vs build decomposition | variance share of finish position explained by pilot skill vs build quality; upset rate | skill 35-55 %, build 35-55 %, each ≥ 30 %; upsets 20-45 % | either factor < 25 % |
| 8 | Landscape smoothness | mean fitness change per single-allele step; density of local optima per biome | mean Δ < 15 % of stat amplitude, > 1 local optimum per biome | Δ > 30 %, or a unique global optimum |
| 9 | EV by skill percentile per tier | prize expectation per race, in % of ticket, by within-band skill percentile | top 30 % positive; median in [-12 %, -8 %]; weak monotonicity; no sub-top-30 profile durably positive | median < -15 %, or top 30 % ≤ 0, or a sub-median profile durably positive |
What each metric protects
- #1 Diversity: many genome archetypes must have somewhere they shine. If stats correlate too positively, one body plan does everything; the lever is hardening the trade-offs in the stat formulas.
- #2 No global dominant: no single genome should win most maps regardless of biome. Protects the entire capture and breeding economy from collapsing onto one blueprint.
- #3 Per-biome concentration: even a specialist's home biome must stay contested; each biome's speed gate mixes several stats rather than rewarding one.
- #4 Intransitivity: a living meta needs rock-paper-scissors cycles between archetypes. A near-total order means one king and a solved ladder.
- #5 Rotation entropy: the hourly map rotation must actually rotate the winners, so niche builds ("freaks") get their hour and hold market value.
- #6 Breeding convergence: the genetics must not be solvable in a spreadsheet: a greedy optimizer needs 6+ generations to approach the frontier, and a closed inbred line must plateau below it. This is what keeps outcrossing, lineages and the specimen market meaningful.
- #7 Skill vs build: the double constraint the whole model rests on: pilot skill must be the dominant, legally decisive factor, while build quality stays significant enough that breeding matters. Both between 35 % and 55 % of outcome variance, with a healthy upset rate.
- #8 Landscape smoothness: breeding must be learnable. One-allele steps should move fitness gently, and each biome should hold several distinct local optima (several viable species), not one chaotic cliff or one global peak.
- #9 EV per tier: the money layer must behave like a competition room, coherent with the published rake:
net(race) = payout(finish_pos) - ticket
payout = pool_net · PAYOUT_SPLIT[pos] // split 65 / 25 / 10 %
pool_net = field_size · ticket · (1 - rake_tier) // rake: T1 12 %, T2 10 %, T3 8 %, T4 7 %, Major 6 %
Strong pilots (top ~30 % of their matchmaking band) finish positive on expectation; the median player pays roughly the rake and nothing more; expectation never decreases as skill rises; and no low-skill profile is durably positive: volume without skill must not pay, which is precisely what separates a contest of skill from everything else.
Built-in sanity check: with a payout split summing to 1, the ticket-weighted mean expectation across a whole tier equals -rake to ±0.5 pt by construction. Any deviation flags an accounting bug in the payout path, not a balance problem.
Failure → lever mapping
Every red metric has a designated lever (terrain gate weights, stamina cost, inbreeding penalty, skill-execution coefficient, rake, matchmaking band width, …), actioned one at a time and journaled. A metric is never "fixed" by re-rolling seeds: the re-run happens on the same seeds, and only the lever moves.