diff --git a/README.md b/README.md index cdbd0d4..7b2d953 100644 --- a/README.md +++ b/README.md @@ -13,278 +13,31 @@ 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.8.2.** A playtest read back against its own save file. **The change a player -notices first: every district now opens on a DEPOT rather than a Whistle Post** — two A/D tracks and -passengers working from Stage 1, where a Whistle Post has one track and is not a Passenger Facility -at all. "Players start with Whistle Posts, not Depots" is offered at game creation for a table that -wants the harder game, and the deck follows the choice: starting on Depots, the four Depot upgrade -cards are left out, since an upgrade must be to the next tier. +**Bundled version: 0.8.6.** Four releases from a code audit of the game — engine, server, browser +client, tests — with every finding verified against the code before it was acted on. -**Three bugs, all reported from one game and all confirmed against its save.** An Office held two -trains on one A/D track — the train an Interlocking had been holding at the Limits took the free -slot and the arriving train was pushed in after it without anyone asking again, so the collision -§8.3 calls for never happened. A seat's history froze permanently part-way through a game, because -each seat's "what have I sent you" bookmark was an index into a log the game trims. And §8.1 asked -the wrong question twice: "trains may pass" short-circuited the whole Subdivision, and a train -standing at an Office was invisible to the scan although it was about to re-enter. +**The one that matters to this server first: 0.8.2 stranded every game on it, and said it stranded +ten.** The server's own boot log refused all thirteen saves at move 3. The Second Section card had +gone into the deck after 0.8.2's save check had been run, and a deck one card larger shuffles into a +different order from the same seed. 0.8.3 deals a save that predates the card from the deck it was +dealt from, and the thirteen replay exactly as 0.8.2's notes promised: three resume, ten refuse, the +same ten at the same moves. Nothing refused under 0.8.2 for a rule is un-refused here. -**GAMES IN PROGRESS: most will not resume**, and it was measured before release rather than -discovered after. Of the thirteen saves on the test server, three resume and ten refuse; six of -those ten are the new rule that a passenger Modifier may not be played at a Whistle Post. A refused -save stops at a named move and is left untouched, so a game worth finishing can be finished by -putting the previous version back. The Depot change itself strands nothing. +**The engine (0.8.3):** a player could switch a rival's train and the rival paid the Moves; a rival's +crew blocked your own track; drawing the last card off a Department could duplicate it and destroy +the refill; the unjam cleared the first load rather than the one named; the collision limit could not +fire in Stage 12; an Expedite fault was charged once per clearance question; a train held at the +Limits was only ever released by another arrival, never by a departure. -**The documentation is a set of rendered pages now**, served by this package and linked from inside -the game, rather than five Markdown files served as plain text. `instructions.md` is a manual again: -the twenty "What changed in …" blocks it had accumulated — 380 of its 469 lines — are gone, because -what changed in a release is what `releaseNotes` is for. +**The transport (0.8.4):** a player who left a lobby kept a token that could stream and move for +whoever took the seat next; the first move after a page reload could be silently swallowed; two moves +at once could tear the save file, and a torn save took every game on the server down at boot; an +error after a stream had started crashed the process; request bodies were unbounded; a double-click +did the thing twice. `http.ts` has an end-to-end test suite on a real port now. -**Previously, 0.8.1.0.** A table pass over 0.8.0.17, and a second-digit bump taken -deliberately — 0.8.1 had been reserved for the seatless display table, which is getting more -thought. **The one that changes state:** the Freight Agent's "clear the red Inbound box" returned -the car to the Classification Yard still marked loaded, carrying a load already delivered and -already paid for. `pooled()` strips a load's `origin` stamp and keeps `loaded` on purpose (a train -can retire with freight aboard), so the call site's comment — "a car back in a yard is back in the -common supply, carrying nothing" — described something it never did. Coaches suffered worst: -detraining needs `coach && !loaded` out of the Division Yard, so a cleared coach came back as stock -that could never unload a passenger. 18 loaded coaches against 6 empty over five measured games. - -**Games in progress resume, and it was measured before release**, not argued from the diff: all -twelve saves on the test box were replayed through `tryResumeSession` — the server's own boot check -— against the new build. Six resume, six refuse, and the six refusals are the same six, at the same -moves, with the same codes, that 0.8.0.17 already logged. **That replay is the check to repeat on -any release that touches state**, because it answers before the install rather than after. - -Also: leaving a running game no longer strands you in a lobby with no way to join or create -(`runLobby` never restored the section `enterSeating` hides); the lobby's action buttons carry the -board's amber; an Enhancement in the history names the Mainline card it went on, slot and type, by -its printed name; the Manage Game dropdown says how long ago each game was last touched; and §6.2's -Department refill — always implemented, never documented — is written into the game's rules -reference. - -**Previously, 0.8.0.17.** Four fixes from a live playtest of 0.8.0.16, every one of them a case -of the game knowing something and the screen not saying it. **ABS Signals could be played on only -one Mainline card** although its own tooltip said "any": the engine allowed all of them, but the -action list drops duplicate labels and every placement described itself identically, so all but the -lowest-index card were discarded before the menu saw them. A card carrying ABS now **draws a signal -mast**, and the three Heavy Grade modifiers draw as BRK, AIR and HLP — none of them marked the board -before, so the only way to learn one was there was to hover it. **A Freight Agent turn claimed a car -moved when none had** (§6.3 requires no action, and the bot declines on purpose rather than wreck a -stocked box); it now says what it may do, says so when it idles and why, and names the industry -rather than a grid coordinate. And **the log and the action list spelled the same square -differently** — one in map order, one in storage order — which is fixed in favour of the map. - -**The full documentation is now served by the package and reachable from inside a running game**, -under the This Game card: Quickstart, Rules, every card, both deck references and Components. 0.8.0.16 -published the Quickstart alone and its "Where to read more" links all 404'd. Games in progress -**resume normally** — no rule changed. - -**Previously, 0.8.0.16.** Six fixes from a live playtest of 0.8.0.13, plus two follow-ups. One is a rules change and -the rest are the game saying what it was already doing. The Sparrow running empty and a Depot that -could not unload its passengers turned out to be the same thing: §9.2 sends an emptied coach to the -Classification Yard and takes a fresh empty out of the Division Yard, and §2.2 returns Classification -only when the Division Yard runs bare — so coaches travel one way. Measured over one three-Day game: -sixteen coaches in the Division Yard at setup, none from Day 2 Stage 8 onward, fifteen piled in -Classification while the Division Yard sat at 46-47 freight cars and stopped draining. The rule -stands (Jesse's ruling, the same one Gitea#2 got); what changed is that a train made up short now -reports what it wanted and why none is coming, and the yard panel warns while the shortage lasts. - -Also: a Small Yard sort shows the train each option would build, laid out west to east as the board -draws it and saying whether the result may leave the Office, and may now leave cars ahead of the -engine; making up a train names the train in the history; a switching turn keeps its first move, -industry work, the sort and a closing summary instead of a line per move; and the Freight Agent, -Porter and Laborer groups say what each role is for. - -Two smaller releases ride along. **v0.8.0.15** stopped the Interchange advertising a car-sorting -action it has never had — the text reached players on the board through `mainlineDescription`, which -`view.ts` renders as a Mainline card's description, so a player could only go hunting for a button -that was not there. What the card actually offers is the one place on the Mainline an Extra may be -made up and started. That release also carries a **Quickstart for new players** and brings the four -hand-written reference documents up to the game as it runs. As of 0.8.0.17 **all of them are served -by this package** — `/quickstart.md`, `/rules.md`, `/home-deck.md`, `/mainline-deck.md`, -`/components.md` and the generated `/rules/as-built.md` — linked from the splash page and from the -This Game card in a running game. They are served as `text/plain`, so their tables render as rows of -pipes; rendering them as styled pages is filed upstream as TODO #109. **v0.8.0.16** is a doc comment on the flag behind that card, which is the -most likely source of the wrong sentence in the first place. - -**GAMES IN PROGRESS MAY NOT RESUME ON THIS ONE**, and it was measured rather than assumed. A Modifier -card may no longer be placed outside a player's Limits, which reverses an earlier ruling and is the -one shape of change that strands a save: a predicate in `apply.ts` changed its answer, so a move that -was legal when played is refused on replay. The Day 3 playtest save stops at intent 528 of 539 — -`card.play c55 → (-2,4)` against a sign at column 3 — eleven moves short of where the table had got -to. The file is left untouched and the server names the move it stopped at, so re-installing -0.8.0.13 finishes a game worth finishing. (0.8.0.10 was the first release to do this, for the §8.1 -clearance correction.) - -The rest of the engine diff strands nothing: `makeUpShort` and `switchingEnded` are new events, -`trayMoved` and `consistSorted` gained fields, and `switch.sortConsist` gained an OPTIONAL `engineAt` -whose absence means what every sort did before — so an older save replays to the same train. Events -are derived by replaying a save rather than stored in one. - -The paragraphs below were written for the 0.7.9.8 bump and still describe how a bump is checked. - -**Why saves are safe this time, and how that was established.** 0.7.9's breakage came from a rules -change, and the general rule behind it is that a save is a seed plus the moves played, replayed -through the *current* rules — so any change that makes a once-legal move illegal stops an older save. -The question for this bump is therefore narrow: did anything become illegal? `git diff v0.7.9..HEAD --- src/engine/` is, in its entirety, four things — `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.** -Eight releases, none of them in the rules. - -Note that `engineVersion` is *not* a gate. `src/server/index.ts` attempts the replay and reports the -stored and running versions only in the failure message; a game is refused because a move no longer -replays, never because the version string differs. - -**Two multiplayer information leaks.** The random seed was announced in the shared narration log at -game creation, and a blind Home Office draw resolved the drawn card to its real name for every seat. -Both were found by reading a plan rather than by a test, which is why 0.7.9.4 added a systematic -redaction net: a seat's Frame, the spectator projection and the narration are serialised and searched -for every opponent card id, every card name unique to one hand, the seed, and any private decision -data — with an allow-list of every public property that fails the suite when a field is added. - -**The history panel came back empty after a mid-game reload.** `Frame.lines` carried the whole -narration log on every push to every seat and nothing read it — `RemoteSession` accumulates from -`Push.lines` alone. The waste was masking the fault: `connect()` cleared the frame cache but not the -narration watermark, so a reconnecting seat was told "nothing new since your last push" while the -browser it was answering had just reloaded from an empty accumulator. - -**Whose turn it is, during the extended-play vote.** The §3.3 vote is parallel — every un-voted seat -may vote at once — so there is no actor to be, and the engine says so. The turn chart named the last -seat to move anyway, beside a tally correctly showing three seats outstanding. Cause: two functions -answering one question, one carrying a status guard and one not; there is one now, and it is the same -function that *refuses* an intent, so the screen can no longer name somebody the server would turn -away. - -**A train held at the Limits was drawn nowhere.** An Interlocking stops an inbound train on the Limit -Track instead of colliding with a full Office. `arriveAtOffice` removes the tray from the Mainline -node's `transits` and the Interlocking branch never assigns `tray.position`, so with the map drawing -mainline nodes from `transits` and squares from `position.at === 'grid'`, the train was in neither — -it vanished off the board until an A/D track freed. Fixed in the view; the engine state was right. - -**Also in this range.** Trains queued for a Crew Tray (a Timetabled departure, a played Extra, an -ordered second section) now report themselves with the free-tray count, where two of the three had -been waiting invisibly behind an exhausted pool. A Red Flag standing at an Office's Limits is drawn -on the map. A spent Telegraph/Telephone/Radio is struck through and says when another district holds -the Fedora — it is the Superintendent's own devices that get spent, and the Fedora moves every three -Stages. The Campaign Train says whether its speeches are made, which is what decides whether leaving -it off the Office square is a fault. Two bugs from the last playtest session: the Express's one -freight car per location rule is explained where it refuses you (the panel had been describing the -industry instead), and westbound trains are drawn in the correct half of a Mainline card. - -**Bundled version: 0.7.9.** Enforces solitaire's collision limits, which had been offered as -settings and never checked — and that is a rules change, so **a solitaire game in progress will not -resume if it has had collisions**. - -`advance.ts` gated §3.4's check on `mode === 'competitive' || mode === 'coop'`, while `SOLO_CONFIG` -carried both limits (3 a Day, 5 total) and the setup screen offered them as live settings with "the -game ends in a loss" printed beside them. A solitaire player could set a limit of 1 and crash all -game. Jesse's ruling: the settings do what they say, so the gate went rather than the controls. - -**Why saves break, and how it was measured.** A solitaire save is `{ seed, history, rules? }` where -`rules` is the house rules only — **the collision caps are not in the save**, so a restore takes -today's defaults. A 0.7.8 save therefore replays under live caps and stops at the move that crossed -one. Measured with a control, because two earlier attempts were wrong: with the caps disabled 1200 -of 1200 generated saves replay every intent; of those, 74 crossed the 5-collision total and **70 of -the 74 truncate** once the caps are enforced, one at 141 of its 532 intents. An earlier run that -reported no breakage had in fact been failing every replay at intent 2 on an unrelated house-rules -mismatch — the control is what caught that. It fails safe: the save is untouched and the game -declines rather than loading a position the rules could not have produced. **Multiplayer games are -unaffected** — competitive and coop were always inside that gate. - -**Also in 0.7.9.** The end-of-game dialog now asks whether to play one more Day; the buttons existed -but were written into `#actions` _underneath_ a modal whose only control was Close, so a solitaire -player reaching the end was never offered the extension — and the Gitea#11 verification missed it -because it drove the HTTP API, which renders no dialog. `Frame.actor` carried `clock.currentActor`, -null for the whole Mainline Phase, so all three interruptions reported that nobody was holding the -game up; it carries `actingPlayer` and an `awaiting` field now. The game settings moved off the top -line into a **This Game** card drawn by the same renderer as the lobby's join preview, with the -running collision counts taking their place on the top line. The Office Area's auto-hide button was -a cycle that could not reach every state and is now three controls. The history reads newest first. -A Heavy Grade card draws which way it climbs. - -**Bundled version: 0.7.8.** Made the solitaire setup screen reachable at all. 0.7.5 skipped it -whenever `load()` found a saved game — reasoned as "a saved game is a game to resume" — and a browser -that has ever played solitaire always has one, so the door could never reach the screen again. The -door (`?solitaire`) outranks a save now; a bare reload still resumes. Since dealing calls -`clearSave()`, the screen carries a **Continue saved game** button and states what Deal costs, so the -door cannot destroy a game in progress. A solitaire save is browser-side, so nothing on this server -is involved either way. The splash footer also now names both ways to play. - -**This was reported three times before it was found, and the first two fixes were real bugs that were -not it** — a routing fault (0.7.6) and a caching fault (0.7.7). Both were reported as verified, and -both verifications read what the SERVER returned rather than exercising the path with the state a -returning player actually has. What found it was a failing test written before the fix. Worth knowing -when the next "that didn't work" arrives: reproduce the reporter's state first. - -**0.7.7 fixed 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 -asked before a game starts since 0.6.0. - -**0.7.4 bundled three rules corrections** off the tracker (Gitea#13, #5, #19), all of them places -where the code and the cards disagreed. - -**The Yard Office is offered rather than imposed (Gitea#5).** It was implemented in a form missing -all three of its conditions: a qualifying train was teleported onto the card, so nobody was asked, no -route was walked — the card's printed "that can reach the yard office in one move" was unenforced — -and nothing was ever met on the way in. The arrival now interrupts the Mainline Phase to ask the -district's owner, reachability is the engine's own move walk, and cars on the lead collide. Where no -route exists the offer is withheld and the history says why. - -**Some Extras must run loaded (Gitea#13).** Circus, Campaign and Military trains take a loaded car -while the Division Yard can supply one, an empty once it cannot, and may depart short. The per-stop -point is earned once per Office Area rather than once per game, and only by a fully loaded train. -Two long-standing bugs went with it: `emptiesOnly` was rendered to the player and enforced nowhere, -and a set-up out on the Mainline paid its point to player 0 whoever was playing. - -**Red Flags is a different card (Gitea#19).** The old rule protected a stopped train on the Mainline -and was played 4 times in 4,212 offers across 600 games. It is now a directional flag on your own -Limits, spent on the train it stops, playable either in phase or at the moment the engine sees a -certain collision. - -**GAMES IN PROGRESS MAY NOT SURVIVE AN UPDATE FROM BEFORE 0.7.4.** Unlike 0.7.3, which changed no -rules, each of the three above can stop an older history replaying: 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 — `src/server/index.ts` 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.3 back on to finish a game that matters. A game that never meets one of the three carries on -normally, which is why this is "may not" rather than 0.7.2's "will not". **0.7.5 carries every game -forward without exception** — see above. - -**Diagnosing the interruptions.** The Mainline Phase can now stop and ask three different questions, -of three different players: §8.1's clearance goes to the Superintendent, the Yard Office offer and -the Red Flag prompt to the owner of the district a train is arriving at. A game sitting on one is -waiting on a person, not stuck. `Games in Progress` shows it as active with nobody to wait for, -because an interruption is not a turn — the same reading as an extension vote. - -0.7.0 remains the shape of the service: the lobby sets a game up from one of four game types -(Solitaire, Co-op, Competitive, Cutthroat) plus Custom, offers the whole rule set for reading before -a seat is taken, and lets a player leave a lobby or a running game and come back to it. None of this -changes anything the package itself does: the submodule pin is the version, and the service is the -same server it always was. - ---- +**Housekeeping (0.8.5)** and **the save rule (0.8.6):** in a Competitive game the save file — which +carries the seed, and so every rival's hand — can be downloaded once the game is over; in Co-op at +any time. ## Table of Contents diff --git a/startos/versions/current.ts b/startos/versions/current.ts index 9fecbde..ee97173 100644 --- a/startos/versions/current.ts +++ b/startos/versions/current.ts @@ -10,156 +10,106 @@ export const current = VersionInfo.of({ // — 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.2:0', + version: '0.8.6:0', releaseNotes: { en_US: - 'Bundles Station Master v0.8.2 — a playtest read back against its own save file. **The change you ' + - 'notice first: every district now opens on a DEPOT rather than a Whistle Post.** A Depot has two ' + - 'arrival/departure tracks and works passengers from the first Stage; a Whistle Post has one track ' + - 'and is not a passenger facility at all, so the opening of every game used to be spent unable to ' + - 'earn from a passenger and one arrival away from a wreck. A table that wants the harder game can ' + - 'tick "Players start with Whistle Posts, not Depots" when the game is created. **GAMES ALREADY ' + - 'RUNNING ON THIS SERVER: MOST WILL NOT RESUME.** Measured before release rather than discovered ' + - 'after: of the thirteen saved games on the test server, three resume and ten stop. Six of those ' + - 'ten are one new rule — a Waiting Area, Restaurant or Hotel may no longer be played at a Whistle ' + - 'Post, because a Whistle Post is not a passenger facility and the card did nothing there. A game ' + - 'that stops says which move it stopped on and its file is left untouched, so anything worth ' + - 'finishing can be finished by putting 0.8.1.0 back. **An Office could hold two trains on one ' + - 'track.** The train an Interlocking had been holding at the Limits took the track that freed, and ' + - 'the train arriving at that moment was let in after it without anyone checking there was still ' + - 'room — so the collision the rules call for simply did not happen. **Your history could freeze ' + - 'part-way through a game** and never gain another line, at a different moment for each player. ' + - '**Trains were released when they should have been held**, twice over: a card that says "trains ' + - 'may pass" was clearing the whole line ahead rather than just itself, and a train standing at a ' + - 'full Office was invisible to the check although it was about to pull out again. **Things that ' + - 'happened silently now say so** — a train held against one coming the other way, a train released ' + - 'from the Limits, and the train an Interlocking is holding, which now draws differently on the ' + - 'board instead of only explaining itself in a tooltip. **When a move is refused, the board says ' + - 'which rule refused it.** **The documentation is a set of proper pages now**, served by this ' + - 'package and reachable from inside a game under This Game, instead of five files of plain text ' + - 'where every table came out as rows of pipes. **Smaller:** a Modifier must sit square against ' + - 'what it serves rather than on a diagonal; ordering a Second Section costs the card, which was ' + - 'declared in the rules and never actually dealt; a train may always recover its own caboose; and ' + - 'an industry may be built over a straight already laid.', + 'Bundles Station Master v0.8.6 — four releases from a code audit of the game (engine, server, ' + + 'browser, tests), every finding checked against the code before it was acted on. **GAMES ALREADY ' + + 'RUNNING ON THIS SERVER: the three that 0.8.2 promised would resume now do, and the ten it refused ' + + 'stay refused.** 0.8.2 had in fact stranded all thirteen — the Second Section card went into the deck ' + + "after that release's save check, and a deck one card larger shuffles into a different order from the " + + 'same seed — so this build deals an older save from the deck it was dealt from. **The engine:** a ' + + "player could switch a rival's train, and the rival paid the Moves; a rival's crew standing in their " + + 'own district blocked yours; drawing the last card off a Department could put the drawn card in two ' + + "places and lose the refill; the Freight Agent's unjam cleared the first load rather than the one you " + + 'named; the collision limit could not fire in Stage 12; an Expedite fault was charged once per ' + + 'clearance question rather than once per phase; a train the Interlocking held at the Limits was only ' + + 'released by another arrival, never by a departure. **The table:** a player who left a lobby kept a ' + + 'token that could watch and move for whoever took the seat next; the first move after reloading the ' + + 'page could be silently swallowed; two moves at once could tear the save file, and one torn file took ' + + 'every game on the server down at start; an error on a stream could stop the whole service; a ' + + 'double-click did the thing twice. **Saving:** in a Competitive game the save file — which carries ' + + "the seed, and so every rival's hand — can be downloaded once the game is over; in Co-op at any time. " + + '**Also:** the documentation pages render nested lists properly, the make-up panel only lists cars ' + + 'the train can still take, and the unused-code check is now part of the build.', es_ES: - 'Incluye Station Master v0.8.2 — una partida de prueba revisada contra su propio archivo ' + - 'guardado. **El cambio que más se nota: cada distrito empieza ahora con un DEPÓSITO en vez de un ' + - 'Apeadero.** Un Depósito tiene dos vías de llegada/salida y trabaja viajeros desde la primera ' + - 'Etapa; un Apeadero tiene una vía y no es una instalación de viajeros, así que el comienzo de ' + - 'cada partida se pasaba sin poder ganar con un viajero y a una llegada de un choque. Una mesa que ' + - 'quiera el juego más difícil puede marcar "Los jugadores empiezan con Apeaderos, no Depósitos" al ' + - 'crear la partida. **LAS PARTIDAS EN CURSO EN ESTE SERVIDOR: LA MAYORÍA NO SE REANUDARÁN.** ' + - 'Medido antes de publicar, no descubierto después: de las trece partidas guardadas en el servidor ' + - 'de pruebas, tres se reanudan y diez se detienen. Seis de esas diez se deben a una regla nueva: ' + - 'una Sala de Espera, un Restaurante o un Hotel ya no pueden jugarse en un Apeadero, porque no es ' + - 'una instalación de viajeros y la carta no hacía nada allí. Una partida que se detiene indica en ' + - 'qué movimiento lo hizo y su archivo queda intacto, así que lo que merezca la pena terminar puede ' + - 'terminarse reinstalando 0.8.1.0. **Una Oficina podía albergar dos trenes en una sola vía.** El ' + - 'tren que el Enclavamiento retenía en los Límites ocupaba la vía que quedaba libre, y el que ' + - 'llegaba en ese momento entraba detrás sin que nadie comprobara que aún hubiera sitio, así que el ' + - 'choque que exigen las reglas simplemente no ocurría. **El historial podía congelarse a mitad de ' + - 'partida** y no añadir ni una línea más, en un momento distinto para cada jugador. **Se soltaban ' + - 'trenes que debían retenerse**, por dos motivos: una carta que dice "los trenes pueden cruzarse" ' + - 'despejaba toda la línea por delante en vez de solo a sí misma, y un tren parado en una Oficina ' + - 'llena era invisible para la comprobación aunque estuviera a punto de salir otra vez. **Lo que ' + - 'antes ocurría en silencio ahora se dice** — un tren retenido ante otro de frente, un tren ' + - 'liberado de los Límites, y el tren que retiene un Enclavamiento, que ahora se dibuja distinto en ' + - 'el tablero en lugar de explicarse solo al pasar el ratón. **Cuando se rechaza un movimiento, el ' + - 'tablero dice qué regla lo rechazó.** **La documentación son páginas de verdad**, servidas por ' + - 'este paquete y accesibles desde dentro de la partida en Esta Partida, en lugar de cinco archivos ' + - 'de texto plano donde cada tabla salía como filas de barras. **Menor:** un Modificador debe ir ' + - 'pegado en ortogonal a lo que sirve, no en diagonal; ordenar una Segunda Sección cuesta su carta, ' + - 'que estaba en las reglas y nunca se repartía; un tren siempre puede recuperar su propio furgón ' + - 'de cola; y una industria puede construirse sobre una vía recta ya colocada.', + 'Incluye Station Master v0.8.6 — cuatro versiones salidas de una auditoría del código del juego ' + + '(motor, servidor, navegador, pruebas), cada hallazgo comprobado contra el código antes de actuar. ' + + '**PARTIDAS YA EN MARCHA EN ESTE SERVIDOR: las tres que 0.8.2 prometió reanudar ahora se reanudan, y ' + + 'las diez que rechazó siguen rechazadas.** En realidad 0.8.2 había dejado colgadas las trece — la ' + + 'carta Segunda Sección entró en el mazo después de la comprobación de partidas guardadas de esa ' + + 'versión, y un mazo con una carta más se baraja en otro orden con la misma semilla — así que esta ' + + 'versión reparte una partida antigua con el mazo con el que se repartió. **El motor:** un jugador ' + + 'podía maniobrar el tren de un rival, y el rival pagaba los Movimientos; una cuadrilla rival en su ' + + 'propio distrito bloqueaba el tuyo; robar la última carta de un Departamento podía duplicarla y ' + + 'perder la de relleno; el desatasco del Agente de Carga retiraba la primera carga y no la señalada; ' + + 'el límite de colisiones no podía dispararse en la Etapa 12; una falta de Expedición se cobraba por ' + + 'cada pregunta de vía libre y no una vez por fase; un tren retenido en los Límites solo lo liberaba ' + + 'otra llegada, nunca una salida. **La mesa:** quien abandonaba una sala conservaba una ficha con la ' + + 'que podía ver y mover por quien ocupara después su asiento; la primera jugada tras recargar la ' + + 'página podía perderse en silencio; dos jugadas a la vez podían corromper el archivo guardado, y un ' + + 'archivo corrupto tumbaba todas las partidas al arrancar; un error en un flujo podía parar todo el ' + + 'servicio; un doble clic hacía la cosa dos veces. **Guardar:** en una partida Competitiva el archivo ' + + 'guardado — que lleva la semilla, y con ella la mano de cada rival — se puede descargar cuando la ' + + 'partida ha terminado; en Cooperativa, en cualquier momento.', de_DE: - 'Enthält Station Master v0.8.2 — ein Testspiel, gegen seine eigene Speicherdatei nachgelesen. ' + - '**Die auffälligste Änderung: jeder Bezirk beginnt jetzt mit einem DEPOT statt einem ' + - 'Haltepunkt.** Ein Depot hat zwei Ankunfts-/Abfahrtsgleise und arbeitet Fahrgäste ab der ersten ' + - 'Etappe ab; ein Haltepunkt hat ein Gleis und ist gar keine Personenanlage, sodass der Anfang ' + - 'jeder Partie ohne Einnahmen aus Fahrgästen verging und eine Ankunft von einem Unfall entfernt ' + - 'war. Wer das härtere Spiel will, hakt beim Erstellen "Spieler starten mit Haltepunkten statt ' + - 'Depots" an. **LAUFENDE PARTIEN AUF DIESEM SERVER: DIE MEISTEN WERDEN NICHT FORTGESETZT.** Vor ' + - 'der Freigabe gemessen, nicht hinterher entdeckt: von dreizehn Spielständen auf dem Testserver ' + - 'werden drei fortgesetzt und zehn brechen ab. Sechs davon wegen einer neuen Regel — ein ' + - 'Wartesaal, ein Restaurant oder ein Hotel darf nicht mehr an einem Haltepunkt gespielt werden, ' + - 'der keine Personenanlage ist und an dem die Karte nichts bewirkte. Eine abgebrochene Partie ' + - 'nennt den Zug, an dem sie stehen blieb, und ihre Datei bleibt unangetastet — was sich zu Ende ' + - 'spielen lohnt, lässt sich mit 0.8.1.0 zu Ende spielen. **Ein Büro konnte zwei Züge auf einem ' + - 'Gleis halten.** Der vom Stellwerk an der Grenze gehaltene Zug nahm das frei gewordene Gleis, und ' + - 'der gerade ankommende wurde dahinter eingelassen, ohne dass noch einmal nach Platz gefragt wurde ' + - '— der von den Regeln geforderte Zusammenstoß blieb also aus. **Der Verlauf konnte mitten im ' + - 'Spiel einfrieren** und keine Zeile mehr bekommen, bei jedem Spieler zu einem anderen Zeitpunkt. ' + - '**Züge fuhren los, die hätten warten müssen**, gleich zweifach: eine Karte mit "Züge können sich ' + - 'begegnen" gab die ganze Strecke frei statt nur sich selbst, und ein an einem vollen Büro ' + - 'stehender Zug war für die Prüfung unsichtbar, obwohl er gleich wieder ausfahren würde. **Was ' + - 'vorher stumm geschah, wird jetzt gesagt** — ein gegen einen entgegenkommenden Zug gehaltener ' + - 'Zug, ein von der Grenze freigegebener Zug, und der vom Stellwerk gehaltene Zug, der nun auf dem ' + - 'Plan anders gezeichnet wird, statt sich nur im Tooltip zu erklären. **Wird ein Zug abgelehnt, ' + - 'nennt der Plan die Regel.** **Die Dokumentation besteht jetzt aus richtigen Seiten**, von diesem ' + - 'Paket ausgeliefert und aus der Partie heraus unter Diese Partie erreichbar, statt aus fünf ' + - 'Textdateien, in denen jede Tabelle als Reihen von Strichen erschien. **Kleineres:** ein ' + - 'Modifikator muss rechtwinklig an dem liegen, was er bedient, nicht diagonal; eine Zweite Sektion ' + - 'kostet ihre Karte, die in den Regeln stand und nie ausgeteilt wurde; ein Zug darf seinen eigenen ' + - 'Zugschlusswagen immer zurückholen; und eine Industrie darf über ein bereits verlegtes gerades ' + - 'Gleis gebaut werden.', + 'Enthält Station Master v0.8.6 — vier Versionen aus einer Code-Prüfung des Spiels (Engine, Server, ' + + 'Browser, Tests), jeder Befund vor dem Handeln am Code geprüft. **BEREITS LAUFENDE PARTIEN AUF DIESEM ' + + 'SERVER: die drei, die 0.8.2 als fortsetzbar versprach, sind es jetzt; die zehn abgelehnten bleiben ' + + 'abgelehnt.** Tatsächlich hatte 0.8.2 alle dreizehn gestrandet — die Karte Zweiter Abschnitt kam nach ' + + 'der Spielstand-Prüfung dieser Version in den Stapel, und ein um eine Karte größerer Stapel mischt ' + + 'sich aus demselben Startwert anders — daher teilt diese Version einen älteren Spielstand aus dem ' + + 'Stapel aus, aus dem er stammte. **Die Engine:** ein Spieler konnte den Zug eines Gegners rangieren, ' + + 'und der Gegner zahlte die Züge; eine gegnerische Mannschaft im eigenen Bezirk blockierte deinen; das ' + + 'Ziehen der letzten Karte einer Abteilung konnte sie verdoppeln und die Nachschubkarte verlieren; das ' + + 'Freiräumen des Frachtagenten nahm die erste Ladung statt der benannten; das Kollisionslimit konnte ' + + 'in Etappe 12 nicht greifen; ein Eilzug-Vergehen wurde je Freigabefrage statt einmal je Phase ' + + 'berechnet; ein an der Grenze gehaltener Zug wurde nur durch eine weitere Ankunft freigegeben, nie ' + + 'durch eine Abfahrt. **Der Tisch:** wer eine Lobby verließ, behielt ein Token, mit dem er für den ' + + 'nächsten Sitzinhaber zusehen und ziehen konnte; der erste Zug nach dem Neuladen der Seite konnte ' + + 'stillschweigend verschluckt werden; zwei Züge zugleich konnten die Spielstanddatei zerreißen, und ' + + 'eine zerrissene Datei legte beim Start jede Partie lahm; ein Fehler auf einem Stream konnte den ' + + 'ganzen Dienst anhalten; ein Doppelklick tat die Sache zweimal. **Speichern:** in einer ' + + 'Wettbewerbspartie lässt sich die Spielstanddatei — sie enthält den Startwert und damit jede ' + + 'gegnerische Hand — erst nach Spielende herunterladen; im Koop-Modus jederzeit.', pl_PL: - 'Zawiera Station Master v0.8.2 — rozgrywkę testową odczytaną z jej własnego zapisu. **Zmiana, ' + - 'którą widać najpierw: każdy okręg zaczyna teraz od DWORCA, a nie od przystanku.** Dworzec ma dwa ' + - 'tory przyjazdowo-odjazdowe i obsługuje pasażerów od pierwszego etapu; przystanek ma jeden tor i ' + - 'wcale nie jest obiektem pasażerskim, więc początek każdej partii mijał bez możliwości zarobku na ' + - 'pasażerze i o jeden przyjazd od katastrofy. Stół, który chce trudniejszej gry, zaznacza przy ' + - 'tworzeniu "Gracze zaczynają od przystanków, nie dworców". **PARTIE TRWAJĄCE NA TYM SERWERZE: ' + - 'WIĘKSZOŚĆ SIĘ NIE WZNOWI.** Zmierzone przed wydaniem, a nie odkryte później: z trzynastu zapisów ' + - 'na serwerze testowym trzy się wznawiają, a dziesięć zatrzymuje. Sześć z nich przez jedną nową ' + - 'zasadę — poczekalni, restauracji ani hotelu nie można już zagrać na przystanku, bo nie jest on ' + - 'obiektem pasażerskim i karta nic tam nie robiła. Zatrzymana partia podaje ruch, na którym ' + - 'stanęła, a jej plik pozostaje nietknięty, więc to, co warto dokończyć, można dokończyć ' + - 'przywracając 0.8.1.0. **Biuro mogło pomieścić dwa pociągi na jednym torze.** Pociąg trzymany ' + - 'przez blokadę na granicy zajmował zwolniony tor, a przyjeżdżający w tej chwili wjeżdżał za nim, ' + - 'choć nikt nie sprawdzał, czy jest jeszcze miejsce — więc wymagana zasadami kolizja po prostu nie ' + - 'następowała. **Historia mogła zamarznąć w połowie partii** i nie dostać już ani jednej linii, u ' + - 'każdego gracza w innym momencie. **Pociągi ruszały, choć powinny czekać**, z dwóch powodów: ' + - 'karta mówiąca "pociągi mogą się mijać" zwalniała całą drogę przed sobą zamiast tylko siebie, a ' + - 'pociąg stojący na pełnym biurze był niewidoczny dla sprawdzenia, choć za chwilę miał znowu ' + - 'wyjechać. **To, co działo się po cichu, teraz jest mówione** — pociąg wstrzymany przed ' + - 'nadjeżdżającym z naprzeciwka, pociąg zwolniony z granicy, oraz pociąg trzymany przez blokadę, ' + - 'który rysuje się teraz inaczej zamiast tłumaczyć się tylko w dymku. **Gdy ruch zostaje ' + - 'odrzucony, plansza podaje zasadę.** **Dokumentacja to teraz prawdziwe strony**, serwowane przez ' + - 'ten pakiet i dostępne z wnętrza gry w karcie Ta Partia, zamiast pięciu plików zwykłego tekstu, w ' + - 'których każda tabela wychodziła jako rzędy kresek. **Drobne:** modyfikator musi przylegać ' + - 'prostopadle do tego, czemu służy, nie po skosie; zamówienie drugiej sekcji kosztuje kartę, która ' + - 'była w zasadach i nigdy nie trafiała do talii; pociąg zawsze może odzyskać własny wagon ' + - 'służbowy; a przemysł można zbudować na już położonym torze prostym.', + 'Zawiera Station Master v0.8.6 — cztery wydania z audytu kodu gry (silnik, serwer, przeglądarka, ' + + 'testy), każde ustalenie sprawdzone w kodzie przed działaniem. **GRY JUŻ TRWAJĄCE NA TYM SERWERZE: ' + + 'trzy, które 0.8.2 obiecało wznowić, teraz się wznawiają; dziesięć odrzuconych pozostaje ' + + 'odrzuconych.** W istocie 0.8.2 unieruchomiło wszystkie trzynaście — karta Druga Sekcja trafiła do ' + + 'talii po kontroli zapisów tego wydania, a talia większa o jedną kartę tasuje się inaczej z tego ' + + 'samego ziarna — więc to wydanie rozdaje starszy zapis z talii, z której został rozdany. **Silnik:** ' + + 'gracz mógł manewrować pociągiem rywala, a rywal płacił Ruchy; załoga rywala w jego własnym okręgu ' + + 'blokowała twój; dobranie ostatniej karty z Działu mogło ją zdublować i zgubić kartę uzupełniającą; ' + + 'odblokowanie przez Agenta Towarowego usuwało pierwszy ładunek zamiast wskazanego; limit kolizji nie ' + + 'mógł zadziałać w Etapie 12; kara za Ekspres była naliczana za każde pytanie o zwolnienie toru ' + + 'zamiast raz na fazę; pociąg zatrzymany na Granicy zwalniało tylko kolejne przybycie, nigdy odjazd. ' + + '**Stół:** kto opuścił poczekalnię, zachowywał token pozwalający oglądać i grać za tego, kto zajął ' + + 'miejsce po nim; pierwszy ruch po przeładowaniu strony mógł zostać po cichu połknięty; dwa ruchy ' + + 'naraz mogły uszkodzić plik zapisu, a jeden uszkodzony plik wyłączał przy starcie wszystkie gry; błąd ' + + 'w strumieniu mógł zatrzymać całą usługę; podwójne kliknięcie robiło rzecz dwa razy. **Zapis:** w ' + + 'grze Rywalizacyjnej plik zapisu — zawierający ziarno, a więc rękę każdego rywala — można pobrać po ' + + 'zakończeniu gry; w Kooperacji w każdej chwili.', fr_FR: - 'Contient Station Master v0.8.2 — une partie de test relue contre sa propre sauvegarde. **Le ' + - 'changement que l\'on voit d\'abord : chaque district commence désormais avec un DÉPÔT et non un ' + - 'arrêt.** Un dépôt a deux voies d\'arrivée et de départ et traite les voyageurs dès la première ' + - 'étape ; un arrêt n\'a qu\'une voie et n\'est pas une installation voyageurs, si bien que le début ' + - 'de chaque partie se passait sans pouvoir gagner sur un voyageur et à une arrivée d\'un accident. ' + - 'Une table qui veut le jeu plus difficile coche « Les joueurs commencent avec des arrêts, pas des ' + - 'dépôts » à la création. **PARTIES EN COURS SUR CE SERVEUR : LA PLUPART NE REPRENDRONT PAS.** ' + - 'Mesuré avant la publication, et non découvert après : sur les treize sauvegardes du serveur de ' + - 'test, trois reprennent et dix s\'arrêtent. Six de ces dix tiennent à une règle nouvelle — une ' + - 'salle d\'attente, un restaurant ou un hôtel ne peut plus être joué sur un arrêt, qui n\'est pas ' + - 'une installation voyageurs et où la carte ne faisait rien. Une partie qui s\'arrête indique à ' + - 'quel coup, et son fichier reste intact : ce qui mérite d\'être terminé peut l\'être en ' + - 'réinstallant 0.8.1.0. **Un bureau pouvait accueillir deux trains sur une seule voie.** Le train ' + - 'que l\'enclenchement retenait aux limites prenait la voie libérée, et celui qui arrivait à cet ' + - 'instant entrait derrière lui sans que personne ne revérifie la place — la collision exigée par ' + - 'les règles n\'avait donc pas lieu. **L\'historique pouvait se figer en pleine partie** et ne plus ' + - 'recevoir une seule ligne, à un moment différent pour chaque joueur. **Des trains partaient alors ' + - 'qu\'ils auraient dû attendre**, pour deux raisons : une carte disant « les trains peuvent se ' + - 'croiser » dégageait toute la voie devant elle au lieu d\'elle seule, et un train à l\'arrêt dans ' + - 'un bureau plein était invisible au contrôle bien qu\'il fût sur le point de repartir. **Ce qui se ' + - 'passait en silence se dit maintenant** — un train retenu face à un autre, un train libéré des ' + - 'limites, et le train que retient un enclenchement, désormais dessiné différemment sur le plan au ' + - 'lieu de ne s\'expliquer qu\'en infobulle. **Quand un mouvement est refusé, le plateau dit quelle ' + - 'règle l\'a refusé.** **La documentation est faite de vraies pages**, servies par ce paquet et ' + - 'accessibles depuis la partie sous Cette Partie, au lieu de cinq fichiers de texte brut où chaque ' + - 'tableau sortait en rangées de barres. **Mineur :** un modificateur doit être accolé ' + - 'orthogonalement à ce qu\'il dessert, jamais en diagonale ; commander une deuxième section coûte ' + - 'sa carte, prévue par les règles et jamais distribuée ; un train peut toujours récupérer son ' + - 'propre fourgon de queue ; et une industrie peut être bâtie sur une voie droite déjà posée.', + "Inclut Station Master v0.8.6 — quatre versions issues d'un audit du code du jeu (moteur, serveur, " + + "navigateur, tests), chaque constat vérifié dans le code avant d'agir. **PARTIES DÉJÀ EN COURS SUR CE " + + 'SERVEUR : les trois que 0.8.2 promettait de reprendre reprennent désormais, et les dix refusées ' + + 'restent refusées.** En réalité 0.8.2 les avait toutes bloquées — la carte Seconde Section est entrée ' + + "dans le paquet après le contrôle des sauvegardes de cette version, et un paquet d'une carte de plus " + + 'se mélange autrement à partir de la même graine — cette version distribue donc une ancienne ' + + "sauvegarde avec le paquet dont elle vient. **Le moteur :** un joueur pouvait manœuvrer le train d'un " + + 'rival, et le rival payait les Mouvements ; une équipe rivale dans son propre district bloquait le ' + + "vôtre ; piocher la dernière carte d'un Département pouvait la dupliquer et perdre la carte de " + + "remplacement ; le déblocage de l'Agent de fret retirait le premier chargement et non celui désigné ; " + + "la limite de collisions ne pouvait pas se déclencher à l'Étape 12 ; une faute d'Express était " + + 'comptée à chaque question de voie libre et non une fois par phase ; un train retenu à la Limite ' + + "n'était libéré que par une autre arrivée, jamais par un départ. **La table :** qui quittait un salon " + + 'gardait un jeton permettant de voir et de jouer pour celui qui prenait ensuite le siège ; le premier ' + + 'coup après rechargement de la page pouvait être avalé en silence ; deux coups à la fois pouvaient ' + + 'déchirer le fichier de sauvegarde, et un fichier déchiré mettait toutes les parties hors service au ' + + 'démarrage ; une erreur sur un flux pouvait arrêter tout le service ; un double clic faisait la chose ' + + 'deux fois. **Sauvegarde :** en partie Compétitive, le fichier — qui porte la graine, donc la main de ' + + 'chaque rival — se télécharge une fois la partie terminée ; en Coopération, à tout moment.', }, migrations: { /** @@ -346,6 +296,29 @@ export const current = VersionInfo.of({ * * SO THE RESUME WARNING IN THESE RELEASE NOTES IS ENTIRELY v0.8.0.14's, and it still applies: * a box on 0.8.0.13:0 takes this update in one hop and meets the Modifier rule on the way. + * + * v0.8.3 THROUGH v0.8.6 ARE THE AUDIT, AND THE RESUME QUESTION WAS MEASURED ON THIS SERVER'S OWN + * SAVES rather than argued from the diff — because the argument had already failed once. 0.8.2's + * entry says three of thirteen resume; the boot log on the box refused thirteen of thirteen, at + * move 3, CARD_NOT_IN_HAND. The Second Section card had gone into the deck after 0.8.2's save + * check ran, and a deck one card larger shuffles into a different order from the same seed. v0.8.3 + * adds `secondSectionCard` to the house rules — no dial, a fact about the deal — and `withSavedDeal` + * sets it false for a saved config that predates `startingOffice`. Result, replayed with + * `tryResumeSession` (never `fromSave`, which skips the legality check): 3 resume / 10 refuse, the + * same ten at the same moves for the same rules 0.8.2 named. So this update RESTORES three games + * 0.8.2 lost and un-refuses none of the ten. + * + * THE ENGINE DIFF DOES CHANGE PREDICATES, and each is the narrowing kind in principle: `check` now + * refuses a switching intent on a tray outside the actor's district; the collision floor is judged + * before the Day rolls over; the Department-draw reshuffle collects a different set; a held train is + * released at the end of a Mainline phase. None of the thirteen saves met any of them — measured, + * above — and a save that did would refuse at the move with its code and be left untouched, as + * always. Events gained `index` (unjam) and `freedBy: number | null` (release); events are derived, + * not stored. v0.8.4 is the HTTP layer and the browser and touches nothing on disk except HOW + * `game.json` is written (unique temp names, one writer per path) — the format is unchanged, and a + * torn file from before is now logged and skipped at boot rather than fatal. v0.8.5 is + * documentation and dead code. v0.8.6 refuses `/api/save` to a Competitive seat until the game is + * finished (Jesse's ruling) — a read-only route, nothing on disk. No migration. */ up: async ({ effects }) => {}, down: IMPOSSIBLE, diff --git a/station-master b/station-master index 3befc42..def4820 160000 --- a/station-master +++ b/station-master @@ -1 +1 @@ -Subproject commit 3befc420da755445509af995fddbfc6004963985 +Subproject commit def48201e49ad24bfbe142d79aec2724ed41429c