A table pass over 0.8.0.17. The second-digit bump is deliberate: 0.8.1 had been reserved for the seatless display table, which is getting more thought, and this batch earned the number on its own. GAMES IN PROGRESS RESUME, AND IT WAS MEASURED BEFORE RELEASE rather than argued from the diff. The bundled release changes what sits in the yards, so the risk was real. All twelve saves on the test box were pulled and replayed through `tryResumeSession` — the server's own boot check — against the new build: six resume, six refuse, and the six refusals are the SAME six, at the same moves, with the same codes, that 0.8.0.17 already logged. Nothing new was stranded. That replay is the check worth repeating on any release that touches state, because it answers before the install rather than after. THE GAME'S OWN FIX, for the README's benefit: the Freight Agent's "clear the red Inbound box" returned the car to the Classification Yard still marked loaded, carrying a load already delivered and already paid for. `pooled()` strips a load's `origin` stamp and keeps `loaded` on purpose — a train can retire at a Division Point with freight aboard — so the call site's comment, "a car back in a yard is back in the common supply, carrying nothing", described something it never did. Coaches suffered worst: detraining takes `coach && !loaded` out of the Division Yard, so a cleared coach came back as stock that could never unload a passenger. 18 loaded coaches against 6 empty over five measured games. THIS PACKAGE'S OWN CHANGE IS THE MANAGE GAME DROPDOWN. It listed each game's code, seat count and position and nothing about when the game was last touched, so four games on a server looked alike — reported 2026-09-22: "I've got four games out there, but I have no idea which one's which or how old they are." `lastMoveAt` was already on the wire from the server's `summary()` and simply unused. Each option now carries both an age and a timestamp, because they answer different questions: "5h ago" answers the one that was asked, and the date beside it is what you quote when deciding to end a game. A lobby has had no move, so it reports when it was created and says so. `when()` moved out of `gamesInProgress.ts` into `utils.ts` alongside a new `ago()`, shared by both actions so an administrator sees one date format wherever a game is named — the second copy would have been the one that drifted. No route, file model or interface changed. README and instructions.md carry the release, and the notes in all five locales say games in progress are unaffected. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MUizFYCMHRWhbWwXhp7WPR
319 lines
27 KiB
TypeScript
319 lines
27 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.1.0:0',
|
|
releaseNotes: {
|
|
en_US:
|
|
'Bundles Station Master v0.8.1.0 — a table pass over v0.8.0.17. **Games already running on this ' +
|
|
'server resume normally**, and that was measured rather than assumed: every save on the test ' +
|
|
'server was replayed against this build before release, and the only games that refuse are the ' +
|
|
'same ones that already refused. **Passenger coaches stopped piling up unusable.** When the ' +
|
|
'Freight Agent cleared a red Inbound box, the car went back to the Classification Yard still ' +
|
|
'marked as carrying its load — a load already delivered and already paid for. A coach that came ' +
|
|
'back that way could never unload passengers again, so they gathered in the yards as dead stock; ' +
|
|
'over five measured games there were 18 such coaches against 6 usable ones. The car comes back ' +
|
|
'**empty** now, which is what the rules always meant. **And the option says what it does**: it ' +
|
|
'read "send the loaded coach in the red Inbound box to the Classification Yard", which is true of ' +
|
|
'the counters and nonsense as a sentence. It now says the passengers leave the station and the ' +
|
|
'coach goes back to the yard empty. **The lobby is not a dead end.** Leaving a game in progress ' +
|
|
'returned you to a lobby showing only the games you were already in, with no way to join a ' +
|
|
'different one or start a new one — both doors were on the page the whole time, hidden. **The ' +
|
|
'lobby\'s buttons look like buttons**, carrying the same amber border that has meant "you can do ' +
|
|
'this now" everywhere else in the game. **Taking the last card from a Department refills it** — ' +
|
|
'that is the rule and always has been, but it was written down nowhere, so it surprised a player ' +
|
|
'at the table; it is in the Rules and the Home deck reference now. **Managing a game tells you ' +
|
|
'how old it is**: the dropdown listed the code and the position and nothing about when the game ' +
|
|
'was last touched, so four games looked alike. **Smaller:** in the history an Enhancement now ' +
|
|
'names the Mainline card it went on — the slot and the card type both, since a Division can be ' +
|
|
'dealt two of the same card — and calls the card by its printed name.',
|
|
es_ES:
|
|
'Incluye Station Master v0.8.1.0 — una revisión tras una partida de prueba de v0.8.0.17. **Las ' +
|
|
'partidas ya en curso en este servidor se reanudan con normalidad**, y eso se midió en vez de ' +
|
|
'suponerse: todas las partidas guardadas del servidor de pruebas se reprodujeron contra esta ' +
|
|
'versión antes de publicarla, y las únicas que fallan son las que ya fallaban. **Los coches de ' +
|
|
'viajeros dejaron de acumularse inservibles.** Cuando el Agente de Carga vaciaba una caja roja de ' +
|
|
'entrada, el vagón volvía al Patio de Clasificación marcado aún como cargado — con una carga ya ' +
|
|
'entregada y ya pagada. Un coche que volvía así nunca podía volver a descargar viajeros, así que ' +
|
|
'se acumulaban como material muerto: en cinco partidas medidas, 18 de ellos frente a 6 ' +
|
|
'utilizables. Ahora el vagón vuelve **vacío**, que es lo que las reglas siempre quisieron decir. ' +
|
|
'**Y la opción dice lo que hace**: antes decía "enviar el coche cargado de la caja roja al Patio ' +
|
|
'de Clasificación", cierto para las fichas y absurdo como frase. Ahora dice que los viajeros ' +
|
|
'salen de la estación y el coche vuelve vacío al patio. **El vestíbulo ya no es un callejón sin ' +
|
|
'salida.** Salir de una partida en curso te devolvía a un vestíbulo que solo mostraba las ' +
|
|
'partidas en las que ya estabas, sin forma de unirte a otra ni crear una nueva; ambas puertas ' +
|
|
'estaban allí todo el tiempo, ocultas. **Los botones del vestíbulo parecen botones**, con el ' +
|
|
'mismo borde ámbar que significa "puedes hacer esto ahora" en el resto del juego. **Tomar la ' +
|
|
'última carta de un Departamento lo rellena** — es la regla y siempre lo fue, pero no estaba ' +
|
|
'escrita en ninguna parte y sorprendió a un jugador; ya está en las Reglas y en la referencia del ' +
|
|
'mazo. **Gestionar una partida dice cuánto hace que se jugó**: la lista mostraba el código y la ' +
|
|
'posición pero nada sobre la última jugada, así que cuatro partidas parecían iguales. **Menor:** ' +
|
|
'en el historial, una Mejora nombra la carta de Línea Principal sobre la que se jugó — la ' +
|
|
'posición y el tipo, porque pueden repartirse dos iguales — y la llama por su nombre impreso.',
|
|
de_DE:
|
|
'Enthält Station Master v0.8.1.0 — ein Durchgang nach einem Testspiel von v0.8.0.17. **Bereits ' +
|
|
'laufende Partien auf diesem Server werden normal fortgesetzt**, und das wurde gemessen statt ' +
|
|
'angenommen: jeder Spielstand des Testservers wurde vor der Freigabe gegen diesen Build ' +
|
|
'abgespielt, und nur die Partien verweigern, die schon vorher verweigerten. **Personenwagen ' +
|
|
'häufen sich nicht mehr unbrauchbar an.** Wenn der Frachtagent eine rote Eingangsbox leerte, ' +
|
|
'kehrte der Wagen in den Rangierbahnhof zurück, immer noch als beladen markiert — mit einer ' +
|
|
'Ladung, die längst geliefert und längst bezahlt war. Ein so zurückgekehrter Wagen konnte nie ' +
|
|
'wieder Fahrgäste ausladen, also sammelten sie sich als totes Material: in fünf gemessenen ' +
|
|
'Partien 18 davon gegen 6 brauchbare. Jetzt kommt der Wagen **leer** zurück, wie es die Regeln ' +
|
|
'immer meinten. **Und die Option sagt, was sie tut**: sie lautete "den beladenen Wagen aus der ' +
|
|
'roten Box in den Rangierbahnhof schicken" — für die Marker zutreffend und als Satz unsinnig. ' +
|
|
'Jetzt heißt es, die Fahrgäste verlassen den Bahnhof und der Wagen kehrt leer zurück. **Die Lobby ' +
|
|
'ist keine Sackgasse mehr.** Wer eine laufende Partie verließ, landete in einer Lobby, die nur ' +
|
|
'die eigenen Partien zeigte, ohne Weg zu einer anderen oder zu einer neuen — beide Türen waren ' +
|
|
'die ganze Zeit da, nur verborgen. **Die Knöpfe der Lobby sehen aus wie Knöpfe**, mit demselben ' +
|
|
'bernsteinfarbenen Rand, der im übrigen Spiel "das kannst du jetzt tun" bedeutet. **Die letzte ' +
|
|
'Karte aus einer Abteilung zu nehmen füllt sie wieder auf** — das ist die Regel und war es immer, ' +
|
|
'stand aber nirgends geschrieben und überraschte einen Spieler; jetzt steht sie in den Regeln und ' +
|
|
'in der Deck-Referenz. **Die Partieverwaltung sagt, wie alt eine Partie ist**: die Liste nannte ' +
|
|
'Code und Position, aber nichts über den letzten Zug, sodass vier Partien gleich aussahen. ' +
|
|
'**Kleineres:** im Verlauf nennt eine Verbesserung die Streckenkarte, auf die sie kam — Platz und ' +
|
|
'Kartentyp, denn es können zwei gleiche ausliegen — und beim gedruckten Namen.',
|
|
pl_PL:
|
|
'Zawiera Station Master v0.8.1.0 — przegląd po rozgrywce testowej v0.8.0.17. **Partie już ' +
|
|
'trwające na tym serwerze wznawiają się normalnie**, i zostało to zmierzone, a nie założone: ' +
|
|
'każdy zapis z serwera testowego odtworzono na tej wersji przed wydaniem, a odmawiają tylko te ' +
|
|
'partie, które odmawiały już wcześniej. **Wagony pasażerskie przestały gromadzić się ' +
|
|
'bezużytecznie.** Gdy Agent Towarowy opróżniał czerwoną skrzynkę przyjęć, wagon wracał na stację ' +
|
|
'rozrządową wciąż oznaczony jako załadowany — ładunkiem już dostarczonym i już opłaconym. Tak ' +
|
|
'powracający wagon nigdy więcej nie mógł wyładować pasażerów, więc gromadziły się jako martwy ' +
|
|
'tabor: w pięciu zmierzonych partiach 18 takich wobec 6 użytecznych. Teraz wagon wraca **pusty**, ' +
|
|
'tak jak zasady zawsze zakładały. **A opcja mówi, co robi**: brzmiała "wyślij załadowany wagon z ' +
|
|
'czerwonej skrzynki na stację rozrządową" — prawdziwe dla znaczników i bez sensu jako zdanie. ' +
|
|
'Teraz mówi, że pasażerowie opuszczają stację, a wagon wraca pusty. **Poczekalnia nie jest już ' +
|
|
'ślepym zaułkiem.** Wyjście z trwającej partii przenosiło do poczekalni pokazującej tylko twoje ' +
|
|
'partie, bez możliwości dołączenia do innej ani stworzenia nowej — obie bramy były tam cały czas, ' +
|
|
'ukryte. **Przyciski poczekalni wyglądają jak przyciski**, z tą samą bursztynową obwódką, która w ' +
|
|
'grze oznacza "to możesz teraz zrobić". **Wzięcie ostatniej karty z Departamentu uzupełnia go** — ' +
|
|
'to zasada i zawsze nią była, ale nigdzie jej nie zapisano i zaskoczyła gracza; teraz jest w ' +
|
|
'Zasadach i w referencji talii. **Zarządzanie partią mówi, ile ma lat**: lista podawała kod i ' +
|
|
'pozycję, lecz nic o ostatnim ruchu, więc cztery partie wyglądały tak samo. **Drobne:** w ' +
|
|
'historii Ulepszenie nazywa kartę Magistrali, na którą trafiło — miejsce i typ, bo mogą trafić ' +
|
|
'się dwie takie same — i po nazwie z karty.',
|
|
fr_FR:
|
|
'Contient Station Master v0.8.1.0 — une passe après une partie de test de v0.8.0.17. **Les ' +
|
|
'parties déjà en cours sur ce serveur reprennent normalement**, et cela a été mesuré plutôt que ' +
|
|
'supposé : chaque sauvegarde du serveur de test a été rejouée contre cette version avant ' +
|
|
'publication, et seules refusent les parties qui refusaient déjà. **Les voitures de voyageurs ne ' +
|
|
's\'accumulent plus, inutilisables.** Quand l\'Agent de Fret vidait une case rouge d\'arrivée, le ' +
|
|
'wagon repartait vers la gare de triage encore marqué comme chargé — d\'un chargement déjà livré ' +
|
|
'et déjà payé. Une voiture revenue ainsi ne pouvait plus jamais débarquer de voyageurs, elles ' +
|
|
's\'entassaient donc en matériel mort : sur cinq parties mesurées, 18 contre 6 utilisables. Le ' +
|
|
'wagon revient **vide** désormais, ce que les règles ont toujours voulu dire. **Et l\'option dit ' +
|
|
'ce qu\'elle fait** : elle indiquait "envoyer la voiture chargée de la case rouge vers la gare de ' +
|
|
'triage", vrai pour les jetons et absurde comme phrase. Elle dit maintenant que les voyageurs ' +
|
|
'quittent la gare et que la voiture repart à vide. **Le salon n\'est plus une impasse.** Quitter ' +
|
|
'une partie en cours ramenait à un salon n\'affichant que vos propres parties, sans moyen d\'en ' +
|
|
'rejoindre une autre ni d\'en créer une — les deux portes étaient là depuis le début, masquées. ' +
|
|
'**Les boutons du salon ressemblent à des boutons**, avec la même bordure ambre qui signifie « ' +
|
|
'vous pouvez faire ceci » partout ailleurs. **Prendre la dernière carte d\'un Département le ' +
|
|
'réapprovisionne** — c\'est la règle et l\'a toujours été, mais elle n\'était écrite nulle part et a ' +
|
|
'surpris un joueur ; elle figure désormais dans les Règles et la référence du deck. **La gestion ' +
|
|
'd\'une partie dit son âge** : la liste donnait le code et la position, rien sur le dernier coup, ' +
|
|
'si bien que quatre parties se ressemblaient. **Mineur :** dans l\'historique, une Amélioration ' +
|
|
'nomme la carte de Grande Ligne où elle a été posée — l\'emplacement et le type, car deux ' +
|
|
'identiques peuvent sortir — et par son nom imprimé.',
|
|
},
|
|
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.
|
|
*
|
|
* v0.8.0.14 IS THE SECOND BUMP THAT BREAKS RESUMES, AND LIKE v0.8.0.10 IT DOES SO DELIBERATELY.
|
|
* A Modifier card may no longer be placed outside a player's Limits (§2.1). That REVERSES an
|
|
* earlier ruling of Jesse's — Modifiers were exempt because a Facility standing at the limit has
|
|
* three of its nine spots beyond the sign — and it is exactly the shape of change this package's
|
|
* `UPDATING.md` says to look for: a predicate in `apply.ts` changed its answer, so a move that
|
|
* was legal when it was played is refused on replay.
|
|
*
|
|
* MEASURED, NOT ESTIMATED. The Day 3 playtest save stops at intent 528 of 539 —
|
|
* `card.play c55 → (-2,4)` with the sign at column 3 — eleven moves short of where the table had
|
|
* got to. `tryResumeSession` names the move, `index.ts` logs the refusal, and the file is left
|
|
* untouched, so re-installing v0.8.0.13 finishes any game worth finishing. Jesse's call, knowing
|
|
* it strands the game that was on the box.
|
|
*
|
|
* THE REST OF THE ENGINE DIFF STRANDS NOTHING, and is worth separating from the part that does.
|
|
* `makeUpShort` is a new event reporting that the make-up round could give a train nothing;
|
|
* `switchingEnded` closes a switching turn; `trayMoved` carries the Stage's Move allowance and
|
|
* `consistSorted` carries where the engine ended up; `switch.sortConsist` gained an OPTIONAL
|
|
* `engineAt` (absent means the nose, which is what every sort did before, so an older save
|
|
* replays to the same train). Events are derived by replaying a save rather than stored in one,
|
|
* and an optional intent field defaulting to the old behaviour changes no past move.
|
|
*
|
|
* THE SMALL YARD RULE CHANGED IN THE PERMISSIVE DIRECTION, which cannot strand a save either: a
|
|
* train there may now be sorted with cars ahead of its engine (`implications.md` against the
|
|
* v0.4.5 card text, Jesse's ruling). Nothing once legal became illegal; §8.2's departure check is
|
|
* untouched and still holds a broken-backed train at the Office.
|
|
*
|
|
* v0.8.0.15 AND v0.8.0.16 CHANGE NO RULE AND STRAND NOTHING.
|
|
* `git diff v0.8.0.14..v0.8.0.16 -- src/engine/` is one sentence of card TEXT and one doc
|
|
* comment. The Interchange stopped telling players "Cars may be sorted into any new order here"
|
|
* — a printed capability that has never been implemented, reaching the board through
|
|
* `mainlineDescription`, which `view.ts` renders as a Mainline card's `what`. Nothing reads
|
|
* `sortsCars` to permit a sort; its only live use is marking the card an Extra may be made up
|
|
* on. No predicate was touched, so no once-legal move became illegal.
|
|
*
|
|
* The rest of those two releases is documentation inside the repository — a Quickstart for a new
|
|
* player, and the four hand-written references brought up to the game as it runs. None of it is
|
|
* served by the site or read by the service; it rides along in the image because the Dockerfile
|
|
* copies the game's tree in.
|
|
*
|
|
* SO THE RESUME WARNING IN THESE RELEASE NOTES IS ENTIRELY v0.8.0.14's, and it still applies:
|
|
* a box on 0.8.0.13:0 takes this update in one hop and meets the Modifier rule on the way.
|
|
*/
|
|
up: async ({ effects }) => {},
|
|
down: IMPOSSIBLE,
|
|
},
|
|
})
|