Vault Breakers: Super Score — Math Specification, draft-v0.2

DEV ONLY · NOT FOR PRODUCTION · NOT FOR CERTIFICATION. Draft, mutable. Internal simulation is not external certification, and nothing in this document may be presented as frozen, final or certified.

draft-v0.2 — DRAFT MATH APPROVED 2026-08-19. Not frozen, not final, not certified, and not yet publishable to DEV. Freeze exit criteria are in the evidence manifest.

Describes draft-v0.2, the tuning pass. draft-v0.1 — the APPROVED unbalanced reference baseline — is superseded and its evidence is retained unchanged under ../evidence/manifest-draft-v0.2.md, including the two Bonus Buy prices that deliberately did not balance.

1. Identity and provenance

FieldValue
Game IDvault-breakers-super-score
Go packagevault_breakers_super_score
Math versiondraft-v0.2
Lifecycle statedraft — mutable
Mechanic versioncount_anywhere_tumble/v1
Canonical configlibs/mathengine/games/vault_breakers_super_score/vault-breakers-super-score.yaml
Config SHA-256fa6d0410d7de619e68b42083e7012b975d70be572a252d0dd60f3debe2ba4fc8
Backend Git SHA5d56362 (see the manifest for the full hash)
Backend branchfeat/vault-breakers-draft-math (not merged, not pushed, not deployed)
RNG algorithm/versionsha256-trunc64-be/go1-alfg#1
Enginelibs/mathengine

Recompute both hashes before trusting this document:

git -C /Users/admin/kiro/backend rev-parse HEAD
shasum -a 256 /Users/admin/kiro/backend/libs/mathengine/games/vault_breakers_super_score/vault-breakers-super-score.yaml

The config SHA-256 is computed from the exact bytes the binary embeds (vault_breakers_super_score.RawYAML()), and pinned by identity_test.go.

2. Units

Every payout, charge value, instant prize and ceiling in this document is a multiple of total bet. There are no paylines and therefore no per-line stake: a count-anywhere game spends the whole stake across the whole grid.

3. Model

PropertyValue
Grid6 reels × 5 rows = 30 cells
Draw modelindependent_cells — all 30 cells drawn independently from one weight table
Evaluationcount-anywhere, no adjacency, no paylines
Bands8–9, 10–11, 12–30. Seven copies pay nothing
Cascaderemove all winning cells, drop survivors, refill, repeat until a snapshot pays nothing
Cascade bound1,000 steps (maxTumbleSteps), a termination guarantee rather than a design value
Ceiling50,000× per game cycle, applied once to base wins, charges, free spins and instant prizes together

Why the draw model matters

The engine historically drew the initial grid as one weighted stop per reel plus a wrapping row window, and refilled cascade cells independently. On a line or ways layout that is invisible. On a count-anywhere layout it is not: the first snapshot and every later snapshot would obey different distributions, so one paytable would mean two different things depending on which step applied it. independent_cells makes them one distribution — and makes each symbol's count Binomial(30, p), which is what puts the exact results in ../evidence/exact/draft-v0.1.md within reach at all.

4. Symbols, weights and the two reel tables

From draft-v0.2 there are two cell tables: the base game's and free spins'. They hold the same symbols and differ in one weight — the charge, at 30 out of 50,000 in the base game and 7,250 in free spins. Within each table all six strips are identical, asserted by TestPack_EveryStripIsIdentical.

That single difference is the whole tuning pass. In v0.1 free spins ran the base reels, so fifteen free spins were worth 15.52× and the reference Bonus Buy prices of 100× and 500× returned 15.52% and 10.94%. The choice was to reprice the buys down to 16.17× and 56.99×, or to make the feature worth its price; v0.2 takes the second. Full weight tables are in ../evidence/exact/draft-v0.2.md.

SymbolWeightpMean/snapshot8–910–1112+
H1 diamond case6,0300.1206003.6185.8414.6429.27
H2 gold bars6,0500.1210003.6302.937.3217.60
H3 cash stacks6,0600.1212003.6361.764.8811.72
H4 bearer bonds6,0650.1213003.6391.172.937.32
L1 thermal cutter6,0700.1214003.6420.581.222.93
L2 keycard6,0760.1215203.6460.490.982.44
L3 crew radio6,0790.1215803.6470.350.741.76
L4 lockpick set6,0800.1216003.6480.250.491.17
MULTIPLIER charge3500.0070000.210
SCATTER robber mask1,1240.0224800.674
SUPER_SCATTER master key160.0003200.0096

