Add Broker client and writer quick dialogs

This commit is contained in:
2026-09-13 14:40:51 +02:00
parent 9f6ebf2053
commit 7ccc8799e9
9 changed files with 274 additions and 32 deletions
+1 -1
View File
@@ -245,7 +245,7 @@ Bounds:256-byte/four-receive request,128-byte snapshot,96-byte result, one slot;
The broker copies compact client rows and writer/lease generation together under its existing mutex with zero wait. Conditional assignment compares generation and connected non-reused target under the same force-writer lock before any effect. Lease grant/release/revoke events advance a separate saturating32-bit generation before delivery attempts, including same-writer ABA; counter clears and dropped events cannot invalidate this fence. UINT32_MAX disables conditional assignment, not ordinary transport/console recovery. Client IDs retain three slot/29 generation bits, but exhausted slots now retire until reboot rather than reusing IDs. Reboot invalidates originating web sessions. Existing unconditional force APIs and one-writer/multiple-observer policy remain unchanged.
Browser Settings/Broker shows safe ID/type/name/role/pending/HWM/drop rows and clears selection on Refresh. Native confirmation captures exact target/generation before session revalidation. Viewing/selecting never mutates; completion checks are bounded to10 one-second GETs/15seconds, no mutation replay. There are no contextual popovers or diagnostic/service controls. Complete contracts, wrap analysis, evidence and pending parent/target review: `docs/phase8d16_implementation.md`.
Browser Settings/Broker shows safe ID/type/name/role/pending/HWM/drop rows. **8D.18** reuses this controller in8D.17's sole nonmodal quick host for admin-only Broker clients/Active writer entrances; no second DOM/draft/backend. Contextual snapshots refresh5seconds after successful completion with one active Broker controller and5-second whole-read deadline, stopping on error/uncertainty/departure. Explicit selection retains its identity and lease version across refresh; stale/absent latches cannot be cleared by later matching snapshots, only deliberate reselection. Native confirmation captures exact target/generation before session revalidation. Viewing/selecting never mutates; completion checks remain bounded to10 one-second GETs/15seconds, no mutation replay. New contextual triggers never navigate away from full-page drafts; promotion preserves selection/controller, stops live scheduling. Both terminals receive with input isolated; focused controls use guarded aria-disabled state to avoid focus loss during refresh. No diagnostic/service controls. Backend/wrap contract: `docs/phase8d16_implementation.md`; current UI/test/target limits: `docs/phase8d18_implementation.md`.
## Local UI and hardware boundaries
+2
View File
@@ -61,6 +61,8 @@ This is a semantic map, not a complete file inventory. Start here, then read the
## Web and WebSocket serial
- **8D.18 client/writer contexts (2026-09-13):** `web_ui.c` extends8D.17's sole quick host with admin-only Broker clients/Active writer entrances to the existing Broker controller/native confirmation. One5-second-after-success live timer and5-second whole-read deadline; explicit identity/lease token retained across refresh, sticky stale/absence latches prevent rebasing/resurrection. Full-page drafts untouched by new triggers; focused controls retain focus with guarded aria-disabled state. No backend/policy/assets/CPU/transport changes. `tests/web_ui_session/{broker.cjs,layout.py}`:135 UI groups+renderer/HTML/CSP; broad broker/auth/lifecycle/transport regressions PASS. Baseline100,300/1,788,661 → final100,300/1,793,301 RAM/flash (+0/+4,640 B), CPU160 verified. Independent parent review and target sign-off pending. Exact contracts/tests/limits/checklist: `docs/phase8d18_implementation.md`.
- **8D.17 quick settings (2026-09-13):** `web_ui.c` owns Serial/Wi-Fi status-trigger nonmodal popovers using the single existing settings DOM/controller, no parallel drafts/endpoints. Secret-free Network quick mode excludes password controls; full-page promotion preserves controller/nonsecret draft, dismissal fences reads/polling without replay. Hover/focus/click/tap, Escape/outside dismiss; full-page drafts protected from hover. Tests `tests/web_ui_session/{browser,network}.cjs`, `layout.py`:126 UI groups + renderer/HTML/CSP PASS; optional Chromium geometry blocked by sandbox, target/independent parent review pending. Baseline100,300/1,782,613 → final100,300/1,788,629 RAM/flash (+0/+6,016 B). CPU160/combined WS send/Broker/Display unchanged. Contract, exact tests and checklist: `docs/phase8d17_implementation.md`.
- **8D.16 Broker (2026-09-13):** `web_broker_settings.{c,h}` owns optional admin-only GET `/api/settings/broker`, GET/POST `/api/settings/broker-operation`; existing dispatcher queues only IDs. `web_ui.c` adds Serial/Display-style full-page rows and explicit confirmed assignment, no mutation on view/selection. 256-byte/four-receive request,2048-byte snapshot,96-byte result, one login-bound slot/no timer;33 handlers/six sockets, unchanged tasks/stacks/queue/assets/CPU160/combined WS send. Tests: cookie `--broker`6+shared, broker management/wrap, dispatcher, lifecycle25, UI119+HTML/CSP and broad regressions. Baseline100,196/1,765,233 B → final100,300/1,782,613 RAM/flash. Independent parent review and target sign-off pending. Contracts/resources/checklist: `docs/phase8d16_implementation.md`.
+2
View File
@@ -4,6 +4,8 @@ This file is working memory. Update it during active work and before handoff; do
## Development state
- **8D.18 implemented (2026-09-13), user-authorized; host/build verified, independently reviewed; target sign-off pending:** UI-only Broker clients/Active writer contexts reuse8D.16 snapshot/lease fence/operation controller and8D.17 single host/native confirmation/dismissal focus fix.5-second-after-success single-flight live refresh with5-second whole-read deadline; errors/timeouts stop, no auto error/mutation retry. Explicit selection identity+lease token is never rebased; stale/absent latches prevent resurrection, consumed selection requires explicit reselection. New triggers preserve full-page Serial/account/Network drafts even on activation; quick promotion preserves selection/controller and stops live timer. Focused controls use aria-disabled plus existing handler guards rather than native focus loss; previous terminals keep receiving with input isolated. Initial worktree clean. PASS135 UI groups+renderer/HTML/CSP, broker management/wrap, cookie Broker+base/all existing variants, lifecycle25, dispatcher/canonical accounts/Network, parser294, transports/tickets/store, idle/diagnostics/performance/security/login and diff check. Broad tests preceded final focus refinement; full UI/build rerun afterward. Independent reviewer found no confirmed actionable defects and reran UI135+renderer/HTML/CSP, canonical broker management/wrap, cookie Broker and diff checks PASS. Parent final pio confirmation PASS6.89s100,300/1,793,301 B; diff check PASS. Native picker during live updates and actual blank/reselect remain browser-validation gaps, not proven defects. Baseline pio7.02s100,300 RAM/1,788,661 flash; final21.52s100,300/1,793,301 (+0/+4,640 B). CPU160 defaults/active/generated verified, combined WS send unchanged. No backend/API/policy/assets/config/dependencies/icons/8D.15/19/later/upload/erase/commit/SDK changes. No real-browser geometry/accessibility or device tests this phase; no reserve/M3 claim. Exact contract, test-development corrections and pending parent/target checklist: `docs/phase8d18_implementation.md`. Stop before any separately authorized next phase.
- **8D.17 independent-review P2 fixed (2026-09-13), independently confirmed resolved:** Quick dismissal now restores Serial/Admin state/input without xterm focus; automatic departure and adjacent-trigger switches preserve focus, Escape/Close focus only trigger. Observable Terminal.focus harness reproduced adjacent-trigger failure before fix;128 UI groups+renderer/HTML/CSP PASS, pio21.90s100,300 RAM/1,788,661 flash (+0/+32 B review delta; phase+0/+6,048 B), diff check PASS. Two new groups cover adjacent keyboard triggers and timed/outside-pointer dismissal/explicit focus for both terminal backgrounds. Existing uncommitted work preserved; no unrelated source/device/assets changes. Reviewer confirmed no new actionable findings and independently reran128 UI groups+renderer/HTML/CSP and diff checks PASS. Parent final build confirmation PASS6.98s,100,300/1,788,661 B; diff check PASS. Exact correction in `docs/phase8d17_implementation.md`; target/geometry limits remain.
- **8D.17 implemented (2026-09-13), user-authorized; host/build verified, independent parent review and target sign-off pending:** UI-only Serial/Wi-Fi quick popovers reuse the sole settings DOM/validators/controllers and typed endpoints. Hover/focus/click/tap, Escape/outside dismissal, bounded scrollable panel, full-page promotion, explicit Apply/Save; Network excludes password controls and clears transient input. Full-page hover cannot steal drafts; focused quick editor resists unrelated hover. Close fences reads/checks, preserves pending uncertainty/no replay; both terminals drain with selected input disabled, previous terminal restored on close. Worktree initially clean. PASS126 UI groups+renderer/HTML/CSP, cookie base/all existing variants, lifecycle25, dispatcher/canonical accounts/Network/broker, parser, transports/tickets/store, idle/diagnostics/performance/security/login regressions and diff check. Optional Chromium18-case geometry attempt failed before measurement (sandbox process-singleton socket/Crash Reports), no geometry pass. New test Serial ack fixture schema fixed and final suite/build passed. Baseline pio6.88s100,300 RAM/1,782,613 flash; final21.74s100,300/1,788,629 (+0/+6,016 B). CPU160 defaults/active/generated confirmed; signed-off combined WS/Broker8D.16/Display unchanged. No backend/API/assets/config/dependencies/icons/8D.18/8D.15/upload/erase/commit. Exact ownership, tests/limits/resources and target checklist: `docs/phase8d17_implementation.md`. Parent will independently review; no target/reserve/M3 sign-off.
+2
View File
@@ -66,6 +66,8 @@ Phase 8D.2 adds a third identity: non-reused 64-bit originating web-session IDs
**Wrap contract:** Three-slot-bit/29-generation-bit broker IDs now retire exhausted slots instead of wrapping. A32-bit lease generation saturates at UINT32_MAX, survives counter clear, and advances for each grant/release/revoke emission before advisory queue delivery. Forced transfer can advance twice; it is an opaque version, not a count. Saturation rejects typed assignment but never prevents normal release/disconnect/request or recovery force. Future writer transitions must preserve the central event-emission invariant. Reboot resets broker state but invalidates web sessions, so authorized old browser work cannot span boots.
**8D.18 browser selection contract:** Live refresh preserves explicit target identity and its original lease token, not just the select value. Lease/identity mismatch, absence or failed read latches invalidation; later matching snapshots cannot resurrect validity or silently reselect a missing target. Only explicit reselection captures a new token, and transfer still requires separate confirmation. One shared quick/full controller fences reads/operations; contextual activation never destroys full-page drafts. Focused controls remain focusable with aria-disabled while independent action guards reject unavailable work. See `docs/phase8d18_implementation.md` for bounds and test limits.
**Consequence:** Never implement snapshot-check-unlock-force, compare only current writer ID, or renew a confirmation implicitly during Refresh. UI must require explicit target selection and confirmation, retain uncertain-outcome handling and never retry mutations automatically. Bounded login-isolated result slots and the existing dispatcher remain the typed HTTP boundary. Details/tests: `docs/phase8d16_implementation.md`, `src/session_broker.{c,h}`, `src/web_broker_settings.{c,h}`.
## UART0 is the physical recovery authority
+113
View File
@@ -0,0 +1,113 @@
# Phase 8D.18 — Client/writer contextual dialogs
## Status and scope (2026-09-13)
User-authorized 8D.18 implementation complete; host tests and bounded firmware builds pass. **Independent review complete with no confirmed actionable defects; target/user sign-off remains pending.** Reviewer independently reran135 UI groups+renderer/HTML/CSP, canonical broker diagnostics/management/wrap, cookie Broker and diff checks PASS. Parent final build confirmation PASS6.89s,100,300 B RAM/1,793,301 B flash; diff check PASS. Native picker behavior during live option updates and real blank-to-target reselection remain target checks, not established by direct Node change events. No M3 or memory-reserve approval. Initial read-only Git status was empty; no preexisting work was removed.
Only `src/web_ui.c`, `tests/web_ui_session/{broker.cjs,layout.py}` and phase/agent documentation changed. No backend, writer policy, API, dispatcher, task, queue, stack-size, schema, dependency, icon, generated asset, SDK or configuration changes. No 8D.19/later or removed 8D.15 diagnostics. No upload, erase, commit or branch creation. The signed-off CPU160 combined binary WebSocket send remains untouched.
## Implementation plan and completed source set
1. Read code-map, current-state, relevant architecture/design decisions and exact 8D.18 row; inspect 8D.17's single quick host/focus correction and 8D.16's typed Broker controller and lease-fence contract.
2. Establish clean-worktree/bounded-build baseline. Reuse the existing Broker snapshot, session validation and operation controller, not a second backend or UI owner.
3. Extend the existing status-trigger/nonmodal quick host to Broker clients and Active writer. Preserve terminal receive/input isolation, dismissal focus semantics and full-page draft ownership.
4. Introduce one explicit selection record and single-flight, deadline-bounded live snapshot refresh. Never renew selection tokens implicitly; latch invalidation and retain visible stale-result/uncertainty messages.
5. Extend emitted-production-JS, parsed HTML and existing broker/auth/lifecycle regressions; build, verify CPU160 and record exact limits and pending target checks.
All five steps completed. Shared firmware APIs already supplied the required correctness boundary; no owner adaptation was necessary.
## UI and ownership contract
- Broker clients and Active writer status values are native labeled buttons, initially disabled, enabled only after validated admin session adoption. Ordinary users retain ordinary status values, cannot open management via hover/focus/click, and receive unchanged server-side denial on protected endpoints. No management read is issued for ordinary users.
- Both contextual entrances disclose the **same existing Broker form** in the sole `serial-settings` host. They have distinct live-client/writer accessible titles, share the client list/selection/explicit assignment controls, and use the existing browser-native confirmation dialog for the actual transfer. No second draft, client list, operation slot or DOM clone.
- Mouse hover and keyboard focus disclose without mutation; native click/Enter/Space/tap activation focuses Close. Touch pointer-enter alone does not disclose. `aria-controls`, `aria-expanded`, `aria-haspopup=dialog`, accessible names, visible focus, nonmodal dialog semantics, native select/actions, Close and full-page link remain available. No focus trap.
- The 8D.17 250ms pointer/focus bridge, focused-editor protection, Escape/outside dismissal and stationary-pointer suppression apply to both new triggers. Dismissal/adjacent-trigger switching restores logical terminal selection without calling xterm focus; Close/Escape focus only the trigger. Both terminals continue receiving bounded binary-transparent output, with input disabled while the settings host is selected. No socket/client/lease mutation on UI navigation.
- Full-page Settings retains its sole DOM/draft owner. **Neither hover, focus nor explicit activation of the new Broker/writer triggers changes a full-page domain or its draft**, including transient account/Network password input. Explicit activation focuses the existing domain navigation; trigger help explains using Broker navigation or returning to a terminal first. Existing Serial/Wi-Fi explicit full-page navigation is unchanged. Switching between quick views is deliberate context departure and retains existing draft cleanup rules.
- Promotion through Open full settings page retains the same Broker selection/controller without refetch, abort, POST or replay; it stops contextual live scheduling. Full Broker remains manually refreshed. Closing/switching clears selection, aborts/fences browser reads/results and stops timers, but never claims cancellation of admitted firmware work.
- Periodic button state updates use `aria-disabled` and preserve a currently focused control instead of natively disabling it and dropping keyboard focus. Nonfocused unavailable controls remain natively disabled. Independent request/action guards enforce availability, including clicks delivered to an aria-disabled focused button. Stale assignment attempts display a rejection without a POST.
## Live refresh and selection fences
- Immediate opening read, then **one next snapshot refresh 5 seconds after successful completion**, only while a Broker contextual view is open. Each cycle revalidates the current login, then uses the existing bodyless GET `/api/settings/broker` (strict 2048-byte/eight-client schema). This is not an additional aggregate status backend.
- At most one active Broker snapshot/operation controller. Manual reads, repeated opening and result/assignment work cannot overlap that controller. A **5-second whole snapshot-cycle deadline** covers session validation, fetch and body handling; timeout aborts, clears controller ownership and invalidates selection. The deadline is cleared on completion/abort. Error/timeout stops automatic live refresh until explicit Refresh/reopen; no automatic error retry.
- No timer while an operation/result is active or its outcome is pending/unknown. Known terminal operation results use the existing refresh path. Polling frequency is not a hard wall-clock freshness guarantee: background timer throttling, HTTPD and network delays remain possible.
- Explicit select change captures target ID, type/name identity and the current opaque lease generation. Reorder/counter-only refresh retains that choice and token. A lease version or identity mismatch latches `stale`; a failed/invalid/timed-out snapshot also latches it. Later matching data cannot clear the latch. A missing target clears the displayed select and latches absence so its later appearance cannot silently reselect it.
- Refresh never authorizes a new transfer. The admin must deliberately choose the blank option then the target again to reselect an otherwise still-displayed stale target. Assignment stays blocked for missing/stale/exhausted/current-writer targets. Submission consumes validity; operation completion refresh cannot re-arm it.
- Confirmation captures exact target/version **before** asynchronous session revalidation and submits once through `/api/settings/broker-operation`. Concurrent real lease changes after the browser snapshot are rejected by the unchanged atomic 8D.16 broker fence. Existing conflict result text visibly states no lease change by that operation. No check-unlock-force, lease-policy change or automatic mutation retry.
- Existing bounded result checks remain at most 10 one-second GETs/15 seconds; lost ACK, replacement, invalid response, expiry and late responses retain uncertainty and explicit Check Result recovery. Browser abort is not server cancellation, successful execution is not a guarantee the writer remains current, and latest login-bound results are not durable/idempotent records.
- Session/work generation, request-controller identity and API abort/current checks fence late responses, including late 401 after navigation. Expiry/logout/pagehide invalidate views and close both routes through existing cleanup. New views cannot adopt stale selection/snapshot/result state.
## Executed validation
All commands below passed, bounded at 120 seconds per tool invocation; none timed out. Broad suites ran after the initial implementation; the final focused-control refinement was followed by another complete UI suite and firmware build.
```sh
python3 tests/web_ui_session/run.py
python3 tests/session_broker_diagnostics/run.py
python3 tests/web_cookie_auth/run.py --broker
python3 tests/admin_console_boundary/run.py
python3 tests/web_admin_transport/server_lifecycle.py
python3 tests/web_cookie_auth/run.py
python3 tests/web_cookie_auth/run.py --settings
python3 tests/web_cookie_auth/run.py --serial-settings
python3 tests/web_cookie_auth/run.py --accounts
python3 tests/web_cookie_auth/run.py --admin
python3 tests/web_cookie_auth/run.py --network
python3 tests/web_cookie_auth/run.py --display
python3 tests/web_auth_parse/run.py
python3 tests/web_session_store/run.py
python3 tests/web_session_store/run.py --serial
python3 tests/admin_console_boundary/accounts.py
python3 tests/admin_console_boundary/lifecycle.py
python3 tests/admin_ssh_policy/run.py
python3 tests/web_network_settings/run.py
python3 tests/web_admin_transport/run.py --tickets
python3 tests/web_httpd_idle/run.py
python3 tests/web_diagnostics/run.py
python3 tests/web_serial_performance/run.py
python3 tests/web_security/run.py
python3 tests/web_login_ui/run.py
pio run
git --no-pager diff --check
```
Final UI **135 behavior groups** (128 baseline +7 contextual groups), plus actual C rendering/header/error checks, parsed unique HTML ownership/native labels and exact unchanged inline-loader CSP. New groups cover:
- ordinary/admin pointer/focus/touch disclosure, explicit close/Escape/outside focus, Serial/Admin receive and input isolation;
- deferred single-flight reads, reordered/counter-updated clients, preserved explicit choice, stale lease/identity latches and missing/returning target non-resurrection;
- focused action/select accessibility during refresh and stale rejection without focus theft or POST;
- malformed/503 snapshots, stalled session/snapshot deadlines, explicit recovery and ignored late snapshot data;
- full-page Serial/account/Network drafts, adjacent Serial→writer keyboard focus and promotion without reads/reset;
- captured confirmation through delayed session validation, visible conflict, lost acknowledgement, dismissal/reopen without replay;
- late read/POST/result401 after adjacent quick navigation, current expiry/pagehide/principal replacement/401 cleanup.
Existing canonical broker management/wrap tests verify real lease ABA/target-generation rejection; cookie Broker tests verify admin/session/Origin/CSRF/bounds/result isolation; lifecycle25 and unchanged dispatcher capacity tests pass. Parser294, transports/tickets, session binding, Network/accounts, idle, diagnostics, combined-send performance, security and login regressions also pass.
Test-development failures were corrected rather than hidden: one old assertion expected refresh to clear the choice; new refresh fixtures initially fired ordinary status's 5-second interval instead of the dedicated one-shot, and a delayed session fixture used the wrong username. The final harness explicitly distinguishes interval versus one-shot timers and uses the actual same principal. Production strict identity rejection was correct.
**Limits:** Node uses deterministic DOM/fetch/clock/socket doubles, not real native browser keyboard event defaults, focus engine, screen reader, mobile picker or touch hardware. Parsed native button semantics plus exercised click/focus/keydown/pointer paths do not establish real-browser accessibility sign-off. No optional Chromium geometry run in this phase; 8D.17 recorded sandbox launch restrictions. No on-device concurrency, actual TLS timing, heap/reserve, HTTPD/dispatcher stack or full-mix target measurement. These results do not reopen or expand the signed-off CPU160 throughput evidence.
## Build and resources
| Build | RAM | Flash | Time |
|---|---:|---:|---:|
| Actual pre-edit baseline | 100,300 B | 1,788,661 B | 7.02 s |
| Initial implementation | 100,300 B | 1,793,077 B | 21.99 s |
| Final focused-control refinement | 100,300 B | 1,793,301 B | 21.52 s |
| Final delta from baseline | **0 B** | **+4,640 B** | incremental times not comparable |
CPU160 verified by targeted inspection of `sdkconfig.defaults`, active `sdkconfig.esp32-s3-devkitc-1-n16r8` and generated `.pio/build/esp32-s3-devkitc-1-n16r8/config/sdkconfig.h`. PlatformIO's generic board banner still says240MHz; actual config says160. No edits to these files. 33 handlers/six sockets, existing tasks/stacks/queue capacity and broker/WebSocket buffers are unchanged. Browser additions are one bounded selection record, one live scheduling timer or active read deadline, and two trigger listener sets; existing rows/controllers are reused. Regular live reads add HTTPS load while shown; runtime headroom remains unmeasured.
## Pending parent and target checklist
- [x] Independent review of source, tests, ownership, stale selection and request/focus fencing; no confirmed actionable defects.
- [ ] Desktop mouse hover bridge, scrollable client list, adjacent triggers, outside dismissal and no unwanted reopening after Escape.
- [ ] Keyboard Tab/Shift-Tab, native Enter/Space, select navigation, blank/reselect, focused action refresh/stale invalidation, native confirmation Cancel/Accept and Escape; no terminal key leakage. Screen-reader titles/expanded/aria-disabled/status announcements.
- [ ] Touch tap/scroll/select/confirm/outside tap, rotation/zoom/software keyboard and narrow/short viewport geometry; real native-picker behavior during refresh.
- [ ] Every full settings draft survives Broker/writer activation; sole-host promotion and Serial/Wi-Fi quick switching behave as documented.
- [ ] USB/SSH/two-browser clients join/leave/reorder; concurrent shell/tab writer changes and same-writer release/reacquire reject stale confirmation visibly; explicit reselection does not assign until separately confirmed.
- [ ] Delayed/lost snapshot/ACK/results, actual network loss, expiry/logout/bfcache and identity replacement: no late state restoration, mutation replay or cancellation claims; Check Result recovery remains available.
- [ ] Both browser terminals continue receiving with UI open; correct input focus after dismissal; physical UART0 administration/native USB recovery remain usable.
- [ ] Full mix at signed-off160MHz/230400 baud with live refresh: capture drops/latency/heap and HTTPD/dispatcher margins, without inferring numeric reserve approval.
No target checklist item or independent-review item was signed off by this implementation. Stop before 8D.19 or any other separately authorized phase.
+1 -1
View File
@@ -189,7 +189,7 @@ Typed operations must preserve subsystem owner/lock/persistence contracts and co
| **8D.14 — Display settings** | **Implemented, host/build verified; target pending.** Typed local display configuration and explicit persistence via `local_ui_config`/generation-checked public UI APIs; [contract/evidence](phase8d14_implementation.md). | Host limits/storage/CLI-generation/activity/lifecycle regressions pass; actual save/reboot, absent-display and concurrent buttons/CLI target checklist remains pending. No I2C ownership changes or electrical diagnostics UI. |
| **8D.16 — Broker client visibility and writer transfer** | **Implemented, host/build verified; independent parent review and target sign-off pending.** Admin-only detailed snapshot plus explicit confirmed assignment through existing dispatcher/broker; smallest owner changes add atomic lease-version/target validation and nonwrapping IDs. [Contract/evidence](phase8d16_implementation.md). | Host stale/disconnected/reused target and lease ABA rejection, one writer, admin denial, bounded/session-isolated results, lifecycle and UI non-mutation regressions pass. Concurrent physical USB/SSH/browser/full-mix and stack-margin checklist remain pending. No transfer on page open/selection; no8D.17/18 popovers/icons. |
| **8D.17 — Serial/Wi-Fi quick popovers** | **Implemented, host/build verified; independent parent review and target sign-off pending.** UI-only reuse of completed typed endpoints through one settings DOM/controller, full-page link and shared validation; `web_ui`. [Contract/evidence](phase8d17_implementation.md). | Hover/focus/click/tap, Escape/outside dismissal, no opening/selection mutation, explicit Apply/Save, Network password exclusion; draft/session/pending-operation regressions pass. Full-page hover deliberately preserves its existing draft; explicit activation navigates that page. Optional geometry blocked by sandbox; real pointer/keyboard/touch/full-mix checklist pending. No duplicate backend/new settings scope/icons/8D.18. |
| **8D.18 — Client/writer contextual dialogs** | Reuse 8D.16 for live client popover and confirmed Active writer dialog. | Accessible pointer/keyboard/touch paths; refresh preserves explicit selection safely; stale confirmation is rejected visibly; normal users retain only ordinary status. No new writer policy. |
| **8D.18 — Client/writer contextual dialogs** | **Implemented, host/build verified; independent parent review and target sign-off pending.** UI-only reuse of8D.16 and8D.17's single host for live client popover and confirmed Active writer dialog. [Contract/tests/checklist](phase8d18_implementation.md). | Native pointer/keyboard/touch entrances; single-flight5-second live refresh/deadline, explicit selection preserved without lease-token renewal, sticky stale/absent rejection, full-page draft protection and focus-safe updates. Ordinary users retain only ordinary status.135 UI groups plus broad broker/auth/lifecycle regressions pass; real browser/device checks pending. No new writer policy/backend/icons/8D.19/later. |
| **8D.19 — Ordinary service/session controls** | Typed service status and targeted disconnect/start/stop controls, excluding actions that cut off the invoking HTTPS session; start in existing service APIs and generation-safe snapshots. | Explicit scope/confirmation, stale target rejection, owner-safe execution and failure isolation. Stop/start and disconnect do not clear settings/identities. Split by service if more than one owner adaptation is necessary. |
| **8D.20 — Self-affecting service actions and reboot** | Confirmed typed operations for connection-losing HTTPS/Wi-Fi/service actions and reboot, reusing lifecycle behavior established in 8D.7/8D.13. | Acknowledgement/pending-action handling is bounded, no duplicate action on UI retry, connection loss is explained, recovery and reconnect work. No new unbounded queue or certificate/key rotation yet. |
| **8D.21 — Security/danger-zone settings** | Carefully separated HTTPS/SSH identity rotation/reset and any explicitly retained recovery-secret operation through existing security APIs. Enumerate allowed operations first; split HTTPS and SSH work into separate requests if both need owner changes. | Confirmation, secret-safe one-time responses, no routine private-key export, expected trust/fingerprint changes, bounded self-disconnect, no accidental configuration wipe. Bootstrap/unavailable-database recovery remain UART0-only. NVS encryption, secure boot, OTA, and new factory-reset semantics stay out of scope. |