Files
blind_chess/CLAUDE.md
T
claude (blind_chess) 077330054b docs: table-fidelity batch deployed to both instances
Deployed 2026-05-18 to CT 690 (chess.sethpc.xyz) and chess.local
(VDJ-RIG); both verified serving the new client build. CLAUDE.md and
the handoff updated to deployed state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 21:09:02 -04:00

7.3 KiB

blind_chess

Web-based two-player chess where each player sees only their own pieces; the server acts as moderator.

Start Here

Read the latest handoff first: .claude/handoffs/ (most recent file).

Then check DECISIONS.md for settled choices, and the design specs:

  • docs/superpowers/specs/2026-04-28-blind-chess-design.md — original MVP spec (data model, protocol, FSM, testing).
  • docs/superpowers/specs/2026-04-28-ai-player-design.md — AI/computer player spec (Casual + gemma4 recon bots, two-phase plan).
  • docs/superpowers/specs/2026-05-18-table-fidelity-features-design.md — table-fidelity batch (announce-all, capture tally, phantom opponent-piece layer).

Project Identity

A digitization of a battleship-style chess variant. Two players, separated; a moderator who sees both boards and announces a fixed vocabulary of events ("Black has moved and captured", "Moving that piece will not help you", "White is in check"). The physical version requires three people; this version replaces the moderator with a server. Ships with both vanilla mode (full reveal — normal chess) and blind mode (the variation) on day one. Mode is a per-player view filter on a shared engine, not a different game.

The system's most distinctive property: highlighting in blind mode reveals zero opponent information. It's computed purely from (piece type, position, own-piece set) — a function whose signature literally cannot read opponent state. The moderator vocabulary is the only legitimate channel for opponent events.

Current State

  • Phase: MVP deployed and live at https://chess.sethpc.xyz (2026-04-28). AI Phase 1 (Casual bot) deployed (2026-04-28) — "Play vs computer" → Casual bot. Blind Casual check-resolution fix shipped (2026-04-29). Table-fidelity feature batch deployed (2026-05-18) — moderator announces every move/attempt to both players, a capture tally, and a client-local phantom opponent-piece layer for blind mode; live on both instances (CT 690 + chess.local). Client UI not yet manually browser-tested.
  • Repo: git.sethpc.xyz/Seth/blind_chess.
  • Stack: Node 22 + TypeScript, Fastify + ws, Svelte 5 + Vite, chess.js, js-chess-engine (Casual vanilla AI). pnpm workspace with packages/{server,client,shared}.
  • Deploy: LXC CT 690 on node-241 at 192.168.0.245, behind Caddy CT 600. Systemd unit blind-chess.service, port 3000. In-memory state only.
  • Tests: 87 passing — 25 in shared (geometric + phantom-model helpers), 62 in server (FSM + view + candidates + casual brain + driver + captures + scripted-game + ai-game-casual integration). The client package has no test harness by design.
  • Known gaps (deferred): drag-and-drop for real moves (still click-to-move; the phantom layer added pointer-drag for phantom pieces only), full integration coverage of every endgame path, mobile-specific polish, observability beyond /api/health and [bot resign] (no metrics, no per-game tracing), localStorage cleanup for phantom layers of abandoned games.
  • AI Phase 2 (gemma4 recon, not built): Spec in docs/superpowers/specs/2026-04-28-ai-player-design.md. Will reuse the Phase 1 Brain/BotDriver infrastructure. Plan to be written when Phase 1 has soaked. Bots play through the same view filter and FSM as humans — no oracle access.

