Files
JesseandClaude Fable 5.1 644b24051a 0.8.6:0 — bundle Station Master v0.8.6, the four audit releases
Submodule pinned 3befc42 (v0.8.2) → def4820 (v0.8.6). `current.ts` bumped in place — the
outgoing `up` was empty, no migration — with the resume question measured on this server's
own thirteen saves rather than argued from the diff: 0.8.2 had refused all thirteen (the
Second Section card went into the deck after its save check), and this build restores the
three it promised while leaving the ten it refused for a rule refused. Release notes in all
five locales; README's bundled-version summary rewritten for 0.8.3 through 0.8.6.
`instructions.md` is unchanged: nothing about running the service moved.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FrCWubm9GAftYCm2hWdKwK
2026-09-29 18:20:35 -04:00

327 lines
28 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.6:0',
releaseNotes: {
en_US:
'Bundles Station Master v0.8.6 — four releases from a code audit of the game (engine, server, ' +
'browser, tests), every finding checked against the code before it was acted on. **GAMES ALREADY ' +
'RUNNING ON THIS SERVER: the three that 0.8.2 promised would resume now do, and the ten it refused ' +
'stay refused.** 0.8.2 had in fact stranded all thirteen — the Second Section card went into the deck ' +
"after that release's save check, and a deck one card larger shuffles into a different order from the " +
'same seed — so this build deals an older save from the deck it was dealt from. **The engine:** a ' +
"player could switch a rival's train, and the rival paid the Moves; a rival's crew standing in their " +
'own district blocked yours; drawing the last card off a Department could put the drawn card in two ' +
"places and lose the refill; the Freight Agent's unjam cleared the first load rather than the one you " +
'named; the collision limit could not fire in Stage 12; an Expedite fault was charged once per ' +
'clearance question rather than once per phase; a train the Interlocking held at the Limits was only ' +
'released by another arrival, never by a departure. **The table:** a player who left a lobby kept a ' +
'token that could watch and move for whoever took the seat next; the first move after reloading the ' +
'page could be silently swallowed; two moves at once could tear the save file, and one torn file took ' +
'every game on the server down at start; an error on a stream could stop the whole service; a ' +
'double-click did the thing twice. **Saving:** in a Competitive game the save file — which carries ' +
"the seed, and so every rival's hand — can be downloaded once the game is over; in Co-op at any time. " +
'**Also:** the documentation pages render nested lists properly, the make-up panel only lists cars ' +
'the train can still take, and the unused-code check is now part of the build.',
es_ES:
'Incluye Station Master v0.8.6 — cuatro versiones salidas de una auditoría del código del juego ' +
'(motor, servidor, navegador, pruebas), cada hallazgo comprobado contra el código antes de actuar. ' +
'**PARTIDAS YA EN MARCHA EN ESTE SERVIDOR: las tres que 0.8.2 prometió reanudar ahora se reanudan, y ' +
'las diez que rechazó siguen rechazadas.** En realidad 0.8.2 había dejado colgadas las trece — la ' +
'carta Segunda Sección entró en el mazo después de la comprobación de partidas guardadas de esa ' +
'versión, y un mazo con una carta más se baraja en otro orden con la misma semilla — así que esta ' +
'versión reparte una partida antigua con el mazo con el que se repartió. **El motor:** un jugador ' +
'podía maniobrar el tren de un rival, y el rival pagaba los Movimientos; una cuadrilla rival en su ' +
'propio distrito bloqueaba el tuyo; robar la última carta de un Departamento podía duplicarla y ' +
'perder la de relleno; el desatasco del Agente de Carga retiraba la primera carga y no la señalada; ' +
'el límite de colisiones no podía dispararse en la Etapa 12; una falta de Expedición se cobraba por ' +
'cada pregunta de vía libre y no una vez por fase; un tren retenido en los Límites solo lo liberaba ' +
'otra llegada, nunca una salida. **La mesa:** quien abandonaba una sala conservaba una ficha con la ' +
'que podía ver y mover por quien ocupara después su asiento; la primera jugada tras recargar la ' +
'página podía perderse en silencio; dos jugadas a la vez podían corromper el archivo guardado, y un ' +
'archivo corrupto tumbaba todas las partidas al arrancar; un error en un flujo podía parar todo el ' +
'servicio; un doble clic hacía la cosa dos veces. **Guardar:** en una partida Competitiva el archivo ' +
'guardado — que lleva la semilla, y con ella la mano de cada rival — se puede descargar cuando la ' +
'partida ha terminado; en Cooperativa, en cualquier momento.',
de_DE:
'Enthält Station Master v0.8.6 — vier Versionen aus einer Code-Prüfung des Spiels (Engine, Server, ' +
'Browser, Tests), jeder Befund vor dem Handeln am Code geprüft. **BEREITS LAUFENDE PARTIEN AUF DIESEM ' +
'SERVER: die drei, die 0.8.2 als fortsetzbar versprach, sind es jetzt; die zehn abgelehnten bleiben ' +
'abgelehnt.** Tatsächlich hatte 0.8.2 alle dreizehn gestrandet — die Karte Zweiter Abschnitt kam nach ' +
'der Spielstand-Prüfung dieser Version in den Stapel, und ein um eine Karte größerer Stapel mischt ' +
'sich aus demselben Startwert anders — daher teilt diese Version einen älteren Spielstand aus dem ' +
'Stapel aus, aus dem er stammte. **Die Engine:** ein Spieler konnte den Zug eines Gegners rangieren, ' +
'und der Gegner zahlte die Züge; eine gegnerische Mannschaft im eigenen Bezirk blockierte deinen; das ' +
'Ziehen der letzten Karte einer Abteilung konnte sie verdoppeln und die Nachschubkarte verlieren; das ' +
'Freiräumen des Frachtagenten nahm die erste Ladung statt der benannten; das Kollisionslimit konnte ' +
'in Etappe 12 nicht greifen; ein Eilzug-Vergehen wurde je Freigabefrage statt einmal je Phase ' +
'berechnet; ein an der Grenze gehaltener Zug wurde nur durch eine weitere Ankunft freigegeben, nie ' +
'durch eine Abfahrt. **Der Tisch:** wer eine Lobby verließ, behielt ein Token, mit dem er für den ' +
'nächsten Sitzinhaber zusehen und ziehen konnte; der erste Zug nach dem Neuladen der Seite konnte ' +
'stillschweigend verschluckt werden; zwei Züge zugleich konnten die Spielstanddatei zerreißen, und ' +
'eine zerrissene Datei legte beim Start jede Partie lahm; ein Fehler auf einem Stream konnte den ' +
'ganzen Dienst anhalten; ein Doppelklick tat die Sache zweimal. **Speichern:** in einer ' +
'Wettbewerbspartie lässt sich die Spielstanddatei — sie enthält den Startwert und damit jede ' +
'gegnerische Hand — erst nach Spielende herunterladen; im Koop-Modus jederzeit.',
pl_PL:
'Zawiera Station Master v0.8.6 — cztery wydania z audytu kodu gry (silnik, serwer, przeglądarka, ' +
'testy), każde ustalenie sprawdzone w kodzie przed działaniem. **GRY JUŻ TRWAJĄCE NA TYM SERWERZE: ' +
'trzy, które 0.8.2 obiecało wznowić, teraz się wznawiają; dziesięć odrzuconych pozostaje ' +
'odrzuconych.** W istocie 0.8.2 unieruchomiło wszystkie trzynaście — karta Druga Sekcja trafiła do ' +
'talii po kontroli zapisów tego wydania, a talia większa o jedną kartę tasuje się inaczej z tego ' +
'samego ziarna — więc to wydanie rozdaje starszy zapis z talii, z której został rozdany. **Silnik:** ' +
'gracz mógł manewrować pociągiem rywala, a rywal płacił Ruchy; załoga rywala w jego własnym okręgu ' +
'blokowała twój; dobranie ostatniej karty z Działu mogło ją zdublować i zgubić kartę uzupełniającą; ' +
'odblokowanie przez Agenta Towarowego usuwało pierwszy ładunek zamiast wskazanego; limit kolizji nie ' +
'mógł zadziałać w Etapie 12; kara za Ekspres była naliczana za każde pytanie o zwolnienie toru ' +
'zamiast raz na fazę; pociąg zatrzymany na Granicy zwalniało tylko kolejne przybycie, nigdy odjazd. ' +
'**Stół:** kto opuścił poczekalnię, zachowywał token pozwalający oglądać i grać za tego, kto zajął ' +
'miejsce po nim; pierwszy ruch po przeładowaniu strony mógł zostać po cichu połknięty; dwa ruchy ' +
'naraz mogły uszkodzić plik zapisu, a jeden uszkodzony plik wyłączał przy starcie wszystkie gry; błąd ' +
'w strumieniu mógł zatrzymać całą usługę; podwójne kliknięcie robiło rzecz dwa razy. **Zapis:** w ' +
'grze Rywalizacyjnej plik zapisu — zawierający ziarno, a więc rękę każdego rywala — można pobrać po ' +
'zakończeniu gry; w Kooperacji w każdej chwili.',
fr_FR:
"Inclut Station Master v0.8.6 — quatre versions issues d'un audit du code du jeu (moteur, serveur, " +
"navigateur, tests), chaque constat vérifié dans le code avant d'agir. **PARTIES DÉJÀ EN COURS SUR CE " +
'SERVEUR : les trois que 0.8.2 promettait de reprendre reprennent désormais, et les dix refusées ' +
'restent refusées.** En réalité 0.8.2 les avait toutes bloquées — la carte Seconde Section est entrée ' +
"dans le paquet après le contrôle des sauvegardes de cette version, et un paquet d'une carte de plus " +
'se mélange autrement à partir de la même graine — cette version distribue donc une ancienne ' +
"sauvegarde avec le paquet dont elle vient. **Le moteur :** un joueur pouvait manœuvrer le train d'un " +
'rival, et le rival payait les Mouvements ; une équipe rivale dans son propre district bloquait le ' +
"vôtre ; piocher la dernière carte d'un Département pouvait la dupliquer et perdre la carte de " +
"remplacement ; le déblocage de l'Agent de fret retirait le premier chargement et non celui désigné ; " +
"la limite de collisions ne pouvait pas se déclencher à l'Étape 12 ; une faute d'Express était " +
'comptée à chaque question de voie libre et non une fois par phase ; un train retenu à la Limite ' +
"n'était libéré que par une autre arrivée, jamais par un départ. **La table :** qui quittait un salon " +
'gardait un jeton permettant de voir et de jouer pour celui qui prenait ensuite le siège ; le premier ' +
'coup après rechargement de la page pouvait être avalé en silence ; deux coups à la fois pouvaient ' +
'déchirer le fichier de sauvegarde, et un fichier déchiré mettait toutes les parties hors service au ' +
'démarrage ; une erreur sur un flux pouvait arrêter tout le service ; un double clic faisait la chose ' +
'deux fois. **Sauvegarde :** en partie Compétitive, le fichier — qui porte la graine, donc la main de ' +
'chaque rival — se télécharge une fois la partie terminée ; en Coopération, à tout moment.',
},
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.
*
* v0.8.3 THROUGH v0.8.6 ARE THE AUDIT, AND THE RESUME QUESTION WAS MEASURED ON THIS SERVER'S OWN
* SAVES rather than argued from the diff — because the argument had already failed once. 0.8.2's
* entry says three of thirteen resume; the boot log on the box refused thirteen of thirteen, at
* move 3, CARD_NOT_IN_HAND. The Second Section card had gone into the deck after 0.8.2's save
* check ran, and a deck one card larger shuffles into a different order from the same seed. v0.8.3
* adds `secondSectionCard` to the house rules — no dial, a fact about the deal — and `withSavedDeal`
* sets it false for a saved config that predates `startingOffice`. Result, replayed with
* `tryResumeSession` (never `fromSave`, which skips the legality check): 3 resume / 10 refuse, the
* same ten at the same moves for the same rules 0.8.2 named. So this update RESTORES three games
* 0.8.2 lost and un-refuses none of the ten.
*
* THE ENGINE DIFF DOES CHANGE PREDICATES, and each is the narrowing kind in principle: `check` now
* refuses a switching intent on a tray outside the actor's district; the collision floor is judged
* before the Day rolls over; the Department-draw reshuffle collects a different set; a held train is
* released at the end of a Mainline phase. None of the thirteen saves met any of them — measured,
* above — and a save that did would refuse at the move with its code and be left untouched, as
* always. Events gained `index` (unjam) and `freedBy: number | null` (release); events are derived,
* not stored. v0.8.4 is the HTTP layer and the browser and touches nothing on disk except HOW
* `game.json` is written (unique temp names, one writer per path) — the format is unchanged, and a
* torn file from before is now logged and skipped at boot rather than fatal. v0.8.5 is
* documentation and dead code. v0.8.6 refuses `/api/save` to a Competitive seat until the game is
* finished (Jesse's ruling) — a read-only route, nothing on disk. No migration.
*/
up: async ({ effects }) => {},
down: IMPOSSIBLE,
},
})