Commit Graph
10 Commits
Author SHA1 Message Date
JesseandClaude Sonnet 5 3fc56de203 0.7.5:0 — bundle Station Master v0.7.5
Submodule pinned to v0.7.5 (3e96149). current.ts bumped in place at
0.7.5:0 — no new version file, no migration: the change is a client-side
flow change (solitaire asks for its options before dealing, the same
question the multiplayer lobby already asks) that touches no rule the
server enforces and no save format, so every game in progress carries
over without exception.

Verified: npm run check clean, prettier clean, make x86 packs as
v0.7.5:0, installed on phoenix.local — logs show the empty migration
running and both games in progress (WHISTLE-4086, COAL-7370) resuming
with their same intent counts, and the served play.html confirmed to
contain the new #solitairesetup screen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AdG46Ja2PEDBkpqiDazMoX
2026-08-29 19:27:35 -04:00
JesseandClaude Opus 5 085b88bb38 0.7.4:0 — bundle Station Master v0.7.4
Submodule pinned to v0.7.4 (19a6a47), `current.ts` at `0.7.4:0`, release notes
rewritten in all five locales, README.md and instructions.md updated. No new version
file and no migration: the outgoing 0.7.3:0's `up` is empty, `versions.md`'s common
case, so `current.ts` bumps in place.

Three rules corrections, all places where the code and the cards disagreed. The Yard
Office is offered rather than imposed, must be reachable in one move, and cars on the
lead collide — none of which it checked. Circus, Campaign and Military trains run
loaded where the yard can supply it, and the per-stop point is earned once per Office
Area by a fully loaded train. Red Flags becomes a directional flag on your own Limits,
spent on the train it stops, playable at the moment the engine sees a certain
collision.

GAMES IN PROGRESS MAY NOT SURVIVE THIS ONE, and the notes lead with it in every locale
— the opposite of 0.7.3 and for a different reason from 0.7.2. Nothing about the save
format changed; what changed is what the rules accept. The Red Flags intent changed
shape, a make-up that was legal may now be refused, and a Yard Office arrival asks a
question no older history has an answer for. It fails safe: the server declines a save
the rules reject, names the move, and leaves the file untouched. A game that never
meets one of the three carries on, which is why this is "may not" rather than 0.7.2's
"will not".

README.md's diagnosing note is extended: the Mainline Phase now stops to ask three
different questions of three different players, and a game sitting on one is waiting
on a person rather than stuck — it shows as active with nobody to wait for, because an
interruption is not a turn.

Verified: `npm run check` clean, prettier clean, `make x86` packs as v0.7.4:0.
NOT verified: not yet installed on a box, and none of the three rules has been played
by a human — upstream TODO.md #35 still stands for extended play too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EAgJSmeV8zrMh55Mj85ESb
2026-08-29 08:20:30 -04:00
JesseandClaude Opus 5 74aea24d74 0.7.3:0 — bundle Station Master v0.7.3
Submodule pinned to v0.7.3 (45580d8), `current.ts` at `0.7.3:0`, release notes
rewritten in all five locales, README.md and instructions.md updated. No new
version file and no migration: the outgoing 0.7.2:0's `up` is empty, which is
`versions.md`'s common case, so `current.ts` bumps in place and `index.ts` is
untouched.

Two features, both about the end of a game. A game no longer stops dead when the
timetable runs out — it enters a fourth state, `awaitingExtension`, and asks the
table whether to play one more Day, unanimously in multiplayer with one refusal
decisive. The official result is frozen at the original `config.days` and never
rewritten, so playing on is explicitly an exhibition, and a §3.4 collision breach
is neither extendable nor able to overwrite a recorded result. And the end of a
game renders a full results screen in place of the raw `outcome.reason` enum the
page used to print.

