From 4b2f1b1a856bc47f813059e5bd76a722ddde312d Mon Sep 17 00:00:00 2001 From: fireshaper Date: Sat, 10 Oct 2026 23:29:29 -0400 Subject: [PATCH] Step 20.4: engine: event-queue catch-up Commands and the resolution loop replay arrivals and Independent pilots' decisions in time order, at most 7 days, in chunks with progress; the same time always gives the same save (decision 0.5.125). Co-Authored-By: Claude Opus 5.5 --- DECISIONS.md | 11 + apps/web/test/about.test.tsx | 2 +- memory-bank/architecture.md | 6 +- memory-bank/progress.md | 2 +- packages/engine/src/game/catchup.ts | 218 ++++++++++++++++++ packages/engine/src/game/company.ts | 4 + packages/engine/src/game/dispatch.ts | 20 +- packages/engine/src/game/engine.ts | 91 ++++++-- packages/engine/src/game/fleet.ts | 2 + packages/engine/src/game/independent.ts | 21 +- packages/engine/src/loop.ts | 4 +- packages/engine/src/notifications.ts | 2 + packages/engine/test/catch-up.test.ts | 171 ++++++++++++++ .../engine/test/ported/tutorial-board.test.ts | 1 + packages/engine/test/support.ts | 3 + packages/schema/src/save.ts | 25 +- packages/schema/test/save-fixture.ts | 8 +- packages/schema/test/save.test.ts | 10 +- 18 files changed, 566 insertions(+), 35 deletions(-) create mode 100644 packages/engine/src/game/catchup.ts create mode 100644 packages/engine/test/catch-up.test.ts diff --git a/DECISIONS.md b/DECISIONS.md index 53d9f62..41ae502 100644 --- a/DECISIONS.md +++ b/DECISIONS.md @@ -1692,3 +1692,14 @@ Implementation decisions not spelled out in `memory-bank/implementation-plan.md` - **Switching to Manual is immediate in the save**, and that already means "when the current trip ends": an Independent pilot only decides while idle, so a trip in progress finishes either way. - **Orders are kept even in Manual**, so switching back to Independent restores them. - **Local checks**: `pnpm -s typecheck` printed nothing while the web package had type errors (the exit code was 2). Types are now checked with `pnpm typecheck` and an "error TS" search. + +## Step 20.4 + +- **Decision points are stored, not derived**: each pilot keeps `nextDecisionAt`. A landing sets it to a turnaround after the arrival, or after the rest it triggers; setting a pilot Independent sets it to a turnaround from then. Rest, the shop and the first-look window each push it later; a wait sets it to the next board period's first-look end. Shop endings and rest endings need no events of their own: the decision point checks them. +- **Board periods matter only to waiting pilots**, so they appear as those pilots' next decision points rather than as separate events. +- **Arrivals resolve at their arrival time** (`resolvedAt` = arrival), not when the app notices them. Without this, splitting time would change Auto top-up credits and every later decision. +- **Ids made during catch-up are `ind--