3.9 KiB
ADR 0006: Vendor-neutral observation sources and live-only timeline
Status: accepted for the experimental Mission Core runtime, 2026-07-16.
Context
The spatial scene and camera workspace must accept one device, a custom rig or a future multi-sensor vehicle without adding vendor-specific branches to the host UI. The currently verified K1 profile exposes one spatial visualization path and two independent H.264 camera preview producers. The browser does not yet have a camera delivery adapter, a shared point-cloud/video clock or confirmed camera intrinsics/extrinsics.
Hard-coded camera slots, direct RTSP URLs in React components and an apparently seekable timeline would therefore create three false contracts: a fixed sensor count, browser ownership of device transport and replay that does not exist.
Decision
- A device plugin normalizes its capabilities into
ObservationSourceDescriptor[]. Mission Core consumes only these generic descriptors. ididentifies a runtime source instance;sourceIdidentifies the producer inside the plugin model;semanticChannelIddescribes the canonical channel. Transport addresses are not identities.- Provider metadata and device/session/acquisition binding are separate. A new acquisition may change layout context without changing the logical producer.
- The host owns visibility, z-order, position, resize and fullscreen. A plugin cannot inject global layout behavior.
- Direct device RTSP URLs do not cross into the generic UI. A future read-only camera adapter must publish a browser-decodable local delivery URL.
- Until a bounded buffer and clock mapping exist, the shared timeline is
live-only,seekable=false,sessionRecording=falseand explicitly markedhost-arrival-best-effort. - Directional 3D camera frustums are not rendered until calibration and extrinsics are available and verified. An unresolved camera may be listed as a source, but its orientation must not be invented.
Current K1 mapping
| Producer | Canonical channel | Host representation |
|---|---|---|
sensor.lidar.primary |
spatial.point-cloud.live |
primary Rerun viewport |
sensor.camera.left |
camera.preview.live |
auxiliary media window / camera card |
sensor.camera.right |
camera.preview.live |
auxiliary media window / camera card |
Both camera producers share the proven canonical channel and remain distinct by
sourceId. Their current state is declared: the compatibility profile proves
the channels, but no browser preview URL is advertised yet.
UI consequences
- The spatial scene source picker renders any number of plugin-published sources.
- Auxiliary media uses the design-system
WorkspaceWindow, constrained to the scene bounds, with controlled drag, resize, close and maximize state. - The Cameras workspace filters media modalities and renders 0, 1, 2 or N cards; only its grid scrolls when the source count exceeds available space.
- Point-cloud focus and camera focus stay inside the application panel rather than taking over the browser viewport.
- Empty and declared channels remain honest placeholders; no demo frames or synthetic sensor values are substituted.
Follow-up gate
The next implementation step is a plugin-owned, read-only H.264 adapter that terminates RTSP/RTP locally and exposes a browser-supported stream plus measured per-source metrics. Synchronized rewind becomes eligible only after the adapter provides bounded buffering and an evidenced mapping between the RTP 90 kHz clock and the spatial stream clock.
Code anchors
apps/control-station/src/core/runtime/contracts.tsapps/control-station/src/core/observation/useObservationLayout.tsapps/control-station/src/components/ObservationSources.tsxapps/control-station/src/components/ObservationTimeline.tsxapps/control-station/src/workspaces/Workspaces.tsxapps/control-station/src/device-plugins/xgrids-k1/observationSources.ts