# 8D.21 — HTTPS and SSH host identity settings ## Current aggregate status (2026-09-13) **The explicitly authorized HTTPS and remaining SSH identity slices are implemented end-to-end and host/build verified.** This completes the allowed implementation scope of 8D.21, not target acceptance, runtime reserve approval, M3, or 8D.22. The HTTPS slice's independent-review history below is preserved. The SSH slice has now been independently reviewed with no confirmed actionable defects. Reviewer checked installed wolfSSH key copying/wiping, retained-context cleanup, reservation/lock ordering, failure effects, public metadata and auth/UI scope; independently reran SSH security5, retention/management, cookie SSH7+shared, UI158+renderer/HTML/CSP, console boundary/lifecycle/policy and HTTPS lifecycle/security17 PASS. Parent final `pio run` confirmation PASS7.15s,100,556 B RAM/1,828,573 B flash; diff check PASS. Target trust renewal, real scheduling, NVS power-loss and runtime margins remain unverified. The SSH continuation began with a clean working tree and preserved the completed HTTPS shared reservations, 8D.19 SSH controller/routes, earlier UI work and 160 MHz throughput configuration. No upload, erase, commit, branch, assets regeneration, SDK/dependency/configuration changes, or new tasks/timers/queues/routes were performed. ### SSH delivered workflow and exclusions Admin Settings → SSH now adds stored host-key OpenSSH SHA-256 fingerprint, identity generation, service generation and the sole canonical supported algorithm, `ecdsa-sha2-nistp256` (ECDSA P-256 / `nistp256`). This is a public metadata projection, not private/public key download or proof of the identity a peer actually served. No algorithm selector or invented host-key algorithm was added; user authorized-key algorithms and authentication are unrelated and unchanged. **Rotate SSH host identity…** confirms the exact old fingerprint and both generations before any asynchronous session validation. It explicitly warns that all SSH sessions, including subsequently admitted sessions, close; already executing administration may finish; stopped ordinary rotation stays stopped; persistence and restart may fail after partial effects. Verify the NEW fingerprint using trusted UART0 **`ssh host-key info` before accepting changed `known_hosts` trust**. Do not blindly remove warnings. HTTPS remains accessible and its login/browser terminals are not deliberately stopped; Wi-Fi, users, UART0 administration and native USB UART1 access are unchanged. USB is not an administrative recovery console. Reset audit: healthy `ssh reset --force` duplicates key replacement, additionally starts stopped SSH and permits unavailable/corrupt-material recovery. Preserve that canonical CLI/deferred-SSH behavior; do not add a duplicate browser Reset or new recovery endpoint. Full21 excludes user authorized-key work, key/certificate export, passwords/recovery secrets, unavailable-database recovery, factory erase/configuration wipe, OTA, NVS encryption and secure boot. Existing browser-shell SSH policy remains unchanged; typed SSH controls do not enable deprecated/restricted shell commands. ### SSH owner and material lifetime contract - `ssh_transport_replace_identity(service_generation, identity_generation, reset, &committed)` is the shared off-HTTPD owner. Both nonzero generations select conditional rotation; both zero retain canonical semantics; reset plus conditional generations is invalid. The canonical `ssh_transport_replace_host_key()` wrapper and existing UART0/deferred admin-SSH paths use it. Conditional stopped rotation is supported without starting SSH. - Take the existing command mutex with zero wait, compare current initialized/service generation/transition/cleanup state, then reserve identity **before stop or crypto/NVS**. Canonical rotate/reset also now fail busy rather than waiting on another identity owner. Ordinary start/stop retain their existing command-mutex waits. The combined command mutex spans stop, replacement and conditional restart, without releasing an interleaving gap. - `ssh_security_reserve_identity()` uses the security mutex only for short admission. Direct canonical `ssh_security_rotate()` / `ssh_security_reset()` share this reservation. Nonreused uint32 tokens are task-owner-bound; only the reserving task can replace once and release; stale tokens cannot release or reuse a later reservation. Failed expected identity comparison has no service side effect. Init cannot publish unavailable material over a live reservation. - After both reservations, advance saturated service generation; retain established **stop → generate/commit/publish → conditional restart** ordering. Crypto and NVS run outside the security mutex and all spinlocks; the service command mutex remains held. Read-only public metadata/DER copies can take their short security mutex without a crypto-held lock. Existing startup initialization retains its mutex semantics. - Failed stop/timeout skips identity mutation and **never attempts another start**. Pending owner work is not cancelled by timeout. Failed cleanup retains canonical recovery. Generation/RNG/NVS failure after successful stop leaves live identity unchanged, but SSH clients have already disconnected; if previously running, make the established best-effort restart using unchanged material. That restart can itself fail. No blanket “failure means no effect” claim. - Commit precedes publication and old-private-material wipe. `committed=true` remains true if the subsequent restart fails; no rollback. Identity generations change only after successful commit, saturating without wrap. Service generation advances on admitted replacement and admitted lifecycle transitions, including failures, independently of counter clear. Reservation exhaustion blocks future identity mutation until reboot; reboot invalidates old browser logins. - Only the existing SSH owner task invokes runtime wolfSSH/context/socket operations. Installed `wolfSSH_CTX_UsePrivateKey_buffer()` delegates to `wolfSSH_ProcessBuffer()`; its ASN.1 path allocates and copies input DER (`internal.c` 2122–2129) before `SetHostPrivateKey`. The production caller wipes its bounded stack DER on every return path, so a running context does not borrow `s_material` or stack bytes. No SDK/library edit was needed. - `start_runtime()` now rejects retained context/listener/non-free slots rather than overwriting orphan handles. `stop_runtime()` retains the context until all slots retire; `process_slots()` frees a retained context on the owner, outside the spinlock, before clearing cleanup admission. The prior `cleanup_slot()` already frees its wolfSSH object before a possible broker-disconnect failure: this review did **not** demonstrate a preexisting UAF. The change enforces the explicitly requested stronger retained-context invariant. Library destructor private-key wiping was source-inspected, not exercised by a real wolfSSH target test. - Existing SSH self-affecting command drain/deferred-control behavior is preserved. No new dispatcher/task or command-string replay. The dispatcher does not execute its own SSH-shell host rotation synchronously; the existing control owner performs it after the handler/drain boundary. Existing authentication roles, shell-request policy, exact session generations and broker routing are unchanged. ### SSH HTTP/UI bounds and result semantics Reuse GET `/api/settings/ssh` and GET/POST `/api/settings/ssh-operation`, current-admin cookie/Origin/CSRF/no-store protections, existing ID-only dispatcher and single original-login slot. No HTTPD crypto, NVS, lifecycle wait or wolfSSH call. Existing 256-byte/four-receive input, 768-byte snapshot and 96-byte result bounds remain unchanged; 39 total handlers/six sockets and unchanged queue depth/item capacity. Service requests retain exactly `action`, `generation`, `target`. Rotation requires exactly four fields, e.g. `{"action":"rotate","generation":7,"target":0,"identity_generation":3}`; unknown/duplicate/escaped fields, unsupported action, nonzero rotation target, missing/zero/saturated identity generation, coercion, malformed or oversized bodies reject. Snapshot adds `identity_generation`, `algorithm`, `fingerprint`, `rotatable` to the existing four fields. Fingerprint is unpadded OpenSSH `SHA256:` base64. Security metadata is atomically copied under a zero-wait lock, with no private material. Service and identity observations are separate, not a cross-owner atomic authorization; execution compares/reserves both. Unavailable identity yields generation0/empty fingerprint/rotatable false without removing ordinary service controls. Queue admission and response follow the existing SSH post-before-execute pattern, **not** the HTTPS self-cutting ACK gate: SSH rotation does not stop the invoking HTTPD/login. A lost response does not cancel queued work. Original-login/current-admin/30-second dequeue deadline checks precede combined owner admission; revocation after admission is not cancellation. Completed duplicate IDs are inert, IDs do not wrap, results are replaceable and login-isolated, not durable/idempotent history. Rotation errors conservatively report `failed`, even for rejected owner admission, because later failures can have partial effects; ordinary service conflict reporting is unchanged. The existing controller keeps 15-second whole-request bounds, captured confirmation values, single-flight/pending gates, manual Check Operation Result then Refresh, navigation/late-response fencing and no mutation retry or restore. Terminal errors/results explicitly warn that SSH may have disconnected despite persistence failure, or a key may be persisted despite restart failure. HTTPS does not require fresh login due to this SSH operation. No new polling timer or separate controller. ### SSH validation and resources Commands actually run, all PASS after the described harness fixes: - `python3 tests/ssh_management/security.py`: five groups, full production security + real host mbedTLS and NVS fault doubles, plus extracted exact production combined owner functions. Covers P-256 generation/validation/copy/reload, RNG/NVS open/set/commit faults and unchanged stored/live bytes, commit-before-publication, stale admission before effects, competing canonical/direct owners during crypto, task/token ownership/reuse/one-shot/exhaustion, postcommit restart failure/no rollback, zero-wait metadata, malformed storage and canonical reset recovery. NVS handle closure and candidate wipes checked. No real power-loss/RTOS scheduling claims. - `python3 tests/ssh_management/runtime.py`: exact production runtime start/stop/process-slot functions; deterministic retained-resource doubles prove failed-stop retention, no orphan overwrite/start, owner-only final retirement and listener-failure cleanup. Not a real wolfSSH allocator/socket test. - `python3 tests/ssh_management/run.py`: five groups, existing published snapshot/session-close/ABA/retired-ID/timeout/exhaustion tests plus combined identity-owner comparison, busy reservation, failed-stop no start/mutation, persistence recovery and stopped/reset semantics. - `python3 tests/web_cookie_auth/run.py --ssh`: seven SSH groups plus shared auth; strict rotation fields/generations, dispatcher-only single execution, revoked queued rotation, login isolation, metadata bounds, existing Origin/CSRF/session/receive/expiry/deadline/lost-response tests. Uses owner doubles, not crypto. - `python3 tests/web_ui_session/run.py`: **158 groups** plus production C rendering/HTML/CSP checks. Adds rotation confirmation/fingerprint/both generations, exact request, all-SSH/trust/UART0/partial-effect warnings, duplicate suppression, HTTPS terminal isolation and malformed/unavailable identity metadata; all prior domains remain green. - Broad PASS: `tests/admin_console_boundary/run.py`, `tests/admin_console_boundary/accounts.py`, `tests/admin_console_boundary/lifecycle.py`, `tests/admin_ssh_policy/run.py`, `tests/web_admin_transport/server_lifecycle.py` (44+2 integrated real HTTPS security groups), `tests/web_security/run.py` (17), all cookie variants (`--admin`, `--settings`, `--serial-settings`, `--accounts`, `--network`, `--display`, `--broker`, `--lifecycle`, `--ssh`), `tests/web_admin_transport/run.py --tickets`, `tests/web_session_store/run.py --serial`, `tests/web_serial_performance/run.py`, `tests/web_httpd_idle/run.py`, `tests/web_auth_parse/run.py`, `tests/web_network_settings/run.py`, `tests/session_broker_diagnostics/run.py`, `tests/web_diagnostics/run.py`, `tests/web_login_ui/run.py` (all invoked with `python3`). - Initial compile caught an enum-type comparison in the new API action; fixed with the module's unsigned action value. Cookie harness needed real `-lmbedcrypto` for base64; integrated owner harness needed its extracted generation constant. These were corrected and affected suites rerun successfully. - Baseline `pio run`: PASS7.20s, **100,532 B RAM / 1,825,073 B flash**. Final production build after retained-context changes: PASS21.98s, **100,556 B RAM / 1,828,573 B flash**, SSH slice delta **+24 B / +3,500 B**; aggregate21 delta versus pre-HTTPS100,508/1,821,505 is **+48 B / +7,068 B**. These are linked static/flash counts, not heap or stack reserves. - Final confirmation `pio run` PASS7.07s at identical100,556/1,828,573 B; final SSH security/runtime/management/cookie/UI158 and console accounts/lifecycle reruns PASS. No independent-review attribution is implied by these same-agent reruns. - Defaults, active sdkconfig and generated sdkconfig.h explicitly checked: CPU **160 MHz**. Board-banner240MHz is not the configured CPU clock. Combined binary WebSocket send path/config/assets untouched. `git diff --check` PASS. ### Pending SSH parent and target gates Independent parent review is required after this implementation; no independent review was performed or fabricated. Review combined-owner lock ordering, command/control self-deferral, direct-security exclusion, retained-context recovery and actual DER-copy/destructor semantics, plus API/UI partial-effect contracts. No target acceptance is claimed. On device: compare stored fingerprint with trusted UART0 `ssh host-key info` and actual peer host key; confirm changed-known_hosts verification; rotate with active admin/user SSH and concurrent HTTPS/USB/full mix; verify all SSH disconnect while HTTPS stays accessible; test stopped rotation/reset recovery, service restart/CLI interleavings, broker cleanup failures, reboot persistence and realistic NVS/power-loss faults. Measure dispatcher/control/SSH/HTTPD stack high-water, heap/internal/DMA minima and throughput at160MHz. Confirm unchanged account roles/authorized keys and ordinary/restricted shell behavior. Hardware trust, timing, power-loss, real-wolfSSH allocation/failure behavior and runtime margins remain unmeasured. No new phase is authorized by this record. --- ## Historical HTTPS slice status (2026-09-13) The following record preserves the completed HTTPS slice and its independent-review evidence. Its statements that SSH/full21 remain unimplemented are historical and superseded by the aggregate status above; its target-pending limits still apply. **Chosen HTTPS slice implemented end-to-end, host-tested and build-verified.** Independent review complete with no confirmed actionable findings; target validation/sign-off remains pending. Full 8D.21 remains incomplete: SSH identity work requires its separately requested owner/scope audit and implementation. No SSH identity changes were made here. The previous agent delivered only an audit and baseline, modifying this document, `docs/agent/current-state.md` and `docs/phase8d_plan.md`. Those were the only initial worktree changes in this continuation. This implementation supersedes their NOT-implemented status, not prior user sign-offs or resource follow-ups. Independent reviewer checked shared service/identity reservations, all canonical mutation callers, installed-IDF TLS material copies, commit/failure semantics, auth/ACK and public metadata. Reviewer reran security17, lifecycle44+2 integration groups, cookie lifecycle8+shared, UI/renderer/HTML/CSP, dispatcher/console lifecycle and diff checks PASS. Parent final `pio run` confirmation PASS6.98s,100,532 B RAM/1,825,073 B flash; diff check PASS. No target trust/reset/NVS power-loss or runtime-margin validation inferred. ## Delivered scope and user workflow - Admin Settings → **HTTPS / Reboot** now also shows the **stored** HTTPS certificate's SHA-256 fingerprint, identity generation and service generation. This is public metadata behind current-admin authorization, not an unauthenticated endpoint, certificate download, private-key export or proof of the served identity. - **Rotate HTTPS identity…** confirms the old fingerprint and both generations, persistence, changed browser trust and loss of all web logins/both browser terminal routes, including clients admitted before execution. Save browser drafts first. - Verify the NEW fingerprint using trusted UART0 `web certificate info` before accepting changed browser trust. A browser certificate warning alone is not trusted verification. Reload and sign in freshly; never automatically retry. - A new identity may already be persisted even if stop/start fails. A retained HTTPD can still serve the old certificate; compare stored and served identity explicitly and recover using canonical `web stop` / `web start` when necessary. - SSH identity, accounts, Wi-Fi, serial configuration and other saved settings are unchanged. UART0 administration and native USB UART1 access are independent of this rotation. USB is not an administrative console. The preexisting reboot action still interrupts the entire device; rotation does not reboot it. - No duplicate browser Reset for healthy TLS material. Existing CLI `web reset --force` retains TLS-only replacement/recovery and starts a stopped HTTPS service; ordinary CLI rotation leaves a stopped service stopped. Neither touches users. Unavailable-user-database recovery stays UART0-only. No browser unavailable-material recovery, bootstrap, retained recovery secret, new password feature, configuration wipe, factory reset, OTA, encryption or secure boot. ## Ownership and admission contract ### Combined service/security owner `web_server_replace_identity(service_generation, identity_generation, reset, &committed)` is the shared off-HTTPD owner entry point. Both nonzero generations select conditional healthy-running rotation; both zero select existing canonical CLI semantics. Reset cannot be combined with conditional generations. 1. Conditional calls avoid the blocking legacy initializer and take the existing server mutex with zero wait. Reject stale/saturated service generation, absent server, transition or failed cleanup **before any identity mutation**. 2. Set `s_transitioning` under the server mutex, then release it. This reservation excludes canonical start/stop/restart/reboot and competing CLI identity work. 3. Reserve the expected identity using `web_security_reserve_identity()`. Its zero-wait security mutex check excludes stale/unavailable/saturated identity, existing reservation and exhausted reservation IDs. Canonical direct `web_security_rotate_certificate()` / `web_security_reset_all()` acquire the same reservation, so they cannot bypass an admitted combined operation. 4. After both reservations, advance the saturated service generation. Generate a local candidate and commit its bounded existing NVS blob without holding either mutex or a spinlock. Publish only after successful commit, wiping the old key. The security mutex protects short state admission/copies/publication, not crypto or flash. Initialization/migration retains its existing startup locking. 5. Keep the identity reservation through canonical reserved stop/start. Start can copy the committed TLS pair under the ordinary security mutex without deadlock. Running rotation/reset restarts HTTPS; stopped rotation remains stopped and stopped reset starts HTTPS. No unreserved stop-to-start gap is introduced. 6. Release the nonreused identity token on return. Only its reserving owner may replace once and release it; old tokens cannot replace/release a new reservation. Identity generation advances only on committed replacement, retaining the existing persisted UINT32_MAX fail-closed rule. Service generation advances on admitted replacement and on each admitted stop/start, including failed attempts, saturating at UINT32_MAX without wrapping. Failed identity admission does not advance it; failed crypto/storage after combined admission can advance service generation without changing identity or stopping HTTPD. Reservation IDs never reuse; exhaustion denies identity mutations until reboot, while existing canonical service recovery remains available. Reboot invalidates all old browser sessions. Public snapshot copies use separate zero-wait service/security observations, not one cross-owner atomic view. They authorize nothing; any intervening service or identity change is rejected by the combined execution-time reservations. Unavailable identity metadata yields generation0/empty fingerprint/rotatable false without removing ordinary lifecycle controls. ### Failures, revocation and console safety - Generation, RNG, NVS open/set/commit errors before publication leave the live identity unchanged and do not stop HTTPD or revoke its logins. Host NVS faults also verify unchanged stored bytes; doubles do not prove power-loss behavior. - `committed=true` is irreversible publication even when stop/start returns an error. Stop failure skips start and retains canonical cleanup ownership. Failed start follows the existing retained-handle cleanup rules. No rollback to the old identity occurs. CLI reports the precommit/postcommit distinction; typed results deliberately retain conservative failure/unknown-outcome language. - Stop invokes canonical `web_cookie_auth_stop()` and transport detach/stopped paths, invalidating all web sessions/tickets and closing browser routes. No unrelated account or SSH revocation is added. Later logout/revocation is not cancellation of admitted crypto/commit/restart. - `web_console.c` rotate/reset wrappers and `web_admin_transport.c` deferred browser-shell rotation call the same combined owner, not separate commit/stop/start. Browser shell retains its existing parsed force policy and drain/dispatcher mask; its acknowledgement is still the bounded application-drain heuristic, not HTTP ACK. - Inspected `web_admin_transport_detach()`: it waits only for queue submitters, not console execution. `admin_ssh_console_close()` marks an executing slot inactive without waiting/wiping it; dispatcher return retires that slot. No self-console cleanup wait, command-string replay, HTTPD self-stop or lock-held HTTPD wait. ## Bounded HTTP and UI contracts Reuse the three existing optional routes and single lifecycle operation slot: - `GET /api/settings/lifecycle`: seven fields, **320-byte response buffer**: `generation`, `running`, `transitioning`, `controllable`, `identity_generation`, `fingerprint` (64 lowercase hex digits, SHA-256), `rotatable`. - `POST /api/settings/lifecycle-operation`: `stop|restart|reboot` still require exactly action + service generation. `rotate` requires exactly `{"action":"rotate","generation":7,"identity_generation":11}`. No reset, extra fields, duplicate fields, escaped/coerced values, zero/saturated generations or trailing bytes. Existing **256-byte/four-receive** bound retained. - `GET /api/settings/lifecycle-operation`: existing **96-byte** login-isolated `id/action/state` result. `failed` can mean rejected admission OR partial effects; no falsely precise success, cancellation, rollback or durable-history guarantee. Current cookie/principal/admin checks protect all routes; mutations additionally require existing JSON/Origin/CSRF policy. The operation keeps the original login, not merely the account. Reuse8D.20's send-return → nonreused-ID HTTPD callback → existing dispatcher handoff: no crypto, persistence or lifecycle on HTTPD and no request/fd/operation pointer captured. Two-second ACK and post-validation30-second dequeue deadlines remain admission bounds, not peer receipt or execution deadlines. One accepted-but-lost callback reservation survives until callback arrival or successful HTTPD destruction; failed destruction cannot accumulate new callbacks. `web_ui.c` extends the existing lifecycle view/controller, not a parallel Security controller. It validates the complete bounded public schema, captures both versions before confirmation/session validation, and shares single-flight/pending gates with all lifecycle actions. Identity unavailable/exhausted disables rotation. Explicit manual Check Result/Refresh,15-second whole-request deadline, late-result/context fencing and original-login rules remain. Unknown/lost ACK cannot clear the duplicate gate by adopting another result; navigation/pagehide does not replay or restore a mutation. No generated secret, secret input or retained retry material is introduced. No generated assets or loader/CSP changes; existing HTML/CSP tests pass. ## Validation performed All commands below passed in this continuation; no hardware/runtime pass inferred. - `python3 tests/web_security/run.py`: **17 production-security groups** with real host mbedTLS, including exact NVS open/set/commit transactional failures, real fingerprint/key changes, generation exhaustion, public-only projection, zero-wait contention, one-use/nonreused tokens and competing canonical writers during real crypto outside locks. Existing migration/invalid storage/recovery tests retained. - `python3 tests/web_admin_transport/server_lifecycle.py`: **44 orchestration/ACK groups plus2 integrated owner/security groups**. The second executable links the extracted production server owner to the complete production security implementation and real mbedTLS, with NVS/HTTPD/scheduler doubles. Tests real generation-time RNG and NVS open/set/commit failures, exact unchanged identity/storage before commit, committed identity surviving stop/start failures, stale service/identity rejection, and canonical/direct-security exclusion during crypto AND stop/start. The44 groups additionally cover CLI stopped rotation/reset, saturated/stale/busy/currentness admission, every detach failure, original ACK sequencing and lifecycle recovery. - `python3 tests/web_cookie_auth/run.py --lifecycle`: **8 extended lifecycle groups plus shared auth tests**, actual handlers/parser/auth/session store; rotate's exact third generation, malformed/truncated inputs, bounded fingerprint-only projection, all four actions off-handler/off-callback, login invalidation after admission, queue/send/lost/late callback/request storage reuse and deadline/wrap regressions. - `python3 tests/web_ui_session/run.py`: **156 browser behavior groups plus C-renderer, seven-view HTML and exact CSP checks**. Three new groups cover fingerprint/version confirmation, missing/invalid generation/fingerprint/secret-field rejection, unavailable identity, shared pending gate, partial-effect warning, role loss, lost ACK, expired login and no replay/restore. Existing lifecycle timing and navigation tests remain. Not real-browser geometry or TLS target validation. - `python3 tests/admin_console_boundary/run.py` and `lifecycle.py`: PASS, including deferred browser certificate dispatcher/executing-slot/self-detach safety and typed dispatcher queue isolation. `python3 tests/web_admin_transport/run.py`: **25 groups**; its owner dependency double now represents the combined API. - `python3 tests/web_cookie_auth/run.py` with no option and each of `--settings`, `--serial-settings`, `--accounts`, `--network`, `--display`, `--broker`, `--ssh`, `--lifecycle`, `--admin`: PASS. - `python3 tests//run.py` for `admin_ssh_policy`, `web_auth_parse`, `web_session_store`, `web_httpd_idle`, `web_serial_performance`, `web_diagnostics`, `web_login_ui`, `ssh_management`, `web_network_settings`, `session_broker_diagnostics`, `web_security`, `web_admin_tickets`: PASS. `python3 tests/web_session_store/run.py --serial`: PASS. - Final combined owner/integration suite rerun after adding generation-time RNG and stop/start reservation interleavings: PASS. The initial integration-fixture compile found an unused copied test counter; fixture extraction was corrected, not compiler warnings disabled. No production test failure was hidden. - `git --no-pager diff --check`: PASS. Final worktree inspection shows only the intended source/tests/docs; no assets, configuration or device-operation changes. ## Build, resources and preserved work - Prior audit baseline: `pio run` PASS7.17s, **100,508 B RAM / 1,821,505 B flash**. It was not redundantly rerun before implementation. - Intermediate implementation build: PASS21.92s,100,532 /1,824,889 B. - Final production `pio run`: **PASS22.78s,100,532 B RAM /1,825,073 B flash**. Final delta against audited baseline: **+24 B RAM /+3,568 B flash**. - Still **39 handlers/six sockets**, same existing lifecycle slot/dispatcher item and queue depth, no new task/timer/stack size/session/ticket/heap allocation/schema. Lifecycle snapshot buffer grows128→320 bytes; identity-operation slot adds one uint32 field; security adds bounded token/one-use state. The existing local TLS candidate is retained, not another persistent private-material allocation. - Defaults, active sdkconfig and generated sdkconfig.h independently checked: **CPU160MHz**. No configuration changes. Combined binary WebSocket send, signed-off throughput, serial broker isolation and native USB path unchanged. - No assets regeneration, SDK/dependency changes, device actions, upload, erase, commit or new branch. User/prior-agent documentation work preserved and updated. Runtime HTTPD/dispatcher stack margins and heap minima are not inferred from linked RAM or host sizeof; the larger snapshot handler frame needs target checks. ## Pending parent/target gates and remaining phase - [ ] Independent parent review of combined ownership, direct canonical exclusions, snapshots/ACK/auth/parser/UI and failure/uncertainty contracts. - [ ] On target, verify old/new stored and served fingerprints, trusted UART0 verification, browser trust renewal, fresh login and persisted identity after a normal reboot (no automatic reboot in this feature). - [ ] Verify canonical CLI reset with unavailable TLS material and stopped-service rotation/reset semantics, including low-memory/cleanup failure recovery. - [ ] Real-client lost response, timeout, two-admin concurrency, stale confirmations, changed role/login and cleanup behavior; no mutation replay. - [ ] Full mix at160MHz (two web serial, browser admin, SSH serial/admin and USB), unchanged binary transparency/writer isolation, UART0 recovery/native USB availability through HTTPS rotation, HTTPD/dispatcher stack and heap minima. - [ ] User target sign-off. No reserve approval, full M3 or full8D.21 claim. **HTTPS slice has no remaining implementation item identified here.** SSH identity metadata/rotation/reset remains outside this slice and requires a separate request; no speculative SSH owner design or implementation is included.