# ADR 0006: Vendor-neutral observation sources and live-only timeline

Status: accepted for the experimental Mission Core runtime, 2026-07-16.

Scope update, 2026-07-17: the live device descriptors in this ADR remain
live-only. ADR 0008 adds a separate host-owned recorded-source catalog,
seekable `session_time` playback and workspace layout; it does not retroactively
turn a live RTSP lease into recorded evidence.

## 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 path-labelled H.264 camera preview producers. The direct physical gate showed
that only one K1 preview producer can deliver frames at a time. A shared
point-cloud/video clock and camera intrinsics/extrinsics remain unavailable.

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

1. A device plugin normalizes its capabilities into
   `ObservationSourceDescriptor[]`. Mission Core consumes only these generic
   descriptors.
2. `id` identifies a runtime source instance; `sourceId` identifies the producer
   inside the plugin model; `semanticChannelId` describes the canonical channel.
   Transport addresses are not identities.
3. Provider metadata and device/session/acquisition binding are separate. A new
   acquisition may change layout context without changing the logical producer.
4. The host owns visibility, z-order, position, resize and fullscreen. A plugin
   cannot inject global layout behavior.
5. Direct device RTSP URLs do not cross into the generic UI. The read-only K1
   adapter publishes an opaque, same-origin fMP4/WebSocket delivery lease.
6. A descriptor may declare a generic activation group, capacity and selection
   state. The K1 camera producers share one group with `maxActive=1`; frontend
   layout enforces it for UX and the plugin remains the backend authority.
7. Until a bounded buffer and clock mapping exist, the shared timeline is
   `live-only`, `seekable=false`, `sessionRecording=false` and explicitly marked
   `host-arrival-best-effort`.
8. 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`. The plugin publishes both catalog rows dynamically, but delivery is
present only on the selected producer. Selecting the peer tears down the old
RTSP/FFmpeg generation before a new browser lease is issued.

## 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 local laboratory adapter now terminates RTSP/RTP with FFmpeg, copy-remuxes
H.264 High L4 without transcoding and publishes complete bounded fMP4 segments
to a generic MSE player. ADR 0008 subsequently added acquisition-owned durable
segments, a prepared recorded-media manifest and host-arrival-best-effort rewind
on the saved-session timeline. This is not proof of a shared device clock or
frame-accurate LiDAR/camera alignment. Portable FFmpeg packaging,
multi-consumer fan-out and remote/WAN delivery remain open. See ADR 0007 and
ADR 0008.

## Code anchors

- `apps/control-station/src/core/runtime/contracts.ts`
- `apps/control-station/src/core/observation/useObservationLayout.ts`
- `apps/control-station/src/components/ObservationSources.tsx`
- `apps/control-station/src/components/ObservationTimeline.tsx`
- `apps/control-station/src/workspaces/Workspaces.tsx`
- `plugins/xgrids-k1/frontend/src/observationSources.ts`
- `src/k1link/device_plugins/xgrids_k1/camera.py`
