# Audit scope — what is in, what is out, and why `GAUNTLET.md` Track I ("the audit pack"). This is the first document of that pack — it draws the boundary the other seven (I2–I8) work inside. **Not itself a measurement** — unlike `contract-surface.md`/`wire-format.md`/etc., which are regenerated by a script, this is a judgement call about what an auditor needs to look at, argued from the two things the audience actually has to trust: **where TON can move**, and **what number the player is shown**. Revise it if either boundary moves; do not let it silently drift from `CLAUDE.md`'s repo layout as the codebase grows. ## The one-line scope **In scope: every path TON can move through, and every figure the webapp or bot shows a player.** Out of scope: everything that only produces those paths or figures without itself moving money or making a claim. ## In scope, and why ### 1. All 16 on-chain contracts (`contracts/contracts/*.tolk`) Listed exhaustively in `docs/audit/contract-surface.md` (103 opcode arms, 139 get-methods, 49 outbound message types, 13,384 lines). This is the unconditional core of the audit: Tolk code is the only place TON custody, the ratchet arithmetic, and every CONCEPT.md invariant actually live. Every one of the tracks below cites back to this surface: - **Every message arm** — who may call it and what it does — `docs/audit/sender-gates.md` (Track D1) and `docs/audit/withdraw-surface.md` (Track C9/D, "no admin withdraw path"). - **Every bounce path** — `docs/audit/bounce-coverage.md` (Track D7), because TON's delivery model makes the failure path a second code path per send, not an edge case. - **Every subtraction that could go negative** — `docs/audit/money-arithmetic.md` (Track D3), TVM integers are signed so this is a real class of bug, not paranoia. - **The nine `CLAUDE.md` invariants** (`k < 1`, `S` never decremented, `T`'s three-term identity, the 100%-closed split, `flush()`'s floor guard, no admin withdraw, the `PRIME_UPLIFT` bound, `PATRON_CAP`, one route per number) — `docs/audit/ invariant-coverage.md` and `docs/audit/test-coverage-map.md`, each invariant paired with the spec file that pins it, not just a citation to CONCEPT.md. - **Wire format** — `docs/audit/wire-format.md`, opcodes and `.tlb` schemas cross-checked against every TypeScript send site (wrappers, backend, webapp, bot), because a contract's own surface only proves the contract is internally consistent, not that every caller agrees with it. - **Reproducible build** — `docs/audit/reproducible-build.md` (Track G10): an auditor who reads source that does not match the deployed bytecode has audited nothing. ### 2. The backend services that gate a money-adjacent claim or hold signing/custody authority Not all six `backend/*` packages carry equal weight; three are custody- or trust-bearing and three are read-only convenience: - **`backend/attribution`** — holds the **voucher-signing key** (`backend/attribution/src/voucher-signer.ts`). A signed voucher is what the ledger's redemption path trusts off-chain; a bug here is a forgeable payout, the off-chain equivalent of a contract authorisation bug. In scope. - **`backend/keeper`** — holds a **TON wallet** (`backend/keeper/src/wallet.ts`) and is the automation that calls permissionless on-chain functions (e.g. `flush()`). It moves no money the contract wouldn't otherwise release to anyone who called the same function, but a compromised or buggy keeper is a live TON-holding process reachable from this repo's code. In scope. - **`backend/read-proxy`** and **`backend/read-index`** — no keys, no custody, but every number the webapp renders under CLAUDE.md rule 4 ("every number the UI shows must map to a public get-method") passes through one of these two. `docs/audit/stat-provenance.md` (Track G/E) is the traceability chain for exactly this reason: a proxy that silently reshapes or invents a figure defeats the get-method guarantee even though the contract itself is correct. In scope for *honesty*, not for custody. - **`backend/event-poller`** — feeds `read-index` from chain events; in scope for the same traceability reason as the two read services, one hop further back. - **`backend/common`** — shared types/utilities with no independent behaviour; covered implicitly wherever the packages that import it are covered, not audited standalone. ### 3. The webapp's numeric surface (`webapp/src`) Not the whole frontend — see §"design/game-feel, out of scope" below — but specifically the claim CLAUDE.md rule 4 makes contract-verifiable: every figure the player sees maps to a get-method, and every parameter to `shared/params.json`. `docs/audit/ stat-provenance.md` is this chain walked end to end; a UI bug that shows a wrong *number* (not a wrong *animation*) is in scope because it breaks the auditor-facing honesty guarantee CONCEPT.md §9.1 makes, independent of whether the underlying contract is right. ### 4. Economic parameter provenance (`shared/params.json` ↔ `sim/`) Not the simulation's code quality — see below — but the **provenance chain**: every sim-derived constant a contract reads must trace to a named `sim/scripts/run_phase1.py` run, per `CLAUDE.md` rule 3 ("never invent an economic parameter"). `docs/audit/ test-coverage-map.md`'s `SimCrossCheck.spec.ts` entry and the forthcoming I8 are the audit's evidence that no contract constant is a hand-picked number with no sim behind it. ## Out of scope, and why - **`sim/` as code.** The Python simulation is the parameter *authority* (rule 3 above), not shipped production code — it never runs against real TON, never holds a key, and its output is checked mechanically against the contracts by `SimCrossCheck.spec.ts` rather than trusted on its own. A bug in `sim/` that produces a wrong constant is caught the same way a wrong constant from any other source would be: by the cross-check, which **is** in scope (§4 above). The simulation's internal code quality is not separately audited. - **`bot/` (the Telegram bot).** Confirmed by reading the code, not assumed: `bot/src` holds no TON key, no mnemonic, and no signing authority of its own (grep for `mnemonic`/`privateKey`/`WalletContractV*` across `bot/src` returns nothing) — every economically meaningful action it exposes (a voucher, a chain fact) is a call *into* `backend/attribution` or a read service, both of which are in scope (§2). The bot is therefore chrome: a `bot.command(...)` wiring bug is a UX defect (tracked in `GAUNTLET.md`/`DECISIONS.md` D-73), not a fund-movement or false-claim risk, so it sits outside the audit pack the same way the webapp's animation layer does. - **`ops/` (deploy, backup, logging infrastructure).** Governs *availability* — whether the service is up, whether a backup exists, whether an alert fires — not custody or correctness of the economic logic. CONCEPT.md §8's "no admin withdraw path, not timelocked, not multisig" already means no `ops/` credential can move contract funds even in the worst case (compromised deploy host, leaked SSH key): the blast radius is service downtime, already tracked as its own concern under `GAUNTLET.md` Track G, not the audit pack. `docs/audit/repo-hygiene.md` (secrets posture, tracked artifacts) is the one `ops`-adjacent question that *is* in scope, because a leaked contract-deploy key or a committed `.env` would be a real finding — that overlap is already covered there, not duplicated here. - **The webapp's design/game-feel layer.** `DESIGN.md` owns this outright (`CLAUDE.md`, `README.md`). Animation timing, ring geometry, colour semantics and copy are real product work but carry no claim an auditor verifies — the *honesty* half (does the ring's fill match the get-method) is in scope under §3 above; whether the ring looks good is not. - **Deleted/historical plan docs** (`docs/phase*-report.md`, `docs/engineering-spec.md`, `GAUNTLET_LOG.md`, etc.). `README.md`'s "retired documents" table is the redirect to where their content now lives (`CONCEPT.md`/`DECISIONS.md`); a comment citing one by section number is provenance, not a live document to audit. - **Tracks J/K/L/N features not yet built** (telemetry, loss-side mechanics, Telegram identity surfaces, the collector audience). None of these exist in shipped code as of this writing — an audit pack describes what exists, not what `GAUNTLET.md` has open. Each becomes in-scope the moment it ships, under whichever of §1–§4 above it falls into (a new opcode → §1, a new webapp number → §3, etc.). ## The one boundary that moves: testnet, not mainnet Per `CLAUDE.md`'s "project status: pre-launch" — there is no mainnet deployment, no real user funds, and contract logic, storage layouts and economic parameters are explicitly free to change without a migration story. This audit pack therefore describes **the contracts and services as deployed on testnet as of the commit each `docs/audit/*.md` file cites**, not a frozen mainnet artifact. Track H ("nothing is done until a transaction hash is in the log block") is the record of what has actually been exercised on chain; where a claim in this pack is code-verified but not yet chain-verified, the relevant Track H item is the citation, not a gap in this document. ## What "in scope" obligates (feeds I2–I8) For everything in §1–§4 above, the pack still owes: - **I2** — the contract surface table (already `docs/audit/contract-surface.md`; I2's job is presenting it as the pack's own page, not re-measuring it). - **I3** — invariant list with the test that proves each (`docs/audit/ invariant-coverage.md`/`test-coverage-map.md` are the source; I3 restates them as one table, no prose). - **I4** — threat model: assets, actors, trust boundaries — this document's §1–§4 *is* the asset/trust-boundary list; I4 adds the actor and attacker-gets-what layer. - **I5** — known limitations and accepted risks, owner-signed — the `DECISIONS.md` entries that accepted a residual risk (e.g. D-47's above-1-TON exception, D-52 while open) are the raw material. - **I6** — deployment story: `docs/testnet-deployment.md` plus `docs/audit/ reproducible-build.md`. - **I7** — build/test reproduction from a clean checkout. - **I8** — economic-parameter provenance, one row per `shared/params.json` constant. Log: written from a fresh read of `docs/audit/*.md`'s existing thirteen files, `CLAUDE.md`'s repo layout, and a direct grep of `bot/src` and `backend/*/src` for key/mnemonic material (confirms `keeper` and `attribution` are the only two backend packages holding signing/ custody authority). No code changed. Not a contract/wire-format change; nothing to prove on chain — this is a documentation-only Track I item.