configWith let the day count and the Revenue floor disagree

minCombinedRevenue fell back to SOLO_CONFIG's constant — the floor for a
FIVE-Day game — whatever days said. configWith({ days: 1 }) asked a
one-Day game to clear 15, which a full five-Day game averages barely
half of; configWith({ days: 10 }) asked for that same 15. It derives
from the days it was given now.

Not a live fault: createLocalSession is the only caller and the page
always writes the floor itself, so no dealt game was ever wrong. Found
by a throwaway probe that passed only days — which is how the next
caller would reach for it. Unchanged at the default day count, since
SOLO_CONFIG's floor is this same formula at DEFAULT_DAYS.

Stays in the unshipped v0.7.9 per Jesse — no version bump for the next
several fixes. 873 tests pass, three new.

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:51:11 -04:00
co-authored by Claude Sonnet 5
parent e035dda5a3
commit 45cf521a40
3 changed files with 61 additions and 3 deletions
+30
View File
@@ -32,6 +32,8 @@ import { createGame as createEngineGame } from '../src/engine/setup.ts';
import { advance as advanceEngine } from '../src/engine/advance.ts';
import type { GameConfig } from '../src/engine/state.ts';
import {
configWith,
SOLO_CONFIG,
overHandLimit,
actionGroups,
actionMenu,
@@ -3339,6 +3341,34 @@ describe('the Day rolling over says so (Gitea#10)', () => {
// ---------------------------------------------------------------------------
describe('configWith', () => {
/**
* The Revenue floor is a function of how long the game is, so a helper that takes `days` and
* defaults the floor has to derive it. It fell back to `SOLO_CONFIG`'s five-Day constant until
* 2026-08-30, which let the two fields disagree: a one-Day game was asked to clear 15, a floor a
* five-Day game averages barely half of. Found by a probe that passed only `days` — which is how
* the next caller would reach for it.
*/
it('derives the Revenue floor from the days it was given', () => {
assert.equal(configWith({ days: 1 }).minCombinedRevenue, 3, 'a one-Day game kept the five-Day floor');
assert.equal(configWith({ days: 10 }).minCombinedRevenue, 30, 'a ten-Day game kept the five-Day floor');
});
it('leaves the default day count exactly where it was', () => {
// The fix must not move the floor anybody is actually playing against: SOLO_CONFIG's own floor
// is this same formula at DEFAULT_DAYS, so the default path is unchanged.
assert.equal(configWith({}).minCombinedRevenue, SOLO_CONFIG.minCombinedRevenue);
assert.equal(configWith({ days: SOLO_CONFIG.days }).minCombinedRevenue, SOLO_CONFIG.minCombinedRevenue);
});
it('still lets a caller name a floor that has nothing to do with the length', () => {
// Deriving is the DEFAULT, not a rule — the New Game dialog and the lobby both let a player set
// a floor directly, and that has to survive being passed through here.
assert.equal(configWith({ days: 10, minCombinedRevenue: 4 }).minCombinedRevenue, 4);
assert.equal(configWith({ days: 3, minCombinedRevenue: 0 }).minCombinedRevenue, 0, 'an off floor was re-derived');
});
});
describe('the end-of-game results screen (Gitea#16)', () => {
/**
* A finished game, built by running the clock off the end of a real one rather than by hand — the