0.7.7:0 — bundle Station Master v0.7.7

Submodule pinned to v0.7.7 (af68aac). current.ts bumped in place at
0.7.7:0 — no new version file, no migration: the change is to how the
built client is cached, not to what it does.

Every packaged build until now published ?v=nogit as its cache key (the
.s9pk Dockerfile copies the tree in without .git, so git rev-parse
fails), and serveStatic sent no Cache-Control at all — so 0.7.5's
solitaire setup screen and 0.7.6's fix to it were both installed here
correctly and neither ever reached a browser.

Verified on phoenix.local against what the server actually returns, not
just what was packed: build tag is 0.7.7-mtf7hyxc (not nogit) and the
module graph's inner imports carry the same tag; play.html is no-cache;
a ?v=-tagged module is immutable for a year; an untagged one is
no-cache. Migration 0.7.6:0 -> 0.7.7:0 ran empty and both games in
progress (WHISTLE-4086, COAL-7370) resumed with their same intent counts.

README.md records that a hard reload is NOT a sufficient check for this
class of bug — confirmed in the field on 0.7.6, where only a fresh
private window showed the new build.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AdG46Ja2PEDBkpqiDazMoX
This commit is contained in:
Jesse
2026-08-29 22:46:25 -04:00
co-authored by Claude Sonnet 5
parent 590ff5fa0b
commit 921db34b55
4 changed files with 74 additions and 46 deletions
+19 -6
View File
@@ -13,12 +13,25 @@ Station Master is a railroad operations board game with an authoritative multipl
solitaire needs no server and is not what this package is for. This package runs that server —
the browser client, the lobby, and the intent/SSE API — as a single StartOS service.
**Bundled version: 0.7.6.** Fixes the solitaire door 0.7.5 introduced: a browser that had ever held a
multiplayer seat could not reach the new setup screen at all — a bare page load could not tell
"clicked Play solitaire" apart from "reloaded mid multiplayer game", so the door lost to whatever
game or lobby that browser last touched. The door now marks its intent explicitly (`?solitaire`), the
same fix `?lobby` already carries for the door on the other side. Client-side only; every game in
progress carries over.
**Bundled version: 0.7.7.** Fixes the client caching that stopped the two releases before it from
ever reaching a browser. `build-web.ts` stamps a build tag onto every module URL as a cache key, and
its fallback when `git rev-parse` fails was the literal `nogit` — which is precisely the `.s9pk`
case, since the Dockerfile copies the working tree in without `.git`. So every packaged release
published `./web/main.js?v=nogit`, byte-identical to the one before, and a returning browser refetched
nothing. `serveStatic` also sent no `Cache-Control` at all, so the pages that carry those tags were
themselves served from cache. The tag is now the package version plus the build timestamp, and a
request carrying `?v=` is `immutable` for a year while everything else is `no-cache`.
**Diagnosing "my fix did not ship".** A hard reload is NOT a sufficient check — confirmed in the
field on 0.7.6: the document refetches but ES module sub-imports keep their cached `?v=` URLs, so the
module graph stays stale. A fresh private window is the reliable test. Reading what the server
returns (`curl` inside the container) proves what was installed, never what a browser is running.
**0.7.6 fixed the solitaire door 0.7.5 introduced**: a browser that had ever held a multiplayer seat
could not reach the new setup screen at all — a bare page load could not tell "clicked Play
solitaire" apart from "reloaded mid multiplayer game", so the door lost to whatever game or lobby
that browser last touched. The door marks its intent explicitly now (`?solitaire`), the same fix
`?lobby` already carries for the door on the other side.
**0.7.5 was a client-side flow change**: a genuinely fresh visit to the solitaire page opens a setup
screen and asks for the game's options before dealing, the same question the multiplayer lobby has
+7
View File
@@ -35,6 +35,13 @@ watches the table — there is nothing else to open.
Solitaire runs entirely in your own browser and needs nothing from the server, so it works here
exactly as it does on the public Station Master site.
**What changed in 0.7.7.** Updates to this service now actually reach your browser. Until now every
release published its files under the same cache name and the server never told browsers when to
look again, so returning players kept running whatever version their browser had already stored —
the 0.7.5 solitaire setup screen and its 0.7.6 fix were both installed correctly here and neither
was ever seen. If a past update seemed to do nothing, this is why, and opening the page in a private
window was the only way to see it. That should not be necessary again.
**What changed in 0.7.6.** The **Play solitaire** door on the front page now reliably reaches
solitaire. If this browser had ever taken a seat at a multiplayer table, the door used to lose to
that game or lobby instead — a plain page load couldn't tell "I clicked Play solitaire" apart from
+47 -39
View File
@@ -5,54 +5,62 @@ export const current = VersionInfo.of({
// (`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.
version: '0.7.6:0',
version: '0.7.7:0',
releaseNotes: {
en_US:
'Bundles Station Master v0.7.6 \u2014 fixes the solitaire door introduced in v0.7.5. A browser that ' +
"had ever held a multiplayer seat could not reach solitaire's new setup screen at all: a bare " +
'page load could not tell "clicked Play solitaire" apart from "reloaded mid multiplayer game", ' +
'so the door lost to whatever game or lobby this browser last touched. The door now marks its ' +
'intent explicitly, so it reaches solitaire every time. No rules changed, so games in progress ' +
'are unaffected.',
'Bundles Station Master v0.7.7 \u2014 updates now actually reach your browser. Every packaged ' +
'release until now published its files under the same cache key, and the server never told ' +
'browsers when to look again, so a returning player kept running whichever version their ' +
'browser had already stored: the v0.7.5 solitaire setup screen and the v0.7.6 fix to it were ' +
'both installed correctly and neither was ever seen. Each build now carries its own key and ' +
"the pages are marked to revalidate, so this is the last update you'll have to open a private " +
'window to see. No rules changed; games in progress are unaffected.',
es_ES:
'Incluye Station Master v0.7.6: corrige la puerta de solitario introducida en v0.7.5. Un ' +
'navegador que alguna vez ocup\u00f3 un asiento multijugador no pod\u00eda llegar en absoluto a la nueva ' +
'pantalla de configuraci\u00f3n del solitario: una carga de p\u00e1gina simple no distingu\u00eda "puls\u00e9 Jugar ' +
'en solitario" de "recargu\u00e9 en medio de una partida multijugador", as\u00ed que la puerta perd\u00eda ' +
'frente a cualquier partida o sala de espera que ese navegador hubiera tocado por \u00faltima vez. La ' +
'puerta ahora marca su intenci\u00f3n expl\u00edcitamente, as\u00ed que llega al solitario siempre. Las reglas ' +
'no han cambiado, as\u00ed que las partidas en curso no se ven afectadas.',
'Incluye Station Master v0.7.7: las actualizaciones ahora llegan de verdad a tu navegador. Hasta ' +
'ahora, cada versi\u00f3n empaquetada publicaba sus archivos bajo la misma clave de cach\u00e9, y el ' +
'servidor nunca indicaba a los navegadores cu\u00e1ndo volver a mirar, as\u00ed que quien regresaba segu\u00eda ' +
'ejecutando la versi\u00f3n que su navegador ya ten\u00eda guardada: la pantalla de configuraci\u00f3n del ' +
'solitario de la v0.7.5 y su correcci\u00f3n en la v0.7.6 se instalaron correctamente y nunca se ' +
'vieron. Ahora cada compilaci\u00f3n lleva su propia clave y las p\u00e1ginas se marcan para revalidarse, ' +
'as\u00ed que esta es la \u00faltima actualizaci\u00f3n que tendr\u00e1s que abrir en una ventana privada para ver. ' +
'Las reglas no han cambiado; las partidas en curso no se ven afectadas.',
de_DE:
'Enth\u00e4lt Station Master v0.7.6 \u2014 behebt die in v0.7.5 eingef\u00fchrte Solo-T\u00fcr. Ein Browser, der ' +
'jemals einen Mehrspieler-Platz innehatte, konnte den neuen Solo-Einrichtungsbildschirm ' +
'\u00fcberhaupt nicht erreichen: ein einfacher Seitenaufruf konnte "Solo spielen angeklickt" nicht ' +
'von "mitten im Mehrspieler-Spiel neu geladen" unterscheiden, sodass die T\u00fcr gegen jedes Spiel ' +
'oder jede Lobby verlor, die dieser Browser zuletzt ber\u00fchrt hatte. Die T\u00fcr markiert ihre Absicht ' +
'jetzt ausdr\u00fccklich und erreicht damit immer den Solo-Modus. An den Regeln hat sich nichts ' +
'ge\u00e4ndert, laufende Spiele sind nicht betroffen.',
'Enth\u00e4lt Station Master v0.7.7 \u2014 Aktualisierungen erreichen jetzt tats\u00e4chlich deinen Browser. ' +
'Bisher ver\u00f6ffentlichte jede paketierte Version ihre Dateien unter demselben Cache-Schl\u00fcssel, ' +
'und der Server teilte Browsern nie mit, wann sie erneut nachsehen sollten. Wer zur\u00fcckkam, ' +
'f\u00fchrte also weiter die Version aus, die sein Browser bereits gespeichert hatte: der ' +
'Solo-Einrichtungsbildschirm aus v0.7.5 und dessen Korrektur in v0.7.6 wurden beide korrekt ' +
'installiert und nie gesehen. Jeder Build tr\u00e4gt nun seinen eigenen Schl\u00fcssel, und die Seiten ' +
'sind zur erneuten Pr\u00fcfung markiert \u2014 dies ist also die letzte Aktualisierung, f\u00fcr die du ein ' +
'privates Fenster \u00f6ffnen musst. Keine Regel\u00e4nderungen; laufende Spiele sind nicht betroffen.',
pl_PL:
'Zawiera Station Master v0.7.6 \u2014 naprawia drzwi do gry solo wprowadzone w v0.7.5. Przegl\u0105darka, ' +
'kt\u00f3ra kiedykolwiek zajmowa\u0142a miejsce w grze wieloosobowej, w og\u00f3le nie mog\u0142a dotrze\u0107 do nowego ' +
'ekranu ustawie\u0144 gry solo: zwyk\u0142e wczytanie strony nie odr\u00f3\u017cnia\u0142o "klikni\u0119to Zagraj solo" od ' +
'"prze\u0142adowano w trakcie gry wieloosobowej", wi\u0119c drzwi przegrywa\u0142y z dowoln\u0105 gr\u0105 lub ' +
'poczekalni\u0105, kt\u00f3rej ta przegl\u0105darka ostatnio dotkn\u0119\u0142a. Drzwi teraz jawnie oznaczaj\u0105 sw\u00f3j ' +
'zamiar, wi\u0119c zawsze prowadz\u0105 do gry solo. Zasady si\u0119 nie zmieni\u0142y, wi\u0119c gry w toku nie s\u0105 ' +
'dotkni\u0119te.',
'Zawiera Station Master v0.7.7 \u2014 aktualizacje naprawd\u0119 docieraj\u0105 teraz do twojej przegl\u0105darki. ' +
'Do tej pory ka\u017cde wydanie publikowa\u0142o swoje pliki pod tym samym kluczem pami\u0119ci podr\u0119cznej, a ' +
'serwer nigdy nie m\u00f3wi\u0142 przegl\u0105darkom, kiedy sprawdzi\u0107 ponownie, wi\u0119c powracaj\u0105cy gracz nadal ' +
'uruchamia\u0142 t\u0119 wersj\u0119, kt\u00f3r\u0105 jego przegl\u0105darka ju\u017c zapisa\u0142a: ekran ustawie\u0144 gry solo z v0.7.5 i ' +
'jego poprawka z v0.7.6 zosta\u0142y poprawnie zainstalowane i nigdy nie zosta\u0142y zobaczone. Ka\u017cda ' +
'kompilacja ma teraz w\u0142asny klucz, a strony s\u0105 oznaczone do ponownej weryfikacji \u2014 to wi\u0119c ' +
'ostatnia aktualizacja, kt\u00f3r\u0105 trzeba otworzy\u0107 w oknie prywatnym, \u017ceby j\u0105 zobaczy\u0107. Zasady si\u0119 ' +
'nie zmieni\u0142y; gry w toku nie s\u0105 dotkni\u0119te.',
fr_FR:
'Inclut Station Master v0.7.6 \u2014 corrige la porte solo introduite dans la v0.7.5. Un navigateur ' +
'ayant d\u00e9j\u00e0 occup\u00e9 un si\u00e8ge en multijoueur ne pouvait pas du tout atteindre le nouvel \u00e9cran de ' +
'configuration du solo : un simple chargement de page ne distinguait pas \u00ab a cliqu\u00e9 sur Jouer en ' +
'solo \u00bb de \u00ab a recharg\u00e9 en pleine partie multijoueur \u00bb, si bien que la porte perdait face \u00e0 la ' +
"derni\u00e8re partie ou salle d'attente que ce navigateur avait touch\u00e9e. La porte marque d\u00e9sormais " +
"son intention explicitement, elle atteint donc toujours le solo. Les r\u00e8gles n'ont pas chang\u00e9, " +
'les parties en cours ne sont donc pas affect\u00e9es.',
'Inclut Station Master v0.7.7 \u2014 les mises \u00e0 jour atteignent enfin r\u00e9ellement votre navigateur. ' +
"Jusqu'ici, chaque version empaquet\u00e9e publiait ses fichiers sous la m\u00eame cl\u00e9 de cache, et le " +
'serveur ne disait jamais aux navigateurs quand regarder \u00e0 nouveau : un joueur qui revenait ' +
"continuait donc d'ex\u00e9cuter la version que son navigateur avait d\u00e9j\u00e0 stock\u00e9e. L'\u00e9cran de " +
'configuration du solo de la v0.7.5 et son correctif en v0.7.6 ont tous deux \u00e9t\u00e9 install\u00e9s ' +
'correctement et ne furent jamais vus. Chaque build porte d\u00e9sormais sa propre cl\u00e9 et les pages ' +
'sont marqu\u00e9es \u00e0 revalider : voici donc la derni\u00e8re mise \u00e0 jour que vous devrez ouvrir dans une ' +
"fen\u00eatre priv\u00e9e pour la voir. Aucune r\u00e8gle n'a chang\u00e9 ; les parties en cours ne sont pas " +
'affect\u00e9es.',
},
migrations: {
/**
* STILL NOTHING TO CARRY. v0.7.6 fixes a routing bug in the solitaire door that v0.7.5
* introduced (a browser remembering a multiplayer seat could not reach the setup screen at
* all) — client-side only, no rule the engine enforces and no save-format change. A game in
* progress, on the server or in a browser, resumes exactly as it would have on v0.7.5.
* STILL NOTHING TO CARRY. v0.7.7 fixes how the built client is CACHED, not what it does: every
* packaged build published the same cache key (`?v=nogit` — the `.s9pk` build has no `.git` for
* `git rev-parse`) and the server sent no `Cache-Control` at all, so two correct releases never
* reached the browsers that asked for them. A build tag that varies and a revalidate header are
* both static-file concerns: no rule the engine enforces, no save-format change. A game in
* progress, on the server or in a browser, resumes exactly as it would have on v0.7.6.
*/
up: async ({ effects }) => {},
down: IMPOSSIBLE,