Key files

  • IDEA.md — original project brief (Seth's words)
  • DECISIONS.md — locked architectural and gameplay decisions
  • docs/superpowers/specs/2026-04-28-blind-chess-design.md — full design spec (data model, protocol, FSM, testing)
  • docs/superpowers/specs/2026-04-28-ai-player-design.md — AI/computer player spec (Casual + gemma4 recon, two-phase plan, endpoint priority list, acceptance bars)
  • packages/shared/src/geometric.ts — the zero-leak helper. The signature is the proof.
  • packages/server/src/view.tsbuildView, the security boundary.
  • packages/server/src/commit.ts — touch-move FSM (the spec's hierarchy decision table).
  • packages/server/src/translator.ts — chess.js Move → moderator-vocabulary enum.
  • packages/server/src/captures.tscaptureTally, the per-viewer capture-count derivation (Feature 2).
  • packages/server/src/game-end.ts — shared endGame / finalizeIfEnded helpers used by both ws and bot driver.
  • packages/server/src/bot/ — Brain interface, BotDriver, CasualBrain, candidates. Vanilla mode delegates to js-chess-engine at level 2; blind mode uses a heuristic.
  • packages/client/src/lib/stores/phantoms.svelte.ts — client-LOCAL phantom opponent-piece store (Feature 3). Never sent to the server; phantom-drag.svelte.ts is its pointer-drag controller.
  • scripts/selfplay.ts — operator CLI for evaluating Casual vs Casual / Random self-play. pnpm selfplay --help.
  • deploy/blind-chess.service — systemd unit (canonical at /etc/systemd/system/blind-chess.service on the CT).
  • deploy/Caddyfile.snippet — block already added to /etc/caddy/Caddyfile on CT 600.

Operations

  • Logs: ssh root@192.168.0.245 'journalctl -u blind-chess -f'
  • Restart: ssh root@192.168.0.245 'systemctl restart blind-chess'
  • Health: curl https://chess.sethpc.xyz/api/health
  • Deploy update: pnpm -r buildpnpm --filter @blind-chess/server deploy --prod --legacy .deploy-server → rsync server bundle to /opt/blind-chess/server/ and client dist/ to /opt/blind-chess/client/dist/chown -R blindchess:blindchess /opt/blind-chesssystemctl restart blind-chess. Server restart drops in-memory games (acceptable for MVP).

Local instance — chess.local on VDJ-RIG

A second, LAN-only deploy on VDJ-RIG (192.168.0.143), fully independent of the CT 690 / chess.sethpc.xyz instance (separate in-memory state). Serves on port 80, reached at http://chess.local via an mDNS alias — no Caddy, no TLS.

  • Artifacts (deploy/): blind-chess-local.service (server unit; binds port 80 as the non-root blindchess user via CAP_NET_BIND_SERVICE), chess-mdns-alias + chess-mdns-alias.service (publishes the chess.local mDNS name with avahi-publish -a -R-R avoids a reverse-PTR collision with the host's own .local name), install-local.sh (root-side installer).
  • On the rig: tree at /opt/blind-chess/{server,client/dist}, units blind-chess.service + chess-mdns-alias.service, Node 22 via NodeSource.
  • Logs: ssh vdj-rig 'journalctl -u blind-chess -f'
  • Restart: ssh vdj-rig 'sudo systemctl restart blind-chess'
  • Health: curl http://chess.local/api/health
  • Redeploy: on steel141 pnpm -r build + pnpm --filter @blind-chess/server deploy --prod --legacy .deploy-server; rsync .deploy-server/ → rig ~/blind-chess-stage/server/, packages/client/dist/~/blind-chess-stage/client-dist/, and the deploy/ files → ~/blind-chess-stage/; then sudo bash ~/blind-chess-stage/install-local.sh.

Conventions

  • Inherits global homelab conventions from ~/bin/CLAUDE.md (gitea CLI, conventional commits, .claude/handoffs/ for session state).
  • pnpm workspace; do not use npm/yarn lockfiles.
  • All inter-package types live in packages/shared/. Never duplicate protocol types in client or server.
  • Server is the single authority on game state. Client commit messages are requests, not facts.
  • The view filter (buildView) is the only egress for board state. Don't bypass it.