v0.4.3 fixed load/unload bugs. empty cars must be staged prior to loading. rolling stock is now conserved.
This commit is contained in:
@@ -21,6 +21,76 @@ page as `v0.1.0 · <sha> · <date>`, so what is deployed can always be identifie
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 0.4.3 — 2026-08-14
|
||||
|
||||
### A load has to have somewhere to go
|
||||
|
||||
Jesse walked through how loading an industry is meant to work at the table, and the engine got four of
|
||||
the five steps exactly right. It got the first one wrong, in both directions.
|
||||
|
||||
**You could stage cargo against no car.** §9.3 requires an empty car of the right type standing on the
|
||||
industry's track before anything else happens — *"otherwise you are just dropping cargo onto the
|
||||
tracks, pointless waste"*. The engine checked for that car only at the **last** step, when the load
|
||||
came off WORK. So you could fetch cargo with the Freight Agent, walk it M→A→W across three Stages and
|
||||
three Laborers, and only then find there was nowhere to put it. Worse than waste: from the moment the
|
||||
load lands on M the industry track is **locked**, so no train can come in to spot the car you now need.
|
||||
The only way out was a Freight Agent unjam — another whole turn, to undo a move the rules should never
|
||||
have offered.
|
||||
|
||||
Now gated in three places, all counted rather than merely present:
|
||||
|
||||
- **`freightAgent.stockOutbound`** — no cargo is fetched unless a matching empty is spotted and not
|
||||
already promised to a load already in the box or on the sign.
|
||||
- **`laborer.startLoad`** — the same check again, because it is not redundant: coupling is mandatory,
|
||||
so a crew running over that industry track *must* pick up the spotted empty, and the cargo you
|
||||
staged an hour ago can be left with nothing.
|
||||
- **`laborer.beginUnload`** — the mirror. The red Inbound box is where an inbound load lands, and it
|
||||
was checked only at the final step too. Counted, because only the W box must be free to begin: once
|
||||
a load moves W→A a second can start behind it, and every red box in play holds exactly one car.
|
||||
|
||||
**Strict type matching throughout** — a hopper load cannot be swapped onto a tank. And `startLoad` no
|
||||
longer always takes `outboundBox[0]`: it starts the first load that has a car to land on, so a Power
|
||||
Plant holding a hopper load and a tank load against one spotted tank works the tank instead of
|
||||
reporting the whole facility blocked.
|
||||
|
||||
**Passengers are deliberately exempt and it is written down.** People can wait on a platform for a
|
||||
train that has not arrived, so a Passenger Facility still stocks freely. Freight cannot: a crate on the
|
||||
ground is not a shipment.
|
||||
|
||||
**Measured before building it, which is why it was worth building.** Requiring the car removes **78% of
|
||||
the `stockOutbound` moves the menu offered** (704 → 157 across 200 games) — but **99.3% of the moves the
|
||||
bot actually took survive** (138 of 139). The rule deletes offers a competent player would never have
|
||||
used. Bot unchanged at 7.3 mean. On the unload side it removes 2.2% of offers, and the jam it prevents
|
||||
was caught happening three times in 200 games.
|
||||
|
||||
### The Blocked panel says what to do, and in what order
|
||||
|
||||
The refusal codes never reach a player, because the menu simply stops offering the action — so with
|
||||
78% of stocking moves gone the panel was the only thing that could explain it. It said *"green box
|
||||
empty — nothing to load (needs a Freight Agent action)"*, which is step two told to someone who has not
|
||||
done step one. It now says to bring a car in first, names the commodity, and distinguishes "MEN is
|
||||
occupied" from "there is nothing here to load onto", which send you to fix quite different things.
|
||||
|
||||
### Rolling stock is exactly conserved
|
||||
|
||||
`TODO.md` recorded the inbound path minting ~1.3 cars a game and blocked tuning `ROLLING_STOCK_SUPPLY`
|
||||
until it was settled. Re-audited: **exactly conserved, 100 games out of 100, range 0..0.** The
|
||||
asymmetry had already been closed from the other end when `unloadBegan` and `passengersDetrained`
|
||||
started taking their replacement empty out of the Division Yard instead of conjuring it — a load is a
|
||||
car that moved, not a car that appeared, which is exactly the tabletop procedure Jesse described.
|
||||
|
||||
Both conjuring fallbacks now **throw** instead of minting, so the leak cannot come back quietly;
|
||||
neither fired across the suite or the audit. `ROLLING_STOCK_SUPPLY` is unblocked for the rebalance.
|
||||
|
||||
(The original audit's arithmetic was off in the same way mine was on the first attempt: cars set out on
|
||||
a card live in `card.standing` and are easy to leave out of the count, which makes a conserved game
|
||||
look like a leaking one.)
|
||||
|
||||
### Replays
|
||||
|
||||
Two of five died on the rule change — they replayed 138/336 and 81/347, which on screen looks exactly
|
||||
like a game that ended early. Re-recorded; three published, all verified to their last intent.
|
||||
|
||||
## 0.4.2 — 2026-08-13
|
||||
|
||||
### A completed run pays the whole table
|
||||
|
||||
Reference in New Issue
Block a user