import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk' export const current = VersionInfo.of({ // `:` — 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.11:0', releaseNotes: { en_US: 'Bundles Station Master v0.8.0.11 — sixteen fixes from the second multiplayer playtest. ' + '**Games already running on this server resume normally.** No rule changed: the whole engine ' + 'difference is one field added to one event and one card description reworded, so nothing ' + 'that was legal has become illegal. **Making up a train is far clearer.** The panel now says ' + 'what the train STILL needs rather than only what its card calls for, says that you add ONE ' + 'car before the round passes to the next player, marks the train being loaded on the Division ' + 'map, and highlights the cars you may add in the same amber every other button uses — the ' + 'cars in the Division Yard have always been the buttons, but they did not look like it. **A ' + 'train’s arrival now says whose Office it reached**, and no longer tells every player they ' + 'can work it when it is standing in somebody else’s district. **While your board catches up** ' + 'on other players’ moves you can now PAUSE it and look as long as you like — a paused move ' + 'keeps the time it had left — and you can open any other player’s Office Area for a look. The ' + 'Day, Stage and phase on screen now match the move you are watching instead of running ahead ' + 'of it, so being five moves behind looks the same everywhere on the page. When nobody is ' + 'being waited on, the screen says what the Division is doing — “the Division is moving ' + 'trains” — instead of “waiting on nobody”. **Saved games download named after the game**, ' + 'with the join code, Day and Stage in the filename. Also: the LIMITS sign is printed below ' + 'its card instead of through the middle of the word, the dividing line on a Mainline card can ' + 'actually be seen, a Restaurant or Hotel next to a Whistle Post says it is dormant until the ' + 'Office is upgraded rather than appearing to do nothing, only the one card that reads ' + 'FAST/SLOW mentions it, and the version number appears once in the page header instead of ' + 'twice.', es_ES: 'Incluye Station Master v0.8.0.11 — dieciséis correcciones de la segunda partida de prueba ' + 'multijugador. **Las partidas en curso en este servidor se reanudan con normalidad**: no ha ' + 'cambiado ninguna regla. **Formar un tren es mucho más claro.** El panel indica ahora lo que ' + 'al tren le FALTA, y no solo lo que pide su carta; explica que añades UN vagón y el turno ' + 'pasa al siguiente jugador; marca en el mapa de la División el tren que se está formando; y ' + 'resalta los vagones que puedes añadir con el mismo ámbar que los demás botones — los vagones ' + 'del Patio de División siempre fueron los botones, pero no lo parecían. **La llegada de un ' + 'tren dice a qué Oficina llegó**, y ya no le dice a todo el mundo que puede trabajarlo cuando ' + 'está en el distrito de otro jugador. **Mientras tu tablero se pone al día** con los ' + 'movimientos de otros, ahora puedes PAUSARLO el tiempo que quieras — el movimiento pausado ' + 'conserva el tiempo que le quedaba — y abrir el Área de Oficina de cualquier otro jugador ' + 'para verla. El Día, la Etapa y la fase en pantalla coinciden con el movimiento que estás ' + 'viendo, así que ir cinco movimientos por detrás se ve igual en toda la página. Cuando no se ' + 'espera a nadie, la pantalla dice qué está haciendo la División — «la División está moviendo ' + 'trenes» — en lugar de «esperando a nadie». **Las partidas guardadas se descargan con el ' + 'nombre de la partida**: el código de acceso, el Día y la Etapa en el nombre del archivo. ' + 'Además: el letrero LIMITS se imprime debajo de su carta y no atravesando la palabra, la ' + 'línea divisoria de una carta de Línea Principal se ve de verdad, un Restaurante u Hotel ' + 'junto a un Whistle Post indica que está inactivo hasta que se mejore la Oficina, solo la ' + 'única carta que lee RÁPIDO/LENTO lo menciona, y el número de versión aparece una vez en la ' + 'cabecera en lugar de dos.', de_DE: 'Enthält Station Master v0.8.0.11 — sechzehn Korrekturen aus der zweiten Mehrspieler-' + 'Testpartie. **Laufende Spiele auf diesem Server werden normal fortgesetzt**: keine Regel ' + 'wurde geändert. **Das Zusammenstellen eines Zuges ist viel klarer.** Das Panel nennt jetzt, ' + 'was dem Zug noch FEHLT, statt nur, was seine Karte verlangt; es sagt, dass Sie EINEN Wagen ' + 'anhängen und die Runde dann zum nächsten Spieler weitergeht; es markiert den Zug, der gerade ' + 'beladen wird, auf der Divisionskarte; und die Wagen, die Sie anhängen dürfen, leuchten im ' + 'selben Bernstein wie jede andere Schaltfläche — die Wagen im Divisionsbahnhof waren immer ' + 'schon die Schaltflächen, sahen aber nicht danach aus. **Die Ankunft eines Zuges nennt jetzt, ' + 'wessen Office er erreicht hat**, und sagt nicht mehr allen, sie könnten ihn bearbeiten, wenn ' + 'er im Bezirk eines anderen steht. **Während Ihr Spielfeld die Züge der anderen nachholt**, ' + 'können Sie es nun PAUSIEREN, so lange Sie wollen — der pausierte Zug behält die Zeit, die ' + 'ihm blieb — und das Office-Gebiet jedes anderen Spielers ansehen. Tag, Etappe und Phase auf ' + 'dem Bildschirm stimmen mit dem Zug überein, den Sie gerade sehen; fünf Züge im Rückstand zu ' + 'sein sieht überall auf der Seite gleich aus. Wartet das Spiel auf niemanden, zeigt der ' + 'Bildschirm, was die Division tut — „die Division bewegt Züge“ — statt „wartet auf niemanden“. ' + '**Gespeicherte Spiele werden nach dem Spiel benannt**: Beitrittscode, Tag und Etappe im ' + 'Dateinamen. Außerdem: Das LIMITS-Schild steht unter seiner Karte statt mitten im Wort, die ' + 'Trennlinie auf einer Hauptstreckenkarte ist tatsächlich zu sehen, ein Restaurant oder Hotel ' + 'neben einem Whistle Post meldet sich als ruhend, bis das Office ausgebaut wird, nur die eine ' + 'Karte, die SCHNELL/LANGSAM liest, erwähnt es, und die Versionsnummer erscheint einmal in der ' + 'Kopfzeile statt zweimal.', pl_PL: 'Zawiera Station Master v0.8.0.11 — szesnaście poprawek z drugiej testowej partii ' + 'wieloosobowej. **Gry w toku na tym serwerze wznawiają się normalnie**: żadna zasada się nie ' + 'zmieniła. **Kompletowanie pociągu jest dużo jaśniejsze.** Panel pokazuje teraz, czego ' + 'pociągowi jeszcze BRAKUJE, a nie tylko czego wymaga jego karta; mówi, że dodajesz JEDEN ' + 'wagon, po czym kolejka przechodzi do następnego gracza; zaznacza kompletowany pociąg na ' + 'mapie Dywizji; a wagony, które możesz dodać, świecą tym samym bursztynem co pozostałe ' + 'przyciski — wagony na Stacji Dywizyjnej zawsze były przyciskami, ale tak nie wyglądały. ' + '**Przyjazd pociągu podaje, czyje Biuro osiągnął**, i nie mówi już wszystkim, że mogą go ' + 'obsłużyć, gdy stoi w dzielnicy innego gracza. **Gdy twoja plansza nadrabia ruchy innych**, ' + 'możesz ją teraz ZATRZYMAĆ na dowolnie długo — zatrzymany ruch zachowuje pozostały mu czas — ' + 'i obejrzeć Biuro dowolnego innego gracza. Dzień, Etap i faza na ekranie zgadzają się z ' + 'ruchem, który oglądasz, więc pięć ruchów w tyle wygląda tak samo na całej stronie. Gdy gra ' + 'na nikogo nie czeka, ekran mówi, co robi Dywizja — „Dywizja przesuwa pociągi” — zamiast ' + '„czeka na nikogo”. **Zapisane gry pobierają się nazwane po grze**: kod dołączenia, Dzień i ' + 'Etap w nazwie pliku. Ponadto: napis LIMITS jest drukowany pod kartą, a nie przez środek ' + 'słowa, linia podziału na karcie Magistrali jest wreszcie widoczna, Restauracja lub Hotel ' + 'obok Whistle Post informuje, że jest uśpiony do czasu rozbudowy Biura, tylko ta jedna karta, ' + 'która czyta SZYBKO/WOLNO, o tym wspomina, a numer wersji pojawia się w nagłówku raz zamiast ' + 'dwa razy.', fr_FR: 'Inclut Station Master v0.8.0.11 — seize corrections issues de la deuxième partie de test ' + 'multijoueurs. **Les parties en cours sur ce serveur reprennent normalement** : aucune règle ' + 'n’a changé. **Composer un train est bien plus clair.** Le panneau indique désormais ce qu’il ' + 'MANQUE au train, et non plus seulement ce que sa carte demande ; il précise que vous ajoutez ' + 'UN wagon avant que le tour ne passe au joueur suivant ; il marque sur la carte de la ' + 'Division le train en cours de composition ; et les wagons que vous pouvez ajouter ' + 's’allument dans le même ambre que tous les autres boutons — les wagons du Dépôt de Division ' + 'ont toujours été les boutons, mais n’en avaient pas l’air. **L’arrivée d’un train indique à ' + 'quel Office il est parvenu**, et ne dit plus à tout le monde qu’il peut le manœuvrer alors ' + 'qu’il stationne dans le district d’un autre. **Pendant que votre plateau rattrape** les ' + 'coups des autres, vous pouvez maintenant le METTRE EN PAUSE aussi longtemps que vous voulez ' + '— le coup mis en pause conserve le temps qu’il lui restait — et ouvrir l’Aire de Bureau de ' + 'n’importe quel autre joueur. Le Jour, l’Étape et la phase affichés correspondent au coup que ' + 'vous regardez : avoir cinq coups de retard se voit de la même façon partout sur la page. ' + 'Quand la partie n’attend personne, l’écran dit ce que fait la Division — « la Division fait ' + 'circuler les trains » — au lieu de « en attente de personne ». **Les parties sauvegardées ' + 'portent le nom de la partie** : code d’accès, Jour et Étape dans le nom du fichier. ' + 'Également : le panneau LIMITS est imprimé sous sa carte au lieu de traverser le mot, la ' + 'ligne de séparation d’une carte de Ligne principale est enfin visible, un Restaurant ou un ' + 'Hôtel à côté d’un Whistle Post indique qu’il est en sommeil jusqu’à l’amélioration de ' + 'l’Office, seule la carte qui lit RAPIDE/LENT le mentionne, et le numéro de version apparaît ' + 'une fois dans l’en-tête au lieu de deux.', }, 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-` 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. */ up: async ({ effects }) => {}, down: IMPOSSIBLE, }, })