v0.7.2 — a leg that is part of the row, the deck the sheet prints, regions not miles per hour, and a Division you read left to right
Gitea#17 — a 45° leg is an end of the west-to-east row, so backing into a cut through a curve's south leg no longer couples it back to front. The same assumption left a crew's own cut standing when it pulled out through a leg, which is the "cars left behind" report we had failed to reproduce. Gitea#14 — every count is docs/Deck cards5.xlsx. Track halved, and the Q12 office doubling and Gap 12 industry tripling both come out with it: they were measured against a deck with twice the track, and keeping them at the sheet's track count wipes out the reefer chain entirely. 84 rows now match card for card; the ten Safety, Event and Inspection cards it adds are not built and are held out. Cards the sheet no longer lists are dealt zero copies rather than deleted, so their rules stay implemented. Gitea#15 — RAR reversed it: a rail may stop dead against its neighbour and the placement is legal. What must hold is that no train crosses the gap, which was already true and is now pinned against the reported board. Gitea#3 — the printed speeds are scenery. A card costs one Stage per printed region and where a train STARTS is what varies; Fast/Slow is read on Hilly alone. Entering a one-region card behind another is a collision now, which is what ABS exists to prevent, and ABS no longer holds trains silently. Gitea#18 — the Division draws as one row, west to east, with no office-area detail. East is finally always to the right. Closes #3 Closes #14 Closes #15 Closes #17 Closes #18
This commit is contained in:
+161
@@ -19,6 +19,167 @@ page as `v0.1.0 · <sha> · <date>`, so what is deployed can always be identifie
|
||||
|
||||
---
|
||||
|
||||
## 0.7.2 — 2026-08-26
|
||||
|
||||
Five issues off the tracker. Two are engine bugs a player hit at the board, two are the design
|
||||
catching up with rulings from RAR that the code had got wrong or never had, and one is the Division
|
||||
map being redrawn. The first four ship as **0.4.9h** on the 0.4.9 line; the map does not — it is a
|
||||
multiplayer redesign, and pushing one of those into a build people are mid-playtest on invalidates
|
||||
the feedback.
|
||||
|
||||
### A 45° leg is part of the row (Gitea#17)
|
||||
|
||||
**REPORTED:** "Cars were West to East Caboose, Loaded boxcar, Loaded boxcar, Loaded boxcar. After
|
||||
backing into that square cars were attached to the train Loaded boxcar, Loaded boxcar, Loaded boxcar,
|
||||
Caboose, Engine." The caboose came back next to the engine instead of at the far end, which also
|
||||
leaves the train badly made up under §8.2.
|
||||
|
||||
The square was a `sw` CURVE and the train backed in through its SOUTH leg. `standing` runs west to
|
||||
east, and both places that walk that row asked the PORT which end they were at: `exploreMoves`
|
||||
reversed the row for an `'e'` entry and nothing else, and `cutTowards` answered "you meet nothing"
|
||||
for a north or south exit. Neither is a property of the port. A 45° leg leaves through the MIDDLE of
|
||||
its edge, so its end of the run is whichever end the arc does not reach — a `sw` curve's south leg is
|
||||
the row's EAST end and an `se` curve's south leg is its WEST end.
|
||||
|
||||
`rowEndAt` answers it from the card, and `cutTowards` is narrowed from `Port` to `'e' | 'w'` so the
|
||||
type checker forces every caller to resolve rather than leaving a fourth to be found later.
|
||||
|
||||
**THE SECOND HALF WAS LIVE TOO, and is a report we had failed to reproduce.** With `cutTowards`
|
||||
returning nothing for a leg, a crew standing on a curve pulled out through it and DROVE AWAY LEAVING
|
||||
ITS OWN CUT STANDING — against §A.4's mandatory coupling. That is "cars left behind when backing up
|
||||
over them", carried as NOT REPRODUCED since 2026-08-22; the earlier sweep had tried that case only
|
||||
with an east or west exit. The report's second sentence — "I can later drive right through them" —
|
||||
is still unexplained and still open.
|
||||
|
||||
### The deck is the sheet (Gitea#14)
|
||||
|
||||
`docs/Deck cards5.xlsx` is in the repo, and every count in the catalogue is now its count. Track is
|
||||
halved: 16 straights, 8+8 curves, 8+8 turnouts, sharp curves at zero — which is where they already
|
||||
were, and where sheet 5 independently puts them.
|
||||
|
||||
**BOTH LONG-STANDING MULTIPLIERS COME OUT WITH IT.** The Q12 office doubling (14 → 7) and the Gap 12
|
||||
industry tripling (27 → 9) were measured against a deck holding 96 track cards, and halving the track
|
||||
turns the tripling backwards — the deck keeps dealing industries while the district stays too small
|
||||
to reach them. Measured over 300 bot games on identical seeds, 96 track with the multipliers / 48
|
||||
with them / 48 without: reefer cars set out by a crew **49 / 0 / 39**, mean revenue **−0.20 / +0.22 /
|
||||
+0.27**. The middle column wipes out the reefer chain completely. The sheet's own density is the best
|
||||
of the three on both counts.
|
||||
|
||||
Q12's own failure was re-measured rather than assumed: 43 of 100 games now never upgrade off a
|
||||
Whistle Post, up from 25 — but they average −0.2 revenue against +1.4 for games that do, where the
|
||||
gap used to be −6.0 against −0.4, and collisions fell from 26 per 100 games to 6. Staying at a
|
||||
Whistle Post is now common and survivable rather than rare and fatal.
|
||||
|
||||
Everything sheet 5 does not list is dealt ZERO copies rather than deleted, so the design stays
|
||||
visible and the rules stay implemented: the Telegraph/Telephone/Radio dispatching ladder, Facing
|
||||
Point Locks, Flying Switch, Section House and Vandalism — all confirmed by Jesse as deliberate
|
||||
removals — plus Poling and the sharp curves, which were already there. Card for card, **84 rows agree
|
||||
with the sheet**; the only ones that do not are the ten Safety, Event, Inspection and Space-use cards
|
||||
it adds that are not built, held out until they are.
|
||||
|
||||
### A rail may stop dead against its neighbour (Gitea#15)
|
||||
|
||||
Filed as "track placements must connect", against a right-hand curve laid with its north leg against
|
||||
an Ice House and the turnout below pointing at its portless south edge. **RAR reversed it on review:**
|
||||
the placement is fine, and a stub like that has a use — a siding to park cars on. What he asked to
|
||||
confirm instead is that no train can traverse the gap.
|
||||
|
||||
It could not, and cannot: `exploreMoves` gates every hop on `joins`, which tests both ports AND that
|
||||
two 45° legs lie on the same diagonal. That was already true and simply unpinned; `track.test.ts`
|
||||
now holds it against the reported geometry, including a check that the curve IS reachable from the
|
||||
side that joins, so the negative test cannot pass on a card that is merely unreachable.
|
||||
|
||||
A per-edge placement check was written and then taken out, along with a matching guard on
|
||||
`checkTurnoutUpgrade`. Both are documented in place as deliberately absent, because this is exactly
|
||||
the rule someone will "fix" again. A Modifier is scenery (Jesse): a rail pointing at a building is
|
||||
fine.
|
||||
|
||||
### Crossing a Mainline card is regions, not miles per hour (Gitea#3)
|
||||
|
||||
**REPORTED:** a train taking two Stages to clear Double Track, which prints 60. RAR, on review:
|
||||
"Ignore speed signs, they are just graphics. Regions shown on cards indicate how many stages it takes
|
||||
to cross."
|
||||
|
||||
Two recorded rulings are superseded together — Q1, that the printed 60/30 are crossing time, and Q2,
|
||||
that a Slow train adds a Stage to every card. Q2 is what produced the report. Cards carry a region
|
||||
count now and **where a train STARTS is what varies**: Plains 1, Double Track 1, Trestle 1, Curves 2,
|
||||
Tunnel 2, Heavy Grade 3. Fast/Slow is read on Hilly and nowhere else — and Hilly no longer reads the
|
||||
consist, which had a fast freight crossing slower than a slow passenger train. The grade modifiers
|
||||
move the start rather than cutting the clock: Helpers start an uphill train a region on, Brakeman a
|
||||
downhill one, Airbrakes another again. The Uncontrolled Siding and the Interchange print a back
|
||||
region that is not road: a train through starts past it, one arriving to find the siding occupied
|
||||
takes it and runs a region behind, and an Extra beginning its run at an Interchange starts there.
|
||||
|
||||
**THREE THINGS WERE MISSING RATHER THAN WRONG.** With Plains now one region, a following train is in
|
||||
the same place as the train ahead the moment it enters — and nothing tested that, because the
|
||||
catch-up check sits inside `stagesRemaining > 1`, which a one-Stage crossing never reaches. That is
|
||||
the case ABS describes ("the train moving onto the card is instead held back") and it needed
|
||||
building. ABS was also holding SILENTLY on the Office and Division Point paths, so the one card whose
|
||||
purpose is preventing a wreck did its job invisibly. And `collide` never released the A/D track,
|
||||
which did not matter while every collision happened out on the road — a train destroyed as it LEAVES
|
||||
is still standing at the Office.
|
||||
|
||||
The Uncontrolled Siding was marked "trains may pass", which skipped the collision test altogether and
|
||||
made the siding do nothing at all. It is `false` now, with the siding entry doing the work.
|
||||
|
||||
Measured: on the Mainline cards of a 3-player Division, a fast train pays ~5.6 Stages against ~5.4
|
||||
before and a slow one ~6.0 against ~9.4. **Fast traffic is unchanged; slow traffic is about a third
|
||||
quicker**, and the gap across a Division collapses from roughly four Stages to under one — so Q2's
|
||||
recorded consequence, that every Slow train is still on the road when the next Day begins holding its
|
||||
Crew Tray, no longer holds and `players + 3` is due a re-examination.
|
||||
|
||||
Two effects are recorded in `TODO.md` rather than acted on: freight share fell 8% → 5% and completed
|
||||
freight loads got scarcer, which runs against the obvious expectation and nobody knows why yet; and
|
||||
the bot stopped playing Red Flags — offered 4,212 times in 600 games, played 4.
|
||||
|
||||
### The Division is one row (Gitea#18)
|
||||
|
||||
**REPORTED:** "track design should not be horseshoe / square, but a single row… Division map should
|
||||
not show any office area detail."
|
||||
|
||||
It was laid out around a table — one row for a single seat, two facing rows for two, a horseshoe for
|
||||
three, a square for four — on the reasoning that players sit around one. Three reports came out of
|
||||
that, and the one that decided it is that **east stopped being to the right**: a player's east could
|
||||
be drawn south, west or north depending which lane their district landed in, on a map whose whole job
|
||||
is saying which way a train is going. `WDP · ML · Office · … · ML · EDP`, left to right, and the
|
||||
buffer stops simply face outward at the two ends.
|
||||
|
||||
An Office no longer expands into its Running Track either, so the map stops carrying every straight,
|
||||
turnout and Limits sign of every district — that is the Office map's job, and it draws them properly,
|
||||
with the rails. It also stops the Division map growing sideways every time somebody lays a card.
|
||||
|
||||
The trains stay, in two registers: those holding an A/D track ON the rail, and crews switching in the
|
||||
district UNDER it — the distinction drawn as position rather than colour, because that is where those
|
||||
trains are. Each chip carries its number, a direction arrow and a car count, with the consist and the
|
||||
train's printed card on the tooltip. Every district cell is four chips two-by-two regardless of tier,
|
||||
because a Whistle Post with one A/D track can still hold four trains when three of them are crews,
|
||||
and sizing by occupancy is what "The Roster Pass" fixed. 1,580px wide at four players against 842
|
||||
before, drawn at 1:1 so it scrolls rather than shrinking — Jesse's call, "zooming and scrolling
|
||||
worked fine".
|
||||
|
||||
This supersedes `TODO.md` item 24 outright and makes 19, 20, 21, 22, 25 and 26 irrelevant; item 27 is
|
||||
fixed.
|
||||
|
||||
### Six test fixtures that pinned a seed and meant "a game like this"
|
||||
|
||||
Every one of them broke on a rules change and none was about the rule that changed: the deck's SIZE
|
||||
moves the RNG stream, so any count change re-deals every fixture that names a seed.
|
||||
`mainline-cards` now searches for a Division holding a single-track card, `multiplayer` for a game
|
||||
that reaches Day 3, `web` clicks every play verb rather than assuming the first goes on the board and
|
||||
searches for a seed that builds a board, and the `sim` commodity samples were re-measured — a tank is
|
||||
first set out at game 216 now, unload Revenue at game 46. A seventh, `mainline-cards`' `hand()`
|
||||
helper, threw when a card was not in the deck, so dealing Flying Switch zero copies took five passing
|
||||
tests of an unchanged rule with it; it mints one now, which is the point of keeping a row at zero.
|
||||
|
||||
**And one real bug, in a test.** `the game conserves Rolling Stock` went red claiming the engine had
|
||||
conjured three cars. The engine was right: Gap 2c sends a wreck's cabooses to the Division Yard and
|
||||
everything else to Classification, destroying nothing. The test subtracted the wreck's consist from
|
||||
the expected census — a rule the engine does not have — and the branch had never executed, because
|
||||
none of its six seeds had ever collided. The census is held flat unconditionally now, which is both
|
||||
the true invariant and stricter than what it replaced.
|
||||
|
||||
---
|
||||
|
||||
## 0.7.1 — 2026-08-25
|
||||
|
||||
Four issues off the Gitea tracker, all of them things a player saw at the board. Two are engine or
|
||||
|
||||
Reference in New Issue
Block a user