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
+88 -26
View File
@@ -10,18 +10,22 @@ trajectory, camera frame or latency values.
## Active device-to-scene path
```text
K1 lio_pcl / lio_pose
K1 lio_pcl / lio_pose / ModelingReport
|
v
read-only MQTT subscription on TCP 1883
|
+--> raw .k1mqtt + JSONL + SHA-256 summary (written first)
+--> raw .k1mqtt + JSONL + durable clock origin (before camera/preview)
+--> transport/session envelope + SHA-256 summary (shutdown/seal)
|
+--> injected K1 ModelingReport observer
| `--> device scan time / distance / speed product metrics
|
v
bounded latest-wins preview queue (32 messages)
bounded latest-wins visual preview queue (4 messages)
|
v
reviewed raw-LZ4/protobuf decoders
reviewed raw-LZ4/protobuf point/pose normalizer
|
v
Rerun Points3D + Transform3D + LineStrips3D
@@ -44,6 +48,10 @@ become a durable pair at the bounded group-commit boundary (at most 0.5 s,
4 MiB or 32 messages), not at every callback. If visualization cannot keep up,
the oldest queued preview is discarded while capture continues. Rerun work
stays on the dedicated publisher thread and cannot block that raw-first path.
The four-message queue size is independent of the 32-message evidence group
commit. A plugin-injected observer consumes bounded K1 `ModelingReport` messages
after raw persistence but before visual admission, so status telemetry cannot
evict a point-cloud or pose preview.
The current live/replay runtime instantiates only `RerunBridge`. The former
Foxglove implementation is not a parallel runtime and does not listen on TCP
@@ -107,14 +115,26 @@ directly and use their sibling metadata receive timestamps when present.
complete visible-device list.
4. Enter the existing router SSID/password and explicitly authorize the reviewed
provisioning write. The backend does not retry the write automatically.
5. When K1 reports a non-AP private address, start live reception.
6. Wait until the UI reports that the local Rerun bridge is ready. No manual
5. Enter the required project name. Mission Core NFKC-normalizes and trims it,
rejects control/surrogate characters or more than 96 characters, and stores
it as local display metadata rather than a path. The read-only profile does
not send it to K1.
6. When K1 reports a non-AP private address, choose **Подготовить локальный
приём данных**. The stronger “initiate device work” wording appears only for
a future profile that actually authorizes a vendor write.
7. Wait until the UI reports that the local Rerun bridge is ready. No manual
viewer URL is needed.
7. Open **Наблюдение → Пространственная сцена**.
8. Double-click the physical K1 button to start scanning. Real point frames and
8. Open **Наблюдение → Пространственная сцена**. The K1 plugin's optional scene
block shows the local preparation/acquisition phase and stop action.
9. Double-click the physical K1 button to start scanning. Real point frames and
pose/trajectory updates then appear in the embedded viewport.
9. Double-click K1 again to stop physical scanning, wait for steady green, then
stop the local session so captures and summaries are finalized.
10. When K1 emits `ModelingReport`, the same plugin block shows its current scan
time, route distance and speed. These are device reports, not values inferred
from a browser timer or accumulated across a device counter reset.
11. Double-click K1 again to stop physical scanning and wait for steady green,
then choose **Остановить локальный приём** in the scene or device workflow
so capture, camera archive and summaries are finalized. That UI action does
not stop K1 on the active profile.
Each new live run creates a direct child below `MISSIONCORE_EVIDENCE_DIR`, or
`.runtime/mission-core/evidence/sessions/` by default, with raw MQTT frames,
@@ -123,6 +143,15 @@ per-message metadata and a hash summary. Repository-level
the current writer. The connector subscribes to the fixed report-topic
allowlist and does not publish an application request or modeling command.
The recovered command substrate is intentionally inert. It can encode exact
start/stop request bytes, correlate response identity/action/result and classify
observed device states without importing MQTT or publishing anything. The header
requires explicit ASCII `device_id` and OpenAPI key and derives the session ID
exactly as `${device_id}:ModelingRequest`. Legitimate OpenAPI key
provenance/provisioning and durable save completion after stop are unresolved,
so `vendor_writes_enabled` is false and the physical-button workflow remains
canonical.
## Automatic Rerun source and lifecycle
On the first live or adapter file-replay session, `RerunBridge`:
@@ -149,6 +178,16 @@ served over HTTP(S). No externally hosted viewer UI is involved:
application. FastAPI carries control state only; the browser reads the point
stream directly from the Rerun gRPC/proxy endpoint.
`activateAutomaticSpatialSource` is a generic host action, not a scanner-control
command. A plugin invokes it only after its live or adapter-replay start returns
success, then opens the spatial scene; a failed start preserves the old scene
and source. The successful action releases any host-selected archive/manual URL
so the new backend source becomes authoritative. After an acquisition becomes
nonterminal, a fail-closed host guard blocks saved-session switching, persisted
replay reattach and manual RRD/Rerun source input/application/reset until the
acquisition ends. This successful-start transition intentionally does not
consult the operator-switch guard, and the guard never stops equipment.
## Rerun entities
| Entity | Rerun archetype | Meaning |
@@ -159,8 +198,11 @@ stream directly from the Rerun gRPC/proxy endpoint.
| `/world/trajectory` | `LineStrips3D` | bounded path of up to 2,000 decoded poses |
Point count, frame rate, queue drops and measured pipeline time remain product
metrics in the outer Control Station; they are not logged as Rerun entities and
therefore cannot create additional automatic viewer panes.
metrics in the outer Control Station. Live K1 scan time, route distance and
speed also remain product metrics in the plugin-owned scene block. Saved-session
export separately logs those three device-reported values below
`/metrics/device` as Rerun scalar time series; this does not add vendor parsing
to the generic live bridge.
Point coordinates remain `(x/scaler, y/scaler, z/scaler)` exactly as decoded.
No axis swap, quaternion normalization, scanner-to-vehicle extrinsic or SLAM
@@ -210,28 +252,46 @@ opaque same-origin RRD rather than starting a second live bridge.
Sealing, recovery or legacy import makes the session eligible for the bounded
backend preparation worker. The worker reads every native message once and
atomically publishes a private cache-v7 RRD using the zero-based `session_time`
duration timeline. A SHA sidecar binds the generation to native evidence.
atomically publishes a private cache-v9 RRD using the zero-based `session_time`
duration timeline. New sessions bind that zero/end to the durable capture-clock
envelope; older valid evidence retains the first/last-message compatibility
fallback. A SHA sidecar binds the generation to native evidence.
Replay-open never performs conversion: it returns HTTP 202 and a preparation
handle or reuses the verified artifact. The embedded viewer opens the exact
generation through Rerun's native incremental HTTP receiver. The bottom Control
Station timeline then controls play/pause and seek directly; it does not
approximate time with a React timer.
The native `.k1mqtt` remains the evidence master. RRD generation does not use
the bounded live-preview queue, so it retains every frame accepted by the
reviewed normalizer. See
The native `.k1mqtt`, aligned metadata and capture-clock envelope remain the
spatial evidence master. RRD generation does not use the bounded live-preview
queue, so it retains every point/pose frame accepted by the reviewed normalizer
and logs every valid `ModelingReport` as distance, speed and elapsed-time scalar
rows. See
[`09_OBSERVATION_SESSIONS.md`](09_OBSERVATION_SESSIONS.md) for storage,
recovery and HTTP Range details.
## Time and latency semantics
The Rerun `capture_time` timeline uses
`StreamMessage.received_at_epoch_ns`: Unix time when the Mac received the MQTT
message. The K1 header timestamp epoch is not proven, so `capture_time` is not
a sensor acquisition timestamp. The viewer accumulation window uses
`stream_time`, assigned when the current live/replay run publishes a message;
therefore replayed historical timestamps do not mix two sequential sessions.
The Rerun `capture_time` timeline uses Mac host-clock epoch values. Data rows use
`StreamMessage.received_at_epoch_ns`, while new archived sessions also contain a
real origin row at the capture-envelope start and a real end row at the sealed
session completion. Their zero-based `session_time` is derived from the same
monotonic envelope; it can therefore cover a camera fragment before the first
MQTT packet or after the last spatial packet without inventing an RRD range.
Legacy evidence without an envelope falls back to first/last message bounds.
The K1 header timestamp epoch is not proven, so `capture_time` is not a sensor
acquisition timestamp. The live viewer accumulation window uses `stream_time`,
assigned when the current live/replay run publishes a message; therefore
replayed historical timestamps do not mix two sequential sessions.
Retained read-only physical captures support the profile-scoped telemetry units:
in five of six runs, `ScanTime / 2` tracks host monotonic duration within about
0.17 seconds across 762,294-second spans; the remaining older run contains a
counter/distance reset and is treated as a new scan generation. In two moving
runs, `ModelingReport.MoveDistance` matches the independent
`lio_pose.distance` values at 41.521 m and 26.631 m, while reported peak speeds
of 1.382 m/s and 1.291 m/s are physically plausible. This evidence does not turn
the counters into a cross-firmware contract.
For live MQTT only, `pipeline_ms` / `mqtt_to_publish_ms` uses the Mac monotonic
clock from MQTT callback receipt through raw disk write, bounded queue wait,
@@ -272,7 +332,8 @@ listener and its process memory must be closed unconditionally.
separate generic media path. Historical sessions predating that archive have
no recoverable video.
- Physical double-click remains the K1 scan start/stop control. Any MQTT command
publisher needs a separately reviewed state-changing profile.
publisher needs a separately reviewed state-changing profile with legitimate
OpenAPI key provisioning and a proven durable-save completion gate.
- No terrain map, elevation model, obstacle segmentation, localization fusion,
mission planner or vehicle control is implemented by this viewer milestone.
- Exact coordinate axes and the scanner-to-vehicle transform remain a mounting
@@ -297,8 +358,9 @@ embedded Web Viewer path without a viewer-side substitute:
The 38 point frames and 42 pose frames account for all 80 observed messages.
This proves current real-device decoding, bridge publication and embedded-viewer
delivery for point cloud plus trajectory. It does not prove a camera channel or
sensor-to-screen latency.
delivery for point cloud plus trajectory. It does not prove archived playback
of one selected camera together with the point cloud or sensor-to-screen
latency.
## Legacy Foxglove regression module