smoke: jump (shared helper) + scan, then assert both events are in
GET /api/events with the newer one first, and that the EVENT LOG terminal
renders both T<turn> // <MESSAGE> lines. Idempotent across retries — asserts
on this run's own entries by turn/message, never absolute counts. state: the
latest five log lines come back identical (ids included) after the mid-run
container restart.
Self-fetching EventLogPanel (MissionPanel pattern — refetches on each tab
open). One terminal line per event: T<turn> // <MESSAGE>, newest first, with
the event's local time as the timestamp; new_game lines render as system
lines. Placeholder feed + now() removed from mission-control.
expand had no event assertion at all; build and mission-complete asserted
type/message but not the event's turn. Issue #11 requires every action type
to be covered with correct turn/type/message.
lib/game/events.ts: the latest N events of the save, newest first (ORDER BY
id DESC), with parseEventLimit for the optional ?limit= param (default 50,
cap 200, 400 otherwise). Unit tests cover default/accept/reject and
newest-first ordering + slicing.
CI run 358: the ACTIVE assertion used exact text but badge.tsx renders a
'●' dot prefix for ACTIVE variants (text is '●ACTIVE'), so it could never
match. And attempt 1's accept persisted an ACTIVE mission, leaving every
ACCEPT button disabled on retry. Drop exact matching and, when a leftover
active mission exists, assert the UI state and complete that one instead of
re-accepting.
smoke: pick an AVAILABLE contract (non-DELIVER preferred), accept it through
the UI (card flips ACTIVE, button disables), complete via API — scan loop for
EXPLORE/FIND, BFS jump path for DELIVER — assert DONE and the reward landed in
the hold. state: mission board deep-equal across the mid-run container restart.
Self-fetching MissionPanel (world-map pattern — refetches on each tab open,
accept responses applied directly). One card per contract: type title + state
badge, CONTRACT // #id line, objective, reward line, EXPLORE progress line.
ACCEPT enabled only when AVAILABLE and nothing else is ACTIVE. Placeholder
encounter content removed.
Routes call ensureSave first (mission functions assume an initialized save),
map MissionError to 404/409 and non-integer path ids to 400. OpenAPI spec in
code gains both paths + the Mission schema (12 -> 14 paths); openapi.test.ts
covers the new shapes.
New missions table (schema + DDL). Pure model in lib/game/missions.ts:
DELIVER / EXPLORE / FIND contracts generated from missionRng(seed, turn),
board always topped up to >=3 AVAILABLE after every action. save.ts wires
SCHEMA_VERSION 5 -> 6 with a v6 backfill step and completion hooks inside
jumpToSystem/explorePlanet (one atomic persist). Unit tests cover generation
determinism, top-up idempotency, backfill, accept validation and per-type
completion incl. reward accumulation.
Flight-Ops plumbing minus game code: in-memory WASM DB, persist() via tmp+rename,
globalThis singleton. Schema is empty at scaffold stage; _meta plumbing table stamps
created_at on first open so the ./db volume holds a valid SQLite file from boot
(a brand-new sql.js database exports as zero bytes). instrumentation.ts opens it at
server start behind a runtime-guarded dynamic import (keeps node:fs out of the Edge
instrumentation bundle).
lib/openapi.ts is the machine-readable spec (served at /api/openapi) per AGENTS.md;
info.version sourced from package.json. Unit tests pin the spec shape and version sync.
scificn-ui v0.1.0 integrated copy-paste per its docs: Button/Panel/Badge/Card/Alert
in components/ui/, cn() helper in lib/utils.ts, theme tokens in app/globals.css.
Deliberate deviation from upstream: --text-muted #4A4A40 -> #6B6B5C (+12pt lightness)
for readability on the near-black background (default SCI-FI theme only). Landing page
proves the integration; no game UI yet.
Prod compose: Traefik labels for space-wanderer.dev.kkhost.pl, ./db volume mount.
CI compose: project space-wanderer-ci on external network space-wanderer-ci-e2e with
the app pinned to static IP 172.39.0.10 (Flight-Ops mechanism verbatim, distinct
network name so both stacks coexist on the shared dind daemon), fresh named DB volume
per run. ci.yml: single 'build + unit + e2e' job — required status check name kept;
flaky-uplink retry loops, dep/browser caches, dind cleanup + prune carried over.