Files
station-master/docs/rules/implications.md
T
Jesse.Markowitz 7804756f11 v0.6.2 — an Extra starts where you put it, a train card is never discarded
Three more from the v0.4.9e gameplay-testing round, filed as Gitea issues, plus two bugs found
underneath them. Gitea#2 is diagnosed but NOT fixed: it needs a ruling, and the reasoning is in
TODO.md under Play Balance.

GITEA#4 — AN EXTRA STARTS WHERE THE PLAYER PUTS IT. Only one Division Point was ever offered,
chosen by number parity. The number no longer decides an Extra's direction — the start does, which
supersedes the recorded ruling that "the number decides, like everything else on the timetable".
The two cannot both hold: an odd, westbound Extra placed at the WEST end would leave the Division
on its first move having crossed nothing, and be paid for the run. Either end now runs the train
away from itself; at an Interchange or a Control Point the player picks the direction. The
Interchange start is a YARD, off the running line, which is what makes the Superintendent clause
work: placing it can never force a collision, a guaranteed one holds it there for another Stage,
and a potential one is the Superintendent's to rule on — exactly evaluateClearance's `blocked` and
`ask`, so nothing new decides collisions. Where an Extra may start is now a house rule
(divisionPointsOnly / ownOffice / anyOffice, defaulting to what the engine already did). The
legacy `atSeat` intent field still replays as it always meant.

FOUND UNDERNEATH IT: an Extra started away from a Division Point ran empty. isBeingMadeUp tested
position alone, so the Control Point start has been shipping since it was added with a train that
could never be given a consist. Found by playing it, not by the tests, which had only asserted
where the tray landed.

FOUND UNDERNEATH IT: collide left the wrecks on the card. Destroyed trains kept their Transit
entries, and evaluateClearance counts every transit as an occupant, so one rear-end collision
permanently poisoned that Mainline card for every later train.

THE MAINLINE CARDS WERE ROLLED, NOT DEALT — drawn from the nine types with replacement, so a
Division could hold two Interchanges and Plains carried the weight of a card printed once. "An
Extra may start at the Interchange if one is on the board" only reads as a rule if the board holds
at most one. Now dealt from the printed deck without replacement, verified over 1600 deals. This
re-deals every seed: the published replays were re-recorded, and the saved games in docs/ are
retired too — two of those were already dead before this release and nobody had noticed.

GITEA#6 — A TRAIN CARD IS NEVER DISCARDED, Timetabled and Extra alike. The forced play needed no
mechanism: nothing discardable plus a hand over the limit leaves exactly one legal way to end the
turn, and playing a train is unconditionally legal, so the corner cannot trap anyone. The bot
needed no rule either. 400/400 games finished, revenue unmoved, trains scheduled 1.2 -> 1.3. The
player is told on the card and on the button.

GITEA#7 — COACH COUNTS. 1/2 Crack Limited 3 -> 2, 5/6 The Sparrow 2 -> 3. A change to the cards,
so Trains3.pdf and the transcription keep the original numbers with a footnote while content.ts
and the Home Deck reference carry what the game plays.

CONTENT.TS COMMENT PASS — no data changed, only comments. Four were factually wrong, including an
office table naming counts doubled long ago and a pointer to a DEALT_DECK_SIZE that has never
existed. Every Enhancement row cited its implementation by line number and every citation had
rotted; they name functions now. Card counts came out of the comments, since they move with play
balance; source-sheet figures and dated measurements stayed.

TODO.md gains an item for a card reference generated from content.ts, in six sections, so the
documentation cannot disagree with the game.

715 tests pass, tsc clean, site builds.
2026-08-22 19:51:40 -04:00

54 KiB
Raw Blame History

Implications of the four recovered design files

Four files were added to docs/ on 2026-07-30 that were part of the original design but never made it into this workspace:

File What it is
Deck cards2.xlsx The complete card list — every card, its count, where it may be placed, what it does
Mainline Cards.pdf The Mainline card types — Plains, Curves, Hilly, Heavy Grade, Double Track, Uncontrolled Siding, Tunnel, Trestle, Interchange (printed "Yard"), and both Division Points
Trains3.pdf The train cards — all 22, with names, speed class, consist and individual operating rules
tracks.png Card art for track and industry cards

This document records what they imply and proposes what to do. §1a below records what has since been implemented; everything else is still a proposal.


1. The headline: the game is roughly 3× what we built

Built Recovered design Change
Home Office deck 52 115 2.2×
Track cards in the deck (12) 104, a per-player supply of 26 moved out of the deck entirely
Start cards ad-hoc 12 (4 Whistle Posts, 8 Limits) formalised
Total components ~52 231
Train cards 16 22 12 timetabled + 10 Extras
Distinct card categories 6 10 four categories are entirely new

The sheet's own totals (115 / 104 / 12 / 231) reconcile exactly with the line items, so these numbers are the design's, not an inference.

Most of my invented numbers are now superseded, and that is a good outcome. Everything in card-reference.md was explicitly provisional — placeholders standing in for exactly this document.


1b. Implementation status after the answers (2026-07-31)

All nine answers are implemented, 170 tests passing:

Answer Implemented as
Q1 crossing time crossingStages() — a 60 card takes 1 Stage, a 30 takes 2. Mainline nodes now carry a terrain type dealt at setup, and trains count down Stages instead of stepping through regions. The Region model is gone.
Q2 Fast/Slow Slow adds one Stage to every card. Hilly reads the consist (any coach = passenger).
Q3 Expedite An expedited train departs the Stage it arrives — it gets a second moveTrain in the same Mainline Phase, still subject to §8.1 clearance.
Q4 Lockouts isLockedOut() rejects the placement with FACILITY_LOCKED.
Q5 Run-around Nothing to do — reachability is geometric, so a built bypass already works.
Q6 Space-use Solitaire decks omit all 22 opponent-directed cards: buildDeck('solitaire') returns 93, competitive returns 115.
Q7 45° geometry The through track runs east-west across the middle of every card; there is no north-south track. Every leg leaves at 45° through the middle of the north or south edge, so two stacked cards join only when their legs share a diagonal (joins/slopeAt in track.ts). Handedness is that diagonal, and a card turns 180° but never flips, so each has two orientations. Office and industry cards carry a plain through track and no stub. A district grows on both sides of the Running Track, so §9's "nine nearby spots" really is nine.
Q8 Crew Tray cap Already correct.
Q9 Second Section newTrain.secondSection plays on a train due out; an identical train is made up behind it next New Train Phase. The Sister trains optional rule is removed from Appendix B.