GAMES IN PROGRESS SURVIVE THIS ONE, which is the opposite of the last release and
is why the notes lead with it in every locale. No card data changed and the engine
changes are additive, so every intent in a 0.7.2 save is still legal: the save
replays intact and the game simply pauses on the new question at the end. Upstream
proves it rather than asserting it — the suite replays the three recorded games in
`public/replays`, all made under an older ruleset, and asserts every intent still
applies. Anyone updating from 0.7.1 or earlier is still in the old boat, and both
docs say so.

README.md gains a short diagnosing note, since `awaitingExtension` is a state an
administrator can meet and misread: such a game is persisted and listed as
`active`, resumes on restart like any live game, and shows nobody to wait for —
because a vote is not a turn.

Verified: `npm run check` clean, prettier clean, `make x86` packs as v0.7.3:0.
NOT verified: not installed on a box and not played. Extended play has never been
exercised against a running service — upstream `TODO.md` #35.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EAgJSmeV8zrMh55Mj85ESb
2026-08-29 05:07:03 -04:00
Jesse 1bfea8d49f 0.7.2:0 — bundle Station Master v0.7.2
Two engine bugs and two rules corrections, plus the Division map redrawn. The submodule pin moves to
v0.7.2 and the version follows it; the downstream digit resets to :0.

- Backing into a cut through a curve's 45° leg no longer couples it back to front, and a crew pulling
  out through one takes its own cut with it instead of leaving it standing.
- The card deck is the published counts exactly, which halves the track and drops two long-standing
  density multipliers — 206 cards to 121.
- Crossing a Mainline card counts the regions printed on it rather than the printed speed, which was
  only ever scenery. Most trains cross faster, slow trains much faster, and Fast/Slow now matters on
  the Hilly card alone.
- The Division map is one row read left to right, so east is always to the right.

GAMES IN PROGRESS DO NOT SURVIVE THIS UPDATE, and this is the first release of which that is true. A
save is a seed plus the moves played, and the deck changing size means a card id recorded under 0.7.1
refers to a different card or to none — so a save stops replaying at its first card.play. There is no
migration because there is no data to move: those moves were made against a deck that no longer
exists, and re-dealing would invent a game nobody played.

It fails safe. The server refuses to resume a save the rules reject, logs which move it stopped at,
and leaves the file untouched, so an operator can put 0.7.1 back on to finish a game that matters.
The release notes lead with this, in all five locales.

Packed and verified as v0.7.2:0 on x86_64.
2026-08-26 15:32:26 -04:00
JesseandClaude Opus 5 ea8e9dbcb8 0.7.1:0 — bundle Station Master v0.7.1
Four playtest fixes off the Gitea tracker. The submodule pin moves to v0.7.1 and the version follows
it; the downstream digit resets to :0, since v0.7.0 only ended on :3 because three test packs were
played before it was released.

- An empties-only train may couple a caboose again — a caboose carries the crew, not freight.
- The end of a Day is a modal carrying the standings, the Days left and the combined target, instead
  of passing between one click and the next inside the automatic phases.
- A Timetabled train may be discarded to a Department pile for a rival to pick up, governed by a new
  discardTimetabled setting that appears in both the New Game dialog and the lobby, on by default. An
  Extra never may.
- A blocked passenger platform now gives its reason, including the coach shortage and what ends it.

No new version file and no migration: current.ts's migrations.up is empty and nothing is carried from
0.7.0. GAMES IN PROGRESS SURVIVE THIS UPDATE — all three engine-visible changes only widen what is
legal, so every intent a 0.7.0 game recorded still replays, and the server resumes a save by replaying
it rather than by comparing version strings (src/server/index.ts in the game repo).

README.md and instructions.md both named 0.7.0 and carry the three user-visible changes now.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FLnYR4XtXQNamYJXGYT8oC
2026-08-25 10:58:14 -04:00
JesseandClaude Opus 5 d26d44d9e2 0.7.0:3 — bundle Station Master v0.7.0
The submodule pin is the version; nothing else about the package changed. Four game types in the
lobby, the whole rule set readable before taking a seat, leaving and rejoining a game, and sound in
a multiplayer game for the first time — all upstream, all through the same server this package has
always run.

