v0.7.9 — solitaire setup screen feedback, and the dead settings it exposed

Four pieces of feedback from Jesse on the solitaire setup screen.

THE COLLISION LIMITS DID NOTHING IN SOLITAIRE. Asked to reword those
entries to "the game ends immediately and results in a loss", which was
unwriteable: advance.ts gated the §3.4 check on competitive/coop, and a
solitaire game's mode is 'solitaire'. Both limits were offered as live
settings, rode into the config, and never fired — the existing text was
already false. The exclusion was never a stated rule and nothing
recorded a reason for it. Jesse's ruling: the settings do what they say,
so the gate is gone rather than the controls.

Measured, not asserted — 200 standard developer-bot games:
loss/collisionFloor 1 in 200, Days played 5.00 -> 4.98 mean with a
minimum of 1, collisions per game unchanged at 0.14. Recorded in
TODO.md under Play Balance, since full-length figures predate it.

Extra start defaults to ownOffice: at one seat it is the same rule as
anyOffice (apply.ts only rejects another seat's start), so this is a
label fix with no gameplay effect.

Also: collision wording on all three screens, Employee Rotation reads
"not applicable for solitaire", and the save warning is legible at 14px
on an amber panel with buttons that say Continue Existing Saved Game and
Deal New Game.

869 tests pass, two new; one asserted the opposite of the ruling and
says so where it was reversed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AdG46Ja2PEDBkpqiDazMoX
This commit is contained in:
Jesse.Markowitz
2026-08-30 01:01:11 -04:00
co-authored by Claude Sonnet 5
parent 193800a649
commit f2c87b6871
9 changed files with 148 additions and 27 deletions
+19 -5
View File
@@ -1636,11 +1636,25 @@ function shiftChange(s: GameState, events: GameEvent[]): AdvanceResult {
events.push({ type: 'stageBegan', day: s.clock.day, stage: s.clock.stage });
}
// §3.4 — every mode but competitive-and-coop-only: a Day's collisions against `maxCollisionsPerDay`
// and the game's running total against `maxCollisionsTotal`. `0` disables either check. Flat, not
// scaled by player count — Jesse's call, 2026-08-20: more players is more independent chances to
// collide, not a bigger shared budget.
if (s.config.mode === 'competitive' || s.config.mode === 'coop') {
/**
* §3.4 — EVERY MODE, SOLITAIRE INCLUDED: a Day's collisions against `maxCollisionsPerDay` and the
* game's running total against `maxCollisionsTotal`. `0` disables either check. Flat, not scaled
* by player count — Jesse's call, 2026-08-20: more players is more independent chances to collide,
* not a bigger shared budget.
*
* SOLITAIRE WAS EXCLUDED UNTIL 2026-08-30 and nothing said so. The gate here read `mode ===
* 'competitive' || mode === 'coop'`, while `SOLO_CONFIG` carried both limits and the New Game
* dialog offered them as live settings — so a solitaire player could set a collision limit, read
* "the game ends in a loss" beside it, and crash as often as they liked. Found reviewing that
* screen's wording (Jesse, 2026-08-30); his ruling is that the settings should do what they say,
* so the gate is gone rather than the controls.
*
* A SOLITAIRE GAME CAN THEREFORE NOW END EARLY, which no measurement in `TODO.md` was taken
* under. At the shipped defaults (3 a Day, 5 total) it is a rare ending rather than a common one —
* the bot averages 0.06 collisions a game — but any figure quoted from a full-length run predates
* it.
*/
{
const perDayBreach =
s.config.maxCollisionsPerDay > 0 && s.collisionsToday >= s.config.maxCollisionsPerDay;
const totalBreach =