Nine fixes from the Day 1-2 playtest of 0.8.0.12, almost all of them about what the table can see. The one that mattered moved a car: the Division Yard chips stayed clickable while a player's board was catching up on other people's turns, so a click submitted a real intent against a position several moves stale. They obey the catch-up queue now, and the yard counts beside them are read from the board on screen rather than the live game. The district picker gained a button for your own seat and is ordered west to east as the map draws it; the Fedora passing is announced and logged; a collision names whose district it was and who loses the 5 Revenue; and a Depot that cannot stock another passenger says which car it is short of instead of the action silently vanishing. Packaging is the submodule pin, the version and the words. No action, route, file model or interface changed — the whole release is inside the bundled game. GAMES IN PROGRESS RESUME NORMALLY, measured rather than assumed: `git diff v0.8.0.12..v0.8.0.13 -- src/engine/` is two ADDED lines — a superintendentChanged variant on the GameEvent union, and the events.push that emits it beside the actorChanged already there. Nothing was removed or edited: check(), legal.ts and every predicate are untouched, so no once-legal move became illegal, and events are derived by replaying a save rather than stored in one, so widening the union cannot invalidate anything on disk. README, instructions.md and the release notes in all five locales say so. Two files come along that this release did not otherwise touch: `prettier --write startos` reflowed a call in restoreSeat.ts and a return type in serverApi.ts, formatting drift left by the 0.8.0.12 commit. The 0.8.0.12 release it follows was deployed and verified at a table: a seat was recovered end to end from a one-time claim code minted by the StartOS action, which is what the previous commit said had not yet been exercised. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DmdqqCNoiqE7GBo6wthBnR
296 lines
25 KiB
TypeScript
296 lines
25 KiB
TypeScript
import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk'
|
||
|
||
export const current = VersionInfo.of({
|
||
// `<upstream>:<downstream>` — the upstream half tracks the bundled Station Master tag exactly
|
||
// (`versions.md`'s consistency checklist), so bumping the submodule pin and bumping this are one
|
||
// action. The downstream half moves only for packaging-only changes, and RESETS to `:0` when the
|
||
// upstream half moves.
|
||
//
|
||
// FOUR COMPONENTS IS FINE. ExVer's upstream half is an arbitrary-length dotted number, not semver
|
||
// — checked against the SDK's own parser rather than assumed, since every example in `versions.md`
|
||
// has three: `0.7.9.8:0` parses to upstream `[0,7,9,8]`, which sorts above `[0,7,9]`, so a box on
|
||
// 0.7.9:0 sees this as an update rather than refusing it as a downgrade.
|
||
version: '0.8.0.13:0',
|
||
releaseNotes: {
|
||
en_US:
|
||
'Bundles Station Master v0.8.0.13 — nine fixes from a live playtest, almost all of them about ' +
|
||
'what the table can see. **Games already running on this server resume normally**: no rule ' +
|
||
'changed. **The one that moved a car.** While your board is catching up on turns taken by ' +
|
||
'other players the game hides the action list, because a move made against a position that ' +
|
||
'has already moved on is a move made blind — but the cars in the Division Yard stayed ' +
|
||
'clickable. One click during a bot’s turn sent a real move against a board several turns ' +
|
||
'stale, and a coach left the yard. The yard follows the same rule as every other control now, ' +
|
||
'and the car counts beside it show the board you are looking at rather than the one the game ' +
|
||
'has already raced ahead to. **You can look at your own district again.** The row of buttons ' +
|
||
'for looking at another player’s Office Area had one for everybody except you, so the player ' +
|
||
'with nothing to do but wait was the one player who could not look at their own board. Your ' +
|
||
'seat is in the row now, and the buttons are in map order — west to east along the Division — ' +
|
||
'instead of the order people joined. **The Fedora is announced when it passes.** The ' +
|
||
'Superintendent changes hands at the end of Stages 3, 6, 9 and 12, and nothing said so out ' +
|
||
'loud; now it is announced on screen and written into the history, the same as a completed ' +
|
||
'run. **A collision says whose district it was and who paid for it.** The line named the ' +
|
||
'wreck and the reason and stopped there, leaving the 5 Revenue penalty in a separate entry ' +
|
||
'further down the log. **A Depot that cannot take another passenger says why.** It needs a ' +
|
||
'loaded coach waiting in the Division Yard, and when there is none the option simply vanished ' +
|
||
'from the menu with no explanation. The shortage itself stays — running out is part of the ' +
|
||
'game — but the panel now says how much room is left, what is missing, and how many loaded ' +
|
||
'coaches are waiting in the Classification Yard. **Smaller:** the train make-up panel says ' +
|
||
'“working eastward” rather than “working left” — the same rule, but the map runs west to east ' +
|
||
'and the table is not everybody’s left; and the history panel keeps 90 lines instead of 60, ' +
|
||
'in the same amount of screen.',
|
||
es_ES:
|
||
'Incluye Station Master v0.8.0.13 — nueve correcciones surgidas de una partida de prueba, ' +
|
||
'casi todas sobre lo que la mesa alcanza a ver. **Las partidas en curso en este servidor se ' +
|
||
'reanudan con normalidad**: no ha cambiado ninguna regla. **La que movió un vagón.** Mientras ' +
|
||
'tu tablero se pone al día con los turnos de los demás, el juego oculta la lista de acciones, ' +
|
||
'porque decidir sobre una posición que ya ha cambiado es decidir a ciegas; pero los vagones ' +
|
||
'del Patio de División seguían siendo pulsables. Un clic durante el turno de un bot envió una ' +
|
||
'jugada real contra un tablero atrasado varios turnos, y un coche salió del patio. Ahora el ' +
|
||
'patio sigue la misma regla que los demás controles, y los recuentos de vagones muestran el ' +
|
||
'tablero que estás viendo, no aquel al que la partida ya se ha adelantado. **Puedes volver a ' +
|
||
'mirar tu propio distrito.** La fila de botones para ver el Área de Oficinas de otro jugador ' +
|
||
'tenía uno para cada cual menos para ti, así que el jugador que solo podía esperar era el ' +
|
||
'único que no podía mirar su propio tablero. Tu asiento ya está en la fila, y los botones ' +
|
||
'siguen el orden del mapa — de oeste a este a lo largo de la División — en vez del orden de ' +
|
||
'llegada. **El sombrero se anuncia al pasar.** El Superintendente cambia al final de las ' +
|
||
'Etapas 3, 6, 9 y 12, y nada lo decía en voz alta; ahora se anuncia en pantalla y queda ' +
|
||
'escrito en el historial, igual que un recorrido completado. **Una colisión dice en qué ' +
|
||
'distrito fue y quién la paga.** La línea nombraba el accidente y la causa y ahí se detenía, ' +
|
||
'dejando la penalización de 5 de Ingresos en otra entrada más abajo. **Un Depósito que no ' +
|
||
'puede recibir otro pasajero explica por qué.** Necesita un coche cargado esperando en el ' +
|
||
'Patio de División, y cuando no lo hay la opción simplemente desaparecía del menú sin ' +
|
||
'explicación. La escasez se mantiene — quedarse sin material es parte del juego — pero ahora ' +
|
||
'el panel indica cuánto sitio queda, qué falta y cuántos coches cargados esperan en el Patio ' +
|
||
'de Clasificación. **Menores:** el panel de formación de trenes dice «trabajando hacia el ' +
|
||
'este» en lugar de «trabajando hacia la izquierda» — la misma regla, pero el mapa va de oeste ' +
|
||
'a este y la mesa no tiene una izquierda común; y el historial guarda 90 líneas en vez de 60, ' +
|
||
'en el mismo espacio.',
|
||
de_DE:
|
||
'Enthält Station Master v0.8.0.13 — neun Korrekturen aus einer echten Testpartie, fast alle ' +
|
||
'davon darüber, was der Tisch sehen kann. **Laufende Spiele auf diesem Server werden normal ' +
|
||
'fortgesetzt**: keine Regel wurde geändert. **Die eine, die einen Wagen bewegt hat.** Während ' +
|
||
'Ihr Brett die Züge der anderen nachholt, verbirgt das Spiel die Aktionsliste — ein Zug gegen ' +
|
||
'eine Stellung, die längst weiter ist, ist ein Zug im Blindflug —, doch die Wagen im ' +
|
||
'Bezirksbahnhof blieben anklickbar. Ein Klick während des Zuges eines Bots schickte einen ' +
|
||
'echten Zug gegen ein mehrere Züge altes Brett, und ein Wagen verließ den Bahnhof. Der ' +
|
||
'Bahnhof folgt jetzt derselben Regel wie jedes andere Bedienelement, und die Wagenzahlen ' +
|
||
'daneben zeigen das Brett, das Sie sehen, statt jenes, dem das Spiel schon vorausgeeilt ist. ' +
|
||
'**Sie können wieder auf Ihren eigenen Bezirk schauen.** Die Knopfreihe zum Betrachten ' +
|
||
'fremder Bürobereiche hatte einen Knopf für jeden außer für Sie — ausgerechnet der Spieler, ' +
|
||
'der nur warten konnte, kam nicht an sein eigenes Brett. Ihr Platz ist jetzt in der Reihe, ' +
|
||
'und die Knöpfe stehen in Kartenreihenfolge — von West nach Ost entlang der Division — statt ' +
|
||
'in der Beitrittsreihenfolge. **Der Hut wird angesagt, wenn er weitergegeben wird.** Der ' +
|
||
'Superintendent wechselt am Ende der Etappen 3, 6, 9 und 12, und nichts sagte es laut; jetzt ' +
|
||
'wird es auf dem Bildschirm angesagt und in den Verlauf geschrieben, wie eine abgeschlossene ' +
|
||
'Fahrt. **Eine Kollision nennt den Bezirk und den, der dafür zahlt.** Die Zeile nannte das ' +
|
||
'Wrack und den Grund und hörte dort auf; die 5 Einnahmen Strafe stand in einem eigenen ' +
|
||
'Eintrag weiter unten. **Ein Depot, das keinen weiteren Fahrgast aufnehmen kann, sagt ' +
|
||
'warum.** Es braucht einen beladenen Personenwagen im Bezirksbahnhof, und fehlte er, ' +
|
||
'verschwand die Option kommentarlos aus dem Menü. Der Mangel bleibt — auszugehen gehört zum ' +
|
||
'Spiel —, aber die Anzeige nennt jetzt den freien Platz, das Fehlende und die Zahl der ' +
|
||
'beladenen Wagen, die im Rangierbahnhof warten. **Kleineres:** die Zugbildungsanzeige sagt ' +
|
||
'„ostwärts arbeitend“ statt „nach links arbeitend“ — dieselbe Regel, aber die Karte läuft von ' +
|
||
'West nach Ost, und der Tisch hat kein gemeinsames Links; und der Verlauf behält 90 Zeilen ' +
|
||
'statt 60, auf gleichem Raum.',
|
||
pl_PL:
|
||
'Zawiera Station Master v0.8.0.13 — dziewięć poprawek z prawdziwej partii testowej, niemal ' +
|
||
'wszystkie o tym, co widzi stół. **Gry w toku na tym serwerze wznawiają się normalnie**: ' +
|
||
'żadna zasada się nie zmieniła. **Ta, która przestawiła wagon.** Kiedy twoja plansza nadrabia ' +
|
||
'ruchy pozostałych graczy, gra chowa listę akcji, bo ruch wykonany wobec pozycji, która już ' +
|
||
'się zmieniła, to ruch na ślepo — ale wagony na Stacji Rejonowej wciąż dawały się kliknąć. ' +
|
||
'Jedno kliknięcie w czasie tury bota wysłało prawdziwy ruch wobec planszy sprzed kilku tur i ' +
|
||
'wagon opuścił stację. Teraz stacja podlega tej samej regule co każdy inny element, a ' +
|
||
'liczniki wagonów obok pokazują planszę, którą widzisz, a nie tę, do której gra już pobiegła ' +
|
||
'naprzód. **Znów możesz zajrzeć do własnego okręgu.** W rzędzie przycisków do podglądania ' +
|
||
'Biura innego gracza był przycisk dla każdego prócz ciebie, więc gracz, który tylko czekał, ' +
|
||
'jako jedyny nie mógł spojrzeć na własną planszę. Twoje miejsce jest już w rzędzie, a ' +
|
||
'przyciski są w kolejności mapy — z zachodu na wschód wzdłuż Dywizji — zamiast w kolejności ' +
|
||
'dołączania. **Przekazanie kapelusza jest ogłaszane.** Superintendent zmienia się na koniec ' +
|
||
'Etapów 3, 6, 9 i 12, a nic nie mówiło tego na głos; teraz jest ogłaszane na ekranie i ' +
|
||
'zapisywane w historii, tak jak ukończony przejazd. **Kolizja mówi, czyj to okręg i kto za ' +
|
||
'nią płaci.** Wiersz podawał wrak i przyczynę, i na tym kończył — kara 5 Przychodu trafiała ' +
|
||
'do osobnego wpisu niżej. **Dworzec, który nie może przyjąć kolejnego pasażera, mówi ' +
|
||
'dlaczego.** Potrzebny jest załadowany wagon osobowy czekający na Stacji Rejonowej, a gdy go ' +
|
||
'nie było, opcja po prostu znikała z menu bez wyjaśnienia. Sam niedobór zostaje — kończące ' +
|
||
'się zasoby to część gry — ale panel podaje teraz, ile zostało miejsca, czego brakuje i ile ' +
|
||
'załadowanych wagonów czeka na Stacji Rozrządowej. **Drobniejsze:** panel formowania składu ' +
|
||
'mówi „pracując na wschód” zamiast „pracując w lewo” — ta sama zasada, ale mapa biegnie z ' +
|
||
'zachodu na wschód, a stół nie ma wspólnej lewej strony; historia zaś zachowuje 90 wierszy ' +
|
||
'zamiast 60, na tym samym miejscu.',
|
||
fr_FR:
|
||
'Inclut Station Master v0.8.0.13 — neuf corrections issues d’une vraie partie de test, ' +
|
||
'presque toutes sur ce que la table peut voir. **Les parties en cours sur ce serveur ' +
|
||
'reprennent normalement** : aucune règle n’a changé. **Celle qui a déplacé un wagon.** ' +
|
||
'Pendant que votre plateau rattrape les tours des autres, le jeu masque la liste des actions, ' +
|
||
'car jouer contre une position qui a déjà avancé, c’est jouer à l’aveugle — mais les wagons ' +
|
||
'de la Gare de Division restaient cliquables. Un clic pendant le tour d’un bot a envoyé un ' +
|
||
'vrai coup contre un plateau vieux de plusieurs tours, et une voiture a quitté la gare. La ' +
|
||
'gare suit désormais la même règle que les autres commandes, et les comptes de wagons à côté ' +
|
||
'affichent le plateau que vous regardez, et non celui où la partie a déjà filé. **Vous pouvez ' +
|
||
'de nouveau regarder votre propre district.** La rangée de boutons permettant de consulter ' +
|
||
'l’Espace Bureaux d’un autre joueur en avait un pour tout le monde sauf vous : le joueur qui ' +
|
||
'n’avait qu’à attendre était le seul à ne pas pouvoir regarder son propre plateau. Votre ' +
|
||
'place y figure désormais, et les boutons suivent l’ordre de la carte — d’ouest en est le ' +
|
||
'long de la Division — plutôt que l’ordre d’arrivée. **Le chapeau est annoncé quand il ' +
|
||
'passe.** Le Superintendant change à la fin des Étapes 3, 6, 9 et 12, et rien ne le disait à ' +
|
||
'voix haute ; c’est maintenant annoncé à l’écran et inscrit dans l’historique, comme un ' +
|
||
'parcours achevé. **Une collision indique le district et celui qui paie.** La ligne nommait ' +
|
||
'l’accident et la cause puis s’arrêtait, laissant la pénalité de 5 Revenus dans une entrée ' +
|
||
'séparée plus bas. **Un Dépôt qui ne peut pas prendre un passager de plus dit pourquoi.** Il ' +
|
||
'lui faut une voiture chargée en attente à la Gare de Division, et faute de quoi l’option ' +
|
||
'disparaissait du menu sans explication. La pénurie demeure — manquer de matériel fait partie ' +
|
||
'du jeu — mais le panneau indique désormais la place restante, ce qui manque, et combien de ' +
|
||
'voitures chargées attendent à la Gare de Triage. **Plus petit :** le panneau de formation ' +
|
||
'des trains dit « en travaillant vers l’est » plutôt que « en travaillant vers la gauche » — ' +
|
||
'même règle, mais la carte va d’ouest en est et la table n’a pas de gauche commune ; et ' +
|
||
'l’historique conserve 90 lignes au lieu de 60, dans la même place.',
|
||
},
|
||
migrations: {
|
||
/**
|
||
* NOTHING TO CARRY, AND CHECKED THE SAME NARROW WAY v0.7.9.8's ENTRY WAS.
|
||
*
|
||
* The rule this package lives by is in the game's README: a save is a seed plus the moves
|
||
* played, replayed through the CURRENT rules, so the only thing that strands an older save is a
|
||
* change that makes a once-legal move illegal. So the question is never "how big was the
|
||
* release" — v0.8.0 is a large one — but "did any predicate change its answer".
|
||
*
|
||
* Measured with `git diff v0.7.9.8..v0.8.0.1 -- src/engine/`. The WHOLE engine diff is eight
|
||
* lines:
|
||
* four `GameEvent` types (`trayMoved`, `carsCoupled`, `carsDropped`, `consistSorted`) gained a
|
||
* `player` field, and the four places that build them pass it. `check()` is untouched, `legal.ts`
|
||
* and `advance.ts` are untouched, and no predicate anywhere was edited. Games in progress resume,
|
||
* and the release notes say so in all five locales rather than leaving it to be discovered.
|
||
*
|
||
* EVENTS ARE NOT PERSISTED, so widening four of them cannot invalidate anything on disk: a
|
||
* `SavedGame` is `{ seed, config, history: Intent[], … }` and the events are derived by replaying
|
||
* it. The narration TEXT of two lines changed with them ("Moved Train 3 …" where it used to read
|
||
* "CREW moved …"), which a resumed game simply regenerates — the log is not stored either.
|
||
*
|
||
* WHAT IS NOT COVERED BY THAT ARGUMENT, and why it still does not need a migration: the wire
|
||
* between this server and a browser gained a lot. `Push` now carries ordered presentation steps
|
||
* and a public-board baseline, and the board deltas changed shape. None of it is on disk, and a
|
||
* browser reloads onto the new page as part of the update, so there is no version skew to
|
||
* migrate — the same reasoning v0.7.9.8 used for its own `Frame` changes.
|
||
*
|
||
* v0.8.0.1 ADDED NOTHING TO THIS ARGUMENT: `git diff v0.8.0..v0.8.0.1 -- src/engine/` is empty.
|
||
* It changed `sim/pacing.ts`, `web/step-queue.ts` and `web/main.ts` — how long a step is shown
|
||
* and when the queue calls itself idle — which is presentation and touches neither the rules nor
|
||
* anything on disk.
|
||
*
|
||
* v0.8.0.2 DOES TOUCH THE ENGINE, and it is worth being exact about why that is still nothing to
|
||
* migrate. `git diff v0.8.0.1..v0.8.0.2 -- src/engine/` is three added lines: `collisionsPrevDay`
|
||
* declared on `GameState`, initialised to 0 in `setup.ts`, and assigned at the Day rollover in
|
||
* `advance.ts`. It is a counter that nothing checks — no predicate reads it, so no once-legal move
|
||
* became illegal.
|
||
*
|
||
* v0.8.0.3 THROUGH v0.8.0.7 ADDED NOTHING: `git diff v0.8.0.2..v0.8.0.7 -- src/engine/` is empty.
|
||
* One moved the Skip button, changed what the waiting row says, and stopped the speed control
|
||
* stretching the clock; one took a hostname out of comments; the last drew the Home Office deck
|
||
* and lit the pile a watched move touched, which is a diff of two frames the client already
|
||
* holds. None of it is a rule, and none of it is on disk.
|
||
*
|
||
* v0.8.0.8 IS DIFFERENT AND IS THE ONE TO READ CAREFULLY: it changes a RULE (Gitea#23). When the
|
||
* Home Office deck is reshuffled, a timetabled train sitting in the SALVAGE YARD is no longer
|
||
* recovered — it was played, its number is on the timetable, and it cannot be run twice. The same
|
||
* card in a DEPARTMENT was discarded rather than played and still comes back, as does any Extra.
|
||
* A duplicate went with it: `trainScheduled` had been pushing a synthetic `train-<n>` beside the
|
||
* real card, so four scheduled trains left eight entries in a pile of four.
|
||
*
|
||
* GAMES IN PROGRESS STILL RESUME, and the reason is the narrow one this package always asks
|
||
* (README § Design notes): a save is a seed plus the moves played, replayed through the CURRENT
|
||
* rules, so what strands one is a change that makes a once-legal move ILLEGAL. Nothing here does.
|
||
* `check()` is untouched; a draw is a draw whatever lies on top of the deck. What differs is the
|
||
* Salvage Yard's depth, which was double-counting, and which cards a reshuffle returns — and a
|
||
* reshuffle is effectively unreachable in ordinary play: eight games driven to 4000 moves across
|
||
* eight seeds produced ZERO. A game that had somehow reshuffled would replay to a different deck
|
||
* order rather than refusing to replay, which is worth knowing and is not the same as breaking.
|
||
*
|
||
* v0.8.0.9 TOUCHES THE ENGINE FOR SPEED, AND PROVED IT CHANGED NOTHING. `git diff v0.8.0.8..v0.8.0.9
|
||
* -- src/engine/` adds a route cache scoped to one unchanged position (`withRouteCache`), splits
|
||
* `applyIntent` into `prepareIntent` + `commitEvents`, trims allocation in `exploreMoves`, adds
|
||
* `legalSwitchingActions`, and exports `badlyMadeUp`, `protoCard` and `extendLimitsIfNeeded` for the
|
||
* bot. No predicate's answer changed: every event and intent of 32 seeded games hashed identical before
|
||
* and after each step, and the game's `test/route-cache.test.ts` pins the split. Everything else is the
|
||
* developer bot, whose past moves are already intents in a save. Games in progress resume.
|
||
*
|
||
* v0.8.0.10 IS THE FIRST BUMP THAT BREAKS RESUMES, AND IT DOES SO DELIBERATELY. It corrects WHEN §8.1
|
||
* asks the Superintendent to rule (Gitea#26): a train on a card BEHIND the one departing is nobody's
|
||
* concern, and was being counted. A save is the seed and the moves replayed through the CURRENT rules,
|
||
* so a game holding a `mainline.clearance` the rules no longer ask for is refused at that move with
|
||
* NO_PENDING_DECISION — `tryResumeSession` reports which move, and `index.ts` logs the refusal and
|
||
* leaves the file alone. Measured before shipping: 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. Jesse's call
|
||
* (2026-09-15): no games in progress need keeping, so this ships without a per-game switch for the old
|
||
* rule, and the release notes say so in all five locales. A game worth finishing can be finished by
|
||
* putting v0.8.0.9 back — the save file is untouched.
|
||
*
|
||
* The rest of the release is the screen and the log — who the board says it is waiting on, what the
|
||
* history says and when it says it, a flash on a realigned Mainline card — plus one new read-only
|
||
* route (`GET /api/save?token=…`) that hands a seated player their own save. None of it is on disk.
|
||
*
|
||
* A NEW STATE FIELD CANNOT STRAND A SAVE HERE, which is the property worth naming rather than
|
||
* re-deriving: a `SavedGame` holds `{ seed, config, history }` and NOT a serialised `GameState`.
|
||
* Resuming calls `createGame` — which fills the new field from `setup.ts` — and then replays the
|
||
* intents through the current rules, so the field is populated on the way past. There is no old
|
||
* shape on disk for a new field to be missing from.
|
||
*
|
||
* THE ONE THING THAT WOULD HAVE NEEDED CARE, had it been built the way the plan first described:
|
||
* the display-step collector runs inside `submit()`, and the resume path (`fromMultiplayerSave`)
|
||
* deliberately does not go through `submit()`. So replaying a saved game emits no steps and burns
|
||
* no sequence numbers. A test in the game pins that, because it is a property rather than an
|
||
* accident.
|
||
*
|
||
* v0.8.0.11 RESUMES, AND IT WAS MEASURED THE SAME NARROW WAY — which matters more than usual
|
||
* here, because the release immediately before it is the one that did NOT.
|
||
* `git diff v0.8.0.10..v0.8.0.11 -- src/engine/` is three files and nineteen insertions:
|
||
* `trainArrived` gains an `owner` field (`events.ts`), the one line in `advance.ts` that fills
|
||
* it from `playerAtSeat`, and a Mainline card's printed description losing a sentence about a
|
||
* speed that is not drawn on the card (`content.ts`). `check()` and `legal.ts` are untouched and
|
||
* no predicate was edited, so nothing once legal became illegal. Events are not persisted — a
|
||
* `SavedGame` is `{ seed, config, history }` and the events are derived by replaying it — so
|
||
* widening one of them cannot invalidate anything on disk, exactly as the v0.8.0.1 entry above
|
||
* argues for four of them.
|
||
*
|
||
* THE REST OF THE RELEASE IS THE SCREEN: a Pause control for the catch-up queue, a one-render
|
||
* look at another player's Office Area, the turn chart following the step being replayed rather
|
||
* than the live game, "still needs" on the make-up panel, the amber on an addable yard chip, and
|
||
* save filenames carrying the join code. None of it is a rule and none of it is on disk.
|
||
*
|
||
* v0.8.0.12 TOUCHES THE ENGINE NOT AT ALL, which is the shortest entry this comment has ever
|
||
* had a right to: `git diff v0.8.0.11..v0.8.0.12 -- src/engine/` is EMPTY. The release is the
|
||
* server's HTTP surface, the browser client and the docs — a seat recovery flow (Gitea#33) for
|
||
* a player whose browser has lost the token that is their only identity.
|
||
*
|
||
* WHAT IT ADDS, AND WHY NONE OF IT IS A MIGRATION: two routes (`POST /api/games/<id>/claim`
|
||
* behind the admin secret, `POST /api/claim` for the player following the link), a `?claim=`
|
||
* entry path in the client, and `seatedPlayers` on the administrative game listing. The codes
|
||
* themselves live in memory and are deliberately NOT persisted — minted on demand and spent
|
||
* within minutes, so a restart dropping them is the right failure rather than a loss. Nothing
|
||
* new is written to the volume, no predicate was edited, and `check()` and `legal.ts` are
|
||
* untouched, so no once-legal move became illegal. Games in progress resume, and the release
|
||
* notes say so in all five locales.
|
||
*
|
||
* v0.8.0.13 TOUCHES THE ENGINE AGAIN, AND THE WHOLE DIFF IS TWO LINES.
|
||
* `git diff v0.8.0.12..v0.8.0.13 -- src/engine/` adds a `superintendentChanged` variant to the
|
||
* `GameEvent` union (`events.ts`) and the one `events.push` in `advance.ts` that emits it beside
|
||
* the `actorChanged` that was already there — §5's handover of the Fedora, which the log had been
|
||
* dropping as turn bookkeeping. Nothing was removed and nothing was edited: `check()`, `legal.ts`
|
||
* and every predicate are untouched, so no once-legal move became illegal, and a widened event
|
||
* cannot invalidate anything on disk because events are DERIVED by replaying a `SavedGame` rather
|
||
* than stored in one — the same argument the v0.8.0.1 and v0.8.0.11 entries above make for
|
||
* theirs. Games in progress resume, and the release notes say so in all five locales.
|
||
*
|
||
* THE REST IS THE SCREEN AND THE LOG, none of it on disk: the Division Yard chips now obey the
|
||
* catch-up queue (they did not, and a click during it submitted a real intent against a stale
|
||
* board), the yard counts are read from the shown board rather than the live game, the district
|
||
* picker gained your own seat and is ordered by seat rather than by player index, collisions name
|
||
* the district's owner and the 5 Revenue they lose, a Depot that cannot stock an outbound
|
||
* passenger explains which car it is short of, and the history panel keeps 90 lines. The
|
||
* passenger case is a RULING rather than a fix — §6.3 wants a loaded coach in the Division Yard,
|
||
* and Jesse kept the shortage (Gitea#2's ruling) while ending the silence about it.
|
||
*/
|
||
up: async ({ effects }) => {},
|
||
down: IMPOSSIBLE,
|
||
},
|
||
})
|