Add an offline Ix initializer through the real setup pipeline, supporting Basic and Advanced play, base factions, Ixians and Tleilaxu with the full 47-card deck and 22-card spice deck. Preserve all normal start and publication gates. Add a reusable local prototype starter: back up the named fresh ready lobby, initialize it once by exact version/state comparison and preserve seat/recovery tables and other rooms. Update the existing checklist with a separate prototype stage and document functional scope, source interpretations and later refinement. Six new tests cover all-profile private setup, exact typed starting forces, Face Dancer/treachery custody, JSON continuation, two fixed-seed complete games and local SQLite write/rejection boundaries. Independent review caught a missing JSON version update, now fixed and covered; focused checking fixed one test typing error before the stable broad check. No new rule interpretation was introduced. Validation: types, lint and 4,211 offline tests passed (123.237s); production build passed (6.543s); all 40 HTTP tests passed (23.578s). Source-bound report: 20260913-ix-prototype-final/report.json, fingerprint 3b8f295593bcb314bb72308d81739006b11d949d1e5906dbf6ce0704b15ebd72. Browser W5LE6VFB: human Ixian + Medium Tleilaxu + Hard Atreides from genuine setup, private starting-card refresh, Weather Control, mobile stronghold placement, then owned Brutal autopilot. Atreides won on turn 1; this short complete journey is not proof of every card or faction interaction. Finished private hand restored at phone width; expanded Poison Tooth was readable. Fixed-seed offline games 2026091301 (Basic) and 2026091302 (Advanced) both completed with both Ix factions. All 64 opening room versions/hashes are unchanged. One browser room and 30 HTTP rooms were added, totaling 95. Reused the running server; no restart or automation. Aggregate goal counters: 59,524,858 to 59,976,567 at completed verification, 451,709 tokens before final Git overhead. Two bounded workhorse helpers handled inventory/tests and independent review; one stable full check/build/HTTP run. Full game scope remains active and unfinished; future work prioritizes missing functional prototypes before exhaustive refinement and final acceptance.
7.0 KiB
Development workflow
Start with README for installation and saved-game behavior and AGENTS.md for project invariants. This page is a navigation and verification guide, not a second implementation-status log.
Start with current status and rule decisions. Use repeatable verification for compact source-bound logs, private saved-game backups/comparisons and HTTP seat restoration. The three-milestone pilot records measurement limits. Use the Ix prototype workflow to connect a fresh local ready lobby to genuine expansion setup with a private backup and preserved sessions. It does not open normal mode gates or require restarting the server.
Architecture map
| Concern | Entry points |
|---|---|
| Authoritative state and actions | game/engine.ts: Game, applyAction, viewGame, normalizeAutomaticGame |
| Rule validation and calculations | Feature modules in game/; *-quote.ts modules compute validated outcomes before mutation |
| AI | game/bots.ts: botActions, runBots; game/bot-*.ts and shared rule modules |
| Persistence, concurrency, recovery | db/rooms.ts; D1 schema in db/schema.ts, additive SQL in drizzle/ |
| HTTP and session boundary | app/api/rooms/route.ts, app/api/rooms/[code]/route.ts, app/api/rooms/[code]/control/route.ts |
| Table UI | components/game-table.tsx orchestrates feature components; app/page.tsx is the route entry |
| Client request/retry state | lib/client-request.ts, lib/room-entry.ts, lib/seat-recovery.ts |
| Player reference and evidence | game/reference.ts, game/faction-reference.ts, app/rules/; feature docs in docs/ |
| Tooling | package.json, tools/test.ts, tools/test-discovery.ts, vite.config.ts |
For a rule change, locate its helper, engine action/continuation, projected player
view, bot policy, UI and existing tests before editing. Keep server legality
authoritative and reuse helpers across those consumers. Test rejection without
mutation, physical resource conservation, interrupted decisions and saved JSON
restoration where relevant. See tests/fixture-hand.ts for physical card fixtures.
Fast feedback
# Inspect selection without loading the engine or starting a server.
npm test -- ecaz-collection ecaz-spice --list
# Run related files, optionally narrowing test names.
npm test -- ecaz-collection ecaz-spice
npm test -- ecaz-spice --name 'fallback|conserves'
# Broad offline validation once the change is coherent.
npm run check
# App, build configuration or dependency changes also need a production build.
npm run build
| Command | Scope | Live server? |
|---|---|---|
npm test |
All offline tests: rules, bots, client/components, tooling and in-memory recovery | No |
npm run test:unit |
Rules, bots, client/components and tooling | No |
npm run test:recovery |
In-memory SQLite persistence and recovery | No |
npm run test:integration |
Explicitly marked HTTP/session tests | Yes |
npm run test:multiplayer |
Recovery plus HTTP tests; preserves the previous command's scope | Yes |
npm run test:all |
Every discovered test | Yes |
npm run check |
Typecheck, lint, then all offline tests | No |
All test commands accept filename fragments, --list, --name REGEX, and
--concurrency NUMBER after npm's --. Filename filters are literal substring
matches, combined with OR; every supplied filter must match its selected suite.
Name patterns are Node test-runner regular expressions and may skip every case,
so check the reported results when using them.
The runner discovers tests/**/*.test.{ts,tsx,mts,js,mjs} recursively and sorts
the paths. New offline tests require no manifest entry. HTTP files carry the
first-line annotation // @dune-suite integration; in-memory recovery tests
are identified by their single-line node:sqlite import. A file referencing
process.env.DUNE_TEST_URL without the HTTP annotation fails discovery. Tests
that introduce a different network helper must also carry the HTTP annotation.
The default offline suite includes every test without that annotation regardless
of its unit/recovery classification.
Offline test files run in isolated processes with at most four workers, avoiding
Node's machine-sized default on large hosts. Suites containing HTTP tests default
to one worker to avoid competing for the same development Worker. The launcher
uses node --import tsx, which avoids the tsx CLI's extra IPC listener. The exact
tsx version is declared directly and locked for clean installs.
HTTP testing and stored games
Start the existing development environment with npm run db:local, then
npm run dev. Reuse a server already serving this checkout. Tests default to
http://localhost:3000; DUNE_TEST_URL can select a dedicated test server:
DUNE_TEST_URL=http://localhost:3000 npm run test:integration
The runner checks server availability before starting any selected HTTP suite.
HTTP tests create their own rooms in that server's database; use a development
or dedicated test instance. In-memory recovery tests execute production room
code and migrations against disposable SQLite databases and do not touch
.wrangler/state. Preserve that directory and existing human games.
Keeping future changes small
TypeScript keeps incremental metadata under node_modules/.cache/dune/; build
outputs and Wrangler state are excluded from typechecking. *.tsbuildinfo and
patch backups are ignored. Git history preserves prior source versions.
Use feature docs for rule decisions and evidence, and keep new evidence concise. The large implementation status log contains historical checkpoints; a previous green count is not proof that the current source passes. Full AI studies and browser acceptance belong to changes in their respective behavior, not every edit. Runtime optimizations should follow a measured bottleneck and retain legality, secrecy and saved-game invariants.