Enhancements (18) are now implemented — placement rules, Small Yard consist re-ordering, ABS Signals, Yard Office diversion, Interlocking, the Telegraph/Telephone/Radio dispatch bonuses and the three defensive cards, covered by test/enhancements.test.ts.

Mainline modifiers (7) and Maneuvers (6 of 7) are now implemented, covered by test/mainline-cards.test.ts. They are not multiplayer-only — that was a mistaken impression given earlier. Brakeman, Airbrakes, Helpers and Realignment all change your own crossing times, and Red Flags prevents a rear-ender, which happens in solitaire too. The real reason they lagged was sequencing: Enhancements were done first because they change core loops.

Card Where it lives Effect
Brakeman, Airbrakes mainline.modify on a grade −1 Stage downhill each; Airbrakes needs Brakeman on the card
Helpers mainline.modify on a grade −1 Stage uphill
Realignment ×2 mainline.modify on any Mainline card converts per REALIGNMENTS; barred while a train is on the card
Facing Point Locks ×2 grid, as the Enhancement the sheet prints this card in both lists — one card, not two
Red Flags ×5 maneuver.redFlags on a stopped train an approaching train is held instead of colliding; flags come in when the train rolls
Flying Switch maneuver.flyingSwitch during switching cuts cars into an adjacent industry without the engine entering; costs a Move
Poling — deliberately unimplemented

Crossing time never falls below one Stage — a train cannot cross in no time.

Poling stays unimplemented. The recovered sheet records its effect as "TBD in the source", so there is nothing to build. A test asserts it remains TBD, to stop anyone "fixing" it by inventing an effect; a silent no-op would be worse than a rejection.

Q11, answered from the source. The Heavy Grade card prints "(Up)" and "Player sets orientation", so which way it climbs is a property of the placed card, not a fixed compass direction. DivisionNode.gradeUp records the direction a train travels when climbing; a train going the other way is descending. Brakeman and Airbrakes apply to the descent, Helpers to the climb, so turning the card around swaps which trains each card helps.

Settled (v0.5.0): orientation is never a player choice, and this overrides the card's own printed "Player sets orientation." A Heavy Grade sits on the shared west-to-east Division chain, between two players (§4.2) or beyond an end Division Point next to one — never inside a single player's own district — so whichever direction climbs advantages one neighbour over the other, and no one player has a fair claim to the decision. Orientation is rolled from the seed instead — deterministic, and roughly even (51/49 east/west across 400 games) — identically for solitaire and multiplayer.

Still not implemented: the Action (10) and Space-use (12) cards, which are genuinely multiplayer-only. Playing them is rejected with NOT_IMPLEMENTED.

Parking trains — two engine bugs and a bot defect

Trains reached an Office and never left: 668 arrivals against 515 departures. A train may only highball from the Office square itself (§8.1, Gap 2b); from anywhere else moveTrain returns held, permanently. 77 of 93 leftover crews were sitting somewhere they could never depart from.

Three separate causes, found by following the stranded crews:

  1. Reverse was hardcoded to east/west. destinationsFor computed the backing-out port as facing === 'e' ? 'w' : 'e'. A crew facing south reversed to east — a port a north-south card does not have — so it could never back out of a district spur. Now opposite(facing).
  2. Facing was derived from direction, which only carries east and west. A crew standing on a north-south spur was given an exit port its card did not have, leaving it with no legal moves at all. CrewTray.facing now records the actual port, updated on every move from the port the crew entered through.
  3. The bot never went home, and its "no useful work" fallback took an arbitrary legal move — the same shuttling bug as before, re-entered by a different door. It now heads for the Office whenever nothing productive remains, and a crew stranded away from the Office can claim a whole Local Operations turn to walk back.

Flying Switch was also mis-modelled: it tested orthogonal adjacency when the cut rolls along the track, which both allowed a cut to cross to a cell with no rail between and refused a siding two cards along the same track. It made the card nearly unplayable — held for 1,400 turns across 60 games and legal on 2. Now the target must be track-connected.

before after
arrivals / departures 668 / 515 (77%) 795 / 793 (99.7%)
leftover crews stranded off the Office 77 of 93 24 of 53
collisions per game 0.2 0.7
revenue per player 1.0 −1.1

Revenue got worse, and that is the honest result. Parked trains were not colliding. With trains circulating properly, every collision is now no free A/D track — 35 of 35 across 60 games — and collisions cost −3.3 of the −1.1 net. The previous figure was flattered by a bug.

A/D congestion is not congestion — it is the Whistle Post

Chasing it found no congestion at all. The Office is empty at 88% of Stage starts (occupancy 0 at 3,136 of 3,600) and mean dwell on an A/D track is 1.4 Stages. Collisions are bursts, and they are concentrated in one place:

  • 25 of 26 collisions happen at Whistle Post, which has one A/D track, so any second arrival is an automatic collision (§8.3, Gap 2a). One collision occurred at Depot; none above it.
  • No collision was ever recorded in a district holding an Interlocking. The enhancement is a complete cure — it just arrives too late and too rarely.
  • 25 of 100 games never escape Whistle Post at all, and those are exactly the games that never drew a Depot card. Mean first upgrade is Stage 9.3 of 60.

The damage is concentrated, not spread:

games mean revenue worst
never upgraded past Whistle Post 25 −6.0 −54
upgraded at least once 75 −0.4 +9 (best)

That is what makes the median +1.0 while the mean is −1.0: a quarter of games are ruined by a draw that never comes. The bot now plays an Office upgrade ahead of everything else and prefers Interlocking over other Enhancements; both were previously unranked. Neither moves the mean, because the constraint is draw luck, not policy — escaping Whistle Post requires one of 4 Depot cards in 133.

Q12 answered — office density doubled

