Phases 0-1 shipped in v0.4.0 (seat/identity split, per-player turn state, the Session boundary). This lands Phase 2 (server core, one game, no lobby) and Phase 3 (persistence and resumption) per docs/architecture/multiplayer.md §12. Phases 4-6 (lobby/reconnection, the 22 opponent-directed cards, StartOS packaging) are still ahead. Phase 2: src/server/session.ts hosts a game in pure logic (no sockets) on top of game.ts's existing Game/submit/currentActor/actionMenu; it verifies seat === currentActor(game) itself before calling submit, since submit() trusts its caller and a server can't. src/server/http.ts and index.ts add POST /api/game, GET /api/stream (SSE, per-seat), POST /api/intent, and static serving of dist/. src/sim/frame-delta.ts is a purpose-built per-seat board delta for one live push at a time. Found and fixed along the way: actionMenu(game, seat) only used seat for the hand field, so a server computing every connected seat's Menu would have handed the acting player's legal moves to a waiting seat. Verified with a live end-to-end smoke test (2-player game, two SSE streams, a rejected intent from the wrong seat, an idempotent resend) plus test/server/session.test.ts and test/redaction.test.ts. Not verified: an actual browser (none available in this environment). Phase 3: src/server/persistence.ts writes game.json and turn-timings.json, atomic-rewrite-then- rename. game.ts gained fromMultiplayerSave, fixing a narration-attribution bug found while testing it (fromSave's replay loop drops the actor argument, invisible in solitaire, unreadable the moment there's more than one seat — fromSave itself still has this gap, deliberately untouched). Verified live: server killed and restarted mid-game, both seats reconnected exactly where they left off. Two rules bugs found while building this: the New Train phase never implemented its car-placement round (every car of every train was placed by the Superintendent alone, in every mode, all along — now reads the round position off tray.consist.length); and victory conditions are now one shared, configurable GameConfig set across solitaire/competitive/coop instead of a fixed length lookup and a dead firstToTarget condition. Also folds in the three fixes already released on the patch line as v0.4.9b/c/d: a switching train's crew badge failing to draw once it left the Office square, an unload that always took the westmost car regardless of which was picked, and a legal decision that could render with zero buttons. docs/testing/0.5.0-test-plan.md and three reported-bug save files (docs/station-master-seed*.json) included for reproducibility. tools/jitsi-harness/ deliberately left untracked — unrelated side-project work, not part of this release. 635 tests, 0 failures.
44 lines
1.3 KiB
Plaintext
44 lines
1.3 KiB
Plaintext
# OS
|
|
.DS_Store
|
|
Thumbs.db
|
|
|
|
# Editors
|
|
.vscode/
|
|
.idea/
|
|
*.swp
|
|
|
|
# Dependencies / build output
|
|
#
|
|
# NO TRAILING SLASH on node_modules, deliberately. `node_modules/` matches a directory and not a
|
|
# SYMLINK of that name — so one pointing at a shared install was committed in v0.4.7, and because it
|
|
# pointed at a path that does not exist, a fresh checkout had no TypeScript: `npm run typecheck` said
|
|
# "tsc: not found" and 20 tests failed for a reason that had nothing to do with the code.
|
|
node_modules
|
|
dist/
|
|
dist-test/
|
|
build/
|
|
target/
|
|
__pycache__/
|
|
*.pyc
|
|
|
|
# Claude Code's own state — session checkpoints and the git worktrees it works in.
|
|
#
|
|
# NOT ignored until now, so `git add -A` in the repo root would have staged
|
|
# `.claude/worktrees/`: a whole second checkout of this repository, committed into itself. Nothing
|
|
# in here is a source file and none of it should travel with the package.
|
|
.claude/
|
|
|
|
# Env
|
|
.env
|
|
.env.local
|
|
|
|
# Logs
|
|
*.log
|
|
|
|
# Generated replays — ANCHORED to the repo root on purpose.
|
|
#
|
|
# Unanchored, `replay*.html` also matched `src/web/replays.html`, which is a SOURCE file: the
|
|
# website's replay viewer. It was therefore never committed, and a fresh clone was missing a page
|
|
# the build copies unconditionally. Only the throwaway files this directory collects are ignored.
|
|
/replay*.html
|