- DECISIONS.md: in-game chat (player↔player and human↔Gemma) deferred
indefinitely. Blind-mode chat is a side channel that defeats the
moderator-vocabulary security boundary; chat with Gemma leaks belief
state mid-game. Resolvable but expensive — revisit only on demand.
- Spec: same deferral noted in "Out of scope".
- New plan: docs/superpowers/plans/2026-04-28-ai-player-phase-1-casual.md
— 13 tasks, 80 sub-steps. Phase 1 only (Casual bot end-to-end). Phase 2
(Recon) gets its own plan once Phase 1 outcomes inform Recon's target.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Updates CLAUDE.md "Current State" + "Key files" to point at the new spec.
Adds DECISIONS.md "AI / computer player" section (11 settled decisions).
Strikes through the prior "Client-side AI / hint generation — out of scope"
row with a "partially superseded" note: the reversal applies only to the
human-vs-AI path. Adds 7 new Deferred/Rejected rows for AI-feature scope.
Handoff at .claude/handoffs/2026-04-28-170713-ai-player-spec.md captures
session state for the next pickup (writing-plans → Phase 1 implementation).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two-phase plan: Casual bot first (algorithmic, ~200 LoC), then Recon bot
(gemma4:26b chat agent) with persistent private chat history per game.
Bots play through the same view filter and FSM as humans — no oracle access.
Endpoint priority: steel141 RTX 3090 Ti primary, pve197 V100 fallback. Mid-game
GPU failover allowed (one-way). Reasoning hidden from user during play, revealed
in collapsible post-game panel.
Reverses the 2026-04-28 DECISIONS.md row "Client-side AI / hint generation —
explicitly out of scope." Reversal is partial: human-vs-human hint generation
remains rejected; this spec only adds AI in the human-vs-AI path.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Svelte 5 $effect tracks every $state read inside its body. The
lifecycle effect that calls game.connect(gameId) implicitly read
state.ws (inside connect()) and then wrote to it, producing an
effect_update_depth_exceeded loop. Symptom in production: the
browser opened ~12 WS connections/sec, none completed the upgrade
handshake, and the lobby flow appeared stuck on 'waiting for
opponent' (the opponent's WS never stabilized long enough for the
server to send 'joined'). untrack() opts the call out of dep tracking.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Svelte 5 runes ($state, $derived, $effect) only run through the
compiler in .svelte and .svelte.ts/js files. A plain .ts file leaves
$state(...) as a literal call at runtime, causing
"ReferenceError: $state is not defined" and a blank page.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>