Players always start at a Whistle Post; that is settled and not up for change. The lever is therefore card density. Office copiesInDeck is doubled: Depot 4→8, Station 2→4, Terminal 1→2. Offices go 7 → 14 and the deck 133 → 140 (solitaire 111 → 118).

Station and Terminal were doubled alongside Depot rather than lifting Depot alone, because upgrades are strictly sequential (Gap 3b): the ladder has to stay a pyramid or players reach a rung whose next card is scarcer than the one that got them there. The test now asserts that property instead of the literal counts, so it survives the next density change.

7 offices / 133 14 offices / 140
revenue per player −1.0 0.7
games never leaving Whistle Post 25 13
mean revenue, games that did upgrade −0.4 1.9
collisions per game 0.7 0.3
lost to collisions −3.3 −1.6
worst game −48 −28

All 37 remaining collisions are still at Whistle Post, which confirms the diagnosis rather than undermining it. Note the games that still never upgrade got worse (−6.0 → −10.5): they are now a smaller, unluckier group, so the mean is both more extreme and noisier. Still 0 wins.

PROVISIONAL — re-evaluate later. These counts were chosen to remove a 25% chance of an unwinnable opening deal, not taken from the recovered design, and the instrument is blunt: it lifts the whole office ladder and dilutes every other category slightly. Revisit once the victory target is settled and freight carries its intended share. The better answer may turn out to be fewer Terminals, a cheaper first upgrade, or more A/D capacity at the Whistle Post itself.

Measuring, after getting it wrong

A throwaway probe reported "60 of 60 games never upgraded past Whistle Post" while the Office-tier histogram from the same run plainly showed Depots, Stations and Terminals. Events reach the log from two sources — the phase driver (pump) and player intents (applyIntent) — and the probe watched only the first. Office upgrades arrive through the second.

The cause was hand-rolling the drive loop. playGame already tallied both sources correctly; it was re-implemented because it returns the event log but not the state at the moment an event fired, which is what questions like "what tier was the Office at this collision" need.

playGame now takes an optional PlayObserver — (event, state) => void, called from the single point both sources funnel through. Two tests guard it: one asserts the observer sees exactly the events the log records, one asserts office upgrades are visible in the log across 25 games. Reintroducing the original mistake fails both.

A wrong measurement is worse than a missing one, because it gets believed and acted on.

Freight throughput — a self-inflicted deadlock

Freight was 10% of gross revenue with 27 industries on the board, so the Gap 12 tripling had bought facilities but not freight. The pipeline said why: 415 loads started, 413 unjams, 13 completions across 60 games — a 3% completion rate, with the Freight Agent spending more than half its actions clearing jams it had caused.

A load leaves MEN|AT|WORK only onto a spotted empty car of its own type (§9.3). Starting one with no car spotted parks it on WORK — and a load on WORK locks the industry track, which blocks the very car that would clear it. The bot started a load whenever the intent was legal, so it jammed its own facilities and then spent its turns unjamming them.

Two fixes, both in the bot; the engine was right throughout.

  • Only start a load that can finish. loadCanFinish requires the receiving car to be spotted already. Worth recording that the first attempt kept a last-resort startLoad "rather than idle a Laborer" and measured identical to having no gate at all — the fallback was taken every time. An idle Laborer is strictly better than a jam, which costs an action to clear and locks the track meanwhile.
  • Weigh the whole consist, not just the back car. 744 switch turns produced 135 Moves and 741 immediate ends: a crew holding wanted cars behind one unwanted car concluded there was nothing to do. §A.3 makes the back car the only droppable one; it does not make it the only one worth travelling for. The crew now sets out dead weight on a plain spur before travelling — ordering that matters, because doing it after produced the shuttling loop for the third time.
before after
loads started / completed 415 / 13 (3%) 44 / 38 (86%)
unjams 413 281
cars dropped 151 197
cars coupled 14 25
unloads completed 40 74
revenue per player 0.7 2.2
cards played 12.4 16.9
trains scheduled 2.0 2.7
passenger revenue 1.3 2.7

Freeing the Laborers freed the whole turn economy — passenger revenue doubled without a single passenger rule changing. Still 0 wins against a target of 20, and freight is still only 13% of gross, so the loop runs now but does not yet carry the game.

Where the empty-car requirement belongs

The rule above was later copied onto stocking as well, so freightAgent.stockOutbound refused a green box with no matching empty spotted. That is one step too early, and the designer's ruling is that it should never have been there:

A freight agent should be able to load an outbound green box prior to having the car there that matches the load that he's putting in there. But in order for the laborers to move it from the green box into the men at work track, they would need to have an empty car of the appropriate type waiting there.

Which is what §6.3 and §9.3 say between them. §6.3 lists the Freight Agent's act with no reference to the industry track at all; §9.3's Load the car is what requires "a load in the Green Loading Box and an empty car of the required type on the industry's track". So the two errands — fetch the cargo, spot the car — may be run in either order, and only the Laborer needs both done.

Staging ahead cannot jam anything, which is why the early gate bought nothing: a load in a green box is waiting, not stuck, and the lockout in §9.3 applies to loads on MEN | AT | WORK. startableLoad holds the real gate, counting cars against loads already staged or on the sign so two loads can never walk toward one car.

Track was unplayable (found while wiring up Enhancements)

Moving track out of the deck into a per-player supply (§12.2) left no way to play it. Districts could only grow through Freight-Facility and Modifier cards, so the Running-Track and Secondary-Track straights that Enhancements attach to essentially never existed. Two bugs compounded it: legalActions offered Enhancements only empty grid cells, when an Enhancement attaches to an occupied card.

Measured before the fix: a hand held a playable Enhancement on 4,778 turns and could legally place one on 33 — and those 33 were all ABS Signals, which targets a Mainline card rather than the grid.

Fixed by adding a track.lay intent drawing from OfficeArea.trackSupply, and by giving Enhancements the occupied cells as candidates. Enhancement placements went 21 → 98 per 40 games.

Q10, answered. Track is laid during the "draw a card" option, one piece a turn — which is how track behaved when it was a card.

Measurement after the answers

100 solitaire Standard games: mean revenue −1.3, trains scheduled 2.8, cards played 11.3.

After Enhancements and the track fix: mean revenue 0.0, trains scheduled 2.9, cards played 13.9, collisions 0.3. Still 0 wins against a target of 20.

