Complete Phase 12 dual-stack networking

Add IPv6-aware Wi-Fi state, HTTPS/SSH listeners, mDNS service
reconciliation, and browser Wi-Fi administration.

Include a guarded build-local fix for mDNS 1.12.0 membership handling,
focused regression suites, and Phase 12 acceptance documentation.
This commit is contained in:
2026-09-20 22:35:34 +02:00
parent ece4ba77e3
commit 8902b25d78
52 changed files with 3042 additions and 163 deletions
+33 -2
View File
@@ -2,6 +2,37 @@
Working memory, not an implementation timeline. Source is authoritative; begin with [code map](code-map.md), [architecture](architecture.md) and [decisions](design-decisions.md).
## Phase 12 COMPLETE — explicit user validation
- User states: “I just validated Phase 12 successfully.” Record acceptance, not a pending phase. Canonical device evidence and reusable regression guidance: [Phase 12](../roadmap.md#phase-12--advanced-network-integration). No unreported DHCP capture, DNS-zone update, exhaustive address/service transition, fault/soak or byte-integrity pass is implied.
- User validated IPv6 ping/HTTPS and Avahi AAAA; Fedora authselect dual-family mDNS resolved the normal hostname lookup issue. Fresh-boot and full-mix captures show healthy reported service lifecycle. At 230400 baud 8N1 RTS/CTS: two SSH sessions with IPv6 ULA peers (user observer/admin console), two serial WebSockets (writer/observer), active browser admin, USB observer; four broker clients, one writer, zero pending/event counts at capture.
- Memory table preserved in roadmap. Fresh internal8/DMA/PSRAM free: 65,880 / 58,124 / 8,196,732 B. Full-mix free: 35,408 / 27,652 / 8,111,952 B; lifetime minima: 8,528 / 772 / 8,072,612 B; largest blocks: 22,528 / 22,528 / 7,995,392 B. Capability pools overlap; minima are conservative per-region lifetime sums, not simultaneous reserves. DMA772 remains a watch item, not proof of OOM or an acceptance blocker. SSH stack20,480B minimum-free18,476→16,284B.
- SSH two successful handshakes, no auth/handshake/timeouts/I/O failures; RX68 accepted65 rejected3, TX161,209B, broker revocations2. Web serial RX27B accepted, TX318,230B across782 frames; send/queue/protocol failures0. Browser admin RX106/TX3,721B with no reported send/queue failures. Do not reinterpret nonzero rejected bytes/writer denials as proven transport loss or claim zero UART/observer drops without their counters.
- Boot TLS -0x004C receive errors and auth-failure counts have no demonstrated cause. Snapshots are non-atomic and counts are not an aligned interval. This handoff changes documentation only; no new build/test/upload/erase/device operation/commit; hardware directory untouched. Prior latest build94,444B RAM/1,854,485B flash and UI174+CSP remain historical validation.
## Follow-up — IPv6 addresses in web Network settings
- User confirms direct IPv6 ping/HTTPS and Avahi AAAA lookup for `sak-1024.local` succeed. Client NSS uses `mdns4_minimal [NOTFOUND=return]`; systemd-resolved explicit mDNS reports no eligible networks. This supports a client resolver integration issue, not failed firmware AAAA publication on the tested Avahi path. The user subsequently enabled dual-family mDNS through Fedora authselect and confirmed success; see acceptance above.
- Added bounded runtime `ipv6_addresses` (<=3 fixed-width lowercase eight-hextet strings) to existing admin Network snapshot, grouped as link-local/ULA/GUA in Settings. Overview/OLED remain flags-only. No new netif call, allocation, task or snapshot storage. Backend/client JSON bound 2048→2304 (+256B response stack); maximum-escaped fixture with all three addresses is 2067B. Strict UI validation/text-only output and existing session fences preserved; generated assets untouched.
- `pio run` PASS **94,444 B linked RAM / 1,854,485 B flash**, +0/+800 versus prior CLI-address build. Network cookie/owner regressions and UI174+CSP PASS. Initial cookie fixture had an obsolete 2048B output buffer; fixed to use the production bound and rerun PASS. Empty/full address lists, byte order, bad counts, malformed/injected UI entries and clearing covered. No upload or hardware operations; hardware directory untouched.
## Follow-up — browser Wi-Fi controls and IPv6 diagnosis
- User requests browser Admin shell Wi-Fi parity with SSH/typed settings. Removed only the Wi-Fi status-only policy gate; canonical settings/lifecycle/persistence/diagnostics and hidden secret prompts now work. mDNS remains status-only and unrelated restrictions stay intact. Disruptive commands may cut off the response; owner admission is not peer acknowledgement or cancellation on disconnect.
- User now confirms the CLI displays an IPv6 address, direct IPv6 ping works, and the web interface opens using IPv6. This validates those reported unicast operations, not all Phase 12 checks. `ping sak-1024.local -6` fails on the client with “Die Adressfamilie für Hostnamen wird nicht unterstützt.” That earlier client failure was subsequently resolved through Fedora authselect dual-family mDNS; Avahi AAAA lookup and normal IPv6 hostname access succeeded. Do not reopen this as an established firmware discovery defect.
- Added three bounded preferred numeric addresses to manager snapshot, copied/cleared with the same TCP/IP observation, and labelled output in `wifi status`. Web/OLED schema unchanged. +48 bytes per snapshot/settings copy and shared static storage; compile rejects >3 lwIP slots. No new allocation/task/socket. Latest `pio run` PASS **94,444 B RAM / 1,853,685 B flash** (+48/+660 vs initial Phase12). No upload/device operations.
- PASS: browser policy, new actual Wi-Fi secret-handler/browser-prompt fixture (cancellation/revocation/wiping/history/role guards), account/lifecycle boundary, preferred-address lifecycle/byte-order/rendering/capacity, Network settings, cookie Network and UI171+CSP, diff check. Broader `admin_console_boundary/run.py` passes console/certificate then fails existing SSH-adapter compilation due missing `web_firmware_update_reserve_reboot` fake; left unrelated fixture unchanged. ASan/UBSan unavailable at host link. Hardware directory untouched.
## Phase 12 implementation history — superseded by acceptance above
- User authorized the agreed DHCPv4 hostname / dual-stack SLAAC / STA DNS-SD baseline. Another agent owns `hardware/`; this work did not read or edit it. Do not commit or revert that agent's work. No upload, erase or device operation performed.
- Wi-Fi owner applies full `sak-<suffix>` before DHCP and on rename for future exchanges, using permanent TCP/IP-owned storage to preserve the existing 59-byte hostname maximum beyond IDF's setter limit. Preferred IPv6 link-local/ULA/GUA can establish ONLINE without IPv4; link-local-only can retire fallback AP. One-second reconciliation handles stale/missed events. Web/OLED expose availability; the follow-up above adds actual preferred addresses to CLI output.
- HTTPS default listener verified dual-stack; shared authority parser now strictly canonicalizes bracketed IPv6 without zone IDs. SSH uses one explicitly dual-stack listener with scope-safe peers, preserving two slots. Service owners publish availability through short portMUX sections; Wi-Fi owner reconciles two DNS-SD records and address families. No new task/socket/broker slot/serial payload buffer, dependency version, partition or generated asset change.
- mDNS action API can silently drop queued work; missing families disable each pass, available families repair/re-probe every 30 seconds. Transient stale/zero A window remains until processed; AAAA follows valid-address semantics including deprecated addresses. Upstream calls can block, so polling is not a hard deadline. The later user acceptance establishes the reported device/AAAA behavior, not exhaustive multicast fault/transition testing.
- New **narrow** `cmake/mdns_membership.*` overlay fixes verified mDNS 1.12.0 per-family multicast reference imbalance and failed-PCB join cleanup. Only a build-local source copy is changed; version/source hash guarded, managed source immutable. This is not the abandoned Phase 9 patch set. Membership/CMake tests include negative controls and repeated transitions.
- Final `pio run` PASS: **94,396 B RAM / 1,853,025 B flash** (+176 / +5,380 versus recorded Phase 10); not runtime headroom. Local saved sdkconfig mDNS capacity changed to 2; durable defaults pin IPv4/IPv6 and two services. Initial bool-atomic target failure fixed with portMUX; final target build includes overlay. Existing SDK Kconfig notes remain.
- Host suites PASS: Wi-Fi, mDNS, membership, SSH dual-stack and existing management/runtime/security, auth parser689 (host + actual lwIP), cookie variants, Network settings (after updated netif fakes), UI171+CSP, HTTPS lifecycle45+status8+identity, firmware88+SDKcontract, broker diagnostics and session-store/serial. No network packet, hardware, fault-injection or new high-speed serial pass is implied. Canonical contracts, limits and device checklist: [Phase 12](../roadmap.md#phase-12--advanced-network-integration).
## Phase 10 COMPLETE — explicit user acceptance, 2026-09-18
- User confirmed after firmware upload implementation and the concise-UI fix: “That works perfectly. And the usual operation is also verified.” Acceptance establishes that upload works and normal operation is verified. Do not infer specific fault-injection, NVS before/after comparisons, power-loss or recovery passes. The roadmap's compact regression guidance is reusable, not an acceptance blocker.
@@ -11,7 +42,7 @@ Working memory, not an implementation timeline. Source is authoritative; begin w
- 4KiB internal buffer + transient2048B-stack reboot owner allocated before erase; 10s stall/120s receive-loop budget, not totalflashdeadline. HTTPD synchronously blocks other web work during upload; networkserial maystall/drop, reboot disruptsall. No task/request/socket lifetime capture after handler. Service/identity reservation and atomic ordinary-reboot gate cover UI/UART0/SSH/browser/localbutton paths. Failed response after bootselect schedules noautomaticreset; selected latch rejects further uploads409, manual reboot available. Successful response schedules500ms reboot retaining reservations.
- Review fixed two actualSDK5.5.0 edge cases: failed esp_ota_begin maypublishlivehandle beforeeraseerror (abortthat handle); rawContentLength64 canwrapHTTPDsize_t32 (overflow-safe actualslotbound/strictdecimal/equality check beforebody/erase). End consumes handle evenerror. SDKvalidation followed by exactparsedimage length includingSHA; basic header requiresS3appdescriptor/hash. Unrelated old/privateSDK code unpatched.
- Parent final pio PASS **94,220 B RAM / 1,847,645 B flash**, +24RAM/+19,080flash vsPhase9, not runtimeheadroom. Parent newbackend88cases+actualSDKbeginfailurecontract, UI169groups+CSP, serverlifecycle44, admin25, consolelifecycle, SSHruntime, cookielifecyclePASS. Additionalbase/admin/display/lifecyclecookie, idle18, SSHmanagement/runtime/security agentPASS after adding missing rebootfake to adminfixture (no productionchange). Independent review final noactionablefindings; realbuilt firmware parsed with SDKmetadata bothOTAoffsets (notdeviceflashproof).
- **Scope decision (2026-09-18):** User removed the BLE transport/provisioning proposal entirely because it no longer fits the project concept. BLE is not planned; retain the existing USB, HTTPS/WebSocket and SSH transport scope. Remaining roadmap candidates are under evaluation, not authorized implementation work. Do not resurrect Phase 9 patches. This update changed documentation only; no build, test, upload, erase, device operation or commit was performed.
- **Scope decision (2026-09-18):** User removed the BLE transport/provisioning proposal entirely because it no longer fits the project concept. BLE is not planned; retain the existing USB, HTTPS/WebSocket and SSH transport scope. This earlier scope decision did not authorize implementation; Phase 12 was subsequently authorized and implemented as recorded above. Do not resurrect Phase 9 patches. This update changed documentation only; no build, test, upload, erase, device operation or commit was performed.
## Session logging scope decision
@@ -27,7 +58,7 @@ Working memory, not an implementation timeline. Source is authoritative; begin w
## Evidence limits and follow-ups
- Previously accepted combined binary WS send: CPU160MHz / 230400 baud full mix including browser admin. Latest recorded telemetry has very low internal/DMA lifetime minima (2,052/460 B); these are nonblocking headroom follow-ups, not approved reserves or proof of simultaneous allocation failure. Full table, capture workload and counter limits are preserved in the roadmap.
- Previously accepted combined binary WS send: CPU160MHz / 230400 baud full mix including browser admin. The earlier Phase 8 telemetry had very low internal/DMA lifetime minima (2,052/460 B); these are nonblocking headroom follow-ups, not approved reserves or proof of simultaneous allocation failure. Full table, capture workload and counter limits are preserved in the roadmap. The latest Phase 12 full-mix minima are 8,528/772 B, with the same evidence limits.
- TLS `-0x004C` means generic NET_RECV_FAILED, not OOM. Historical authentication/admission symptoms do not establish a cause. Do not invent fault, soak, timing or power-loss passes.
- Credentials remain unencrypted; old flash contents are not erased. Intermittent trusted-network operation reduces exposure, not physical-extraction risk. Upstream upgrades are separate deliberate tasks, not an endless local backport programme.
- Phase 10 is complete by the explicit acceptance above; detailed unreported regression scenarios remain unevidenced, not completion blockers. Device operations, branch/reset, commits and dependency upgrades remain outside this documentation task.