Files
station-master-startos/startos/versions/current.ts
T
JesseandClaude Opus 5 3e6e4690e2 0.8.0.9:0 — bundle Station Master v0.8.0.9
The bots that fill empty seats play far better: they plan each switching turn,
stop taking cards they cannot play, no longer run Second Sections by accident,
and lay track where it opens something up. The engine checks moves about three
times faster, with play proven identical. No rule changed, so games in progress
resume; the release notes say so in all five locales.

README's bundled-version line had stayed at 0.7.9.8 through the 0.8.0 series;
it now names 0.8.0.9.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017nnuCv8UodHucFfx3LWEoX
2026-09-15 15:34:35 -04:00

173 lines
14 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.9:0',
releaseNotes: {
en_US:
'Bundles Station Master v0.8.0.9 — the bots play much better, and the server does its work ' +
'faster. GAMES IN PROGRESS ON THIS SERVER ARE UNAFFECTED and will resume normally: no rule ' +
'changed. A bot filling an empty seat now plans its whole switching turn before its first ' +
'move, so it delivers cars to industries that can work them instead of choosing one move at a ' +
'time, and it brings expedited trains back to the station. It no longer takes face-up cards ' +
'it cannot play only to throw them back, so it builds its district — more track, more ' +
'industries, and run-arounds far more often, because it now lays track where it opens up ' +
'something to do. And it no longer runs a Second Section by accident when it meant to start ' +
'an Extra, which caused many of its collisions. Measured over thousands of simulated games, a ' +
'bot now earns about 4.8 Revenue a game, where it earned about −0.3 before. Behind the ' +
'scenes, working out where a train can move is now done once per position instead of several ' +
'times, which makes the server about three times faster at checking moves — with play proven ' +
'identical.',
es_ES:
'Incluye Station Master v0.8.0.9 — los bots juegan mucho mejor y el servidor trabaja más ' +
'rápido. LAS PARTIDAS EN CURSO EN ESTE SERVIDOR NO SE VEN AFECTADAS y se reanudarán con ' +
'normalidad: no ha cambiado ninguna regla. Un bot que ocupa un asiento vacío planifica ahora ' +
'su turno de maniobras completo antes de su primer movimiento, así que entrega vagones a las ' +
'industrias que pueden trabajarlos en lugar de decidir movimiento a movimiento, y devuelve ' +
'los trenes expresos a la estación. Ya no toma cartas descubiertas que no puede jugar solo ' +
'para volver a descartarlas, así que construye su distrito — más vía, más industrias y vías ' +
'de circunvalación mucho más a menudo, porque ahora tiende vía donde abre algo que hacer. Y ' +
'ya no lanza una Segunda Sección por accidente cuando quería poner en marcha un Extra, lo que ' +
'causaba muchas de sus colisiones. Medido en miles de partidas simuladas, un bot gana ahora ' +
'unos 4,8 de Ingresos por partida, frente a unos −0,3 antes. Por dentro, calcular adónde ' +
'puede moverse un tren se hace ahora una vez por posición en lugar de varias, lo que hace al ' +
'servidor unas tres veces más rápido al comprobar movimientos — con el juego demostrado ' +
'idéntico.',
de_DE:
'Enthält Station Master v0.8.0.9 — die Bots spielen deutlich besser, und der Server arbeitet ' +
'schneller. LAUFENDE SPIELE AUF DIESEM SERVER SIND NICHT BETROFFEN und werden normal ' +
'fortgesetzt: Keine Regel hat sich geändert. Ein Bot auf einem freien Platz plant jetzt ' +
'seinen ganzen Rangierzug, bevor er sich zum ersten Mal bewegt, und stellt Wagen daher bei ' +
'Industrien zu, die sie bearbeiten können, statt Zug um Zug zu entscheiden; beschleunigte ' +
'Züge bringt er zum Bahnhof zurück. Er nimmt keine offenen Karten mehr, die er nicht spielen ' +
'kann, nur um sie wieder abzuwerfen, und baut deshalb seinen Bezirk aus — mehr Gleis, mehr ' +
'Industrien und viel öfter Umfahrgleise, weil er Gleis jetzt dort legt, wo es etwas zu tun ' +
'eröffnet. Und er setzt keinen zweiten Zugteil (Second Section) mehr aus Versehen ein, wenn ' +
'er einen Sonderzug starten wollte, was viele seiner Zusammenstöße verursachte. Über Tausende ' +
'simulierter Spiele gemessen, erzielt ein Bot jetzt etwa 4,8 Einnahmen pro Spiel, vorher etwa ' +
'−0,3. Im Hintergrund wird jetzt einmal pro Stellung statt mehrfach berechnet, wohin ein Zug ' +
'fahren kann, was den Server beim Prüfen von Zügen etwa dreimal schneller macht — bei ' +
'nachweislich identischem Spielverlauf.',
pl_PL:
'Zawiera Station Master v0.8.0.9 — boty grają znacznie lepiej, a serwer pracuje szybciej. GRY ' +
'W TOKU NA TYM SERWERZE NIE SĄ ZAGROŻONE i zostaną normalnie wznowione: żadna zasada się nie ' +
'zmieniła. Bot zajmujący wolne miejsce planuje teraz całą swoją turę manewrów przed pierwszym ' +
'ruchem, więc dostarcza wagony do zakładów, które mogą je obsłużyć, zamiast decydować ruch po ' +
'ruchu, i odprowadza pociągi przyspieszone z powrotem na stację. Nie bierze już odkrytych ' +
'kart, których nie może zagrać, tylko po to, by je odrzucić, więc rozbudowuje swój okręg — ' +
'więcej torów, więcej zakładów i znacznie częściej tory objazdowe, bo kładzie teraz tor tam, ' +
'gdzie otwiera to coś do zrobienia. I nie uruchamia już przez przypadek Drugiej Sekcji, gdy ' +
'chciał wypuścić pociąg dodatkowy, co powodowało wiele jego zderzeń. Zmierzone w tysiącach ' +
'symulowanych gier: bot zarabia teraz około 4,8 Przychodu na grę, wcześniej około −0,3. W tle ' +
'to, dokąd pociąg może pojechać, jest teraz liczone raz na pozycję zamiast kilka razy, co ' +
'czyni serwer około trzy razy szybszym przy sprawdzaniu ruchów — przy udowodnionym ' +
'identycznym przebiegu gry.',
fr_FR:
'Inclut Station Master v0.8.0.9 — les bots jouent beaucoup mieux, et le serveur travaille ' +
'plus vite. LES PARTIES EN COURS SUR CE SERVEUR NE SONT PAS AFFECTÉES et reprendront ' +
'normalement : aucune règle n’a changé. Un bot qui occupe une place libre planifie désormais ' +
'tout son tour de manœuvres avant son premier mouvement, si bien qu’il livre les wagons aux ' +
'industries capables de les traiter au lieu de décider coup par coup, et il ramène les trains ' +
'accélérés en gare. Il ne prend plus de cartes face visible qu’il ne peut pas jouer pour les ' +
'défausser aussitôt, donc il développe son district — plus de voie, plus d’industries et bien ' +
'plus souvent des voies d’évitement, parce qu’il pose désormais la voie là où elle ouvre ' +
'quelque chose à faire. Et il ne lance plus une Deuxième Section par erreur quand il voulait ' +
'faire partir un train supplémentaire, ce qui causait beaucoup de ses collisions. Mesuré sur ' +
'des milliers de parties simulées, un bot gagne maintenant environ 4,8 de Revenu par partie, ' +
'contre environ −0,3 auparavant. En coulisses, le calcul des endroits où un train peut aller ' +
'se fait désormais une fois par position au lieu de plusieurs, ce qui rend le serveur environ ' +
'trois fois plus rapide pour vérifier les coups — avec un jeu prouvé identique.',
},
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.
*
* 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.
*/
up: async ({ effects }) => {},
down: IMPOSSIBLE,
},
})