Gap 12 resolved — industry density

The shortfall was structural rather than a missing rule. Freight was 10% of gross revenue and carsCoupled fired 4 times in 100 games: the chain needs a Freight Facility, an empty car of its exact type spotted on its industry track, three Laborer advances, and then a crew with spare capacity to lift the load — and there were only 1.6 freight facilities per game, because the recovered sheet puts 9 industries in a 115-card deck where the prototype had 10 in 52.

Every industry's copies is tripled: 9 → 27, deck 115 → 133 (solitaire 93 → 111). Tripling uniformly restores roughly the prototype ratio while preserving the sheet's proportions exactly — the outbound/inbound balance and the lockout structure are untouched.

ROLLING_STOCK_SUPPLY scaled with it, from 62 pieces to 80: worst-case demand at 27 industries is boxcar 15, hopper 12, tank 9, reefer 6, and a Division Yard that runs dry would starve the very loop the increase exists to feed. That supply was already flagged as provisional, not transcribed.

9 industries / 115 27 industries / 133
revenue per player 0.0 1.1
freight facilities per game 1.6 3.6
freight share of gross 10% 18%
laborer actions 9.8 16.9
collisions 0.3 0.1
trains scheduled 2.9 2.1

First positive mean revenue recorded, and the carsCoupled anomaly cleared. Still 0 wins against a target of 20, so this is progress on a diagnosis, not a balanced game. Note the side effect: trains scheduled fell 2.9 → 2.1, because 22 train cards in 133 are drawn less often than 22 in 115. Train density may need the same treatment.

Still no wins, and still not a verdict — roughly a third of the deck does nothing yet, and the Small Yard enhancement (which is what makes the switching puzzle solvable) is among the unimplemented cards. Gap 12 stays invalidated until the enhancements are in.


1a. What has been done so far (2026-07-31)

Transcribed and in code, with 169 tests passing:

  • The full 115-card deck — deckComposition() reconciles exactly with the sheet's own total.
  • Track removed from the deck and modelled as a per-player supply of 26 pieces (TRACK_SUPPLY), with printed handedness and a move cost field (2 for sharp curves).
  • Curves added to the track graph; the invented run-around card removed.
  • All 22 trains with names, Fast/Slow speed class, category-based consists and per-card operating rules.
  • Industries retuned to 1-out / 1-loader, with the real six kinds and their lockout lists.
  • All 23 modifiers, each tied to its specific hosts, with their effects applied on placement.
  • Office slots corrected to equal porter count; deck copies corrected to Depot 4 / Station 2 / Terminal 1.
  • The ten Mainline card types with speeds and named entry points, as data.
  • The four new categories (space-use, enhancements, mainline modifiers, maneuver, action) are in the deck. Playing them is rejected with NOT_IMPLEMENTED rather than silently doing nothing — the failure mode that left Modifiers as dead weight for weeks.

Not done, pending the questions in §10: the speed model, Expedite, lockout enforcement, space-use semantics, and everything the four new categories actually do.

First measurement on the real catalogue

100 solitaire Standard games, same bot: mean revenue −1.9, trains scheduled 2.3 (was 4.8), cards played 10.5 (was 16.3).

Development has slowed sharply, and the reason is visible in the composition: industries are now 9 cards in 115 (7.8%), where the placeholder had 10 in 52 (19%). Their density more than halved, and trains fell from 16-in-52 to 22-in-115. The deck is much more diluted, which is exactly what the enhancements, maneuver and action cards are there to fill — and none of those do anything yet.

Read no balance conclusions from this number. It measures a half-implemented ruleset.


2. Deck composition

What the design says — 115 cards

