The telepath audit becomes a guard test, and the audits get a skill

ui-coverage.test.ts fails the suite the moment an engine event has no
client handling (allowlist entries require a written reason) or a
cell/edge-targeting card is missing from the board's aim sets — the
one-at-a-time bug reports become a red test instead. The wizwar-audits
skill documents the three house audits (UI coverage, ledger inspection
by room code, the determinism gate); .claude/skills/ joins the repo so
they travel with it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-23 12:01:22 -04:00
co-authored by Claude Fable 5
parent 813f92d419
commit a4f572a164
3 changed files with 134 additions and 1 deletions
+59
View File
@@ -0,0 +1,59 @@
---
name: wizwar-audits
description: Run the Wiz-War health audits — UI coverage of engine events/cards (the "telepath audit"), live-game ledger inspection by room code, and the pre-deploy determinism gate. Use when asked to audit, when adding cards or events, or when a player reports "the engine did X but I never saw it".
---
# Wiz-War audits
Three recurring audits keep the maze honest. The first is self-enforcing;
the other two are on-demand.
## 1. UI coverage — "the telepath audit" (automated)
`packages/engine/test/ui-coverage.test.ts` runs with every `npm test` and
fails when:
- a GameEvent type has no client handling (no `humanize` case in
`net.svelte.ts`, no fx in `fx.ts`, no modal check in `App.svelte`) and is
not in the test's `SILENT_BY_DESIGN` allowlist — each allowlist entry
needs a reason for why the player sees the information another way;
- a card resolver demanding a cell/edge target is missing from App's
`CELL_CARDS` / `EDGE_CARDS` click-targeting sets (an unaimable cast).
When adding an **event**: give it a `humanize` line at minimum. Private
info (`visibleTo` events carrying cards) deserves the `cardReveal` modal
in App.svelte — see `handRevealedPrivate` / `cardsStolenPrivate` /
`handTakenPrivate` for the pattern. When adding a **card** with a cell or
edge target, add it to the App targeting set; with `params`, wire the
named-card picker (`NAMED_CARDS` + suggestions) or a bespoke control.
The one axis the test cannot judge: whether a `params`-taking card's
input UI actually offers sensible choices. Check that by hand when adding
one (thief → target's steallables, deja-vu → discard contents, etc.).
## 2. Live-game audit by room code
Fetch and replay production ledgers (details in auto-memory
`wizwar-fetch-game-files`):
scp root@104.236.96.198:/var/lib/wizwar/rooms/<CODE>.jsonl <scratchpad>/
Replay with `createGame({playerIds, seed, sets, colors, deckRev})` +
`applyCommand` per command line (see `deploy/replay-verify.mjs`). Stop at
any seq to inspect full state. To ask why a bot did something, rebuild
the state at its turn and call `automatonCommand(viewFor(state, id),
style, tier)` — and if its choice differs from the ledger, the engine
refused it and the fallback burned the turn (the X2XN pattern).
For "which games are open/stalled" sweeps: fetch all `*.jsonl`, replay
each, and report phase / round / humans vs bots / last command's `at`.
## 3. Determinism gate (before deploying engine changes)
deploy/verify-ledgers.sh 104.236.96.198
Strict-replays every production ledger against the local engine; one
refused command fails. A room whose ledger no longer replays becomes
unreachable after restart. Rules changes while games are live need a
`deckRev` bump plus an engine gate (the convention survives the 2026-08
reset to rev 1).