wip(k1): checkpoint connection recovery rewrite
Capture the current unreleased K1 connection, recovery, lifecycle, viewer, and test work as a single known-bad baseline for subsequent fixes.
This commit is contained in:
@@ -0,0 +1,393 @@
|
||||
# K1 connection lifecycle and recovery runbook
|
||||
|
||||
Canonical model: [`../20_K1_CONNECTION_SUPERVISION_CANON.md`](../20_K1_CONNECTION_SUPERVISION_CANON.md).
|
||||
This runbook is the operator-facing projection of that model. Technical terms in
|
||||
the internal-safety sections are engineering evidence; they are not wizard copy.
|
||||
|
||||
## One operator wizard
|
||||
|
||||
The connection surface is one progressive wizard, not a recovery dashboard.
|
||||
Its only model-bearing heading is **Подключение XGRIDS LixelKity K1**. Inside
|
||||
the wizard the two step names are exactly **Подключение** and **Сеть**.
|
||||
|
||||
### Cold entry
|
||||
|
||||
On a clean cold entry show only:
|
||||
|
||||
- the connection-mode selector;
|
||||
- Step 01 **Подключение** with 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.
|
||||
|
||||
Do not render Step 02 yet and do not start discovery automatically. The mode
|
||||
selector and same-mode **Подключить новый K1** escape remain available through
|
||||
every other lifecycle state. The first gesture may supersede another pending
|
||||
local action. While that one bounded scenario reset itself owns `mode`, all
|
||||
three reset entry points show pending and dispatch no B intent. Each accepted
|
||||
gesture sends one idempotent local `reset_scenario` CAS: it queues behind old
|
||||
local lifecycle ownership, seals retained receiver/camera/control resources,
|
||||
invalidates candidates/drafts/credentials and retires the old physical lineage
|
||||
without resolving its outcome. It sends no BLE, device or host network command,
|
||||
MQTT publish, Verify, provisioning, START, STOP or automatic Scan. Opening and
|
||||
polling the surface still do nothing. Scan, Verify, provisioning and START
|
||||
retain separate backend gates.
|
||||
|
||||
The top-right refresh-shaped utility is the same explicit emergency reset, not
|
||||
a passive state refresh. Its accessible label is **Сбросить подключение**; while
|
||||
the request owns the current action it reads **Сбрасываем подключение** and
|
||||
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,
|
||||
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
|
||||
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
|
||||
unknown outcome must immediately render its current recovery/error surface;
|
||||
reload must neither hide that new failure nor resurrect the prior prompt.
|
||||
|
||||
### Step 01 — Подключение
|
||||
|
||||
Step 01 **Подключение** is visible immediately.
|
||||
|
||||
1. Bluetooth discovery starts only after the operator presses the search
|
||||
action.
|
||||
2. For the full bounded search, show an activity indicator and a visible
|
||||
seconds countdown in the same step.
|
||||
3. After search completes, show the result count or the empty result. Every
|
||||
connectable result row keeps the same one enabled **Выбрать** action,
|
||||
including an exact UUID used in an earlier scenario. That action is
|
||||
local-only and never invokes reopen or Verify. Fresh results never render a
|
||||
reconnect CTA, a disabled competing primary or an old/new-device decision.
|
||||
A successful admitted Scan first settles only the reset marker whose
|
||||
id/revision/mode it captured at action entry, recording the later admitted
|
||||
discovery generation while retaining the marker for idempotent reset replay.
|
||||
Failed/cancelled Scan and an older Scan racing a newer pending reset leave
|
||||
the marker active and do not expose stale recovery authority.
|
||||
4. After ordinary **Выбрать**, retain the chosen device card and reveal only
|
||||
the applicable local draft inputs. Selection itself has no loader and makes
|
||||
no controller call.
|
||||
5. Only an authoritative successful connection outcome renders Step 01 green
|
||||
as **Подключение установлено** and advances the normal connection flow.
|
||||
|
||||
The wizard never labels a candidate as saved, original, retired or physically
|
||||
ambiguous and never exposes ledger, CAS, retirement, reopen or reconnect
|
||||
terminology in the search list. Exact recovery belongs only to a previously
|
||||
established session after an actual interruption.
|
||||
|
||||
### Step 02 — Сеть
|
||||
|
||||
Step 02 **Сеть** exists only after Step 01 has a confirmed green connection.
|
||||
|
||||
- If the selected device is already usable on the chosen connection path,
|
||||
show the network result without asking for credentials.
|
||||
- If backend policy has safely admitted explicit network setup, show the exact
|
||||
retained device context and SSID/password fields here, never beside the
|
||||
candidate list.
|
||||
- One explicit submit owns any exact hidden revalidation and at most one
|
||||
reviewed network write.
|
||||
- **Изменить сеть** belongs only to this step and starts no Bluetooth search
|
||||
when its form opens.
|
||||
- A stale tab, changed runtime/binding or policy denial fails before a write and
|
||||
never exposes a foreign candidate.
|
||||
|
||||
## Ordinary selection
|
||||
|
||||
The ordinary **Выбрать** action is presentation simplification, not relaxed
|
||||
safety. It creates only a browser-local candidate draft and performs no
|
||||
controller I/O. It never selects an internal recovery path:
|
||||
|
||||
- an ordinary fresh candidate becomes only the selected local draft;
|
||||
- an exact prior candidate uses the same **Выбрать** action as every row;
|
||||
- no candidate selection retires old authority, reopens a ledger record, calls
|
||||
Verify, connects GATT, scans again or changes topology or the device;
|
||||
- a foreign, stale, non-connectable or policy-denied candidate remains
|
||||
unavailable and changes no topology, ledger or device.
|
||||
|
||||
After an explicit committed scenario reset, only its successfully completed
|
||||
successor Scan may make an exact previously retired transport eligible for a
|
||||
new network draft. Apply still captures that exact current-generation handle,
|
||||
validates the live GATT baseline and crosses at most one reviewed write edge.
|
||||
Selection performs no recovery action. At the final Apply boundary, the backend
|
||||
may append one exact request-bound local reopen checkpoint after network
|
||||
PREPARED and before write dispatch. That checkpoint preserves physical
|
||||
retirement/original-outcome audit, performs no device I/O and authorizes no
|
||||
START or STOP. The same applied intent then uses fresh DeviceInfo plus a
|
||||
non-retained DeviceStatus to settle READY as standby or identity-bound SCANNING as
|
||||
active, without a visible Verify step or command replay. In the SCANNING case
|
||||
it materializes only explicit STOP authority; it does not restart the retired
|
||||
receiver, camera, evidence writer or acquisition.
|
||||
|
||||
### Exact internal recovery for an established session
|
||||
|
||||
For an exact target belonging to a previously established session with one
|
||||
active retirement,
|
||||
`physical-command.reopen-retired-reconciliation` requires:
|
||||
|
||||
- `operator_confirmed=true`, bound to a separately explicit session-recovery
|
||||
action outside cold entry and the Bluetooth result list;
|
||||
- a stable `reopening_id` and reason
|
||||
`device-returned-for-explicit-reconciliation`;
|
||||
- exact `expected_snapshot_runtime_id`, `expected_revision`,
|
||||
`expected_retirement_id`, `expected_transport_ref` and
|
||||
`expected_discovery_generation` CAS;
|
||||
- a current connectable candidate and safe lifecycle/process ownership.
|
||||
|
||||
The transaction changes only the local durable ledger. It appends reopen audit,
|
||||
preserves the retirement and unknown command outcome as history, restores the
|
||||
original unresolved `dispatching` or `observing` stage and removes only that
|
||||
retirement's active deny. It performs zero BLE, Wi-Fi, MQTT, DeviceConfig,
|
||||
ModelingStatus, workspace, project, START or STOP I/O and starts no Scan.
|
||||
|
||||
The same still-current session-recovery action may then own one exact read-only
|
||||
Verify. Ordinary **Выбрать** never invokes either half. Recovery never replays
|
||||
historical START/STOP and never silently provisions:
|
||||
|
||||
- fresh non-retained READY resolves standby;
|
||||
- fresh exact same-project SCANNING resolves active and permits only the
|
||||
separately guarded stop path;
|
||||
- identity, GATT, CAS, route/control or policy failure leaves the outcome
|
||||
unknown and ends the established-session recovery without entering the new
|
||||
connection wizard.
|
||||
|
||||
If the action response is lost, refreshed state may continue the same click
|
||||
only when it proves that exact `reopening_id` audit was committed and every
|
||||
original runtime, candidate and authority fence still matches. A second tab,
|
||||
new discovery generation, new retirement or different reopening identity cannot
|
||||
inherit the continuation.
|
||||
|
||||
### Internal retirement
|
||||
|
||||
`physical-command.retire-unavailable` is a local durable primitive for an
|
||||
unresolved target that is truly unavailable or replaced. It may run only from
|
||||
its separately confirmed recovery/reset path, never from ordinary candidate
|
||||
selection, UI entry, polling or a timer. Admission requires explicit
|
||||
confirmation, stable `retirement_id` and exact backend runtime,
|
||||
operation, revision and transport CAS while every local owner is safe.
|
||||
|
||||
Retirement preserves the complete old attempt and unknown command outcome,
|
||||
activates an exact-transport deny and performs zero device I/O or automatic
|
||||
discovery. Retirement history remains durable even if an exact later recovery
|
||||
action uses the reopen transaction. The wizard exposes no retirement
|
||||
transaction or historical label. Any plain-language exact recovery CTA belongs
|
||||
only to the established-session surface when backend authority permits it.
|
||||
|
||||
Current FW 3.0.2 BLE `7f02` does not expose stable DeviceInfo identity. The same
|
||||
hardware under a new CoreBluetooth UUID cannot be recognized before DeviceInfo
|
||||
becomes available. This remains an explicit protocol/hardware acceptance gap;
|
||||
the wizard must not speculate.
|
||||
|
||||
## Session and freshness rules
|
||||
|
||||
A scan result is an unselected presence candidate owned by the latest explicit
|
||||
scan generation. Wall-clock age does not remove its row while the operator is
|
||||
reading or completing the form. A successor Scan, explicit scenario reset,
|
||||
runtime-owner teardown or proven exact-target GATT failure invalidates it. The
|
||||
row itself is never network authority: Apply still requires the exact captured
|
||||
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.
|
||||
|
||||
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
|
||||
local scenario-reset CAS. It can wait for and supersede live/recovery ownership,
|
||||
seal retained local producers and retire unresolved old lineage, but performs
|
||||
zero device/host I/O and starts no Scan. Scan, Verify, provisioning and START
|
||||
remain independently fenced until an explicit candidate intent crosses its
|
||||
reviewed transition. No old host route, endpoint, control, data or BLE authority
|
||||
crosses a committed reset boundary.
|
||||
|
||||
## Active scanning: transient host-path recovery
|
||||
|
||||
This is the sole automatic read-only rebind exception. It exists only after
|
||||
Mission Core itself has a composite-confirmed START and still owns the exact
|
||||
acquisition/runtime/device/connection/evidence lineage. It does not apply on a
|
||||
cold connection screen, after backend restart, to an external SCANNING K1 or to
|
||||
an unresolved/foreign START.
|
||||
|
||||
When the Mac loses Wi-Fi/route or the data socket while that acquisition is
|
||||
running, the active scanning pane shows a neutral spinner and
|
||||
**Восстанавливаем соединение** with attempt/elapsed time. Do not show a red
|
||||
terminal operation banner for the expected late failure of the superseded old
|
||||
control socket. Keep the acquisition and evidence session owned while the
|
||||
backend retries exact route/TCP and inspection-only DeviceInfo/status proof.
|
||||
|
||||
The recovery loop never sends BLE, changes Wi-Fi, writes DeviceConfig, repeats
|
||||
START or sends STOP. Outcomes are:
|
||||
|
||||
- exact same-device/same-project initialized `SCANNING`: silently resume the
|
||||
point stream/control binding and, when necessary, CAS-restart the dead or
|
||||
stalled acquisition-owned right-camera FFmpeg epoch;
|
||||
- fresh `READY`: interrupt/seal host-owned acquisition resources truthfully,
|
||||
without STOP;
|
||||
- fresh `SCAN_OVER`: persist cessation, interrupt/seal locally and retain a
|
||||
read-only `awaiting READY` fence that denies a new START;
|
||||
- wrong identity/same IP, changed lineage or failed camera CAS: remain blocked
|
||||
for explicit operator handling; and
|
||||
- device/system fault or unsafe status: show a truthful terminal fault, with no
|
||||
command retry.
|
||||
|
||||
While state is `reconnecting` or `blocked`, expose **Завершить локально**. The
|
||||
action `acquisition.force-finish-local` requires the current snapshot runtime,
|
||||
acquisition id/state revision, recovery generation, producer generation match,
|
||||
an idempotency key and explicit confirmation. It cancels recovery first, then
|
||||
seals only local receiver/camera/control/perception owners. It preserves the
|
||||
physical START ledger and sends no STOP. If a connection-mode reset races this
|
||||
action, the shared lifecycle gate makes cleanup idempotent; the loser cannot
|
||||
overwrite the new mode or revive the old acquisition.
|
||||
|
||||
If receiver, camera or evidence sealing fails, the recovery generation is
|
||||
still irrevocably cancelled first. The force-finish operation ends with a
|
||||
visible `local-cleanup-failed` result whose retryability applies only to local
|
||||
finalization; the terminal acquisition retains `cleanup_pending` and blocks a
|
||||
replacement session. A later explicit local stop or exact connection-scenario
|
||||
reset may retry those host resources. It must not retry START, STOP, BLE or a
|
||||
network write, and a late success from the retired recovery generation remains
|
||||
fenced.
|
||||
|
||||
## Failure matrix
|
||||
|
||||
| Event | Product result | Operator path |
|
||||
| --- | --- | --- |
|
||||
| Cold entry | 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 |
|
||||
| Search finds no candidates | Step 01 reports no matches | Repeat search explicitly |
|
||||
| Search finds one or many candidates | Every connectable row has one enabled **Выбрать**, including the exact prior UUID | Select one row; no reconnect or recovery action appears in search results |
|
||||
| Wall-clock time passes after Scan before selection | Latest-generation rows remain stable; no operation starts | Select normally; exact capture and live GATT will gate Apply |
|
||||
| A new Scan/reset/runtime teardown or exact-target GATT failure invalidates the generation | Old rows disappear or the attempted action fails cleanly before mutation | Run one explicit new search if needed |
|
||||
| Selection is rejected by identity, GATT, CAS, lifecycle or safety policy | Loader ends; nothing changed; Step 02 remains absent | **Повторить** or **Выбрать другое** |
|
||||
| Selection completes exact device connection | Step 01 turns green | Continue in Step 02 **Сеть** |
|
||||
| Network setup is safely required | Credentials appear only in Step 02 | Submit once |
|
||||
| Network write becomes ambiguous after dispatch | Attempt ends unknown; no replay | Wait for cleanup, then create a distinct explicit attempt |
|
||||
| Device powers off or BLE disconnects | Live selection and authority revoke after proof | Search and select explicitly after the device is available |
|
||||
| Router, Mac Wi-Fi or MQTT control is lost while idle/pre-START | Host/control authority revokes; data may remain evidence only | Restore reachability, then use the same wizard flow |
|
||||
| Mac Wi-Fi/route is briefly lost during one composite-confirmed owned acquisition | Active pane remains neutral **Восстанавливаем соединение**; no START/STOP/network retry | Wait for exact automatic read-only rebind or press **Завершить локально** |
|
||||
| Active recovery returns READY or SCAN_OVER | Local receiver/camera seal without STOP; SCAN_OVER remains fenced until fresh READY | Start another scenario only after backend policy reports it safe |
|
||||
| Active recovery sees another K1 on the same IP or changed lineage | Recovery blocks fail-closed; no camera/data resurrection | Finish locally or explicitly choose/reset connection scenario |
|
||||
| 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 |
|
||||
|
||||
## Physical START/STOP safety remains separate
|
||||
|
||||
The simplified wizard never weakens physical-command safety:
|
||||
|
||||
- loss of control does not prove that K1 stopped recording;
|
||||
- START and STOP are never replayed automatically;
|
||||
- local receiver/camera/ingress cleanup is not physical STOP;
|
||||
- an ambiguous post-dispatch command remains unknown until exact fresh proof;
|
||||
- read-only recovery is pinned to the durable transport, identity/profile,
|
||||
host epoch and project;
|
||||
- each observation publishes exactly one DeviceInfo request and may classify
|
||||
only a fresh non-retained DeviceStatus after that barrier;
|
||||
- READY records cessation without inventing a successful STOP;
|
||||
- SCAN_OVER records cessation without inventing STOP, but keeps a durable
|
||||
read-only fence until a later fresh unbound READY observation;
|
||||
- exact same-project SCANNING may mint one single-use, separately confirmed STOP
|
||||
checkpoint; it does not send STOP automatically;
|
||||
- a wrong transport/device/project changes no topology or ledger state;
|
||||
- accepted STOP without READY or SCAN_STOPPING by the backend deadline closes
|
||||
only host-owned resources, yields `timed_out` / `standby-unknown`, preserves
|
||||
the unresolved ledger and keeps mutation fenced.
|
||||
|
||||
Engineering logs and state APIs retain these distinctions. The connection
|
||||
wizard projects only the ordinary progressive flow and a non-technical terminal
|
||||
selection result.
|
||||
|
||||
## No automatic action rule
|
||||
|
||||
None of these events may scan, select, reconnect, Verify, provision, START or
|
||||
STOP:
|
||||
|
||||
- opening or resizing the connection surface;
|
||||
- backend event delivery or state polling;
|
||||
- an acknowledged scenario reset (it may perform only its explicit local
|
||||
retirement, never any listed device/network action or automatic Scan);
|
||||
- candidate list refresh after an ended search;
|
||||
- browser refresh, sleep/wake or backend restart;
|
||||
- timeout, disconnect or a historical audit record.
|
||||
|
||||
The only exception is the service-owned active-stream read-only rebind above.
|
||||
It is triggered by the already-owned receiver's transport loss, not UI entry or
|
||||
polling, and is limited to route/TCP, DeviceInfo/status inspection, receiver
|
||||
resubscribe and exact local camera-epoch restart. It never performs discovery,
|
||||
provisioning, START, STOP or any device/network write.
|
||||
|
||||
Only the currently pressed search, distinct exact recovery CTA, network submit
|
||||
or separately guarded acquisition control may own corresponding I/O. Ordinary
|
||||
**Выбрать** owns only a browser-local draft and never owns a loader. Every
|
||||
loader belongs to the explicit action that created it and ends with it.
|
||||
|
||||
## Hardware acceptance order
|
||||
|
||||
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
|
||||
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.
|
||||
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
|
||||
exactly one enabled **Выбрать** action and none auto-selects or auto-connects.
|
||||
Repeat with the exact prior UUID after reset and prove it has the same
|
||||
**Выбрать** action, with no reconnect/reopen/Verify path.
|
||||
4. Select a Bridge device, including that prior UUID, and prove the card remains visible through
|
||||
**Подключение…**, then Step 01 turns green before Step 02 **Сеть** appears.
|
||||
5. Prove network fields never coexist with candidate rows, and one explicit
|
||||
submit owns at most one write.
|
||||
6. Wait beyond the legacy candidate TTL and prove both the latest-generation
|
||||
unselected rows and an admitted selected session remain stable; then prove a
|
||||
missing exact handle/live GATT failure blocks Apply before any write.
|
||||
7. Exercise identity, GATT, stale-CAS, lifecycle-busy, disconnect and power-off
|
||||
failures; each ends the loader, leaves Step 02 absent and offers only ordinary
|
||||
retry/choose-another copy.
|
||||
8. Retire an unresolved target in controlled fault injection, perform one
|
||||
scenario reset and rediscover its exact UUID in the successor Scan. Prove its
|
||||
sole action is **Выбрать**, selection performs no I/O and Step 02 appears
|
||||
immediately. Apply once and prove exact current-generation handle capture,
|
||||
live GATT baseline, exactly one request-bound append-only physical reopen
|
||||
checkpoint and at most one network write. The original retirement/outcome
|
||||
audit remains immutable; the service-owned continuation uses only DeviceInfo
|
||||
and non-retained status, with zero START/STOP and no browser Verify. Inject
|
||||
failed and outcome-unknown network results; each current error/recovery
|
||||
surface remains visible after reload.
|
||||
9. Try a different device while old authority is unavailable and prove its
|
||||
ordinary selection triggers no hidden retirement/reopen/Verify and cannot
|
||||
bypass the durable target.
|
||||
10. Prove no row labels a device saved/original/retired, says
|
||||
**Переподключиться**, or exposes physical-state/ledger terminology. The model name
|
||||
appears only in the top heading; step names remain **Подключение / Сеть**.
|
||||
11. During a composite-confirmed live acquisition, remove host Wi-Fi for longer
|
||||
than the old control keepalive and restore it. Prove neutral reconnecting,
|
||||
same-lineage SCANNING resume, raw-writer continuity, exact camera epoch
|
||||
restart when stalled, and zero START/STOP/BLE/network mutation. Repeat with
|
||||
READY, SCAN_OVER, wrong identity and permanent loss plus
|
||||
**Завершить локально**.
|
||||
12. Repeat idle/pre-START Bridge network loss, Mac Wi-Fi switch, sleep/wake,
|
||||
hard K1 power loss, STOP deadline and backend restart; prove zero automatic
|
||||
command or retry outside the sole active-stream exception.
|
||||
13. Repeat the entire acceptance separately for Quick Connect before claiming
|
||||
Quick coverage.
|
||||
|
||||
The current software contract is not real-hardware acceptance. The acceptance
|
||||
manifest lists executable coverage and the remaining Bridge/Quick field gaps.
|
||||
Reference in New Issue
Block a user