v0.8.0.10 — playtest fixes: clearance rulings, the log, the map, and a save file
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 #24 Closes #25 Closes #26 Closes #27 Closes #28 Closes #29 Closes #30 Closes #31 Closes #32 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017nnuCv8UodHucFfx3LWEoX
This commit is contained in:
co-authored by
Claude Opus 5
parent
76c6e103b3
commit
4adf149ba5
+104
@@ -19,6 +19,110 @@ page as `v0.1.0 · <sha> · <date>`, so what is deployed can always be identifie
|
||||
|
||||
---
|
||||
|
||||
## 0.8.0.10 — 2026-09-15
|
||||
|
||||
Three reports from the first multiplayer playtest of v0.8.0.9 — one player and three bots — each traced
|
||||
to its cause before it was fixed.
|
||||
|
||||
### The Superintendent is no longer asked about a train BEHIND the one departing (Gitea#26)
|
||||
|
||||
*"Two westbound trains: X15 is further west on Mainline cards than X18. And I still get a Superintendent
|
||||
must rule... held X15 and then collision happened. X18 destroyed, but X15 fine."*
|
||||
|
||||
**Reproduced by replaying the exported save.** At move 78, X15 was highballing west out of seat 3's
|
||||
Office while X18, also westbound, was still crossing the card to its EAST — behind it. Every Office was a
|
||||
Whistle Post, so the Subdivision ran the whole railroad, and `evaluateClearance` counted every train in it
|
||||
without asking which side of the departing train it stood on. The ruling was meaningless; holding X15
|
||||
kept the Whistle Post's only A/D track full, and X18 arrived into it and was destroyed. Unasked, X15 —
|
||||
the lower number, so the first to move — would have left and freed the track.
|
||||
|
||||
§8.1 asks about a train the departing one would FOLLOW and one moving TOWARDS it, and both are ahead of
|
||||
it. So a train on a card strictly behind the departing train's own card is no longer counted, in either
|
||||
pass: a following train behind is no concern, and an oncoming one behind is moving away. A train on the
|
||||
SAME card is still counted, exactly as before — which of two trains sharing a card is in front is
|
||||
`entryConflict`'s region question. The other two rulings in the save (moves 37 and 530) were correct and
|
||||
are unchanged.
|
||||
|
||||
A test had the fault written into it: its "train ahead" of an eastbound train was the first Mainline card
|
||||
in the Division, which is west of the Office. It now stands on a card the train would follow, and three
|
||||
new cases pin the rule: a same-direction train behind is not put to the Superintendent, an opposite-
|
||||
direction train behind does not bar the departure, and a same-direction train ahead still is. The tally
|
||||
test's seed moved from 42 to 44, because the collision seed 42 was chosen for was this bug.
|
||||
|
||||
### Games in progress — MANY WILL NOT RESUME
|
||||
|
||||
**This release changes when the engine asks for a ruling**, so a save holding a ruling it would no longer
|
||||
ask for stops replaying at that move: `mainline.clearance` is refused with `NO_PENDING_DECISION`. The
|
||||
server then refuses to resume that game and logs the move it stopped at, leaving the save untouched —
|
||||
putting v0.8.0.9 back would resume it. **Measured:** 40 four-seat co-op games recorded by bots under
|
||||
v0.8.0.9 and replayed under this release — 28 stop, usually 5–40% of the way in, most at a ruling on a
|
||||
train behind (about ten rulings a game were being asked). The exported playtest game stops at move 78.
|
||||
**Jesse's call (2026-09-15): no games in progress need keeping, so the fix ships as it is,** with no
|
||||
per-game switch preserving the old rule.
|
||||
|
||||
### Six more from the same playtest (Gitea#27–#32)
|
||||
|
||||
**A Realignment says which card it converted (#27).** *"It stated Mainline card 3 converted to plains. It
|
||||
should state that the mainline card 3 curves was converted to plains."* The event carried only what the
|
||||
card became, so the line could not name what it had been; `mainlineModified` now carries `from` as well —
|
||||
events are derived by replaying a save and never stored, so widening one strands nothing — and it reads
|
||||
"Realignment: Mainline card 3, Curves, converted to Plains".
|
||||
|
||||
**And the map flashes it (#28).** *"Is it possible to flash the mainline card when it gets changed by
|
||||
realignment?"* The one play that changes the Division itself was invisible on the map of it.
|
||||
`changedDivisionCards` compares the two public boards the animation queue already holds — the same way a
|
||||
pile is lit — so the pulse lands with the step that shows the change rather than when the intent arrived,
|
||||
and it is shown to the player who made it too, unlike a lit pile. `prefers-reduced-motion` turns it off.
|
||||
|
||||
**The history stops running ahead of the board (#29).** *"Does history display immediately for all bot
|
||||
turns... is it possible to stall history so it stays in sync with the number behind?"* A push carries its
|
||||
narration and its steps together, so every line of a bot's turn was in the panel before the board had
|
||||
drawn any of it. The queue now reports how many lines belong to steps not yet shown, and the panel holds
|
||||
back exactly those, revealing each as its step goes up. Skip still shows everything at once.
|
||||
|
||||
**A ruling reads as the office's (#30).** *"If a player makes a move as a superintendent instead of as
|
||||
themselves maybe it could say 'Superintendent Player Tom'."* The three moves made by holding the office
|
||||
rather than in turn — §8.1's clearance, §11's Yard Office offer, §Q's Red Flag prompt — are prefixed that
|
||||
way. `clearanceGiven` carries no player at all (the office made it, whoever holds it), so the acting seat
|
||||
is what names it.
|
||||
|
||||
**And it names them once (#31).** *"It gives the player's name and then their player number together."*
|
||||
`record()` prefixes the acting player's NAME for every event carrying `player`, and five narration lines
|
||||
embedded `Player <index>` themselves — phase ended, actor changed, the Red Flag ruling, the extension vote
|
||||
and the Yard Office ruling. The name is the log's job; the sentence is the narration's. A test now scans a
|
||||
played game's whole log for a bare player index.
|
||||
|
||||
**A multiplayer game can be saved as a file (#32).** *"In the StartOS actions for the save game, I get a
|
||||
string I can copy. Most of the time, I want to just save it as a JSON file."* Not possible in the action
|
||||
itself: an action result member is text only — copyable, QR or masked, with nested groups — and the SDK
|
||||
has no file member. So it is done where it can be: the play page's "Save replay" button was shown only in
|
||||
solitaire, because a server-backed session has no local save to hand it. `GET /api/save?token=…` — the
|
||||
same seat token `/api/stream` and `/api/intent` use, not the administrative secret — hands a seated player
|
||||
their own game, and the button now appears in multiplayer.
|
||||
|
||||
### "Waiting on" follows the move on screen (Gitea#25)
|
||||
|
||||
*"Playing against 3 bots — waiting on always says me, even when it is someone else's turn."*
|
||||
|
||||
The server plays every bot move the moment a human's turn ends, so the LIVE game is almost always waiting
|
||||
on the human — while the screen is still replaying those bots step by step. The turn chart and the
|
||||
Division map's move marker read the live actor, and contradicted the playback row naming the bot actually
|
||||
moving. `actorOnScreen` (`web/step-queue.ts`) answers with the player of the step on screen while the
|
||||
board is catching up, and the live actor once it has; during playback the chart also leaves off a live
|
||||
"asks … ruling" note that belongs to a position the screen has not reached. Five tests pin it.
|
||||
|
||||
### The name on the Division map is readable again (Gitea#24)
|
||||
|
||||
*"When it shows your player, the font is unreadable... the bold font makes it look fuzzy, and the letters
|
||||
blur together."*
|
||||
|
||||
A name takes the class `bs-turn` while it is that player's move — and `.bs-turn` is also the Division
|
||||
map's turn ARROW, which strokes its shape 2.4px grey with no fill. The name's own rule changed only the
|
||||
fill, so every letter was outlined in grey. It showed for the viewing player almost constantly because of
|
||||
Gitea#25: the map believed it was nearly always their move. `.bs-name` now sets `stroke:none`.
|
||||
|
||||
---
|
||||
|
||||
## 0.8.0.9 — 2026-09-15
|
||||
|
||||
**The developer bot, re-measured decision by decision — and an engine 2.8× faster.** Across the changes
|
||||
|
||||
Reference in New Issue
Block a user