Nine reports from the Day 1-2 playtest of v0.8.0.12. One moved a car, one was a
rule working correctly with nothing on screen to say so, and the rest are things
the table could not see.
The real bug: the Division Yard chips stayed lit and clickable while the board
was catching up. `renderActions` puts the action list away while the queue is
behind — a move offered against a position that has already moved on is a move
made blind — but the make-up wiring sat outside that guard. A chip was clicked
during a bot's make-up, a coach left the yard, and the train ended up with three
cars: a real intent submitted against a board several moves stale. The chips now
follow the queue like every other control, and the yard COUNTS are drawn from the
shown board rather than the live game — they were the one panel still reporting a
future the player had not been shown.
The Office Area picker had a button per opponent and none for yourself, so the
one player who could not reach their own district was the player waiting on
everybody else. Your own seat is in the row now, and the row is ordered by SEAT,
west to east as the Division map draws it, rather than by join order — sorted
from the Frame's own `seat` on every render, so it rotates with Employee Rotation
instead of having to be told.
§5's handover of the Fedora rode on `actorChanged`, which is turn bookkeeping and
which `record()` drops as noise, so the one moment it carried that a player needed
went past in silence. It is its own event now, narrated and announced. The phase
keeps its name: the Supervisor Shift refreshes every Laborer and Porter EVERY
Stage and the Fedora moves only every third.
A collision now names whose Office it was and who paid the 5 Revenue, which rode
in a separate `revenueChanged`; a Mainline collision is phrased differently
because §10 makes it the Superintendent's.
Passengers, reported as a bug and ruled not one after replaying the save: the
Depot's capacity and modifiers were fine, and §6.3 stocking wants a LOADED coach
out of the Division Yard, which held none while six sat in Classification. The
shortage stays — running out is part of the game, the same ruling Gitea#2 got —
but the blocked panel says so now instead of the action being silently absent.
Smaller: "working left" is "working eastward" in the make-up panel and the New
Train tip, because the map runs west to east and the table does not; the history
panel keeps 90 lines instead of 60 in the same 230px box.
`git diff v0.8.0.12..v0.8.0.13 -- src/engine/` is NOT empty this time:
`events.ts` declares `superintendentChanged` and `advance.ts` emits it. Both are
additive — `check()`, `legal.ts` and every predicate are untouched, and events are
derived by replaying a save rather than stored — so no once-legal move became
illegal and games in progress resume.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DmdqqCNoiqE7GBo6wthBnR
From the first two multiplayer playtests of v0.8.0.9, each traced before fixing.
The engine:
- A train on a card BEHIND the one departing no longer triggers a clearance
ruling or an opposite-direction bar (#26). Reproduced from the exported
save: X15 was held over X18 behind it, and X18 then collided into the full
Whistle Post. Games in progress holding a ruling the engine no longer asks
for will not resume (28 of 40 recorded four-seat games); shipped as is at
Jesse's call.
- `mainlineModified` carries the card's previous kind, so the log can say
what a Realignment converted (#27).
The screen:
- The turn chart and the Division map name the player whose move is on
screen while bot turns replay, not the live actor (#25).
- The owning player's name is no longer outlined by the turn arrow's stroke,
which made it unreadable (#24).
- A Mainline card flashes on the map when a Realignment changes it (#28).
- The history is held back with the board and revealed step by step, instead
of arriving whole while the board is still catching up (#29).
- A ruling made by holding the office reads "Superintendent Player X" (#30),
and no line names a player twice (#31).
- A seated player can download their own game as a save file: the play
page's Save replay button, fed by GET /api/save?token=… (#32). The StartOS
action cannot do this — an action result is text only.
Closes#24Closes#25Closes#26Closes#27Closes#28Closes#29Closes#30Closes#31Closes#32
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017nnuCv8UodHucFfx3LWEoX
TODO #13, #15 and #18 — Gitea#20 steps 2-4 pointed at a seated player's own screen.
Every accepted intent, and every automatic phase that does anything, becomes an
ordered presentation step. A bot's whole switching turn used to land in one push;
now it arrives as a run of steps, the district panel follows whoever is acting,
and a [N behind] … [Skip] row says how far the board is from the game.
Solitaire runs the same path — one collector inside submit(), which both session
kinds already funnel through — which is where its automatic phases finally get a
visible beat.
Dwell is assigned by kind: switching holds the screen, turn bookkeeping costs
nothing, and the clock turning over earns the beat. Tunable per viewer without a
rebuild, and off entirely at pace 0.
Also: switching was the one class of action logging unattributed, and now names
its train. Reasoning, measurements and the three things that turned out wrong are
in CHANGELOG.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X6cF1iYvJ1kNmzYBzu4QX6