10 KiB
K1 connection-path audit and R15
Observed failure sequence
The owner reported four failed enrollment results between 19:08 and 19:11 MSK on 2026-09-07. The board is running the matched R14 pair: Node 0.8.11 and K1 0.1.11. The K1 service entered active state at 19:06:33 MSK with zero restarts. This is not an old-package or service-restart explanation.
| Journal time (MSK) | Recorded failure boundary | Device Wi-Fi write |
|---|---|---|
| 19:08:36 | BleakDBusError, ensure_device_for_gatt → find_device_by_address → active_scan:477 → assert_reply |
Not reached |
| 19:08:51 | NetworkProvisioningConflict, exact capture admission at facade.connect:11127 |
Not reached |
| 19:09:51 | Same nested discovery boundary as 19:08:36 | Not reached |
| 19:10:41 | Same revoked-capture admission as 19:08:51 | Not reached |
The first and third failures occur before BleakClient.__aenter__, service
validation, baseline read and the journalled Wi-Fi write. The second and fourth
occur even earlier. A wrong Wi-Fi password cannot cause these four failures;
this does not prove the supplied credentials correct, because K1 never received
them in these calls. No credential or raw exception payload is copied here.
R14 held a BleakScanner open while its nested resolver started a second
scanner. Bleak 3.0.2 uses one BlueZ manager/D-Bus client per loop. BlueZ permits
one discovery session per client and adapter, not one per Python scanner.
See the BlueZ Adapter API.
The retained path was absent, so these calls took that nested branch.
The Wi-Fi function then revoked the exact selected capture in finally simply
because no GATT baseline had completed. Discovery failure was thus incorrectly
treated as a failed GATT exchange. The UI classified only connect-failed as
a Bluetooth failure, leaving the form usable after resolution-failed.
The next explicit Apply met the already-revoked capture and produced the
misleading expired-search message. This is explicit invalidation, not a form
timeout or a Wi-Fi refusal.
The old journal formatter omitted structured extra fields and native D-Bus
codes. The exact native code of the historical calls was not retained. A test
using the installed Bleak manager and a synthetic D-Bus wire enforcing BlueZ's
documented single-session rule reproduces R14's exact call chain with
org.bluez.Error.InProgress. This is reproduction evidence, not a claim that
the missing historical code was recovered. The bounded Bluetooth service
journal contains no additional entries for this interval. Protected stores
were not bypassed to obtain more diagnostics.
Path ownership review
| Path | Owner and final authority | Result of review |
|---|---|---|
| Search / select in enrollment | UI selects one row from runtime + discovery + mode revision; selecting a row performs no physical connection | Retained; no automatic Apply or scan added |
| UI → Core Fleet → Node Go broker | One operation ID, durable delivery journal, deadline, exact node/runtime binding; lost response observes the same ID | Retained; delivery completion does not mean device connected |
| Node bridge → plugin facade | One bridge lock; plugin journal, lifecycle/dispatch gates and OS BLE arbiter | Retained; no second writer or recovery loop introduced |
| Fresh / retained / durable BLE identity | Exact address/native path, owner epoch and scan/session lineage; these identities have distinct admission purposes | Retained; age alone does not revoke a form selection |
| Native path resolution → Connect | Previously separate holder plus nested resolver | Replaced by one selected_device_discovery context; exact observations come from its own scanner; held through Connect and released before GATT I/O |
| Station provisioning / status read / AP activation | Different reviewed payloads and policies, same native connection lifecycle | All three use that single discovery context; one Connect, no automatic write repeat |
| Failure / cancellation cleanup | Transport lease, native callbacks and command journal have separate ownership | Removed duplicate revocation in exception and finally paths; only an attempted Connect/GATT exchange without baseline revokes a capture |
| Verify in enrollment / Verify in device detail | Facade policy, ledger lineage, exact persisted target, route, DeviceInfo and physical reconciliation | Removed the adapter-level divergence: both use the same verification_parameters; another selected device cannot inherit the saved target |
| Host Wi-Fi network list | Linux host network manager, read-only listing | Separate from BLE discovery; not a second K1 scanner |
| Wi-Fi response → control readiness | Same parent intent and owned DeviceInfo bootstrap; network-applied and control-ready are distinct | Retained; missing control confirmation never authorizes resending Wi-Fi |
| START / STOP / preview | Named acquisition, physical command journal, active session and persistent preview recording | Existing R13/R14 behavior retained; this change issues no physical test commands |
The simplification removes overlapping native discovery, duplicate failure cleanup, divergent Node verification selection and duplicated password markup. It does not combine different physical modes into a guessed fallback or erase their side-effect/identity fences.
Operator presentation and diagnostics
- Both direct and onboard enrollment consume
K1WifiPasswordField, extracted from the existing direct composition using Design GuidelineTextField,IconButtonand eye icons. Visibility resets when the value is cleared. Passwords remain absent from command journals and are cleared after submission. - Search busy, unavailable Bluetooth, missing selected K1, and other discovery
failures have distinct shared messages. They state that Wi-Fi was not sent
only with
side_effect_status=none. Unknown/after-write outcomes keep the existing read-only reconciliation path. - Legacy resolution errors are recognized as Bluetooth failures so an old result cannot leave the same invalid form open for another Apply.
- Node failure logs now print a finite allowlist of stage, native BlueZ error and write-attempt/confirmation booleans alongside the existing causal stack. Exception messages, SSID, password, frame data and locals are excluded.
Verification and delivery
The regression first failed on unmodified R14 with the same nested stack, then passed after replacing the resolver. The test uses the real pinned Bleak BlueZ manager/scanner and dbus-fast with a synthetic wire; no adapter is accessed. Tests cover cached/missing paths, timeout, busy reply, cancellation, connection failure and callback/session release for all three BLE operation kinds. Other tests cover exact address/adapter, owner and capture changes, write boundary, single submission, shared Verify admission, and password visibility.
The dev dependency explicitly includes the same pinned dbus-fast version so this contract is also tested on macOS. Linux runtime dependencies are unchanged. Detailed final check counts and artifact provenance are recorded after the release checks. R15 is Node 0.8.12 plus K1 0.1.12 and uses the existing encrypted onboard application credential. Installation and physical UI acceptance are separate from synthetic checks; neither is claimed from a successful build.
Source acceptance
- Backend connection/arbiter/journal suite: 189 passed.
- Installer and package lifecycle tests: 14 passed.
- Complete Control Station unit suite: 808 passed, including direct K1 recovery, frontend boundaries and shared password visibility.
- Node UI boundary test: 1 passed.
- Node Go enrollment tests passed.
- Control Station production build and TypeScript check passed (8.00 s).
- Ruff and Git whitespace checks passed.
The board was online and published idle acquisition before staging. The local Docker daemon was not running; no Docker startup or parallel heavy builds were used. The original canonical Core process remained on port 8000.
Built and staged R15
Source commit: 762d77ef95ccd763b7e3a0d62e04464a4f9289c1. Node production
build/typecheck passed. Both packages were inspected: no archive links, unsafe
paths or private application-key member; matching source provenance. K1 public
provenance has application_material_included=false, and every payload hash
listed in its provenance matched. Node retains the admitted Design Guideline
commit 5b882bc3d9b13a86e6c26111ef5ded687ea3a2fc. Payload regular-file counts are
71 for Node and 150 for K1.
mission-core-node_0.8.12_amd64.deb: 109838058 bytes; SHA-256b5ee0471e3dc61f5533e5e4e80b3b98a6afc73aa964f7a74fbb20d1df58ef44f.mission-core-xgrids-k1_0.1.12_amd64.deb: 318115004 bytes; SHA-2569b382258d358f8cabf5b75e4f46d3475b83856ec604a389b10d0a575ea85cd27.
The unique R15 directory is staged on the authorized board. Both remote SHA-256 checks passed. Apt simulation upgrades exactly Node 0.8.11 → 0.8.12 and K1 0.1.11 → 0.1.12, with zero additions/removals. Existing pre-install safe-state guards are unchanged. No credential extraction or replacement is included.
The native “Mission Core · K1 R15” installer is open for owner-entered sudo. Actual installation status and physical acceptance remain pending. The owner should test through the regular UI with Chrome cache cleared: fresh scan/select, password visibility, one Apply, named start, stop, and Verify after returning to the device. No physical CLI probe or scanner command was issued by the agent. CUA exposes no documented cache/click controls in this session, so clean-cache visual/hardware acceptance is not inferred from unit or source checks.
Final Core health returned HTTP 200 and ok=true. Port 8000 is still served by
the original PID 88424; its HTML references the newly built app-ClyCkvea.js and
app-DD9yVBC_.css. No service on port 8765 was started.
Installation verified after owner restart
The owner completed the Ubuntu installation and restarted. Read-only checks confirmed Node 0.8.12 and K1 0.1.12 installed. Both services are active/running with NRestarts=0; start times are 20:13:40 and 20:13:49 MSK respectively on 2026-09-07. The bounded last-five-minutes warning/error service journal returned no entries. Fleet reports the board online. Physical enrollment and acquisition acceptance remain pending the owner's next UI test.