From 81e71e843640dcc62b7de9a4785d9c63856c6b68 Mon Sep 17 00:00:00 2001 From: fireshaper Date: Sun, 4 Oct 2026 00:13:49 -0400 Subject: [PATCH] Config: 10-minute board period and 10-hour rest Co-Authored-By: Claude Opus 5.5 --- DECISIONS.md | 6 ++++++ apps/server/test/game.ts | 4 +++- apps/web/test/board-refresh.test.tsx | 7 ++++--- packages/content/src/data/config.ts | 6 +++--- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/DECISIONS.md b/DECISIONS.md index 57d4f15..f952f54 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -868,3 +868,9 @@ Implementation decisions not spelled out in `memory-bank/implementation-plan.md` - **Final screenshots are palette-quantized** (sharp `palette: true`, quality 90): 24 shots in 6 MB instead of 18 MB, with no visible banding in the art. - **The 500 KB chunk warning is accepted for now.** The UI kit and screens added about 27 KB to the main chunk; route-level code splitting (like the map's) can take it back under when the PWA work in Phase 11 looks at load size. + +## Config change: shorter board period and rest + +- **`contractBoardPeriodRealMinutes` 60 → 10 and `restGameHours` 60 → 10** (user request, after Phase 10D). At 60× compression a rest is now 10 real minutes, exactly one board period, so decision 0.5.46 still holds and its content test (rest in real time ≥ board period) is unchanged and passing. +- **Effects:** boards refresh every 10 real minutes and every contract expires at the end of its period, so offers turn over six times as fast. A rested pilot is back in 10 minutes instead of an hour. This also resolves the earlier note that the CR-004 example expected a short rest. +- **Two tests assumed a 60-minute period** and now derive their timing from config instead: the server's `testContract` helper (expiry = end of the board period) and the board-refresh countdown test. No game code changed. diff --git a/apps/server/test/game.ts b/apps/server/test/game.ts index 0e26870..456242d 100644 --- a/apps/server/test/game.ts +++ b/apps/server/test/game.ts @@ -3,6 +3,7 @@ import { content } from "@deadhead/content"; import { createGuestResponseSchema, playerStateSchema, type PlayerState } from "@deadhead/schema"; import { boardPeriodIndex, + boardPeriodMs, createDispatchRecord, createRepositionRecord, type Contract, @@ -105,7 +106,8 @@ export function testContract(overrides: Partial = {}): Contract { requiredSkill: null, requiredLongHaulLevel: 0, offeredAt: TEST_NOW, - expiresAt: TEST_NOW + 3_600_000, + // Contracts expire at the end of their board period (TEST_NOW is a period start). + expiresAt: TEST_NOW + boardPeriodMs(content.config), firstContact: false, ...overrides, }; diff --git a/apps/web/test/board-refresh.test.tsx b/apps/web/test/board-refresh.test.tsx index eceec1f..aee828f 100644 --- a/apps/web/test/board-refresh.test.tsx +++ b/apps/web/test/board-refresh.test.tsx @@ -5,11 +5,12 @@ import { screen, waitFor, within } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { useClock } from "../src/clock/clock"; +import { formatClock } from "../src/format"; import { fakeApi, renderApp, samplePlayerState } from "./render"; const period = boardPeriodMs(content.config); -// 17.5 minutes into a board period. -const NOW = Math.ceil(Date.parse("2100-01-01T00:00:00Z") / period) * period + 17.5 * 60_000; +// A quarter of the way into a board period (derived from config, whatever its length). +const NOW = Math.ceil(Date.parse("2100-01-01T00:00:00Z") / period) * period + period / 4; const periodEndsAt = (boardPeriodIndex(NOW, content.config) + 1) * period; const courier: Ship = { @@ -79,7 +80,7 @@ describe("board refresh and the nothing-here case (Step 10D.8)", () => { it("counts down to the next board period", async () => { renderApp(api([heavyJob]), "/contracts?location=earth"); expect(await screen.findByLabelText("Board refresh")).toHaveTextContent( - "New contracts in 42:30", + `New contracts in ${formatClock(periodEndsAt - NOW)}`, ); }); diff --git a/packages/content/src/data/config.ts b/packages/content/src/data/config.ts index 83a65bc..7df7068 100644 --- a/packages/content/src/data/config.ts +++ b/packages/content/src/data/config.ts @@ -23,13 +23,13 @@ export const gameConfig: GameConfig = { loanRepaymentShare: 0.3, // Courier price + Earth bay lease. dealLoanAmount: 5000, - contractBoardPeriodRealMinutes: 60, + contractBoardPeriodRealMinutes: 10, // Duty and rest (CR-004): about three Moon round trips, then rest. dutyLimitGameHours: 12, longHaulDutyBonusGameHours: 2, - // One board period (60 real minutes at 60× compression), so a rested pilot + // One board period (10 real minutes at 60× compression), so a rested pilot // always wakes to a fresh board (decision 0.5.46). - restGameHours: 60, + restGameHours: 10, firstContactChance: 0.1, firstContactPayoutMultiplier: 2, // One band per ship size, so every board has work for every ship (playtest fix):