Authoring rationale

Eight regular symbols, not six. The approved design named six; eight was measured to be a requirement and approved on 2026-08-19. On 30 cells with an 8-of-a-kind minimum, inventory size sets the hit rate, the hit rate sets the cascade length, and the cascade length sets the largest payout a 96% game can afford:

Regular symbolsSnapshot hit rateWhole-game RTP at scale 1Paytable scale for 96%
655.5%2800.8%0.0336
732.9%330.6%0.2898
819.1%99.8%0.9615
911.3%44.7%2.1581

At six symbols the top band would pay 1.68× and the lowest 0.013×. The reference game has eight regular symbols for this reason.

Near-equal weights. Spreading the paying mass evenly minimises the hit rate for a fixed mass. The skewed table this pack started from (means 2.76 to 6.66) hit 75.4% of snapshots against 55.5% for six equal symbols — the difference between a two-step and a seven-step cascade. The high/low distinction therefore lives in the payouts, not the weights.

The paytable ladder. Authored as a reference-style spread — top symbol at the top band worth 117× the bottom symbol at the bottom band — then scaled once by the factor that lands the whole game on 96.00%. Each band step is roughly 2.5×; each symbol rank step is roughly 1.7×.

MULTIPLIER at 30 in the base game, 7,250 in free spins. Charges are the free-spins mechanic. A paid spin sees one on about 1.9% of rounds; a free spin averages 4.35 per snapshot. That asymmetry is what makes a fifteen-spin feature worth roughly a hundred stakes and therefore worth a 100× price.

SCATTER at 722, SUPER_SCATTER at 22 — on BOTH tables. Keeping the scatter class identical across the two tables means the retrigger rate is the same question as the trigger rate rather than a second thing to reason about.

The class weight is also the final tuning lever, and the correct one: it moves the whole game without moving either buy, because a buy is priced off the sequence award and the sequence award does not depend on how often a sequence is triggered for free. Sizing note for the next pass — P(4+ of the class) does not scale as the fourth power of the class weight over this range; measured across two 100,000,000-round confirmations the effective exponent is about 2.78, and assuming 4 overshot the first correction by a third of a point.

5. Multiplier charges

  • Pool bounded by the design at 2× and 500×; both ends reachable.
  • Base pool mean 3.6850×; Super pool mean 18.6600×, floor 10×.
  • The Super pool mean is 5.06× the base pool's, which is what puts the Super buy at five times the Standard buy's price and holds both at their reference values.
  • A charge's value is drawn once, its cell is freed, and values across one spin's whole sequence are added. The sum multiplies that sequence's aggregate regular-symbol win.
  • A sequence with charges but no regular win pays no multiplier.
  • The accumulator resets per spin, and each free spin runs its own.

Recorded assumption. A charge on the terminal, non-winning snapshot is collected. That snapshot is part of the sequence either way, and a rule conditioned on whether it happened to pay is a rule the simulator and the runtime could quietly disagree about. Flipping this is a one-line change and a re-tune; it is called out because it moves RTP.

6. Scatters

SCATTER and SUPER_SCATTER are one class and count together.

RuleValue
Base trigger4+ scatter-class on ONE snapshot → 15 free spins
Which mode a natural trigger awardsalways Standard — FS_SUPER is BuyOnly
Retrigger3+ scatter-class on ONE free-spin snapshot → +5 spins, repeatable
Snapshot ruleEither the initial grid or any later tumble grid; the first qualifying one owns it
Sequences per wagerAt most one
Instant prize1/2/3/4+ Super Scatters → 100× / 500× / 5,000× / 50,000×, base game only

The trigger is decided on the cascade's per-snapshot census, which the engine records as it runs and reports on the outcome. The settled grid cannot answer the question — by the time the cascade stops the cells have moved — so the runtime consumes the engine's verdict via mathengine.ResolveOutcomeTrigger rather than re-deriving one.

