From 935d9b43f0e5b2f2d1ce75390805ed99412c8080 Mon Sep 17 00:00:00 2001 From: fireshaper Date: Sat, 3 Oct 2026 21:43:09 -0400 Subject: [PATCH] Step 10D.1: duty limit, Long Haul duty bonus and rest config Co-Authored-By: Claude Opus 5.5 --- DECISIONS.md | 5 +++++ memory-bank/progress.md | 2 +- packages/content/src/data/config.ts | 6 ++++++ packages/content/src/schemas.ts | 6 ++++++ packages/content/test/config.test.ts | 10 ++++++++++ packages/content/test/schemas.test.ts | 3 +++ 6 files changed, 31 insertions(+), 1 deletion(-) diff --git a/DECISIONS.md b/DECISIONS.md index 1becd62..d8451bc 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -761,3 +761,8 @@ Implementation decisions not spelled out in `memory-bank/implementation-plan.md` - **Decision numbering:** the CR's 0.5.34–0.5.38 are recorded as **0.5.42 Duty clock, 0.5.43 Duty limit, 0.5.44 Finish the job, 0.5.45 Rest, 0.5.46 Rest covers a board refresh**, since 34–41 were already in use. - **Error code:** the CR's `pilot_resting` is `pilot-resting`, matching the API's kebab-case codes. - **Rest length vs. the CR's example:** the CR's rule sets the default rest to one board period (60 real minutes = 60 game hours at the current compression), but its worked example says a pilot "rests about 15 real minutes". The rule is explicit and test-enforced (decision 0.5.46), so it wins: default rest is 60 game hours (one real hour). Shortening rest would mean shortening the board period, which is a balance change for Phase 12. + +## Step 10D.1 + +- **Field names:** `dutyLimitGameHours`, `longHaulDutyBonusGameHours`, `restGameHours`. All in game hours, like other trip times. +- **The "rest ≥ board period" rule is a content test, not a schema refinement**, as the CR asks. The schema only requires the three numbers to be positive. diff --git a/memory-bank/progress.md b/memory-bank/progress.md index a917727..c044df0 100644 --- a/memory-bank/progress.md +++ b/memory-bank/progress.md @@ -164,7 +164,7 @@ Spec: `memory-bank/change-requests/CR-003-map-art.md`. New decisions recorded as Spec: `memory-bank/change-requests/CR-004-pilot-duty-rest.md`. New decisions recorded as plan §0.5.42–0.5.46. -- [ ] Step 10D.1 — Content config +- [x] **Step 10D.1 — Content config.** GameConfig gains `dutyLimitGameHours` (12), `longHaulDutyBonusGameHours` (2) and `restGameHours` (60 = one 60-minute board period at 60× compression). Tests: rest in real time ≥ board period; duty numbers positive. - [ ] Step 10D.2 — Sim: duty and rest functions - [ ] Step 10D.3 — Sim: validation and resolution - [ ] Step 10D.4 — Schema and database diff --git a/packages/content/src/data/config.ts b/packages/content/src/data/config.ts index 525a9bf..83a65bc 100644 --- a/packages/content/src/data/config.ts +++ b/packages/content/src/data/config.ts @@ -24,6 +24,12 @@ export const gameConfig: GameConfig = { // Courier price + Earth bay lease. dealLoanAmount: 5000, contractBoardPeriodRealMinutes: 60, + // 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 + // always wakes to a fresh board (decision 0.5.46). + restGameHours: 60, firstContactChance: 0.1, firstContactPayoutMultiplier: 2, // One band per ship size, so every board has work for every ship (playtest fix): diff --git a/packages/content/src/schemas.ts b/packages/content/src/schemas.ts index 22d5cb3..0cd583d 100644 --- a/packages/content/src/schemas.ts +++ b/packages/content/src/schemas.ts @@ -134,6 +134,12 @@ export const gameConfigSchema = z /** Loan taken on with the deal, in credits (decision 0.5.30). */ dealLoanAmount: positiveInt, contractBoardPeriodRealMinutes: z.number().positive(), + /** Game hours a pilot may fly before mandatory rest, at Long Haul 0 (decision 0.5.43). */ + dutyLimitGameHours: z.number().positive(), + /** Extra duty game hours per Long Haul level (decision 0.5.43). */ + longHaulDutyBonusGameHours: z.number().positive(), + /** How long a rest lasts, in game hours; at least one board period (decision 0.5.46). */ + restGameHours: z.number().positive(), firstContactChance: fraction, firstContactPayoutMultiplier: z.number().positive(), /** diff --git a/packages/content/test/config.test.ts b/packages/content/test/config.test.ts index da8e85f..2c65ef1 100644 --- a/packages/content/test/config.test.ts +++ b/packages/content/test/config.test.ts @@ -67,4 +67,14 @@ describe("game config", () => { const total = gameConfig.contractMassBands.reduce((sum, b) => sum + b.count, 0); expect(total).toBe(gameConfig.contractBoardSize); }); + + it("rests a pilot for at least one contract board period of real time (CR-004)", () => { + const restRealMinutes = (gameConfig.restGameHours * 60) / gameConfig.timeCompression; + expect(restRealMinutes).toBeGreaterThanOrEqual(gameConfig.contractBoardPeriodRealMinutes); + }); + + it("has positive duty numbers (CR-004)", () => { + expect(gameConfig.dutyLimitGameHours).toBeGreaterThan(0); + expect(gameConfig.longHaulDutyBonusGameHours).toBeGreaterThan(0); + }); }); diff --git a/packages/content/test/schemas.test.ts b/packages/content/test/schemas.test.ts index 4c5afbe..2b9c8cd 100644 --- a/packages/content/test/schemas.test.ts +++ b/packages/content/test/schemas.test.ts @@ -63,6 +63,9 @@ const validGameConfig = { contractBoardSize: 8, tutorialBoardSize: 50, contractBoardPeriodRealMinutes: 60, + dutyLimitGameHours: 12, + longHaulDutyBonusGameHours: 2, + restGameHours: 60, firstContactChance: 0.1, firstContactPayoutMultiplier: 2, contractMassBands: [