- startos/versions/current.ts — 0.7.0:3, with release notes in all five languages.
- instructions.md — how a game is set up now, and what Leave / Forget mean for a seat.
- README.md — the bundled version, and a limitation spelled out: a player's identity lives in their
  browser, so a lost token cannot be recovered from this package.
- UPDATING.md — how to pack a test build from work that is not pushed yet, which is how v0.7.0 was
  played before release, and why the downstream digit moves for each one.

The downstream digit is :3 rather than :0 because three test packs were installed on the box while
v0.7.0 was being played; publishing :0 now would be a downgrade it would refuse.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016JczK5i33ZNSf2PtzZqdhS
2026-08-23 05:50:38 -04:00
Jesse e84c640067 Bundle Station Master v0.6.0: updates stop destroying games in progress
Pin moves to v0.6.0, package version to 0.6.0:0.

README and instructions.md both promised the opposite of what now happens
and had to be rewritten: an update keeps games in progress unless the rules
actually changed, and a game that genuinely cannot replay is named in the
log rather than described as a version mismatch.

Verified on phoenix.local by doing the thing the release is about. A game
(MAIL-4571) was created on the installed 0.5.6:0, then this build was
installed over it. All four saved games on the volume came back:

  Resuming 4 saved game(s)…
  Resumed HOPPER-4607  — 37 intents replayed.   (written under 0.5.2)
  Resumed TRESTLE-5109 —  5 intents replayed.   (written under 0.5.3)
  Resumed TENDER-8092  — 38 intents replayed.   (written under 0.5.5)
  Resumed MAIL-4571    —  0 intents replayed.   (written under 0.5.6)

The first three had been refused on every boot since the release that
stranded them. They were never damaged, only unreachable, and replaying
them is all it took to get them back — which is the clearest evidence that
the version comparison was answering the wrong question. All four now show
in Games in Progress with the correct Day, Stage and waiting-on player.
2026-08-21 21:56:58 -04:00
Jesse c95620d566 Bundle Station Master v0.5.3: games in progress, and a way to end one
Pin moves to v0.5.3, package version to 0.5.3:0.

The health check no longer just probes a port. It fetches the server's own
/api/health and reports what it says — "Multiplayer server is ready — 3
games in progress", with ", 1 waiting to start" appended only when a lobby
exists and "no games in progress" on an idle server. A server that doesn't
answer is reported as STARTING, never failed: the server replays its saved
games before binding its port, so a boot legitimately looks like nothing is
listening, and calling that a failure makes an ordinary restart look like a
crash.

Two new actions, both only-running. Games in Progress is read-only and
lists every game and lobby with players, Day/Stage/phase, who it waits on,
when it started and when it last moved. Manage Game picks one from a
dropdown built live from the server and either exports it or ends it —
ending being the only way a game finishes other than being played out,
since an abandoned game otherwise stays active and is resumed on every
restart forever. Ending always returns the deleted game's save, so nothing
is destroyed without being handed back first.

They are only-running because none of it is readable from disk: a save is a
seed plus a list of moves, so whose-turn-it-is exists only after a replay
through the engine, which lives in the game repo rather than here. The
running server has already done that work and is asked for the answer.
startos/serverApi.ts is the single place that asks.

store.json gained adminSecret (32 chars) beside joinSecret, seeded on
install and backfilled on update for a volume written before the field
existed. It is deliberately NOT the join secret: every player holds that
one, so gating a delete with it would let anyone at the table destroy
anyone else's game. init/generateJoinSecret.ts is renamed generateSecrets.ts
now that it mints both.

Also brought getJoinSecret's result strings under i18n(). They shipped as
plain strings two commits ago, which actions.md is explicit about — every
user-facing string including result titles, messages and thrown errors.
The new actions follow it, so the old one shouldn't be the odd one out.

