Files
Dune/docs/DEVELOPMENT.md
T
Quintine cab2f1c42d Connect expansion faction setup and saved Ixian auction decline
Add a local faction-only prototype profile for all seven nonempty expansion selections, genuine Basic/Advanced initialization and existing private setup, controls, AI and saved continuation. Ecaz allocates six forces across Imperial Basin sectors and retains fourteen reserves before later setup; preserve Fremen, Advanced BG and Moritani ordering with printed and inferred boundaries explicit. Keep optional Ecaz Treachery cards separate, ordinary deck counts 33/35/47, and Richese cache separate. Public start and publication gates remain closed.

Replace the Advanced Ixian/Richese pre-offer stop with an explicit per-lot Ixian decline. Bind the saved original offer to its round, turn, owner, independent event, exact card custody and terms before view/action/normalization. Decline resumes that unchanged lot once without using Technology; later normal lots still offer the exchange. Protect reserved cards across transfers, spending and random Harkonnen exchange, and preserve legitimate Gift/Truthtrance interruptions. The actual special-lot exchange still awaits replacement-custody interpretation.

Validation: focused setup, rules, UI/bot, private JSON/SQLite reload and concurrent CAS tests and independent custody/persistence review passed. Typecheck, lint, 4573 offline tests, production build and 43 HTTP tests passed. Browser Ecaz setup rejected an incomplete total, saved a 2/2/2 split, and refreshed to fourteen reserves and unchanged private cards. A separate genuine Advanced QA game restored the Ixian choice; explicit decline opened the unchanged cache lot with legal bidding and retained private hand, spice, pool count and unused Technology after refresh.

Five of six genuine four-profile samples finish: CHOAM Basic 1054 actions/28 JSON restores, CHOAM Advanced 225/6, Ecaz Basic 91/2, Ecaz Advanced 523/14, all-three Basic 476/12. Combined Advanced passes three former auction stops and reaches turn three/action614 with 16 restores, then hits an existing CHOAM movement/Ambassador arrival guard. Ecaz samples also include guarded arrival candidates with legal alternatives. Full combined play is not certified; arrival integration is the next gap. Retain initial failed logs, including a corrected private harness sold-card receipt alias.

After the outage, all 597 opening rooms and original seat/recovery records were preserved (632 after QA/HTTP). A stale development module cache required restart after a fresh 598-room backup; all 598 matched afterward and the QA seat restored. Final integrity and foreign keys passed. No database reset, recurring automation or publication.

Verified source tree: 5e2ff244a1167f2834bb46d609b8de914a34f7049ff7b06046243068c0935131
2026-09-13 22:51:19 +10:00

7.2 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. The expansion-faction profile extends genuine setup to selected faction sets without optional modules, including Ecaz starting placement. Remaining combined-play guards still apply.

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.