Feature/replay simulation mode#3
Merged
Merged
Conversation
Summary:
- Added replay/source-mode shared types and REPLAY_LOG_SCHEMA_VERSION = 1
to packages/shared (TelemetrySourceMode, ReplayStatus, ReplayTimingMode,
ReplaySpeedMode, ReplayLogEvent union, NormalizedReplayEvent,
ReplayLogMetadata, ReplayDiagnostics, ReplayControllerState,
SimulationScenario/Options).
- Set up Vitest in apps/web (node env, src/**/*.test.ts) with test/
test:watch scripts; added vitest dev dependency.
- Implemented the replay parser: JSONL + JSON-manifest forms, legacy
{time,type,data}, plain TelemetryState lines, comment/empty-line
skipping, synthetic 20 Hz timeline, non-monotonic preservation, and
metadata extraction (counts, duration, hasGps/Battery/Radio/Attitude).
- Added parser fixtures and 13 parser tests.
- No UI integration yet.
Summary:
- Added apps/web/src/replay/scheduler.ts: a pure, timer-free scheduler
core with no React state, timers, DOM, rAF, or wall-clock reads.
- Functions: advanceTo, stepOnce, seekTo, reset, plus eventVirtualTimeMs
and totalDurationMs helpers.
- Implements all four timing modes:
- original — emit events with mapped time <= virtual time
- fixedRate — index-based cadence (N * 1000/Hz), ignoring original gaps
- manual — no auto-advance; stepOnce only
- max — capped chunks/frame (DEFAULT_MAX_EVENTS_PER_CHUNK = 1000),
always finishes on the last event
- seekTo rebuilds from index 0 for deterministic state/track reconstruction.
- Seeks are clamped; stepOnce is idempotent at the end.
- Added 14 scheduler tests using synthetic timestamps (no fake timers).
…rack
Summary:
- Added apps/web/src/replay/reconstruct.ts (pure):
- applyEvent: full telemetry events replace state (merged onto a fresh
empty state to normalize + sanitize); partialTelemetry events deep-merge.
- deepMerge drops NaN/Infinity and out-of-range GPS (lat ∉ [-90,90],
lon ∉ [-180,180]) without wiping existing fields; unknown fields pass
through without crashing.
- foldEvents builds telemetry state + a deduplicated controlled track
(TrackPoint[]); stationary positions don't append duplicate points.
- reconstructUpTo rebuilds deterministically from index 0 for seek/restart.
- Reuses lib/geo validCoordinate and lib/initialTelemetry defaults.
- Added 9 reconstruction tests (full replace, partial merge preservation,
invalid-value rejection, unknown-field safety, track dedup, determinism,
seek forward/back, incremental == full rebuild).
Summary:
- Added apps/web/src/replay/simulation.ts (pure, deterministic):
- mulberry32 PRNG (no dependency), bounded ReplayEvent[] generation.
- Scenarios: nominalFlight, weakRadioLink, gpsDegradation,
lowBatteryApproach, each with distinct battery drain, RSSI, and GPS
behavior plus deterministic lifecycle/warning activity events.
- generateSimulationEvents + generateSimulationMetadata; no wall-clock
reads (absoluteTsMs always null, timeline starts at 0).
- 9 simulation tests (determinism, rate/shape, scenario effects).
- Added apps/web/src/hooks/useReplayController.ts:
- Stateful engine wrapping the tested scheduler + reconstruction cores.
- Thin requestAnimationFrame driver; commits React state once per frame.
- load/start/pause/resume/stop/restart/seek/step, timing-mode/speed/
fixed-rate setters, tagged [REPLAY]/[SIM] activity log, separate
ReplayDiagnostics, deterministic seek/restart (track never duplicates).
- Idempotent controls, duplicate-rAF guard, cleanup on unmount, and a
sessionStorage reload marker (handoff §12). Never touches serial.
Summary:
- Added apps/web/src/hooks/useTelemetrySource.ts:
- Wraps live useTelemetry() + useReplayController() behind one
dashboard-facing surface (same field names the dashboard already uses).
- Owns activeSourceMode; displayed telemetry is selected from the active
mode while live/replay/sim telemetry stay internally separate.
- Live telemetry keeps running in the background during replay/sim;
exposes liveConnectedInBackground and liveControlsLocked.
- GUARDS live session-mutating actions (connect/disconnect/reset/logging/
refreshPorts) to no-op while a non-live mode is active — defense in depth
so replay/sim can never trigger serial writes or reconnect logic.
- Merges live + replay/sim activity logs (newest first, capped at 200);
clearLogs clears both.
- Switching directly between replay and simulation halts the rAF driver
and discards the prior load so no stale data shows under the wrong banner.
Summary: - App.tsx now uses useTelemetrySource(); adds a persistent non-live banner (REPLAY/SIMULATION) and an inset color tint around the dashboard. - MapPanel: added controlled-track support (controlledTrack + trackMode). Live mode is unchanged (internal append-on-change track); replay/sim render exactly the controller-provided track and never append. Clear Track button is hidden in controlled mode. - Topbar: added Live/Replay/Simulation segmented control + colored source badge (green/amber/purple), the "Live connected in background" notice, and disabled all live serial controls (port/baud/refresh/connect/disconnect/ reset/logging) while a non-live mode is active. - New ReplaySimPanel: file picker with ~25 MB warn / ~100 MB hard-refuse guards (raw text read locally, never stored in state), metadata summary, transport controls (start/pause/resume/stop/restart/step), seek bar, speed/timing-mode/fixed-rate selectors, scenario+seed+duration+rate form for simulation, and a diagnostics readout. Shows the GPS/privacy note.
Summary:
- Node writer (apps/server/src/services/loggerService.ts): now records the
v1 schema { schemaVersion, ts, relativeMs, source:"live", type:"telemetry",
state } instead of legacy { time, type, data }. Captures sessionStartMs on
start() so relativeMs = ts - sessionStartMs. Log location and start/stop UX
unchanged.
- Rust/desktop writer (apps/desktop/src-tauri/src/lib.rs): same v1 schema;
added LoggerState.session_start_ms (set on start_logging), and
write_log_if_active now emits schemaVersion/ts/relativeMs/source/state using
saturating_sub for relativeMs.
- The replay parser already reads both v1 and legacy {time,type,data}, so old
logs remain replayable and new logs replay without conversion (covered by
the existing basic-flight.jsonl v1 fixture + legacy-flight.jsonl fixture).
Summary: - Added docs/replay-mode.md: source modes (Live/Replay/Simulation), replay usage + size guards, transport/timing/speed controls, simulation scenarios, JSONL v1 + legacy log format, parser tolerance rules, privacy/security notes (GPS, no upload, untrusted input), diagnostics, and how to run tests. - README: added Replay & Simulation to the feature list with links to docs/replay-mode.md and ADR 0003.
gitfeber
added a commit
that referenced
this pull request
Jun 8, 2026
Feature/replay simulation mode
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request introduces frontend-only replay and simulation modes, enabling the dashboard to display recorded or synthetic telemetry data without requiring a live hardware connection. It standardizes the log file schema for compatibility with the new replay engine, updates the UI to clearly indicate the active source mode, and ensures the map and track rendering behave correctly across live, replay, and simulation modes. Additional developer tooling and documentation improvements are also included.
Replay & Simulation Mode Support:
Added replay and simulation as selectable telemetry sources in the frontend, allowing users to view recorded
.jsonl/.jsonlogs or run deterministic simulations, with clear UI indicators and controls for source mode selection. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]Updated the
MapPanelcomponent to support a controlled track mode, rendering replay/simulation tracks deterministically and disabling internal track appending when not in live mode. [1] [2] [3] [4]Log Schema and Backend Updates:
schemaVersion,ts,relativeMs,source,type, andstate, ensuring compatibility with the replay engine and future extensibility. [1] [2] [3] [4] [5] [6] [7]Documentation Improvements:
README.mdandCONTEXT.mdto clarify terminology and describe the new replay and simulation capabilities, including references to relevant ADRs and technical docs. [1] [2]Developer Tooling:
vitestand related scripts to the web app'spackage.jsonto enable unit testing. [1] [2]