diff --git a/CHANGELOG.md b/CHANGELOG.md index 14b3ea9..12bce55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,91 @@ page as `v0.1.0 · · `, so what is deployed can always be identifie --- +## 0.8.0.16 — 2026-09-20 + +The Quickstart put where a tester can actually reach it, the last place that still told the old +story about the Interchange, and the release that carries v0.8.0.15's corrected card text into a +package. + +### The Quickstart is published beside the game + +v0.8.0.15 wrote a Quickstart for a tester who has never played, and then left it in `docs/`, where +a tester does not look — reachable only by someone who already has the repository. Nobody being +handed the box has it. + +`build-web.ts` now copies `docs/StationMaster-Quickstart.md` into `dist/quickstart.md`, and the +splash page offers it under the three doors: *New to Station Master? Read the Quickstart guide.* +**Not a fourth door** — reading the guide is not a way to play, and giving it equal weight in that +grid would say it is. + +**Copied, never re-written.** The Markdown document stays the one copy. A hand-written HTML twin +would drift from it on the first edit, which is exactly the failure #15a was raised about and +exactly what the v0.8.0.15 pass spent its time undoing: four references a month and two minor +versions out of date. + +**Served as plain text, which is honest rather than good.** Tables render as rows of pipes and the +links do not click. Rendering it into a styled page wants a small Markdown converter and is filed +as **TODO #109**; this is the fifteen-minute version that gets the guide in front of testers for +this round instead of leaving them without one. + +Two things had to be true and neither is checked by `tsc`, so both are tests: + +- **The link has to find the file.** The href on the splash page and the filename the build writes + are two strings with nothing connecting them — rename the document and the build quietly + publishes nothing while the page keeps offering a link that 404s. The test asserts the guide is + in `dist`, is the guide, and is the file the splash page names. The build also warns loudly + rather than silently skipping a missing document. +- **A `.md` file must not arrive as a download.** The server's MIME fallback is + `application/octet-stream`, which a browser saves instead of displaying, so the link would hand a + tester a file rather than a page. `'.md': 'text/plain; charset=utf-8'` was added to the table in + `http.ts`, and the test reads that table out of the source rather than asserting on a copy of it, + which would pass while the real one was wrong. + +### `sortsCars` says what it gates, not what the card prints + +Asked directly after v0.8.0.15 — does everything now agree? — and the audit turned up one place that +did not. The field's own doc comment read: + +```ts +/** Interchange: "Sort cars in new order". */ +sortsCars: boolean; +``` + +which names the printed text as though it were the flag's meaning. Nothing reads it to permit a +sort. Its two readers — `resolveExtraStart` in `apply.ts` and the enumeration in `legal.ts` — both +ask the same question, which is whether this is the one Mainline card with a Yard Limit and +therefore the one an Extra may be made up and started on. + +**Comment only, and worth the bump because of where it is.** This is what a developer reads before +using the flag, and it is the most likely source of the sentence v0.8.0.15 had to correct — the one +telling players, on the board, that cars could be sorted at an Interchange. The name is kept for its +link to the card face, and the comment now says outright that the name is not the meaning. + +Everything else already agreed, and was checked rather than assumed: `mainlineDescription`, the +generated `rules/as-built.md`, the Mainline deck reference and the Rules FAQ all say the printed +sorting is unimplemented and that a consist is re-ordered at a Small Yard. `rules/implications.md` +is the deliberate exception and was already correct — it transcribes what the card face prints and +then records that the concept is "still unimplemented". + +### The reference stamps, and what was filed rather than done + +The five documents v0.8.0.15 stamped — the Quickstart, the Rules, Components, the Home deck and the +Mainline deck — plus `docs/design.md` now read **v0.8.0.16**, and the Rules book's implementation +note about `card.discard` says the same. They describe this build because the audit above re-checked +them against it, not because the number was swept forward: the point of the stamp is that it was +earned, and a stamp bumped without a reading is worth less than none. + +**TODO #109** holds the part deliberately not done — rendering the guide into a styled page instead +of serving it as plain text. `build-web.ts`'s comment names that number rather than gesturing at +"the next step", so the file and the worklist cannot drift apart the way the references just did. + +### Why this is a release at all + +One player-visible change, the link to the guide, and one that only a developer reads. The +Interchange correction a player actually sees on the board is v0.8.0.15's; this is the version the +wrapper bundles, so that correction reaches the box rather than only the repository — and a tag +with an uncommitted comment sitting on top of it is not a thing to package. + ## 0.8.0.15 — 2026-09-20 The reference documentation brought up to the game as it actually runs, ahead of the next round of diff --git a/TODO.md b/TODO.md index c1fd656..317a68c 100644 --- a/TODO.md +++ b/TODO.md @@ -582,6 +582,23 @@ What the project says about itself, and what it ships alongside the code. - [ ] **#88** — `card-reference.md`'s industry table may still be stale beyond Grocer's Warehouse and the Oil Refinery. See **Reference · #88**. +- [ ] **#109** — **Render the published Quickstart instead of serving it as plain text.** v0.8.0.16 + publishes `docs/StationMaster-Quickstart.md` to `dist/quickstart.md` and links it from the + splash page, served as `text/plain` — so a tester reads the guide's tables as rows of pipes and + its links do not click. That was the fifteen-minute version, taken deliberately to get the + guide in front of testers for this round rather than to leave them without one. + + **Copy the document, do not re-write it.** A hand-written HTML twin drifts from the Markdown on + the first edit, which is the whole argument of #15a. The step is a small Markdown-to-HTML + converter in `scripts/build-web.ts` writing `quickstart.html` beside the game, styled like the + splash page — headings, lists, tables, links and code spans are the whole of what the guide + uses. The `.md` MIME entry in `src/server/http.ts` and the two assertions in + `test/web.test.ts` (`the Quickstart guide reaches the site`) move to the rendered file with it. + + **Cost:** an afternoon, most of it in the converter's table and list handling. No dependency — + a Markdown library would be the only runtime dependency this project has, and the guide uses a + small enough subset that it is not worth becoming the first. + --- ## Reference — measurements, rulings and rejected approaches diff --git a/docs/StationMaster-Components-v0.4.5.md b/docs/StationMaster-Components-v0.4.5.md index d0f9058..f956d14 100644 --- a/docs/StationMaster-Components-v0.4.5.md +++ b/docs/StationMaster-Components-v0.4.5.md @@ -1,6 +1,6 @@ # Station Master — Components and Markers -**Describes the game as built at v0.8.0.15** (2026-09-20). Previously stamped "v0.4.5", the +**Describes the game as built at v0.8.0.16** (2026-09-20). Previously stamped "v0.4.5", the prototype rules edition these references were first written against; the filename keeps that stamp because `src/`, `CHANGELOG.md` and `docs/rules/` all cite this file by name. diff --git a/docs/StationMaster-Home-Deck-v0.4.5.md b/docs/StationMaster-Home-Deck-v0.4.5.md index b1e053a..9cbc1b8 100644 --- a/docs/StationMaster-Home-Deck-v0.4.5.md +++ b/docs/StationMaster-Home-Deck-v0.4.5.md @@ -1,6 +1,6 @@ # Station Master — Home Deck -**Describes the game as built at v0.8.0.15** (2026-09-20). Previously stamped "v0.4.5", the +**Describes the game as built at v0.8.0.16** (2026-09-20). Previously stamped "v0.4.5", the prototype rules edition these references were first written against; the filename keeps that stamp because `src/`, `CHANGELOG.md` and `docs/rules/` all cite this file by name. diff --git a/docs/StationMaster-Mainline-Deck-v0.4.5.md b/docs/StationMaster-Mainline-Deck-v0.4.5.md index 0d870a4..c889913 100644 --- a/docs/StationMaster-Mainline-Deck-v0.4.5.md +++ b/docs/StationMaster-Mainline-Deck-v0.4.5.md @@ -1,6 +1,6 @@ # Station Master — Mainline Deck -**Describes the game as built at v0.8.0.15** (2026-09-20). Previously stamped "v0.4.5", the +**Describes the game as built at v0.8.0.16** (2026-09-20). Previously stamped "v0.4.5", the prototype rules edition these references were first written against; the filename keeps that stamp because `src/`, `CHANGELOG.md` and `docs/rules/` all cite this file by name. diff --git a/docs/StationMaster-Quickstart.md b/docs/StationMaster-Quickstart.md index 05c9333..a22b3bb 100644 --- a/docs/StationMaster-Quickstart.md +++ b/docs/StationMaster-Quickstart.md @@ -1,6 +1,6 @@ # Station Master — Quickstart -**For a tester who has never played. Describes the game as built at v0.8.0.15** (2026-09-20). +**For a tester who has never played. Describes the game as built at v0.8.0.16** (2026-09-20). Read this once before you sit down. It is about twenty minutes of reading and will save you an hour of confusion. The deeper references are listed at the end. diff --git a/docs/StationMaster-Rules-v0.4.5.md b/docs/StationMaster-Rules-v0.4.5.md index 7273df6..b5a49da 100644 --- a/docs/StationMaster-Rules-v0.4.5.md +++ b/docs/StationMaster-Rules-v0.4.5.md @@ -1,6 +1,6 @@ # Station Master — Rules -**Describes the game as built at v0.8.0.15** (2026-09-20). Previously stamped "v0.4.5", the +**Describes the game as built at v0.8.0.16** (2026-09-20). Previously stamped "v0.4.5", the prototype rules edition this reference was first written against; the filename keeps that stamp because `src/`, `CHANGELOG.md` and `docs/rules/` all cite this file by name. @@ -206,7 +206,7 @@ roll a tail cut into a connected Freight Facility. **Freight Agent.** Make one of these operations, then the turn ends: stock one green outbound box from a matching loaded Division Yard car; clear one red inbound box to the Classification Yard; unjam one outbound, inbound, or MEN | AT | WORK load to the Classification Yard; or explicitly end without acting. Freight can be stocked only when an unclaimed empty matching car is already spotted at that industry. Passengers may wait in a green Office box without a train present. -Implementation note, still true at v0.8.0.15: `card.discard` is accepted during Local Operations +Implementation note, still true at v0.8.0.16: `card.discard` is accepted during Local Operations without checking that the Draw option was chosen — unlike `card.play`, which does check. This is an implementation quirk rather than a fourth published turn option. diff --git a/docs/design.md b/docs/design.md index 478c66a..323bb9c 100644 --- a/docs/design.md +++ b/docs/design.md @@ -66,7 +66,7 @@ must do. ## Current status -**v0.8.0.15.** Rules formalized, card faces specified, architecture documented, and the game +**v0.8.0.16.** Rules formalized, card faces specified, architecture documented, and the game playable **solitaire and multiplayer** in a browser against an authoritative server. See [`../CHANGELOG.md`](../CHANGELOG.md) for what each version changed and [`../TODO.md`](../TODO.md) for what is open; this section is the shape of the project, not a running tally, because a diff --git a/package.json b/package.json index afafb5c..ec958fa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "station-master", - "version": "0.8.0.15", + "version": "0.8.0.16", "private": true, "type": "module", "description": "Station Master — a railroad operations game", diff --git a/scripts/build-web.ts b/scripts/build-web.ts index 672caef..d7d1a1f 100644 --- a/scripts/build-web.ts +++ b/scripts/build-web.ts @@ -188,6 +188,27 @@ if (existsSync(imageSrc)) { for (const f of readdirSync(imageSrc)) copyFileSync(join(imageSrc, f), join(imageOut, f)); } +/** + * The Quickstart, published beside the game so a tester can reach it from the box. + * + * COPIED, NOT RE-WRITTEN. `docs/StationMaster-Quickstart.md` is the one copy; a hand-written HTML + * twin would drift from it on the first edit, which is the whole lesson of TODO #15a and of the + * 2026-09-20 documentation pass that found four references a month out of date. + * + * SERVED AS PLAIN TEXT for now, which is honest rather than good: tables render as pipes and the + * links do not click. Rendering it into a styled page needs a small Markdown converter and is + * filed as TODO #109 — this is the fifteen-minute version that gets the guide in front of testers + * for this round rather than leaving them without one. + */ +const guideSrc = join(root, 'docs/StationMaster-Quickstart.md'); +if (existsSync(guideSrc)) { + copyFileSync(guideSrc, join(dist, 'quickstart.md')); +} else { + // Loud rather than silent: a missing guide is a broken link on the splash page, and the build is + // the only place that can still notice. + console.error('WARNING: docs/StationMaster-Quickstart.md is missing — the splash link will 404'); +} + // A tiny note for whoever unzips this later and wonders what it needs. writeFileSync( join(dist, 'README.txt'), diff --git a/src/engine/content.ts b/src/engine/content.ts index e4f28e3..20ac9a9 100644 --- a/src/engine/content.ts +++ b/src/engine/content.ts @@ -589,7 +589,20 @@ export type MainlineProfile = { speedStarts?: { fast: number; slow: number }; /** Double Track: "Trains may pass". */ trainsMayPass: boolean; - /** Interchange: "Sort cars in new order". */ + /** + * Interchange only. The card prints "Sort cars in new order" — **and that is not what this flag + * does**, which is why it is worth spelling out where the field is declared. + * + * The printed sorting has never been implemented: nothing reads this to permit a sort, and a + * consist is re-ordered at a Small Yard in a district (`switch.sortConsist`). What this actually + * marks is the one Mainline card with a Yard Limit, and therefore the one an Extra may be made up + * and started on (`apply.ts` § resolveExtraStart, `legal.ts`). + * + * Named for the printed text, and kept that way deliberately — renaming it would lose the link to + * the card face — but the name has already misled once: `mainlineDescription` grew a sentence + * telling players cars could be sorted here, which reached the board and the generated card + * reference before it was caught on 2026-09-20. + */ sortsCars: boolean; /** Named entry points printed on the card; some are unlocked by modifier cards. */ entryPoints: readonly string[]; diff --git a/src/server/http.ts b/src/server/http.ts index 895a10c..3751929 100644 --- a/src/server/http.ts +++ b/src/server/http.ts @@ -85,6 +85,14 @@ const MIME: Record = { '.json': 'application/json; charset=utf-8', '.png': 'image/png', '.svg': 'image/svg+xml', + /** + * The Quickstart guide, published by `build-web.ts` as `quickstart.md`. + * + * text/plain ON PURPOSE. The fallback below is `application/octet-stream`, which makes a browser + * DOWNLOAD the file instead of showing it — so without this line the splash page's "read the + * guide" link hands a tester a file to save rather than a page to read. + */ + '.md': 'text/plain; charset=utf-8', }; const HEARTBEAT_MS = 20_000; diff --git a/src/web/index.html b/src/web/index.html index 78fc3a7..122644b 100644 --- a/src/web/index.html +++ b/src/web/index.html @@ -27,6 +27,11 @@ h1{font-size:32px;margin:0 0 2px;letter-spacing:.02em} a.door:hover{border-color:#4d6fa8;background:#1f2733;transform:translateY(-1px)} .door h2{font-size:17px;margin:0 0 5px;color:#9fb6d8} .door p{margin:0;color:var(--dim);font-size:13px;line-height:1.5} +/* Not a fourth door: reading the guide is not a way to play, and giving it equal weight in the + grid would say it is. A line under the doors, where somebody who does not know what to click + will already be looking. */ +.newhere{margin:16px 2px 0;color:var(--dim);font-size:13px;line-height:1.55} +.newhere a{color:#9fb6d8} .door .go{display:inline-block;margin-top:11px;font-size:12px;color:#5aa9e6} .door.disabled .go{color:var(--dim)} a.door.disabled{pointer-events:none} @@ -96,6 +101,11 @@ footer{margin-top:26px;color:var(--dim);font-size:11px;display:flex;gap:18px;fle +

New to Station Master? + Read the Quickstart guide — what the game is, how you win, + how a Stage runs, what is on the screen, and a first twenty minutes. About twenty minutes to + read, and it will save you an hour of guessing.

+