commit 483ba9f2a208c5ea32ec5ac302e71c96a98ea2e1 Author: drjones Date: Wed Aug 5 01:54:01 2026 +0000 Add Quantum Arcade design spec Co-Authored-By: Claude Opus 5 diff --git a/docs/superpowers/specs/2026-08-05-quantum-arcade-design.md b/docs/superpowers/specs/2026-08-05-quantum-arcade-design.md new file mode 100644 index 0000000..c0fa30f --- /dev/null +++ b/docs/superpowers/specs/2026-08-05-quantum-arcade-design.md @@ -0,0 +1,181 @@ +# Quantum Arcade — Design Spec + +**Date:** 2026-08-05 +**Status:** Approved for planning +**Repo:** https://gitea.thetempleofdoom.com/drjones/casino.git + +## 1. Context and Scope + +Quantum Arcade is a private, LAN-hosted physics gaming platform for the host and +their friends, including at parties of up to ~100 people on phones. It runs +entirely on a single Linux box owned by the host. + +**In scope:** deterministic physics games (group and single-player), a +provably-fair RNG, a double-entry ledger, Lightning deposits/withdrawals and +peer-to-peer transfers, ephemeral chat, and a single-box Docker deployment. + +**Out of scope for this phase:** public internet deployment, KYC/identity +verification, geo-gating, and licensed real-money operation. The architecture +keeps these as additive modules rather than rewrites, but they are not built +here and this system is not to be exposed publicly as-is. + +**Success criteria:** +- A guest joins from a phone in under 5 seconds with no account creation. +- 100 concurrent phones sustain a group round with no visible desync. +- Any player can independently verify any round outcome on their own device. +- End-of-night balances reconcile exactly, with a per-transaction explanation. + +## 2. Identity + +Identity is a keypair, not an account. + +On first visit the browser generates an ed25519 keypair stored in IndexedDB and +prompts for a nickname. The public key is the player ID: it is what the ledger +posts against and what signs bet intents. There is no email, password, reset +flow, or KYC. + +Multi-device: a QR code exports the key from one device to another. +Key loss means balance loss. This is accepted and stated plainly in the UI. + +Nicknames are display-only and non-unique; the pubkey prefix disambiguates. + +## 3. Architecture + +One Go binary with enforced internal module boundaries, plus PostgreSQL, Redis, +LND, and Caddy. Nine separate services on one machine would add latency and +operational burden with no benefit at this scale. + +``` +Caddy (TLS termination, static assets, WebSocket upgrade) + └── quantum-arcade (single Go binary) + ├── ledger/ double-entry postings, append-only + ├── rng/ commit-reveal seed lifecycle + ├── sim/ deterministic physics core + ├── room/ round lifecycle, tick broadcast + ├── wallet/ Lightning in/out, P2P transfers + └── chat/ ephemeral, in-memory only +PostgreSQL ledger, rounds, seeds, results +Redis live room state, presence, rate limits +LND Lightning node, isolated wallet +``` + +Modules communicate only through Go interfaces defined by the *consumer*. No +module imports another's internal types. Extracting a module into its own +process later is a transport change at the call site, not a rewrite. + +**Scaling posture:** 100 concurrent WebSocket clients is a small fraction of a +single Go process's capacity. The genuine constraint is PostgreSQL write +throughput at settlement, addressed by settling each round in exactly one +transaction with batched postings. + +## 4. Deterministic Simulation Core + +The physics core is fixed-timestep and integer-seeded, using fixed-point +arithmetic rather than floating point to guarantee bit-identical results across +platforms. It is compiled twice from one source: natively for the authoritative +server, and to WASM for the browser. + +Consequences: +- The server broadcasts a seed, not a position stream. Bandwidth per additional + phone is negligible. +- Any client can replay any historical round locally. +- The public verifier is simply the sim run against published inputs. + +Determinism is a hard invariant, enforced by test (§9), not a convention. + +## 5. Provable Fairness + +Per round: + +1. **Commit.** Server generates `serverSeed`, publishes `SHA256(serverSeed)` + before the betting window opens. +2. **Client seed.** Derived from the concatenated public keys of all + participants in the round, in join order. The host cannot know the outcome in + advance because the host does not control the inputs. +3. **Outcome.** `HMAC-SHA256(serverSeed, clientSeed || nonce)` seeds the sim. + The crash point / result is a pure function of that seed. +4. **Reveal.** After settlement the server publishes `serverSeed`. Clients + recompute the commitment hash, re-derive the seed, and re-run the WASM sim. + +Verification runs on-device in roughly 400ms and requires trusting no server +response. Seeds, commitments, and participant sets are retained permanently. + +## 6. Games + +All games share the sim core and the fairness pipeline. + +**Group rounds** — a fixed ~5-minute cadence; all players watch the same +simulation. Three crash variants rotate: +- *Rocket vs. gravity* — multiplier is altitude; the craft visibly strains as + fuel depletes toward the seeded crash point. +- *Orbital decay* — multiplier is orbits completed, each pass dipping lower. +- *Stacking tower* — multiplier is height; wobble grows until collapse. + +Round lifecycle: `betting_open` → `locked` → `running` → `settled`. Cash-out +intents are signed by the player key and accepted only while `running`. + +**Single-player** — always available between group rounds, ~10 seconds per play, +one tap to start: gravity-slingshot targeting, physics drop, and a +momentum/timing challenge. Same fairness proof, per-play nonce. + +## 7. Ledger and Money + +Double-entry, append-only. No row is ever updated or deleted; corrections are +compensating entries. + +Every posting records: transaction ID, timestamp, player pubkey, account, +amount, round ID, balance before, balance after. Each transaction's postings sum +to zero. Player balances may never go negative. + +Accounts: per-player balances, house pot, and Lightning bridge accounts. The +house pot balance is displayed in the UI to all players — the pool is never +opaque. + +**Lightning:** deposit and withdraw via invoice/QR against the on-box LND node. +The LND wallet is isolated from application state, with its own credentials and +backup path. + +**Peer-to-peer transfers:** instant, purely internal ledger entries between two +player accounts, signed by the sender's key. This is the primary way value moves +between friends at a party. + +## 8. Interface and Feel + +Phone-first portrait layout; cash-out is thumb-reachable. + +Deep obsidian and indigo ground, with dense ornate filigree etched into the +background. Vibrant cyan and magenta are reserved exclusively for the live +multiplier, the player's balance, and the cash-out control — everything that +matters is luminous, nothing else is. + +Ambient music is synthesized in WebAudio: endless, non-looping, and shipping +with zero audio assets. + +Chat is a compact sidebar, in-memory only, discarded when the round ends. +Nothing is written to disk. + +## 9. Testing + +- **Ledger:** property-based tests for the invariants in §7 — postings sum to + zero, balances never negative, no value created or destroyed across arbitrary + transaction sequences. +- **Sim determinism:** identical seed produces identical output across 10,000 + runs, and native output matches WASM output byte-for-byte. +- **Fairness:** commitment always matches revealed seed; independent + reimplementation of the verifier agrees with the server on recorded rounds. +- **Load:** harness simulating 150 concurrent phone clients through a complete + group round, asserting no desync and correct settlement. + +## 10. Deployment + +`docker compose up` on the single Linux box. Postgres and LND data on persistent +volumes with scheduled backups. Caddy terminates TLS on the LAN. Prometheus and +Grafana included for host and application metrics. + +## 11. Explicit Non-Goals + +- Not exposed to the public internet in this phase. +- No engagement mechanics designed to extend play beyond a player's intent: no + loss-chasing prompts, no artificial near-miss tuning, no dark patterns on + cash-out. Game feel comes from the physics being genuinely good. +- No mixing or obfuscation of fund provenance. The ledger is the product.