v0.59.0 — SSE frames drop terminal package history (#133) #134

Merged
kamilkrzywda merged 1 commits from feat/sse-payload into master 2026-09-23 08:06:45 +02:00
Owner

Closes #133

Measured first (live v0.58.0): each /api/events frame was compact JSON at ~597 KB, pushed exactly once per real second regardless of time scale (background tick is a fixed 1 s interval; ×1000 only advances the clock further per frame). 99.8 % of it was packages: 1,521 rows — terminal packages are never deleted from the DB (expired 564, delivered 528, ignored 386, abandoned 31) while only 12 were open. No component reads a terminal-status package: the market renders open, on-board cargo is loaded/expired.

Fix: new sseFrame(snapshot) in lib/game/state.ts projects to the client-rendered statuses (SSE_PACKAGE_STATUSES = open|loaded|expired). Used by both SSE paths — the broadcast in lib/sim/engine.ts and the initial frame in app/api/events/route.ts. Live payload: ~597 KB → ~10 KB per frame (≈60×), bounded forever by fleet/market size instead of growing with play time.

Deliberately unchanged: /api/state and action responses keep the FULL package set, so every e2e oracle asserting delivered/abandoned transitions via state lookups still works; the polling fallback stays a strict superset of what SSE pushes. No hash-skip (the snapshot's clockMs advances on every tick even while idle — frames are never equal), no throttling (already 1 Hz), no diff/patch engine.

Tests: unit +3 in new lib/game/state.test.ts; e2e/events.spec.ts now asserts no terminal status ever appears in a frame and frames stay < 200 KB. Local: tsc --noEmit clean, vitest 381/381 (baseline 378 + 3), playwright lists all 62 tests.

Closes #133 **Measured first (live v0.58.0):** each `/api/events` frame was compact JSON at **~597 KB**, pushed exactly **once per real second** regardless of time scale (background tick is a fixed 1 s interval; ×1000 only advances the clock further per frame). 99.8 % of it was `packages`: **1,521 rows** — terminal packages are never deleted from the DB (expired 564, delivered 528, ignored 386, abandoned 31) while only **12 were open**. No component reads a terminal-status package: the market renders `open`, on-board cargo is `loaded`/`expired`. **Fix:** new `sseFrame(snapshot)` in `lib/game/state.ts` projects to the client-rendered statuses (`SSE_PACKAGE_STATUSES = open|loaded|expired`). Used by both SSE paths — the broadcast in `lib/sim/engine.ts` and the initial frame in `app/api/events/route.ts`. Live payload: **~597 KB → ~10 KB per frame (≈60×)**, bounded forever by fleet/market size instead of growing with play time. **Deliberately unchanged:** `/api/state` and action responses keep the FULL package set, so every e2e oracle asserting `delivered`/`abandoned` transitions via state lookups still works; the polling fallback stays a strict superset of what SSE pushes. No hash-skip (the snapshot's `clockMs` advances on every tick even while idle — frames are never equal), no throttling (already 1 Hz), no diff/patch engine. **Tests:** unit +3 in new `lib/game/state.test.ts`; `e2e/events.spec.ts` now asserts no terminal status ever appears in a frame and frames stay < 200 KB. Local: `tsc --noEmit` clean, vitest 381/381 (baseline 378 + 3), playwright lists all 62 tests.
kamilkrzywda added 1 commit 2026-09-23 07:49:34 +02:00
kamilkrzywda scheduled this pull request to auto merge when all checks succeed 2026-09-23 07:52:02 +02:00
kamilkrzywda merged commit 1d9e9ade58 into master 2026-09-23 08:06:45 +02:00
kamilkrzywda deleted branch feat/sse-payload 2026-09-23 08:06:45 +02:00
Sign in to join this conversation.