Files
station-master-startos/UPDATING.md
T
JesseandClaude Opus 5 8f2f733a66 0.7.9.8:0 — bundle Station Master v0.7.9.8
Eight releases of fixes since v0.7.9, most of them multiplayer, which is
what this package is for. Submodule pin and `startos/versions/current.ts`
only — no Dockerfile, main.ts or manifest change, as an ordinary bump
should be.

Bumped in place rather than spun off: v0.7.9's migration body is empty,
which is `versions.md`'s common case, and git history keeps its release
notes.

FOUR-COMPONENT VERSION, CHECKED. Every example in `versions.md` has
three, so `0.7.9.8:0` was parsed with the SDK's own ExVer parser before
being written down: upstream `[0,7,9,8]`, which sorts above `[0,7,9]`, so
a box on 0.7.9:0 takes this as an update rather than refusing it as a
downgrade.

GAMES IN PROGRESS ON THE BOX RESUME, and that was established rather than
hoped for. v0.7.9 broke solitaire saves because it changed a RULE, and
the rule behind that is that a save is a seed plus the moves played,
replayed through the CURRENT rules — so the question for any bump is
whether something became illegal. `git diff v0.7.9..HEAD -- src/engine/`
is, in full: `isExpedited` exported and widened to a structural parameter
type, `isFreight` exported, one new read-only helper
(`freightRuleSpentHere`, which only the blocked panel asks), and
`check('draw.end')`'s inline hand-limit test replaced by a call to
`overHandLimit(state, player)` holding the identical expression. No
predicate changed its answer. The release notes say so in all five
locales rather than leaving it to be discovered.

UPDATING.md CORRECTED: it said a running server's saves "are stamped with
`engineVersion` and refuse to resume under a mismatched one". They are
stamped with it and it is reported, but `src/server/index.ts` decides by
attempting the replay and names the versions only inside the failure
message — its own comment says why, that "some version differs" was never
enough to act on. A doc that sends the next person to schedule downtime
for a bump that needs none costs about as much as the reverse. It now
carries the diff command to ask the question of the code instead.

What players get, briefly: two multiplayer information leaks closed (the
seed in the shared log, and a blind Home Office draw naming its card); a
history panel that came back EMPTY after a mid-game browser reload; the
extended-play vote no longer naming an arbitrary player when the vote is
open to everyone at once; a train held at your Limits by an Interlocking
no longer vanishing off the board until a track frees; trains queued for
a Crew Tray saying so with the free count; a Red Flag drawn on the map; a
spent Telegraph/Telephone/Radio struck through; the Campaign Train saying
whether its speeches are made; and two bugs from the last playtest — the
Express's one-freight-car-per-location rule explained where it refuses
you, and westbound trains drawn in the correct half of a card.

README.md and instructions.md updated in the same change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y5boPxP6JHRYMm8adXaF5R
2026-09-08 03:56:40 -04:00

111 lines
5.5 KiB
Markdown

