feat(k1): complete primary acquisition lifecycle
This commit is contained in:
@@ -15,7 +15,7 @@ and the bounded laboratory runtime seam in
|
||||
| `apps/control-station/src/core/device-plugins/frontendSdk.ts` | Public React host surface for reviewed frontend contributions | Versioned frontend Plugin SDK package surface |
|
||||
| `packages/plugin-sdk/` | Installable v0alpha2 Pydantic contracts and JSON Schema export | Portable host/plugin identity, lifecycle, stream and evidence boundary |
|
||||
| `plugins/xgrids-k1/` | v1alpha2 manifest, exact profile/loader and plugin-owned React connection/acquisition UI | Independently versioned XGRIDS device plugin |
|
||||
| `plugins/xgrids-k1/frontend/` | XGRIDS provisioning, acquisition/replay, diagnostics, metrics, runtime mapping and scoped CSS | Plugin-owned reviewed frontend contribution |
|
||||
| `plugins/xgrids-k1/frontend/` | XGRIDS provisioning, project/acquisition/replay, optional spatial controls, diagnostics, metrics, runtime mapping and scoped CSS | Plugin-owned reviewed frontend contribution |
|
||||
| `src/k1link/web/` | Local FastAPI host, fail-closed runtime handshake/transport seam, in-memory operation/acquisition lifecycle and generic session API | Generic host APIs plus isolated plugin supervisor |
|
||||
| `src/k1link/device_plugins/xgrids_k1/` | Physically isolated K1 BLE/MQTT/protobuf/LZ4/camera/replay/CLI compatibility implementation | Independently built XGRIDS device plugin process |
|
||||
| `src/k1link/data_plane/` | Transport-neutral decoded in-process consumer views | Local projections hydrated from portable SDK envelopes |
|
||||
@@ -32,7 +32,8 @@ The current K1 live/replay data path is:
|
||||
```text
|
||||
raw K1 transport
|
||||
-> raw-first evidence capture
|
||||
-> bounded preview queue
|
||||
-> injected K1 ModelingReport observer (device time/distance/speed)
|
||||
-> bounded four-message visual preview queue
|
||||
-> XGRIDS normalizer injected by the plugin facade
|
||||
-> DecodedPointCloudView / DecodedPoseView
|
||||
-> Rerun bridge
|
||||
@@ -44,12 +45,25 @@ The host-owned recorded path is separate from the disposable live preview:
|
||||
```text
|
||||
sealed or recovered native observation session
|
||||
-> SQLite catalog and bounded single-worker preparation
|
||||
-> atomic RRD cache v7 + immutable recorded-media manifest v2
|
||||
-> capture-clock-bound atomic RRD cache v9 + immutable recorded-media manifest v2
|
||||
-> generation-bound same-origin HTTP
|
||||
-> aggregate RRD/camera admission
|
||||
-> native Rerun HTTP receiver + recorded fMP4 player
|
||||
```
|
||||
|
||||
New K1 source generations durably publish
|
||||
`captures/mqtt_live/mqtt.timeline.origin.json` before camera production. MQTT
|
||||
shutdown adds provisional transport envelope `mqtt.timeline.json`; after camera
|
||||
and MQTT/runtime shutdown, the acquisition owner publishes content-addressed
|
||||
`mqtt.timeline.session-<sha256>.json` and atomically switches the capture-summary
|
||||
pointer while still holding the session lease. Only that `session` scope is
|
||||
eligible to advertise combined media replay. Cache v9 materializes both session
|
||||
envelope endpoints as real RRD rows and logs archived device-reported scan time,
|
||||
route distance and speed as scalar time series. A crash-recovered origin-only
|
||||
point/pose prefix falls back to its last validated message and cannot advertise
|
||||
camera media. Older valid sessions without the clock contract keep their
|
||||
first/last-message fallback and cannot acquire camera evidence retroactively.
|
||||
|
||||
Rerun does not import K1 protocol code, inspect MQTT topics or receive raw
|
||||
payloads. `VisualizationRuntime` cannot choose a vendor decoder implicitly; its
|
||||
composition owner injects one. The local `Decoded*View` classes are in-process
|
||||
@@ -73,7 +87,20 @@ selects a manifest model and mounts its `device.connection` component. Concrete
|
||||
XGRIDS source lives under `plugins/xgrids-k1/frontend`, imports the host only via
|
||||
`@mission-core/plugin-sdk`, and is connected by the single reviewed import in
|
||||
`apps/control-station/src/composition/devicePlugins.ts`. BLE/Wi-Fi provisioning,
|
||||
exact-profile confirmation and acquisition/replay UI are not Core components.
|
||||
exact-profile confirmation, project metadata, acquisition/replay UI and the
|
||||
optional K1 spatial-scene control block are not Core components. The host owns
|
||||
only the optional slot contract and generic actions such as opening the scene or
|
||||
releasing a prior manual/archive selection after a plugin source successfully
|
||||
starts.
|
||||
|
||||
A generic fail-closed guard blocks manual source input/apply/reset,
|
||||
saved-session switching and persisted replay reattach whenever the runtime
|
||||
reports a nonterminal acquisition. Unknown future acquisition states block by
|
||||
default. A plugin clears the previous host-selected source only after its start
|
||||
returns success, preserving the current scene on failure. That internal
|
||||
success-result transition is distinct from an operator switch. The guard does
|
||||
not stop equipment or invent a lifecycle transition; the acquisition must
|
||||
finish through its owning plugin.
|
||||
|
||||
## Experimental vocabulary, not Platform Ontology
|
||||
|
||||
@@ -115,6 +142,17 @@ transport mutation. Application-command publishing remains disabled; the
|
||||
separately reviewed BLE Wi-Fi provisioning write retains its own explicit
|
||||
operator gate.
|
||||
|
||||
An exact but inert K1 modeling-control substrate now lives inside the vendor
|
||||
plugin. It encodes the recovered start/stop protobuf shapes, strictly correlates
|
||||
response identity/action/numeric result and maps bounded device-status values
|
||||
into an observation-only state machine. Header construction is no longer
|
||||
guessed: callers provide explicit ASCII device ID and ASCII OpenAPI key, and the
|
||||
session ID is derived exactly as `${device_id}:ModelingRequest`. No MQTT import
|
||||
or publisher exists in that substrate. Legitimate OpenAPI key
|
||||
provenance/provisioning and stable-artifact proof after the stop lifecycle are
|
||||
still unresolved, so `vendor_writes_enabled=false` and every state-machine
|
||||
snapshot remains false for durable save completion.
|
||||
|
||||
## Semantic lifecycle
|
||||
|
||||
The transitional facade now creates separate provisional device,
|
||||
@@ -123,6 +161,20 @@ wait for receiver readiness, then wait for an external physical start, and becom
|
||||
data, wait for an externally confirmed stop, finalize and complete. Capture-only
|
||||
stop reports the K1 physical state as unknown.
|
||||
|
||||
Preparation requires a project name. The frontend and backend both apply NFKC
|
||||
normalization plus surrounding-whitespace trimming, reject control/surrogate
|
||||
characters and names above 96 Unicode characters, and store the result as
|
||||
session/catalog display metadata. It is not a path component. Because command
|
||||
publishing is off, the current integration does not claim that the name reaches
|
||||
K1.
|
||||
|
||||
The K1 contribution may mount a `SpatialControlsView` beside the host-owned
|
||||
viewport. It presents plugin lifecycle wording, the local stop action and live
|
||||
`ModelingReport` scan time, route distance and speed. Under the current
|
||||
capture-only profile the stop action seals local reception; it does not claim a
|
||||
device stop. `ModelingReport` is consumed before the visual preview queue through
|
||||
an injected observer, preserving the generic normalizer/Rerun boundary.
|
||||
|
||||
The operation journal is bounded and in memory. It records IDs, idempotency,
|
||||
declared deadlines, progress and terminal results without action parameters or secrets.
|
||||
It is not durable, distributed or recoverable after process restart.
|
||||
@@ -140,8 +192,7 @@ independently of browser delivery. The generic recorded player, manifest-v2
|
||||
validation and shared `session_time` controls are connected; historical sessions
|
||||
created before this archive contract contain no recoverable video, so physical
|
||||
recorded-camera acceptance remains open. Portable FFmpeg packaging, disk-backed
|
||||
browser buffering, fan-out and remote delivery also remain open. Device status
|
||||
and heartbeat remain raw observed channels without semantic decoders. Device
|
||||
browser buffering, fan-out and remote delivery also remain open. Device
|
||||
calibration command and sensor-to-vehicle extrinsics are unavailable.
|
||||
|
||||
The 2026-07-17 physical acceptance gate confirmed continuously updating point
|
||||
@@ -149,7 +200,10 @@ clouds, a matching live trajectory, and both camera selections in the same
|
||||
Mission Core acquisition. The embedded Rerun blueprint owns live-edge following
|
||||
on `stream_time`; the React shell selects the timeline once and does not drive it
|
||||
with a timer. Raw captures, camera frames, device identity and network details
|
||||
remain outside Git. See [`ADR 0007`](adr/0007-k1-camera-preview-copy-remux-gateway.md)
|
||||
remain outside Git. The bounded acquisition subset of `DeviceStatusReport` and
|
||||
`ModelingReport` route telemetry are decoded for the exact profile; heartbeat
|
||||
and nested system/RTK status payloads remain raw observed evidence. See
|
||||
[`ADR 0007`](adr/0007-k1-camera-preview-copy-remux-gateway.md)
|
||||
for the measured gate and remaining limits.
|
||||
|
||||
## Remaining extraction order
|
||||
@@ -169,8 +223,9 @@ views.
|
||||
4. Physically accept a newly archived left/right K1 session, then package the
|
||||
read-only RTSP/H.264 adapter for each target OS, add disk-backed sealed media
|
||||
caching and evolve same-host MSE delivery toward an authenticated Edge media
|
||||
plane; keep the modeling-command publisher disabled until its separate safety
|
||||
gate closes.
|
||||
plane. Keep the modeling-command publisher disabled until legitimate OpenAPI
|
||||
key provisioning and durable-save confirmation close its separate safety
|
||||
gate.
|
||||
|
||||
Complex equipment will likely be assembled from separately useful component
|
||||
plugins into configured hardware packs, while standalone equipment remains
|
||||
@@ -209,8 +264,8 @@ single K1 vertical.
|
||||
- remote Edge split, authenticated WAN relay and fleet orchestration;
|
||||
- automatic K1 start/stop/calibration commands;
|
||||
- device-reported camera capability discovery beyond the reviewed K1 profile;
|
||||
- physical acceptance of shared-timeline recorded-camera playback on a newly
|
||||
archived K1 session;
|
||||
- physical acceptance of shared-timeline point-cloud plus one selected-camera
|
||||
playback on a newly archived K1 session;
|
||||
- frame-accurate camera/LiDAR calibration, panoramic stitching, disk-backed
|
||||
browser media cache and remote multi-consumer delivery;
|
||||
- production retention, replication, encryption and long-run WebViewer/WASM
|
||||
|
||||
Reference in New Issue
Block a user