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.
Wi-Fi Phase 12 focused host regression
Run python3 tests/wifi_phase12/run.py. The renderer tests use the installed public esp_netif_ip_addr.h at ~/.platformio/packages/framework-espidf/components/esp_netif/include/ with host endian/config shims (no SDK modification). Optional --sanitize requires host ASan/UBSan runtime libraries. No PlatformIO build or device access is performed. Compilation/executables use a temporary directory.
The harness extracts production hostname, address reconciliation, IP callback, and deadline functions verbatim. Real manager/config headers define the data contracts. Host fakes model driver association, netif-up state, IPv6 slot states, TCP/IP execution, and clock; surrounding failover/driver operations are call-count fakes, not a full scheduler/network simulation. Wiring assertions cover pre-connect hostname installation and message dispatch.
Coverage includes:
- Configured hostname and rename without disconnect; full 59-byte hostname; config-read failure.
- STA-only IPv6 event filtering, null events, and IPv4 netif filtering.
- Explicit STA SLAAC enablement, link-local creation, no repeated tentative/duplicate DAD.
- Link-local-only, ULA/GUA, IPv4-only, and dual-stack readiness.
- IPv4 loss while IPv6 remains, IPv6 deprecation/removal and restoration.
- No IPv4 deadline failover on usable IPv6; no perpetual fallback stability reset.
- Dropped address/association events, dropped online disconnect, recreated LL after missed disconnect/reconnect, and stale events during stop/profile advance.
- Permanent owner wakeup, including boot-disabled and stopped Wi-Fi; offline service withdrawal, failed record updates and pending reannouncement retries at one-second cadence.
- Busy-loop calls do not repeat periodic work; persistent mDNS failure does not generate per-pass warnings.
- Permanent hostname pointer lifetime, failed offline rename retry, and mutex/TCP-IP-context assertions for address and hostname access.
- Address-read failure/uncertain callback completion withdraws stale readiness without retiring the recovery AP; later successful reads restore readiness.
- Verbatim production console rendering of simultaneous preferred link-local, ULA and GUA addresses, with non-symmetric network-order words and IDF public formatting macros; client-interface zone guidance never renders the ESP32 zone.
- Full numeric list and count clearing on failed callback admission, skipped callback, IP-info error, netif-down and the production disconnect-clear helper; wiring assertions require intentional disconnect, stop and disconnect-event paths to call that helper. Tentative, duplicate and deprecated slots are excluded by the preferred-getter fake matching SDK semantics.
- Increasing configured SDK slots to four fails the production compile-time capacity assertion.
Contract and SDK evidence
ONLINE means a current association/netif with IPv4 or a preferred IPv6 link-local/ULA/GUA address. It is not an Internet/default-route check. Deprecated-only addresses do not qualify for new service readiness. In particular, link-local-only operation suppresses DHCPv4-driven profile failover and can retire the fallback AP after the existing stability interval. IPv6 link-local clients need an interface scope. Snapshot IPv4 fields remain zero on IPv6-only networks; ipv6_linklocal / ipv6_routable booleans report preferred-address availability, not routing success. The console also lists up to three numeric preferred IPv6 addresses from the exact same TCP/IP observation as those flags. Count and all address storage are published/cleared together under the manager mutex. The configured lwIP slot count must not exceed three (compile-time contract, no silent truncation). Web/OLED continue consuming the existing flags without adding list output.
Inspected installed ESP-IDF 5.5.0 sources:
esp_netif/lwip/esp_netif_lwip.c: netif-up and address getters access lwIP directly; all manager netif-up/address checks now execute inside the TCP/IP callback. Preferred getter excludes tentative/duplicate/deprecated/invalid addresses. Disconnect invalidates/clears IPv6 slots.esp_netif_tcpip_execsupplies synchronous TCP/IP context, with no retained stack request on return. Its IDF 5.5 wrapper ignores the underlyingtcpip_send_msg_wait_semresult: explicit completion markers therefore detect a callback that was never executed despite an apparentESP_OK. No hard wall-clock guarantee is made if upstream stalls.lwip/port/include/lwipopts.h,lwip/src/include/lwip/opt.h, andesp_netif_start_api: savedCONFIG_LWIP_IPV6_AUTOCONFIGis disabled, but lwIP SLAAC remains compiled viaLWIP_IPV6_AUTOCONFIG. Explicit per-STAnetif_set_ip6_autoconfig_enabledis needed; AP policy is untouched.esp_netif_set_hostname_apihas a 32-byte limit, below the existing configured hostname maximum of 59. The manager therefore installs permanent bounded storage throughnetif_set_hostnamein TCP/IP context, without transferring ownership to esp-netif.netif_adddoes not clear the hostname;esp_netif/lwip/netif/wlanif.cpreserves it viaesp_netif_get_hostnameduring initialization.lwip/src/core/ipv4/dhcp.c: option 12 is read from the current netif hostname in subsequent outgoing DHCP exchanges (request/renew/rebind included). Rename does not force release/reacquisition or promise immediate router/DNS cache replacement.
Reverify these boundaries for an SDK upgrade. Tests do not emulate DHCP wire packets, router advertisements, actual DAD timers, mDNS component behavior, or socket listeners. A target syntax check is not a linked firmware build. Device and integration validation remain separate.
Coordination
The owner calls the new mdns_service_reconcile every second even offline/stopped. A pending online reannouncement uses mdns_service_reannounce, which also reconciles records. Listener owners' lock-free availability stores need no queue wakeup; changes and failures converge on subsequent passes. Reconciliation never initializes the responder; startup still requires either-family STA readiness. Failures remain nonfatal, visible through service error status, and do not log each retry. Upstream mDNS calls may block: the cadence bounds attempt frequency, not upstream execution time.
wifi_manager_mdns_reannounce also refreshes DHCP option 12 while offline. Periodic hostname refresh retries failed/missed DHCP-name changes without reconnecting. The permanent hostname buffer is only read/written in TCP/IP context; no application status caller borrows that pointer (use the copied mDNS snapshot). Pending mDNS rename errors retry online. Other owners should consume the IPv6 snapshot flags rather than infer readiness from snapshot.ip != 0.
Diagnostic addition resource budget and handoff
The numeric payload is three arrays of four network-order uint32_t words (48 bytes), plus a one-byte count that fits existing snapshot padding. No strings, device zones, task, socket, heap allocation or queue-message growth are introduced. Host layout measurements with production headers: snapshot 232 → 280 bytes; settings projection 424 → 472 bytes; manager shared storage 760 → 808 bytes; temporary address observation 16 → 64 bytes. Thus the manager's static storage grows by 48 bytes, and each existing snapshot/settings copy (console, web, local UI) grows by 48 bytes. The owner observation adds 48 bytes of transient stack payload; the existing three-entry SDK enumeration scratch is unchanged. Actual compiler stack-frame/high-water effects and linked target RAM remain for the parent's build/device checks; host sizes are not runtime headroom evidence.
Scoped validation: normal host suite and slot-cap negative compile PASS. --sanitize could not link on this host because libasan.so.8.0.0 / libubsan.so.1.0.0 are missing. No dependency changes, PlatformIO build or hardware operation performed. Parent owns durable documentation updates (the flags-only statements in agent memory/command docs are now stale for console status) and firmware build. Production edits are limited to src/wifi_manager.c, src/wifi_manager.h, and src/wifi_console.c; tests/docs for this addition stay here.