v0.4.1 - bug fixes. initial d12 rolls determine what player in which seat.

This commit is contained in:
Jesse
2026-08-13 15:28:53 -04:00
parent 49f8504b05
commit a7221dcf20
22 changed files with 736 additions and 237 deletions
+38 -58
View File
@@ -49,73 +49,53 @@ must do.
## Current status
Rules formalized, card faces specified, architecture documented, and the rules engine built and
simulated. Eleven of thirteen gaps are closed; **Gap 12 (balance variance) and Gap 13 (deck scaling)
remain open**, both with data behind them.
**v0.4.1.** Rules formalized, card faces specified, architecture documented, and the game playable
solitaire in a browser. See [`../CHANGELOG.md`](../CHANGELOG.md) for what each version changed and
[`../TODO.md`](../TODO.md) for what is open; this section is the shape of the project, not a
running tally, because a hand-maintained tally is what drifted last time.
Gaps 8–13 were all found by working the design forward — building it or simulating it — rather than
by reading the PDFs. None arises in tabletop play, where a person simply does the sensible thing.
**What is built.** The rules engine, the developer bot, the balance harness, the replay viewer and
the playable page — components 1–7, 17 and 18 of
[`architecture/components.md`](architecture/components.md). A game can be saved, shared, replayed and
stepped back through. **493 tests.**
**What is not.** The server. Phases 0 and 1 of
[`architecture/multiplayer.md`](architecture/multiplayer.md) landed in v0.4.0 — seat and player are
separate, turn state is per player, and the page talks to a `Session` rather than to the engine, so a
`RemoteSession` drops in without the page changing. Phase 2 onward is **deliberately held** until the
two provisional rules introduced in v0.3.0 have been played at a table: changing a rule after the wire
format is live costs far more than changing it before. Also unbuilt: the 22 opponent-directed cards
and real audio.
**Balance is not where it should be, and no conclusion should be read from the revenue numbers yet.**
The rebalance pass is deliberately deferred until the rules stop moving — card counts, industry counts
and the track mix all need moving together. `TODO.md` carries the standing distortions and the
measurements behind them.
**Three rules are genuinely open**, and they are the reason the README does not claim the rules are
finished: where the Local's coach stands while its engine works (a §A.4 question, not a train-card
question); Poling, the one card in the deck with no defined behaviour; and whether a Heavy Grade's
orientation is rolled or chosen at setup. Thirteen gaps in the prototype rules were found and closed;
these three came after.
**The event log narrates; the intents reconstruct.** Settled in v0.4.0 after the documentation had
claimed `state = fold(events)` for months. It is not true — the phase driver mutates state and then
describes it — so the canonical record is `{ seed, history: Intent[] }` and persistence will be built
on that. [`architecture/protocol.md`](architecture/protocol.md) §3 has the reasoning;
`test/events.test.ts` pins it.
**The economy, in one line:** Local Operations actions are the main currency — one per Stage, twelve
per Day — but **inbound work bypasses them**, which is where the game's variance comes from. See
`card-reference.md` §7.
**Wanted, not yet designed:** post-game replay — watching a finished game back at speed. The
architecture already produces what it needs (an ordered append-only event log plus a stored seed), so
the note in `architecture/overview.md` exists to keep the capability from being designed out. It is
explicitly not scheduled.
**Provisional numbers** — the victory targets are now confirmed at the mean by simulation. Still
untested by play: Crew Tray count, Laborer counts, and whether the variance in Gap 12 is a flaw.
**Next steps.** The specification is complete enough to build against or to play on paper.
The build path is laid out in [`architecture/components.md`](architecture/components.md) — 20
components, a dependency graph, and a twelve-step order. Its **MVP is solitaire: one Office, a fixed
number of Days, a server talking to a single browser, display functional rather than pretty.** The
milestones worth knowing:
- **Step 4** — a full solitaire game runs to completion headless, proving the rules before a pixel is
drawn.
- **Step 6** — the balance harness validates or retunes the provisional numbers, while changing them
is still free.
- **Step 10** — MVP complete; a human plays end to end.
**Stack: TypeScript**, chosen so the engine runs in both the server and the browser — one
implementation of the movement rules, and instant affordances without a round-trip. Node 22 runs
TypeScript natively, so there is no build step during development.
TypeScript natively, so there is no build step during development, which also means **erasable syntax
only**: no `enum`, no parameter properties, no namespaces.
> **The recovered design files are now transcribed and the nine open questions answered** — see
> [`rules/implications.md`](rules/implications.md) §1b for exactly what is implemented. The deck is
> 115 cards (93 in solitaire), Mainline cards have terrain and crossing times, and the balance
> numbers below predate all of it.
**Steps 1–6 are done** — the rules engine (components 1–7), heuristic bots (17) and the balance
harness (18), with 134 tests passing.
**The step 4 milestone is met: a full solitaire game runs to completion, headless.** Games are
reproducible from a seed, terminate from every seed tried, conserve all 62 rolling stock pieces, and
develop properly.
**End-of-game statistics** (`src/sim/stats.ts`) report revenue by source, traffic, development,
action mix and strategy buckets — plus an **anomaly detector** that treats "this event never fired"
as a finding. It caught two bugs on its first run.
**The step 6 milestone is met, with a caveat.** The harness found **five engine bugs that no test had
caught**, and once they were fixed the numbers came good: **~35% win rate and 5.0 Revenue/player/Day,
matching the Gap 10e prediction of 5-6.**
The caveat is large: those numbers were themselves measured against a **scoring bug**, since fixed.
Honest figures are ~0.9 Revenue/Day and a **0% win rate** — the targets are currently unreachable.
The bot is still the prime suspect (it uses ~10 Laborer actions per game out of ~900 available), so
this is **Gap 12** and remains open. One genuine signal did emerge: **mixed freight/passenger
strategies outscore pure ones**, with pure freight much the worst.
**Gap 11 is decided** — track orientation is chosen on placement, settled by measurement.
**Gap 13** answers the deck-size question: do not double it; scale only the buildable cards with
player count.
Next: step 7 begins the server (components 8, 9, 20).
Running alongside, and independent of all of it: **print-and-play components.** `card-reference.md`
specifies every card face, so layout and art are the only remaining work before a table playtest —
which answers the one question simulation cannot, whether it is fun.
Run the harness with `node src/sim/harness.ts [games] [length]`.