7. RTP decomposition

Method per term is stated. Nothing is counted twice: the four terms are disjoint contributions to one round total, taken from the engine's own per-feature aggregation.

  base regular-symbol RTP        MONTE CARLO
+ base multiplier contribution   MONTE CARLO
+ free-spins contribution        MONTE CARLO   (regular + charge split measured separately)
+ Super Scatter instant prize    MONTE CARLO   (per-snapshot expectation is EXACT)
= whole-game RTP

Measured over 100,000,000 seeded rounds across 16 shards:

TermMethodContribution
base regular-symbol RTPMONTE CARLO76.5053%
base multiplier contributionMONTE CARLO5.0105%
free spins — regular partderived0.5714%
free spins — charge partderived11.9856%
Super Scatter instant prizeMONTE CARLO1.8246%
whole-game RTP95.8973%

RunBatch reports free spins as one number, 12.5570%, because the atomic executor settles a sequence as a lump. It is split by the regular/charge ratio measured on runtime-shaped sequences — 4.55% / 95.45% — which is the same rule the atomic path applies. The split is derived, the total is measured, and neither is counted twice.

Full tables, seeds and shard boundaries are in ../evidence/simulation/draft-v0.1.md and bound by ../evidence/manifest-draft-v0.1.md.

Why the whole game is not exact

mathengine.CheckEnumerable refuses this config, and the refusal is respected rather than worked around. Three separate reasons, each sufficient: a cascade snapshot holds survivors and is no longer i.i.d.; charge values are drawn after the initial grid; free spins are a stochastic sequence. What is exact — one snapshot's regular RTP, hit rate, trigger probability and instant-prize expectation — is in the exact report and is never re-derived by sampling.

8. Tolerance

Approved target: 96.00%. Achievable band: see below — this supersedes the ±0.10 pp proposed on 2026-08-19 before the variance was measured.

The original proposal assumed the Super Scatter prize was the dominant variance term and that computing it exactly would buy the precision. Measurement says otherwise: per-round σ ≈ 15, and the dominant contributor is the charge mechanic, whose sum-of-charges rule is inherently sampled and cannot be Rao-Blackwellised while charge values share the round's RNG stream.

Measured per-round σ = 13.531314.

Sample sizeStandard error95% CI half-width
25,000,0000.271 pp0.530 pp
100,000,0000.135 pp0.265 pp
733,000,0000.050 pp0.098 pp
whole-game RTP = 95.8973%  +/-0.2652 pp   (95% CI, 100,000,000 rounds)
target         = 96.0000%
deviation      = -0.1027 pp  =  0.76 standard errors
verdict        = target inside the interval

Lattice note. One unit of symbol weight out of 50,000 moves whole-game RTP by well under 0.01 pp, so the config lattice is not the binding constraint here — sampling is. That is the opposite of the usual situation and is why the band is stated from the interval.

9. Buy options

Prices are derived, not inherited. The design's 100× and 500× are reference-baseline values and the design itself requires recomputation against the tuned model.

Measured over 200,000 sequences per mode, played the way the runtime plays them — one spin per request, retriggers from the engine's verdict, ceiling ending generation:

ModePriceE[sequence award]95% CIRTP at that priceFair price for 96.00%
Standard100×96.4173×[95.1786, 97.6561]96.4173%100.4347×
Super500×485.2263×[481.6275, 488.8250]97.0453%505.4440×

Both reference prices land within half a percent of fair value. In draft-v0.1 the same prices returned 15.52% and 10.94%; the difference is free spins running their own charge-dense reel table rather than the base one.

How they were held. By making the feature worth its price rather than by repricing it. The alternative — derived prices of 16.17× and 56.99× — was measured, costed and rejected on 2026-08-19; it is recorded in draft-v0.1's simulation report.

10. Max win

