v0.7.1 — a caboose is not a load, a Day that says it ended, and a train you may throw away

Four issues off the Gitea tracker, all of them things a player saw at the board. Reasoning for
every item, and what was verified how: CHANGELOG.md.

- Gitea#8: X22 Pee-Dee refused every caboose, including the one it was made up with, so setting it
  out stranded the train. All six cabooses are minted loaded because §2.2's "coloured is loaded,
  white is empty" doubles as a piece count in the supply table; one read of the flag took that
  literally. A caboose carries the crew, not freight, so it is never a load.
- Gitea#10: a Day turns over inside the phases that run themselves, so it passes between one click
  and the next — and both transient signals fade before a player reading the board notices. A modal
  stops and waits, carrying the standings, the Days left and the combined target. Suppressed on the
  first frame, on Undo stepping back across a rollover, and on the Day the game ends.
- Gitea#9, which SUPERSEDES Gitea#6 from three days ago: a Timetabled train may be tossed face-up
  to a Department slot, where a rival may pick it up — the second half of the ruling needed no code,
  since that is where every discard already goes. An Extra still may not. A New Game setting on this
  line (discardTimetabled, on by default), the plain rule on the 0.4.9 line.
- Gitea#2 is not an engine bug: the rules are implemented exactly, and running the coach pool dry is
  Jesse's ruling to keep — "part of the strategy". What was wrong is that the game said nothing. A
  blocked platform now gives its reason, from the engine's own predicate, including how many coaches
  are stranded in Classification and what brings them back.

The same four ship as v0.4.9g on the playtest line.

