fix(k1): gate control dialogue on live state

This commit is contained in:
DCCONSTRUCTIONS
2026-07-18 17:19:21 +03:00
parent a29b38a0d7
commit 36f0c93d2a
14 changed files with 1435 additions and 122 deletions
+25 -5
View File
@@ -21,7 +21,7 @@ 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 (first physical bootstrap failed closed before START) — plugin v0.4.0 runtime remains dormant/write-disabled; the uninstalled acceptance transport completed one connection, six QoS2 bootstrap publishes and five correlated responses, then rejected one live batch-3 response; K1 remained READY, START was not emitted, retry is forbidden and the temporary Keychain item was deleted |
| K1 application control | PAUSE (accepted START followed by `ALGORITHM_ERROR`) — first live attempt stopped before START on a batch-3 correlation failure; a second attempt correlated all 10 pre-START requests plus START but collapsed UI stages into 365 ms and omitted the retained post-START/control-session lifecycle. The collapsed path and standalone START/STOP are disabled. An uninstalled offline executor now uses explicit UI checkpoints plus live DeviceStatus gates; no further physical write is authorized yet |
| 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
@@ -61,7 +61,26 @@ required responses through batch 3, but the orchestrator raised
`ApplicationBootstrapError` while correlating that batch. No START was emitted;
live DeviceStatus stayed READY and the local point/pose counts remained zero.
The local capture was sealed and the temporary Keychain item was deleted.
Physical START/STOP therefore remain untested; the button is the safe fallback.
The second physical attempt then correlated all ten bootstrap requests and one
START success response. It nevertheless did not reproduce the full LixelGO
lifecycle: all eleven publishes completed in 365 ms, the process did not retain
the control session through initialization, and it omitted the immediate and
post-initialization status reads present in both retained LixelGO START captures.
K1 reported `SCAN_STARTING` for about 24 seconds, emitted system error
`0x32040133` twice (the recovered `ALGORITHM_ERROR` namespace/value), returned
to `OTHER_STATUS`, produced zero point/pose frames and showed steady red. The
operator restored steady green through a normal power cycle. The legacy
`run_bootstrap()` path now rejects before emission. The offline acceptance path
maps requests 16 to connection, request 7 to explicit scan-workspace entry,
requests 810 to explicit project-prompt opening and request 11 to the operator's
START confirmation. Captured human delays are not replayed or treated as minimum
timeouts. After the immediate operation-12 read, operations 1314 wait for the
same bound K1 to report `SCANNING`, a bound project and `init_ready=true`.
The same transport is then serviced until an explicit STOP request; post-STOP
ownership waits for live `READY` plus physical standby confirmation. System-error
and status reports are decoded into redacted safety state. This path is not
wired into the plugin runtime/UI and has only synthetic regression coverage;
physical STOP/save remains untested and the button is the 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;
@@ -280,8 +299,9 @@ 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;
- OS-independent plugin/edge authority provider, redacted live-response
diagnostics for bootstrap batch 3, a newly permitted operator-present full
START/STOP attempt and stable-artifact proof after STOP;
- OS-independent plugin/edge authority provider, PCAP-to-executor transcript
regression, runtime ownership integration, a separately reviewed and newly
permitted operator-present START/STOP attempt, and stable-artifact proof after
STOP;
- long-running large-session WebViewer/WASM memory telemetry;
- production retention, replication, encryption and cross-platform packaging.
+51 -9
View File
@@ -188,14 +188,31 @@ 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 retained request/response timing further divides the dialogue into five
bounded batches. DeviceInfo response establishes identity before later bound
requests. Required response barriers are correlated by topic, exact session,
vendor identity, application authority and numeric success. The initial
ModelingStatus request is intentionally not treated as a required synchronous
response: the clean cycle continued without one, and readiness belongs to the
live DeviceStatus gate. The offline orchestrator completes over the retained
payloads without substitution or skipped requests.
The first ten requests use five response-barrier batches, but those barriers are
not the whole application lifecycle. Two independent owner-operated START
captures contain the same 14-operation order: the ten requests above, START,
one bound `ModelingStatus` read, then a bound `DeviceInfo` plus
`ModelingStatus` refresh about 2425 seconds after START. The first capture
reached START 202.423 seconds after its initial DeviceInfo; the faster capture
reached it after 54.130 seconds. This variation is operator/UI time, while the
stage order is invariant. In both captures the original control MQTT connection
remained open throughout initialization and the later refresh; no DISCONNECT or
UNSUBSCRIBE occurred. DeviceInfo response establishes identity before later
bound requests. Required response barriers are correlated by topic, exact
session, vendor identity, application authority and numeric success. The
initial and immediate post-START ModelingStatus reads are intentionally not
treated as mandatory synchronous responses. Readiness belongs to live
DeviceStatus plus point/pose observation.
The UI/event correlation is also fixed by the retained capture. Requests 16
follow successful data connection. Entering the scan workspace causes request
7. Opening the record/project-name prompt causes reads 810. The project name is
not sent by a separate save mutation: it first appears in the START payload when
the operator confirms the prompt. K1 then reports `SCAN_STARTING`; completion is
the live transition to `SCANNING` with a bound project and `init_ready=true`.
Operations 1314 coincide with that state in both captures. The observed
2425-second initialization duration is therefore evidence/telemetry, not a
hard-coded transition delay.
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
@@ -230,7 +247,32 @@ connection and emitted bootstrap ordinals 16. All six QoS 2 publishes complet
and five required responses were collected, but exact correlation rejected one
response in batch 3. The executor stopped before building or publishing START;
K1 remained `READY`, project binding stayed absent and point/pose remained zero.
No automatic retry was attempted.
No automatic retry was attempted. A second explicitly permitted attempt then
correlated all ten bootstrap responses and one START success response, with 11
QoS2 completions, but it compressed the exchange into 365 ms and ended without
the retained post-START reads or durable control-session ownership. K1 remained
in `SCAN_STARTING` for about 24 seconds, emitted two identical
`report/system_error` values `0x32040133`, returned to `OTHER_STATUS`, produced
no point/pose frames and showed steady red. The bounded system-error decoder maps
the `0x32040000 + 307` value to the recovered `ALGORITHM_ERROR` state. A normal
operator power cycle restored steady green.
This disproves the earlier assumption that byte-matched pre-START payloads plus
a correlated START acknowledgement are sufficient acceptance. The legacy
collapsed `run_bootstrap()` executor now rejects before emission. Its
replacement is an uninstalled acceptance-only session owner. It requires the
observed connection, workspace-entry and project-prompt checkpoints instead of
wall-clock floors, sends the immediate post-START ModelingStatus read, services
the same MQTT socket until live `SCANNING + project + init_ready`, then emits the
DeviceInfo/ModelingStatus refresh. It continues servicing that socket until an
explicit STOP request and afterwards until live `READY` plus operator-confirmed
standby. System-error and DeviceStatus reports are decoded into redacted safety
state; a fault forbids further automatic action. Standalone START/STOP are
disabled. MQTT keepalive/report processing also continues while the operator is
between UI actions; the 15120-second command permit is created at the actual
START or STOP confirmation, not at connection time. This path is
synthetic-test-only and remains outside facade/UI, so it
does not authorize a new physical attempt.
The one-time Keychain administration command uses `security -w` as the final
argument so Apple's own TTY prompt receives the authority. Mission Core never
@@ -37,10 +37,14 @@ K1 application control is exact-profile, live-bound and fail-closed.
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.
4. The complete retained START lifecycle keeps its 14-operation order, stage
boundaries and one continuous control MQTT session. The first ten operations
are pre-START; operation 11 is START; operation 12 is a bound ModelingStatus
read; operations 1314 are the post-initialization DeviceInfo/ModelingStatus
refresh. The only preparatory mutation is time/timezone sync. No stage is
collapsed, skipped or automatically retried. Captured wall-clock gaps are
operator/UI timing, not protocol delays. Stage progression uses explicit UI
actions and live K1 state reports.
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.
@@ -55,7 +59,7 @@ K1 application control is exact-profile, live-bound and fail-closed.
quiescence/evidence sealing, READY plus steady green, then independent native
project verification.
## Recovered pre-START sequence
## Recovered START sequence
The clean cycle contains:
@@ -70,6 +74,9 @@ The clean cycle contains:
9. bound `GetRtkAdvanceRequest`;
10. bound `DeviceInfoRequest`;
11. bound `ModelingRequest` START.
12. bound `ModelingStatusRequest`;
13. bound `DeviceInfoRequest` after static initialization;
14. bound `ModelingStatusRequest` after static initialization.
Normal sessions are `${device_id_or_empty}:${MessageType}`. Time sync uses the
captured special relation
@@ -115,9 +122,20 @@ An unknown post-publish outcome can only be reconciled physically/status-wise;
the same operation key can never be attempted again by that transport.
The acceptance executor requires a 15120 second single-action permit backed by
five explicit operator confirmations. START cannot skip the five recovered
bootstrap batches; STOP uses a separate permit. These types are not imported by
the facade, declared as plugin actions or represented by UI controls.
five explicit operator confirmations. After the failed 2026-07-18 physical
attempt proved that five response batches alone are insufficient, the collapsed
bootstrap entry point and standalone START/STOP were disabled. The uninstalled
replacement binds requests 16 to connection, request 7 to scan-workspace entry,
requests 810 to project-prompt entry and START to a separate operator permit.
There is no separate project-name mutation; the validated name is carried by
START. Operations 1314 are gated by bound `SCANNING`, project presence and
`init_ready`, not by the observed 2425-second duration. The same owner services
MQTT through explicit STOP and waits for live READY plus operator-confirmed
standby. Fault/status observations are redacted and any fault forbids automatic
continuation. The socket remains serviced during operator/UI waits, and each
short action permit is created at its button confirmation rather than at
connection time. These types are synthetic-test-only, not imported by the facade,
declared as plugin actions or represented by UI controls.
`MacOSKeychainApplicationAuthorityProvisioner` invokes Apple's interactive
`security add-generic-password ... -w` prompt with `-w` last. The private value
@@ -133,10 +151,11 @@ transport:
1. provision the reviewed private authority into the fixed local Keychain item;
2. confirm battery/storage and select one K1 over BLE;
3. run the exact response-gated bootstrap and attest activated FW 3.0.2;
3. run the exact staged response-gated preparation 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;
6. preserve the same control MQTT connection, issue the retained post-START
reads and observe calibration plus first point/pose/camera data;
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;
@@ -0,0 +1,91 @@
# Lab 003 — K1 application-control physical acceptance
- Date: 2026-07-18
- Device scope: one owner-controlled LixelKity K1, firmware `3.0.2`
- Result: **PAUSE — START acknowledgement is not lifecycle acceptance**
This report contains no device identity, application authority, address,
credential, raw MQTT payload or project contents. Private evidence remains in
ignored session storage.
## Safety boundary
The operator was present and confirmed ownership, steady-green standby,
battery/storage, exact direct-LAN target and closed LixelGO. Every request used
QoS 2, retain false, one connection attempt and no automatic retry. The local
point/pose receiver was read-only and independent of the control client.
## Attempt 1
The control client emitted bootstrap ordinals 16. All six QoS2 transactions
completed and five required responses arrived, but the batch-3 response did not
pass exact correlation. The executor stopped before START. K1 remained READY
and steady green; point/pose counts stayed zero.
## Attempt 2
After adding redacted live-response diagnostics, one new explicit permit was
used. All ten pre-START requests and START completed QoS2; all required
responses, including the START response, passed identity/session/action/result
correlation. The eleven publishes completed in approximately `365 ms`.
The device then reported `SCAN_STARTING` for approximately 24 seconds. No point
cloud or pose message arrived. It emitted two identical
`lixel/application/report/system_error` messages with code `0x32040133`, reset
to `OTHER_STATUS` without a project binding and showed a steady-red indicator.
The bounded decoder maps the observed namespace/value as
`0x32040000 + 307 = ALGORITHM_ERROR`. A normal operator power cycle restored
steady green. No guessed STOP or repeated START was sent.
## Canonical-diff finding
Re-audit of two independent owner-operated LixelGO START captures found the
same 14-operation order in both:
1. unbound DeviceInfo;
2. unbound ModelingStatus;
3. unbound GetRtkAdvance;
4. bound time/timezone DeviceConfig;
5. bound DeviceInfo;
6. bound GetRtkAdvance;
7. bound GetNtripProfile;
8. bound GetCloudServerConfig;
9. bound GetRtkAdvance;
10. bound DeviceInfo;
11. bound START;
12. bound ModelingStatus;
13. bound DeviceInfo after initialization;
14. bound ModelingStatus after initialization.
The first retained capture reached START at `+202.423 s`; the faster one at
`+54.130 s`. This is variable operator/UI time, not a fixed scanner timeout.
Both preserved the stage order, sent operation 12 within about one second of
START, sent operations 1314 about 2425 seconds after START and kept the same
control MQTT connection open throughout. Neither capture disconnected or
unsubscribed during initialization.
The same re-audit shows that those wall-clock gaps are not protocol timers.
Requests 16 follow connection, request 7 follows explicit workspace entry,
requests 810 follow opening the project prompt, and START follows the operator's
confirmation. No separate project-name save request exists; the name first
appears in START. In both captures operations 1314 coincide with K1's own
`SCANNING`, bound-project and `init_ready=true` DeviceStatus transition.
Attempt 2 matched the first eleven payload/topic operations but violated the
larger lifecycle: it collapsed the UI stages, omitted operations 1214 and did
not preserve a long-lived control-session owner. The evidence does not prove
which individual deviation caused the device algorithm failure, so none is
treated as the sole cause.
## Code decision
The legacy collapsed `run_bootstrap()` executor now rejects before emission.
The replacement acceptance-only executor uses explicit connection/workspace/
project-prompt checkpoints with no captured-delay replay. It owns operations
114, gates the final refresh on live K1 state, surfaces redacted system errors,
keeps the same socket serviced through explicit STOP and waits for READY plus
operator-confirmed standby. The socket is also serviced between every UI action;
START/STOP permits begin only at their respective confirmations. Standalone
START/STOP are rejected. This remains an
uninstalled synthetic-test-only boundary; no new physical attempt is authorized
by this implementation. Physical double-click remains the canonical fallback.