feat(k1): complete primary acquisition lifecycle

This commit is contained in:
DCCONSTRUCTIONS
2026-07-17 23:03:59 +03:00
parent 9d51080d2e
commit aa3680948f
66 changed files with 6093 additions and 544 deletions
+66 -11
View File
@@ -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