fc40fc39edea0be68910a9ff183af6b60e499294
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
fc40fc39ed |
v0.8.0.4 — take the test server's name back out of the tracked files
Both repositories allow anonymous clone — checked rather than assumed: info/refs for git-upload-pack answers 200 for each, git-receive-pack answers 401. So everything committed here is public, and tracked files are supposed to carry placeholders rather than real hosts. Ten mentions added while building v0.8.0 are now "the test server" or "the target hardware", across CHANGELOG.md, the common-board plan's three deferral banners, sim/pacing.ts, and two test files. Prose and comments only, no behaviour; the quotes are untouched, because what was said about bot pacing is the part worth keeping. Left alone deliberately: nineteen older mentions in entries about v0.7.5, v0.7.6 and v0.7.8 and in TODO.md, since rewriting a changelog after the fact makes the record less true; and scripts/deploy-web.ts, where the host is the functional default for FB_URL rather than prose — turning that into a required variable changes how deploying works and wants deciding on its own. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X6cF1iYvJ1kNmzYBzu4QX6 |
||
|
|
c10f52791e |
v0.8.0.2 — the speed control that was only ever a URL parameter, and a Day-end
contradiction Two things found by playing v0.8.0.1, neither in the mechanism itself. ?pace= never worked. index.html's doors are play.html?lobby and play.html?solitaire, so arriving through the splash replaces the query string and the play page only ever saw ?lobby — a whole game was played at 1x while believing it was at 7x. v0.8.0 shipped that parameter as the only way to change speed and the game's own front door destroyed it. There is a control on the play screen now, beside zoom, persisted per viewer; the doors carry pace through as well, so the URL lever is honest for handing two playtesters different speeds. PACE_LEVELS moved to sim/pacing.ts with DWELL and MAX_PACE — the tuning surface in one file, and testable. The committed default is unchanged: what it should be is a question for a game played at a speed that took effect. And the Day-end dialog said "0 today, 2 in all". advance.ts increments the Day and then zeroes collisionsToday, and noteDayEnd() fires when the Day goes up — so the dialog reporting the Day that just finished was drawn from the very frame in which that Day's count was reset. Reproduced on four of five seeds before changing anything. The count is captured at the rollover now; it is not derivable on the client, because in multiplayer the push announcing the new Day is the same push that carries the reset. And "today" was the wrong word regardless: it names the Day instead — "Collisions: 2 on Day 1, 2 in all". Unrelated to v0.8.0 — that one has been wrong since the dialog was built for Gitea#10, and needed somebody to play a Day with a collision in it and then read the summary. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X6cF1iYvJ1kNmzYBzu4QX6 |
||
|
|
02289e94b8 |
v0.8.0 — the board replays what everyone else did, instead of arriving rearranged
TODO #13, #15 and #18 — Gitea#20 steps 2-4 pointed at a seated player's own screen. Every accepted intent, and every automatic phase that does anything, becomes an ordered presentation step. A bot's whole switching turn used to land in one push; now it arrives as a run of steps, the district panel follows whoever is acting, and a [N behind] … [Skip] row says how far the board is from the game. Solitaire runs the same path — one collector inside submit(), which both session kinds already funnel through — which is where its automatic phases finally get a visible beat. Dwell is assigned by kind: switching holds the screen, turn bookkeeping costs nothing, and the clock turning over earns the beat. Tunable per viewer without a rebuild, and off entirely at pace 0. Also: switching was the one class of action logging unattributed, and now names its train. Reasoning, measurements and the three things that turned out wrong are in CHANGELOG.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X6cF1iYvJ1kNmzYBzu4QX6 |
||
|
|
312e0301e0 |
v0.7.9.8 — the test command did not typecheck, and the plan had gone stale
Housekeeping before v0.8.0: the answer to "anything else that should be looked at first". One real hole, one stale document, and my own leavings. #102 — `npm test` passed green on a type error. `pretest` ran `scripts/build-web.ts`, which invokes `tsc --ignoreConfig` against three web entry points, so it saw only what those three transitively import and under a WEAKER configuration than tsconfig.json — no `noUncheckedIndexedAccess`, no `exactOptionalPropertyTypes`, `--types ''`. It never saw `src/server/` or a single file under `test/`. Demonstrated rather than argued: a planted `const DELIBERATE_TYPE_ERROR: number = 'not a number';` in src/server/session.ts gives `npm run typecheck` a TS2322 and `npm test` a clean `# fail 0`. `pretest` is `tsc --noEmit && node scripts/build-web.ts` now, and the same error exits 1 with the tests never running. This mattered THIS week rather than generally: v0.8.0 is steps 2-7 of the common board — display stream, credentials, persistence, Chromium supervisor — which is almost entirely src/server/, exactly the half the test command could not see. #103 — the plan had drifted from the code it is the source for. docs/plans/jitsi-common-board.md was written 2026-08-27, still said "No implementation has been performed", and is what steps 2-7 get built from. Step 1 shipped across four releases since, so every "current code finding" under it described a fault that is now fixed — a document reading as present tense and nine days stale sends the next reader to fix things twice. Measured: its PublicFrame sketch lists four properties never built (protocolVersion, config, scoring, deckCounts) and omits 28 that exist, and the shape is the real difference — the implementation is FLAT where the plan grouped things into objects, so a renderer written from the sketch would not compile. The plan now says so at the top and at step 1, names src/sim/view.ts and the redaction allow-list as the authority, keeps the original sketch for its reasoning, and calls out `protocolVersion` as unbuilt rather than dropping it quietly — step 2 is the reconnecting display stream and is the first thing that would want one. One step-1 item is STRUCK OFF rather than built: "add the Red Flag holder to the public player projection". The premise does not hold here. `decks.redFlags` is written once, in setup.ts, from `optionalRules.emergencyToolbox`, and never again — `redFlag.play` emits `phaseEnded` and does not spend it — so every player holds one or none does, decided before the deal. A per-player `redFlagHeld` would be one already-public option copied N times, while telling every reader of the common board that it varies by player and might change mid-game. Worse than the absence. Pinned by test so it is not re-raised from the plan. Four dead imports removed, all mine: `HAND_LIMIT` left unused in apply.ts, view.ts and web/game.ts when 0.7.9.6 consolidated the three copies of the §6.2 test, and `actingPlayer` in web/game.ts, dead since 0.7.9.5 made `currentActor` delegate. Finding them re-measured #46: `tsc --noUnusedLocals` now reports 40, up from 29 on 2026-08-30. That entry's "without the flag this list simply regrows" is a measurement rather than a forecast now. The other 36 and the flag stay open. 946 tests pass, up from 943. No behaviour changes: three new tests pin an invariant, and the rest is a build command, dead imports and a document. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y5boPxP6JHRYMm8adXaF5R |
||
|
|
d5445badcc |
v0.7.9.5 — two answers to one question, and the copy nobody read
Both faults are in what 0.7.9.4 had just built, and both are the same shape: a second copy of an answer that agreed with the first until it didn't. #96 — the §3.3 vote has no actor, and the screen named one anyway. The vote is PARALLEL: every un-voted seat may vote at any moment, in any order, one refusal ends it, and `apply.ts` says where it accepts one that there is no actor to be. The turn chart named the last seat to move before the timetable ran out — no more claim on the vote than anybody else — directly above a tally correctly showing three seats outstanding. The cause is worth more than the symptom. `currentActor(game)` (`web/game.ts`) guarded on `status !== 'active'`; `currentActorOfState` (`sim/view.ts`), added the same day in #95 and the one the frame calls, did not, so it handed back whatever `clock.currentActor` was left holding. The view now carries the guard and `currentActor` delegates to it. That matters more than the tidiness: `currentActor` is what REFUSES an intent, so a screen answering differently tells the table to wait on a player the server would turn away. The fourth of this class after Gitea#21, #22 and #94 — but the first found by asking a view helper its question in a state the game is not `active` in, which is the generalisation and is cheaper than finding the fifth the same way. #97 — narration reaches a seat once, by one path. `Frame.lines` carried the whole log on every push to every seat, and nothing read it: `RemoteSession` accumulates from `push.lines` alone and its `lines()` returns that accumulator, so the log was serialised into every frame, grew all game, and was discarded on arrival while `linesSince` sent the same text correctly beside it. The duplicate was masking a bug rather than merely wasting bandwidth. `connect()` cleared `lastFrame` but not `sentLines`, so a reconnecting seat was told "nothing new since your last push" while the browser it answered had just reloaded from an EMPTY accumulator — the history panel came back blank, mid-game, with the server holding the whole log. So the two halves are one change, and the plan's instruction taken alone ("stop passing the full game log into `frameFor()`") would have deleted a real behaviour rather than a duplicate. Every remaining reader of `Frame.lines` was checked before the field was emptied: all of them are the solitaire and replay path, which builds Frames through `snapshot()` directly and never goes near a session. One test was wrong before the code was. The first draft of the reconnect test connected inside its own fixture, so both sides of the comparison were the empty array and it passed against the broken server. Each test now asserts its premise is non-empty before comparing. Also: `docs/plans/jitsi-common-board.md` is committed. It was never added — not ignored, just missed — while TODO.md cites it twice as the plan for all of v0.8.0 and the last two releases were built from it, so a clone got a TODO pointing at a file that did not exist. 917 tests pass, up from 909. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y5boPxP6JHRYMm8adXaF5R |