chore(k1): checkpoint connection recovery work
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# K1 connection supervision canon
|
||||
|
||||
Status: canonical target and product acceptance contract, updated 2026-08-11;
|
||||
Status: canonical target and product acceptance contract, updated 2026-08-20;
|
||||
implementation/hardware conformance remains tracked by the acceptance manifest.
|
||||
|
||||
Operator recovery procedure: [`runbooks/K1_CONNECTION_RECOVERY.md`](runbooks/K1_CONNECTION_RECOVERY.md).
|
||||
@@ -16,10 +16,12 @@ point packet means that the device is connected.
|
||||
|
||||
The product goal is a simple operator-owned lifecycle: every app start,
|
||||
disconnect, explicit stop, or committed network-mode transition ends the old
|
||||
connection session. A normal connection has one discovery intent and one
|
||||
application intent: the operator explicitly searches, selects one fresh result,
|
||||
enters the network data immediately, and presses **Применить** once. Opening the
|
||||
UI, selecting a result and editing credentials are presentation inputs only.
|
||||
live connection authority. The last exactly confirmed K1 and topology remain a
|
||||
durable read-only fast-reconnect target until the operator changes the device or
|
||||
network. A normal new connection has one discovery intent and one application
|
||||
intent: the operator explicitly searches, selects one fresh result, enters the
|
||||
network data immediately, and presses **Применить** once. Opening the UI,
|
||||
selecting a result and editing credentials are presentation inputs only.
|
||||
Changing mode is one explicit local scenario-reset operation; it performs no
|
||||
device or host I/O and starts no discovery. Historical attempts are audit
|
||||
evidence only. They never
|
||||
@@ -109,9 +111,14 @@ terminology, physical-ledger state and protocol recovery names are not operator
|
||||
ceremonies.
|
||||
|
||||
1. A cold plugin section shows the connection-mode selector and Step 01
|
||||
**Подключение** with its explicit Bluetooth search action. Historical K1
|
||||
identity never adds a reconnect prompt on cold entry. Opening or polling the
|
||||
surface performs no action.
|
||||
**Подключение**. When an exact last confirmed K1 and unchanged topology are
|
||||
available, it shows the saved target with **Переподключиться** plus the
|
||||
separate **Найти по Bluetooth** path. The reconnect action performs only a
|
||||
server-pinned read-only observation; it sends no network settings, START or
|
||||
STOP. A browser-cache reset or local scenario reset closes live authority but
|
||||
does not erase this durable offer. Audit-only historical identities do not
|
||||
create it. Without an eligible durable target, Step 01 shows only the explicit
|
||||
Bluetooth search action. Opening or polling the surface performs no action.
|
||||
Each selector/escape gesture sends one explicit CAS-fenced
|
||||
`reset_scenario`; it may seal only old local receiver/camera/control owners
|
||||
and retire their audit lineage, but performs no BLE, device/host Wi-Fi,
|
||||
@@ -173,9 +180,11 @@ reopened record from fresh DeviceInfo plus non-retained DeviceStatus: READY
|
||||
settles standby, while identity-bound initialized SCANNING settles active without replaying
|
||||
START and materializes only a STOP-only control shell. A reset-owned settlement
|
||||
never restarts the retired receiver, camera, evidence writer or acquisition.
|
||||
Exact operator-facing physical recovery keeps its backend CAS and
|
||||
transport pinning, but appears only inside an established session after an
|
||||
actual interruption, never in cold entry or Bluetooth results.
|
||||
Exact operator-facing physical recovery keeps its backend CAS and transport
|
||||
pinning and remains distinct from cold fast reconnect. Fast reconnect only
|
||||
re-proves an unchanged saved target; unresolved physical START/STOP state still
|
||||
uses the stricter recovery path. Neither action appears inside Bluetooth result
|
||||
rows.
|
||||
|
||||
Outside that reset-owned STOP-only settlement, fresh non-retained READY proof
|
||||
resolves physical ambiguity as standby; fresh exact same-project SCANNING resolves it as active and exposes only the
|
||||
@@ -248,7 +257,7 @@ not fabricate the state of another row.
|
||||
|
||||
| Boundary that can fail | Typical real scenario | Required response |
|
||||
| --- | --- | --- |
|
||||
| Browser ↔ local API | app refresh/restart, closed tab, suspended renderer, lost HTTP response | App restart/close ends its operator connection session without sending a device command; a single lost response never repeats an action. The next app session starts with discovery and selection. |
|
||||
| Browser ↔ local API | app refresh/restart, closed tab, suspended renderer, lost HTTP response | App restart/close ends live operator authority without sending a device command; a single lost response never repeats an action. When an exact last confirmed K1/topology remains durable, the next app session offers an explicit read-only fast reconnect alongside fresh discovery. Otherwise it starts with discovery and selection. |
|
||||
| Mission Core process | crash, upgrade, second process, stale worker thread | Close the active connection session on restart; retain terminal audit only; stable process locks prevent a second controller; old runtime generations cannot publish evidence into a new session. |
|
||||
| CoreBluetooth discovery/GATT | K1 powers off, Mac sleeps, disconnect callback arrives, scan callback arrives late | Close and clear the selected session on proven disconnect. A later operator scan and selection establish a new GATT connection. Unselected rows remain stable for the latest admitted scan generation and are invalidated only by an explicit successor/reset, runtime-owner teardown or proven exact-target GATT failure. A row never grants mutation authority without exact-handle capture and live GATT validation. |
|
||||
| Mac Wi-Fi association | Quick AP is left manually, Bridge router changes, same IP is reused by another AP | Rotate host epoch using an opaque OS association identity in addition to route/interface/source IP. Rebuild TCP and protocol proof. |
|
||||
|
||||
@@ -12,16 +12,19 @@ the wizard the two step names are exactly **Подключение** and **Се
|
||||
|
||||
### Cold entry
|
||||
|
||||
On a clean cold entry show only:
|
||||
On a clean cold entry show:
|
||||
|
||||
- the connection-mode selector;
|
||||
- Step 01 **Подключение** with the explicit Bluetooth search action.
|
||||
- Step 01 **Подключение**;
|
||||
- when an exact last confirmed K1 and unchanged topology are durable,
|
||||
**Переподключиться** and the separate **Найти по Bluetooth** path;
|
||||
- otherwise only the explicit Bluetooth search action.
|
||||
|
||||
Historical K1 identity never adds a reconnect choice to cold entry. If local
|
||||
session ownership or an older connection scenario exists, one explicit
|
||||
`reset_scenario` CAS first closes only that local scenario. Only after the reset
|
||||
is accepted does clean Step 01 expose **Найти по Bluetooth** as a separate
|
||||
click; reset never starts Scan itself.
|
||||
**Переподключиться** is a read-only fast connection to the server-pinned last
|
||||
K1. It does not send network settings, START or STOP. Historical audit identity
|
||||
alone never creates this choice. A browser-cache reset or accepted
|
||||
`reset_scenario` closes the old live/local authority but does not erase the
|
||||
last confirmed target. Reset never starts reconnect or Scan itself.
|
||||
|
||||
Do not render Step 02 yet and do not start discovery automatically. The mode
|
||||
selector and same-mode **Подключить новый K1** escape remain available through
|
||||
@@ -42,12 +45,14 @@ the request owns the current action it reads **Сбрасываем подклю
|
||||
does not dispatch a second reset until that bounded request settles. It remains
|
||||
available to supersede any other local action. The accepted revision always
|
||||
returns the new local scenario and even a dirty browser selector to canonical
|
||||
**Bridge**, clears the old browser/backend presentation and source owners, and
|
||||
leaves Scan as a separate click. It performs no hidden Scan, Verify, Connect,
|
||||
**Bridge**, clears old browser drafts and source owners, and leaves both an
|
||||
eligible durable fast reconnect and Scan as separate clicks. It performs no
|
||||
hidden Scan, Verify, Connect,
|
||||
START, STOP, BLE or network write and never substitutes a passive `state.read`
|
||||
for the reset mutation. After settlement the product surface contains no prior
|
||||
UUID, result count, **Повторить поиск**, reconnect error, selected device,
|
||||
credentials or recovery card; it returns to **Найти по Bluetooth**. Late
|
||||
for the reset mutation. After settlement the product surface contains no stale
|
||||
result count, **Повторить поиск**, reconnect error, selected draft or
|
||||
credentials. It retains only the exact durable fast-reconnect card when one is
|
||||
eligible, alongside **Найти по Bluetooth**. Late
|
||||
Scan/Verify settlements from the retired scenario cannot repopulate it.
|
||||
The retained reset marker fences only work that belonged to the retired
|
||||
scenario. A newly correlated post-reset network attempt that fails or has an
|
||||
@@ -196,8 +201,10 @@ CoreBluetooth object and live GATT validation before any write.
|
||||
|
||||
The selected session ends on proven disconnect, explicit lifecycle stop, a
|
||||
committed network transition, selection of another device, backend restart or
|
||||
proven native cleanup. A later connection always requires an explicit search
|
||||
and **Выбрать**. Polling can update presentation but starts neither operation.
|
||||
proven native cleanup. A later new-device connection requires an explicit search
|
||||
and **Выбрать**. An unchanged exact last confirmed K1 may instead use the
|
||||
explicit read-only fast reconnect. Polling can update presentation but starts
|
||||
neither operation.
|
||||
|
||||
Bridge, Quick Connect and Direct Connect are separate topologies. In
|
||||
any state, changing the mode or choosing another K1 in the same mode sends one
|
||||
@@ -260,7 +267,8 @@ fenced.
|
||||
|
||||
| Event | Product result | Operator path |
|
||||
| --- | --- | --- |
|
||||
| Cold entry | Mode plus Step 01 and explicit Scan; zero device I/O before Scan | Start search explicitly |
|
||||
| Cold entry with an exact last confirmed K1/topology | Mode plus Step 01, read-only **Переподключиться**, and separate explicit Scan; zero device I/O before a click | Fast reconnect or start search explicitly |
|
||||
| Cold entry without an eligible durable target | Mode plus Step 01 and explicit Scan; zero device I/O before Scan | Start search explicitly |
|
||||
| Disconnected/idle mode or same-mode new-device request with unresolved durable physical history | Local session/audit lineage is retired under one reset CAS; zero device/host I/O and no automatic Scan | Start the clean Step 01 search explicitly; the old physical outcome remains auditable |
|
||||
| Mode reset while live, reconnecting or terminal cleanup still owns local sources | Reset supersedes recovery and locally seals receiver/camera/control; previous K1 may still scan | Wait for the bounded local cleanup or retry the same reset if local sealing fails |
|
||||
| Search running | Step 01 spinner and visible countdown | Wait or let the bounded search end |
|
||||
@@ -280,7 +288,8 @@ fenced.
|
||||
| A physical START/STOP edge is unresolved | Mutation stays fenced; no technical wizard ceremony | Search/select remains explicit; backend admits only a safe exact path |
|
||||
| Exact actively retired UUID is present after committed reset and successor Scan | The row exposes the same enabled **Выбрать** as every candidate | Select locally; Apply remains exact-handle/live-GATT gated and may append one internal local settlement checkpoint before its sole write; audit remains append-only and START/STOP stay denied until fresh read-only classification |
|
||||
| Another candidate is selected while old authority is unavailable and no reset-owned new scenario exists | Selection stays local and Apply remains denied | Start an explicit new connection scenario, then Scan and select again |
|
||||
| Browser refresh or backend restart | No automatic operation and no restored live selection | Begin from the cold progressive wizard |
|
||||
| Browser refresh or cache reset | No automatic operation and no restored live authority; exact durable last target remains available for read-only fast reconnect | Reconnect explicitly or begin a fresh Bluetooth search |
|
||||
| Backend restart without an eligible durable target | No automatic operation and no restored live selection | Begin from the cold progressive wizard |
|
||||
|
||||
## Physical START/STOP safety remains separate
|
||||
|
||||
@@ -336,15 +345,19 @@ loader belongs to the explicit action that created it and ends with it.
|
||||
|
||||
Software tests do not replace a real K1/macOS/router run. Accept sequentially:
|
||||
|
||||
1. Open cold and prove mode plus Step 01 and its explicit Scan action are
|
||||
visible, while Step 02 is absent and no discovery starts automatically. With both empty and
|
||||
1. Open cold and prove mode plus Step 01 are visible, while Step 02 is absent
|
||||
and no discovery starts automatically. With an exact last confirmed K1 and
|
||||
unchanged topology, prove **Переподключиться** and **Найти по Bluetooth** are
|
||||
both available after reload and browser-cache reset; reconnect performs only
|
||||
read-only verification. With no eligible durable target, prove only explicit
|
||||
Scan is available. With both empty and
|
||||
unresolved durable physical history, change the mode and prove one local
|
||||
reset CAS, zero device/host calls and no automatic Scan. Repeat from active,
|
||||
reconnecting and terminal `cleanup_pending` states; prove local sources are
|
||||
sealed, the old K1 is not claimed stopped, and a local cleanup failure leaves
|
||||
the exact reset retryable. With an exact prior connection, prove cold entry
|
||||
contains no historical reconnect prompt; after one reset CAS and zero Scan,
|
||||
a separate clean **Найти по Bluetooth** action remains clean after reload.
|
||||
the exact reset retryable. With an exact prior connection, prove one reset
|
||||
CAS and zero Scan preserve its fast-reconnect card and a separate clean
|
||||
**Найти по Bluetooth** action after reload.
|
||||
2. Start discovery and prove the spinner and seconds countdown remain visible
|
||||
for the bounded search, then the exact result count appears.
|
||||
3. With multiple advertisements, prove every ordinary connectable row keeps
|
||||
|
||||
Reference in New Issue
Block a user