Category Cards Notes
Offices (Depot 4, Station 2, Terminal 1) 7 We had 9 (4/3/2)
Passenger modifiers (Waiting area 3, Restaurant 2, Hotel 1) 6 each adds 1 passenger-out + 1 porter
Industries (Freight House 2, Mine Tipple 2, Refinery 1, Power Plant 2, Packing Sheds 1, Grocer's Warehouse 1) 9 We had 10 in a different mix
Industry modifiers 17 each tied to a specific industry
Trains (12 timetabled + 10 Extras) 22 We had 16
Space-use cards 12 entirely new — cards that burn table space
Enhancements 18 entirely new
Mainline modifiers 7 entirely new
Maneuver cards 7 Red Flags ×5, Flying Switch, Poling
Action cards ("screw you") 10 entirely new — played at other players
Total 115

Proposal

  • Replace content.ts wholesale with this catalogue. It is data, so this is transcription rather than design.
  • Gap 4a (52-card deck) is superseded. Record it as such rather than deleting the reasoning — the deck was a stand-in and it did its job.
  • Gap 13 (deck scaling by player count) largely dissolves. Track is now per-player by construction, which was the real pressure I measured. The 115-card deck is shared. Re-measure before concluding anything further.

3. Track — the biggest structural change

What the design says

Track is not in the deck. Each player gets a fixed personal supply of 26 pieces:

Piece Per player Total (4p) Notes
Straight 8 32
Curved left 4 16 we have no curves at all
Curved right 4 16
Sharp curved left 1 4 any move across is doubled — two Moves
Sharp curved right 1 4
Turnout left 4 16
Turnout right 4 16

Column J ("Train can stop here") is set for straights and curves, blank for turnouts — which matches what we built: a turnout is not Operational Rail.

What this changes

  1. Curves exist and we have none. Our geometry is straight / turnout / run-around. The design has straight / curved / sharp-curved / turnout, each in left and right hands. Run-around is not a card at all — it is presumably built from a turnout pair.
  2. Handedness is printed, not chosen. Left and right are distinct physical cards. Gap 11's decision — "orientation is chosen on placement" — is therefore superseded. The measurement behind it stands (a fixed default made vertical growth impossible), but the design's answer is different and better: give the player a supply containing both hands.
  3. Sharp curves cost two Moves. A per-card movement cost, which our Move model does not have.
  4. Track no longer competes for deck slots, so the draw is entirely about industry, trains and enhancements. This materially changes the economy I measured.

Proposal

  • Rework track.ts around a per-player supply with printed handedness; drop the variant machinery.
  • Add a move cost per card (1 normally, 2 for sharp curves) and charge it against the six Moves.
  • Confirm with the designer whether run-around is a built pattern rather than a card — see §10.

4. Industries and modifiers — much smaller, much more specific

What the design says

Each industry is one car out and one loader, not the 2–3 capacity and 2–3 Laborers I invented:

Industry In deck Car Direction Base capacity
Freight House 2 Box BOTH 1 boxcar out, 1 loader; boxcars in
Mine Tipple 2 Hopper OUT 1 hopper out, 1 loader
Refinery 1 Tank OUT 1 tank out, 1 loader
Power Plant 2 Hopper, Tank IN 1 loader
Packing Sheds 1 Reefer OUT 1 reefer out, 1 loader
Grocer's Warehouse 1 Box, Reefer IN —

Capacity is then grown by industry-specific modifiers, each adding "+1 out, +1 loader":

  • Mine Tipple → Prep Plant, Coal Piles, Conveyor Belts
  • Refinery → Pipelines, Oil Depot, Viscosity breakers
  • Power Plant → Transmission lines, Rotary Dumps, Steam Turbines
  • Packing Sheds / Grocer's → Ice House, Local small groceries
  • Freight House / Packing Sheds / Grocer's → Truck dock, Forklifts, Railroad Express Agency

Column E is a lockout list — a concept we do not have at all. Freight House locks out Grocer's Warehouse; Mine Tipple locks out Power Plant; Refinery locks out Power Plant; Packing Sheds locks out Grocer's Warehouse. Presumably a player may not build both of a locked-out pair.

Passenger side — our guesses were right

Office Design What we built
Depot 1 psgr out, 1 in, 1 porter, 2 A/D 1 porter, 2 green, 2 red, 2 A/D
Station 2 / 2 / 2 porters, 3 A/D 2 porters, 3 green, 3 red, 3 A/D
Terminal 3 / 3 / 3 porters, 4 A/D 3 porters, 4 green, 4 red, 4 A/D
Whistle Post 1 A/D, not in deck, 4 copies 1 A/D ✓

Porters and A/D tracks match exactly. Our slot capacities are one too generous at every tier — the design gives slots equal to porters, not one more. Passenger modifiers (Waiting area, Restaurant, Hotel) are what grow them.

Proposal

  • Retune every industry to 1 out / 1 loader and rebuild capacity growth around the 17 modifiers. This makes Gap 10a's "moderate, varied by industry" profile obsolete.
  • Correct passenger slots to equal porter count.
  • Implement lockouts — a new placement constraint.
  • This changes the economy substantially: a base industry is far weaker than what we modelled, so Gap 12's balance measurements must be re-run from scratch rather than adjusted.

5. Trains — names, speed classes, and per-train rules

Timetabled (1–12)

# Name Speed Consist Rule
1/2 Crack Limited Fast 3 coaches † Stop at Terminals only. No switching. Expedite.
3/4 Express Fast 2 freight May drop or pick up one freight car at every location. Expedite.
5/6 The Sparrow Fast 2 coaches † No switching. Expedite.
7/8 Local Slow 1 freight + 1 coach Coach must remain on station track if switching.
9/10 Heavy Freight Slow 3 freight + caboose
11/12 Drag Freight Slow 2 freight + caboose

† The two coach counts have since been swapped by Jesse (Gitea#7, 2026-08-22): the Crack Limited now carries 2 coaches and The Sparrow 3. The table above is left as Trains3.pdf prints it, because that is what this section is for — what the design SAYS. What the game plays is src/engine/content.ts, with the per-card table in ../StationMaster-Home-Deck-v0.4.5.md.

Extras (X13–X22) — ten distinct trains, not four generic ones

Appleseed Extra (MT freight only, may drop but not pick up), Fruit Growers Express (reefers only), Yard Xfer, Light Engine Move (no cars at all), Campaign Train (one turn at station for speeches), Circus Train (one turn stopped anywhere earns 1 point), Military Train, Director's Private Car, Freight Extra, Pee-Dee (per-diem, may only pick up empties). Plus a Second Section card that duplicates the next scheduled train's seniority, rules and consist.

What this changes

  1. Consists are by CATEGORY — "Freight (2)" means any two freight cars, not two hoppers. Our allowedTypes model is too narrow.
  2. Fast / Slow is a train property that pairs with the Mainline cards' 60/30 speeds (§6). We have no speed model at all.
  3. "Expedite" is a keyword appearing on seven trains, meaning is not yet defined for us.
  4. Per-train operating rules — "no switching", "stop at Terminals only", "may drop or pick up one freight car at every location". We have none of these.
  5. Extras are X13–X22, all junior to every timetabled train. Gap 5 (Extra vs Timetabled ties) becomes unreachable — the tie it resolves cannot occur. The decision is harmless but moot.
  6. The Circus Train earns a point for standing still — the first revenue source that is not a load/unload operation. Our scoring model assumes only §9 operations and collisions.
  7. Second Section makes the "Sister trains" optional rule concrete.

Proposal

  • Rewrite the train catalogue from Trains3.pdf.
  • Add speed: fast | slow and a rules field per train; implement the operating rules as checks in apply.ts.
  • Define "Expedite" with the designer before implementing it — see §10.

6. Mainline cards — a whole system we reduced to a constant

We modelled a Mainline card as 2 regions, uniform. The design has ten distinct card types:

Card Speed Notes
Plains 60
Curves 30
Hilly P60 / F30 different speeds for passenger and freight
Heavy Grade (Up) G player sets orientation; Brakeman/Airbrakes/Helpers unlock better start positions
Double Track 60 trains may pass
Uncontrolled Siding 60 trains may pass; separate "no pass" and "passing" starts
Tunnel 30
Trestle 60
Interchange 60 sort cars into any new order; has a Yard Limit. Printed "Yard" on the prototype card and renamed after play — it shared a word with the Division Yard, the Classification Yard, the Salvage Yard, the Yard Office and the Small Yard, and is none of them
East / West Division Point — the ends

Each card shows Start positions — where a train enters depending on direction, train type, and which modifier cards are in play. The Heavy Grade card has five distinct starts (plain, brakemen, airbrakes, plain, helpers), so playing Brakeman literally moves your entry point further along.

Realignment can convert one Mainline card type into another (Plains→Double Track, Curves→Plains, Uncontrolled Siding→Double Track, Trestle→Uncontrolled Siding).

What this changes

This is the single largest mechanical gap. Our Mainline Phase moves every train one region per Stage, unconditionally. The design has speed classes, per-train-type speeds, passing, grades that modifier cards ameliorate, and yards that re-sort consists.

It also bears directly on Gap 12. I measured "a train stands at the Office only 18% of Stages" and treated it as a possible balance problem. With Double Track, passing sidings, and 60-speed cards, traffic density is a designed variable — the measurement was taken against a placeholder.

Proposal

  • Model Mainline cards as typed, with a speed and a set of named entry points.
  • Implement Fast/Slow × card-speed to derive how far a train moves per Stage.
  • Re-run every Gap 12 measurement afterwards. The current numbers describe a game that does not exist.

7. Four entirely new card categories

Space-use cards (12)

Bean House, Flop House, Watertower, Hobo Jungle, Section House, City Blocks ×4, Engine Shops, Tenderloin District, Engineer Cemetery. All "burn tablespace" — they occupy a grid cell and do nothing for you. Presumably played at opponents, or a cost of drawing.

Enhancements (18)

  • Interlocking (+ Facing Point Locks): may stop an inbound train on the Limit track.
  • Yard Office: an inbound train with no coaches may arrive at the yard instead of the Train Order Office.
  • Small Yard: a train spending one Move in the yard may sort itself into any order, including cars ahead of the engine.
  • Water Column: lets you remove a Watertower.
  • Overpass: removes restrictions on a Railroad Crossing.
  • Telegraph / Telephone / Radio: once a day, when dispatching facing trains, add +4 / +8 / +12 to the other train's number. A genuine dispatching-technology progression.
  • ABS Signals: trains on this Mainline card will not rear-end each other; they stop short.

Small Yard deserves special note. It solves precisely the problem my bot cannot handle: §A.3 forces cars off in seated order, so spotting a specific car needs the consist re-ordered. A Small Yard makes that possible. The switching puzzle was designed to have this answer, and we did not have the card.

ABS Signals directly touches Gap 2. We made collisions unconditional; this card makes them avoidable on a given card.

Mainline modifiers (7)

Brakeman, Airbrakes (requires Brakeman), Helpers, Realignment ×2, Facing Point Locks ×2.

Action cards — played at other players (10)

Derail, Broken Coupler, Railroad Crossing, Per Diem Inventory, Demurrage Charge, Customer Complaints, Vandalism, Hotbox, Outlawed.

We have no player-interaction mechanic whatsoever. Several of these cause point losses based on board state — "lose one point per 2 empty cars on Secondary Tracks" — which is a scoring channel our model does not have. In a Competitive game these are presumably a large part of the tension.

Proposal

Treat these as four separate work packages, in this order: Enhancements (they change core movement and switching), Mainline modifiers, Action cards (needed for multiplayer to mean anything), Space-use (lowest mechanical weight).


8. What this does to the decided gaps

Gap Status now Why
1 Phase order stands nothing in the new files contradicts it
2 Collisions automatic amended ABS Signals makes them avoidable on a card
3 Office upgrades stands, counts confirmed A/D and porters match exactly
4a Deck composition superseded 52 → 115, track removed from deck
4b Piece counts needs re-derivation Mainline speeds change train turnaround entirely
4c Consist criteria superseded consists are by category, with per-train rules
5 Extra/Timetabled ties moot Extras are X13–X22; the tie cannot occur
6 Victory conditions needs re-derivation new revenue sources and point losses
7 Terminology stands
8 Office junction stubs superseded tracks.png gives every office and industry card a plain east-west track and no stub; a district hangs off a turnout
9 Make-up round repeats stands
10 Card faces superseded this is the real card list
11 Track orientation superseded handedness is printed; both hands are supplied
12 Balance targets invalidated, re-measure measured against a placeholder ruleset
13 Deck scaling largely dissolves track is per-player by construction

Superseded decisions should be marked, not deleted — the reasoning that produced them is how we know what questions the design answers.


9. Code impact

Component Impact Notes
1 Card catalogue Rewrite pure data; largest single edit but lowest risk
2 State model Major new card kinds, per-player track supply, typed Mainline cards, train speed/rules
3 Track graph Major curves, printed handedness, per-card move cost
4 apply Major per-train operating rules, enhancements, action cards played at opponents
5 Phase driver Major speed model, passing, grades, yard sorting
6 legalActions Moderate follows from 4; the discipline of delegating to check protects it
7 RNG None
17 Bot Rewrite Small Yard changes the switching problem fundamentally
18 Harness Minor re-run everything
16 Replay Moderate new card types and mechanics to narrate
19 Tests Substantial most rules assertions need revisiting

The engine's architecture holds. Nothing here breaks the check/execute/reduce split, the event log, or the pure-engine boundary. This is a large content and rules expansion inside a structure that was built to take it — which is the main thing worth saying about it.


9a. Answers from the designer

Recorded as they are given, so nothing is lost between sessions.

# Question Answer
1 What do Mainline 60 / 30 mean? Miles per hour, expressed as crossing time. A 60 card takes one Stage to cross; a 30 card takes two. The printed cells are decoration. Realignment (Curves→Plains) therefore has real value, and 30-cards are genuine chokepoints.
2 How does Fast/Slow affect crossing? Slow adds one Stage to every card. Fast 60→1, 30→2; Slow 60→2, 30→3. The label therefore matters on every card. Consequence to watch: Slow trains occupy a Crew Tray roughly twice as long, so tray scarcity (§7) bites considerably harder than the placeholder measured.
3 What does "Expedite" mean? The train departs the same Stage it arrives — it does not spend a Stage standing at the Office. Still subject to the normal §8.1 clearance rules, so it can be held. Fits X17's "one turn at station then expedite", and partly offsets the Slow-train transit cost below.
4 What does a lockout prevent? Building both in your district. If you hold a Mine Tipple, a Power Plant card is unplayable in your Office Area, and vice versa. Each locked pair is a producer and the consumer of the same commodity, so this forces traffic to flow between districts — a deliberate multiplayer-interdependence mechanic. In solitaire it simply narrows the build options.
5 Is a run-around a card? No — a pattern built from the track supply. Opposite-hand turnouts joined by straights. Nothing to implement: reachability is computed from geometry, so a valid bypass already works. This explains the 8 turnouts per player, and makes §A.5's facing-point move a building achievement rather than a lucky draw.
6 How are Space-use cards played? At another player's district, consuming a grid cell they wanted. This explains Water Column ("remove any Watertower in your district" — one an opponent gave you) and Vandalism (exploits a Hobo Jungle you were saddled with). A second, milder attack channel alongside the Action cards. In solitaire they have no target — see the note below.
7 Does a district grow both ways? Yes, both — measured off tracks.png rather than inferred. The through track runs east-west across the exact vertical middle of every card, and every diverging leg leaves at 45° through the middle of the north or south edge. Turning a card 180° swaps that leg between north and south, so a turnout serves either side. Supersedes Gap 8's stubs in the other direction: no office or industry card carries a leg at all, so a district hangs off a turnout laid on the Running Track. Consequences: no card joins north to south, so descending a row costs at least two cards (leg out, then a curve turning the run back east-west) and districts are wide and shallow; and a printed card's handedness fixes which diagonal its leg lies on, so a run-around needs one card of each hand.
8 Any cap on trains in play? No — Crew Trays are the only limit. All 12 timetabled trains may end up scheduled; Extras run on top ad hoc; a due train with no free crew is held (§7). Already implemented. This makes the Crew Tray count (players + 3) the single most important balance dial, and "held" a common visible state.
9 What is the Second Section card? A card played on a train that is due out. A second identical train runs immediately behind it — same number, rules and consist — and needs its own Crew Tray. It deliberately creates the following-train situation §8.1 makes the Superintendent rule on, so a player can force the game's central decision onto the table. Explains the green flags on the artwork. Supersedes the "Sister trains" optional rule, which should be removed from Appendix B.

Solitaire consequence of Q6

If Space-use cards are played at opponents, then in the solitaire MVP they have no legal target — 12 of 115 cards (10.4%) become dead draws. Combined with the 10 Action cards, which are also opponent-directed, 22 of 115 cards (19%) do nothing in a one-player game.

That is a real finding for the MVP, and there are only a few honest ways to handle it: remove them from a solitaire deck, allow them to be discarded freely, or accept that solitaire draws are a fifth dead. Worth deciding explicitly rather than by default. Not blocking — flagged for after the remaining questions.

Consequence noted at the time of answering

Under Q1 + Q2, on a 3-player Division (4 Mainline cards, mixed terrain):

Mainline Stages + Office stops End-to-end
Fast train 6 3 9 Stages
Slow train 10 3 13 Stages

A Day is 12 Stages, so every Slow train is still on the road when the next Day begins, holding its Crew Tray. With players + 3 trays this will throttle freight hard. Expedite (Q3) relieves it somewhat for the trains that carry it — but none of the Slow freight trains do. Worth re-measuring once the speed model is implemented; the Crew Tray count is the obvious dial.


10. Questions only the designer can answer

  1. "Expedite" — appears on seven trains and is never defined. Priority? No stopping? Extra speed?
  2. Speed numbers. Do 60 and 30 mean "cells per Stage", "Stages to cross", or literal mph against a 2-hour Stage? A Mainline card is "roughly a hundred miles" (§2.1), so 60 mph × 2 h ≈ one card per Stage and 30 ≈ two — but this should be confirmed, not inferred.
  3. Fast vs Slow trains — how do they interact with a card's speed? Does a Slow train take double on every card, or only where the card distinguishes (Hilly's P60/F30)?
  4. Lockouts (spreadsheet column E) — does one card prevent building the other, or prevent both operating?
  5. Run-around — we treat it as a card; it is not in the supply. Is it a pattern built from two turnouts?
  6. Space-use cards — played at yourself as a cost of drawing, or at opponents?
  7. Where the Office's junction stubs are. Settled by measuring tracks.png: the through line is dead centre on every card, not along the top edge, and no office or industry card has a stub in either direction. See Q7 above.
  8. Are all 22 trains in play at once, or is the timetable still 12 slots with Extras run on top?
  9. Second Section — is it a card played on a scheduled train, or its own train?

The temptation is to rebuild everything at once. I would not.

  1. Transcribe the catalogue first (content.ts from the spreadsheet and Trains3.pdf). Pure data, no rules risk, and it makes the true scope concrete.
  2. Answer §10's questions, particularly speed and Expedite — several later decisions hang on them.
  3. Mainline card types and the speed model. The largest mechanical gap and the one that invalidates the current balance numbers.
  4. Track supply and curves, including the sharp-curve double Move cost.
  5. Industry retune to 1-out/1-loader plus the modifier system, then re-run the harness. Expect very different numbers.
  6. Enhancements, starting with Small Yard and ABS Signals — both change core loops.
  7. Action cards, which is when multiplayer becomes a real game rather than parallel solitaire.
  8. Space-use cards last.

Do not retune anything against current measurements. Gap 12's numbers describe a placeholder ruleset. Re-measure after step 5 and treat everything before that as void.


§10 Q13 — rear-end collisions on a Mainline card are not implemented

Found by playing. The Superintendent's §8.1 ruling asks whether one train may follow another onto an occupied Mainline card. Granting it is currently free: both trains cross, nothing collides, no penalty. Verified directly — two trains on one card, clearance granted, both alive and revenue unchanged.

Two places in the rules say it should not be free:

  • §10 — "A collision on a Mainline card is the fault of the Superintendent who cleared the trains out; he loses 5 Revenue points" and "Train-on-train. Both trains are immediately removed."
  • ABS Signals — "Trains on this card will not rear-end each other. They will stop short of a collision." A card whose entire purpose is preventing rear-enders presupposes that rear-enders happen.

But §8.3's trigger list does not include it. The three automatic triggers are all about arriving at an Office or highballing past fouled track; none covers a follower catching a leader mid-card. So the rule is asserted in §10 and priced by ABS Signals, yet never given a trigger.

The missing piece is timing, and it is a design decision rather than a transcription gap. Crossing is counted in Stages (Q1), so both trains simply run their counters down. Candidates:

  1. On entry — following onto an occupied card wrecks both at once. Makes clearance a pure gamble and ABS Signals very strong.
  2. On catching up — collide only when the follower's remaining Stages would take it past the leader. Rewards judging the gap, which is what a Superintendent actually does.
  3. Never — clearance is genuinely safe, §10's Mainline clause is vestigial, and ABS Signals is worth less than it reads.

Until this is settled the clearance buttons describe only what the engine actually does — they say the train "closes up behind" rather than promising a −5 risk that cannot occur. Wording that invents a consequence is worse than wording that under-sells one.


§7 — where an Extra starts, and which way it runs

Reported from playing v0.4.9e (Gitea#4): "When extras are played the player doing so may choose where the extra starts. They may choose either division point. And if the interchange mainline card has been played, they may start the extra on that card and choose the direction from there. If there is potential for conflict with other trains in that area the superintendent may hold the extra."

This supersedes an earlier ruling, and the supersession is the interesting part. §2.3 gives every train its direction from its number — odd runs west, even runs east — and an earlier pass extended that to Extras explicitly: "the number decides, like everything else on the timetable." That reading cannot survive "either Division Point". An odd Extra placed at the WEST end would run west, leave the Division on its first move having crossed nothing, and be paid the completion Revenue for the run.

So for Extras only, the start decides the direction:

Start Direction
Western Division Point east
Eastern Division Point west
Interchange player's choice
Control Point (any Office above a Whistle Post) player's choice

A timetabled train is unchanged: its number still decides. The Extra cards were always printed direction: 'playerChoice' (§5) and the engine had been overriding it; they now mean it.

The Interchange start is a YARD, not a spot on the running line

§7's last clause — "the superintendent may hold the extra" — is what settles how this is modelled. An Extra started at an Interchange stands in that card's yard, off the running line, and highballs onto the card itself at a later Mainline Phase. Three things follow, all of them Jesse's rule rather than an implementation convenience:

  1. Placing it can never force a collision, however busy the card is. It is not on the road yet.
  2. A guaranteed collision holds it in the yard for another Stage, and it tries again next Stage.
  3. A potential collision is the Superintendent's to rule on.

Those last two are exactly §8.1's two answers — an absolute bar against a facing train, a judgment call against a following one — so the Extra leaves the yard through the same clearance check a train leaves a Division Point through. Nothing new decides collisions.

The Interchange keeps its printed "sort cars in new order" concept, still unimplemented (§6). Being the card with a Yard Limit is what makes it the one Mainline card a train can be made up on.

Which starts are offered is a setting

The Division Points and the Interchange sit on shared ground and belong to nobody; starting an Extra inside a player's own district does not. That is a table preference rather than a rule, so it is set when the game is dealt (extraStart): Division Points and Interchange only, plus the playing player's own Control Point, or plus any player's Control Point. A Whistle Post never qualifies at any setting — being a place an Extra can start is part of what upgrading buys (§11).

Two bugs found underneath it

  • The Mainline cards were rolled, not dealt. buildDivision drew uniformly from the nine card TYPES with replacement, so a Division could be dealt two Interchanges or two Tunnels, and Plains — printed twice in the deck — carried the same weight as cards printed once. docs/StationMaster-Mainline-Deck-v0.4.5.md had already flagged the mismatch as needing correction; "an Extra may start at the Interchange if one is on the board" is what forced it, since that only reads as a rule if the board holds at most one. Now dealt from the printed ten-card deck without replacement.
  • An Extra started anywhere but a Division Point ran empty. isBeingMadeUp asked only "is this tray standing at a Division Point", which was the whole truth while that was the only place to build a train — so the Control Point start had shipped since it was added with a train that could never be given a consist, and the Interchange start would have shipped the same way. Found by playing it, not by the tests, which had only ever asserted where the tray landed.

§6.2 — a train card is never discarded

Jesse's ruling, v0.4.9e playtest (Gitea#6): "Players are not allowed to discard Train cards. They may keep the card in their hand for multiple stages and even multiple days, but they may not discard it. If a player has three train cards in their hand, and they draw a fourth, then they must play one of those cards."

Extras count. An Extra is a train, even though it runs once and ends in the Salvage Yard where a Timetabled card joins the timetable for the rest of the game.

§6.2 as transcribed says only "the player must reduce his hand to no more than three cards" with no exception for any card type, so this is a ruling rather than a gap — the prototype rules do not address it either way.

It needs no forcing mechanism, and that is the point

The interesting property of this rule is that the forced play falls out of two rules that already exist rather than needing a third:

  1. a train card cannot be discarded, so it is not among the ways to shed a card; and
  2. draw.end already refuses while the hand is over the limit (§6.2).

A player holding four trains therefore has exactly one legal way to conclude the turn — play one — without anything in the engine ever computing "you must play a train". The corner cannot lock a player in, because playing a train card is unconditionally legal: card.play's train case refuses only a board placement, and a train card played when the timetable is full still leaves the hand (it simply schedules nothing). Confirmed by playing it: a hand of four trains offers zero discards, no draw.end, and four plays.

The bot needed no rule of its own either. legal.ts enumerates candidates and filters them through check, so the option stops being offered; and the developer bot already reaches for card.play before it reaches for a discard. Measured over 400 games: 400/400 finished, revenue unmoved, and trains scheduled 1.2 → 1.3 — the rule's intended effect, small because a bot rarely held four.

Consequences

  • Two of the three published replays discarded train cards (2 and 15 of them) and were retired and re-recorded. Jesse's call: "I'm okay with retiring the replays that no longer work under those old rules."
  • The opening six-card hand is not exempt. Under six random cards a player opens holding six against a limit of three; if four or more are trains, they all go onto the timetable on turn one. Jesse's call: "If the opening hand has lots of trains, then lots of trains will be placed on the board." Rare — roughly 1.5% of deals — but deliberate.
  • The player is told, on the card and on the button. handDiscardable on the Frame marks which cards may be shed, the hand panel says so in the card's own tooltip, and when EVERY card held is a train the blocked end-turn button changes its text to say a train must be played. That is the Gitea#2 lesson applied: a rule the player cannot see is a board with nothing to click and no reason given.