Portfolio demo · fictional game · QA against docs/RULES.md

Comet Coins

Generated 2026-11-045,000 captured roundsPlaywright: desktop + phonePlay the gameRules
Verdict
GO, with 1 item to watch

Every captured round re-derives exactly from the rules (5,000 rounds, 0 mismatches), the balance never drifts, and the observed RTP, hit rate and Coin Burst frequency match the exact model. One statistical flag on reel 1 did not reproduce in 5 fresh sessions, so it's recorded as a watch item, not a bug.

24Pass
0Fail
1Watch
2Notes

Findings

Watch · S-4.1

Reel 1 stop distribution flagged in one capture

Seen
chi² 62.86 on 29 df, p < 0.001 in the main capture (seed 2026)
Re-test
5 fresh sessions of 5,000 rounds: every reel p > 0.01 (lowest 0.036)
Call
Not reproduced, so not a bug. Keep watching in future captures.
Note · engineering

Use a stronger random number generator in production

Why
The demo engine uses a small seeded PRNG (mulberry32), fine for replayable tests, not for real money or prizes.
Suggest
A cryptographic RNG on the server, with the seed kept for audit.
Self-test · M-3

The verifier catches a 1-cent overpay

How
One winning round in a copy of the capture was raised by 0.01.
Result
Flagged exactly that round: total win differs: expected 0.8, got 0.81

Maths and statistics

The verifier (tools/verify.js) was written from the rules document, not from the game code. The exact model goes through all 27,000 stop combinations.

5,000 / 5,000rounds re-derive exactly
94.781%exact RTP (observed 90.28%, z -1.70)
38.72%exact hit rate (observed 38.98%, z 0.37)
1 in 125Coin Burst (observed 41 in 5,000)
25.6×highest possible win (cap 500× never reached)
1.87×standard deviation per round
Re-test sessionReel 1 pReel 2 pReel 3 p
Main capture (seed 2026)< 0.0010.4150.253
Fresh session, seed 110.0360.2720.649
Fresh session, seed 230.2830.0860.272
Fresh session, seed 570.6810.9710.991
Fresh session, seed 1010.8890.6410.472
Fresh session, seed 4040.7320.0370.501

All checks

ResultCheckAreaActual
PassPW §1 loads with the start balance and the lowest play amountBehaviour · desktopPassed in Playwright
PassPW §8 − and + step through every play amount and disable at the endsBehaviour · desktopPassed in Playwright
PassPW §8 controls are locked while a round playsBehaviour · desktopPassed in Playwright
PassPW §7 balance after every round = before − play + win (20 rounds, mixed amounts)Behaviour · desktopPassed in Playwright
PassPW §3–§7 every round the server returns re-verifies independently (100 rounds)Behaviour · desktopPassed in Playwright
PassPW §7 a play larger than the balance is refused with no round and no debitBehaviour · desktopPassed in Playwright
PassPW §8 history lists the last rounds, newest first, with the right winsBehaviour · desktopPassed in Playwright
PassPW §1 nothing on screen uses gambling wording ("bet", "wager", "cash")Behaviour · desktopPassed in Playwright
PassPW §1 loads with the start balance and the lowest play amountBehaviour · phonePassed in Playwright
PassPW §8 − and + step through every play amount and disable at the endsBehaviour · phonePassed in Playwright
PassPW §8 controls are locked while a round playsBehaviour · phonePassed in Playwright
PassPW §7 balance after every round = before − play + win (20 rounds, mixed amounts)Behaviour · phonePassed in Playwright
PassPW §3–§7 every round the server returns re-verifies independently (100 rounds)Behaviour · phonePassed in Playwright
PassPW §7 a play larger than the balance is refused with no round and no debitBehaviour · phonePassed in Playwright
PassPW §8 history lists the last rounds, newest first, with the right winsBehaviour · phonePassed in Playwright
PassPW §1 nothing on screen uses gambling wording ("bet", "wager", "cash")Behaviour · phonePassed in Playwright
PassM-1 Every captured round re-derives from the rules (lines, wilds, Coin Burst, cap, rounding, balance)Maths5,000 rounds, 0 mismatches
PassM-2 Balance chains from round to round with no driftMathsEach round starts at the previous round's end balance
PassM-3 Verifier self-test: it catches a planted 1-cent overpayMaths1 mismatch found in the tampered capture (R01003)
PassS-1 Observed RTP is consistent with the exact modelStatistics90.28% vs 94.781% (z -1.70)
PassS-2 Hit rate is consistent with the exact modelStatistics38.98% vs 38.72% (z 0.37)
PassS-3 Coin Burst frequency is consistent with the exact modelStatistics41 in 5000 vs 1 in 125 (z 0.16)
WatchS-4.1 Reel 1 stops are uniformStatisticschi² 62.86 on 29 df, p < 0.001 · not reproduced in 5 re-tests
PassS-4.2 Reel 2 stops are uniformStatisticschi² 29.98 on 29 df, p = 0.415
PassS-4.3 Reel 3 stops are uniformStatisticschi² 33.63 on 29 df, p = 0.253
NoteQ-1 Cap before or after rounding? (§9)Open questionObserved: cap first, then round down. The highest possible win is 25.6× play, so the 500× cap is never reached
NoteQ-2 RTP (§9, not stated)Open questionExact RTP 94.781% from all 27,000 stop combinations

How it was tested

The game was played in Chromium (desktop and Pixel 7 emulation) with Playwright, which also captured each round's payload. Every payload was re-checked by the independent verifier. A separate capture of 5,000 rounds fed the statistics. Statistical flags were re-tested on fresh sessions before any call was made. Everything here can be reproduced with npm run all.