Closes #2
Closes #8
Closes #9
Closes #10

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FLnYR4XtXQNamYJXGYT8oC
This commit is contained in:
Jesse.Markowitz
2026-08-25 10:46:22 -04:00
co-authored by Claude Opus 5
parent 603d38602c
commit 441447648d
17 changed files with 977 additions and 115 deletions
+77 -18
View File
@@ -69,12 +69,40 @@ Queued 2026-08-22, from the v0.4.9e gameplay-testing report filed as Gitea issue
and Extra alike; the forced play falls out of the hand limit rather than needing a mechanism of
its own. Reasoning in `docs/rules/implications.md` §6.2.
12b. **Gitea#2 — four porters, two passengers on the platform, and only one may be worked.**
DIAGNOSED, AWAITING JESSE'S RULING — see Play Balance below. The engine is faithful to the
written rules at every step; what bites is that BOTH directions of porter work move coaches
one-way into a Classification Yard that comes back only when the Division Yard is bare of all
~60 cars. Sixteen coaches in the game, and the reported save runs dry on Day 5 with eight of
them stranded in Classification.
12b. ~~**Gitea#2 — four porters, two passengers on the platform, and only one may be worked**~~ —
RULED AND FIXED in the release below, though not the way the report implies. The engine is
faithful to the written rules at every step; what bites is that BOTH directions of porter work
move coaches one-way into a Classification Yard that comes back only when the Division Yard is
bare of all ~60 cars. Sixteen coaches in the game, and the reported save runs dry on Day 5 with
eight of them stranded in Classification. **Jesse's ruling: the shortage stays** — "it is
possible to run out, that's part of the strategy" — so the three balance options in Play Balance
below are declined, not deferred. What was actually wrong is that the game said NOTHING: a Porter
action that cannot be taken is simply absent from the menu, and the "why is nothing moving?"
panel covered freight facilities only. That half is fixed.
12e. ~~**Gitea#8 — the per-diem train could not couple a caboose**~~ — done in the release below.
`ROLLING_STOCK_SUPPLY` mints all six cabooses `loaded: true` because §2.2's "coloured is loaded,
white is empty" doubles as a PIECE COUNT there and there is no white caboose. X22 Pee-Dee, whose
whole card is "may only pick up MTs", read that literally and refused every caboose including the
one it was made up with — set it out and the train was stranded, which made it unplayable rather
than merely restricted. A caboose carries the crew, not freight, so it is never a load.
12g. ~~**Gitea#9 — a Timetabled train may be discarded**~~ — done in the release below, and it
SUPERSEDES Gitea#6 (item 12c above), shipped three days earlier. A Timetabled train may be tossed
face-up to a Department slot, where a rival may pick it up — which needed no machinery, since
that is where every discard already goes. An Extra still may not: it never joins the timetable,
so it can never be what jams it. On this line the Timetabled half is a New Game setting
(`discardTimetabled`, on by default), because Jesse's reasoning is about games run longer than
five Days; the 0.4.9 line takes the plain rule. Reasoning in `docs/rules/implications.md` §6.2.
12f. ~~**Gitea#10 — a dialog when the Day rolls over**~~ — done in the release below. "Hard to keep
track of time." Nothing on screen was wrong — the clock, the turn chart and the timetable all
said which Day it was — but a Day turns over inside the phases that run themselves, so it passes
between one click and the next, and the two transient signals the page had (the phase banner at
2.6s, the announcement flash at 4.2s) are both gone before a player reading the board notices.
A modal stops and waits, and carries the standings, the Days left and the combined target.
Suppressed on the first frame, on Undo stepping back across a rollover, and on the Day the game
ends — the outcome panel is the thing to read then.
13. **Show me the other players' moves, bots included** — raised by Jesse 2026-08-22 from playing a
multiplayer game. Reasoning in Multiplayer below.
@@ -130,6 +158,29 @@ pass as 19-21 and 24 above, and he asked for them to be discussed together rathe
29. **Put the Fedora at the right-hand end of the phase row**, with (or in) the Supervisor Shift
pill. Reasoning in Display below.
Queued 2026-08-25, from releasing 0.7.1 / 0.4.9g. **Both are blocked on the two commits being made
and pushed** — they were still uncommitted when the session ended.
30. **Close the Gitea issues by hand, each with a comment naming the commit that fixed it.** Raised
by Jesse 2026-08-25. `Closes #<n>` is in the main commit message and will auto-close #2, #8, #9
and #10 when it reaches the default branch, but auto-closing leaves the issue with no record of
WHICH commit or WHICH release answered it — and #9 supersedes #6, which nothing on #6 will ever
say. So each issue wants a comment of its own: the commit SHA on both lines, the version each
shipped in (0.7.1 and 0.4.9g), and for #2 and #9 the ruling that decided it, since neither was
fixed the way the report implies. #6 wants a comment too, pointing at #9. The token and the API
calls are in the workspace's `AGENTS.local.md`.
31. **Bump the StartOS wrapper to 0.7.1.** `station-master-startos` is clean, on `master`, pinned to
`v0.7.0` and versioned `0.7.0:3`. Once v0.7.1 is tagged: move the submodule pin to the tag, set
`startos/versions/current.ts` to **`0.7.1:0`** (a new upstream tag resets the downstream digit —
`UPDATING.md`), and write release notes in all five locales. **No new version FILE and no
migration** — `current.ts`'s `migrations.up` is empty, so nothing is carried from 0.7.0, and a
0.7.0 save replays under 0.7.1 unchanged (its intents cannot contain a Timetabled discard,
because that was illegal when they were recorded). `instructions.md` and `README.md` both name
0.7.0 and both need the three user-visible changes: the Day-end dialog, the Timetabled discard
and its New Game checkbox, and the reasons a blocked platform now gives. Remember the branch
trap: the game pushes to `main`, the wrapper to `master`.
---
## Replay / Save Games
@@ -466,19 +517,27 @@ number until the rules stop moving.
~60 cars) are consumed by both halves of every passenger cycle. Traced over the reported game
the coach pool goes 8+/8− to 0+/1− by Day 5.
**Three ways out, and it is Jesse's call which:** (a) refill when the Division Yard is dry of
the type-and-state being asked for rather than dry of everything — the reading a player
rummaging a table-top pile actually uses, and the biggest balance change; (b) the same trigger
but return only the cars of that type; (c) leave the rules alone and raise the coach count in
`ROLLING_STOCK_SUPPLY`, which the item below already sanctions — lowest risk, but it delays the
wall rather than removing it. Measure (a) or (b) over 400 paired seeds before shipping.
**RULED — the shortage stays, and none of the three is being built.** Jesse: "it is possible
to run out, that's part of the strategy." For the record, the options were (a) refill when the
Division Yard is dry of the type-and-state being asked for rather than dry of everything; (b)
the same trigger but return only the cars of that type; (c) leave the rules alone and raise the
coach count in `ROLLING_STOCK_SUPPLY`. All three are declined. What shipped instead is the
EXPLANATION — the impediments panel now says the Division Yard has no white coach, how many are
stranded in Classification, and that Classification returns only when the Division Yard is
bare. Running dry is a position to play out of, not a broken game, once the screen says so.
- [ ] **A blocked PASSENGER facility produces no impediment at all.** `impediments()`
(`src/sim/narrate.ts`) opens with `if (!f || f.kind !== 'freight') continue`, so the "why
nothing is moving" panel has never had anything to say about a platform. That is the second
half of Gitea#2 and the half that is unambiguously a bug: the player above was not merely
blocked, he was given no reason — the button simply was not there. Worth fixing whichever way
the supply question is settled.
- [x] **A blocked PASSENGER facility produces no impediment at all — FIXED.** `impediments()`
(`src/sim/narrate.ts`) opened with `if (!f || f.kind !== 'freight') continue`, so the "why
nothing is moving" panel had never had anything to say about a platform. That was the second
half of Gitea#2 and the half that was unambiguously a bug: the player above was not merely
blocked, he was given no reason — the button simply was not there. A platform now reports
passengers with no train, a train the card bars Porters from working, full coaches, full red
slots, the same-district rule, and the coach shortage itself — the last naming how many coaches
are stranded in Classification and what brings them back. The reason comes from
`passengerRefusal`, the engine's own predicate, so the panel cannot drift from the rule that
actually refused. Fixing the label found a second defect: a Passenger Facility rides on the
`office` card, so every passenger row would have read `facility 0,0` next to `mineTipple 1,-3`;
it is named by its tier now.
- [ ] **The log lowercases the first letter of every narration it attributes to a player**, so
`EXTRA X18 started…` renders as `Player Solitaire eXTRA X18 started…` (`src/web/game.ts`:1065,