feat(k1): complete primary acquisition lifecycle
This commit is contained in:
@@ -28,23 +28,41 @@ admission and browser APIs. A plugin owns native evidence discovery, transport
|
||||
format validation, recovery semantics, timeline-origin extraction and conversion
|
||||
of its primary artifact into the canonical recorded Rerun artifact.
|
||||
|
||||
For new K1 sessions, the plugin also contributes confined clock artifacts. A
|
||||
durable origin is published before camera production, MQTT shutdown creates a
|
||||
transport-scoped provisional envelope, and the acquisition owner publishes a
|
||||
content-addressed session envelope plus an atomic summary-pointer switch after
|
||||
camera and MQTT/runtime shutdown. A provisional envelope cannot advertise
|
||||
combined camera replay. Valid older sessions without this contract keep their
|
||||
first/last-message compatibility fallback.
|
||||
|
||||
`ReplayCommand` is now vendor-neutral. It contains an owning `plugin_id`, an
|
||||
opaque primary artifact ID, an ordered tuple of confined artifacts and a ready
|
||||
timeline origin. It contains no filename suffix, MQTT topic or sidecar name.
|
||||
The materializer selects the exporter by `plugin_id` and stages every validated
|
||||
artifact prefix while preserving only its plugin-owned basename.
|
||||
|
||||
Derived RRD cache v7 binds the published RRD to:
|
||||
Derived RRD cache v9 binds the published RRD to:
|
||||
|
||||
- plugin ID and primary artifact ID;
|
||||
- ordered artifact IDs and media types;
|
||||
- full file identity and replay boundary for every artifact;
|
||||
- per-artifact prefix digest;
|
||||
- derived recording digest and zero-based timeline bounds.
|
||||
- durable clock origin, active-envelope start/completion, selected clock
|
||||
artifact identity and both digests when present;
|
||||
- derived recording digest and zero-based timeline bounds whose origin and end
|
||||
are both materialized as real RRD rows.
|
||||
|
||||
Cache v6 and older sidecars are rebuilt once. The native evidence is not
|
||||
Cache v8 and older sidecars are rebuilt once. The native evidence is not
|
||||
rewritten.
|
||||
|
||||
The K1 exporter also recognizes bounded `ModelingReport` messages. It writes the
|
||||
reported route distance, speed and scan time as scalar time series below
|
||||
`/metrics/device`; it does not infer them from pose integration or a UI timer.
|
||||
Live observation consumes the same status through a plugin-injected raw-message
|
||||
observer before the four-message visual preview queue. The generic
|
||||
`VisualizationRuntime` still has no K1 decoder or topic knowledge.
|
||||
|
||||
The concrete implementation is physically located below:
|
||||
|
||||
```text
|
||||
@@ -79,6 +97,11 @@ therefore requires a manifest/runtime contribution and a plugin-owned reviewed
|
||||
UI contribution, not edits to the session API, preparation queue, Rerun consumer
|
||||
or main application shell. ADR 0010 defines that frontend boundary.
|
||||
|
||||
Additional acceptance tests bind the K1 capture clock into the ordered replay
|
||||
artifacts, reject corrupt or provisional new-schema boundaries, materialize real
|
||||
origin/end rows and retain archived device-metric samples without traversing the
|
||||
lossy live-preview queue.
|
||||
|
||||
## Consequences
|
||||
|
||||
The semantic and physical vendor boundary is complete for the current
|
||||
@@ -87,6 +110,12 @@ operator workflows remain compatible. The `k1link` distribution name and CLI
|
||||
command remain transitional compatibility names; their implementation is now
|
||||
plugin-owned.
|
||||
|
||||
The operator project name is normalized and validated by the K1 contribution,
|
||||
stored as display/catalog metadata and never used as a path component. This ADR
|
||||
does not claim that it reaches the scanner: the inert modeling-control codec has
|
||||
no publisher, and automatic K1 writes remain disabled pending legitimate OpenAPI
|
||||
credential provisioning and durable post-stop save evidence.
|
||||
|
||||
ADR 0011 subsequently places the action control plane behind a versioned
|
||||
descriptor/handshake/health transport seam. Observation discovery and export
|
||||
remain host-called plugin contributions and are not yet portable process
|
||||
|
||||
@@ -26,10 +26,13 @@ are physically located under:
|
||||
```text
|
||||
plugins/xgrids-k1/frontend/src/
|
||||
plugin.ts
|
||||
projectName.ts
|
||||
automaticSourceStart.ts
|
||||
XgridsK1Connection.tsx
|
||||
components/
|
||||
K1ProvisioningPipeline.tsx
|
||||
K1AcquisitionPipeline.tsx
|
||||
K1SpatialControls.tsx
|
||||
K1Diagnostics.tsx
|
||||
K1Metrics.tsx
|
||||
```
|
||||
@@ -43,9 +46,32 @@ NODE.DC UI kit. It may not import Control Station implementation paths.
|
||||
`apps/control-station/src/composition/devicePlugins.ts` is the only Core file
|
||||
which imports the concrete XGRIDS frontend. The host owns model selection,
|
||||
safe deactivation, the `device.connection` slot, navigation, the spatial scene,
|
||||
saved-session UX and global layout. The plugin owns BLE candidates, exact-profile
|
||||
attestation, credentials-in-memory form state, K1 endpoint state, connection
|
||||
instructions and the live/replay acquisition controls.
|
||||
saved-session UX and global layout. A contribution may additionally expose one
|
||||
optional `SpatialControlsView`, which the generic scene mounts beside the
|
||||
viewport without learning its fields or lifecycle wording. The plugin owns BLE
|
||||
candidates, exact-profile attestation, credentials-in-memory form state, K1
|
||||
endpoint state, connection instructions, project-name validation, live/replay
|
||||
acquisition controls and its scene-level status/stop/telemetry block.
|
||||
|
||||
The host surface includes `activateAutomaticSpatialSource`. The name refers to
|
||||
viewer-source ownership, not automatic equipment control. The plugin calls it
|
||||
only after live or adapter replay start returns success and then opens the scene;
|
||||
a failed start leaves the existing scene/source intact. The action clears the
|
||||
earlier manual/archive selection so backend state can supply the successful new
|
||||
source. A generic fail-closed acquisition guard blocks saved-session switching,
|
||||
persisted replay reattach and manual source input/apply/reset for every
|
||||
nonterminal state, cleanup-pending terminal state or unknown acquisition state.
|
||||
The internal successful-start action is not an operator source switch and
|
||||
performs no implicit stop.
|
||||
|
||||
K1 project names are required, NFKC-normalized and trimmed, rejected for control
|
||||
or surrogate characters or more than 96 Unicode characters, and sent to the
|
||||
backend as local display metadata. The active profile has
|
||||
`vendor_writes_enabled=false`, so its
|
||||
buttons and scene control say that they prepare/stop local reception. Before an
|
||||
acquisition exists, device-start wording is gated by active-control capability;
|
||||
after start, calibration/device-stop wording additionally requires a
|
||||
plugin-commanded acquisition mode.
|
||||
|
||||
Plugin CSS is imported with the contribution and scoped below
|
||||
`.xgrids-k1-plugin`. A plugin cannot add global navigation, route ownership or
|
||||
@@ -65,19 +91,24 @@ the correct component for each model. It also fails when:
|
||||
- generic Core files other than the composition root contain XGRIDS/Lixel/K1
|
||||
implementation knowledge;
|
||||
- plugin source imports Control Station implementation paths;
|
||||
- provisioning, acquisition, diagnostics or scoped-style modules disappear.
|
||||
- provisioning, acquisition, optional scene controls, diagnostics or
|
||||
scoped-style modules disappear;
|
||||
- a nonterminal acquisition can be replaced by a manual or recorded spatial
|
||||
source, including persisted replay reattach.
|
||||
|
||||
The accepted local gate is 114 frontend unit tests, TypeScript strict checking
|
||||
The accepted local gate is the frontend unit suite, TypeScript strict checking
|
||||
and a Vite production build. Backend behavior and the physical K1 protocol are
|
||||
unchanged by this source/UI decomposition.
|
||||
unchanged by this source/UI decomposition; protocol command authorization is a
|
||||
separate backend/physical gate.
|
||||
|
||||
## Consequences
|
||||
|
||||
A second device family can provide a completely different connection pipeline
|
||||
and UI while reusing the same model catalog, lifecycle transition, observation
|
||||
scene and saved-session host. Adding it requires its own plugin-owned frontend
|
||||
contribution and one reviewed composition import, not edits to `App`,
|
||||
`DeviceWorkspace` or generic runtime state.
|
||||
and optional scene controls while reusing the same model catalog, lifecycle
|
||||
transition, observation scene and saved-session host. Adding it requires its own
|
||||
plugin-owned frontend contribution and one reviewed composition import; the
|
||||
generic host changes only when a genuinely cross-device slot/action is added,
|
||||
not for vendor fields or protocol-specific workflow steps.
|
||||
|
||||
The remaining isolation gap is deployment-level: frontend contributions are
|
||||
still compiled into one signed application build, and backend plugins still run
|
||||
|
||||
Reference in New Issue
Block a user