Verified on phoenix.local, installed as an UPDATE from 0.5.2:0 rather than
a fresh install, which exercised three things at once: the boot log line
("Resuming 1 saved game(s)…"), the engine-version refusal firing for real
on a game recorded under 0.5.2, and the adminSecret backfill (store.json
came out with both secrets, 24 and 32 chars). Then, from inside the
container: the package-generated admin secret authenticating against
/api/games (200) while a wrong one is refused (403), health counts tracking
0 -> lobby 1 -> active 1 through a create/bot/start, and every field the
actions render present and correct on the listing.

NOT verified: the actions' own forms and result rendering. `start-cli
package action run` fails with a client-side deserialization error on every
action on this box — including the already-shipped get-join-secret and
actual-budget's equivalent — so it is a start-cli problem, not this
package's. The data path underneath them is verified above; the SDK
form/result rendering needs the web UI.

A test game (TRESTLE-3221, Alice + a bot) is left running on the box so
there is something for Games in Progress to show.
2026-08-21 16:00:05 -04:00
Jesse ea012f1329 Bundle Station Master v0.5.2, and fix the package version scheme
Submodule pin moves to v0.5.2, which carries the working splash-page
multiplayer door and the GET /api/health probe behind it.

The interface goes back to serving `/` — the splash, which is the front
door to all three ways to play. It pointed at /play.html only because the
splash's multiplayer door was hardcoded to "Coming soon", making the front
page a dead end on a real server; v0.5.2 removes the reason for the
workaround. The splash now probes /api/health on load, so served from here
it opens the lobby and served as a plain static site it says plainly that
it needs a server.

The package version was wrong and is corrected: 1.0.0:0 -> 0.5.2:0. That
1.0.0 was the scaffold's placeholder, left in by mistake — versions.md's
consistency checklist requires the upstream half to match the bundled tag,
which is what makes "bump the pin, bump the version" one mechanical action
rather than a judgement call. No historical version file is needed: the
placeholder carried no migration and was never published anywhere.

The correction is a downgrade in ExVer terms, so StartOS refused to install
over the existing copy ("uninit target range `!` is unsatisfiable"). The
installed package was therefore removed and reinstalled — checked first
that the volume held only an auto-generated join secret and no games. Two
consequences, both one-time and both recorded in UPDATING.md: the join
secret is regenerated, and the host's public domain binding was dropped
with the uninstall and has to be re-added.

Verified on phoenix.local: builds as v0.5.2:0, installs, starts, and serves
/api/health 200 with the right body; the splash carries all three doors
including a live ./play.html?lobby, no "Coming soon" anywhere, all three
ids the probe addresses present, and #lobby rendering on play.html?lobby.
2026-08-21 11:13:40 -04:00
Jesse de28b30eea Initial StartOS package for Station Master (v0.5.1)
Built from source via a git submodule pinned to a tag, not a published image
— the Dockerfile, main.ts, and manifest should never need to change for an
ordinary version bump, only the submodule pin (see UPDATING.md). One volume,
one interface serving the browser client + lobby/intent API + SSE stream
from a single origin, no dependencies. The server-wide join secret (D14) is
seeded on install, exposed via the Get Join Secret action, and blocks start
behind a critical task until retrieved — the same first-set/rotation pattern
as actual-budget-startos's admin password.

Verified on phoenix.local: installs, the critical task correctly blocks an
ordinary start, force-starting confirms the daemon binds its port and serves
the client, and store.json correctly holds the install-seeded join secret.
Not verified: the Get Join Secret action's execution end-to-end — start-cli's
`package action run` fails with a client-side deserialization error that
reproduces identically against actual-budget's already-shipped equivalent
action, so this looks like a start-cli issue rather than a defect here.

icon.svg is still the scaffold's hello-world placeholder — no real Station
Master icon exists yet to ship in its place.
2026-08-21 08:44:07 -04:00