feat: v0.19.0 — ISS-011 auto-slow to 1x when all planes have landed
CI / build + unit + e2e (pull_request) Successful in 6m14s

This commit is contained in:
2026-09-19 18:07:42 +00:00
parent f0602453ea
commit 86379fc9c6
9 changed files with 261 additions and 7 deletions
+8
View File
@@ -1,5 +1,13 @@
# Changelog
## v0.19.0 — 2026-09-19 18:05
- **Auto-slow to 1× when all planes have landed (ISS-011).** When the last plane in flight lands, the sim slows down on its own so an idle fleet doesn't sit at 1000×. Server-side and authoritative: `tickOnce` (`lib/sim/engine.ts`) now remembers how many planes `deliverPackages` finalized during a tick, and when ≥1 plane landed this tick AND no plane remains with status `'flying'` AND the sim is not paused, it persists `timeScale = 1` on the same `sim_state` write as the clock — so the UI slider reflects it on the very next snapshot (no API or OpenAPI change: timeScale is still set via the existing `POST /api/sim`, and `clampTimeScale` semantics are untouched since 1 is a valid ladder value)
- **Arrival-triggered, not idle-enforced.** The trigger fires only on the tick that processes a landing — a grounded fleet at high scale with no flight ever happening is left alone (this keeps the existing slider e2e in `panes.spec.ts` green: it sets 1000× and expects the server to confirm it while nothing is flying). Paused state is untouched: while paused no landings are processed, so a paused sim never auto-slows
- **No auto-restore by design.** The previous scale is not remembered — once the game slows to 1× after the last landing, the player speeds up manually again (slider or `POST /api/sim`). Deliberately minimal scope: no "resume my old speed" behavior
- Tests: unit — new `describe('auto-slow …')` block in `lib/sim/engine.test.ts`: last plane lands → stored timeScale becomes 1; a landing while another plane is still flying → no change; already at 1× → stays 1; paused sim with all planes landed → no change. e2e — new `e2e/auto-slow.spec.ts` (serial mode, SCALE=1000, self-heal fly-home in afterEach like relocation.spec.ts): sets 1000× via the API, dispatches plane-starter on the shortest leg from its hub (EDDF → nearest airport), waits for the landing and asserts the server's `timeScale` is exactly 1 in that snapshot, then proves manual override still works (`POST /api/sim {timeScale: 1000}` confirmed by response + fresh snapshot)
- **e2e suite adapted to the new behavior.** Every existing spec that flies out-and-back relied on 1000× persisting across a landing — with ISS-011 it no longer does, so each return leg now re-sets SCALE explicitly: `flyHomeViaApi` in actions/relocation/right-pane/hover (re-set before the repositioning flight after waiting for an in-flight leg to land) and the restore legs inside the test bodies of actions.spec.ts (core loop, expired packages, validation paths ×2), right-pane.spec.ts (fly-to-destination, refuel-for-leg) and hover.spec.ts (flying-plane route highlight). map-interactions.spec.ts needed no change — its `loadAndFly` helper already re-sets SCALE before every landing wait
- Verified: `tsc --noEmit` clean; unit suite green locally; e2e not run locally by design — CI verifies against an isolated stack
## v0.18.0 — 2026-09-19 16:02
- **Relocate a grounded (empty) plane to any airport (ISS-010).** `flyPlane` has allowed pure repositioning since v0.12.0, but the UI only exposed flying for planes that carried cargo — an empty grounded plane had no fly control anywhere. Two new surfaces now drive the EXISTING `POST /api/planes/{id}/fly {destIcao}` endpoint (no API or OpenAPI change):
- **Right-pane market row** (`components/RightPane.tsx`): a fourth `.market-row` with `[data-testid="relocate-plane"]` (grounded planes, "ATR 72-600 — EDDF" labels), `[data-testid="relocate-dest"]` (all airports from a one-time `GET /api/airports` fetch per page life — same promise-ref pattern as Map.tsx — sorted by name for stable e2e selection) and the `[data-testid="relocate-go"]` "Relocate" button, disabled while busy or until both selects have a value. Same effective-selection + `runAction` pattern as the buy/sell/refuel rows (first grounded plane / first airport preselected); the row wraps (`market-row-relocate`) since two selects don't fit one 360 px line