feat(k1): recover exact application bootstrap

This commit is contained in:
DCCONSTRUCTIONS
2026-07-18 13:54:25 +03:00
parent af9319a33b
commit d7749208a7
15 changed files with 906 additions and 215 deletions
+14 -12
View File
@@ -21,23 +21,25 @@ Each gate produces evidence and an explicit GO, PAUSE or BLOCKED result.
| Stage 7 observation archive | GO (point/pose/telemetry contract) — durable catalog, recovery, capture-clock-bounded RRD preparation, archived metric time series, saved-session timeline and atomic playback are implemented |
| Stage 7 recorded cameras | GO (contract), acceptance pending — acquisition-owned fMP4 archive and player are implemented/tested; one real archived K1 camera plus point-cloud session has not passed playback yet |
| Plugin isolation | GO (laboratory control plane) — vendor backend/frontend and optional scene controls are plugin-owned; manifest/runtime descriptor parity, versioned handshake, lifecycle health and transport correlation fail closed while execution remains in-process |
| K1 application control | PAUSE (shadow gate implemented) — the exact captured codec is byte-matched, live status binds vendor identity plus serial, and START/STOP can be planned without publish authority; device-bound OpenAPI enrollment, one-shot publisher, physical save acceptance and recovery policy remain closed gates |
| K1 application control | PAUSE (exact shadow dialogue implemented) — all 10 retained pre-START requests and START/STOP are byte-matched; BLE-selected live DeviceInfo supplies per-scanner identity while one private application-level OpenAPI authority remains outside Git/Ops; publisher, physical save acceptance and recovery policy remain closed gates |
| Stage 8 product storage | PAUSE — retention, replication, encryption, capacity monitoring and long-run browser/WASM stress remain deployment gates |
USB project copying remains optional ground truth rather than a blocker for the
now-verified network path. Owner-operated LixelGO traffic verifies the MQTT
start/stop mapping and RTSP camera transport. The exact start/stop protobuf
encoder, response correlator and device-status state machine now exist without a
publisher. Header construction is known: an explicit ASCII device ID and ASCII
OpenAPI key are required, while the session ID is derived exactly as
`${device_id}:ModelingRequest`. MQTT control publishing remains deliberately
disabled. A live-only shadow safety layer now observes the device-reported
vendor identity and serial, rejects identity drift or malformed status, and can
form a non-executable START only from unbound `READY` or STOP only from a bound
`SCANNING` state. Its output contains a digest and wire metadata, never the
device identity, serial, OpenAPI value or payload. Legitimate per-device OpenAPI
provisioning, an authorized one-shot publisher and a durable post-stop save gate
are not proven. The physical button remains the known-safe fallback.
publisher. Retained PCAP plus client static analysis prove that OpenAPI is one
private application-level value in this LixelGO build, not a per-scanner
credential. The selected BLE peripheral returns its own LAN IP; the initial
unbound `DeviceInfoRequest` then returns vendor ID, serial, model, activation and
version facts for that live K1. Mission Core's shadow bootstrap reproduces the
10 observed pre-START requests byte-for-byte: three unbound discovery reads,
one response-bound time/timezone sync and six further reads. A live-only safety
layer rejects identity drift or malformed status, and can form a non-executable
START only from unbound `READY` or STOP only from bound `SCANNING`. Public output
contains only digests and wire metadata. Secure application-authority loading,
an authorized response-gated one-shot publisher and durable post-stop save are
not yet proven. The physical button remains the known-safe fallback.
The Stage 6 live path uses a bounded raw-first bridge: loss in the visualization
queue cannot discard MQTT evidence. The queue holds four preview messages;
@@ -256,7 +258,7 @@ useful stream is decoded or structurally identified.
- firmware or internal-Linux analysis;
- physical end-to-end shared-timeline playback for a newly archived session
containing point cloud plus one selected K1 camera;
- legitimate K1 OpenAPI credential provisioning, authorized command transport
- private application-level OpenAPI authority loading, authorized command transport
and stable-artifact proof after the observed stop lifecycle;
- long-running large-session WebViewer/WASM memory telemetry;
- production retention, replication, encryption and cross-platform packaging.
+23 -10
View File
@@ -166,14 +166,27 @@ separated four values which must never be substituted for one another:
belongs in a vendor request;
- the vendor device ID comes from live K1 status and occupies the request header;
- the K1 serial is a separate live device-binding value;
- the OpenAPI value is a private, device-bound command credential and is not
present in the status report.
- the OpenAPI value is private application-level material embedded by the
observed LixelGO build; it is shared across all retained request types and is
not derived from the current scanner while the application value is present.
Consequently, support for another K1 cannot replay this scanner's captured
payload or OpenAPI value. It requires a separate owner-authorized enrollment
whose vendor device ID and serial are attested against live status under the
same exact firmware/topology profile. Any mismatch, identity drift, malformed
status, replay-only evidence or unexpected lifecycle state fails closed.
Consequently, support for another K1 never replays captured payload bytes and
does not require a manually maintained scanner profile. BLE selection and its
provisioning response bind the transport to that unit; an initial
`DeviceInfoRequest` without device ID returns the live vendor ID, serial, model,
activation and version facts. Those values bind later requests and must agree
with the live status stream. Any mismatch, identity drift, malformed response,
replay-only evidence or unexpected lifecycle state fails closed.
The clean LixelGO cycle contains exactly ten requests before START, all QoS 2
and retain false: `DeviceInfo`, `ModelingStatus`, `GetRtkAdvance`, a bound
`DeviceConfig` time/timezone sync, then `DeviceInfo`, `GetRtkAdvance`,
`GetNtripProfile`, `GetCloudServerConfig`, `GetRtkAdvance`, `DeviceInfo`. The
special time-sync session is exactly
`${device_id}:DeviceConfigRequest:Publish_Proto_DeviceConfig_SetTime`. The
repository shadow bootstrap reproduces all ten retained payloads and their
topic order byte-for-byte. Time sync is the only mutation before START; the
other nine requests are reads.
The repository now contains an inert bounded encoder/response parser and a
fail-closed device-status state machine for this exact profile. A live-only
@@ -182,9 +195,9 @@ from `SCANNING` with a bound project. It emits only a non-executable digest and
wire metadata, uses QoS 2 with retain false, and declares automatic retry
forbidden. It has no MQTT publish dependency and cannot send a command.
Publishing remains deliberately disabled: secure per-device OpenAPI enrollment
is unresolved, and the complete stop/save sequence has not physically proved a
durable vendor project. A correlated STOP success, stream quiescence, return to
Publishing remains deliberately disabled: the private application authority
still needs a secure runtime loader and the complete stop/save sequence has not
physically proved a durable vendor project. A correlated STOP success, stream quiescence, return to
`READY`/steady-green hardware state and appearance of a reusable native project
are separate gates. The verified physical double-click remains the acquisition
control until a separately reviewed one-shot write gate closes.
+9 -10
View File
@@ -143,14 +143,13 @@ 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.
The recovered command substrate is intentionally inert. It byte-matches the ten
observed pre-START requests plus START/STOP, correlates DeviceInfo and modeling
responses, and classifies live device states without importing MQTT or
publishing anything. One private application-level OpenAPI authority is kept
separate from the transient vendor ID/serial returned by the BLE-selected K1.
Secure authority loading and durable save completion after stop remain open, so
`vendor_writes_enabled` is false and the physical-button workflow is canonical.
## Automatic Rerun source and lifecycle
@@ -332,8 +331,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 with legitimate
OpenAPI key provisioning and a proven durable-save completion gate.
publisher needs reviewed private application-authority loading, response-gated
one-shot behavior 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
+10 -12
View File
@@ -142,16 +142,14 @@ 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.
An exact but inert K1 application-control substrate now lives inside the vendor
plugin. It byte-matches the retained ten-request pre-START dialogue plus
START/STOP, correlates live DeviceInfo/modeling responses and maps bounded
device-status values into an observation-only state machine. The OpenAPI value
is one private application-level authority; vendor ID and serial come from the
BLE-selected live K1 and are cross-checked against status. No MQTT publisher
exists. Secure authority loading and stable-artifact proof after STOP remain
unresolved, so `vendor_writes_enabled=false`.
## Semantic lifecycle
@@ -223,8 +221,8 @@ 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 legitimate OpenAPI
key provisioning and durable-save confirmation close its separate safety
plane. Keep the modeling-command publisher disabled until private application
authority loading and durable-save confirmation close its separate safety
gate.
Complex equipment will likely be assembled from separately useful component
+1 -1
View File
@@ -513,5 +513,5 @@ viewer/WASM payload. That is a packaging optimization item, not a failed gate.
No retained physical K1 session contains the new canonical camera archive, so a
real point-cloud plus one-camera recorded playback remains an explicit hardware
acceptance test. Automated protocol tests also do not authorize K1 modeling
publishing: legitimate OpenAPI key provisioning and durable save completion
publishing: private application-authority loading and durable save completion
remain separate physical/security gates.
@@ -112,9 +112,9 @@ 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.
does not claim that it reaches the scanner: the inert application-control codec
has no publisher, and automatic K1 writes remain disabled pending reviewed
private application-authority loading 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
@@ -1,4 +1,4 @@
# ADR 0012: device-bound K1 command authority
# ADR 0012: live-bound K1 control with application-level authority
- Status: accepted
- Date: 2026-07-18
@@ -6,89 +6,113 @@
## Context
Owner-controlled LixelGO traffic proves the K1 modeling START/STOP protobuf
shape, MQTT topic, QoS and correlated success response for one K1 running the
exact `xgrids.lixelkity-k1.fw-3.0.2.direct-lan.v1` profile. A bounded offline
audit also proves that Mission Core's encoder reproduces both retained requests
byte-for-byte. This is sufficient to describe the current device dialogue, but
not to replay a captured request or authorize writes to any K1.
Owner-controlled LixelGO traffic proves the K1 preparation and modeling
dialogue for one activated K1 running the exact
`xgrids.lixelkity-k1.fw-3.0.2.direct-lan.v1` profile. Offline regression proves
that Mission Core reproduces all ten requests before START, plus START and STOP,
byte-for-byte. This describes the current device dialogue but does not authorize
writes to any K1.
The protocol exposes several identities with different authority. Mission
Core's provisional device UUID is local inventory identity. The vendor device
ID is reported by the live K1 and occupies the request header. The K1 serial is
a separate device-binding value. The OpenAPI value is private command material
which is absent from live status. LixelGO derives the command session relation
from the vendor device ID and request type; it is not a reusable caller session.
The protocol exposes identities with different ownership. Mission Core's
inventory UUID and the macOS CoreBluetooth UUID are local transport identities.
The vendor device ID and serial identify the live scanner. The OpenAPI value is
private application material: retained traffic uses one value across every
request type, and decompiled LixelGO uses its embedded application value before
the serial-derived fallback. It is therefore not a manual per-scanner profile.
Native project durability is also not equivalent to command acceptance. STOP
success, stream quiescence, return to READY/steady green and a reusable project
on the scanner are separate observations.
The selected BLE peripheral returns the LAN address of that same unit during
the reviewed Wi-Fi provisioning exchange. On MQTT, LixelGO first sends
`DeviceInfoRequest` without a device ID. `DeviceInfoResponse` supplies vendor ID,
serial, model, activation and version facts; subsequent headers bind to that
identity. Native project durability remains separate from command acceptance.
## Decision
K1 application control is exact-profile, device-bound and fail-closed.
K1 application control is exact-profile, live-bound and fail-closed.
1. Mission Core never sends its local inventory UUID, BLE identifier or a K1
serial in place of the vendor request identity.
2. Each K1 requires an owner-authorized enrollment containing its vendor device
ID, serial and private OpenAPI value. Enrollment secrets are not committed,
placed in Ops, returned by APIs or written to logs.
3. Before a command can be considered, live MQTT status must attest the same
vendor device ID and serial under the exact firmware/topology profile.
Replay evidence cannot establish current command authority.
4. Identity drift, missing identity, malformed status, profile mismatch or an
unexpected lifecycle state blocks command planning.
5. START retains the observed LixelGO parameters: record-and-calculate mode 2,
LCC scan mode 1, handheld mount mode 0 and the operator's validated project
name. STOP contains only the same bound header and action.
6. MQTT command semantics remain QoS 2, retain false. Automatic retry is
forbidden: an unknown outcome must be reconciled from live status and
physical evidence before another command.
7. No firmware, activation, account, update or vendor-cloud endpoint is part of
the control path. Local direct-LAN MQTT is the only reviewed transport.
8. STOP completion has four gates: correlated command result, local stream
quiescence and evidence sealing, READY/steady-green device state, then native
project verification. Earlier gates must not claim the later ones.
1. Mission Core never substitutes its inventory UUID, BLE UUID or serial for
the vendor request identity.
2. One private application-level OpenAPI authority is loaded outside Git, Ops,
browser state, APIs and logs. It is not copied into scanner profiles.
3. The BLE-selected transport is followed by an unbound DeviceInfo exchange.
Its live vendor ID, serial, activation and FW 3.0.2 facts form the transient
device binding; a saved profile is optional metadata, not protocol authority.
4. The ten retained pre-START requests keep their exact order and response
boundaries. The only mutation is the observed time/timezone sync; the other
nine requests are reads. No request is batched, skipped or automatically
retried.
5. Live DeviceInfo binding must agree with the live DeviceStatus stream before
START/STOP planning. Identity drift, malformed data, inactive equipment,
profile mismatch or an unexpected lifecycle state fails closed.
6. START retains record-and-calculate mode 2, LCC mode 1, handheld mount 0 and
the validated project name. STOP contains only bound header and action.
7. MQTT application semantics remain QoS 2, retain false. An unknown outcome is
reconciled from correlated response, status and physical evidence before any
new operator-authorized attempt.
8. No firmware, activation, account, update or vendor-cloud mutation belongs to
this path. `GetCloudServerConfig` is a local K1 read.
9. STOP completion has separate gates: correlated result, local stream
quiescence/evidence sealing, READY plus steady green, then independent native
project verification.
## Recovered pre-START sequence
The clean cycle contains:
1. unbound `DeviceInfoRequest`;
2. unbound `ModelingStatusRequest`;
3. unbound `GetRtkAdvanceRequest`;
4. bound `DeviceConfigRequest` time/timezone sync;
5. bound `DeviceInfoRequest`;
6. bound `GetRtkAdvanceRequest`;
7. bound `GetNtripProfileRequest`;
8. bound `GetCloudServerConfigRequest`;
9. bound `GetRtkAdvanceRequest`;
10. bound `DeviceInfoRequest`;
11. bound `ModelingRequest` START.
Normal sessions are `${device_id_or_empty}:${MessageType}`. Time sync uses the
captured special relation
`${device_id}:DeviceConfigRequest:Publish_Proto_DeviceConfig_SetTime`.
## Current implementation boundary
`LiveModelingControlSafety` observes only live device-status messages. It binds
vendor identity and serial, tracks lifecycle state and creates non-executable
shadow START/STOP plans. Public state and plan output contain only booleans,
counts, action, topic, QoS, retain flag, payload length and digest. The encoded
payload and enrolled values remain private in memory.
`application_bootstrap.py` provides the bounded application authority type,
DeviceInfo response correlation/decoding and the exact non-executable ten-step
shadow plan. Its retained clean-cycle regression is 10/10 payloads and topic
order. `LiveModelingControlSafety` independently binds that DeviceInfo identity
to live status and creates non-executable START/STOP plans.
The shadow plan is blocked by both `vendor-writes-disabled` and
`publisher-not-installed`. There is no MQTT publisher, enrollment endpoint or
automatic retry path. The physical K1 control remains the production fallback.
Public state contains only booleans, counts and wire metadata. Private identity,
authority and payload bytes stay out of repr/API output. Both shadow paths are
blocked by `vendor-writes-disabled` and `publisher-not-installed`; no MQTT
publisher or automatic retry path exists.
## Promotion gate
A future publisher requires a separate review and an operator-present physical
acceptance on the enrolled K1:
A future publisher requires separate review and an operator-present physical
acceptance:
1. confirm exact firmware/profile, steady-green state, battery and storage;
2. close LixelGO and arm raw evidence plus the intended camera receiver;
3. attest live READY identity against the device enrollment;
4. review the shadow command metadata;
5. send one START, without retry, and correlate its exact response;
1. load the private application authority through a reviewed local secret
mechanism;
2. confirm battery/storage and select one K1 over BLE;
3. run the exact response-gated bootstrap and attest activated FW 3.0.2;
4. confirm READY identity against DeviceInfo and review shadow metadata;
5. send one START without retry and correlate its response;
6. observe calibration and first point/pose/camera data;
7. send one STOP, without retry, and correlate its exact response;
7. send one STOP without retry and correlate its response;
8. seal local evidence while accepting the bounded stream tail;
9. wait for READY and steady green before power-off or another scan;
10. verify the native project independently through the vendor-supported
workflow.
9. wait for READY and steady green;
10. verify the native project through the vendor-supported workflow.
Any unknown response, identity change, activation state, fault, low battery or
unexpected lifecycle transition pauses the test. It does not trigger a guessed
recovery command.
Any unknown response, identity change, fault, low battery/storage or unexpected
transition pauses the test. It never triggers a guessed recovery command.
## Consequences
Adding another K1 means creating another private enrollment and proving its
exact compatibility profile; it never means reusing captured bytes from the
first scanner. The design preserves native record-and-calculate behavior while
keeping command authority inside the XGRIDS plugin and out of generic Mission
Core. It intentionally postpones convenience automation until identity,
credential provenance, one-shot transport behavior and durable save semantics
have all passed physical acceptance.
Adding another identical K1 means selecting it over BLE and deriving a fresh
live DeviceInfo binding, not creating or copying a command profile. A second
physical K1 remains a useful portability acceptance, but another packet capture
is not required before implementing the reviewed current profile. The design
preserves native record-and-calculate behavior while keeping vendor control in
the XGRIDS plugin and out of generic Mission Core.