517238a7275d09752f7edbca1d315891e963828e
14
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b90c0413d2 |
v0.8.0.17 — four things the game knew and the screen did not say
All four reported from a table on Day 1 of v0.8.0.16, and all the same shape. ABS SIGNALS COULD ONLY BE PLAYED ON ONE MAINLINE CARD, while its tooltip said "any Mainline card". The engine was never wrong: check accepts any node whose kind is mainline and legalActions filters by check, so all of them were legal. The failure was the LABEL — describeIntent named i.placement and never i.node, so every placement described itself as plain "play ABS Signals", and the action list drops duplicate labels. All but the lowest-index node were discarded before the menu saw them. This is the THIRD time that trap has fired and the file documents the other two three lines apart: a turnout's two rotations, and three Department discards. Same fix — name what distinguishes them. The card is also called what the card face calls it. prettyKey rendered absSignals as "Abs Signals" beside a tooltip saying ABS, an acronym no key-splitter can recover, so the authored names now win. Three of those names were transcribed in sentence case and were CORRECTED rather than adopted: the repository says "Yard Office" 36 times against "Yard office" twice. A lookup that imports its own source's typos is the drift it exists to prevent. NOTHING ON A MAINLINE CARD SHOWED WHAT WAS STANDING ON IT. Played, ABS left no mark and you found out by hovering — the same complaint the Heavy Grade wedge answered, and it matters more here because ABS decides whether a second train on that card is safe. It draws a signal mast with a lit lamp now; a signal is the literal object and needs no room for words, which is what lets it sit clear of a name as long as "Uncontrolled Siding" on a 152px cell. The Mainline modifiers draw as BRK, AIR and HLP. Realignment is deliberately not among them: reduce takes the `became` branch and changes node.card, so a realigned Trestle IS an Uncontrolled Siding afterwards. Asserted, so the absence reads as a finding. A FREIGHT AGENT TURN SAID A CAR MOVED WHEN NONE HAD. Three faults behind one line. It asserted an outcome, where §6.3 requires no action and the bot declines deliberately — unjamming a healthy box destroys a load that cost a whole action to stock. An idle Agent was then silent, which read as a dropped turn; a new freightAgentIdled event says so and why, reducing to nothing exactly like switchingEnded. And the work named a coordinate rather than the industry, though a `place` helper has existed for precisely that since the switching lines moved to it. "Loaded a loaded boxcar INTO the green Outbound box at the Freight House", with the direction in capitals because to-or-from was the question asked. THE LOG AND THE ACTION MENU SPELLED THE SAME SQUARE DIFFERENTLY. view.ts wrote (col,row) — X,Y, east/west then north/south — with a comment saying why; narrate.ts wrote the internal storage order with no comment at all. So the menu offered a move to "(1,-1)" and the log reported it at "(-1,1)", side by side. Pinned by a test that renders one square through BOTH describers and compares them to each other: a test written against either file alone would have passed. THE DOCUMENTATION IS REACHABLE FROM A RUNNING GAME, AND ALL OF IT IS PUBLISHED. v0.8.0.16 published the Quickstart and nothing it points at — its §8 links five documents by relative path and every one 404'd on the package, verified against the running container. The build publishes the full set, and the test reads the links OUT OF the guide rather than listing them. They are linked from the This Game card, where reference already lives, rather than the header that must not wrap; no mode awareness is needed, because solitaire and multiplayer are the same page on the same origin. THE REFERENCES DROPPED THE VERSION FROM THEIR NAMES. Four described v0.8.0.16 and had since the v0.8.0.15 audit; the v0.4.5 was the prototype edition they were first written against, kept only because 36 citations pointed at it — and it read as documentation five minor versions stale. They are quickstart.md, rules.md, home-deck.md, mainline-deck.md and components.md now, kept current with each release rather than published as editions. Two errors surfaced while checking them against this release, which is the argument for doing it: home-deck.md filed ABS Signals under Enhancements "played into your district" that "change what a square does" — it does neither, this release's bug written down — and mainline-deck.md, which lists everything playable onto a Mainline card, never mentioned it at all. 1010 fast tests and 35 sim tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MUizFYCMHRWhbWwXhp7WPR |
||
|
|
dc31555625 |
v0.8.0.16 — the guide a tester can reach, and a flag that named the card instead of the gate
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 somebody who already has the repository. Nobody handed the box had it. build-web.ts now copies it to dist/quickstart.md and the splash page offers it under the three doors, as a line rather than 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 drifts from it on the first edit, which is the failure #15a was raised about and precisely what the v0.8.0.15 pass spent itself undoing. It is served as PLAIN TEXT, which is honest rather than good — tables render as pipes and the links do not click. Rendering it into a styled page wants a small Markdown converter and is filed as TODO #109; build-web.ts's comment names that number rather than gesturing at "the next step", so the file and the worklist cannot drift the way the references just did. Two things had to be true and tsc checks neither, so both are tests. 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. And 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 have handed a tester a file to save rather than a page to read. '.md' is in http.ts's table now, 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. VERIFIED AGAINST A RUNNING SERVER, not only compiled: 200, text/plain; charset=utf-8, the guide's own first lines, and the splash link resolving. THE sortsCars COMMENT. Asked after v0.8.0.15 whether everything now agreed, and the audit turned up one place that did not — the field's own doc comment named the card's 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 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: it is what a developer reads before using the flag, and it is the likeliest source of the sentence v0.8.0.15 had to correct off the board. The name is kept for its link to the card face and the comment now says outright that the name is not the meaning. The five references and docs/design.md read v0.8.0.16. They describe this build because the audit re-checked them against it, not because the number was swept forward — a stamp bumped without a reading is worth less than none. 1001 fast tests and 35 sim tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MUizFYCMHRWhbWwXhp7WPR |
||
|
|
f308a2d94d |
v0.8.0.15 — the reference documents, and a card that advertised what it cannot do
The four hand-written references brought up to the game as it actually runs, ahead of the next testing round, plus a Quickstart to hand a tester who has never played. They had not been touched since v0.6.2 — a month and two minor versions — and each now says at the top which build it describes. ONE LIVE BUG CAME OUT OF THE PASS. mainlineDescription told players "Cars may be sorted into any new order here" on the Interchange. It is the printed capability and has never been implemented: nothing reads sortsCars to permit a sort, and its one live use is marking the card an Extra may be made up on, because it is the Mainline card with a yard. That sentence is not only documentation — view.ts renders it as a Mainline card's `what`, so it is what a player reads on the board, and the generated reference printed a "Sorts cars: yes" column beside it. A card advertising a button that does not exist sends a player hunting for it and then concluding the game is broken. What the documents had wrong, all of it verified against the code rather than read for tone: the victory model in the Rules book (firstToTarget / highestAfterDays and the target-bearing length presets stopped existing in 2026-08 — it is a free days count and a combined floor of 3 x players x days); "there is no lobby, no server, no multiplayer"; crossing time in mph rather than regions; Extras launched automatically eastbound; the Uncontrolled Siding listed as a passing card; industry track length taken from the box count; and a "Sister Trains" optional rule that never existed. The Home deck's counts table came out under TODO #15a — Jesse's own ruling that counts move with balance — and it had been wrong for a month, which is the argument made twice. The Home and Mainline deck references are restructured to explain how a deck is USED and to defer every per-card table to rules/as-built.md. Duplicating it by hand is precisely the drift #15a was raised about: as-built needed no correction beyond the Interchange, because build:cards regenerates it and a test fails when the checked-in file disagrees. Everything hand-maintained around it had drifted; it had not. docs/design.md, the index everything starts from, said v0.4.3, "what is not: the server", and 493 tests. It now also lists the player-facing references, which it never has, so the Quickstart is findable at all. 999 fast tests and 35 sim tests pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DmdqqCNoiqE7GBo6wthBnR |
||
|
|
9a9e50b3c6 |
v0.8.0.11 — sixteen fixes from the second multiplayer playtest
Arrivals name whose Office they reached, and no longer tell every seat they can work the train. The turn chart follows the animation queue, so being five behind looks five behind across the whole screen rather than half of it. Pause sits beside Skip and preserves the dwell a held step still owed. A one-render look at another player's Office Area. The district summary counts the board being shown. LIMITS is printed beneath its card instead of through its border. The Mainline region divider is visible. Only Hilly mentions FAST/SLOW, because it is the only card that reads it. A passenger Modifier on a Whistle Post reports itself dormant rather than claiming the facility "only receives". An automatic phase says what the Division is doing instead of answering by negation. The version appears once in the header rather than twice on every .s9pk. Save files carry the join code, the Stage and the date. The New Train phase, reviewed before being changed: the make-up panel now says what the train STILL needs rather than only what its card calls for, explains that a player adds one car before the round passes on, marks the train being loaded on the Division map, and gives an addable car in the yard the same amber every other clickable thing on the page wears. Reasoning, measurements and the reports behind each are in CHANGELOG.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017nnuCv8UodHucFfx3LWEoX |
||
|
|
e734481d65 |
v0.7.9.3 — the reference says what only the code knows, and saves get a rule
The generated card reference now carries the half TODO #15a said was the point of generating it: every Enhancement's `live` / `dormantSolo` / `unbuilt` status — whether its printed effect actually resolves yet — and the opponent-directed Action and Space-use cards, none of which is dealt in any deck. A transcription cannot carry either fact. Card counts are removed throughout, as ruled: they move with play balance so a document printing them is stale on the next retune. Where a count matters it is a yes/no "is this dealt at all", which is a fact about the design rather than the current tuning. #88 closes with it — it asked whether `card-reference.md`'s industry rows were stale, deliberately without rewriting them since Laborer counts are a balance decision. They are; nothing in the engine changed; that file is simply no longer where anyone looks. The balance question it guarded is #70. Save compatibility becomes a general rule in `README.md` § Design notes rather than a fact restated per version: a save is a list of moves and reopens by being re-played through the CURRENT rules, so any change that makes a once-legal move illegal stops an older one there — a deck change being the likeliest breaker. It fails safe every time. #40 generalised, #32's version-specific note dropped, #52 carries the ruling that versioned replays are a post-1.0 question. #94 opened: a Red Flag set out at an Office's Limits holds the next train from that side and is drawn nowhere. `DivisionView`'s office node has no `redFlag` field and `board-svg.ts` never mentions one, so after the single log line announcing it there is nothing on screen. Same class as Gitea#21 and #22, and already on the common board's step 1 list. No engine change. 897 tests pass, unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E3Qk7uresKCHksdZajXCLg |
||
|
|
819996faa2 |
v0.7.9.2 — two things the table could hear that only one seat should
Both leaks were found while planning the common board (Gitea#20 step 1), and both are live multiplayer bugs with or without that display, so they are fixed now rather than with 0.8.0. `game.log` is one shared list and `linesSince(seat)` slices it with no per-seat filter, so every line reaches every player. It carried the SEED in the opening line of each multiplayer game — the whole future of the deal — and the NAME OF A CARD DRAWN BLIND from the face-down Home Office deck. Solitaire deliberately keeps both: a one-seat table has nobody to leak to, the seed is what a bug report quotes, and a player's own history naming their own draw is the record. A Department slot is face up and stays named. The drawer still learns their card through `justDrawn`, which already goes to that seat alone. Neither was found by a test. Every test in `redaction.test.ts` passes an empty log, so the whole of narration has sat outside the redaction net since the net was built. Both now have tests there; TODO #91 carries what is still owed and supersedes #78, which described a gap that had already been closed and never mentioned this one. `docs/rules/` had no current description of the game, and `content.ts` named `card-reference.md` as the file that carries what the cards say — a file whose own banner says not to use its numbers, describing the v0.4.5 deck where 3/4 is a Mail-Express with three coaches. Every file in that directory is a deliberate historical record, so none of them is rewritten. `as-built.md` is new and GENERATED from the same catalogues the engine instantiates from, with a test that re-runs the generator and fails when the checked-in file disagrees. A hand-written replacement would have drifted the same way, for the same reason. TODO.md: #32 closed — the playtest migration note did its job and the jump is made; the durable fact it carried is kept. #78 retired in favour of #91. The "play it at a table" section now records that 0.7.4-0.7.9 were test-run without change requests, and that more testing comes at the end of the 0.7.9 series. 897 tests pass, up from 891. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E3Qk7uresKCHksdZajXCLg |
||
|
|
af68aac78d |
v0.7.7 — two releases shipped to a browser that never received them
buildStamp()'s no-git fallback was the literal "nogit", and the .s9pk Dockerfile copies the tree in without .git — so git rev-parse fails on every packaged build. That string is also the cache-bust key every module URL carries, so v0.7.4, v0.7.5 and v0.7.6 all published ./web/main.js?v=nogit, byte-identical, and returning browsers refetched nothing. v0.7.5's setup screen and v0.7.6's door fix were both correct and neither arrived. The fallback is now the package version plus the build timestamp, always distinct. And serveStatic sent no Cache-Control at all, which is the other half — a cached play.html pins a player to the whole build it names. A request carrying ?v= is now immutable for a year; everything else is no-cache. ?v= rather than "not HTML" because build-web.ts tags the modules and nothing else. Neither half is sufficient alone. 864 tests pass, two new. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AdG46Ja2PEDBkpqiDazMoX |
||
|
|
42adfda390 |
v0.6.3 — the deploy script follows the host to FileBrowser Quantum
The deploy script only. No rules change, no game change, and the built site is byte-for-byte what 0.6.2 produced — this repairs the path that publishes it. Found trying to publish the 0.4.9f playtest build: every deploy died with "login failed: 404 404 page not found". The File Browser host has been upgraded to FileBrowser Quantum, a fork whose API differs from the v2.63 one deploy-web.ts was written against. Three things moved at once, each fatal on its own: auth is a session COOKIE rather than a JWT sent back as X-Auth, so a deploy that ignored it would authenticate and then be rejected by every upload; the password is an X-Password header, URL-encoded, rather than a JSON body field; and the path is a query parameter, with every resource call also having to name a `source` — Quantum can serve several named stores and refuses any call that does not say which, a concept the v2.63 API did not have. Rewritten against the running instance's own bundle rather than guessed, the same discipline the v2.63 version was written with. Two things worth knowing next time: the bundle is gzip-compressed, so it needs gunzip before it can be grepped; and an endpoint that exists answers a bad password with 401 while a missing one answers 404, which is how each path was confirmed against the live host without holding a password. The source is discovered from GET /api/settings/sources — one configured source is used silently, several makes the script stop and list them rather than deploy into the wrong store. FB_SOURCE overrides it, FB_OTP carries a two-factor code. Verified by deploying with it rather than by reading: 0.4.9f went up this way. This is that same file byte-identical, brought across to the main line — both branches carried the same broken script, so deploying 0.6.x would have failed identically. Also removes dist-test/, an untracked hand-made copy of a v0.6.2 dist/ build that no script or test references. build-web.ts hardcodes dist and wipes it on every run, so nothing in the repo could have produced that directory or would ever read it. .gitignore is deliberately unchanged: the answer for a directory that should not exist is to delete it, not to hide it. 715 tests pass, tsc clean, site builds. |
||
|
|
c3c5cbfeec |
v0.5.0 — multiplayer Phases 2 and 3: a server that runs a game and survives being restarted
Phases 0-1 shipped in v0.4.0 (seat/identity split, per-player turn state, the Session boundary). This lands Phase 2 (server core, one game, no lobby) and Phase 3 (persistence and resumption) per docs/architecture/multiplayer.md §12. Phases 4-6 (lobby/reconnection, the 22 opponent-directed cards, StartOS packaging) are still ahead. Phase 2: src/server/session.ts hosts a game in pure logic (no sockets) on top of game.ts's existing Game/submit/currentActor/actionMenu; it verifies seat === currentActor(game) itself before calling submit, since submit() trusts its caller and a server can't. src/server/http.ts and index.ts add POST /api/game, GET /api/stream (SSE, per-seat), POST /api/intent, and static serving of dist/. src/sim/frame-delta.ts is a purpose-built per-seat board delta for one live push at a time. Found and fixed along the way: actionMenu(game, seat) only used seat for the hand field, so a server computing every connected seat's Menu would have handed the acting player's legal moves to a waiting seat. Verified with a live end-to-end smoke test (2-player game, two SSE streams, a rejected intent from the wrong seat, an idempotent resend) plus test/server/session.test.ts and test/redaction.test.ts. Not verified: an actual browser (none available in this environment). Phase 3: src/server/persistence.ts writes game.json and turn-timings.json, atomic-rewrite-then- rename. game.ts gained fromMultiplayerSave, fixing a narration-attribution bug found while testing it (fromSave's replay loop drops the actor argument, invisible in solitaire, unreadable the moment there's more than one seat — fromSave itself still has this gap, deliberately untouched). Verified live: server killed and restarted mid-game, both seats reconnected exactly where they left off. Two rules bugs found while building this: the New Train phase never implemented its car-placement round (every car of every train was placed by the Superintendent alone, in every mode, all along — now reads the round position off tray.consist.length); and victory conditions are now one shared, configurable GameConfig set across solitaire/competitive/coop instead of a fixed length lookup and a dead firstToTarget condition. Also folds in the three fixes already released on the patch line as v0.4.9b/c/d: a switching train's crew badge failing to draw once it left the Office square, an unload that always took the westmost car regardless of which was picked, and a legal decision that could render with zero buttons. docs/testing/0.5.0-test-plan.md and three reported-bug save files (docs/station-master-seed*.json) included for reproducibility. tools/jitsi-harness/ deliberately left untracked — unrelated side-project work, not part of this release. 635 tests, 0 failures. |
||
|
|
859817d173 |
v0.4.9 — X,Y coordinates, no-switching can still clear the mainline, Q3 corrected, a clearance bug, three sounds, and the box art
A playtest review of seed 58228926 (day 6), plus one long-standing display complaint and the first real audio beyond a placeholder. - Coordinate labels read X,Y everywhere shown to a player, not the internal Y,X storage order. Display-only. - "No switching" now means may not add or drop cars, not "never touch it" — these trains can still be moved onto Secondary Track to clear the mainline. - Q3 corrected: Expedite governs WHERE a train may be left standing, not WHEN it leaves. The forced same-Stage departure is gone; a new fault costs 1 Revenue if an expedited train is left off the station when a Mainline Phase begins. Resolves "3/4 Express prints a rule it can never use" as a side effect. - evaluateClearance now checks every occupant on a Mainline card before offering a judgment call, instead of returning on whichever it found first — found while explaining a playtest report, fixed with a regression test. - Three new synthesised sounds: arrive, depart, crash. - The splash page shows the box art. Full detail, measurements and reasoning in CHANGELOG.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FvU99NEakShRMg3nN3fHAZ |
||
|
|
ec792dfc15 |
Say who is playing, what you can press, and where you are in the Stage
Mostly presentation, plus one rules fix found on the way. |
||
|
|
f52ff0e9ac |
Draw the board as track, split the site into three pages, and fix curve geometry
Adds SVG board rendering shared by the game and the replay, a splash page with a shareable replay directory, hover tooltips for reference detail, and makes curves two-port arcs so sidings and run-arounds can finally be built. |
||
|
|
dd300ac154 | Fix caching, Limits placement, and explain the board better | ||
|
|
2eca9de09f | various fixes. added version#s and added a playable browser build of the solitaire game (including deploy to filebrowser script) |