# Updating the upstream version
Station Master is built from a git submodule at `station-master/` (tracking
[`Jesse.Markowitz/station-master`](https://draco.local:53871/Jesse.Markowitz/station-master), a
self-hosted Gitea repo — this is Jesse's own game, not a third-party upstream, but it is packaged
the same way: `Dockerfile` builds whatever commit the submodule points at, with no pinned
`dockerTag` in the manifest. The submodule pin **is** the version.
Station Master tags its releases (`v0.5.1`, …) at the commit that bumped `package.json`. Nothing
else about this package should need to change for a bump — not the `Dockerfile`, not `main.ts`,
not the manifest — only the submodule pin and this package's own version (below).
## Determining the upstream version
```bash
cd station-master && git fetch --tags && git tag -l --sort=-v:refname | head -5
```
The current pin is the submodule's checked-out commit:
```bash
git submodule status station-master
```
## Applying the bump
```bash
cd station-master && git fetch --tags && git checkout v<new version>
cd .. && git add station-master
```
Then set this package's version in `startos/versions/current.ts` to **the same number**, as
`<tag>:0` — `versions.md`'s consistency checklist requires the upstream half to match the
submodule tag exactly, so v0.5.3 becomes `0.5.3:0`. Give it release notes naming what changed for
a player, then rebuild (`make`). Raise the `:0` instead, leaving the upstream half alone, when the
change is packaging-only and the bundled game has not moved.
> The initial release shipped as `1.0.0:0` — the scaffold's placeholder, left in by mistake while
> the game was at 0.5.1. It was corrected to `0.5.2:0` before the package was ever published
> anywhere, which is the only reason a downgrade was harmless: `0.5.2:0` sorts _below_ `1.0.0:0`,
> so an installed copy had to be removed rather than updated over.
## Building a test package from work that is not pushed yet
The Dockerfile copies `station-master/` out of the build context, so what is packed is whatever is
in that directory — the submodule's _pin_ only matters for reproducibility, not for `make`. That is
what makes it possible to put a build on a test box before the game is committed, tagged or pushed,
which is how v0.7.0 was played before release:
```bash
# point the submodule at a local commit that exists nowhere else yet
cd station-master && git fetch --no-tags /path/to/station-master main && git checkout --detach FETCH_HEAD
# or, for work that is not even committed, copy the working tree in
rsync -a --delete --exclude .git --exclude node_modules --exclude dist \
/path/to/station-master/ station-master/
cd .. && make x86 && make install
```
**Move the DOWNSTREAM digit for each test build** — `0.7.0:1`, `:2`, `:3`. StartOS installs an
update, not a re-install, so a rebuild at the same version has nothing to install over; and the
downstream half is exactly the right one to move, since the upstream game has not been released
again between two test packs. Whichever digit the box ends up on is the one the real release should
carry: publishing a _lower_ one afterwards is a downgrade the box will refuse.
**Before committing the wrapper**, put the pin back on a real tag — a submodule pointing at a commit
that only exists on one machine is a package nobody else can build:
```bash
cd station-master && git fetch --tags origin && git checkout v<version>
cd .. && git add station-master
```
The pack's git stamp says `-modified` for the whole of this, which is the flag that a build came
from a dirty tree. Never publish one of those.
---
## Will the games already on the box survive the bump?
**`engineVersion` is NOT a gate, and this section used to say it was.** It claimed a running server's
saves "are stamped with `engineVersion` and refuse to resume under a mismatched one". They are
stamped with it, and it is *reported* — but `src/server/index.ts` decides by attempting the replay,
and names the stored and running versions only inside the failure message. Its own comment says why:
"some version differs" was never enough to act on. A game is refused because a move no longer
replays, never because a string changed.
**So the real question is whether anything became ILLEGAL.** A save is a seed plus the moves played,
replayed through the *current* rules, so a change that makes a once-legal move illegal truncates an
older save; everything else — new fields, renderer work, exports, refactors — cannot. Ask it directly
of the code rather than of the changelog:
```bash
cd station-master
git diff v<old>..v<new> -- src/engine/ | grep -E '^[+-]' | grep -vE '^[+-]{3}' \
| grep -vE '^[+-]\s*(\*|//|/\*)' | grep -vE '^[+-]\s*$'
```
Read every surviving line. For v0.7.9 → v0.7.9.8 that was four things — two exports, one new
read-only helper, and one inline expression moved into a shared function — so no predicate changed
its answer and every game resumed. **If a predicate in `apply.ts`, `legal.ts` or `advance.ts` did
change, say so in the release notes in all five locales**, the way v0.7.9 did: an in-progress game
must then finish, or be accepted as lost, before the bump.
Multiplayer saves live on the SERVER, which is the half this package can actually strand — a
solitaire save lives in the player's own browser, where nothing here can reach it either way.
The `Frame` sent to a browser is not part of this question. It gains and loses fields freely; a
browser reloads onto the new client as part of the update, so there is no version skew to migrate.