NODEDC_MISSION_CORE/docs/adr/0013-k1-local-connection-ma...

157 lines
9.3 KiB
Markdown

# ADR 0013: explicit K1 local connection matrix
- Status: amended 2026-07-20; Bridge is the product path, Quick Connect retained as a prepared-host laboratory path
- Date: 2026-07-19
- Extends: ADR 0004, ADR 0005 and ADR 0012
## Context
Mission Core v0.5.0 exposed only the already accepted shared-LAN path even
though the product UI named the other XGRIDS connection directions. Retained
owner-operated evidence establishes two different network ownership models:
- the K1 joins a network whose credentials are sent in the reviewed 99-byte BLE
provisioning frame; and
- the controller joins the K1 access point and then reaches the same local
MQTT/RTSP data plane at the observed AP address.
Official workflow notes separately name Bridge, Direct Connect and Quick
Connect. The names alone do not authorize another BLE command or an inferred
credential decoder.
## Decision
Plugin v0.6.0 exposes three explicit, fail-closed choices under one exact
firmware `3.0.2` compatibility profile:
| UI mode | Topology | Device action | Host action | Acceptance |
| --- | --- | --- | --- | --- |
| Bridge | `direct-lan` | one reviewed BLE provisioning write | none | physically accepted in Mission Core |
| Direct Connect | `controller-hotspot` | the same reviewed BLE provisioning write | operator prepares the hotspot and route | implementation complete; physical run pending |
| Quick Connect | `device-ap` | one fixed reviewed 100-byte AP-enable write | preinstalled exact-firmware credential provider, bounded exact-SSID discovery and one association | physically accepted on one prepared Mac; not portable bootstrap |
Bridge remains the default. Every API request carries both `connection_mode`
and its exact topology attestation; mismatched pairs are rejected before any
network action. Acquisition and camera admission must match the active mode.
The fixed K1 AP address is admitted only after a successful Quick Connect host
association.
Bridge and Direct Connect do not have a fixed product IP. The address reported
by BLE characteristic `7f02` is a DHCP lease observation scoped to the current
connection, never device identity and never a durable configuration value.
Before a new application-control session, an implicit-host acquisition, or a
factory-calibration read, Mission Core performs one read-only `7f02` read for
the selected CoreBluetooth device and replaces the previous target. An address
change creates a new `device_session_id` and invalidates calibration captured
for the previous session. An active acquisition is never retargeted in place.
The later correlated MQTT `DeviceInfo` response supplies model, firmware,
serial and vendor identity; IP equality alone cannot identify a K1.
Product decision on 2026-07-20: Bridge/direct-LAN is the continuing route.
Quick Connect remains visible and executable on an already prepared host, but
is not a deployment dependency or portability claim.
Direct Connect does not introduce a new vendor payload. The operator first
starts a hotspot on the controlling device and enters that hotspot's SSID and
password. Mission Core performs the same single, physically reviewed BLE write
used by Bridge and accepts only the non-AP private IPv4 returned by K1 status.
Quick Connect does not accept a credential from the browser/API. The first
implementation incorrectly jumped from BLE discovery directly to host Wi-Fi
association. A physical negative run showed that the selected K1 was still on
the existing LAN and the expected AP was not visible. Re-review of the exact
LixelGO branch recovered the missing state transition: after BLE connection it
writes one 100-byte `7f01` frame, zero except for `0x01` at offset 99, and treats
the callback as the AP-launch result before invoking the OS Wi-Fi connector.
Mission Core now performs that bounded AP-enable write at most once. The first
physical run reached `WIFI_AP` at the reviewed AP address, and a targeted
CoreWLAN scan found the SSID matching the selected BLE advertised name. It also
disproved the earlier assumption that LixelGO carried one global Quick Connect
profile: retained client analysis exposes `WiFiAP_SSID` and `WiFiAP_Password` as
fields of each device record.
A subsequent run found that `7f02` may retain `WIFI_AP / 192.168.56.1` after the
SSID stops beaconing. Static review then recovered the missing discriminator:
LixelGO maps response byte 51 to its AP-ready flag and waits up to 15 seconds for
that flag. Mission Core therefore mirrors LixelGO: every new operator Quick
Connect action emits exactly one reviewed enable frame, including from a
`WIFI_AP` baseline, and admits host discovery only after byte 51 becomes
non-zero. This is not an automatic retry.
The same review proved that LixelGO does not close its BLE manager between the
AP-ready callback and native Wi-Fi connect. A failed Mission Core run had done
exactly that: byte 51 changed from zero to one, the Python BLE context exited,
and the following cold Swift/CoreWLAN process missed the beacon. The corrected
implementation holds the selected `BleakClient` open through bounded native
SSID discovery and the single association call.
BLE discovery and the selected device action form one host session. A physical
run proved that immediately rediscovering the same K1 by its CoreBluetooth UUID
can fail even though the preceding scan exposed it. Mission Core retains the
non-serializable `BLEDevice` handle process-locally and uses that exact handle
for the next selected network action; it never exposes the handle through API
state or treats the macOS UUID as durable device identity.
The corrected host boundary derives a non-secret, device-scoped profile ID from
the selected SSID. The reviewed client contains per-device `WiFiAP_SSID` and
`WiFiAP_Password` fields, but the 2026-07-20 review of the exact official K1
`3.0.2` firmware recovered their upstream source: the scanner's bundled
NetworkManager AP script assigns one firmware-constant WPA2 material, while
`lixel_nman` constructs `XGR-` plus six device-identity characters with a MAC
fallback. It is neither an iPhone credential nor a per-device secret.
The laboratory implementation can install a firmware-scoped credential source from the
authenticated official archive. The offline importer validates the exact
SHA-256, streams the bounded application-partition range, requires one valid AP
declaration and writes the value to the OS secure store through helper stdin.
On macOS, the Keychain helper materializes the selected device profile from
that opaque source before any BLE write. A missing provider fails closed. The
browser, API, argv, logs, manifests and evidence never receive the secret; the
importer's short-lived mutable buffer is zeroized after the Keychain handoff.
The host-network boundary, rather than the XGRIDS frontend, owns platform
association. Browsers expose no Wi-Fi join API, and Apple's iOS
`NEHotspotConfiguration` consent flow is unavailable on macOS. The current
implementation therefore uses a short-lived Swift/CoreWLAN + macOS Keychain
helper; Windows Credential Manager and Linux Secret Service adapters remain
separate platform work. The helper performs repeated read-only exact-SSID scans
inside one 15-second discovery window and at most one association. It never
repeats the BLE command, guesses a password or treats `7f01` as a credential-read
command. The credential-bearing 99-byte station-provisioning frame and fixed
100-byte AP-enable frame are separate reviewed payloads.
No reviewed BLE characteristic or response supplies the AP credential. That
does not prove a universal negative for every vendor build, but it means the
current plugin has no evidence-backed device-side credential acquisition path.
The owner also observed no explicit device/account pairing in the normal
LixelGo onboarding flow; this is consistent with a firmware-defined AP secret,
but does not establish account-wide authorization for arbitrary scanners.
Connection verification refreshes the session-scoped lease with the same
read-only BLE status operation. It does not write a characteristic, re-provision
Wi-Fi, scan the subnet, change a host route, or touch VPN configuration. The
later canonical MQTT session supplies the real data-plane connection and live
`DeviceInfo` identity check. A BLE lease observation is therefore not by itself
a claim that MQTT/RTSP is reachable.
## Consequences
- The UI now represents all three intended directions instead of disabled
placeholders.
- Quick Connect can temporarily remove the controlling host from its previous
Wi-Fi network. The operating system may require Wi-Fi/location permission.
- A new host needs a separate exact-firmware provider installation. The current
application does not obtain it from BLE and does not bootstrap it by itself.
- Automatic firmware download, iPhone extraction and hard-coded credential
delivery are explicitly rejected product routes. Windows/Linux adapters are
therefore not scheduled for this Quick Connect path.
- Direct Connect requires an already-running hotspot and a controller route;
Mission Core does not create or manage that hotspot.
- The application-control, START/STOP and raw-first acquisition protocol is
unchanged after a target address is admitted.
- Direct Connect remains explicitly pending one owner-operated physical
acceptance cycle. Quick Connect AP activation and host association are
physically accepted only on the prepared K1/FW 3.0.2 Mac stand. Bridge is the
only accepted portable product path in this matrix.