Declared ceiling 50,000×, applied once to the whole game cycle.

  • Reachability: witnessed deterministically. A grid holding four Super Scatters triggers and pays the 50,000× band on the snapshot that triggered, settling at exactly the ceiling with Capped set. Recorded in ../evidence/max-win/draft-v0.1.md.
  • Frequency: four Super Scatters on one snapshot is about 1 in 3.5 billion snapshots, so it is a construction rather than a search. Other paths to the ceiling — long charge sequences and free-spin runs — are far more frequent and are reported from the confirmation run.
  • Termination: reaching the ceiling ends mathematical generation. Free spins stop being generated rather than being generated and then clamped, asserted by TestCapTermination_FreeSpinsStopGeneratingAtTheCap.

11. Residual items and known limitations

  1. Free-spin shape. A free-spin snapshot pays a regular win on 8.23% of snapshots against the base game's 19.76%, because charges occupy 14.5% of the grid and every cell a charge takes cannot complete an eight-of-a-kind. 95%+ of a sequence's award is the charge part. Approved for Draft on 2026-08-19 with a condition: a separate DEV playtest before Freeze. Do not smooth it and do not retune it without playtest results — the shape is what is under test, not a defect to fix.
  2. No math-studio authoring preset. DrawModel needs a column in studio_reel_sets and a migration (LayoutType is a column; InitialStops is already dropped by that store), plus multiplier_charge and super_scatter as domain types with validation, build_config translation, feature-store and handler decoding, and count_anywhere in the accepted win types. Until then the pack cannot be seeded through versions/from-pack, the route scripts/seed-magic-vault.sh uses to publish to DEV.

Correction, 2026-08-20 (second). Published to dev and smoke-tested. The Super Scatter instant prize does not pay on the player path: the orchestrator strips free_spins from every base spin and SuperScatterExecutor resolves through the free-spins trigger, so it never fires. 400,000 drawn rounds: full config 55 prizes, player config 0. Against what this spec records, the runtime serves Super Scatter at 0% instead of 1.8246%, whole-game ≈94.07% instead of 95.8973%, and the 50,000× max win is unreachable. The figures here are correct about the approved math and are not rewritten — the gap is in the runtime. Freeze blocker. See evidence/manifest-draft-v0.2.md, second addendum.

Correction, 2026-08-20. Items 2 and 3 above were true when written and are now closed. The table is studio_reelsets, not studio_reel_sets. InitialStops was one of two silent losses — the second was Paytable.WinTiers — closed by migrations 008 and 009; DrawModel by 007. A third identity defect, Paytable.LineDefinitions publishing as [] where the approved pack carries nil, was found by the publishing identity gate and fixed without moving the in-memory value. The DEV admission gate exists. Full identities and the remaining Freeze blockers are in evidence/manifest-draft-v0.2.md, addendum of the same date.

  1. No game-engine DEV admission gate. Deliberate: publishing is out of scope until this Draft is approved.
  2. The free-spins regular/charge split is derived from the feature-conditioned run rather than measured inside the whole-game run; the atomic executor reports a sequence as one number.
  3. Charges collected inside free spins are not itemised; only base-game charges are.

12. Verification

GateCommand
Pack contract, exact, identitygo test -race -count=1 ./libs/mathengine/games/vault_breakers_super_score
Enginego test -race ./libs/mathengine/...
Runtimego test -race ./apps/game-engine/...
Reference↔runtime paritymake test-parity
Vetgo vet ./libs/... ./apps/...
PostgreSQL integrationTEST_DATABASE_URL=... go test -tags integration -race ./apps/game-engine/... ./apps/math-studio/...
Draft evidencego test -tags vbdraft -count=1 -v -timeout 180m ./libs/mathengine/games/vault_breakers_super_score -run Draft

13. Status

draft-v0.2. DRAFT MATH APPROVED 2026-08-19. Not frozen. Not final. Not certified. Not yet publishable to DEV.

Approved: whole-game RTP 95.8973% against a 96.00% target; Standard Buy at 100× returning 96.4173%; Super Buy at 500× returning 97.0453%; max win 50,000×; and the high-volatility, charge-dominant free-spins shape.

The free-spins shape is approved FOR DRAFT with a condition: it must pass a separate DEV playtest before Freeze. Do not smooth it and do not retune it without playtest results.

Not published. Not enabled for any operator. Freeze exit criteria are recorded in ../evidence/manifest-draft-v0.2.md.

AWAITING_USER_APPROVAL — DEV PUBLISHING PLAN.