diff --git a/.gitignore b/.gitignore index e4ce498..e6c1229 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ sdkconfig* !sdkconfig.defaults + +!sdkconfig.defaults.* + diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29..0000000 diff --git a/CMakeLists.txt b/CMakeLists.txt index 199d7c2..7e9d23a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,87 @@ if (ESP_PLATFORM OR IDF_TARGET) set(CM_PLATFORM "ESP32") endif() +# Bench / silent measurement sdkconfig. Must be set before project(). +set(AE_EXP_PREPARED_MESSAGE_E2E "" CACHE STRING + "No-sleep prepared-message E2E bench (set to 1)") +set(AE_EXP_PREPARED_WIFI_CACHE_5X20 "" CACHE STRING + "Silent 5x20 prepared Wi-Fi cache bench (set to 1)") +set(AE_EXP_PREPARED_KEEP_WIFI_UP_5X20 "" CACHE STRING + "Silent 5x20 keep-Wi-Fi-up prepared bench (set to 1)") +set(AE_EXP_PREPARED_WIFI_BISECT "" CACHE STRING + "Silent single-factor prepared Wi-Fi bisect (set to 1)") +set(AE_EXP_PREPARED_WIFI_FASTEST "" CACHE STRING + "Silent fastest-path prepared Wi-Fi campaign (set to 1)") +set(AE_EXP_PREPARED_DEEPSLEEP_5X50 "" CACHE STRING + "Silent deep-sleep 5x50 prepared E2E (set to 1)") +set(AE_EXP_PREPARED_TX_DONE_DIAG "" CACHE STRING + "Silent TX-done callback diagnostic 1x50 (set to 1)") +set(AE_EXP_PREPARED_MAC_RETRY_DIAG "" CACHE STRING + "Silent MAC retry-limit diagnostic 7x50 (set to 1)") +set(AE_EXP_PREPARED_BOOT_WIFI_OPT "" CACHE STRING + "Silent boot/wifi HOT opt campaign 11x30 (set to 1)") +set(AE_EXP_PREPARED_BOOT_WIFI_VAL100 "" CACHE STRING + "Silent VAL100 combined boot/wifi winners (set to 1)") +set(AE_EXP_TX_DIAG_MODE "" CACHE STRING + "TX-done diag wait mode: 0=FIRST_ANY 1=FIRST_SUCCESS") +set(AE_EXP_FAST_DISABLE_WPA3 "" CACHE STRING + "Benchmark-only: disable CONFIG_ESP_WIFI_ENABLE_WPA3_SAE (set to 1)") +set(AE_EXP_BISECT_CONSOLE "" CACHE STRING + "Bisect USB stage markers / console (set to 1; disables silent)") +set(AE_EXP_BISECT_SMOKE "" CACHE STRING + "Bisect smoke: B1 only, 2 prepared (set to 1)") +if(AE_EXP_BISECT_CONSOLE STREQUAL "1" AND + AE_EXP_PREPARED_WIFI_BISECT STREQUAL "1") + list(APPEND SDKCONFIG_DEFAULTS + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.bench") +elseif(AE_EXP_PREPARED_DEEPSLEEP_5X50 STREQUAL "1") + list(APPEND SDKCONFIG_DEFAULTS + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.silent" + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.fastest" + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.wpa2only" + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.deepsleep_5x50") +elseif(AE_EXP_PREPARED_TX_DONE_DIAG STREQUAL "1") + list(APPEND SDKCONFIG_DEFAULTS + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.silent" + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.fastest" + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.wpa2only" + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.deepsleep_5x50") +elseif(AE_EXP_PREPARED_MAC_RETRY_DIAG STREQUAL "1") + list(APPEND SDKCONFIG_DEFAULTS + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.silent" + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.fastest" + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.wpa2only" + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.deepsleep_5x50") +elseif(AE_EXP_PREPARED_BOOT_WIFI_OPT STREQUAL "1") + list(APPEND SDKCONFIG_DEFAULTS + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.silent" + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.fastest" + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.wpa2only" + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.deepsleep_5x50") +elseif(AE_EXP_PREPARED_BOOT_WIFI_VAL100 STREQUAL "1") + list(APPEND SDKCONFIG_DEFAULTS + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.silent" + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.fastest" + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.wpa2only" + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.deepsleep_5x50") +elseif(AE_EXP_PREPARED_WIFI_FASTEST STREQUAL "1") + list(APPEND SDKCONFIG_DEFAULTS + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.silent" + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.fastest") + if(AE_EXP_FAST_DISABLE_WPA3 STREQUAL "1") + list(APPEND SDKCONFIG_DEFAULTS + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.wpa2only") + endif() +elseif(AE_EXP_PREPARED_WIFI_CACHE_5X20 STREQUAL "1" OR + AE_EXP_PREPARED_KEEP_WIFI_UP_5X20 STREQUAL "1" OR + AE_EXP_PREPARED_WIFI_BISECT STREQUAL "1") + list(APPEND SDKCONFIG_DEFAULTS + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.silent") +elseif(AE_EXP_PREPARED_MESSAGE_E2E STREQUAL "1") + list(APPEND SDKCONFIG_DEFAULTS + "${CMAKE_CURRENT_LIST_DIR}/sdkconfig.defaults.bench") +endif() + set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/README.md b/README.md index 1f0e51b..cb61e6f 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,6 @@ ## Build Instructions ### Init dependencies -It uses git submodules to manage dependencies. -``` -git submodule update --init --remote ./aether-client-cpp -``` +`aether-client-cpp` is fetched automatically by [CPM.cmake](https://github.com/cpm-cmake/CPM.cmake) during the CMake configure step (branch `prepared-packet-v0`). ### For desktop For desktop a regular cmake project is used. diff --git a/experiments/PREPARED_BOOT_WIFI_OPT_REPORT.md b/experiments/PREPARED_BOOT_WIFI_OPT_REPORT.md new file mode 100644 index 0000000..ff7cb81 --- /dev/null +++ b/experiments/PREPARED_BOOT_WIFI_OPT_REPORT.md @@ -0,0 +1,110 @@ +# Prepared Boot / Wi-Fi HOT Optimization Report + +ESP32-C6 · ESP-IDF v6.0.2 · branch `thermometer-prepared-send-v0` +aether-client-cpp **unchanged** `157aadbec8e7b852d0f89274307ff7cb8103e5f7` + +## Campaign + +- One autonomous flash, RTC state machine, **30 HOT / variant** (not 50). +- Telemetry only via Æther (`BootWifiOptPayload` `0xD8`); no COM after flash. +- Baseline locked: WPA2, cached channel, no BSSID, static IP/ARP, Wi-Fi 4, auto PHY, + `WIFI_PS_NONE`, default TX power, PRE=25 ms, late TX-done, no MAC retry setter, + deep sleep between sends. +- Runtime matrix: **D0–D3, G1, H1–H2, E1–E4** (11 variants). +- Stopped at **E4 ≈27/30** (COM stuck awake); **298 HOT** records analyzed. FINAL not received. + +## Effective compile-time config (this flash) + +| Item | Value | Notes | +|------|-------|-------| +| External RTC crystal | **yes** `CONFIG_RTC_CLK_SRC_EXT_CRYS=y` | Already enabled | +| `RTC_CLK_CAL_CYCLES` | **1024** | Defaults file asks for `0`; forced `0` on first attempt left COM awake with zero telemetry — **reverted** | +| Boot validation | `SKIP_VALIDATE_IN_DEEP_SLEEP=y` (+ `ON_POWER_ON=y`) | A1 already; A0 not a separate flash | +| Bootloader opt | **SIZE** (not PERF) | A2 skipped (one-flash) | +| Flash | **DIO 80 MHz** | QIO not forced (board/flash not verified for QIO) | +| Secure Boot | **disabled** | | +| Flash encryption | **disabled** | | +| AMPDU TX/RX | **already off** in sdkconfig | F1–F6 skipped as identical to control | + +### A-matrix (one-flash limitation) + +| Variant | Status | +|---------|--------| +| A0 CONTROL (validate on deep-sleep wake) | Not flashed separately | +| A1 SKIP_VALIDATE_IN_DEEP_SLEEP | **Effective** | +| A2 + PERF | Not applied | +| A3 QIO 80 | Not applied (DIO 80 kept) | +| A4 CAL_CYCLES=0 | **Attempted → hang; kept 1024** | +| A5 SKIP_VALIDATE_ALWAYS | Not applied (bench-only; Secure Boot off) | + +**Security note (A5):** `SKIP_VALIDATE_ALWAYS` disables image validation on every boot — incompatible with Secure Boot / anti-rollback / flash-encryption production posture. Effective here: Secure Boot off, flash encryption off. + +### B — External crystal + +Enabled. Wake overhead median ≈ **40.7 ms** on all variants (compile-time, not runtime). +3 s sleep drift / hardware deep-sleep current: not measured in software (scope separately). + +### C — PHY cal RTC reuse + +**`RTC_PHY_CAL_REUSE_NOT_SUPPORTED_BY_PUBLIC_API`** + +IDF 6.0.2 exposes `esp_phy_load_cal_data_from_nvs` / `esp_phy_store_cal_data_to_nvs` and deep-sleep path uses `PHY_RF_CAL_NONE`, but there is **no public API** to inject an RTC-held `esp_phy_calibration_data_t` blob into PHY init. No opaque driver memcpy. Measured path = stock IDF deep-sleep no-calibration + NVS cal storage left enabled. + +## Main results (median µs) + +See also `experiments/prepared_boot_wifi_opt_summary.tsv` and raw `experiments/prepared_boot_wifi_opt.tsv`. + +| variant | setting | delivery/30 | wake_ov_med | wifi_init_med | connect_med | txdone_med | hot_user_med | p90 | max | heap_delta | notes | +|---------|---------|-------------|-------------|---------------|-------------|------------|--------------|-----|-----|------------|-------| +| D0_CONTROL | baseline | 29/30 | 40732 | 16447 | 143814 | 6490 | 250269 | 320267 | 410269 | 46584 | n=29 | +| D1_STORAGE_RAM | WIFI_STORAGE_RAM | 27/30 | 40736 | 16404 | 138933 | 5606 | **240270** | 310257 | 520259 | 46584 | n=27 | +| D2_NVS_OFF | nvs_enable=0 | 25/30 | 40770 | **10623** | 233508 | 7721 | 340259 | 380256 | 470264 | 46480 | worse connect | +| D3_RAM_NVS_OFF | RAM+nvs_off | 25/30 | 40772 | 10618 | 238533 | 6435 | 370256 | 420256 | 440249 | 46480 | worse | +| G1_HT20 | force HT20 | 30/30 | 40752 | 16360 | 134263 | 6306 | 250271 | 320269 | 390269 | 46584 | connect↓ | +| H1_CS_OFF | dynamic_cs=false | 26/30 | 40767 | 16441 | 138312 | 5037 | 250264 | 310271 | 380266 | 46584 | ≈D0 | +| H2_CS_ON | dynamic_cs=true | 26/30 | 40776 | 16357 | 141900 | 5552 | 270274 | 320272 | 820265 | 46584 | worse tails | +| E1_TX_HALF | dyn_tx=16 | 30/30 | 40772 | 16433 | 133819 | 3138 | 260266 | 310269 | 670262 | 46584 | time≈ | +| E2_TX_MIN | dyn_tx=8 | 25/30 | 40766 | 16366 | 136230 | 4665 | 250269 | 310269 | 340269 | 46584 | time≈ | +| E3_RX_HALF | rx 5/16 | 29/30 | 40768 | 16366 | **132388** | 5142 | 250269 | 310274 | 1040297 | **37984** | RAM↓ | +| E4_RX_MIN | rx 3/8 | 26/30 | 40780 | 16272 | 146044 | 5960 | 270269 | 420267 | 770272 | **34544** | best RAM | + +## Winners + +| Category | Winner | Evidence | +|----------|--------|----------| +| **BOOT** | A1 + EXT_CRYS (wake_ov ≈40.7 ms) | Flat across runtime variants; A4=0 unsafe here | +| **WIFI / hot_user** | **D1_STORAGE_RAM** | −10 ms median vs D0 | +| **RAM** | **E4_RX_MIN** (then E3) | heap_delta 34544 / 37984 vs 46584 | +| **PHY CAL** | N/A public RTC inject | stock IDF no-cal on deep-sleep wake | +| **EXTERNAL XTAL** | enabled | CAL_CYCLES effective **1024** | +| **Wi-Fi storage** | **D1 RAM** | D2/D3 hurt connect ≫ init win | +| **NVS enable** | keep **enabled** | nvs_off regresses hot cycle | +| **AMPDU/A-MSDU** | already off | no new variants | +| **HT20** | neutral time, slightly faster connect | include in combined | +| **dynamic CS** | **false** (H1) ≈ control; true worse tails | include false | +| **buffers** | E3/E4 save RAM; little time win | E3 in combined | + +### Combined BEST candidate → VAL100 + +`WIFI_STORAGE_RAM` + `force HT20` + `dynamic_cs=false` + RX half (`static_rx=5`, `dynamic_rx=16`) + `nvs_enable=1`. + +TX power / MAC retry policy unchanged. + +## VAL100 + +Combined: `WIFI_STORAGE_RAM` + HT20 + `dynamic_cs=false` + RX half (5/16) + `nvs_enable=1`. + +| metric | value | +|--------|-------| +| delivery | **91/100** received (txok=91); FINAL received | +| wake_overhead_med | **40710 µs** | +| wifi_init_med | 16387 µs | +| connect_med | **131618 µs** | +| txdone_med | 11621 µs | +| hot_user_med | **250269 µs** (p90 320268, max 470270) | +| heap_delta_med | **37984** (E3-class RAM) | +| brownouts | **0** | + +Notes: first post-flash wake needed a manual board reset (COM stuck awake until reset), same as the main campaign. Combined config matches D0 on hot_user median; **D1 alone** remains the best single time win (−10 ms). Combined keeps E3 RAM savings and faster connect vs D0. + +Raw: `experiments/prepared_boot_wifi_val100.tsv` diff --git a/experiments/PREPARED_DEEPSLEEP_5X50_REPORT.md b/experiments/PREPARED_DEEPSLEEP_5X50_REPORT.md new file mode 100644 index 0000000..b90fb3f --- /dev/null +++ b/experiments/PREPARED_DEEPSLEEP_5X50_REPORT.md @@ -0,0 +1,139 @@ +# Prepared deep-sleep 5×50 E2E report + +Experiment only. Production `SendPreparedOnce` was **not** switched. + +## Pins + +| Repo | Branch | SHA | +|------|--------|-----| +| temperature-sensor | `thermometer-prepared-send-v0` | *(this commit)* | +| aether-client-cpp | `exp/esp32c6-wifi-lifecycle-diag` | `157aadbec8e7b852d0f89274307ff7cb8103e5f7` **unchanged** | + +## Effective sdkconfig (verified before flash) + +``` +CONFIG_RTC_CLK_SRC_EXT_CRYS=y +# CONFIG_RTC_CLK_SRC_INT_RC is not set +CONFIG_RTC_CLK_CAL_CYCLES=1024 +CONFIG_ESP_BROWNOUT_DET=y +CONFIG_ESP_BROWNOUT_DET_LVL_SEL_7=y (from base defaults) +# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set +CONFIG_ESP_CONSOLE_NONE=y +CONFIG_LOG_DEFAULT_LEVEL_NONE=y +CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y +# CONFIG_PM_ENABLE is not set +CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y +``` + +## Fast Wi-Fi / HOT path + +- WPA2-PSK, negotiated authmode=3 on all recovered HOT samples +- Cached channel; **no** BSSID reconnect +- Static IPv4 / netmask / gateway + cached GW MAC + static ARP (RTC `PreparedWifiRtcCache`) +- Wi-Fi 4 (b/g/n), auto PHY, `WIFI_PS_NONE`, max TX, retry=10 +- PRE=25 ms, POST=0, late TX-done callback immediately before `sendto`, socket held until callback +- Safety callback wait ≤100 ms; no fingerprint matching + +## RTC state + +- `RtcState` (magic `DS3P`) + CRC: phase, outer 1..5, hot 1..50, attempts, pending measurement, brownout/unexpected counters, sleep arm timestamp +- `PreparedWifiRtcCache` (magic `WCF1`) + CRC: channel, IP, netmask, gateway, gw_mac (BSSID diagnostic only) +- Prepared nonce block remains `RTC_NOINIT` `PreparedSendMessageBlock` (existing aether layout) +- Early `app_main` hook: `ExperimentEarlyAppEntry()` before WDT/`setup` + +## Campaign shape + +- Client id: `prepared_deepsleep_5x50_v1` +- 5 measured FULL Æther cycles +- Per FULL: `PrepareSendMessageBlock(50)` → 50 deep-sleep HOT wakes (3 s) → next FULL +- Target: 250 prepared `sendto`; FINAL Aether report after last HOT + +## Delivery / lifecycle + +| Item | Result | +|------|--------| +| FULL messages recovered | **5/5** | +| HOT measurement records | **249/250** (outer 5 missing last pending = HOT#50 flush via FINAL) | +| FINAL message | **not received** (FINAL Aether phase stuck/retried; campaign timed out) | +| callback_seen (HOT) | **246** | +| callback_timeout (HOT) | **3** | +| authmode=3 | **249/249** HOT | +| brownout boots | **0** | +| unexpected resets (payload) | **0** | + +Prepared `sendto` lifecycle on device is independent of UDP delivery; UDP losses are expected. + +## FULL USER CYCLE (n=5) + +Raw (ms): 12670, 3640, 4310, 3600, 3620 + +| | ms | +|--|-----| +| min | 3600 | +| **median** | **3640** | +| p90 | 12670 | +| max | 12670 | + +(First FULL includes colder registration-adjacent work; later FULLs ~3.6–4.3 s.) + +## HOT USER CYCLE (n=249) + +| | ms | +|--|-----| +| min | ~(from samples) | +| **median** | **250** | +| p90 | 320 | +| p99 | 1090 | +| max | 1370 | + +## HOT WIFI CYCLE (n=249) + +| | ms | +|--|-----| +| **median** | **239** | +| p90 | 309 | +| p99 | 1079 | +| max | 1359 | + +## CONNECT / TX-DONE / TEARDOWN (HOT) + +| | med ms | p90 ms | max ms | +|--|--------|--------|--------| +| connect | 133 | 188 | 1293 | +| tx-done wait | 11 | 23 | 100 | +| teardown | 77 | 97 | 967 | + +## SLEEP → APP overhead + +`sleep_elapsed_to_app_us` median ≈ **3040.7 ms** (requested 3000 ms) + +| | med ms | p90 | p99 | max | +|--|--------|------|-----|-----| +| sleep_to_app_overhead | **40.7** | 40.8 | 40.8 | 40.9 | +| app_entry_esp_timer_us | **5424** | 5424 | — | 5425 | + +## Brownout / reset + +| | count | +|--|-------| +| ESP_RST_BROWNOUT boots (payload flag) | 0 | +| unexpected_reset_count in payloads | 0 | +| recovery FULL (not observed in TSV) | 0 | + +## Confirmation + +- Five FULL blocks: **yes** (records for outer 1..5) +- 50 prepared nonces per block: **yes** (HOT counts 50/50/50/50/49 recovered; last pending needs FINAL) +- Total prepared sends targeted 250: device completed through HOT#46–50 of outer 5; **249** timing records recovered via pending chain + +## Artifacts + +- `experiments/prepared_deepsleep_5x50.tsv` +- `experiments/run_deepsleep_5x50.py` +- `main/prepared_deepsleep_5x50_bench.cpp` +- `sdkconfig.defaults.deepsleep_5x50` + +## Note on FINAL + +FINAL Æther write after HOT#50 outer 5 did not reach the receiver before the orchestrator timeout. A fail-counter fallback to DONE was added for subsequent runs. Metrics above are from the successful pending-chain delivery of FULL + HOT records. diff --git a/experiments/PREPARED_KEEP_WIFI_UP_REPORT.md b/experiments/PREPARED_KEEP_WIFI_UP_REPORT.md new file mode 100644 index 0000000..b18c3ff --- /dev/null +++ b/experiments/PREPARED_KEEP_WIFI_UP_REPORT.md @@ -0,0 +1,103 @@ +# Prepared KEEP-WIFI-UP 5×20 (ESP32-C6, silent) + +Hardware: ESP32-C6, ESP-IDF v6.0.2, COM7 +Aether: `exp/esp32c6-wifi-lifecycle-diag` @ `157aadbec8e7b852d0f89274307ff7cb8103e5f7` (**unchanged**) +Firmware: `AE_EXP_PREPARED_KEEP_WIFI_UP_5X20=1`, silent console/log NONE +Client: `prepared_keep_wifi_up_5x20_v1` +Receiver UID: `5aade50f-00d9-4624-b097-e203cdcf1e38` +Block reserve: **20** (unchanged prepared packet path) + +## Hypothesis + +Losses on prepared sends may be caused by **full Wi-Fi teardown + reassociation after every prepared message**. + +## A/B change (bench-only) + +Production `SendPreparedOnce()` unchanged. + +New session API: + +- `BeginPreparedWifiSession()` — init, associate, static IP/ARP once; leave Wi-Fi up +- `SendPreparedPacketOnActiveWifi()` — EncodePacket → socket → sendto → close (no stop/deinit/reconnect) +- `EndPreparedWifiSession()` — stop/deinit/cleanup after message #20 + +Per outer cycle: FULL → PrepareSendMessageBlock(20) → capture Wi-Fi cache → release FULL Æther → Begin session → 20 prepared sends (1 s gap, **no** post-send hold) → End session. + +Socket is still create/close **per message** (extra socket A/B not required). + +## previous + +| Experiment | Delivery | +|---|---| +| static ARP + teardown each send | **29/100** | +| hold 300→600 ms (control) | **6/20 ≈ 30%** | + +## new + +| Experiment | Delivery | +|---|---| +| keep Wi-Fi up (5×20) | **96/100** | + +### DELIVERY detail + +``` +full=6/5 +prepared=96/100 +final=1/1 +missing=4 +duplicates=1 +out_of_order=0 +``` + +Cache flags on recovered prepared: BSSID/IP/DHCP-skip/static-ARP hits=99 (payload flag path active). + +## wifi_session_start + +Measured once per outer cycle (init → association → static IP/ARP ready). Carried on PREPARED#1 as `previous_full_us`. Only 2/5 first-of-burst messages recovered, so n=2: + +``` +raw=[254249, 279549] +min=254249 +median=279549 +max=279549 +n=2 +``` + +(~0.25–0.28 s) + +## prepared send (encode + socket + sendto + close only) + +No 300 ms post-send hold in this mode. + +### FIRST PREPARED (send-only) + +``` +raw=[2467, 2415, 2418, 3785, 2413] +min=2413 +median=2418 +max=3785 +n=5 +``` + +### ALL PREPARED (send-only) + +``` +n=99 +min=2180 +median=2600 +p90=2710 +p99=3785 +max=3785 +``` + +(~2.6 ms median) + +## Verdict + +``` +LOSS LOCATION = WIFI RECONNECT/TEARDOWN +``` + +KEEP-WIFI-UP reaches **96/100** (criterion ~95–100/100). Packet encoding / server / nonce / UDP path is adequate when Wi-Fi stays associated; prior ~30% delivery tracks full teardown/reassociation between each prepared send. + +Do **not** chase further Wi-Fi micro-optimizations (ARP, hold) for this loss class — next product work is avoiding per-message Wi-Fi lifecycle, not changing prepared packets. diff --git a/experiments/PREPARED_MAC_RETRY_DIAG_REPORT.md b/experiments/PREPARED_MAC_RETRY_DIAG_REPORT.md new file mode 100644 index 0000000..c1b5fde --- /dev/null +++ b/experiments/PREPARED_MAC_RETRY_DIAG_REPORT.md @@ -0,0 +1,91 @@ +# Prepared MAC retry diagnostic report + +Experiment-only. Production `SendPreparedOnce` unchanged. +aether-client-cpp SHA `157aadbec8e7b852d0f89274307ff7cb8103e5f7` **unchanged=yes**. + +## Campaign notes + +- One flash (`AE_EXP_PREPARED_MAC_RETRY_DIAG=1`), RTC magic `MRT1`. +- COM used only for flash; progress via Æther receiver only. +- `esp_wifi_internal_set_retry_counter` **symbol_resolved=yes** (map `.text.esp_wifi_internal_set_retry_counter`). +- Runtime: CONTROL `retry_set_rc=-1` (not called); all other variants `retry_set_rc=0` (`ESP_OK`). +- Campaign progressed CONTROL→…→V6 then stalled around V6 ~41/50 received (no further RETRY for >10 min). Analysis uses collected TSV (incomplete delivery on later variants is UDP loss + stall). +- ESP still attempted fire-and-forget sendto; missing receiver packets are not campaign blockers. + +## Per-variant summary (reconnect_count==0) + +| variant | n | delivery | tx_ok | tx_fail | rc_ok | txdone_med | p90 | p99 | max | +|---|---:|---:|---:|---:|---:|---:|---:|---:|---:| +| CONTROL | 50 | 50/50 | 50 | 0 | yes | 3709 | 12766 | 28724 | 28724 | +| 0/0 | 38 | 38/50 | 31 | 7 | yes | 5188 | 18446 | 76286 | 76286 | +| 1/1 | 38 | 38/50 | 34 | 4 | yes | 4658 | 17001 | 22203 | 22203 | +| 2/2 | 38 | 38/50 | 34 | 4 | yes | 6556 | 24145 | 50821 | 50821 | +| 3/3 | 40 | 40/50 | 36 | 4 | yes | 5303 | 23152 | 46327 | 46327 | +| 1/7 | 22 | 22/50 | 17 | 5 | yes | 5200 | 9867 | 11888 | 11888 | +| 7/1 | 41 | 41/50 | 37 | 4 | yes | 5565 | 14354 | 58869 | 58869 | + +Units for txdone_*: microseconds. + +## Retry limit curve + +| retry | delivery | tx_ok | tx_fail | med | p90 | p99 | max | +|---|---:|---:|---:|---:|---:|---:|---:| +| CONTROL | 50/50 | 50 | 0 | 3709 | 12766 | 28724 | 28724 | +| 0/0 | 38/50 | 31 | 7 | 5188 | 18446 | 76286 | 76286 | +| 1/1 | 38/50 | 34 | 4 | 4658 | 17001 | 22203 | 22203 | +| 2/2 | 38/50 | 34 | 4 | 6556 | 24145 | 50821 | 50821 | +| 3/3 | 40/50 | 36 | 4 | 5303 | 23152 | 46327 | 46327 | + +No monotonic 0→1→2→3→CONTROL growth of tx_done tail. + +## Short vs long (CONTROL / 1/7 / 7/1) + +| variant | delivery | tx_ok | tx_fail | med | p90 | p99 | max | +|---|---:|---:|---:|---:|---:|---:|---:| +| CONTROL | 50/50 | 50 | 0 | 3709 | 12766 | 28724 | 28724 | +| 1/7 | 22/50 | 17 | 5 | 5200 | 9867 | 11888 | 11888 | +| 7/1 | 41/50 | 37 | 4 | 5565 | 14354 | 58869 | 58869 | + +1/7 shows a shorter p90 than CONTROL but **n=22 incomplete** and higher fail rate; 7/1 still has a long max. **INCONCLUSIVE** for short vs long ownership. + +## tx_done buckets (reconnect==0) + +- CONTROL: <2ms=18, 2-5ms=9, 5-10ms=10, 10-20ms=9, 20-40ms=4, 40-60ms=0, 60-100ms=0, timeout=0 +- 0/0: <2ms=13, 2-5ms=5, 5-10ms=10, 10-20ms=6, 20-40ms=2, 40-60ms=0, 60-100ms=2, timeout=0 +- 1/1: <2ms=12, 2-5ms=8, 5-10ms=9, 10-20ms=7, 20-40ms=2, 40-60ms=0, 60-100ms=0, timeout=0 +- 2/2: <2ms=9, 2-5ms=8, 5-10ms=8, 10-20ms=5, 20-40ms=6, 40-60ms=2, 60-100ms=0, timeout=0 +- 3/3: <2ms=8, 2-5ms=8, 5-10ms=10, 10-20ms=6, 20-40ms=7, 40-60ms=1, 60-100ms=0, timeout=0 +- 1/7: <2ms=6, 2-5ms=4, 5-10ms=10, 10-20ms=2, 20-40ms=0, 40-60ms=0, 60-100ms=0, timeout=0 +- 7/1: <2ms=16, 2-5ms=3, 5-10ms=11, 10-20ms=8, 20-40ms=2, 40-60ms=1, 60-100ms=0, timeout=0 + +## RSSI medians + +- CONTROL: -35 dBm (n=50) +- 0/0: -42 dBm (n=38) +- 1/1: -40 dBm (n=38) +- 2/2: -40 dBm (n=38) +- 3/3: -41 dBm (n=40) +- 1/7: -40 dBm (n=22) +- 7/1: -43 dBm (n=41) + +CONTROL had markedly better RSSI; later variants ran with worse RSSI, confounding retry comparisons. + +## Answers + +1. **API works on ESP32-C6 / IDF 6.0.2?** yes (`retry_set_rc=0` whenever called). +2. **0/0 semantics?** Not “off”. Tail and fails **worse** than CONTROL → likely clamp/default-like or ineffective for our frame; not a clean disable. +3. **short vs long?** **NEITHER / INCONCLUSIVE** (incomplete 1/7, no clean CONTROL-like vs collapsed-tail split). +4. **tx_done_wait vs limit?** No useful monotonic curve; CONTROL often best. +5. **txStatus?** CONTROL 50/0 ok/fail; setting limits introduced fails (~4–7). +6. **UDP delivery?** Incomplete on later variants (loss + stall); not improved by lowering MAC retry. +7. **Long tail gone at 0/1?** **No** — 0/0 and 1/1 still show 10–20ms+ and 0/0 has 60–100ms samples. +8. **RSSI correlation?** Yes confounder: CONTROL −35 dBm vs later ≈−40…−43 dBm. +9. **MAC_RETRY_HYPOTHESIS_CONFIRMED=no** + Observed dense RF / long `tx_done_wait` is **not** systematically explained by `esp_wifi_internal_set_retry_counter` in this run. +10. **Latency/energy suggestion (not production):** leave default (**CONTROL** / do not call setter) until a cleaner equal-RSSI rerun. + +## Verdict + +`MAC_RETRY_HYPOTHESIS_NOT_CONFIRMED` + +Next candidates: management/control traffic after sendto, teardown traffic, other driver activity, or AP-side behavior — not application UDP retry (none performed). diff --git a/experiments/PREPARED_MESSAGE_E2E_REPORT.md b/experiments/PREPARED_MESSAGE_E2E_REPORT.md new file mode 100644 index 0000000..bd43aa2 --- /dev/null +++ b/experiments/PREPARED_MESSAGE_E2E_REPORT.md @@ -0,0 +1,57 @@ +# Prepared message E2E (ESP32-C6, no sleep) + +Hardware: ESP32-C6, ESP-IDF v6.0.2, COM7 +Aether: `exp/esp32c6-wifi-lifecycle-diag` @ `157aadbec8e7b852d0f89274307ff7cb8103e5f7` +Firmware build: `build-esp32c6-save-bench-smoke` (`AE_EXP_PREPARED_MESSAGE_E2E=1`) +Receiver: `temperature_receiver/build-prepared-e2e` (`prepared_message_bench_rx_v1`) +Session: `experiments/prepared_message_rx_session` + +## Coordinated run (authoritative) + +| Item | Value | +|------|-------| +| Bench client | `prepared_message_bench_v6` | +| Sender UID | `bb28fcdf-3872-4214-adb1-9ee63f05f85e` | +| Receiver UID | `fd4e309f-1619-4cbb-ada7-c69134901490` | + +### Metrics (ESP serial) + +``` +REGISTRATION + time_ms=1048 +FULL CYCLE + time_ms=11715 +PREPARED + raw=[2250, 2250, 2190, 2340, 2390, 2240, 2290, 2340, 2230] + min=2190 + median=2250 + p90=2340 + max=2390 + completed=9/10 +prepared block: + reserved=10 + remaining=1 +``` + +PREPARED #1: `wifi-failed` / `connect_timeout` (~15090 ms, nonce not consumed). +PREPARED #2–#10: `sent` (~2.2–2.4 s each). + +### Receiver (desktop console) + +``` +RECEIVER + full=1/1 + prepared=9/10 + missing=1 [1] + duplicates=0 +``` + +Observed RECV: `FULL:0`, `PREPARED:2` … `PREPARED:10` (no `PREPARED:1`). + +## Notes + +- Single boot: registration → destroy Æther → FULL + block(10) → destroy Æther → 10 hot-path sends (1 s gap outside timer). +- `prepared_packet/` identical between experiment SHA and main `07841f3c`; no cherry-pick. +- No-sleep bench calls `ReleaseFullAetherWifiForHotPath()` before prepared loop (Aether leaves ESP-IDF Wi-Fi up; production uses deep-sleep reboot). +- First prepared send after release hits hot-path Wi-Fi `connect_timeout`; local RTC Wi-Fi cache not warm until after first successful connect. +- `prepared_message_e2e.tsv` — raw timings for this run. diff --git a/experiments/PREPARED_STATIC_ARP_5X20_REPORT.md b/experiments/PREPARED_STATIC_ARP_5X20_REPORT.md new file mode 100644 index 0000000..123a9c5 --- /dev/null +++ b/experiments/PREPARED_STATIC_ARP_5X20_REPORT.md @@ -0,0 +1,133 @@ +# Prepared static ARP 5×20 (ESP32-C6, no sleep, silent) + +Hardware: ESP32-C6, ESP-IDF v6.0.2, COM7 +Aether: `exp/esp32c6-wifi-lifecycle-diag` @ `157aadbec8e7b852d0f89274307ff7cb8103e5f7` (**unchanged**) +Firmware: `AE_EXP_PREPARED_WIFI_CACHE_5X20=1`, silent console/log NONE +Client: `prepared_wifi_cache_5x20_v1` +Receiver UID: `5aade50f-00d9-4624-b097-e203cdcf1e38` +Post-send hold: **300 ms** (included in prepared timings) + +## Changes vs `669ccdc3…` + +- Local prepared Wi-Fi cache extended with `gateway_mac[6]` + `gateway_mac_valid` +- Cold/DHCP path resolves gateway MAC via lwIP ARP (`etharp_request` / `etharp_find_addr` on tcpip thread) +- `CapturePreparedWifiCacheFromActiveConnection()` exports BSSID/channel/IP/gw/MAC from live FULL Æther Wi-Fi before release +- Fast path installs static ARP (`etharp_add_static_entry` via `esp_netif_tcpip_exec`) before `EncodePacket` / `sendto` +- Payload flags: `used_static_arp`, `arp_fallback`, `wifi_fallback` (plus existing BSSID/IP/DHCP bits) + +## Comparison to previous (`669ccdc3…`) + +| Metric | BEFORE (`669ccdc`) | AFTER (static ARP + FULL cache export) | +|---|---|---| +| prepared delivery | **44/100** | **29/100** | +| warm median | ~640 ms | ~650 ms | +| FIRST PREPARED | ~15.1 s cold (1/5 recovered) | **~660–760 ms** (3/5 recovered) | +| used_static_arp | n/a | **32 hits** | +| arp_fallback | n/a | 0 | +| wifi_fallback | 0 | 0 | + +**Verdict:** FULL→prepared cache export fixed FIRST PREPARED (no longer ~15 s cold). Static ARP installed and used (`flags=15`). Delivery did **not** improve (still far from 100/100); slightly worse in this run. + +## REGISTRATION + +``` +time_us=251137 +``` + +(~0.25 s) — NVS already had registration after earlier erase+boot; not a cold cloud register. + +## FULL + +``` +raw=[4738679, 3471545, 2911524, 3591534, 2871515] +min=2871515 +median=3471545 +max=4738679 +n=5 +``` + +## FIRST PREPARED (after FULL cache export) + +``` +raw=[760476, 730476, 660476] +min=660476 +median=730476 +max=760476 +n=3 +``` + +(~0.66–0.76 s including 300 ms hold) — **fast**, matches warm path. + +### FIRST PREPARED BEFORE vs AFTER + +| | BEFORE | AFTER | +|---|---|---| +| FIRST PREPARED | ~cold / ~15 s | ~730 ms median | + +## WARM PREPARED + +``` +n=29 +min=610482 +median=650477 +p90=720478 +p99=3020485 +max=3020485 +``` + +(~0.65 s median including 300 ms hold). Two ~3.0 s outliers. + +## ALL PREPARED (recovered timings) + +``` +n=32 +min=610482 +median=650482 +p90=730476 +p99=3020485 +max=3020485 +``` + +## DELIVERY + +``` +full=6/5 +prepared=29/100 +final=1/1 +missing=71 +duplicates=1 +out_of_order=0 +``` + +`full=6/5` / `duplicates=1`: one duplicated FULL outer=1 after mid-run hard reset. + +## CACHE + +``` +BSSID reuse confirmed=yes (hits=32) +static IP reuse confirmed=yes (hits=32) +DHCP skipped confirmed=yes (hits=32) +used_static_arp hits=32 +arp_fallback hits=0 +wifi_fallback hits=0 +``` + +`cache_flags=15` = `UsedBssid | UsedStaticIp | DhcpSkipped | UsedStaticArp`. + +## Control: hold=600 ms × 20 prepared + +Same fast path + static ARP; only hold increased to 600 ms; one outer × 20. + +``` +prepared delivery = 6/20 (~30%) +timings ~930–970 ms (includes 600 ms hold) +used_static_arp on recovered samples +``` + +**600 ms did not improve delivery** (same ~30% rate as 29/100). Unlikely that post-`sendto` async TX flush alone explains losses under a 300 ms hold. + +## Notes / next hypotheses + +- Static ARP + cache export are working; reliability bottleneck is elsewhere (Wi-Fi teardown vs UDP path, AP/router drop, packet size/path, or association instability — see ~3 s outliers). +- Do not increase hold further without a new hypothesis. +- Prefer targeted diagnostics (e.g. keep Wi-Fi up across prepared burst, or confirm UDP arrives at gateway) over broad refactors. diff --git a/experiments/PREPARED_WIFI_CACHE_5X20_REPORT.md b/experiments/PREPARED_WIFI_CACHE_5X20_REPORT.md new file mode 100644 index 0000000..b4f3970 --- /dev/null +++ b/experiments/PREPARED_WIFI_CACHE_5X20_REPORT.md @@ -0,0 +1,97 @@ +# Prepared Wi-Fi cache 5×20 (ESP32-C6, no sleep, silent) + +Hardware: ESP32-C6, ESP-IDF v6.0.2, COM7 +Aether: `exp/esp32c6-wifi-lifecycle-diag` @ `157aadbec8e7b852d0f89274307ff7cb8103e5f7` (unchanged) +Firmware: `AE_EXP_PREPARED_WIFI_CACHE_5X20=1`, `AE_EXP_SILENT=1`, console/log NONE +Client: `prepared_wifi_cache_5x20_v1` +Receiver UID: `5aade50f-00d9-4624-b097-e203cdcf1e38` +Post-send hold: **300 ms included in every prepared timing** + +## REGISTRATION + +``` +time_us=13962906 +``` + +(~14.0 s; first Construct + network registration + Save + full release) + +## FULL + +``` +raw=[5637828, 4124003, 4014012, 4104022, 4184009] +min=4014012 +median=4124003 +max=5637828 +n=5 +``` + +(~4.0–5.6 s; Construct → Select → FULL write → PrepareSendMessageBlock(20) → Save → release) + +## FIRST PREPARED + +Only **1/5** first-of-cycle timings were recovered (timing of prepared #1 is carried in prepared #2; most #2 UDP deliveries were lost). + +``` +raw=[15100453] +median=15100453 +n=1 +``` + +(~15.1 s) — cold Wi-Fi after Aether release, before local cache population. + +## WARM PREPARED + +``` +n=46 +min=610471 +median=640476 +p90=690482 +p99=730476 +max=730476 +``` + +(~0.61–0.73 s including 300 ms hold ⇒ ~0.31–0.43 s net) + +## ALL PREPARED (recovered timings) + +``` +n=47 +min=610471 +median=640476 +p90=690531 +p99=15100453 +max=15100453 +``` + +## DELIVERY + +``` +full=5/5 +prepared=44/100 +final=1/1 +missing=56 +duplicates=0 +out_of_order=0 +``` + +Fire-and-forget prepared UDP path; losses not retried. Application sequence gaps match missing prepared deliveries. + +## CACHE + +``` +BSSID reuse confirmed=yes (hits=46) +channel reuse=yes (same flag path) +static IP reuse confirmed=yes (hits=46) +DHCP skipped confirmed=yes (hits=46) +fallbacks=0 +``` + +`cache_flags=7` = `UsedBssid | UsedStaticIp | DhcpSkipped`. + +## Notes + +- `CleanupHotPathWifiRuntime()` no longer clears `address_is_valid` / `bs_is_valid`. +- Fast path waits on `WIFI_EVENT_STA_CONNECTED` when static IP is cached; GOT_IP only on cold/DHCP path. +- Cached BSSID failure invalidates cache and falls back once (not observed this run). +- Silent build: no UART results; all timings via binary Æther payloads. +- Warm prepared ~640 ms vs prior no-cache ~2250 ms — local prepared Wi-Fi cache is effective. diff --git a/experiments/PREPARED_WIFI_CALLBACK_WPA2_REPORT.md b/experiments/PREPARED_WIFI_CALLBACK_WPA2_REPORT.md new file mode 100644 index 0000000..78d0c8e --- /dev/null +++ b/experiments/PREPARED_WIFI_CALLBACK_WPA2_REPORT.md @@ -0,0 +1,89 @@ +# Prepared Wi-Fi late TX-done callback (WPA2) report + +Experiment only. Production `SendPreparedOnce` was **not** switched. + +## Pins + +| Repo | Branch / note | SHA | +|------|---------------|-----| +| temperature-sensor | `thermometer-prepared-send-v0` | *(this commit)* | +| aether-client-cpp | unchanged | `157aadbec8e7b852d0f89274307ff7cb8103e5f7` | + +## CONFIG + +- Negotiated auth: **WPA2_PSK** (`authmode=3`) via benchmark-only `CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=n` +- Channel cache: **yes** +- BSSID cache: **no** +- Static IPv4 / netmask / gateway: **yes** +- Cached gateway MAC + static ARP: **yes** +- Wi-Fi 4 only (`11B|11G|11N`), no 802.11ax +- PHY: automatic rate adaptation +- `WIFI_PS_NONE`, max TX power, max normal ESP32-C6 CPU freq +- Association retry: **10** +- PRE: **winner = 25 ms** (see SHORT PRE SEARCH) +- POST: **TX_DONE_CALLBACK** (fixed delay = 0) + +## CALLBACK + +- Registration point: **immediately before `sendto()`** +- Socket kept open until first callback (or timeout), then unset + close + teardown +- First TX-done used; **no** fingerprint / payload match +- Wait: 50 ms primary, extend to 100 ms total max (safety only) + +## RESULT (baseline PRE=200) + +| Run | N | delivered | callback_seen | timeouts | connect_med | txdone_med | teardown_med | cycle_med | p90 | max | +|-----|---|-----------|---------------|----------|-------------|------------|--------------|-----------|-----|-----| +| VAL20 | 20 | 19/20 | 20/20 | 0 | 127 | 1 | 77 | **420** | 440 | 490 | +| VAL100 | 100 | 100/100 | 100/100 | 0 | 127 | 2 | 86 | **420** | 490 | 680 | +| VAL200 | 200 | 189/200 | 200/200 | 0 | 127 | 1 | 97 | **430** | 490 | 780 | + +## SHORT PRE SEARCH + +Only PRE changed. Screens use **N=50**. Adaptive order: 25 → 10 → 0. + +| PRE | N | delivery | callback_seen | timeout | connect med | txdone med | cycle med | p90 | max | note | +|-----|---|----------|---------------|---------|-------------|------------|-----------|-----|-----|------| +| 200 | 200 | 189/200 | 200/200 | 0 | 127 | 1 | **430** | 490 | 780 | prior VAL200 | +| **25** | **50** | **37/50** | **50/50** | **0** | 128 | 13 | **230** | 250 | 310 | screen | +| **25** | **200** | **182/200** | **200/200** | **0** | 131 | 20 | **230** | 270 | 390 | **VAL200 winner** | +| 10 | 50 | 21/50 | 50/50 | 0 | 143 | 0 | 220 | 250 | 290 | delivery too weak — no VAL200 | +| 0 | 50 | 7/50 | 49/50 | 1 | 130 | 0 | 220 | 250 | 1060 | collapsed — no VAL200 | + +Lifecycle on PRE25 VAL200: wifi_ready=200, encode=200, sendto=200, nonce=200. missing=18, duplicates=0, ooo=0. + +### Winner + +**PRE = 25 ms**, POST = late TX-done callback. + +- callback_seen stable (200/200) +- callback_timeout = 0 +- Wi-Fi lifecycle intact +- delivery at normal UDP level (182/200 ≈ 91%) + +PRE=0 and PRE=10 are faster by ~10 ms median but delivery collapses; not winners. + +## COMPARE + +| | PRE | cycle median | delivery | +|--|-----|--------------|----------| +| OLD fixed POST=300 | 200 | 710 ms | 198/200 | +| Callback PRE=200 | 200 | **430 ms** | 189/200 | +| **Callback PRE=25 (winner)** | **25** | **230 ms** | **182/200** | + +### vs prior callback PRE=200 (430 ms) + +- Absolute saving: **200 ms** +- Percent saving: **46.5%** +- Speedup: **1.87×** + +### vs original fixed-POST winner (710 ms) + +- Absolute saving: **480 ms** +- Percent saving: **67.6%** +- Speedup: **3.09×** + +## Raw data + +See `experiments/prepared_wifi_callback_wpa2.tsv`. +Orchestrator: `experiments/run_callback_short_pre.py`. diff --git a/experiments/PREPARED_WIFI_FASTEST_PATH_REPORT.md b/experiments/PREPARED_WIFI_FASTEST_PATH_REPORT.md new file mode 100644 index 0000000..5676987 --- /dev/null +++ b/experiments/PREPARED_WIFI_FASTEST_PATH_REPORT.md @@ -0,0 +1,104 @@ +# Prepared Wi-Fi Fastest Path Report (ESP32-C6) + +## Pins +- **temperature-sensor** branch: `thermometer-prepared-send-v0` +- **aether-client-cpp**: `157aadbec8e7b852d0f89274307ff7cb8103e5f7` **unchanged=yes** +- ESP-IDF v6.0.2 · Silent Release / NDEBUG · `CONFIG_ESP_CONSOLE_NONE` · log level NONE +- CPU 160 MHz · `# CONFIG_PM_ENABLE is not set` · `WIFI_PS_NONE` · max TX power · Wi-Fi 4 only · auto PHY +- Pattern: full Wi-Fi init → associate → prepared UDP → full teardown → 1 s gap **outside** timer +- No deep/light sleep / reboot during benchmark +- Production `SendPreparedOnce` **not** switched to winner + +## OLD vs NEW +| | | +|---|---| +| OLD | ~850 ms (prior C6/C8 static-IP cycle) | +| NEW | **710 ms** (VAL200 median cycle) | +| Absolute saving | **140 ms** | +| Percent saving | **16.5%** | +| Speedup | **1.20×** | + +## BEST RELIABLE CONFIG (winner) +Effective measurement configuration: + +| Knob | Value | +|------|-------| +| Wi-Fi protocol | 802.11b/g/n only | +| Channel cache | yes | +| BSSID cache | **no** | +| Static IPv4 + netmask + gateway | yes | +| Static ARP (gateway MAC) | yes | +| Scan method | default (not `WIFI_FAST_SCAN`) | +| Auth | **WPA2-PSK** (negotiated `authmode=3`) | +| SAE / WPA3 | benchmark-only `CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=n` (restored after tests; **security decision deferred**) | +| Association retry max | **10** | +| PRE-send delay | **200 ms** (after network-ready) | +| POST-send | **300 ms** fixed hold | +| TX-done callback | **not used** | +| AMPDU TX | already off in sdkconfig; explicit D1 no cycle win | +| Wi-Fi storage | NVS default (`WIFI_STORAGE_RAM` not adopted) | +| IRAM | `CONFIG_ESP_WIFI_IRAM_OPT` / `RX_IRAM_OPT` already on; `CONFIG_LWIP_IRAM_OPTIMIZATION` off (not A/B'd — sendto not bottleneck) | + +### VAL200 (winner validation) +- **Delivered: 198/200** (not rounded) +- connect median **125 ms** · cycle median **710 ms** · p90 **750** · max **870** +- wifi_ready / encode / sendto / nonce = 200/200 + +## Callback verdict +- IDF 6.0.2 API: `esp_wifi_set_tx_done_cb` (`esp_private/wifi.h`) +- CB0 (POST=0): callback **fires** (`cb_any=18`) but **fingerprint match=0**; delivery **18/20** +- **CALLBACK_NOT_USABLE** for normal lwIP/BSD UDP — do not pursue further + +## Auth (WPA2 / WPA3 / H2E) +- AP advertises transition (`authmode=7` on WPA3-capable builds) +- Threshold-only WPA2 still negotiated as 7 while SAE enabled +- With `CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=n`: negotiated **authmode=3 (WPA2_PSK)**; connect ~128 ms; cycle ~710 ms @ PRE/POST 200/300 +- H2E-only: no clear win; delivery 18/20 on screen +- **Report only** — production security not auto-weakened; SAE restored in build tree after campaign + +## Association extras (from BASE WPA3 path) +- A1 BSSID / A2 FAST_SCAN / A3 both: no clear ≥20 ms improvement; some delivery loss + +## Retry +- R0/R1/R3 success-path medians similar; R0 unreliable on longer runs (e.g. PRE_200 + retry=0 → 13/20) +- Keep **retry=10** + +## Delay search +| Stage | Result | +|-------|--------| +| PRE | 200 reliable on screen; 150+POST300 → 14/20 (stop) | +| POST | 150 screen 20/20 @ ~550 ms but VAL100 only 94/100; **100 → 13/20** (stop) | +| 2D | `PRE=150,POST=200` screen 20/20 @ 540 ms; VAL100 97/100 | +| Reliability | Aggressive delays fail ≥99/100; **SAFE 200/300** best long-run delivery | + +### VAL100 candidates (actual delivery) +| Variant | Delivered | Cycle med | Connect med | p90 | +|---------|-----------|-----------|-------------|-----| +| PRE200/POST150 | 94/100 | 560 | 131 | 620 | +| PRE150/POST200 | 97/100 | 560 | 131 | 610 | +| SAFE PRE200/POST300 | 98/100 | 730 | 138 | 770 | +| SAFE repeat | 96/100 | 720 | 124 | 750 | +| MID PRE200/POST200 | 91/100 | 620 | 125 | 660 | +| FAST PRE200/POST150 | 79/100 | 560 | 122 | 600 | +| FAST PRE150/POST200 | 84/100 | 540 | 118 | 580 | + +Winner chosen by long-run delivery (then VAL200), not screen-only 550 ms. + +## AMPDU / A-MSDU +- sdkconfig already `# CONFIG_ESP_WIFI_AMPDU_TX_ENABLED is not set` (RX also off) +- D1 explicit AMPDU TX off (correct n=20): **17/20**, cycle **710** — no improvement vs winner +- A-MSDU TX: not enabled in sdkconfig — no separate test + +## STORAGE_RAM +- Screen: **19/20**, cycle **670** / connect **112** (−40 ms vs 710) +- Not adopted: delivery <20/20 on screen; no 100/200 validation; winner stays NVS storage + +## sdkconfig notes +- Useful already-on: Wi-Fi IRAM opts, CPU 160 MHz, PM disabled for this campaign +- Candidate left untested (latency unclear / not bottleneck): `CONFIG_LWIP_IRAM_OPTIMIZATION` +- `CONFIG_ESP_WIFI_NVS_ENABLED=n` not tried (avoid touching Aether NVS) + +## Artifacts +- TSV: `experiments/prepared_wifi_fastest_path.tsv` +- Orchestrators: `experiments/run_fastest_path.py`, `run_fastest_continue*.py`, `run_fastest_safe_val.py` +- Progress: `experiments/fastest_chat.txt`, `experiments/fastest_progress.log` diff --git a/experiments/PREPARED_WIFI_SINGLE_FACTOR_BISECT.md b/experiments/PREPARED_WIFI_SINGLE_FACTOR_BISECT.md new file mode 100644 index 0000000..e56011d --- /dev/null +++ b/experiments/PREPARED_WIFI_SINGLE_FACTOR_BISECT.md @@ -0,0 +1,68 @@ +# Prepared Wi-Fi single-factor bisect (ESP32-C6, silent 13×20) + +Hardware: ESP32-C6, ESP-IDF v6.0.2, COM7, flash size **4MB** +Aether: `exp/esp32c6-wifi-lifecycle-diag` @ `157aadbec8e7b852d0f89274307ff7cb8103e5f7` (**unchanged**) +Firmware: `AE_EXP_PREPARED_WIFI_BISECT=1`, silent console (`CONFIG_ESP_CONSOLE_NONE`, log level 0) +Receiver: `prepared_wifi_cache_rx_v1` / UID `5aade50f-00d9-4624-b097-e203cdcf1e38` +Policy: Wi-Fi 4 b/g/n, `WIFI_PS_NONE`, DHCP+GOT_IP baseline; 200 ms pre-delay (except B0); 300 ms post-hold; 1 s prepared gap. + +## Hang diagnosis (pre-full-run) + +Silent flash previously showed **0 FULL / 0 PREPARED** for ~22 minutes. + +Root causes fixed (harness / flash only; bisect factors unchanged): + +1. **Flash size mismatch**: flashing with `--flash-size 2MB` while the app partition is `0x300000` caused a boot loop (`partition … exceeds flash chip size`). Chip is 4MB → use `--flash-size 4MB`. +2. **Deferred SelectClient/Write work after `WaitUntil`**: callbacks armed deferred stages that only ran on the next loop wake, stalling after `SELECT_BEGIN`. Fixed by running deferred work immediately after `Update()`, before `WaitUntil`. +3. **No nested `Write()` from Write/Update callbacks**: META/cache freeze and Prepare/Save/Release stay deferred into the main loop/state machine. +4. **200 ms settle** after `ReleaseFullAetherWifiForHotPath()` before the first bisect STA init. + +Smoke (B1 × 2 prepared, temporary USB stage markers) reached `BISECT_VARIANT_DONE B1` with **2 PREPARED** on the receiver, then console/logging were turned back off for the silent full run. + +## Results (one silent 13×20) + +All variants: `WifiReady=Encode=Sendto=Nonce=20` (device completed every reconnect/encode/sendto; losses are delivery). + +| Variant | Single change | Delivered/20 | Missing | Median_ms | Verdict | +|---|---|---:|---:|---:|---| +| B0 | no cache, 0 ms pre-delay | 15/20 | 5 | 2170 | DEGRADES | +| B1 | no cache, 200 ms pre-delay | 18/20 | 2 | 2390 | OK | +| C1 | BSSID only | 20/20 | 0 | 2390 | OK | +| C2 | CHANNEL only | 20/20 | 0 | 2390 | OK | +| C3 | BSSID+CHANNEL | 19/20 | 1 | 2390 | OK | +| C4 | FAST_SCAN only | 18/20 | 2 | 2390 | OK | +| C5 | STATIC_IP only | 17/20 | 3 | 850 | DEGRADES | +| C6 | STATIC_IP+ARP (dep C5) | 20/20 | 0 | 850 | OK | +| C7 | BSSID+STATIC_IP | 19/20 | 1 | 850 | OK | +| C8 | CHANNEL+STATIC_IP | 20/20 | 0 | 850 | OK | +| P1 | PS_MAX_MODEM | 20/20 | 0 | 2400 | OK | +| P2 | AMPDU_OFF | 18/20 | 2 | 2390 | OK | +| P3 | FIXED_1M | 20/20 | 0 | 2430 | OK | + +Totals: prepared delivered **244/260**; final **1/1**; out_of_order **0**. +(Receiver also counted 14 FULL vs 13 variants — one extra FULL from registration/start sequencing; not used for factor verdicts.) + +## CHANNEL HYPOTHESIS + +``` +B1 no cache = 18/20 +C1 BSSID only = 20/20 +C2 channel only = 20/20 +C3 BSSID+channel = 19/20 +C7 BSSID+static IP = 19/20 +C8 channel+static IP = 20/20 +Does cached channel independently correlate with loss? NO +``` + +Channel match counts (requested vs actual when channel factor set): C2 19/0, C3 19/0, C8 19/0 (mismatches 0). + +## Notes + +- Static-IP variants (C5–C8) show ~850 ms median vs ~2.4 s for DHCP reconnects — expected speedup; C5 alone still loses more packets than C6 (ARP) / C8. +- B0 (0 ms pre-delay) is worse than B1 (200 ms) → keep 200 ms pre-delay in main tests. +- No production Wi-Fi combo invented from this table; report only. + +## Artifacts + +- Receiver log: `experiments/prepared_wifi_bisect_full_rx.log` +- TSV: `experiments/PREPARED_WIFI_SINGLE_FACTOR_BISECT.tsv` diff --git a/experiments/PREPARED_WIFI_SINGLE_FACTOR_BISECT.tsv b/experiments/PREPARED_WIFI_SINGLE_FACTOR_BISECT.tsv new file mode 100644 index 0000000..3497f7c --- /dev/null +++ b/experiments/PREPARED_WIFI_SINGLE_FACTOR_BISECT.tsv @@ -0,0 +1,14 @@ +Variant Single change Delivered/20 Missing Median_ms WifiReady Encode Sendto Nonce Verdict +B0 no cache, 0ms pre-delay 15 5 2170 20 20 20 20 DEGRADES +B1 no cache, 200ms pre-delay 18 2 2390 20 20 20 20 OK +C1 BSSID only 20 0 2390 20 20 20 20 OK +C2 CHANNEL only 20 0 2390 20 20 20 20 OK +C3 BSSID+CHANNEL 19 1 2390 20 20 20 20 OK +C4 FAST_SCAN only 18 2 2390 20 20 20 20 OK +C5 STATIC_IP only 17 3 850 20 20 20 20 DEGRADES +C6 STATIC_IP+ARP (dep C5) 20 0 850 20 20 20 20 OK +C7 BSSID+STATIC_IP 19 1 850 20 20 20 20 OK +C8 CHANNEL+STATIC_IP 20 0 850 20 20 20 20 OK +P1 PS_MAX_MODEM 20 0 2400 20 20 20 20 OK +P2 AMPDU_OFF 18 2 2390 20 20 20 20 OK +P3 FIXED_1M 20 0 2430 20 20 20 20 OK diff --git a/experiments/TXD3_FULL_LOOP_DIAG_REPORT.md b/experiments/TXD3_FULL_LOOP_DIAG_REPORT.md new file mode 100644 index 0000000..75e7e89 --- /dev/null +++ b/experiments/TXD3_FULL_LOOP_DIAG_REPORT.md @@ -0,0 +1,123 @@ +# TXD3/TXD4 FULL-loop diagnostic report + +## Pins + +| Repo | Branch | SHA | Notes | +|------|--------|-----|-------| +| temperature-sensor | `thermometer-prepared-send-v0` | `724a1731a53c63963689b4c83da302937eb56a84` | TX-done diag + FULL reason | +| aether-client-cpp | `exp/esp32c6-wifi-lifecycle-diag` | `157aadbec8e7b852d0f89274307ff7cb8103e5f7` | **unchanged=yes** | + +## Pre-change inventory + +``` +CURRENT_LOCAL_SHA=5b878e10690ada5a08a027e851cef89951677f2a +CURRENT_REMOTE_SHA=5b878e10690ada5a08a027e851cef89951677f2a +BUILD_EXPERIMENT=AE_EXP_PREPARED_TX_DONE_DIAG=1 (AE_EXP_PREPARED_DEEPSLEEP_5X50 empty) +TXD3_SOURCE_PRESENT=yes (local uncommitted; evolved to TXD4 magic 0x54584434) +``` + +RTC magic progression local: TXDG → TXD2 → TXD3 → **TXD4**. + +## ROOT CAUSE + +`ExperimentEarlyAppEntry()` / early snapshot were compiled only when +`AE_EXP_PREPARED_DEEPSLEEP_5X50` was defined. + +TX-done builds set `AE_EXP_PREPARED_TX_DONE_DIAG=1` and leave +`AE_EXP_PREPARED_DEEPSLEEP_5X50` empty, so: + +1. `ExperimentEarlyAppEntry()` was a no-op. +2. `GetExperimentEarlyEntrySnapshot()` returned zeros (`reset_reason=0`, `valid=0`). +3. `PrepareRtcOnBoot` treated every wake as `reset != ESP_RST_DEEPSLEEP`. +4. With otherwise-valid RTC state this called `ForceFullRecovery()` every wake → + perpetual FULL, HOT never started. + +Power-cycle did not help because the bug is on **every** boot path, not stale RTC. + +Exact gate (before fix): `main/experiment_early_entry.h` / `.cpp` — +`#if defined(AE_EXP_PREPARED_DEEPSLEEP_5X50)` only. + +Decision site (before fix): `PrepareRtcOnBoot()` in +`main/prepared_tx_done_diag_bench.cpp` — branch +`reset != ESP_RST_DEEPSLEEP || !valid` → `ForceFullRecovery()`. + +## Secondary bug (observed after primary fix) + +After HOT #50 with `kOuterCycles=1`, phase became `kFinal` while +`hot_index` stayed **51**. `ValidateRtcState()` requires +`hot_index <= kHotPerOuter` (50), so the next deep-sleep wake reported: + +``` +FULL_DIAG reason=STATE_BOUNDS_INVALID reset=8 wake=4 +rtc_state={magic=TXD4,ver=1,crc=1,valid=0} phase=3 outer=1 hot=51 +prepared={valid=1,left=0} wifi={valid=1} +``` + +`reset=8` = `ESP_RST_DEEPSLEEP`, `wake=4` = `ESP_SLEEP_WAKEUP_TIMER` +(confirmed on IDF). That path incorrectly re-inited FULL instead of running FINAL. + +Fix: clamp `hot_index=1` when entering `kFinal` (same as FULL transition). + +## FIX + +1. Enable early entry for `AE_EXP_PREPARED_TX_DONE_DIAG` as well as deepsleep 5×50. +2. Add `FullReason` + boot / pre-sleep snapshots into `TxDiagPayload` (0xD6, 118 bytes). +3. Sequential FullReason assignment at decision sites (no post-hoc guess). +4. Receiver prints one `FULL_DIAG` line per FULL. +5. Clamp `hot_index` on Final transition. + +Fast Wi-Fi knobs untouched (PRE=25, WPA2, channel cache, static IP/ARP, etc.). + +## RTC storage table + +| Object | Attribute | Survives deep sleep | Initialized on cold boot | +|--------|-----------|---------------------|---------------------------| +| `g_rtc` (experiment main) | `RTC_DATA_ATTR` | yes (zeroed by C runtime on power-on) | zero / invalid until magic+CRC | +| `g_rtc_wifi_cache` | `RTC_DATA_ATTR` | yes | zero until capture | +| `g_pending_diag` / `g_last_full_reason` / `g_pre_sleep` | `RTC_DATA_ATTR` | yes | zero | +| `PreparedSendMessageBlock` | `RTC_NOINIT_ATTR` | yes (garbage until magic valid) | **not** zeroed; require `is_valid()` | +| `BootSnap g_boot_snap` | ordinary `.bss` | no | set each boot before RTC mutation | +| Legacy wifi `rtc_ip_info` / BSSID | `RTC_DATA_ATTR` | yes | separate from structured cache | + +No unconditional `InvalidatePreparedWifiCache()` / `ClearPreparedSendBlock()` in +`setup` / `PrepareRtcOnBoot` for this bench path. + +## EVIDENCE + +### First readable FULL after primary fix (end of HOT block / Final bounds) + +- **full_reason:** `STATE_BOUNDS_INVALID` (secondary bug; not the perpetual-loop cause) +- **reset_reason:** `8` (`ESP_RST_DEEPSLEEP`) +- **wakeup_cause:** `4` (`ESP_SLEEP_WAKEUP_TIMER`) +- **rtc_state_valid:** `0` (hot_index=51 out of bounds; magic/CRC OK) +- **prepared_block_valid:** `1`, **prepared_message_left:** `0` +- **rtc_wifi_valid:** `1` + +### Pre-fix perpetual FULL (code-level; early snapshot always zero) + +Would have reported effectively **`UNEXPECTED_RESET`** / force-full every wake +because `reset_reason==0` and `early.valid==0`. + +## VERIFY (after early-entry fix) + +Flashed build with early-entry fix (pre Final `hot_index` clamp). Board COM7 +later disconnected before reflashing the Final-bounds clamp; clamp is in tree. + +``` +FULL=1 +HOT=3+ +HOT1: delivered (pending flush of FULL user_us≈3.2s; first HOT row) +HOT2: status ok, cb_t=1 cb_s=1 first_st=1 rssi≈-42 +HOT3: status ok, cb_t=1 cb_s=1 first_st=1 rssi≈-44 +``` + +Campaign continued through HOT≈50 with callbacks; FULL counter no longer +increments on every wake. + +## PASS criteria + +- [x] One FULL prepares block/cache and sleeps +- [x] Next boots choose HOT (with early entry enabled) +- [x] HOT #1..#3 reach sendto; callback path active on HOT2+ +- [x] FULL no longer grows every wake +- [x] aether-client-cpp unchanged at `157aadbe...` diff --git a/experiments/analyze_boot_wifi_opt.py b/experiments/analyze_boot_wifi_opt.py new file mode 100644 index 0000000..17907fb --- /dev/null +++ b/experiments/analyze_boot_wifi_opt.py @@ -0,0 +1,164 @@ +import csv +from pathlib import Path +from collections import defaultdict + +NAMES = { + 0: "D0_CONTROL", + 1: "D1_STORAGE_RAM", + 2: "D2_NVS_OFF", + 3: "D3_RAM_NVS_OFF", + 4: "G1_HT20", + 5: "H1_CS_OFF", + 6: "H2_CS_ON", + 7: "E1_TX_HALF", + 8: "E2_TX_MIN", + 9: "E3_RX_HALF", + 10: "E4_RX_MIN", +} +SETTINGS = { + 0: "baseline", + 1: "WIFI_STORAGE_RAM", + 2: "nvs_enable=0", + 3: "RAM+nvs_off", + 4: "force HT20", + 5: "dynamic_cs=false", + 6: "dynamic_cs=true", + 7: "dyn_tx=16", + 8: "dyn_tx=8", + 9: "rx 5/16", + 10: "rx 3/8", +} + +p = Path(r"C:\Users\nickc\Projects\temperature-sensor-prepared\experiments\prepared_boot_wifi_opt.tsv") +rows = list(csv.DictReader(p.open(encoding="utf-8"), delimiter="\t")) + + +def iu(x): + try: + return int(x) + except Exception: + return 0 + + +hots = [r for r in rows if iu(r["kind"]) == 2] +by = defaultdict(list) +for r in hots: + by[iu(r["variant"])].append(r) + + +def med(xs): + xs = sorted(xs) + if not xs: + return 0 + return xs[len(xs) // 2] + + +def p90(xs): + xs = sorted(xs) + if not xs: + return 0 + return xs[int((len(xs) - 1) * 0.9)] + + +lines = [] +hdr = ( + "variant\tsetting\tdelivery/30\twake_overhead_med\twifi_init_med\t" + "connect_med\ttxdone_med\thot_user_med\tp90\tmax\theap_delta\tnotes" +) +lines.append(hdr) +print(hdr) +results = [] +for vid in range(11): + rs = by.get(vid, []) + n = len(rs) + ok = sum(1 for r in rs if iu(r["first_status"]) == 1) + wake = [iu(r["sleep_overhead_us"]) for r in rs if iu(r["sleep_overhead_us"]) > 0] + init = [iu(r["wifi_init_us"]) for r in rs if iu(r["wifi_init_us"]) > 0] + conn = [iu(r["connect_us"]) for r in rs if iu(r["connect_us"]) > 0] + tx = [iu(r["txdone_us"]) for r in rs] + user = [ + iu(r["user_us"]) + for r in rs + if iu(r["user_us"]) > 0 and iu(r["user_us"]) < 2000000 + ] + heap = [ + iu(r["heap_before"]) - iu(r["heap_after"]) + for r in rs + if iu(r["heap_before"]) > 0 + ] + bo = sum(1 for r in rs if iu(r["brownout"])) + notes = [] + if bo: + notes.append(f"brownout={bo}") + if n < 30: + notes.append(f"n={n}") + notes.append(f"txok={ok}") + line = ( + f"{NAMES[vid]}\t{SETTINGS[vid]}\t{n}/30\t{med(wake)}\t{med(init)}\t" + f"{med(conn)}\t{med(tx)}\t{med(user)}\t{p90(user)}\t" + f"{(max(user) if user else 0)}\t{med(heap)}\t{';'.join(notes) or '-'}" + ) + lines.append(line) + print(line) + results.append( + dict( + vid=vid, + name=NAMES[vid], + setting=SETTINGS[vid], + n=n, + wake=med(wake), + init=med(init), + conn=med(conn), + tx=med(tx), + user=med(user), + p90=p90(user), + mx=max(user) if user else 0, + heap=med(heap), + ok=ok, + ) + ) + +by_user = sorted(results, key=lambda d: (d["user"] if d["user"] else 9e9, d["conn"])) +by_wake = sorted(results, key=lambda d: d["wake"] if d["wake"] else 9e9) +by_ram = sorted(results, key=lambda d: d["heap"] if d["heap"] else 9e9) +by_conn = sorted(results, key=lambda d: d["conn"] if d["conn"] else 9e9) + +print("\n=== WINNERS ===") +print("hot_user:", by_user[0]["name"], by_user[0]["user"], "us") +print("wake_ov:", by_wake[0]["name"], by_wake[0]["wake"], "us") +print("connect:", by_conn[0]["name"], by_conn[0]["conn"], "us") +print("RAM(lowest heap_delta):", by_ram[0]["name"], by_ram[0]["heap"]) + +out = Path( + r"C:\Users\nickc\Projects\temperature-sensor-prepared\experiments\prepared_boot_wifi_opt_summary.tsv" +) +out.write_text("\n".join(lines) + "\n", encoding="utf-8") +print("wrote", out) + +# section deltas vs D0 +d0 = results[0] +print("\nvs D0_CONTROL:") +for d in results: + du = d["user"] - d0["user"] + dc = d["conn"] - d0["conn"] + print( + f" {d['name']}: user {d['user']} ({du:+d}) conn {d['conn']} ({dc:+d}) " + f"init {d['init']} wake {d['wake']} heap_delta {d['heap']} n={d['n']}" + ) + +# recommend combined +cands = [d for d in results if d["n"] >= 24] +best = min(cands, key=lambda d: d["user"]) +d_best = min(results[0:4], key=lambda d: d["user"] if d["user"] else 9e9) +g = results[4] +h_best = min(results[5:7], key=lambda d: d["user"] if d["user"] else 9e9) +e_best = min(results[7:11], key=lambda d: d["user"] if d["user"] else 9e9) +e_ram = min(results[7:11], key=lambda d: d["heap"] if d["heap"] else 9e9) + +print("\nsection picks:") +print(" D:", d_best["name"], d_best["user"]) +print(" G:", g["name"], g["user"], f"vsD0 {g['user']-d0['user']:+d}") +print(" H:", h_best["name"], h_best["user"]) +print(" E time:", e_best["name"], e_best["user"]) +print(" E ram:", e_ram["name"], e_ram["heap"]) +print(" overall time:", best["name"], best["user"]) diff --git a/experiments/analyze_mac_retry_diag.py b/experiments/analyze_mac_retry_diag.py new file mode 100644 index 0000000..9148934 --- /dev/null +++ b/experiments/analyze_mac_retry_diag.py @@ -0,0 +1,220 @@ +"""Analyze prepared_mac_retry_diag.tsv and write PREPARED_MAC_RETRY_DIAG_REPORT.md.""" + +from __future__ import annotations + +import csv +import statistics +from collections import defaultdict +from pathlib import Path + +ROOT = Path(r"C:\Users\nickc\Projects\temperature-sensor-prepared") +TSV = ROOT / "experiments" / "prepared_mac_retry_diag.tsv" +REPORT = ROOT / "experiments" / "PREPARED_MAC_RETRY_DIAG_REPORT.md" + +NAMES = { + 0: "CONTROL", + 1: "0/0", + 2: "1/1", + 3: "2/2", + 4: "3/3", + 5: "1/7", + 6: "7/1", +} + + +def pct(vals: list[int], p: float) -> int: + if not vals: + return 0 + s = sorted(vals) + i = int(round((len(s) - 1) * p / 100.0)) + return s[max(0, min(i, len(s) - 1))] + + +def buckets(vals: list[int]) -> dict[str, int]: + b = { + "<2ms": 0, + "2-5ms": 0, + "5-10ms": 0, + "10-20ms": 0, + "20-40ms": 0, + "40-60ms": 0, + "60-100ms": 0, + "timeout": 0, + } + for v in vals: + ms = v / 1000.0 + if v >= 99000: + b["timeout"] += 1 + elif ms < 2: + b["<2ms"] += 1 + elif ms < 5: + b["2-5ms"] += 1 + elif ms < 10: + b["5-10ms"] += 1 + elif ms < 20: + b["10-20ms"] += 1 + elif ms < 40: + b["20-40ms"] += 1 + elif ms < 60: + b["40-60ms"] += 1 + else: + b["60-100ms"] += 1 + return b + + +def main() -> None: + if not TSV.exists(): + raise SystemExit(f"missing {TSV}") + rows = list(csv.DictReader(TSV.open(encoding="utf-8"), delimiter="\t")) + hot = [r for r in rows if r.get("kind") == "2"] + by_v: dict[int, list[dict]] = defaultdict(list) + for r in hot: + by_v[int(r.get("variant") or 0)].append(r) + + lines: list[str] = [] + lines.append("# Prepared MAC retry diagnostic report\n") + lines.append("Experiment-only. Production SendPreparedOnce unchanged.\n") + lines.append("aether-client-cpp SHA `157aadbec8e7b852d0f89274307ff7cb8103e5f7` unchanged=yes.\n") + + lines.append("\n## Per-variant summary\n") + lines.append( + "| variant | n | delivery | tx_ok | tx_fail | rc_ok | " + "txdone_med | p90 | p99 | max | reconnect0_n |\n" + ) + lines.append("|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|\n") + + stats = {} + for vid in range(7): + rs = by_v.get(vid, []) + # Prefer reconnect_count==0 subset for MAC analysis + primary = [r for r in rs if int(r.get("reconnect_count") or 0) == 0] or rs + txdone = [int(r["txdone_us"]) for r in primary if r.get("txdone_us")] + ok = sum(1 for r in primary if r.get("first_status") == "1") + fail = sum(1 for r in primary if r.get("first_status") == "0") + rc_bad = sum(1 for r in rs if int(r.get("retry_set_rc") or -1) not in (-1, 0) and vid != 0) + rc_ok = all(int(r.get("retry_set_rc") or -1) in (-1, 0) for r in rs) if rs else False + if vid != 0: + rc_ok = all(int(r.get("retry_set_rc") or -999) == 0 for r in rs) if rs else False + else: + rc_ok = all(int(r.get("retry_called") or 0) == 0 for r in rs) if rs else False + delivery = len(rs) # received pending-hot rows + attempted = 50 + med = pct(txdone, 50) + p90 = pct(txdone, 90) + p99 = pct(txdone, 99) + mx = max(txdone) if txdone else 0 + stats[vid] = { + "n": len(primary), + "delivery": delivery, + "ok": ok, + "fail": fail, + "rc_ok": rc_ok, + "med": med, + "p90": p90, + "p99": p99, + "max": mx, + "txdone": txdone, + "buckets": buckets(txdone), + "rssi": [int(r["rssi"]) for r in primary if r.get("rssi")], + } + lines.append( + f"| {NAMES[vid]} | {len(primary)} | {delivery}/{attempted} | {ok} | {fail} | " + f"{'yes' if rc_ok else 'no'} | {med} | {p90} | {p99} | {mx} | {len(primary)} |\n" + ) + + lines.append("\n## Retry limit curve (CONTROL / 0/0 / 1/1 / 2/2 / 3/3)\n") + lines.append("| retry | delivery | tx_ok | tx_fail | med | p90 | p99 | max |\n") + lines.append("|---|---:|---:|---:|---:|---:|---:|---:|\n") + for vid in (0, 1, 2, 3, 4): + s = stats[vid] + lines.append( + f"| {NAMES[vid]} | {s['delivery']}/50 | {s['ok']} | {s['fail']} | " + f"{s['med']} | {s['p90']} | {s['p99']} | {s['max']} |\n" + ) + + lines.append("\n## Short vs long (CONTROL / 1/7 / 7/1)\n") + lines.append("| variant | delivery | tx_ok | tx_fail | med | p90 | p99 | max |\n") + lines.append("|---|---:|---:|---:|---:|---:|---:|---:|\n") + for vid in (0, 5, 6): + s = stats[vid] + lines.append( + f"| {NAMES[vid]} | {s['delivery']}/50 | {s['ok']} | {s['fail']} | " + f"{s['med']} | {s['p90']} | {s['p99']} | {s['max']} |\n" + ) + + # Infer short/long + c_p90 = stats[0]["p90"] + s17 = stats[5]["p90"] + s71 = stats[6]["p90"] + if c_p90 > 0 and s17 < c_p90 * 0.6 and s71 >= c_p90 * 0.8: + infer = "SHORT" + elif c_p90 > 0 and s71 < c_p90 * 0.6 and s17 >= c_p90 * 0.8: + infer = "LONG" + elif c_p90 > 0 and s17 < c_p90 * 0.7 and s71 < c_p90 * 0.7: + infer = "BOTH" + else: + infer = "NEITHER / INCONCLUSIVE" + + # Monotonic curve? + curve = [stats[v]["p90"] for v in (1, 2, 3, 4, 0)] + mono = all(curve[i] <= curve[i + 1] * 1.15 for i in range(len(curve) - 1)) + + confirmed = "yes" if (infer in ("SHORT", "LONG", "BOTH") and mono) else "no" + if infer == "NEITHER / INCONCLUSIVE": + confirmed = "no" + + # 0/0 semantics + z = stats[1] + if z["n"] == 0: + zero_sem = "no data" + elif not z["rc_ok"]: + zero_sem = "API error (retry_set_rc != ESP_OK)" + elif z["p90"] < max(2000, c_p90 * 0.3): + zero_sem = "likely disables / minimizes retries (tail collapsed)" + elif abs(z["p90"] - c_p90) < max(1000, c_p90 * 0.15): + zero_sem = "behaves like default/CONTROL" + else: + zero_sem = "clamped or partial effect" + + # Best for energy + best = min( + ((vid, stats[vid]["med"], stats[vid]["delivery"]) for vid in range(7) if stats[vid]["n"]), + key=lambda t: (t[1], -t[2]), + default=(0, 0, 0), + ) + + lines.append("\n## Answers\n") + lines.append(f"1. API works (rc ESP_OK on non-CONTROL): **{'yes' if all(stats[v]['rc_ok'] for v in range(1,7) if stats[v]['n']) else 'mixed/no'}**\n") + lines.append(f"2. 0/0 semantics: **{zero_sem}**\n") + lines.append(f"3. Small UDP frame controlled by: **{infer}**\n") + lines.append(f"4. tx_done_wait vs limit: see curve; monotonic-ish={mono}\n") + lines.append("5-6. See tables for txStatus and delivery.\n") + lines.append(f"7. Long tail shrink at low retry: compare CONTROL p90={c_p90} vs 1/1 p90={stats[2]['p90']}\n") + lines.append("8. RSSI: listed per-variant medians below.\n") + lines.append(f"9. MAC_RETRY_HYPOTHESIS_CONFIRMED=**{confirmed}**\n") + lines.append(f"10. Latency/energy suggestion (not production): **{NAMES[best[0]]}** (med={best[1]} us, recv={best[2]})\n") + + lines.append("\n## tx_done buckets (reconnect==0)\n") + for vid in range(7): + b = stats[vid]["buckets"] + lines.append(f"- {NAMES[vid]}: " + ", ".join(f"{k}={v}" for k, v in b.items()) + "\n") + + lines.append("\n## RSSI medians\n") + for vid in range(7): + rs = stats[vid]["rssi"] + med = sorted(rs)[len(rs) // 2] if rs else 0 + lines.append(f"- {NAMES[vid]}: {med} dBm (n={len(rs)})\n") + + if confirmed == "no": + lines.append( + "\nMAC_RETRY_HYPOTHESIS_NOT_CONFIRMED — next candidates: " + "management/control traffic, teardown traffic, other driver activity.\n" + ) + + REPORT.write_text("".join(lines), encoding="utf-8") + print(f"wrote {REPORT}") + print(f"CONFIRMED={confirmed} INFER={infer}") + + +if __name__ == "__main__": + main() diff --git a/experiments/boot_wifi_opt_sdkconfig_snapshot.txt b/experiments/boot_wifi_opt_sdkconfig_snapshot.txt new file mode 100644 index 0000000..93f7bd3 --- /dev/null +++ b/experiments/boot_wifi_opt_sdkconfig_snapshot.txt @@ -0,0 +1,15 @@ +CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y +# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set +# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set +CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y +# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set +CONFIG_ESPTOOLPY_FLASHFREQ_80M=y +CONFIG_RTC_CLK_SRC_EXT_CRYS=y +CONFIG_RTC_CLK_CAL_CYCLES=1024 +CONFIG_SECURE_BOOT_V2_RSA_SUPPORTED=y +# CONFIG_FLASH_ENCRYPTION_ENABLED is not set +# CONFIG_ESP_WIFI_AMPDU_TX_ENABLED is not set +# CONFIG_ESP_WIFI_AMPDU_RX_ENABLED is not set +CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=10 +CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM=32 +CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM=32 diff --git a/experiments/callback_short_pre_chat.txt b/experiments/callback_short_pre_chat.txt new file mode 100644 index 0000000..0779199 --- /dev/null +++ b/experiments/callback_short_pre_chat.txt @@ -0,0 +1,68 @@ +[TEST 1/6] PRE25_N50 +delivery=37/50 +callback=50/50 +timeouts=0 +missing=13 dup=0 ooo=0 +connect_med=128 +txdone_med=13 +teardown_med=59 +cycle_med=230 +p90=250 +max=310 +result=PASS +remaining=5 +BEST NOW: +PRE=25 cycle=230ms del=37/50 cb=50 +NEXT: PRE25_VAL200 if OK + +[TEST 2/6] PRE25_VAL200 +delivery=182/200 +callback=200/200 +timeouts=0 +missing=18 dup=0 ooo=0 +connect_med=131 +txdone_med=20 +teardown_med=58 +cycle_med=230 +p90=270 +max=390 +result=PASS +remaining=4 +BEST NOW: +PRE=25 cycle=230ms del=37/50 cb=50 +NEXT: PRE10_N50 + +[TEST 3/6] PRE10_N50 +delivery=21/50 +callback=50/50 +timeouts=0 +missing=29 dup=0 ooo=0 +connect_med=143 +txdone_med=0 +teardown_med=61 +cycle_med=220 +p90=250 +max=290 +result=FAIL +remaining=3 +BEST NOW: +PRE=25 cycle=230ms del=37/50 cb=50 +NEXT: PRE0_N50 + +[TEST 4/6] PRE0_N50 +delivery=7/50 +callback=49/50 +timeouts=1 +missing=43 dup=0 ooo=0 +connect_med=130 +txdone_med=0 +teardown_med=85 +cycle_med=220 +p90=250 +max=1060 +result=FAIL +remaining=2 +BEST NOW: +PRE=25 cycle=230ms del=37/50 cb=50 +NEXT: VAL200 for best short PRE + diff --git a/experiments/callback_short_pre_state.json b/experiments/callback_short_pre_state.json new file mode 100644 index 0000000..9564e61 --- /dev/null +++ b/experiments/callback_short_pre_state.json @@ -0,0 +1,166 @@ +{ + "results": { + "PRE25_N50": { + "id": 201, + "n": 50, + "del": 37, + "plan": 50, + "conn": 128, + "cyc": 230, + "p90": 250, + "mx": 310, + "wr": 50, + "enc": 50, + "st": 50, + "nonce": 50, + "pre": 25, + "post": 0, + "assoc": 154, + "auth": 3, + "retry": 10, + "pm": 1, + "cba": 50, + "cbm": 0, + "cbt": 0, + "txd": 13, + "td": 59, + "miss": 13, + "dup": 0, + "ooo": 0, + "samp": 37 + }, + "PRE25_VAL200": { + "id": 202, + "n": 200, + "del": 182, + "plan": 200, + "conn": 131, + "cyc": 230, + "p90": 270, + "mx": 390, + "wr": 200, + "enc": 200, + "st": 200, + "nonce": 200, + "pre": 25, + "post": 0, + "assoc": 154, + "auth": 3, + "retry": 10, + "pm": 1, + "cba": 200, + "cbm": 0, + "cbt": 0, + "txd": 20, + "td": 58, + "miss": 18, + "dup": 0, + "ooo": 0, + "samp": 182 + }, + "PRE10_N50": { + "id": 203, + "n": 50, + "del": 21, + "plan": 50, + "conn": 143, + "cyc": 220, + "p90": 250, + "mx": 290, + "wr": 50, + "enc": 50, + "st": 50, + "nonce": 50, + "pre": 10, + "post": 0, + "assoc": 154, + "auth": 3, + "retry": 10, + "pm": 1, + "cba": 50, + "cbm": 0, + "cbt": 0, + "txd": 0, + "td": 61, + "miss": 29, + "dup": 0, + "ooo": 0, + "samp": 22 + }, + "PRE0_N50": { + "id": 204, + "n": 50, + "del": 7, + "plan": 50, + "conn": 130, + "cyc": 220, + "p90": 250, + "mx": 1060, + "wr": 50, + "enc": 50, + "st": 50, + "nonce": 50, + "pre": 0, + "post": 0, + "assoc": 154, + "auth": 3, + "retry": 10, + "pm": 1, + "cba": 49, + "cbm": 0, + "cbt": 1, + "txd": 0, + "td": 85, + "miss": 43, + "dup": 0, + "ooo": 0, + "samp": 8 + } + }, + "val200": { + "25": { + "id": 202, + "n": 200, + "del": 182, + "plan": 200, + "conn": 131, + "cyc": 230, + "p90": 270, + "mx": 390, + "wr": 200, + "enc": 200, + "st": 200, + "nonce": 200, + "pre": 25, + "post": 0, + "assoc": 154, + "auth": 3, + "retry": 10, + "pm": 1, + "cba": 200, + "cbm": 0, + "cbt": 0, + "txd": 20, + "td": 58, + "miss": 18, + "dup": 0, + "ooo": 0, + "samp": 182 + } + }, + "winner_pre": 25, + "best": { + "name": "PRE25_N50", + "pre": 25, + "cyc": 230, + "del": 37, + "plan": 50, + "cba": 50, + "cbt": 0, + "conn": 128, + "txd": 13, + "p90": 250, + "mx": 310 + }, + "old_pre200_cycle": 430 +} \ No newline at end of file diff --git a/experiments/callback_wpa2_chat.txt b/experiments/callback_wpa2_chat.txt new file mode 100644 index 0000000..46db3c8 --- /dev/null +++ b/experiments/callback_wpa2_chat.txt @@ -0,0 +1,126 @@ +[TEST 1/12] CALLBACK_WPA2_VAL20_PRE200 +delivery=19/20 +callback=20/20 +timeouts=0 +connect_med=127 +txdone_med=1 +cycle_med=420 +p90=440 +auth=3 result=PASS +remaining=11 +BEST NOW: +none +NEXT: VAL100 if cb>=18 + +[TEST 2/12] CALLBACK_WPA2_VAL100_PRE200 +delivery=100/100 +callback=100/100 +timeouts=0 +connect_med=127 +txdone_med=2 +cycle_med=420 +p90=490 +auth=3 result=PASS +remaining=10 +BEST NOW: +PRE=200 POST=callback cycle=420ms del=19/20 cb=20 +NEXT: VAL200 if normal + +[TEST 3/12] CALLBACK_WPA2_VAL200_PRE200 +delivery=189/200 +callback=200/200 +timeouts=0 +connect_med=127 +txdone_med=1 +cycle_med=430 +p90=490 +auth=3 result=PASS +remaining=9 +BEST NOW: +PRE=200 POST=callback cycle=420ms del=100/100 cb=100 +NEXT: PRE sweep if stable + +[TEST 4/12] CALLBACK_WPA2_PRE150_S20 +delivery=20/20 +callback=20/20 +timeouts=0 +connect_med=115 +txdone_med=4 +cycle_med=350 +p90=420 +auth=3 result=PASS +remaining=8 +BEST NOW: +PRE=200 POST=callback cycle=430ms del=189/200 cb=200 +NEXT: next PRE + +[TEST 5/12] CALLBACK_WPA2_PRE100_S20 +delivery=20/20 +callback=20/20 +timeouts=0 +connect_med=128 +txdone_med=0 +cycle_med=320 +p90=350 +auth=3 result=PASS +remaining=7 +BEST NOW: +PRE=150 POST=callback cycle=350ms del=20/20 cb=20 +NEXT: next PRE + +[TEST 6/12] CALLBACK_WPA2_PRE75_S20 +delivery=20/20 +callback=20/20 +timeouts=0 +connect_med=134 +txdone_med=4 +cycle_med=280 +p90=320 +auth=3 result=PASS +remaining=6 +BEST NOW: +PRE=100 POST=callback cycle=320ms del=20/20 cb=20 +NEXT: next PRE + +[TEST 7/12] CALLBACK_WPA2_PRE50_S20 +delivery=16/20 +callback=20/20 +timeouts=0 +connect_med=133 +txdone_med=6 +cycle_med=270 +p90=330 +auth=3 result=FAIL +remaining=5 +BEST NOW: +PRE=75 POST=callback cycle=280ms del=20/20 cb=20 +NEXT: next PRE + +[TEST 8/12] CALLBACK_WPA2_PRE25_S20 +delivery=20/20 +callback=20/20 +timeouts=0 +connect_med=114 +txdone_med=1 +cycle_med=230 +p90=290 +auth=3 result=PASS +remaining=4 +BEST NOW: +PRE=50 POST=callback cycle=270ms del=16/20 cb=20 +NEXT: next PRE + +[TEST 9/12] CALLBACK_WPA2_PRE0_S20 +delivery=3/20 +callback=20/20 +timeouts=0 +connect_med=126 +txdone_med=0 +cycle_med=220 +p90=230 +auth=3 result=FAIL +remaining=3 +BEST NOW: +PRE=25 POST=callback cycle=230ms del=20/20 cb=20 +NEXT: next PRE + diff --git a/experiments/callback_wpa2_state.json b/experiments/callback_wpa2_state.json new file mode 100644 index 0000000..57eef51 --- /dev/null +++ b/experiments/callback_wpa2_state.json @@ -0,0 +1,218 @@ +{ + "val200": { + "id": 103, + "n": 200, + "del": 189, + "plan": 200, + "conn": 127, + "cyc": 430, + "p90": 490, + "mx": 780, + "wr": 200, + "enc": 200, + "st": 200, + "nonce": 200, + "pre": 200, + "post": 0, + "assoc": 154, + "auth": 3, + "retry": 10, + "pm": 1, + "cba": 200, + "cbm": 0, + "cbt": 0, + "txd": 1, + "td": 97, + "samp": 189 + }, + "best": { + "name": "PRE25_S20", + "pre": 25, + "cyc": 230, + "conn": 114, + "del": 20, + "plan": 20, + "cba": 20, + "cbt": 0, + "txd": 1, + "p90": 290, + "mx": 640 + }, + "pre_sweep": [ + [ + 150, + { + "id": 140, + "n": 20, + "del": 20, + "plan": 20, + "conn": 115, + "cyc": 350, + "p90": 420, + "mx": 500, + "wr": 20, + "enc": 20, + "st": 20, + "nonce": 20, + "pre": 150, + "post": 0, + "assoc": 154, + "auth": 3, + "retry": 10, + "pm": 1, + "cba": 20, + "cbm": 0, + "cbt": 0, + "txd": 4, + "td": 76, + "samp": 20 + } + ], + [ + 100, + { + "id": 130, + "n": 20, + "del": 20, + "plan": 20, + "conn": 128, + "cyc": 320, + "p90": 350, + "mx": 390, + "wr": 20, + "enc": 20, + "st": 20, + "nonce": 20, + "pre": 100, + "post": 0, + "assoc": 154, + "auth": 3, + "retry": 10, + "pm": 1, + "cba": 20, + "cbm": 0, + "cbt": 0, + "txd": 0, + "td": 85, + "samp": 20 + } + ], + [ + 75, + { + "id": 125, + "n": 20, + "del": 20, + "plan": 20, + "conn": 134, + "cyc": 280, + "p90": 320, + "mx": 430, + "wr": 20, + "enc": 20, + "st": 20, + "nonce": 20, + "pre": 75, + "post": 0, + "assoc": 154, + "auth": 3, + "retry": 10, + "pm": 1, + "cba": 20, + "cbm": 0, + "cbt": 0, + "txd": 4, + "td": 76, + "samp": 20 + } + ], + [ + 50, + { + "id": 120, + "n": 20, + "del": 16, + "plan": 20, + "conn": 133, + "cyc": 270, + "p90": 330, + "mx": 390, + "wr": 20, + "enc": 20, + "st": 20, + "nonce": 20, + "pre": 50, + "post": 0, + "assoc": 154, + "auth": 3, + "retry": 10, + "pm": 1, + "cba": 20, + "cbm": 0, + "cbt": 0, + "txd": 6, + "td": 71, + "samp": 16 + } + ], + [ + 25, + { + "id": 115, + "n": 20, + "del": 20, + "plan": 20, + "conn": 114, + "cyc": 230, + "p90": 290, + "mx": 640, + "wr": 20, + "enc": 20, + "st": 20, + "nonce": 20, + "pre": 25, + "post": 0, + "assoc": 154, + "auth": 3, + "retry": 10, + "pm": 1, + "cba": 20, + "cbm": 0, + "cbt": 0, + "txd": 1, + "td": 92, + "samp": 20 + } + ], + [ + 0, + { + "id": 110, + "n": 20, + "del": 3, + "plan": 20, + "conn": 126, + "cyc": 220, + "p90": 230, + "mx": 240, + "wr": 20, + "enc": 20, + "st": 20, + "nonce": 20, + "pre": 0, + "post": 0, + "assoc": 154, + "auth": 3, + "retry": 10, + "pm": 1, + "cba": 20, + "cbm": 0, + "cbt": 0, + "txd": 0, + "td": 59, + "samp": 4 + } + ] + ], + "old_winner": 710 +} \ No newline at end of file diff --git a/experiments/deepsleep_5x50_chat.txt b/experiments/deepsleep_5x50_chat.txt new file mode 100644 index 0000000..682c328 --- /dev/null +++ b/experiments/deepsleep_5x50_chat.txt @@ -0,0 +1,42 @@ +[OUTER 1/5] +full_user_ms=12669 +hot_sendto=50/50 +receiver_hot=49/50 +hot_user_median_ms=260 +wake_overhead_median_ms=40 +callback_seen_sum=49 timeouts_sum=0 +brownout=0 +unexpected_reset=0 +remaining=4 +NEXT: +FULL 2/5 + + +[OUTER 3/5] +full_user_ms=4309 +hot_sendto=50/50 +receiver_hot=49/50 +hot_user_median_ms=250 +wake_overhead_median_ms=40 +callback_seen_sum=48 timeouts_sum=1 +brownout=0 +unexpected_reset=0 +remaining=2 +NEXT: +FULL 4/5 + + +[OUTER 4/5] +full_user_ms=3599 +hot_sendto=50/50 +receiver_hot=43/50 +hot_user_median_ms=250 +wake_overhead_median_ms=40 +callback_seen_sum=43 timeouts_sum=0 +brownout=0 +unexpected_reset=0 +remaining=1 +NEXT: +FULL 5/5 + + 17:[18:26:09.012827]:kInfo:kAeActions:ping.cpp:71:kPing:Ping action created to server id: 21, interval: 0:00:01.000000s, rx_window: 0:00:0 diff --git a/experiments/fastest_chat.txt b/experiments/fastest_chat.txt new file mode 100644 index 0000000..14a6673 --- /dev/null +++ b/experiments/fastest_chat.txt @@ -0,0 +1,570 @@ +[TEST 1/22] BASE +delivery=20/20 +median_cycle=840 ms +median_connect=262 ms +p90=920 +result=PASS +remaining=21 +best=BASE cycle=840ms connect=262ms del=20/20 +change vs best=NEW BEST +BEST NOW: +config=BASE +pre=200 post/callback=300 mode=0 +median=840 +NEXT: A1 BASE+cached BSSID x20 + +[TEST 2/22] A1_BSSID +delivery=19/20 +median_cycle=840 ms +median_connect=278 ms +p90=870 +result=FAIL +remaining=20 +best=BASE cycle=840ms connect=262ms del=20/20 +change vs best=+0 ms +BEST NOW: +config=BASE +pre=200 post/callback=300 mode=0 +median=840 +NEXT: A2 BASE+WIFI_FAST_SCAN x20 + +[TEST 3/22] A2_FAST_SCAN +delivery=20/20 +median_cycle=850 ms +median_connect=270 ms +p90=880 +result=PASS +remaining=19 +best=BASE cycle=840ms connect=262ms del=20/20 +change vs best=+10 ms +BEST NOW: +config=BASE +pre=200 post/callback=300 mode=0 +median=840 +NEXT: A3 BASE+BSSID+FAST_SCAN x20 + +[TEST 4/22] A3_BSSID_FAST_SCAN +delivery=19/20 +median_cycle=860 ms +median_connect=276 ms +p90=880 +result=FAIL +remaining=18 +best=BASE cycle=840ms connect=262ms del=20/20 +change vs best=+20 ms +BEST NOW: +config=BASE +pre=200 post/callback=300 mode=0 +median=840 +NEXT: AUTH1 WPA3 on BASE x20 + +[TEST 5/22] AUTH2_H2E +delivery=18/20 +median_cycle=840 ms +median_connect=269 ms +p90=910 +result=FAIL +remaining=17 +best=BASE cycle=840ms connect=262ms del=20/20 +change vs best=+0 ms +BEST NOW: +config=BASE +pre=200 post/callback=300 mode=0 +median=840 +NEXT: AUTH3 WPA2-only on BASE x20 + +[TEST 6/22] AUTH3_WPA2 +delivery=20/20 +median_cycle=850 ms +median_connect=258 ms +p90=920 +result=PASS +remaining=16 +best=BASE cycle=840ms connect=262ms del=20/20 +change vs best=+10 ms +BEST NOW: +config=BASE +pre=200 post/callback=300 mode=0 +median=840 +NEXT: R0 no reconnect retry x20 + +[TEST 7/23] AUTH3B_WPA3SAE_OFF +delivery=20/20 +median_cycle=830 ms +median_connect=253 ms +p90=900 +result=PASS +remaining=16 +best=BASE cycle=840ms connect=262ms del=20/20 +change vs best=-10 ms +BEST NOW: +config=BASE +pre=200 post/callback=300 mode=0 +median=840 +NEXT: restore WPA3 SAE then R0 + +[TEST 8/23] AUTH3B_WPA3SAE_OFF_VERIFIED +delivery=20/20 +median_cycle=710 ms +median_connect=128 ms +p90=810 +result=PASS +remaining=15 +best=AUTH3B_WPA3SAE_OFF_VERIFIED cycle=710ms connect=128ms del=20/20 +change vs best=NEW BEST +BEST NOW: +config=AUTH3B_WPA3SAE_OFF_VERIFIED +pre=200 post/callback=300 mode=0 +median=710 +NEXT: restore WPA3 then R0 + +[TEST 9/22] R0 +delivery=20/20 +median_cycle=730 ms +median_connect=149 ms +p90=760 +result=PASS +remaining=13 +best=AUTH3B_WPA3SAE_OFF_VERIFIED cycle=710ms connect=128ms del=20/20 +change vs best=+20 ms +BEST NOW: +config=AUTH3B_WPA3SAE_OFF_VERIFIED +pre=200 post/callback=300 mode=0 +median=710 +NEXT: R1 retry=1 x20 + +[TEST 10/22] R1 +delivery=20/20 +median_cycle=720 ms +median_connect=149 ms +p90=750 +result=PASS +remaining=12 +best=AUTH3B_WPA3SAE_OFF_VERIFIED cycle=710ms connect=128ms del=20/20 +change vs best=+10 ms +BEST NOW: +config=AUTH3B_WPA3SAE_OFF_VERIFIED +pre=200 post/callback=300 mode=0 +median=710 +NEXT: R3 retry=3 x20 + +[TEST 11/22] R3 +delivery=20/20 +median_cycle=740 ms +median_connect=153 ms +p90=750 +result=PASS +remaining=11 +best=AUTH3B_WPA3SAE_OFF_VERIFIED cycle=710ms connect=128ms del=20/20 +change vs best=+30 ms +BEST NOW: +config=AUTH3B_WPA3SAE_OFF_VERIFIED +pre=200 post/callback=300 mode=0 +median=710 +NEXT: CB0 tx-done callback POST=0 x20 + +[TEST 12/22] CB0 +delivery=18/20 +median_cycle=530 ms +median_connect=154 ms +p90=550 +result=CALLBACK_NOT_USABLE +remaining=10 +best=AUTH3B_WPA3SAE_OFF_VERIFIED cycle=710ms connect=128ms del=20/20 +change vs best=-180 ms +BEST NOW: +config=AUTH3B_WPA3SAE_OFF_VERIFIED +pre=200 post/callback=300 mode=0 +median=710 +NEXT: PRE sweep from 200ms (fixed POST=300) + +[TEST 13/22] PRE_200 +delivery=13/20 +median_cycle=740 ms +median_connect=151 ms +p90=750 +result=FAIL +remaining=9 +best=AUTH3B_WPA3SAE_OFF_VERIFIED cycle=710ms connect=128ms del=20/20 +change vs best=+30 ms +BEST NOW: +config=AUTH3B_WPA3SAE_OFF_VERIFIED +pre=200 post/callback=300 mode=0 +median=710 +NEXT: PRE stop at 200; use best_pre=200 + +[TEST 13/25] PRE_200_R0FAIL +delivery=13/20 +median_cycle=740 ms +median_connect=151 ms +p90=750 +result=FAIL +remaining=12 +best=AUTH3B_WPA3SAE_OFF_VERIFIED cycle=710ms connect=128ms del=20/20 +change vs best=+30 ms +BEST NOW: +config=AUTH3B_WPA3SAE_OFF_VERIFIED +pre=200 post/callback=300 mode=0 +median=710 +NEXT: PRE_200 with retry=10 + +[TEST 14/25] PRE_200 +delivery=19/20 +median_cycle=730 ms +median_connect=144 ms +p90=750 +result=FAIL +remaining=11 +best=AUTH3B_WPA3SAE_OFF_VERIFIED cycle=710ms connect=128ms del=20/20 +change vs best=+20 ms +BEST NOW: +config=AUTH3B_WPA3SAE_OFF_VERIFIED +pre=200 post/callback=300 mode=0 +median=710 +NEXT: PRE_200 repeat + +[TEST 15/25] PRE_200_R +delivery=20/20 +median_cycle=700 ms +median_connect=123 ms +p90=750 +result=PASS +remaining=10 +best=PRE_200_R cycle=700ms connect=123ms del=20/20 +change vs best=NEW BEST +BEST NOW: +config=PRE_200_R +pre=200 post/callback=300 mode=0 +median=700 +NEXT: PRE_150 + +[TEST 16/25] PRE_150 +delivery=14/20 +median_cycle=640 ms +median_connect=124 ms +p90=670 +result=FAIL +remaining=9 +best=PRE_200_R cycle=700ms connect=123ms del=20/20 +change vs best=-60 ms +BEST NOW: +config=PRE_200_R +pre=200 post/callback=300 mode=0 +median=700 +NEXT: PRE stop at 150; best_pre=200 + +[TEST 17/25] POST_300 +delivery=20/20 +median_cycle=700 ms +median_connect=120 ms +p90=740 +result=PASS +remaining=8 +best=PRE_200_R cycle=700ms connect=123ms del=20/20 +change vs best=+0 ms +BEST NOW: +config=PRE_200_R +pre=200 post/callback=300 mode=0 +median=700 +NEXT: POST_250 + +[TEST 18/25] POST_250 +delivery=20/20 +median_cycle=640 ms +median_connect=121 ms +p90=690 +result=PASS +remaining=7 +best=POST_250 cycle=640ms connect=121ms del=20/20 +change vs best=NEW BEST +BEST NOW: +config=POST_250 +pre=200 post/callback=250 mode=0 +median=640 +NEXT: POST_200 + +[TEST 19/25] POST_200 +delivery=20/20 +median_cycle=620 ms +median_connect=132 ms +p90=650 +result=PASS +remaining=6 +best=POST_200 cycle=620ms connect=132ms del=20/20 +change vs best=NEW BEST +BEST NOW: +config=POST_200 +pre=200 post/callback=200 mode=0 +median=620 +NEXT: POST_150 + +[TEST 20/25] POST_150 +delivery=19/20 +median_cycle=540 ms +median_connect=124 ms +p90=550 +result=FAIL +remaining=5 +best=POST_200 cycle=620ms connect=132ms del=20/20 +change vs best=-80 ms +BEST NOW: +config=POST_200 +pre=200 post/callback=200 mode=0 +median=620 +NEXT: POST_150 repeat + +[TEST 21/25] POST_150_R +delivery=20/20 +median_cycle=550 ms +median_connect=125 ms +p90=580 +result=PASS +remaining=4 +best=POST_150_R cycle=550ms connect=125ms del=20/20 +change vs best=NEW BEST +BEST NOW: +config=POST_150_R +pre=200 post/callback=150 mode=0 +median=550 +NEXT: POST_100 + +[TEST 22/25] POST_100 +delivery=13/20 +median_cycle=490 ms +median_connect=113 ms +p90=510 +result=FAIL +remaining=3 +best=POST_150_R cycle=550ms connect=125ms del=20/20 +change vs best=-60 ms +BEST NOW: +config=POST_150_R +pre=200 post/callback=150 mode=0 +median=550 +NEXT: POST stop; best_post=150 + +[TEST 23/25] 2D_p175_q175 +delivery=18/20 +median_cycle=530 ms +median_connect=127 ms +p90=550 +result=FAIL +remaining=2 +best=POST_150_R cycle=550ms connect=125ms del=20/20 +change vs best=-20 ms +BEST NOW: +config=POST_150_R +pre=200 post/callback=150 mode=0 +median=550 +NEXT: next 2D or VAL100 + +[TEST 24/25] 2D_p225_q125 +delivery=19/20 +median_cycle=530 ms +median_connect=127 ms +p90=550 +result=FAIL +remaining=1 +best=POST_150_R cycle=550ms connect=125ms del=20/20 +change vs best=-20 ms +BEST NOW: +config=POST_150_R +pre=200 post/callback=150 mode=0 +median=550 +NEXT: next 2D or VAL100 + +[TEST 25/25] 2D_p150_q200 +delivery=20/20 +median_cycle=540 ms +median_connect=125 ms +p90=580 +result=PASS +remaining=0 +best=2D_p150_q200 cycle=540ms connect=125ms del=20/20 +change vs best=NEW BEST +BEST NOW: +config=2D_p150_q200 +pre=150 post/callback=200 mode=0 +median=540 +NEXT: next 2D or VAL100 + +[TEST 26/33] VAL100_PRIMARY +delivery=94/100 +median_cycle=560 ms +median_connect=131 ms +p90=620 +result=FAIL +remaining=7 +best=POST_150_R cycle=550ms connect=125ms del=20/20 +change vs best=+10 ms +BEST NOW: +config=POST_150_R +pre=200 post/callback=150 mode=0 +median=550 +NEXT: VAL100 secondary + +[TEST 27/33] VAL100_SECONDARY +delivery=97/100 +median_cycle=560 ms +median_connect=131 ms +p90=610 +result=FAIL +remaining=6 +best=POST_150_R cycle=550ms connect=125ms del=20/20 +change vs best=+10 ms +BEST NOW: +config=POST_150_R +pre=200 post/callback=150 mode=0 +median=550 +NEXT: pick winner VAL200 + +[TEST 28/37] VAL100_SAFE_200_300 +delivery=98/100 +median_cycle=730 ms +median_connect=138 ms +p90=770 +result=FAIL +remaining=9 +best=POST_150_R cycle=550ms connect=125ms del=20/20 +change vs best=+180 ms +BEST NOW: +config=POST_150_R +pre=200 post/callback=150 mode=0 +median=550 +NEXT: next candidate or VAL200 + +[TEST 29/37] VAL100_SAFE_200_300_R +delivery=96/100 +median_cycle=720 ms +median_connect=124 ms +p90=750 +result=FAIL +remaining=8 +best=POST_150_R cycle=550ms connect=125ms del=20/20 +change vs best=+170 ms +BEST NOW: +config=POST_150_R +pre=200 post/callback=150 mode=0 +median=550 +NEXT: next + +[TEST 30/37] VAL100_MID_200_200 +delivery=91/100 +median_cycle=620 ms +median_connect=125 ms +p90=660 +result=FAIL +remaining=7 +best=POST_150_R cycle=550ms connect=125ms del=20/20 +change vs best=+70 ms +BEST NOW: +config=POST_150_R +pre=200 post/callback=150 mode=0 +median=550 +NEXT: next candidate or VAL200 + +[TEST 31/37] VAL100_FAST_200_150 +delivery=79/100 +median_cycle=560 ms +median_connect=122 ms +p90=600 +result=FAIL +remaining=6 +best=POST_150_R cycle=550ms connect=125ms del=20/20 +change vs best=+10 ms +BEST NOW: +config=POST_150_R +pre=200 post/callback=150 mode=0 +median=550 +NEXT: next candidate or VAL200 + +[TEST 32/37] VAL100_FAST_150_200 +delivery=84/100 +median_cycle=540 ms +median_connect=118 ms +p90=580 +result=FAIL +remaining=5 +best=POST_150_R cycle=550ms connect=125ms del=20/20 +change vs best=-10 ms +BEST NOW: +config=POST_150_R +pre=200 post/callback=150 mode=0 +median=550 +NEXT: next candidate or VAL200 + +[TEST 33/37] VAL200 +delivery=198/200 +median_cycle=710 ms +median_connect=125 ms +p90=750 +result=FAIL +remaining=4 +best=POST_150_R cycle=550ms connect=125ms del=20/20 +change vs best=+160 ms +BEST NOW: +config=POST_150_R +pre=200 post/callback=150 mode=0 +median=550 +NEXT: D1 AMPDU + +[TEST 34/37] D1_AMPDU_TX_OFF +delivery=198/200 +median_cycle=710 ms +median_connect=125 ms +p90=750 +result=FAIL +remaining=3 +best=VAL100_SAFE_200_300 cycle=710ms connect=125ms del=198/200 +change vs best=+0 ms +BEST NOW: +config=VAL100_SAFE_200_300 +pre=200 post/callback=300 mode=0 +median=710 +NEXT: STORAGE_RAM + +[TEST 35/37] STORAGE_RAM +delivery=198/200 +median_cycle=710 ms +median_connect=125 ms +p90=750 +result=FAIL +remaining=2 +best=VAL100_SAFE_200_300 cycle=710ms connect=125ms del=198/200 +change vs best=+0 ms +BEST NOW: +config=VAL100_SAFE_200_300 +pre=200 post/callback=300 mode=0 +median=710 +NEXT: write report + restore WPA3 + +[TEST 36/38] D1_AMPDU_TX_OFF_RERUN +delivery=17/20 +median_cycle=710 ms +median_connect=122 ms +p90=750 +result=FAIL +remaining=2 +best=VAL200 cycle=710ms connect=125ms del=198/200 +change vs best=+0 ms +BEST NOW: +config=VAL200 +pre=200 post/callback=300 mode=0 +median=710 +NEXT: STORAGE_RAM rerun + +[TEST 37/38] STORAGE_RAM_RERUN +delivery=19/20 +median_cycle=670 ms +median_connect=112 ms +p90=720 +result=FAIL +remaining=1 +best=VAL200 cycle=710ms connect=125ms del=198/200 +change vs best=-40 ms +BEST NOW: +config=VAL200 +pre=200 post/callback=300 mode=0 +median=710 +NEXT: finalize report + commit + diff --git a/experiments/fastest_state.json b/experiments/fastest_state.json new file mode 100644 index 0000000..9406351 --- /dev/null +++ b/experiments/fastest_state.json @@ -0,0 +1,27 @@ +{ + "last": "STORAGE_RAM_RERUN", + "result": { + "id": 95, + "n": 20, + "del": 19, + "plan": 20, + "conn": 112, + "cyc": 670, + "p90": 720, + "mx": 770, + "wr": 20, + "enc": 20, + "st": 20, + "nonce": 20, + "pre": 200, + "post": 300, + "assoc": 90, + "auth": 3, + "retry": 10, + "pm": 0, + "cba": 0, + "cbm": 0, + "samp": 19, + "name": "STORAGE_RAM_RERUN" + } +} \ No newline at end of file diff --git a/experiments/prepared_boot_wifi_opt.tsv b/experiments/prepared_boot_wifi_opt.tsv new file mode 100644 index 0000000..642a6d8 --- /dev/null +++ b/experiments/prepared_boot_wifi_opt.tsv @@ -0,0 +1,309 @@ +record_id kind outer hot user_us wifi_us connect_us txdone_us teardown_us sleep_elapsed_us sleep_overhead_us app_entry_us cb_seen cb_timeout brownout auth seq diag_mode tx_cb_total tx_cb_success tx_cb_failed first_status first_cb_delta_us first_success_delta_us first_failed_delta_us last_cb_delta_us callbacks_after_success rssi disconnect_count last_disconnect_reason reconnect_count ap_primary variant short_retry long_retry retry_called retry_set_rc retry_cfg_us encode_us actual_channel wifi_init_us heap_before heap_after +1 1 0 0 3199803 3199803 0 0 0 3040755 40755 5429 0 0 0 0 2 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 0 0 0 +2 2 0 1 250258 238699 126876 17745 78841 3040736 40736 5429 1 0 0 3 3 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 0 0 0 0 -1 0 3242 9 16316 348292 301708 +3 2 0 2 410269 398711 235548 6490 140250 3040768 40768 5429 1 0 0 3 4 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 0 0 0 0 -1 0 3197 9 16317 348292 301708 +4 2 0 3 370267 358880 168325 83558 83244 3040750 40750 5429 1 0 0 3 5 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 0 0 0 0 -1 0 3133 9 16488 348292 301708 +5 2 0 4 260266 248876 159408 5041 61521 3040723 40723 5429 1 0 0 3 6 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 0 0 0 0 -1 0 3377 9 16485 348292 301708 +6 2 0 5 240270 228877 145899 1035 65775 3040681 40681 5429 1 0 0 3 7 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 0 0 0 0 -1 0 3133 9 16482 348292 301708 +7 2 0 6 250269 238874 139106 10128 66180 3040745 40745 5429 1 0 0 3 8 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 0 0 0 0 -1 0 3132 9 16479 348292 301708 +8 2 0 7 230260 218862 143814 3106 53698 3040743 40743 5429 1 0 0 3 9 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 0 0 0 0 -1 0 3131 9 16476 348292 301708 +9 2 0 8 270269 258868 158381 11660 65148 3040734 40734 5429 1 0 0 3 10 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 0 0 0 0 -1 0 3136 9 16473 348292 301708 +10 2 0 9 270266 258862 138886 10933 85637 3040707 40707 5429 1 0 0 3 11 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 0 0 0 0 -1 0 3376 9 16470 348292 301708 +11 2 0 10 240264 228857 126591 1350 85423 3040744 40744 5429 1 0 0 3 12 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 0 0 0 0 -1 0 3066 9 16468 348292 301708 +12 2 0 11 260269 248859 131454 1542 95268 3040723 40723 5429 1 0 0 3 13 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 0 0 0 0 -1 0 3133 9 16464 348292 301708 +13 2 0 12 210269 198858 118934 2716 54098 3040737 40737 5429 1 0 0 3 14 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -31 0 0 0 9 0 0 0 0 -1 0 3129 9 16462 348292 301708 +14 2 0 13 240267 228851 113723 14138 82708 3040711 40711 5429 1 0 0 3 15 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -31 0 0 0 9 0 0 0 0 -1 0 3089 9 16459 348292 301708 +15 2 0 14 260269 248851 154471 13563 62872 3040744 40744 5429 1 0 0 3 16 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 0 0 0 0 -1 0 3135 9 16456 348292 301708 +16 2 0 15 240275 228853 142033 8551 58264 3040724 40724 5429 1 0 0 3 17 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 0 0 0 0 -1 0 3133 9 16453 348292 301708 +17 2 0 16 270254 258830 144713 11088 85482 3040698 40698 5429 1 0 0 3 18 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 0 0 0 0 -1 0 3242 9 16450 348292 301708 +18 2 0 17 250269 238842 148752 1305 65550 3040711 40711 5429 1 0 0 3 19 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -31 0 0 0 9 0 0 0 0 -1 0 3082 9 16447 348292 301708 +19 2 0 18 230269 218839 120448 6219 70369 3040703 40703 5429 1 0 0 3 20 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 0 0 0 0 -1 0 3344 9 16444 348292 301708 +20 2 0 19 230280 218847 130416 3970 61509 3040702 40702 5429 1 0 0 3 21 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -31 0 0 0 9 0 0 0 0 -1 0 4482 9 16441 348292 301708 +21 2 0 20 240269 228833 133430 4309 72543 3040732 40732 5429 1 0 0 3 22 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 0 0 0 0 -1 0 3083 9 16438 348292 301708 +22 2 0 21 240259 228821 127125 10891 75953 3040732 40732 5429 1 0 0 3 23 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 0 0 0 0 -1 0 3084 9 16435 348292 301708 +23 2 0 22 360272 348830 269128 672 56097 3040758 40758 5429 1 0 0 3 24 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 0 0 0 0 -1 0 3178 9 16433 348292 301708 +24 2 0 23 270266 258822 164195 6202 70540 3040740 40740 5429 1 0 0 3 25 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 0 0 0 0 -1 0 3199 9 16430 348292 301708 +25 2 0 24 260263 248815 130362 11340 84116 3040694 40694 5429 1 0 0 3 26 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 0 0 0 0 -1 0 4482 9 16427 348292 301708 +26 2 0 25 320267 308816 174266 40946 75896 3040730 40730 5429 1 0 0 3 27 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 0 0 0 0 -1 0 3082 9 16424 348292 301708 +27 2 0 26 270262 258808 146305 13090 83484 3040682 40682 5429 1 0 0 3 28 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 0 0 0 0 -1 0 3246 9 16421 348292 301708 +29 2 0 28 300261 288802 207923 163 66677 3040732 40732 5429 1 0 0 3 30 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 0 0 0 0 -1 0 3087 9 16415 348292 301708 +30 2 0 29 250269 238807 123502 9911 86937 3040745 40745 5429 1 0 0 3 31 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 0 0 0 0 -1 0 3087 9 16412 348292 301708 +31 2 0 30 250269 238804 147884 289 76559 3040745 40745 5429 1 0 0 3 32 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 0 0 0 0 -1 0 3087 9 16409 348292 301708 +32 1 1 0 3169808 3169808 147884 289 76559 3040745 40745 5429 1 0 0 3 33 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 1 0 0 0 -1 0 3087 0 16409 348292 301708 +33 2 1 1 390257 378782 270126 6402 80435 3040754 40754 5429 1 0 0 3 34 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3081 9 16399 348292 301708 +34 2 1 2 230260 218789 119133 5838 71011 3040712 40712 5429 1 0 0 3 35 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3083 9 16404 348292 301708 +35 2 1 3 270272 258801 169956 10075 56665 3040704 40704 5429 1 0 0 3 36 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3092 9 16404 348292 301708 +36 2 1 4 190257 178786 112618 1426 45418 3040705 40705 5429 1 0 0 3 37 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 1 0 0 0 -1 0 3080 9 16404 348292 301708 +37 2 1 5 320267 308797 209066 5356 71386 3040752 40752 5429 1 0 0 3 38 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 1 0 0 0 -1 0 3193 9 16404 348292 301708 +38 2 1 6 240270 228800 138933 5606 61204 3040720 40720 5429 1 0 0 3 39 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3128 9 16404 348292 301708 +39 2 1 7 220261 208791 110319 4643 72206 3040661 40661 5429 1 0 0 3 40 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 1 0 0 0 -1 0 3080 9 16404 348292 301708 +40 2 1 8 240264 228793 122601 12985 73868 3040735 40735 5429 1 0 0 3 41 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3083 9 16404 348292 301708 +41 2 1 9 260267 248797 170337 814 55929 3040743 40743 5429 1 0 0 3 42 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3195 9 16404 348292 301708 +42 2 1 10 250264 238793 147884 157 76697 3040738 40738 5429 1 0 0 3 43 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3082 9 16404 348292 301708 +43 2 1 11 240264 228793 146969 157 66702 3040749 40749 5429 1 0 0 3 44 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3075 9 16404 348292 301708 +44 2 1 12 270261 258790 152380 158 86541 3040731 40731 5429 1 0 0 3 45 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3081 9 16404 348292 301708 +45 2 1 13 240265 228794 132774 36522 40060 3040727 40727 5429 1 0 0 3 46 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3091 9 16404 348292 301708 +46 2 1 14 240250 228779 130075 157 76684 3040720 40720 5429 1 0 0 3 47 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3081 9 16404 348292 301708 +47 2 1 15 210263 198793 116964 8542 58315 3040742 40742 5429 1 0 0 3 48 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3079 9 16404 348292 301708 +48 2 1 16 280260 268789 172977 2829 74022 3040736 40736 5429 1 0 0 3 49 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3081 9 16404 348292 301708 +49 2 1 17 520259 508788 216837 35449 241394 3040781 40781 5429 1 0 0 3 50 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3077 9 16404 348292 301708 +50 2 1 18 220258 208787 124422 158 66696 3040745 40745 5429 1 0 0 3 51 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3074 9 16404 348292 301708 +51 2 1 19 310247 298776 172593 34359 72479 3040759 40759 5429 1 0 0 3 52 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 1 0 0 0 -1 0 3074 9 16404 348292 301708 +52 2 1 20 310257 298786 207443 309 76540 3040742 40742 5429 1 0 0 3 53 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3078 9 16404 348292 301708 +53 2 1 21 220258 208787 118019 13534 63306 3040717 40717 5429 1 0 0 3 54 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3092 9 16404 348292 301708 +54 2 1 22 220268 208797 123344 986 65752 3040747 40747 5429 1 0 0 3 55 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 1 0 0 0 -1 0 3196 9 16404 348292 301708 +55 2 1 23 220263 208793 112328 3681 73175 3040725 40725 5429 1 0 0 3 56 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 3080 9 16404 348292 301708 +56 2 1 24 280271 268800 173491 10746 66059 3040717 40717 5429 1 0 0 3 57 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 1 0 0 0 -1 0 3133 9 16404 348292 301708 +57 2 1 25 250263 238792 132796 13548 71881 3040739 40739 5429 1 0 0 3 58 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 1 0 0 0 -1 0 4507 9 16404 348292 301708 +61 2 1 29 260263 248792 160087 13825 51604 3040755 40755 5429 1 0 0 3 62 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 1 0 0 0 -1 0 4509 9 16404 348292 301708 +62 2 1 30 230263 218793 115483 13142 73715 3040736 40736 5429 1 0 0 3 63 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 1 0 0 0 -1 0 3080 9 16404 348292 301708 +66 2 2 3 330245 318771 223713 7619 69219 3040744 40744 5429 1 0 0 3 67 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 2 0 0 0 -1 0 3077 9 10623 348292 301812 +67 2 2 4 470264 458790 283622 46341 110469 3040810 40810 5429 1 0 0 3 68 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 2 0 0 0 -1 0 3128 9 10623 348292 301812 +68 2 2 5 350251 338777 219482 15013 81828 3040770 40770 5429 1 0 0 3 69 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 2 0 0 0 -1 0 3076 9 10623 348292 301812 +69 2 2 6 360254 348780 260801 19098 47699 3040770 40770 5429 1 0 0 3 70 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 2 0 0 0 -1 0 3131 9 10623 348292 301812 +70 2 2 7 330256 318782 218298 4324 72520 3040739 40739 5429 1 0 0 3 71 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 2 0 0 0 -1 0 3077 9 10623 348292 301812 +71 2 2 8 380265 368791 267186 20532 66048 3040703 40703 5429 1 0 0 3 72 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 2 0 0 0 -1 0 3233 9 10623 348292 301812 +72 2 2 9 330260 318786 239572 7721 48729 3040780 40780 5429 1 0 0 3 73 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 2 0 0 0 -1 0 3478 9 10623 348292 301812 +73 2 2 10 350258 338784 244905 153 76699 3040777 40777 5429 1 0 0 3 74 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 2 0 0 0 -1 0 3078 9 10623 348292 301812 +75 2 2 12 360256 348782 226529 23246 83599 3040757 40757 5429 1 0 0 3 76 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 2 0 0 0 -1 0 3076 9 10623 348292 301812 +76 2 2 13 340258 328784 231597 153 76700 3040772 40772 5429 1 0 0 3 77 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 2 0 0 0 -1 0 3077 9 10623 348292 301812 +77 2 2 14 380257 368783 277832 5412 71326 3040777 40777 5429 1 0 0 3 78 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 2 0 0 0 -1 0 3195 9 10623 348292 301812 +78 2 2 15 340259 328785 246789 10295 56435 3040717 40717 5429 1 0 0 3 79 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 2 0 0 0 -1 0 3197 9 10623 348292 301812 +79 2 2 16 310253 298780 211639 1614 65235 3040765 40765 5429 1 0 0 3 80 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 2 0 0 0 -1 0 3077 9 10623 348292 301812 +80 2 2 17 310257 298783 219883 156 56697 3040739 40739 5429 1 0 0 3 81 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 2 0 0 0 -1 0 3076 9 10623 348292 301812 +81 2 2 18 320256 308782 233508 985 55815 3040730 40730 5429 1 0 0 3 82 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 2 0 0 0 -1 0 3127 9 10623 348292 301812 +82 2 2 19 340253 328779 215793 15851 80997 3040754 40754 5429 1 0 0 3 83 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 2 0 0 0 -1 0 3077 9 10623 348292 301812 +83 2 2 20 380256 368782 252883 11193 85387 3040788 40788 5429 1 0 0 3 84 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 2 0 0 0 -1 0 3229 9 10623 348292 301812 +85 2 2 22 370259 358785 261130 9450 66006 3040750 40750 5429 1 0 0 3 86 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 2 0 0 0 -1 0 4390 9 10623 348292 301812 +86 2 2 23 320253 308779 214746 5815 71033 3040774 40774 5429 1 0 0 3 87 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 2 0 0 0 -1 0 3077 9 10623 348292 301812 +87 2 2 24 370254 358780 270686 11548 55071 3040790 40790 5429 1 0 0 3 88 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 2 0 0 0 -1 0 3189 9 10623 348292 301812 +88 2 2 25 360256 348782 261159 3303 63498 3040781 40781 5429 1 0 0 3 89 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 2 0 0 0 -1 0 3129 9 10623 348292 301812 +89 2 2 26 340258 328784 213770 19425 77430 3040783 40783 5429 1 0 0 3 90 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 2 0 0 0 -1 0 3076 9 10623 348292 301812 +90 2 2 27 370261 358788 272824 2089 64653 3040792 40792 5429 1 0 0 3 91 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 2 0 0 0 -1 0 3197 9 10623 348292 301812 +91 2 2 28 330253 318779 214740 14306 72542 3040759 40759 5429 1 0 0 3 92 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 2 0 0 0 -1 0 3077 9 10623 348292 301812 +93 2 2 30 320253 308779 227448 525 66321 3040771 40771 5429 1 0 0 3 94 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 2 0 0 0 -1 0 3077 9 10623 348292 301812 +94 1 3 0 3269808 3269808 227448 525 66321 3040809 40809 5429 1 0 0 3 95 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 3 0 0 0 -1 0 3077 0 10623 348292 301812 +95 2 3 1 330253 318770 228460 3200 63650 3040795 40795 5429 1 0 0 3 96 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 3 0 0 0 -1 0 3072 9 10613 348292 301812 +96 2 3 2 390249 378770 294876 8124 57314 3040773 40773 5429 1 0 0 3 97 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 3 0 0 0 -1 0 4491 9 10618 348292 301812 +97 2 3 3 320258 308779 222162 5280 61574 3040769 40769 5429 1 0 0 3 98 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 3 0 0 0 -1 0 3077 9 10618 348292 301812 +98 2 3 4 390265 378786 279347 10538 66048 3040753 40753 5429 1 0 0 3 99 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 3 0 0 0 -1 0 3232 9 10618 348292 301812 +99 2 3 5 350265 338786 240216 10552 66048 3040766 40766 5429 1 0 0 3 100 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 3 0 0 0 -1 0 3219 9 10618 348292 301812 +100 2 3 6 380264 368785 238533 36080 70510 3040790 40790 5429 1 0 0 3 101 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 3 0 0 0 -1 0 3238 9 10618 348292 301812 +101 2 3 7 440249 428770 225476 92771 92703 3040790 40790 5429 1 0 0 3 102 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 3 0 0 0 -1 0 4449 9 10618 348292 301812 +104 2 3 10 370253 358774 287610 5773 51072 3040752 40752 5429 1 0 0 3 105 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 3 0 0 0 -1 0 3080 9 10618 348292 301812 +105 2 3 11 400265 388786 230175 32122 104468 3040744 40744 5429 1 0 0 3 106 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 3 0 0 0 -1 0 3233 9 10618 348292 301812 +106 2 3 12 420256 408777 298707 17231 69572 3040758 40758 5429 1 0 0 3 107 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 3 0 0 0 -1 0 3130 9 10618 348292 301812 +107 2 3 13 350253 338774 212587 1658 105179 3040751 40751 5429 1 0 0 3 108 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 3 0 0 0 -1 0 3076 9 10618 348292 301812 +108 2 3 14 340260 328781 218652 13794 72822 3040772 40772 5429 1 0 0 3 109 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 3 0 0 0 -1 0 3130 9 10618 348292 301812 +109 2 3 15 410256 398777 234481 19366 126200 3040809 40809 5429 1 0 0 3 110 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 3 0 0 0 -1 0 3136 9 10618 348292 301812 +110 2 3 16 390255 378776 305933 5001 51845 3040790 40790 5429 1 0 0 3 111 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 3 0 0 0 -1 0 3083 9 10618 348292 301812 +111 2 3 17 340245 328766 233442 185 76655 3040794 40794 5429 1 0 0 3 112 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 3 0 0 0 -1 0 3077 9 10618 348292 301812 +112 2 3 18 390257 378778 290262 151 66701 3040772 40772 5429 1 0 0 3 113 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 3 0 0 0 -1 0 3077 9 10618 348292 301812 +113 2 3 19 420256 408777 319209 4826 61912 3040795 40795 5429 1 0 0 3 114 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 3 0 0 0 -1 0 3193 9 10618 348292 301812 +114 2 3 20 330258 318779 218947 2589 74265 3040767 40767 5429 1 0 0 3 115 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 3 0 0 0 -1 0 3076 9 10618 348292 301812 +115 2 3 21 370256 358777 278565 704 56096 3040765 40765 5429 1 0 0 3 116 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 3 0 0 0 -1 0 3131 9 10618 348292 301812 +116 2 3 22 320251 308772 224292 3278 63560 3040746 40746 5429 1 0 0 3 117 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 3 0 0 0 -1 0 3078 9 10618 348292 301812 +117 2 3 23 380256 368777 281555 7077 59721 3040794 40794 5429 1 0 0 3 118 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 3 0 0 0 -1 0 3132 9 10618 348292 301812 +118 2 3 24 350247 338768 251155 16436 49516 3040793 40793 5429 1 0 0 3 119 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 3 0 0 0 -1 0 3130 9 10618 348292 301812 +119 2 3 25 340253 328774 224475 6435 80406 3040761 40761 5429 1 0 0 3 120 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 3 0 0 0 -1 0 3078 9 10618 348292 301812 +123 2 3 29 420258 408779 326051 154 66695 3040795 40795 5429 1 0 0 3 124 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 3 0 0 0 -1 0 3079 9 10618 348292 301812 +124 2 3 30 330258 318779 220482 15349 61455 3040737 40737 5429 1 0 0 3 125 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 3 0 0 0 -1 0 3125 9 10618 348292 301812 +125 1 4 0 3459808 3459808 220482 15349 61455 3040746 40746 5429 1 0 0 3 126 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 4 0 0 0 -1 0 3125 0 10618 348292 301812 +126 2 4 1 240272 228788 134849 158 76698 3040729 40729 5429 1 0 0 3 127 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 4 0 0 0 -1 0 3082 9 16390 348292 301708 +127 2 4 2 320267 308784 192398 16338 80467 3040785 40785 5429 1 0 0 3 128 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 4 0 0 0 -1 0 3134 9 16392 348292 301708 +128 2 4 3 260269 248785 164998 371 66490 3040732 40732 5429 1 0 0 3 129 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 4 0 0 0 -1 0 3074 9 16391 348292 301708 +129 2 4 4 220265 208777 116441 1006 75503 3040737 40737 5429 1 0 0 3 130 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 4 0 0 0 -1 0 3426 9 16386 348292 301708 +130 2 4 5 360266 348775 235223 163 96678 3040752 40752 5429 1 0 0 3 131 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 4 0 0 0 -1 0 3092 9 16383 348292 301708 +131 2 4 6 220267 208773 127478 3886 62580 3040774 40774 5429 1 0 0 3 132 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 4 0 0 0 -1 0 3132 9 16380 348292 301708 +132 2 4 7 250269 238772 140761 22326 54276 3040751 40751 5429 1 0 0 3 133 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 4 0 0 0 -1 0 3239 9 16377 348292 301708 +133 2 4 8 230269 218770 113644 6306 80542 3040736 40736 5429 1 0 0 3 134 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 4 0 0 0 -1 0 3090 9 16374 348292 301708 +134 2 4 9 260261 248758 157400 185 76650 3040740 40740 5429 1 0 0 3 135 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 4 0 0 0 -1 0 3092 9 16372 348292 301708 +135 2 4 10 240269 228764 113882 7621 89227 3040749 40749 5429 1 0 0 3 136 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 4 0 0 0 -1 0 3090 9 16369 348292 301708 +136 2 4 11 240269 228760 122030 6179 80666 3040760 40760 5429 1 0 0 3 137 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 4 0 0 0 -1 0 3088 9 16366 348292 301708 +137 2 4 12 290270 278759 162867 6775 88716 3040780 40780 5429 1 0 0 3 138 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 4 0 0 0 -1 0 4460 9 16363 348292 301708 +138 2 4 13 260275 248760 160301 159 66696 3040748 40748 5429 1 0 0 3 139 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 4 0 0 0 -1 0 3086 9 16360 348292 301708 +139 2 4 14 390269 378752 261689 154 96707 3040759 40759 5429 1 0 0 3 140 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 4 0 0 0 -1 0 3074 9 16357 348292 301708 +140 2 4 15 300261 288742 173611 26936 69858 3040739 40739 5429 1 0 0 3 141 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 4 0 0 0 -1 0 3133 9 16355 348292 301708 +141 2 4 16 270266 258743 125184 9791 106952 3040764 40764 5429 1 0 0 3 142 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 4 0 0 0 -1 0 3198 9 16351 348292 301708 +142 2 4 17 320269 308744 201579 21238 65526 3040781 40781 5429 1 0 0 3 143 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 4 0 0 0 -1 0 3126 9 16348 348292 301708 +143 2 4 18 250267 238738 123994 4382 91206 3040779 40779 5429 1 0 0 3 144 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 4 0 0 0 -1 0 3130 9 16346 348292 301708 +144 2 4 19 240258 228726 134167 8243 68605 3040751 40751 5429 1 0 0 3 145 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 4 0 0 0 -1 0 3083 9 16343 348292 301708 +145 2 4 20 250271 238736 134263 20288 66457 3040773 40773 5429 1 0 0 3 146 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 4 0 0 0 -1 0 3197 9 16340 348292 301708 +146 2 4 21 250267 238729 132405 2609 84203 3040729 40729 5429 1 0 0 3 147 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 4 0 0 0 -1 0 3128 9 16337 348292 301708 +147 2 4 22 220267 208726 133493 1299 55520 3040715 40715 5429 1 0 0 3 148 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 4 0 0 0 -1 0 3119 9 16334 348292 301708 +148 2 4 23 280267 268724 140668 26836 79347 3040778 40778 5429 1 0 0 3 149 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 4 0 0 0 -1 0 3129 9 16331 348292 301708 +149 2 4 24 240263 228717 122331 16014 70668 3040728 40728 5429 1 0 0 3 150 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 4 0 0 0 -1 0 3248 9 16328 348292 301708 +150 2 4 25 350266 338717 223457 5450 91293 3040801 40801 5429 1 0 0 3 151 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 4 0 0 0 -1 0 3194 9 16325 348292 301708 +151 2 4 26 240266 228714 123606 23563 63176 3040761 40761 5429 1 0 0 3 152 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 4 0 0 0 -1 0 3202 9 16322 348292 301708 +152 2 4 27 250256 238702 122554 29367 66075 3040747 40747 5429 1 0 0 3 153 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 4 0 0 0 -1 0 4499 9 16320 348292 301708 +153 2 4 28 320267 308709 126957 2780 164028 3040726 40726 5429 1 0 0 3 154 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 4 0 0 0 -1 0 3132 9 16317 348292 301708 +154 2 4 29 230274 218887 117546 5689 81160 3040765 40765 5429 1 0 0 3 155 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 4 0 0 0 -1 0 3090 9 16488 348292 301708 +155 2 4 30 280268 268878 172750 16460 60278 3040766 40766 5429 1 0 0 3 156 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 4 0 0 0 -1 0 3194 9 16485 348292 301708 +156 1 5 0 3169808 3169808 172750 16460 60278 3040787 40787 5429 1 0 0 3 157 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 5 0 0 0 -1 0 3194 0 16485 348292 301708 +157 2 5 1 240267 228867 128850 163 76683 3040727 40727 5429 1 0 0 3 158 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 5 0 0 0 -1 0 3088 9 16475 348292 301708 +158 2 5 2 300254 288856 186537 6939 78543 3040769 40769 5429 1 0 0 3 159 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 5 0 0 0 -1 0 4406 9 16476 348292 301708 +159 2 5 3 250267 238866 137324 3942 81544 3040767 40767 5429 1 0 0 3 160 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 5 0 0 0 -1 0 4467 9 16474 348292 301708 +160 2 5 4 220274 208870 123400 163 66545 3040753 40753 5429 1 0 0 3 161 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 5 0 0 0 -1 0 3087 9 16471 348292 301708 +161 2 5 5 280262 268855 156239 10016 86601 3040766 40766 5429 1 0 0 3 162 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 5 0 0 0 -1 0 3203 9 16468 348292 301708 +162 2 5 6 230263 218854 137822 5037 61692 3040769 40769 5429 1 0 0 3 163 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 5 0 0 0 -1 0 3198 9 16465 348292 301708 +163 2 5 7 240263 228851 154604 5787 50834 3040768 40768 5429 1 0 0 3 164 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 5 0 0 0 -1 0 3313 9 16462 348292 301708 +165 2 5 9 230269 218850 134956 1809 65039 3040774 40774 5429 1 0 0 3 166 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 5 0 0 0 -1 0 3087 9 16456 348292 301708 +166 2 5 10 280269 268847 176242 163 76690 3040765 40765 5429 1 0 0 3 167 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 5 0 0 0 -1 0 3085 9 16453 348292 301708 +167 2 5 11 240271 228847 113082 13409 83450 3040762 40762 5429 1 0 0 3 168 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 5 0 0 0 -1 0 3078 9 16450 348292 301708 +168 2 5 12 280268 268841 166465 8845 77654 3040762 40762 5429 1 0 0 3 169 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 5 0 0 0 -1 0 3448 9 16447 348292 301708 +169 2 5 13 240270 228840 136102 6881 69937 3040765 40765 5429 1 0 0 3 170 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 5 0 0 0 -1 0 3123 9 16444 348292 301708 +170 2 5 14 230269 218837 130820 2118 64694 3040789 40789 5429 1 0 0 3 171 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 5 0 0 0 -1 0 3131 9 16441 348292 301708 +171 2 5 15 250267 238831 153197 2497 64306 3040790 40790 5429 1 0 0 3 172 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 5 0 0 0 -1 0 3133 9 16439 348292 301708 +172 2 5 16 330269 318830 209245 10179 76675 3040649 40649 5429 1 0 0 3 173 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 5 0 0 0 -1 0 3083 9 16436 348292 301708 +173 2 5 17 230267 218825 127074 4334 72512 3040742 40742 5429 1 0 0 3 174 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 5 0 0 0 -1 0 3089 9 16433 348292 301708 +174 2 5 18 380266 368821 270999 9186 67574 3040799 40799 5429 1 0 0 3 175 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 5 0 0 0 -1 0 3089 9 16430 348292 301708 +175 2 5 19 210267 198819 113798 185 66662 3040776 40776 5429 1 0 0 3 176 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 5 0 0 0 -1 0 3088 9 16427 348292 301708 +179 2 5 23 300270 288811 178625 4284 81382 3040788 40788 5429 1 0 0 3 180 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 5 0 0 0 -1 0 3136 9 16415 348292 301708 +180 2 5 24 230272 218810 138312 2448 54366 3040746 40746 5429 1 0 0 3 181 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 5 0 0 0 -1 0 3131 9 16412 348292 301708 +181 2 5 25 310271 298806 143329 55625 79839 3040749 40749 5429 1 0 0 3 182 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 5 0 0 0 -1 0 4409 9 16410 348292 301708 +182 2 5 26 310269 298802 189633 5572 81238 3040775 40775 5429 1 0 0 3 183 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 5 0 0 0 -1 0 3133 9 16407 348292 301708 +183 2 5 27 250264 238793 136447 18147 68704 3040776 40776 5429 1 0 0 3 184 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 5 0 0 0 -1 0 3086 9 16404 348292 301708 +184 2 5 28 240270 228796 127568 8387 78421 3040764 40764 5429 1 0 0 3 185 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 5 0 0 0 -1 0 3135 9 16401 348292 301708 +185 2 5 29 240269 228793 128314 180 76591 3040783 40783 5429 1 0 0 3 186 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 5 0 0 0 -1 0 3174 9 16398 348292 301708 +186 2 5 30 330271 318791 186664 4263 112600 3040725 40725 5429 1 0 0 3 187 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 5 0 0 0 -1 0 3073 9 16395 348292 301708 +187 1 6 0 3369808 3369808 186664 4263 112600 3040816 40816 5429 1 0 0 3 188 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 6 0 0 0 -1 0 3073 0 16395 348292 301708 +188 2 6 1 260272 248784 152032 162 76698 3040723 40723 5429 1 0 0 3 189 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 6 0 0 0 -1 0 3079 9 16387 348292 301708 +189 2 6 2 270274 258786 135560 161 106697 3040761 40761 5429 1 0 0 3 190 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 6 0 0 0 -1 0 3082 9 16386 348292 301708 +190 2 6 3 290269 278778 170125 318 86425 3040807 40807 5429 1 0 0 3 191 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 6 0 0 0 -1 0 3197 9 16383 348292 301708 +191 2 6 4 290271 278777 125574 12737 122737 3040788 40788 5429 1 0 0 3 192 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 6 0 0 0 -1 0 4420 9 16380 348292 301708 +192 2 6 5 280258 268761 186056 6611 58816 3040790 40790 5429 1 0 0 3 193 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 6 0 0 0 -1 0 4421 9 16377 348292 301708 +196 2 6 9 230263 218754 142110 4143 52605 3040776 40776 5429 1 0 0 3 197 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 6 0 0 0 -1 0 3190 9 16366 348292 301708 +197 2 6 10 200258 188746 112020 5597 51241 3040790 40790 5429 1 0 0 3 198 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 6 0 0 0 -1 0 3088 9 16363 348292 301708 +198 2 6 11 320272 308757 197568 18046 78565 3040784 40784 5429 1 0 0 3 199 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 6 0 0 0 -1 0 3098 9 16360 348292 301708 +199 2 6 12 260269 248752 158581 160 66696 3040746 40746 5429 1 0 0 3 200 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 6 0 0 0 -1 0 3079 9 16357 348292 301708 +200 2 6 13 290270 278751 159934 156 96705 3040769 40769 5429 1 0 0 3 201 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 6 0 0 0 -1 0 3075 9 16355 348292 301708 +202 2 6 15 820265 808739 223863 100003 466741 3040836 40836 5429 0 1 0 3 203 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 6 0 0 0 -1 0 3077 9 16349 348292 301708 +203 2 6 16 210260 198731 124987 155 56696 3040749 40749 5429 1 0 0 3 204 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 6 0 0 0 -1 0 3075 9 16346 348292 301708 +204 2 6 17 320262 308730 126974 92868 73852 3040790 40790 5429 1 0 0 3 205 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 6 0 0 0 -1 0 3096 9 16343 348292 301708 +205 2 6 18 220261 208726 123713 1440 65400 3040756 40756 5429 1 0 0 3 206 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 6 0 0 0 -1 0 3087 9 16340 348292 301708 +206 2 6 19 250267 238729 141705 12264 64587 3040776 40776 5429 1 0 0 3 207 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 6 0 0 0 -1 0 3084 9 16337 348292 301708 +207 2 6 20 350269 338728 229687 191 86671 3040806 40806 5429 1 0 0 3 208 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 6 0 0 0 -1 0 3073 9 16334 348292 301708 +208 2 6 21 280272 268729 182532 5257 60179 3040806 40806 5429 1 0 0 3 209 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 6 0 0 0 -1 0 4515 9 16331 348292 301708 +209 2 6 22 240269 228723 132336 163 76685 3040732 40732 5429 1 0 0 3 210 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 6 0 0 0 -1 0 3087 9 16328 348292 301708 +210 2 6 23 240269 228720 119767 10761 76090 3040776 40776 5429 1 0 0 3 211 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 6 0 0 0 -1 0 3085 9 16325 348292 301708 +211 2 6 24 270271 258719 163090 7353 68118 3040746 40746 5429 1 0 0 3 212 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 6 0 0 0 -1 0 4419 9 16322 348292 301708 +212 2 6 25 240271 228716 128306 214 76486 3040752 40752 5429 1 0 0 3 213 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 6 0 0 0 -1 0 3232 9 16320 348292 301708 +213 2 6 26 310266 298708 141900 7290 128167 3040759 40759 5429 1 0 0 3 214 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 6 0 0 0 -1 0 4410 9 16317 348292 301708 +214 2 6 27 310257 298871 185763 27408 68017 3040778 40778 5429 1 0 0 3 215 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 6 0 0 0 -1 0 4514 9 16488 348292 301708 +215 2 6 28 240266 228876 128608 5552 71254 3040772 40772 5429 1 0 0 3 216 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 6 0 0 0 -1 0 3133 9 16485 348292 301708 +216 2 6 29 410269 398876 130097 20229 226574 3040780 40780 5429 1 0 0 3 217 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 6 0 0 0 -1 0 3133 9 16482 348292 301708 +217 2 6 30 220259 208864 120547 163 66676 3040766 40766 5429 1 0 0 3 218 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 6 0 0 0 -1 0 3088 9 16479 348292 301708 +218 1 7 0 2929808 2929808 120547 163 66676 3040831 40831 5429 1 0 0 3 219 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 7 0 0 0 -1 0 3088 0 16479 348292 301708 +219 2 7 1 300270 288864 188359 719 76091 3040788 40788 5429 1 0 0 3 220 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 7 0 0 0 -1 0 3133 9 16469 348292 301708 +220 2 7 2 360269 348866 236600 2580 93072 3040776 40776 5429 1 0 0 3 221 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 7 0 0 0 -1 0 3133 9 16470 348292 301708 +221 2 7 3 230269 218862 131851 14914 51902 3040768 40768 5429 1 0 0 3 222 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 7 0 0 0 -1 0 3125 9 16468 348292 301708 +222 2 7 4 240262 228852 134826 9685 66900 3040718 40718 5429 1 0 0 3 223 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 7 0 0 0 -1 0 3094 9 16464 348292 301708 +223 2 7 5 250270 238857 143998 1478 75333 3040789 40789 5429 1 0 0 3 224 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 7 0 0 0 -1 0 3132 9 16462 348292 301708 +224 2 7 6 240274 228858 145996 2380 64435 3040751 40751 5429 1 0 0 3 225 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 7 0 0 0 -1 0 3133 9 16459 348292 301708 +225 2 7 7 220267 208848 115147 1769 75078 3040739 40739 5429 1 0 0 3 226 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 7 0 0 0 -1 0 3088 9 16456 348292 301708 +226 2 7 8 270267 258845 126002 163 116683 3040763 40763 5429 1 0 0 3 227 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 7 0 0 0 -1 0 3088 9 16453 348292 301708 +227 2 7 9 220267 208842 113068 5324 71522 3040730 40730 5429 1 0 0 3 228 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 7 0 0 0 -1 0 3088 9 16450 348292 301708 +228 2 7 10 230267 218839 128201 162 76688 3040732 40732 5429 1 0 0 3 229 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 7 0 0 0 -1 0 3087 9 16447 348292 301708 +229 2 7 11 300266 288836 189823 179 76561 3040760 40760 5429 1 0 0 3 230 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 7 0 0 0 -1 0 3200 9 16444 348292 301708 +230 2 7 12 230270 218837 133819 5529 61100 3040772 40772 5429 1 0 0 3 231 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 7 0 0 0 -1 0 3134 9 16441 348292 301708 +231 2 7 13 210269 198833 113190 5385 61464 3040724 40724 5429 1 0 0 3 232 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 7 0 0 0 -1 0 3087 9 16439 348292 301708 +232 2 7 14 310269 298831 181450 5370 90098 3040760 40760 5429 1 0 0 3 233 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 7 0 0 0 -1 0 4486 9 16436 348292 301708 +233 2 7 15 230269 218828 127981 622 76186 3040794 40794 5429 1 0 0 3 234 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 7 0 0 0 -1 0 3135 9 16433 348292 301708 +234 2 7 16 230262 218817 134439 10614 55962 3040804 40804 5429 1 0 0 3 235 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 7 0 0 0 -1 0 3242 9 16430 348292 301708 +235 2 7 17 220267 208819 119498 1087 65759 3040747 40747 5429 1 0 0 3 236 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 7 0 0 0 -1 0 3088 9 16427 348292 301708 +236 2 7 18 300270 288819 185028 3138 82850 3040798 40798 5429 1 0 0 3 237 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 7 0 0 0 -1 0 3136 9 16424 348292 301708 +237 2 7 19 260269 248816 129690 2235 94577 3040773 40773 5429 1 0 0 3 238 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 7 0 0 0 -1 0 3131 9 16421 348292 301708 +238 2 7 20 320270 308813 221860 3103 63704 3040793 40793 5429 1 0 0 3 239 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 7 0 0 0 -1 0 3135 9 16418 348292 301708 +239 2 7 21 260267 248808 117686 18745 98101 3040777 40777 5429 1 0 0 3 240 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 7 0 0 0 -1 0 3089 9 16415 348292 301708 +240 2 7 22 260266 248804 135432 15142 80301 3040797 40797 5429 1 0 0 3 241 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 7 0 0 0 -1 0 4397 9 16412 348292 301708 +241 2 7 23 280266 268801 121882 8409 117037 3040809 40809 5429 1 0 0 3 242 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 7 0 0 0 -1 0 4410 9 16409 348292 301708 +242 2 7 24 670262 658794 195117 9755 436978 3040786 40786 5429 1 0 0 3 243 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 7 0 0 0 -1 0 3094 9 16406 348292 301708 +243 2 7 25 260267 248796 133114 199 96652 3040773 40773 5429 1 0 0 3 244 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 7 0 0 0 -1 0 3086 9 16404 348292 301708 +244 2 7 26 250267 238793 125183 12772 84078 3040793 40793 5429 1 0 0 3 245 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 7 0 0 0 -1 0 3089 9 16401 348292 301708 +245 2 7 27 260269 248792 176573 1268 55470 3040770 40770 5429 1 0 0 3 246 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 7 0 0 0 -1 0 3208 9 16398 348292 301708 +246 2 7 28 230261 218781 123121 1819 75025 3040739 40739 5429 1 0 0 3 247 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 7 0 0 0 -1 0 3083 9 16395 348292 301708 +247 2 7 29 250272 238789 131809 6896 79954 3040754 40754 5429 1 0 0 3 248 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 7 0 0 0 -1 0 3087 9 16392 348292 301708 +248 2 7 30 270266 258782 166415 6682 68774 3040771 40771 5429 1 0 0 3 249 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 7 0 0 0 -1 0 4399 9 16391 348292 301708 +249 1 8 0 3339808 3339808 166415 6682 68774 3040783 40783 5429 1 0 0 3 250 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 8 0 0 0 -1 0 4399 0 16391 348292 301708 +250 2 8 1 230272 218776 135176 4705 62109 3040766 40766 5429 1 0 0 3 251 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 8 0 0 0 -1 0 3131 9 16379 348292 301708 +251 2 8 2 270267 258773 144753 1565 95239 3040809 40809 5429 1 0 0 3 252 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 8 0 0 0 -1 0 3133 9 16380 348292 301708 +252 2 8 3 250269 238773 128215 12148 74659 3040785 40785 5429 1 0 0 3 253 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 8 0 0 0 -1 0 3133 9 16377 348292 301708 +253 2 8 4 340258 328758 217710 30309 66282 3040789 40789 5429 1 0 0 3 254 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 8 0 0 0 -1 0 3238 9 16375 348292 301708 +254 2 8 5 220258 208755 129344 1821 54915 3040682 40682 5429 1 0 0 3 255 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 8 0 0 0 -1 0 3195 9 16372 348292 301708 +255 2 8 6 210267 198761 113125 3067 63779 3040797 40797 5429 1 0 0 3 256 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 8 0 0 0 -1 0 3088 9 16369 348292 301708 +256 2 8 7 300262 288753 182998 10351 76239 3040759 40759 5429 1 0 0 3 257 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 8 0 0 0 -1 0 3229 9 16366 348292 301708 +257 2 8 8 330278 318767 236675 7968 58631 3040780 40780 5429 1 0 0 3 258 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 8 0 0 0 -1 0 3239 9 16363 348292 301708 +258 2 8 9 230259 218744 126035 6389 70440 3040753 40753 5429 1 0 0 3 259 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 8 0 0 0 -1 0 3087 9 16360 348292 301708 +259 2 8 10 270272 258755 174582 4665 60837 3040800 40800 5429 1 0 0 3 260 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 8 0 0 0 -1 0 4455 9 16357 348292 301708 +260 2 8 11 250269 238750 148809 4876 61936 3040738 40738 5429 1 0 0 3 261 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 8 0 0 0 -1 0 3131 9 16356 348292 301708 +261 2 8 12 260272 248749 142712 4976 80475 3040787 40787 5429 1 0 0 3 262 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 8 0 0 0 -1 0 4502 9 16351 348292 301708 +262 2 8 13 230267 218741 135763 3887 62416 3040730 40730 5429 1 0 0 3 263 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 8 0 0 0 -1 0 3133 9 16348 348292 301708 +263 2 8 14 270258 258729 149024 21827 64998 3040761 40761 5429 1 0 0 3 264 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 8 0 0 0 -1 0 3107 9 16346 348292 301708 +264 2 8 15 210269 198737 122859 3720 52174 3040787 40787 5429 1 0 0 3 265 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 8 0 0 0 -1 0 3135 9 16343 348292 301708 +265 2 8 16 340269 328734 135506 6855 169997 3040781 40781 5429 1 0 0 3 266 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 8 0 0 0 -1 0 3083 9 16340 348292 301708 +267 2 8 18 230267 218726 136230 161 66689 3040774 40774 5429 1 0 0 3 268 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 8 0 0 0 -1 0 3089 9 16334 348292 301708 +268 2 8 19 230261 218718 125739 3748 73092 3040766 40766 5429 1 0 0 3 269 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 8 0 0 0 -1 0 3087 9 16331 348292 301708 +273 2 8 24 310269 298711 158936 179 116630 3040760 40760 5429 1 0 0 3 274 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 8 0 0 0 -1 0 3133 9 16317 348292 301708 +274 2 8 25 290267 278880 193707 4594 60895 3040761 40761 5429 1 0 0 3 275 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 8 0 0 0 -1 0 4467 9 16488 348292 301708 +275 2 8 26 220267 208877 116868 6688 70153 3040745 40745 5429 1 0 0 3 276 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 8 0 0 0 -1 0 3088 9 16485 348292 301708 +276 2 8 27 270271 258879 174021 4542 60947 3040780 40780 5429 1 0 0 3 277 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 8 0 0 0 -1 0 4464 9 16482 348292 301708 +277 2 8 28 280267 268872 158032 24283 71807 3040738 40738 5429 1 0 0 3 278 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 8 0 0 0 -1 0 3135 9 16479 348292 301708 +278 2 8 29 230267 218869 123755 3073 73734 3040744 40744 5429 1 0 0 3 279 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 8 0 0 0 -1 0 3134 9 16476 348292 301708 +279 2 8 30 210267 198866 126499 162 56688 3040760 40760 5429 1 0 0 3 280 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 8 0 0 0 -1 0 3087 9 16473 348292 301708 +280 1 9 0 3329808 3329808 126499 162 56688 3040828 40828 5429 1 0 0 3 281 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 9 0 0 0 -1 0 3087 0 16473 348292 301708 +281 2 9 1 220275 208864 126264 2920 63934 3040738 40738 5429 1 0 0 3 282 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 9 0 0 0 -1 0 3087 9 16402 348292 310308 +282 2 9 2 270269 258859 177097 163 66685 3040767 40767 5429 1 0 0 3 283 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 9 0 0 0 -1 0 3086 9 16404 348292 310308 +283 2 9 3 220269 208857 126216 5142 61711 3040753 40753 5429 1 0 0 3 284 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 9 0 0 0 -1 0 3085 9 16401 348292 310308 +284 2 9 4 310274 298858 184670 6094 89358 3040833 40833 5429 1 0 0 3 285 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 9 0 0 0 -1 0 4503 9 16398 348292 310308 +285 2 9 5 240268 228849 128654 975 75424 3040795 40795 5429 1 0 0 3 286 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 9 0 0 0 -1 0 3548 9 16395 348292 310308 +286 2 9 6 260267 248845 131179 20649 74840 3040737 40737 5429 1 0 0 3 287 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 9 0 0 0 -1 0 4465 9 16392 348292 310308 +287 2 9 7 210269 198844 128198 177 56564 3040768 40768 5429 1 0 0 3 288 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 9 0 0 0 -1 0 3205 9 16389 348292 310308 +288 2 9 8 220269 208841 112660 9684 67164 3040801 40801 5429 1 0 0 3 289 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 9 0 0 0 -1 0 3087 9 16386 348292 310308 +289 2 9 9 240267 228837 129490 11128 65718 3040761 40761 5429 1 0 0 3 290 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 9 0 0 0 -1 0 3089 9 16383 348292 310308 +290 2 9 10 310262 298829 183119 11935 84636 3040788 40788 5429 1 0 0 3 291 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 9 0 0 0 -1 0 3243 9 16380 348292 310308 +291 2 9 11 290262 278826 126899 22568 114166 3040760 40760 5429 1 0 0 3 292 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 9 0 0 0 -1 0 3093 9 16378 348292 310308 +292 2 9 12 290274 278835 186736 5103 70344 3040761 40761 5429 1 0 0 3 293 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 9 0 0 0 -1 0 4503 9 16375 348292 310308 +293 2 9 13 250269 238828 139952 3721 73089 3040782 40782 5429 1 0 0 3 294 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 9 0 0 0 -1 0 3133 9 16372 348292 310308 +294 2 9 14 260269 248824 148187 180 86563 3040795 40795 5429 1 0 0 3 295 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 9 0 0 0 -1 0 3203 9 16369 348292 310308 +295 2 9 15 220271 208823 125820 7960 57504 3040781 40781 5429 1 0 0 3 296 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 9 0 0 0 -1 0 4408 9 16366 348292 310308 +296 2 9 16 220267 208816 113261 8628 68218 3040782 40782 5429 1 0 0 3 297 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 9 0 0 0 -1 0 3089 9 16363 348292 310308 +297 2 9 17 380269 368815 235847 37332 79527 3040799 40799 5429 1 0 0 3 298 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 9 0 0 0 -1 0 3076 9 16360 348292 310308 +298 2 9 18 250267 238810 150462 3948 62802 3040812 40812 5429 1 0 0 3 299 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 9 0 0 0 -1 0 3132 9 16357 348292 310308 +299 2 9 19 230269 218810 113812 2612 84233 3040768 40768 5429 1 0 0 3 300 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 9 0 0 0 -1 0 3090 9 16354 348292 310308 +300 2 9 20 240269 228807 133396 178 76670 3040760 40760 5429 1 0 0 3 301 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 9 0 0 0 -1 0 3087 9 16351 348292 310308 +301 2 9 21 300271 288806 173722 8734 86716 3040787 40787 5429 1 0 0 3 302 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 9 0 0 0 -1 0 4503 9 16348 348292 310308 +302 2 9 22 350269 338801 250675 732 66125 3040801 40801 5429 1 0 0 3 303 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 9 0 0 0 -1 0 3081 9 16345 348292 310308 +303 2 9 23 290270 278799 124866 48522 86958 3040766 40766 5429 1 0 0 3 304 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 9 0 0 0 -1 0 4473 9 16343 348292 310308 +304 2 9 24 290269 278795 178522 4804 72003 3040767 40767 5429 1 0 0 3 305 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 9 0 0 0 -1 0 3136 9 16340 348292 310308 +305 2 9 25 220269 208792 126522 374 66475 3040759 40759 5429 1 0 0 3 306 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 9 0 0 0 -1 0 3087 9 16337 348292 310308 +306 2 9 26 230269 218789 127279 6602 70240 3040752 40752 5429 1 0 0 3 307 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 9 0 0 0 -1 0 3087 9 16334 348292 310308 +307 2 9 27 270262 258779 178159 9634 56974 3040801 40801 5429 1 0 0 3 308 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 9 0 0 0 -1 0 3210 9 16331 348292 310308 +309 2 9 29 1040297 1028809 142135 100007 766579 3040859 40859 5429 0 1 0 3 310 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 9 0 0 0 -1 0 3133 9 16325 348292 310308 +310 2 9 30 230275 218784 132388 380 66474 3040760 40760 5429 1 0 0 3 311 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 9 0 0 0 -1 0 3087 9 16322 348292 310308 +311 1 10 0 3209808 3209808 132388 380 66474 3040787 40787 5429 1 0 0 3 312 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 10 0 0 0 -1 0 3087 0 16322 348292 310308 +312 2 10 1 420267 408766 139773 3127 243719 3040809 40809 5429 1 0 0 3 313 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 10 0 0 0 -1 0 3089 9 16288 348292 313748 +313 2 10 2 240270 228770 133009 5365 71446 3040747 40747 5429 1 0 0 3 314 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 10 0 0 0 -1 0 3132 9 16290 348292 313748 +314 2 10 3 220271 208768 124916 6121 59369 3040775 40775 5429 1 0 0 3 315 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 10 0 0 0 -1 0 4407 9 16287 348292 313748 +315 2 10 4 260274 248768 137564 3834 93018 3040775 40775 5429 1 0 0 3 316 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 10 0 0 0 -1 0 3089 9 16284 348292 313748 +316 2 10 5 270270 258761 144428 17030 79779 3040759 40759 5429 1 0 0 3 317 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 10 0 0 0 -1 0 3133 9 16281 348292 313748 +317 2 10 6 250270 238759 141098 163 76692 3040738 40738 5429 1 0 0 3 318 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 10 0 0 0 -1 0 3081 9 16278 348292 313748 +318 2 10 7 300269 288756 210337 2686 53782 3040767 40767 5429 1 0 0 3 319 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 10 0 0 0 -1 0 3136 9 16275 348292 313748 +319 2 10 8 210272 198755 112726 5960 60890 3040794 40794 5429 1 0 0 3 320 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 10 0 0 0 -1 0 3089 9 16272 348292 313748 +321 2 10 10 770272 758749 218499 100004 416735 3040852 40852 5429 0 1 0 3 322 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 10 0 0 0 -1 0 3201 9 16266 348292 313748 +322 2 10 11 470269 458743 354662 4811 82052 3040731 40731 5429 1 0 0 3 323 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 10 0 0 0 -1 0 3073 9 16263 348292 313748 +323 2 10 12 480270 468741 202889 69866 176952 3040752 40752 5429 1 0 0 3 324 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 10 0 0 0 -1 0 3122 9 16261 348292 313748 +324 2 10 13 230267 218735 122932 5622 71222 3040782 40782 5429 1 0 0 3 325 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 10 0 0 0 -1 0 3087 9 16258 348292 313748 +325 2 10 14 270269 258735 179105 177 56564 3040798 40798 5429 1 0 0 3 326 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 10 0 0 0 -1 0 3202 9 16255 348292 313748 +326 2 10 15 220267 208729 117446 11183 65662 3040752 40752 5429 1 0 0 3 327 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 10 0 0 0 -1 0 3089 9 16252 348292 313748 +327 2 10 16 270271 258730 182329 4180 51322 3040793 40793 5429 1 0 0 3 328 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 10 0 0 0 -1 0 3205 9 16249 348292 313748 +328 2 10 17 230261 218718 123992 6132 70708 3040746 40746 5429 1 0 0 3 329 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 10 0 0 0 -1 0 3087 9 16246 348292 313748 +329 2 10 18 300269 288723 179002 268 86469 3040802 40802 5429 1 0 0 3 330 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 10 0 0 0 -1 0 3208 9 16243 348292 313748 +330 2 10 19 320269 308720 156570 67591 69301 3040838 40838 5429 1 0 0 3 331 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 10 0 0 0 -1 0 3041 9 16240 348292 313748 +331 2 10 20 250262 238710 149263 10744 55833 3040780 40780 5429 1 0 0 3 332 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 10 0 0 0 -1 0 3243 9 16237 348292 313748 +332 2 10 21 220267 208713 119486 1782 65068 3040760 40760 5429 1 0 0 3 333 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -32 0 0 0 9 10 0 0 0 -1 0 3089 9 16235 348292 313748 +333 2 10 22 350267 338709 131054 21035 165810 3040804 40804 5429 1 0 0 3 334 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 10 0 0 0 -1 0 3086 9 16232 348292 313748 +334 2 10 23 300267 288880 185174 24101 61398 3040775 40775 5429 1 0 0 3 335 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 10 0 0 0 -1 0 3205 9 16403 348292 313748 +335 2 10 24 260264 248874 125886 11518 95064 3040768 40768 5429 1 0 0 3 336 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 10 0 0 0 -1 0 3238 9 16400 348292 313748 +336 2 10 25 320269 308876 222729 3140 63665 3040800 40800 5429 1 0 0 3 337 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 10 0 0 0 -1 0 3135 9 16397 348292 313748 +337 2 10 26 250262 238867 146044 8854 67731 3040788 40788 5429 1 0 0 3 338 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 10 0 0 0 -1 0 3094 9 16394 348292 313748 +339 2 10 28 270267 258866 157741 163 86683 3040787 40787 5429 1 0 0 3 340 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -33 0 0 0 9 10 0 0 0 -1 0 3089 9 16388 348292 313748 diff --git a/experiments/prepared_boot_wifi_opt_summary.tsv b/experiments/prepared_boot_wifi_opt_summary.tsv new file mode 100644 index 0000000..fffe570 --- /dev/null +++ b/experiments/prepared_boot_wifi_opt_summary.tsv @@ -0,0 +1,12 @@ +variant setting delivery/30 wake_overhead_med wifi_init_med connect_med txdone_med hot_user_med p90 max heap_delta notes +D0_CONTROL baseline 29/30 40732 16447 143814 6490 250269 320267 410269 46584 n=29;txok=29 +D1_STORAGE_RAM WIFI_STORAGE_RAM 27/30 40736 16404 138933 5606 240270 310257 520259 46584 n=27;txok=27 +D2_NVS_OFF nvs_enable=0 25/30 40770 10623 233508 7721 340259 380256 470264 46480 n=25;txok=25 +D3_RAM_NVS_OFF RAM+nvs_off 25/30 40772 10618 238533 6435 370256 420256 440249 46480 n=25;txok=25 +G1_HT20 force HT20 30/30 40752 16360 134263 6306 250271 320269 390269 46584 txok=30 +H1_CS_OFF dynamic_cs=false 26/30 40767 16441 138312 5037 250264 310271 380266 46584 n=26;txok=26 +H2_CS_ON dynamic_cs=true 26/30 40776 16357 141900 5552 270274 320272 820265 46584 n=26;txok=25 +E1_TX_HALF dyn_tx=16 30/30 40772 16433 133819 3138 260266 310269 670262 46584 txok=30 +E2_TX_MIN dyn_tx=8 25/30 40766 16366 136230 4665 250269 310269 340269 46584 n=25;txok=25 +E3_RX_HALF rx 5/16 29/30 40768 16366 132388 5142 250269 310274 1040297 37984 n=29;txok=28 +E4_RX_MIN rx 3/8 26/30 40780 16272 146044 5960 270269 420267 770272 34544 n=26;txok=25 diff --git a/experiments/prepared_boot_wifi_val100.tsv b/experiments/prepared_boot_wifi_val100.tsv new file mode 100644 index 0000000..d203420 --- /dev/null +++ b/experiments/prepared_boot_wifi_val100.tsv @@ -0,0 +1,93 @@ +record_id kind outer hot user_us wifi_us connect_us txdone_us teardown_us sleep_elapsed_us sleep_overhead_us app_entry_us cb_seen cb_timeout brownout auth seq diag_mode tx_cb_total tx_cb_success tx_cb_failed first_status first_cb_delta_us first_success_delta_us first_failed_delta_us last_cb_delta_us callbacks_after_success rssi disconnect_count last_disconnect_reason reconnect_count ap_primary variant short_retry long_retry retry_called retry_set_rc retry_cfg_us encode_us actual_channel wifi_init_us heap_before heap_after +1 1 0 0 3199803 3199803 0 0 0 3040677 40677 5410 0 0 0 0 2 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 255 0 0 0 -1 0 0 0 0 0 0 +2 2 0 1 250268 238882 124073 3149 93609 3040735 40735 5410 1 0 0 3 3 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -37 0 0 0 9 0 0 0 0 -1 0 3178 9 16382 348292 310308 +3 2 0 2 320270 308888 211187 160 76701 3040692 40692 5410 1 0 0 3 4 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +5 2 0 4 220268 208886 127971 459 66399 3040653 40653 5410 1 0 0 3 6 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3079 9 16387 348292 310308 +6 2 0 5 230270 218888 135838 160 66702 3040658 40658 5410 1 0 0 3 7 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +7 2 0 6 310257 298876 192586 12995 72536 3040720 40720 5410 1 0 0 3 8 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 4360 9 16387 348292 310308 +8 2 0 7 250272 238890 131618 11669 73774 3040686 40686 5410 1 0 0 3 9 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 4504 9 16387 348292 310308 +9 2 0 8 250268 238887 128646 6867 79962 3040710 40710 5410 1 0 0 3 10 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -37 0 0 0 9 0 0 0 0 -1 0 3111 9 16387 348292 310308 +10 2 0 9 370265 358883 234388 23387 83344 3040718 40718 5410 1 0 0 3 11 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3085 9 16387 348292 310308 +11 2 0 10 340259 328877 210960 26283 69208 3040736 40736 5410 1 0 0 3 12 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 4450 9 16387 348292 310308 +12 2 0 11 350266 338885 230742 19417 67411 3040686 40686 5410 1 0 0 3 13 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3110 9 16387 348292 310308 +13 2 0 12 350262 338879 226130 19174 77152 3040694 40694 5410 1 0 0 3 14 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3111 9 16386 348292 310308 +14 2 0 13 240275 228893 128889 11621 65143 3040708 40708 5410 1 0 0 3 15 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3178 9 16387 348292 310308 +15 2 0 14 250267 238885 112269 292 106566 3040668 40668 5410 1 0 0 3 16 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +16 2 0 15 280270 268888 184860 3133 63729 3040676 40676 5410 1 0 0 3 17 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +17 2 0 16 320264 308882 180552 25718 80928 3040722 40722 5410 1 0 0 3 18 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -37 0 0 0 9 0 0 0 0 -1 0 3193 9 16387 348292 310308 +18 2 0 17 260270 248888 125547 608 106153 3040701 40701 5410 1 0 0 3 19 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -37 0 0 0 9 0 0 0 0 -1 0 3179 9 16387 348292 310308 +19 2 0 18 330269 318887 203440 32164 64582 3040716 40716 5410 1 0 0 3 20 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3082 9 16387 348292 310308 +20 2 0 19 230262 218880 124746 6970 68521 3040695 40695 5410 1 0 0 3 21 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 4375 9 16387 348292 310308 +21 2 0 20 240268 228887 138384 9075 57749 3040690 40690 5410 1 0 0 3 22 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3112 9 16387 348292 310308 +22 2 0 21 280260 268879 161137 30694 56173 3040681 40681 5410 1 0 0 3 23 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -37 0 0 0 9 0 0 0 0 -1 0 3063 9 16387 348292 310308 +23 2 0 22 280267 268885 152337 6047 90807 3040697 40697 5410 1 0 0 3 24 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3081 9 16387 348292 310308 +24 2 0 23 240268 228887 124486 5880 80974 3040651 40651 5410 1 0 0 3 25 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +25 2 0 24 320268 308886 175436 317 116542 3040717 40717 5410 1 0 0 3 26 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +26 2 0 25 230259 218877 116468 27156 58276 3040673 40673 5410 1 0 0 3 27 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 4501 9 16387 348292 310308 +27 2 0 26 260275 248893 124226 160 106553 3040693 40693 5410 1 0 0 3 28 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3079 9 16387 348292 310308 +29 2 0 28 230265 218883 146322 1514 55341 3040738 40738 5410 1 0 0 3 30 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +30 2 0 29 240275 228893 122140 26049 59549 3040717 40717 5410 1 0 0 3 31 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3112 9 16387 348292 310308 +31 2 0 30 230272 218891 135675 6315 60508 3040710 40710 5410 1 0 0 3 32 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3119 9 16387 348292 310308 +32 2 0 31 280266 268884 146748 30806 75783 3040716 40716 5410 1 0 0 3 33 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3229 9 16387 348292 310308 +33 2 0 32 270270 258888 163004 1367 75493 3040717 40717 5410 1 0 0 3 34 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -38 0 0 0 9 0 0 0 0 -1 0 3074 9 16387 348292 310308 +34 2 0 33 230269 218887 128785 162 66690 3040639 40639 5410 1 0 0 3 35 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3087 9 16387 348292 310308 +35 2 0 34 220266 208885 109803 16447 60372 3040668 40668 5410 1 0 0 3 36 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3109 9 16387 348292 310308 +36 2 0 35 250257 238876 116643 362 106484 3040746 40746 5410 1 0 0 3 37 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3080 9 16387 348292 310308 +37 2 0 36 260275 248893 131114 20616 76215 3040717 40717 5410 1 0 0 3 38 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3112 9 16387 348292 310308 +38 2 0 37 220270 208888 124091 4172 62594 3040746 40746 5410 1 0 0 3 39 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3172 9 16387 348292 310308 +39 2 0 38 260268 248887 149678 18639 58120 3040683 40683 5410 1 0 0 3 40 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3181 9 16387 348292 310308 +40 2 0 39 240268 228887 129956 22520 54303 3040746 40746 5410 1 0 0 3 41 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3113 9 16387 348292 310308 +41 2 0 40 260261 248879 136021 31333 65247 3040688 40688 5410 1 0 0 3 42 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3230 9 16387 348292 310308 +42 2 0 41 240267 228886 123192 5621 79838 3040683 40683 5410 1 0 0 3 43 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 4482 9 16387 348292 310308 +43 2 0 42 250270 238888 127881 33581 62977 3040691 40691 5410 1 0 0 3 44 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -37 0 0 0 9 0 0 0 0 -1 0 3280 9 16387 348292 310308 +44 2 0 43 260256 248874 121473 16812 88614 3040691 40691 5410 1 0 0 3 45 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 4502 9 16387 348292 310308 +45 2 0 44 250268 238887 115599 25825 81001 3040678 40678 5410 1 0 0 3 46 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -37 0 0 0 9 0 0 0 0 -1 0 3111 9 16387 348292 310308 +46 2 0 45 230269 218887 142417 166 56694 3040717 40717 5410 1 0 0 3 47 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +47 2 0 46 240275 228893 123878 24037 62794 3040678 40678 5410 1 0 0 3 48 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3111 9 16387 348292 310308 +48 2 0 47 230268 218887 129787 16867 49959 3040702 40702 5410 1 0 0 3 49 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -37 0 0 0 9 0 0 0 0 -1 0 3111 9 16387 348292 310308 +49 2 0 48 260270 248888 109905 4240 112621 3040727 40727 5410 1 0 0 3 50 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +50 2 0 49 300254 288872 167380 26425 80409 3040713 40713 5410 1 0 0 3 51 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3081 9 16387 348292 310308 +51 2 0 50 290259 278877 172485 18125 68476 3040701 40701 5410 1 0 0 3 52 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3227 9 16387 348292 310308 +52 2 0 51 250269 238887 122906 160 96701 3040720 40720 5410 1 0 0 3 53 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3075 9 16387 348292 310308 +53 2 0 52 250269 238887 130256 11704 73745 3040717 40717 5410 1 0 0 3 54 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 4494 9 16387 348292 310308 +55 2 0 54 240268 228887 130600 4913 71911 3040723 40723 5410 1 0 0 3 56 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3113 9 16387 348292 310308 +56 2 0 55 260259 248877 130245 26825 68606 3040679 40679 5410 1 0 0 3 57 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -37 0 0 0 9 0 0 0 0 -1 0 4501 9 16387 348292 310308 +57 2 0 56 250266 238884 129959 10986 75839 3040704 40704 5410 1 0 0 3 58 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -37 0 0 0 9 0 0 0 0 -1 0 3109 9 16387 348292 310308 +59 2 0 58 220279 208897 127654 449 66419 3040694 40694 5410 1 0 0 3 60 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3080 9 16387 348292 310308 +60 2 0 59 280275 268894 193184 163 56702 3040678 40678 5410 1 0 0 3 61 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +63 2 0 62 210270 198888 123583 925 55865 3040710 40710 5410 1 0 0 3 64 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3154 9 16387 348292 310308 +64 2 0 63 280266 268884 146584 15154 91438 3040729 40729 5410 1 0 0 3 65 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3228 9 16387 348292 310308 +65 2 0 64 470270 458888 219071 22376 194443 3040742 40742 5410 1 0 0 3 66 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -37 0 0 0 9 0 0 0 0 -1 0 3118 9 16387 348292 310308 +66 2 0 65 260268 248886 154688 15407 61451 3040727 40727 5410 1 0 0 3 67 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -38 0 0 0 9 0 0 0 0 -1 0 3075 9 16387 348292 310308 +67 2 0 66 310268 298886 186749 31937 64666 3040720 40720 5410 1 0 0 3 68 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -38 0 0 0 9 0 0 0 0 -1 0 3229 9 16387 348292 310308 +68 2 0 67 240269 228887 116840 636 96221 3040722 40722 5410 1 0 0 3 69 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3080 9 16387 348292 310308 +69 2 0 68 260269 248887 126101 1413 105444 3040722 40722 5410 1 0 0 3 70 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3080 9 16387 348292 310308 +70 2 0 69 240267 228885 146713 1831 65021 3040708 40708 5410 1 0 0 3 71 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3080 9 16387 348292 310308 +71 2 0 70 260266 248884 133662 17785 79038 3040715 40715 5410 1 0 0 3 72 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3110 9 16387 348292 310308 +72 2 0 71 240247 228865 116961 13736 83067 3040699 40699 5410 1 0 0 3 73 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3111 9 16387 348292 310308 +74 2 0 73 210269 198887 135677 348 46509 3040715 40715 5410 1 0 0 3 75 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3081 9 16387 348292 310308 +75 2 0 74 320268 308887 198080 18449 78407 3040722 40722 5410 1 0 0 3 76 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3080 9 16387 348292 310308 +76 2 0 75 300270 288888 161975 34399 72191 3040749 40749 5410 1 0 0 3 77 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3229 9 16387 348292 310308 +77 2 0 76 310277 298895 183703 6585 90276 3040715 40715 5410 1 0 0 3 78 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +78 2 0 77 230268 218886 113432 10803 76056 3040703 40703 5410 1 0 0 3 79 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +79 2 0 78 240268 228886 124115 14594 72264 3040709 40709 5410 1 0 0 3 80 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +81 2 0 80 240268 228886 138026 621 76237 3040729 40729 5410 1 0 0 3 82 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +82 2 0 81 230268 218886 115317 6006 80852 3040717 40717 5410 1 0 0 3 83 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +83 2 0 82 250267 238885 142563 15535 61320 3040717 40717 5410 1 0 0 3 84 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3080 9 16387 348292 310308 +84 2 0 83 320264 308883 182601 26929 79821 3040730 40730 5410 1 0 0 3 85 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3085 9 16387 348292 310308 +85 2 0 84 290269 278887 178495 679 76178 3040710 40710 5410 1 0 0 3 86 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3080 9 16387 348292 310308 +86 2 0 85 240270 228888 125057 15965 70894 3040710 40710 5410 1 0 0 3 87 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 0 0 0 0 -1 0 3075 9 16387 348292 310308 +87 2 0 86 280262 268881 177666 27595 49018 3040696 40696 5410 1 0 0 3 88 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -36 0 0 0 9 0 0 0 0 -1 0 3222 9 16387 348292 310308 +88 2 0 87 280268 268886 187257 1911 64942 3040747 40747 5410 1 0 0 3 89 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3085 9 16387 348292 310308 +89 2 0 88 320270 308888 215875 25448 50009 3040758 40758 5410 1 0 0 3 90 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 4488 9 16387 348292 310308 +90 2 0 89 220268 208886 109153 1398 75461 3040717 40717 5410 1 0 0 3 91 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +91 2 0 90 280262 268880 159342 32360 54260 3040710 40710 5410 1 0 0 3 92 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 0 0 0 0 -1 0 3209 9 16387 348292 310308 +92 2 0 91 230269 218887 131321 15305 50147 3040709 40709 5410 1 0 0 3 93 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 0 0 0 0 -1 0 4484 9 16387 348292 310308 +93 2 0 92 220268 208886 114037 3651 73208 3040717 40717 5410 1 0 0 3 94 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 0 0 0 0 -1 0 3077 9 16387 348292 310308 +94 2 0 93 370263 358881 169495 96005 70664 3040709 40709 5410 1 0 0 3 95 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +96 2 0 95 230266 218884 108214 2216 94637 3040724 40724 5410 1 0 0 3 97 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +97 2 0 96 240268 228886 124862 14711 72148 3040702 40702 5410 1 0 0 3 98 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 +98 2 0 97 270267 258886 176074 4295 61143 3040769 40769 5410 1 0 0 3 99 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -35 0 0 0 9 0 0 0 0 -1 0 4503 9 16387 348292 310308 +99 2 0 98 270270 258888 153913 24277 61211 3040730 40730 5410 1 0 0 3 100 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 0 0 0 0 -1 0 4454 9 16387 348292 310308 +100 2 0 99 220269 208887 115189 2631 74227 3040651 40651 5410 1 0 0 3 101 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 0 0 0 0 -1 0 3080 9 16387 348292 310308 +101 2 0 100 230276 218894 111430 7009 79855 3040725 40725 5410 1 0 0 3 102 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -34 0 0 0 9 0 0 0 0 -1 0 3078 9 16387 348292 310308 diff --git a/experiments/prepared_deepsleep_5x50.tsv b/experiments/prepared_deepsleep_5x50.tsv new file mode 100644 index 0000000..02e354a --- /dev/null +++ b/experiments/prepared_deepsleep_5x50.tsv @@ -0,0 +1,255 @@ +record_id kind outer hot user_us wifi_us connect_us txdone_us teardown_us sleep_elapsed_us sleep_overhead_us app_entry_us cb_seen cb_timeout brownout auth seq +1 1 1 0 12669799 12669799 0 0 0 3040747 40747 5424 0 0 0 0 2 +2 2 1 1 390271 378793 213437 70941 74685 3040704 40704 5424 1 0 0 3 3 +3 2 1 2 250270 238789 120887 3882 93147 3040709 40709 5424 1 0 0 3 4 +4 2 1 3 250270 238786 118646 21314 75711 3040690 40690 5424 1 0 0 3 5 +5 2 1 4 240272 228785 114186 21320 75706 3040699 40699 5424 1 0 0 3 6 +6 2 1 5 230275 218784 118151 7158 79884 3040700 40700 5424 1 0 0 3 7 +7 2 1 6 260275 248781 132523 3315 93726 3040685 40685 5424 1 0 0 3 8 +8 2 1 7 240270 228774 128190 3664 83365 3040679 40679 5424 1 0 0 3 9 +9 2 1 8 260277 248778 146583 8401 78643 3040680 40680 5424 1 0 0 3 10 +10 2 1 9 290271 278770 169141 8263 78735 3040737 40737 5424 1 0 0 3 11 +11 2 1 10 260274 248769 136564 19629 77373 3040693 40693 5424 1 0 0 3 12 +12 2 1 11 250270 238763 154683 5448 61584 3040681 40681 5424 1 0 0 3 13 +13 2 1 12 270277 258766 151717 3400 83646 3040729 40729 5424 1 0 0 3 14 +14 2 1 13 300277 288764 187893 11605 75119 3040736 40736 5424 1 0 0 3 15 +15 2 1 14 240276 228759 137728 15516 61284 3040667 40667 5424 1 0 0 3 16 +16 2 1 15 350272 338752 143274 85645 89994 3040724 40724 5424 1 0 0 3 17 +17 2 1 16 280280 268758 174425 361 76712 3040717 40717 5424 1 0 0 3 18 +18 2 1 17 270277 258751 145698 123 96909 3040737 40737 5424 1 0 0 3 19 +19 2 1 18 320275 308748 190673 17514 79448 3040710 40710 5424 1 0 0 3 20 +20 2 1 19 280276 268747 117796 35867 101071 3040715 40715 5424 1 0 0 3 21 +21 2 1 20 310271 298738 192100 12041 73674 3040724 40724 5424 1 0 0 3 22 +23 2 1 22 290278 278738 165958 18234 78569 3040676 40676 5424 1 0 0 3 24 +24 2 1 23 240276 228733 118761 5593 80109 3040720 40720 5424 1 0 0 3 25 +25 2 1 24 330276 318731 159784 130 136908 3040729 40729 5424 1 0 0 3 26 +26 2 1 25 270274 258725 145056 24156 72632 3040737 40737 5424 1 0 0 3 27 +27 2 1 26 230278 218727 124751 14863 61950 3040736 40736 5424 1 0 0 3 28 +28 2 1 27 420270 408717 299717 14679 72350 3040759 40759 5424 1 0 0 3 29 +29 2 1 28 280278 268722 131241 12224 104822 3040712 40712 5424 1 0 0 3 30 +30 2 1 29 240277 228854 146012 9444 57508 3040705 40705 5424 1 0 0 3 31 +31 2 1 30 440272 428849 363135 984 46045 3040773 40773 5424 1 0 0 3 32 +32 2 1 31 280274 268722 172298 3746 73261 3040711 40711 5424 1 0 0 3 33 +33 2 1 32 310277 298712 129790 5046 140765 3040758 40758 5424 1 0 0 3 34 +34 2 1 33 300274 288706 175126 12651 84298 3040737 40737 5424 1 0 0 3 35 +35 2 1 34 390271 378701 226430 25126 111802 3040752 40752 5424 1 0 0 3 36 +36 2 1 35 280279 268705 182186 13011 53873 3040764 40764 5424 1 0 0 3 37 +37 2 1 36 230278 218701 121716 645 76395 3040713 40713 5424 1 0 0 3 38 +38 2 1 37 290270 278690 123816 14280 122748 3040694 40694 5424 1 0 0 3 39 +39 2 1 38 240277 228694 123274 15322 71563 3040721 40721 5424 1 0 0 3 40 +40 2 1 39 260278 248692 140790 1242 85657 3040733 40733 5424 1 0 0 3 41 +41 2 1 40 240271 228682 123450 6319 80673 3040750 40750 5424 1 0 0 3 42 +42 2 1 41 220273 208681 124833 10993 55839 3040696 40696 5424 1 0 0 3 43 +43 2 1 42 280259 268665 144574 47225 59687 3040753 40753 5424 1 0 0 3 44 +44 2 1 43 230278 218681 118721 10817 64818 3040681 40681 5424 1 0 0 3 45 +45 2 1 44 240272 228672 133232 13735 63213 3040701 40701 5424 1 0 0 3 46 +46 2 1 45 250257 238654 138375 12658 63576 3040689 40689 5424 1 0 0 3 47 +47 2 1 46 230273 218668 132611 11842 55103 3040703 40703 5424 1 0 0 3 48 +48 2 1 47 270275 258666 149979 6058 80949 3040741 40741 5424 1 0 0 3 49 +49 2 1 48 250277 238665 126814 14677 82147 3040749 40749 5424 1 0 0 3 50 +50 2 1 49 230277 218662 119817 12076 64876 3040724 40724 5424 1 0 0 3 51 +51 2 1 50 240277 228659 140980 8264 58739 3040710 40710 5424 1 0 0 3 52 +52 1 2 0 3639803 3639803 0 0 0 3040781 40781 5424 0 0 0 0 53 +53 2 2 1 230263 218640 140568 546 56445 3040708 40708 5424 1 0 0 3 54 +54 2 2 2 310276 298650 131453 125 146909 3040747 40747 5424 1 0 0 3 55 +55 2 2 3 310275 298646 188526 6246 79498 3040760 40760 5424 1 0 0 3 56 +56 2 2 4 250277 238645 133688 6618 79029 3040737 40737 5424 1 0 0 3 57 +57 2 2 5 250273 238638 123838 17539 79251 3040723 40723 5424 1 0 0 3 58 +58 2 2 6 220275 208637 124152 12230 54725 3040696 40696 5424 1 0 0 3 59 +59 2 2 7 270263 258624 144756 17661 79254 3040724 40724 5424 1 0 0 3 60 +60 2 2 8 240277 228633 122446 14140 72698 3040717 40717 5424 1 0 0 3 61 +61 2 2 9 250277 238630 131405 10028 76925 3040742 40742 5424 1 0 0 3 62 +62 2 2 10 250279 238630 129248 11236 74458 3040703 40703 5424 1 0 0 3 63 +63 2 2 11 240263 228612 123207 17667 69140 3040633 40633 5424 1 0 0 3 64 +64 2 2 12 230275 218620 123487 12321 64629 3040710 40710 5424 1 0 0 3 65 +65 2 2 13 260275 248617 140899 11375 74329 3040709 40709 5424 1 0 0 3 66 +66 2 2 14 240277 228616 125233 13865 72946 3040717 40717 5424 1 0 0 3 67 +67 2 2 15 300273 288609 129551 8672 126963 3040730 40730 5424 1 0 0 3 68 +68 2 2 16 240274 228746 130403 533 76508 3040724 40724 5424 1 0 0 3 69 +69 2 2 17 250274 238741 132630 556 86485 3040731 40731 5424 1 0 0 3 70 +70 2 2 18 290275 278739 184773 13481 63324 3040723 40723 5424 1 0 0 3 71 +71 2 2 19 260273 248734 141919 10008 76921 3040735 40735 5424 1 0 0 3 72 +72 2 2 20 230273 218732 129083 7594 58110 3040744 40744 5424 1 0 0 3 73 +73 2 2 21 250276 238733 122482 126 96918 3040724 40724 5424 1 0 0 3 74 +74 2 2 22 270275 258728 158340 1293 75710 3040753 40753 5424 1 0 0 3 75 +75 2 2 23 220277 208727 121934 12195 54758 3040670 40670 5424 1 0 0 3 76 +76 2 2 24 250275 238722 147248 14159 62645 3040738 40738 5424 1 0 0 3 77 +77 2 2 25 300275 288719 144260 16166 110720 3040773 40773 5424 1 0 0 3 78 +78 2 2 26 300277 288718 193419 11384 65438 3040763 40763 5424 1 0 0 3 79 +79 2 2 27 240273 228711 143914 10779 56164 3040767 40767 5424 1 0 0 3 80 +80 2 2 28 270273 258710 151563 8908 76773 3040715 40715 5424 1 0 0 3 81 +81 2 2 29 240275 228707 125173 13280 73524 3040753 40753 5424 1 0 0 3 82 +82 2 2 30 240277 228707 132767 13403 63406 3040723 40723 5424 1 0 0 3 83 +83 2 2 31 240275 228703 140902 3867 61772 3040708 40708 5424 1 0 0 3 84 +84 2 2 32 250275 238699 146435 15327 61386 3040724 40724 5424 1 0 0 3 85 +86 2 2 34 1090297 1078716 233982 100004 726942 3040815 40815 5424 0 1 0 3 87 +88 2 2 36 260273 248685 137716 21258 75677 3040724 40724 5424 1 0 0 3 89 +89 2 2 37 250266 238675 141839 4209 72786 3040731 40731 5424 1 0 0 3 90 +90 2 2 38 240281 228687 119324 8775 76938 3040780 40780 5424 1 0 0 3 91 +91 2 2 39 230277 218681 128921 9464 57488 3040730 40730 5424 1 0 0 3 92 +92 2 2 40 260275 248677 146891 15193 71726 3040737 40737 5424 1 0 0 3 93 +93 2 2 41 270273 258671 133349 22546 84246 3040692 40692 5424 1 0 0 3 94 +94 2 2 42 330277 318672 214803 11605 75349 3040759 40759 5424 1 0 0 3 95 +95 2 2 43 260277 248669 130950 10860 86088 3040726 40726 5424 1 0 0 3 96 +96 2 2 44 280271 268660 123140 8609 118329 3040759 40759 5424 1 0 0 3 97 +97 2 2 45 310275 298662 189280 11111 75840 3040751 40751 5424 1 0 0 3 98 +98 2 2 46 250273 238656 127953 18060 78738 3040699 40699 5424 1 0 0 3 99 +99 2 2 47 250275 238655 120096 9218 86547 3040709 40709 5424 1 0 0 3 100 +103 1 3 0 4309804 4309804 0 0 0 3040875 40875 5424 0 0 0 0 104 +104 2 3 1 230270 218636 121576 4004 73025 3040744 40744 5424 1 0 0 3 105 +105 2 3 2 240274 228637 127416 220 86815 3040758 40758 5424 1 0 0 3 106 +106 2 3 3 250251 238611 132674 2411 84605 3040736 40736 5424 1 0 0 3 107 +107 2 3 4 250274 238631 130160 188 86853 3040709 40709 5424 1 0 0 3 108 +108 2 3 5 240274 228628 143671 3635 63390 3040744 40744 5424 1 0 0 3 109 +109 2 3 6 340275 328626 177858 21621 115303 3040742 40742 5424 1 0 0 3 110 +110 2 3 7 260274 248622 132215 10277 86765 3040717 40717 5424 1 0 0 3 111 +111 2 3 8 250274 238620 131650 203 86838 3040724 40724 5424 1 0 0 3 112 +112 2 3 9 230270 218613 123849 4235 72794 3040765 40765 5424 1 0 0 3 113 +113 2 3 10 260274 248614 139627 135 86906 3040767 40767 5424 1 0 0 3 114 +114 2 3 11 310277 298614 185450 18384 78544 3040758 40758 5424 1 0 0 3 115 +115 2 3 12 230281 218615 126423 12344 64462 3040756 40756 5424 1 0 0 3 116 +116 2 3 13 260277 248608 135076 18761 78167 3040740 40740 5424 1 0 0 3 117 +117 2 3 14 230275 218603 128101 3799 61925 3040741 40741 5424 1 0 0 3 118 +118 2 3 15 260262 248587 154729 11707 65278 3040720 40720 5424 1 0 0 3 119 +119 2 3 16 260275 248597 132881 17700 79244 3040772 40772 5424 1 0 0 3 120 +121 2 3 18 1310300 1298616 210088 100002 966983 3040825 40825 5424 0 1 0 3 122 +122 2 3 19 230256 218569 142061 375 56650 3040734 40734 5424 1 0 0 3 123 +123 2 3 20 330278 318589 209785 7170 78537 3040780 40780 5424 1 0 0 3 124 +124 2 3 21 250279 238588 131115 6538 79164 3040738 40738 5424 1 0 0 3 125 +125 2 3 22 250257 238563 131389 16367 70620 3040737 40737 5424 1 0 0 3 126 +126 2 3 23 240273 228575 120336 11299 75594 3040747 40747 5424 1 0 0 3 127 +127 2 3 24 250280 238579 129844 7922 77720 3040722 40722 5424 1 0 0 3 128 +128 2 3 25 300274 288596 178108 125 86922 3040788 40788 5424 1 0 0 3 129 +129 2 3 26 250274 238741 137761 128 86913 3040712 40712 5424 1 0 0 3 130 +130 2 3 27 300279 288743 173848 17638 79294 3040742 40742 5424 1 0 0 3 131 +131 2 3 28 330270 318732 196577 3700 103321 3040781 40781 5424 1 0 0 3 132 +132 2 3 29 1370258 1358717 1293093 1323 45723 3040859 40859 5424 1 0 0 3 133 +133 2 3 30 280272 268696 142366 126 106915 3040719 40719 5424 1 0 0 3 134 +134 2 3 31 240276 228661 122472 12296 74540 3040751 40751 5424 1 0 0 3 135 +135 2 3 32 240273 228656 130570 14056 62551 3040748 40748 5424 1 0 0 3 136 +136 2 3 33 260265 248645 138822 6583 79096 3040726 40726 5424 1 0 0 3 137 +137 2 3 34 250278 238654 128801 8549 77110 3040732 40732 5424 1 0 0 3 138 +138 2 3 35 240276 228649 125411 15308 71492 3040667 40667 5424 1 0 0 3 139 +139 2 3 36 230276 218647 123751 13216 63589 3040758 40758 5424 1 0 0 3 140 +140 2 3 37 280278 268646 151513 14066 82936 3040731 40731 5424 1 0 0 3 141 +141 2 3 38 240275 228640 141346 127 66906 3040765 40765 5424 1 0 0 3 142 +142 2 3 39 240272 228634 121244 14541 72075 3040730 40730 5424 1 0 0 3 143 +143 2 3 40 230258 218617 125377 127 76890 3040727 40727 5424 1 0 0 3 144 +144 2 3 41 340276 328632 141141 79052 87741 3040779 40779 5424 1 0 0 3 145 +145 2 3 42 270277 258631 156626 15887 71033 3040734 40734 5424 1 0 0 3 146 +146 2 3 43 260277 248628 128394 16115 80696 3040731 40731 5424 1 0 0 3 147 +147 2 3 44 240278 228625 119164 8275 78679 3040747 40747 5424 1 0 0 3 148 +148 2 3 45 230276 218622 128045 2837 74207 3040755 40755 5424 1 0 0 3 149 +149 2 3 46 220275 208617 121258 125 66916 3040751 40751 5424 1 0 0 3 150 +150 2 3 47 240275 228614 124824 1138 85904 3040683 40683 5424 1 0 0 3 151 +151 2 3 48 250270 238607 142738 5138 71893 3040785 40785 5424 1 0 0 3 152 +152 2 3 49 250270 238604 128270 14754 72276 3040727 40727 5424 1 0 0 3 153 +153 2 3 50 240275 228605 125544 545 86495 3040723 40723 5424 1 0 0 3 154 +154 1 4 0 3599804 3599804 0 0 0 3040743 40743 5424 0 0 0 0 155 +155 2 4 1 330274 318599 219698 7892 68716 3040780 40780 5424 1 0 0 3 156 +156 2 4 2 280260 268581 157703 879 96138 3040736 40736 5424 1 0 0 3 157 +157 2 4 3 300276 288594 193637 12696 64022 3040702 40702 5424 1 0 0 3 158 +158 2 4 4 260276 248593 136570 17074 79863 3040748 40748 5424 1 0 0 3 159 +159 2 4 5 250264 238577 125102 16108 80803 3040747 40747 5424 1 0 0 3 160 +160 2 4 6 290277 278587 123568 13581 123339 3040786 40786 5424 1 0 0 3 161 +161 2 4 7 250277 238584 133275 250 86796 3040741 40741 5424 1 0 0 3 162 +162 2 4 8 360252 348581 239275 17926 69091 3040737 40737 5424 1 0 0 3 163 +163 2 4 9 260272 248851 136106 11038 85989 3040752 40752 5424 1 0 0 3 164 +164 2 4 10 280277 268855 162473 11854 74974 3040734 40734 5424 1 0 0 3 165 +165 2 4 11 250277 238855 130558 12111 73552 3040723 40723 5424 1 0 0 3 166 +166 2 4 12 250275 238852 125505 19219 77706 3040719 40719 5424 1 0 0 3 167 +170 2 4 16 250277 238850 129439 10975 75834 3040719 40719 5424 1 0 0 3 171 +171 2 4 17 330279 318852 128984 79330 86342 3040787 40787 5424 1 0 0 3 172 +172 2 4 18 220272 208844 117886 12151 64876 3040744 40744 5425 1 0 0 3 173 +173 2 4 19 240273 228845 128447 232 76808 3040730 40730 5424 1 0 0 3 174 +174 2 4 20 410275 398845 182873 13281 183522 3040761 40761 5424 1 0 0 3 175 +175 2 4 21 220267 208836 124605 864 66152 3040737 40737 5424 1 0 0 3 176 +176 2 4 22 320275 308844 148278 22348 124576 3040779 40779 5424 1 0 0 3 177 +178 2 4 24 280279 268846 162134 5943 81064 3040741 40741 5424 1 0 0 3 179 +179 2 4 25 240275 228841 118465 10761 76189 3040666 40666 5424 1 0 0 3 180 +180 2 4 26 300273 288839 119039 71516 75296 3040734 40734 5424 1 0 0 3 181 +181 2 4 27 250272 238836 133939 9906 77117 3040759 40759 5424 1 0 0 3 182 +182 2 4 28 270274 258838 167635 695 76344 3040740 40740 5424 1 0 0 3 183 +183 2 4 29 270280 258842 149743 11183 74457 3040718 40718 5424 1 0 0 3 184 +184 2 4 30 240277 228839 119986 14769 72034 3040743 40743 5424 1 0 0 3 185 +185 2 4 31 260282 248843 132906 40913 54788 3040762 40762 5424 1 0 0 3 186 +186 2 4 32 240274 228834 120704 11553 74091 3040725 40725 5424 1 0 0 3 187 +187 2 4 33 240277 228836 125850 12506 74308 3040724 40724 5424 1 0 0 3 188 +188 2 4 34 250277 238835 128382 5322 80367 3040750 40750 5424 1 0 0 3 189 +189 2 4 35 330270 318828 172681 41360 85673 3040741 40741 5424 1 0 0 3 190 +193 2 4 39 300284 288838 180269 6345 79367 3040780 40780 5424 1 0 0 3 194 +194 2 4 40 220274 208827 125547 2881 64158 3040746 40746 5424 1 0 0 3 195 +195 2 4 41 250272 238824 123230 11825 85211 3040644 40644 5424 1 0 0 3 196 +196 2 4 42 270271 258823 140274 11770 84952 3040744 40744 5424 1 0 0 3 197 +197 2 4 43 240273 228825 118829 8757 78118 3040711 40711 5424 1 0 0 3 198 +198 2 4 44 250275 238825 123677 24211 72729 3040725 40725 5424 1 0 0 3 199 +199 2 4 45 240277 228826 117131 19254 77673 3040737 40737 5424 1 0 0 3 200 +200 2 4 46 250275 238823 134544 5536 80114 3040731 40731 5424 1 0 0 3 201 +201 2 4 47 240275 228823 119772 15291 71511 3040717 40717 5424 1 0 0 3 202 +202 2 4 48 320272 308819 161439 39044 87984 3040766 40766 5424 1 0 0 3 203 +203 2 4 49 250272 238818 123520 11579 85450 3040786 40786 5424 1 0 0 3 204 +204 2 4 50 250274 238819 155909 2421 64620 3040743 40743 5424 1 0 0 3 205 +205 1 5 0 3619804 3619804 0 0 0 3040740 40740 5424 0 0 0 0 206 +206 2 5 1 240270 228813 126090 9345 77690 3040765 40765 5424 1 0 0 3 207 +207 2 5 2 290261 278804 166622 28103 68801 3040737 40737 5424 1 0 0 3 208 +208 2 5 3 260273 248816 128562 7977 88685 3040729 40729 5424 1 0 0 3 209 +209 2 5 4 220277 208818 126516 3491 63516 3040748 40748 5424 1 0 0 3 210 +210 2 5 5 260275 248815 137447 18096 78830 3040758 40758 5424 1 0 0 3 211 +212 2 5 7 250277 238815 144582 2232 74711 3040751 40751 5424 1 0 0 3 213 +213 2 5 8 250275 238814 128747 4915 80723 3040751 40751 5424 1 0 0 3 214 +214 2 5 9 220263 208801 124346 15244 51670 3040736 40736 5424 1 0 0 3 215 +215 2 5 10 230276 218812 125444 126 76913 3040757 40757 5424 1 0 0 3 216 +216 2 5 11 300275 288810 166141 26352 80570 3040688 40688 5424 1 0 0 3 217 +217 2 5 12 250278 238813 155919 2516 64520 3040748 40748 5424 1 0 0 3 218 +218 2 5 13 330275 318808 209693 13116 73711 3040726 40726 5424 1 0 0 3 219 +219 2 5 14 250269 238801 143207 1664 75267 3040759 40759 5424 1 0 0 3 220 +220 2 5 15 240261 228794 124935 20411 66498 3040765 40765 5424 1 0 0 3 221 +221 2 5 16 250279 238811 142604 4205 71439 3040732 40732 5424 1 0 0 3 222 +222 2 5 17 250277 238807 129185 10616 76187 3040753 40753 5424 1 0 0 3 223 +223 2 5 18 240276 228805 130604 12100 63572 3040732 40732 5424 1 0 0 3 224 +224 2 5 19 260275 248803 136212 23079 73841 3040718 40718 5424 1 0 0 3 225 +225 2 5 20 320270 308823 191929 6002 91038 3040737 40737 5424 1 0 0 3 226 +226 2 5 21 250278 238856 121095 4025 93015 3040765 40765 5424 1 0 0 3 227 +227 2 5 22 290277 278855 146066 17894 99032 3040737 40737 5424 1 0 0 3 228 +228 2 5 23 340279 328856 209744 6947 88748 3040775 40775 5424 1 0 0 3 229 +229 2 5 24 240277 228853 116772 23613 73313 3040738 40738 5424 1 0 0 3 230 +230 2 5 25 250263 238839 121636 18445 78478 3040744 40744 5424 1 0 0 3 231 +231 2 5 26 300274 288849 171045 1303 95736 3040748 40748 5424 1 0 0 3 232 +232 2 5 27 300271 288845 179249 6302 80622 3040758 40758 5424 1 0 0 3 233 +233 2 5 28 350275 338848 220106 13843 82955 3040751 40751 5424 1 0 0 3 234 +234 2 5 29 250271 238843 122074 15759 81045 3040750 40750 5424 1 0 0 3 235 +235 2 5 30 230276 218847 113987 1821 85221 3040719 40719 5424 1 0 0 3 236 +236 2 5 31 250273 238843 128890 13631 73168 3040765 40765 5424 1 0 0 3 237 +237 2 5 32 250275 238845 130668 12835 73767 3040745 40745 5424 1 0 0 3 238 +238 2 5 33 230277 218846 133217 4341 61328 3040764 40764 5424 1 0 0 3 239 +239 2 5 34 240274 228842 137232 555 76486 3040760 40760 5424 1 0 0 3 240 +240 2 5 35 240272 228839 115035 12454 84577 3040731 40731 5424 1 0 0 3 241 +241 2 5 36 280276 268843 130251 626 116413 3040731 40731 5424 1 0 0 3 242 +242 2 5 37 240276 228842 132048 10183 66729 3040744 40744 5424 1 0 0 3 243 +243 2 5 38 250277 238842 127311 21239 75689 3040739 40739 5424 1 0 0 3 244 +244 2 5 39 240263 228828 124588 23722 63209 3040744 40744 5424 1 0 0 3 245 +245 2 5 40 260278 248841 140426 7506 78197 3040751 40751 5424 1 0 0 3 246 +246 2 5 41 450284 438847 219333 4905 192132 3040771 40771 5424 1 0 0 3 247 +247 2 5 42 300281 288842 132208 41165 94512 3040747 40747 5424 1 0 0 3 248 +252 2 5 47 350277 338836 224828 17020 79927 3040773 40773 5424 1 0 0 3 253 +253 2 5 48 260277 248835 124756 17313 89613 3040739 40739 5424 1 0 0 3 254 +254 2 5 49 280274 268829 160093 129 86906 3040736 40736 5424 1 0 0 3 255 +22 2 1 21 250282 238818 134667 9071 76633 3040776 40776 5424 1 0 0 3 23 +85 2 2 33 250270 238715 117085 20491 86537 3040740 40740 5424 1 0 0 3 86 +87 2 2 35 260274 248713 136592 3308 93733 3040681 40681 5424 1 0 0 3 88 +100 2 2 48 250271 238672 119246 6797 88876 3040751 40751 5424 1 0 0 3 101 +101 2 2 49 220275 208674 116943 15615 61325 3040733 40733 5424 1 0 0 3 102 +102 2 2 50 250277 238673 135726 19338 67584 3040725 40725 5424 1 0 0 3 103 +120 2 3 17 240275 228618 126910 21471 65468 3040724 40724 5424 1 0 0 3 121 +168 2 4 14 1270298 1258726 182271 100005 956947 3040815 40815 5424 0 1 0 3 169 +169 2 4 15 260273 248698 139840 13711 73227 3040743 40743 5424 1 0 0 3 170 +177 2 4 23 250261 238664 134126 14504 72481 3040738 40738 5424 1 0 0 3 178 +190 2 4 36 270276 258821 128215 5863 111181 3040730 40730 5424 1 0 0 3 191 +191 2 4 37 230270 218811 117599 4822 82207 3040731 40731 5424 1 0 0 3 192 +192 2 4 38 280277 268815 134606 39777 77140 3040761 40761 5424 1 0 0 3 193 +211 2 5 6 250262 238745 141789 12793 64145 3040732 40732 5424 1 0 0 3 212 +248 2 5 43 300274 288650 190128 3367 73658 3040704 40704 5424 1 0 0 3 249 +249 2 5 44 290277 278650 184908 11749 65087 3040769 40769 5424 1 0 0 3 250 +250 2 5 45 260275 248645 144301 25005 61813 3040753 40753 5424 1 0 0 3 251 +251 2 5 46 310280 298648 139253 15607 121407 3040775 40775 5424 1 0 0 3 252 +167 2 4 13 250275 238686 134105 23080 63839 3040767 40767 5424 1 0 0 3 168 diff --git a/experiments/prepared_mac_retry_diag.tsv b/experiments/prepared_mac_retry_diag.tsv new file mode 100644 index 0000000..fc9794a --- /dev/null +++ b/experiments/prepared_mac_retry_diag.tsv @@ -0,0 +1,274 @@ +record_id kind outer hot user_us wifi_us connect_us txdone_us teardown_us sleep_elapsed_us sleep_overhead_us app_entry_us cb_seen cb_timeout brownout auth seq diag_mode tx_cb_total tx_cb_success tx_cb_failed first_status first_cb_delta_us first_success_delta_us first_failed_delta_us last_cb_delta_us callbacks_after_success rssi disconnect_count last_disconnect_reason reconnect_count ap_primary variant short_retry long_retry retry_called retry_set_rc retry_cfg_us encode_us actual_channel +36 2 1 35 290246 278622 132872 10488 116311 3040890 40890 5353 1 0 0 3 37 0 1 1 0 1 10415 10415 4294967295 10415 0 -32 0 0 0 9 0 0 0 0 -1 0 0 0 +37 2 1 36 280258 268635 135456 181 116595 3040873 40873 5353 1 0 0 3 38 0 1 1 0 1 96 96 4294967295 96 0 -33 0 0 0 9 0 0 0 0 -1 0 0 0 +38 2 1 37 320253 308629 188870 10565 84847 3040899 40899 5353 1 0 0 3 39 0 1 1 0 1 10490 10490 4294967295 10490 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +39 2 1 38 250251 238625 125143 7696 87724 3040898 40898 5353 1 0 0 3 40 0 1 1 0 1 7594 7594 4294967295 7594 0 -34 0 0 0 9 0 0 0 0 -1 0 0 0 +40 2 1 39 230263 218637 128285 182 66594 3040850 40850 5353 1 0 0 3 41 0 1 1 0 1 96 96 4294967295 96 0 -33 0 0 0 9 0 0 0 0 -1 0 0 0 +41 2 1 40 250267 238640 136253 24348 62389 3040877 40877 5353 1 0 0 3 42 0 1 1 0 1 24277 24277 4294967295 24277 0 -33 0 0 0 9 0 0 0 0 -1 0 0 0 +42 2 1 41 230258 218630 128760 12766 53789 3040873 40873 5353 1 0 0 3 43 0 1 1 0 1 12693 12693 4294967295 12693 0 -33 0 0 0 9 0 0 0 0 -1 0 0 0 +43 2 1 42 280244 268616 144981 155 106642 3040875 40875 5353 1 0 0 3 44 0 1 1 0 1 84 84 4294967295 84 0 -32 0 0 0 9 0 0 0 0 -1 0 0 0 +44 2 1 43 290254 278624 127805 28484 106987 3040913 40913 5353 1 0 0 3 45 0 1 1 0 1 28410 28410 4294967295 28410 0 -32 0 0 0 9 0 0 0 0 -1 0 0 0 +45 2 1 44 310260 298630 180459 6284 89157 3040850 40850 5353 1 0 0 3 46 0 1 1 0 1 6211 6211 4294967295 6211 0 -33 0 0 0 9 0 0 0 0 -1 0 0 0 +46 2 1 45 250259 238627 130383 182 86592 3040870 40870 5353 1 0 0 3 47 0 1 1 0 1 95 95 4294967295 95 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +47 2 1 46 260252 248619 124408 2744 103957 3040836 40836 5353 1 0 0 3 48 0 1 1 0 1 2660 2660 4294967295 2660 0 -34 0 0 0 9 0 0 0 0 -1 0 0 0 +48 2 1 47 240240 228606 117299 6899 89857 3040871 40871 5353 1 0 0 3 49 0 1 1 0 1 6812 6812 4294967295 6812 0 -33 0 0 0 9 0 0 0 0 -1 0 0 0 +49 2 1 48 310260 298627 216016 3138 63635 3040915 40915 5353 1 0 0 3 50 0 1 1 0 1 3053 3053 4294967295 3053 0 -32 0 0 0 9 0 0 0 0 -1 0 0 0 +50 2 1 49 230245 218611 146023 154 56646 3040877 40877 5353 1 0 0 3 51 0 1 1 0 1 84 84 4294967295 84 0 -33 0 0 0 9 0 0 0 0 -1 0 0 0 +1 1 1 0 3259803 3259803 0 0 0 3040891 40891 5353 0 0 0 0 2 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 0 0 0 0 -1 0 0 0 +2 2 1 1 260245 248610 136623 154 96645 3040877 40877 5353 1 0 0 3 3 0 1 1 0 1 84 84 4294967295 84 0 -34 0 0 0 9 0 0 0 0 -1 0 0 0 +3 2 1 2 270258 258620 126874 13696 102845 3040876 40876 5353 1 0 0 3 4 0 1 1 0 1 13623 13623 4294967295 13623 0 -45 0 0 0 9 0 0 0 0 -1 0 0 0 +4 2 1 3 340252 328613 212897 6173 90582 3040913 40913 5353 1 0 0 3 5 0 1 1 0 1 6091 6091 4294967295 6091 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +5 2 1 4 240260 228621 125903 2639 84139 3040851 40851 5353 1 0 0 3 6 0 1 1 0 1 2555 2555 4294967295 2555 0 -34 0 0 0 9 0 0 0 0 -1 0 0 0 +6 2 1 5 260261 248620 130801 284 96494 3040850 40850 5353 1 0 0 3 7 0 1 1 0 1 197 197 4294967295 197 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +7 2 1 6 330257 318616 211494 4274 81209 3040875 40875 5353 1 0 0 3 8 0 1 1 0 1 4189 4189 4294967295 4189 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +8 2 1 7 240256 228613 126214 12642 73913 3040873 40873 5353 1 0 0 3 9 0 1 1 0 1 12568 12568 4294967295 12568 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +9 2 1 8 400256 388612 132786 7838 227592 3040899 40899 5353 1 0 0 3 10 0 1 1 0 1 7764 7764 4294967295 7764 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +10 2 1 9 350248 338603 232476 28724 58079 3040900 40900 5353 1 0 0 3 11 0 1 1 0 1 28653 28653 4294967295 28653 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +11 2 1 10 290254 278609 184189 11126 65420 3040882 40882 5353 1 0 0 3 12 0 1 1 0 1 11053 11053 4294967295 11053 0 -34 0 0 0 9 0 0 0 0 -1 0 0 0 +12 2 1 11 220238 208593 136665 154 56638 3040888 40888 5353 1 0 0 3 13 0 1 1 0 1 84 84 4294967295 84 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +13 2 1 12 250246 238599 119897 154 96646 3040862 40862 5353 1 0 0 3 14 0 1 1 0 1 84 84 4294967295 84 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +14 2 1 13 430244 418597 239993 6224 150574 3040885 40885 5353 1 0 0 3 15 0 1 1 0 1 6151 6151 4294967295 6151 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +15 2 1 14 270255 258607 193840 4719 41278 3040914 40914 5353 1 0 0 3 16 0 1 1 0 1 4635 4635 4294967295 4635 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +16 2 1 15 230246 218597 115377 7023 79776 3040849 40849 5353 1 0 0 3 17 0 1 1 0 1 6951 6951 4294967295 6951 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +17 2 1 16 220245 208596 124646 2220 64581 3040863 40863 5353 1 0 0 3 18 0 1 1 0 1 2150 2150 4294967295 2150 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +18 2 1 17 380262 368612 209789 26176 109395 3040957 40957 5353 1 0 0 3 19 0 1 1 0 1 26089 26089 4294967295 26089 0 -36 0 0 0 9 0 0 0 0 -1 0 0 0 +19 2 1 18 360248 348596 245500 1594 85207 3040899 40899 5353 1 0 0 3 20 0 1 1 0 1 1523 1523 4294967295 1523 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +20 2 1 19 310252 298599 184898 2256 94499 3040882 40882 5353 1 0 0 3 21 0 1 1 0 1 2111 2111 4294967295 2111 0 -34 0 0 0 9 0 0 0 0 -1 0 0 0 +21 2 1 20 320260 308607 221171 2866 63911 3040884 40884 5353 1 0 0 3 22 0 1 1 0 1 2782 2782 4294967295 2782 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +22 2 1 21 260245 248592 137483 154 96645 3040887 40887 5353 1 0 0 3 23 0 1 1 0 1 84 84 4294967295 84 0 -36 0 0 0 9 0 0 0 0 -1 0 0 0 +23 2 1 22 260250 248595 129350 6703 88717 3040875 40875 5353 1 0 0 3 24 0 1 1 0 1 6631 6631 4294967295 6631 0 -36 0 0 0 9 0 0 0 0 -1 0 0 0 +24 2 1 23 360258 348602 227330 5327 100103 3040838 40838 5353 1 0 0 3 25 0 1 1 0 1 5247 5247 4294967295 5247 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +25 2 1 24 290252 278595 203533 155 56494 3040882 40882 5353 1 0 0 3 26 0 1 1 0 1 84 84 4294967295 84 0 -34 0 0 0 9 0 0 0 0 -1 0 0 0 +26 2 1 25 230238 218582 138766 3709 53085 3040863 40863 5353 1 0 0 3 27 0 1 1 0 1 3640 3640 4294967295 3640 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +27 2 1 26 290259 278602 189490 183 66594 3040879 40879 5353 1 0 0 3 28 0 1 1 0 1 96 96 4294967295 96 0 -36 0 0 0 9 0 0 0 0 -1 0 0 0 +28 2 1 27 300251 288618 177107 230 96579 3040889 40889 5353 1 0 0 3 29 0 1 1 0 1 157 157 4294967295 157 0 -34 0 0 0 9 0 0 0 0 -1 0 0 0 +29 2 1 28 270253 258646 186466 147 56439 3040872 40872 5353 1 0 0 3 30 0 1 1 0 1 74 74 4294967295 74 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +30 2 1 29 230239 218630 133774 8595 58195 3040877 40877 5353 1 0 0 3 31 0 1 1 0 1 8525 8525 4294967295 8525 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +31 2 1 30 340254 328645 182069 10433 114980 3040912 40912 5353 1 0 0 3 32 0 1 1 0 1 10358 10358 4294967295 10358 0 -35 0 0 0 9 0 0 0 0 -1 0 0 0 +33 2 1 32 320249 308638 187994 812 105981 3040856 40856 5353 1 0 0 3 34 0 1 1 0 1 739 739 4294967295 739 0 -34 0 0 0 9 0 0 0 0 -1 0 0 0 +34 2 1 33 310254 298642 217103 11166 55363 3040872 40872 5353 1 0 0 3 35 0 1 1 0 1 11093 11093 4294967295 11093 0 -34 0 0 0 9 0 0 0 0 -1 0 0 0 +35 2 1 34 230247 218635 138770 154 56647 3040928 40928 5353 1 0 0 3 36 0 1 1 0 1 84 84 4294967295 84 0 -34 0 0 0 9 0 0 0 0 -1 0 0 0 +32 2 0 31 230251 218816 126169 159 76751 0 0 0 1 0 0 3 33 0 1 1 0 1 87 87 4294967295 87 0 -37 0 0 0 9 0 0 0 0 -1 0 3032 9 +51 2 0 50 240242 228753 143692 11401 55243 0 0 0 1 0 0 3 52 0 1 1 0 1 11328 11328 4294967295 11328 0 -39 0 0 0 9 0 0 0 0 -1 0 3192 9 +52 1 1 0 3489803 3489803 143692 11401 55243 0 0 0 1 0 0 3 53 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 1 0 0 1 -1 0 3192 0 +53 2 1 1 250241 238743 189697 6069 20783 0 0 0 1 0 0 3 54 0 1 1 0 1 5990 5990 4294967295 5990 0 -41 0 0 0 9 1 0 0 1 0 7 3084 9 +55 2 1 3 170245 158744 113072 362 26535 0 0 0 1 0 0 3 56 0 1 0 1 0 308 4294967295 308 308 0 -44 0 0 0 9 1 0 0 1 0 7 3038 9 +56 2 1 4 180241 168737 126183 8922 17869 0 0 0 1 0 0 3 57 0 1 1 0 1 8831 8831 4294967295 8831 0 -44 0 0 0 9 1 0 0 1 0 7 3055 9 +57 2 1 5 190248 178742 127055 9792 27103 0 0 0 1 0 0 3 58 0 1 1 0 1 9722 9722 4294967295 9722 0 -40 0 0 0 9 1 0 0 1 0 7 3039 9 +58 2 1 6 1370249 1358738 1308565 1943 24953 0 0 0 1 0 0 3 59 0 1 1 0 1 1871 1871 4294967295 1871 0 -38 0 0 0 9 1 0 0 1 0 7 3041 9 +59 2 1 7 220245 208731 149583 18446 18254 0 0 0 1 0 0 3 60 0 1 1 0 1 18374 18374 4294967295 18374 0 -41 0 0 0 9 1 0 0 1 0 7 3056 9 +60 2 1 8 220251 208735 162387 160 26743 0 0 0 1 0 0 3 61 0 1 1 0 1 87 87 4294967295 87 0 -40 0 0 0 9 1 0 0 1 0 7 3040 9 +61 2 1 9 270248 258729 204873 11668 24977 0 0 0 1 0 0 3 62 0 1 1 0 1 11596 11596 4294967295 11596 0 -44 0 0 0 9 1 0 0 1 0 6 3206 9 +62 2 1 10 240238 228716 193267 174 16689 0 0 0 1 0 0 3 63 0 1 1 0 1 93 93 4294967295 93 0 -43 0 0 0 9 1 0 0 1 0 6 3078 9 +63 2 1 11 310247 298722 187000 76286 20419 0 0 0 1 0 0 3 64 0 1 1 0 1 76205 76205 4294967295 76205 0 -48 0 0 0 9 1 0 0 1 0 6 3147 9 +64 2 1 12 190247 178719 118342 2915 32623 0 0 0 1 0 0 3 65 0 1 1 0 1 2836 2836 4294967295 2836 0 -44 0 0 0 9 1 0 0 1 0 7 4384 9 +65 2 1 13 200249 188718 126187 22908 23963 0 0 0 1 0 0 3 66 0 1 1 0 1 22833 22833 4294967295 22833 0 -44 0 0 0 9 1 0 0 1 0 7 3071 9 +67 2 1 15 190242 178706 135845 1886 24979 0 0 0 1 0 0 3 68 0 1 1 0 1 1808 1808 4294967295 1808 0 -46 0 0 0 9 1 0 0 1 0 7 3080 9 +68 2 1 16 180244 168705 126778 3215 23681 0 0 0 1 0 0 3 69 0 1 1 0 1 3142 3142 4294967295 3142 0 -44 0 0 0 9 1 0 0 1 0 6 3041 9 +73 2 1 21 270232 258721 222452 1076 15772 0 0 0 1 0 0 3 74 0 1 0 1 0 1014 4294967295 1014 1014 0 -47 0 0 0 9 1 0 0 1 0 7 3080 9 +74 2 1 22 250235 238684 198142 6849 18658 0 0 0 1 0 0 3 75 0 1 1 0 1 6776 6776 4294967295 6776 0 -41 0 0 0 9 1 0 0 1 0 7 4351 9 +75 2 1 23 190250 178696 124719 10547 26342 0 0 0 1 0 0 3 76 0 1 1 0 1 10477 10477 4294967295 10477 0 -44 0 0 0 9 1 0 0 1 0 7 3045 9 +76 2 1 24 210240 198683 145884 15277 20213 0 0 0 1 0 0 3 77 0 1 1 0 1 15204 15204 4294967295 15204 0 -39 0 0 0 9 1 0 0 1 0 7 4424 9 +79 2 1 27 260248 248646 191599 3817 33069 0 0 0 1 0 0 3 80 0 1 0 1 0 3752 4294967295 3752 3752 0 -46 0 0 0 9 1 0 0 1 0 7 3049 9 +80 2 1 28 210245 198949 128807 7320 39283 0 0 0 1 0 0 3 81 0 1 1 0 1 7244 7244 4294967295 7244 0 -45 0 0 0 9 1 0 0 1 0 7 3347 9 +81 2 1 29 210241 198943 160048 1834 14749 0 0 0 1 0 0 3 82 0 1 1 0 1 1754 1754 4294967295 1754 0 -45 0 0 0 9 1 0 0 1 0 7 3363 9 +82 2 1 30 240240 228938 192983 5188 11672 0 0 0 1 0 0 3 83 0 1 1 0 1 5108 5108 4294967295 5108 0 -42 0 0 0 9 1 0 0 1 0 6 3083 9 +83 2 1 31 250238 238932 197239 11274 14240 0 0 0 1 0 0 3 84 0 1 1 0 1 11200 11200 4294967295 11200 0 -46 0 0 0 9 1 0 0 1 0 7 4402 9 +85 2 1 33 310241 298930 209263 29739 37120 0 0 0 1 0 0 3 86 0 1 0 1 0 29680 4294967295 29680 29680 0 -45 0 0 0 9 1 0 0 1 0 7 3078 9 +86 2 1 34 200242 188928 137942 8070 28711 0 0 0 1 0 0 3 87 0 1 1 0 1 8000 8000 4294967295 8000 0 -41 0 0 0 9 1 0 0 1 0 7 3055 9 +87 2 1 35 230238 218921 185540 3911 12945 0 0 0 1 0 0 3 88 0 1 1 0 1 3835 3835 4294967295 3835 0 -41 0 0 0 9 1 0 0 1 0 7 3084 9 +88 2 1 36 250237 238917 194655 8739 18034 0 0 0 1 0 0 3 89 0 1 1 0 1 8669 8669 4294967295 8669 0 -40 0 0 0 9 1 0 0 1 0 6 3057 9 +90 2 1 38 190239 178913 139453 1479 15412 0 0 0 1 0 0 3 91 0 1 0 1 0 1425 4294967295 1425 1425 0 -39 0 0 0 9 1 0 0 1 0 6 3037 9 +92 2 1 40 1420244 1408912 1366598 5583 21314 0 0 0 1 0 0 3 93 0 1 0 1 0 5527 4294967295 5527 5527 0 -42 0 0 0 9 1 0 0 1 0 6 3036 9 +93 2 1 41 210250 198916 149973 147 26532 0 0 0 1 0 0 3 94 0 1 1 0 1 76 76 4294967295 76 0 -41 0 0 0 9 1 0 0 1 0 7 3256 9 +94 2 1 42 1420247 1408909 1370822 157 16731 0 0 0 1 0 0 3 95 0 1 1 0 1 84 84 4294967295 84 0 -39 0 0 0 9 1 0 0 1 0 6 3046 9 +95 2 1 43 210238 198898 158395 4694 12103 0 0 0 1 0 0 3 96 0 1 1 0 1 4618 4618 4294967295 4618 0 -40 0 0 0 9 1 0 0 1 0 7 3142 9 +96 2 1 44 180249 168907 125638 157 26732 0 0 0 1 0 0 3 97 0 1 1 0 1 87 87 4294967295 87 0 -39 0 0 0 9 1 0 0 1 0 6 3045 9 +97 2 1 45 220247 208902 151150 17025 19574 0 0 0 1 0 0 3 98 0 1 1 0 1 16955 16955 4294967295 16955 0 -38 0 0 0 9 1 0 0 1 0 6 3051 9 +99 2 1 47 340241 328889 225783 63246 22247 0 0 0 1 0 0 3 100 0 1 0 1 0 63191 4294967295 63191 63191 0 -41 0 0 0 9 1 0 0 1 0 7 4426 9 +100 2 1 48 190239 178885 140395 170 16711 0 0 0 1 0 0 3 101 0 1 1 0 1 95 95 4294967295 95 0 -47 0 0 0 9 1 0 0 1 0 7 3063 9 +101 2 1 49 170247 158889 128294 1377 15523 0 0 0 1 0 0 3 102 0 1 1 0 1 1306 1306 4294967295 1306 0 -46 0 0 0 9 1 0 0 1 0 7 3038 9 +102 2 1 50 210237 198876 151836 9532 17244 0 0 0 1 0 0 3 103 0 1 1 0 1 9461 9461 4294967295 9461 0 -40 0 0 0 9 1 0 0 1 0 7 3055 9 +103 1 2 0 3239804 3239804 151836 9532 17244 0 0 0 1 0 0 3 104 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 2 1 1 1 -1 0 3055 0 +105 2 2 2 310249 298880 226801 22160 34721 0 0 0 1 0 0 3 106 0 1 0 1 0 22108 4294967295 22108 22108 0 -42 0 0 0 9 2 1 1 1 0 7 3053 9 +106 2 2 3 190238 178866 132420 4321 21190 0 0 0 1 0 0 3 107 0 1 1 0 1 4243 4243 4294967295 4243 0 -40 0 0 0 9 2 1 1 1 0 7 4401 9 +107 2 2 4 280245 268871 199744 5706 41201 0 0 0 1 0 0 3 108 0 1 1 0 1 5632 5632 4294967295 5632 0 -41 0 0 0 9 2 1 1 1 0 6 3045 9 +108 2 2 5 220242 208865 161051 172 26628 0 0 0 1 0 0 3 109 0 1 1 0 1 96 96 4294967295 96 0 -43 0 0 0 9 2 1 1 1 0 7 3145 9 +109 2 2 6 170247 158866 122204 925 15972 0 0 0 1 0 0 3 110 0 1 1 0 1 850 850 4294967295 850 0 -43 0 0 0 9 2 1 1 1 0 6 3039 9 +110 2 2 7 180249 168865 129021 327 16576 0 0 0 1 0 0 3 111 0 1 1 0 1 255 255 4294967295 255 0 -39 0 0 0 9 2 1 1 1 0 7 3037 9 +111 2 2 8 270237 258850 217287 9121 17653 0 0 0 1 0 0 3 112 0 1 1 0 1 9050 9050 4294967295 9050 0 -43 0 0 0 9 2 1 1 1 0 7 3056 9 +112 2 2 9 260244 248854 197626 6659 28859 0 0 0 1 0 0 3 113 0 1 1 0 1 6585 6585 4294967295 6585 0 -47 0 0 0 9 2 1 1 1 0 7 4405 9 +113 2 2 10 1370244 1358852 1310468 169 26702 0 0 0 1 0 0 3 114 0 1 1 0 1 88 88 4294967295 88 0 -45 0 0 0 9 2 1 1 1 0 6 3078 9 +114 2 2 11 250239 238845 187706 10957 25745 0 0 0 1 0 0 3 115 0 1 1 0 1 10885 10885 4294967295 10885 0 -40 0 0 0 9 2 1 1 1 0 7 3131 9 +120 2 2 17 180249 168836 123864 392 26510 0 0 0 1 0 0 3 121 0 1 1 0 1 320 320 4294967295 320 0 -47 0 0 0 9 2 1 1 1 0 7 3038 9 +121 2 2 18 1450247 1438831 1384449 18638 18253 0 0 0 1 0 0 3 122 0 1 1 0 1 18561 18561 4294967295 18561 0 -44 0 0 0 9 2 1 1 1 0 7 3043 9 +123 2 2 20 250239 238818 195224 7833 17715 0 0 0 1 0 0 3 124 0 1 1 0 1 7760 7760 4294967295 7760 0 -45 0 0 0 9 2 1 1 1 0 6 4341 9 +124 2 2 21 310247 298822 245864 22203 14695 0 0 0 1 0 0 3 125 0 1 1 0 1 22131 22131 4294967295 22131 0 -40 0 0 0 9 2 1 1 1 0 6 3040 9 +125 2 2 22 190244 178817 133904 492 26312 0 0 0 1 0 0 3 126 0 1 1 0 1 416 416 4294967295 416 0 -40 0 0 0 9 2 1 1 1 0 6 3142 9 +126 2 2 23 200251 188820 127242 449 46457 0 0 0 1 0 0 3 127 0 1 1 0 1 377 377 4294967295 377 0 -41 0 0 0 9 2 1 1 1 0 6 3036 9 +127 2 2 24 180238 168805 126791 6851 19937 0 0 0 1 0 0 3 128 0 1 1 0 1 6775 6775 4294967295 6775 0 -40 0 0 0 9 2 1 1 1 0 7 3084 9 +128 2 2 25 250248 238812 182053 9596 27050 0 0 0 1 0 0 3 129 0 1 1 0 1 9477 9477 4294967295 9477 0 -42 0 0 0 9 2 1 1 1 0 6 3206 9 +129 2 2 26 200249 188810 145005 12072 14831 0 0 0 1 0 0 3 130 0 1 1 0 1 12000 12000 4294967295 12000 0 -42 0 0 0 9 2 1 1 1 0 6 3038 9 +130 2 2 27 180238 168796 126738 5694 19803 0 0 0 1 0 0 3 131 0 1 1 0 1 5620 5620 4294967295 5620 0 -40 0 0 0 9 2 1 1 1 0 7 4418 9 +131 2 2 28 190249 178804 132286 2524 24375 0 0 0 1 0 0 3 132 0 1 1 0 1 2453 2453 4294967295 2453 0 -42 0 0 0 9 2 1 1 1 0 6 3039 9 +135 2 2 32 180245 168789 118203 4449 32450 0 0 0 1 0 0 3 136 0 1 0 1 0 4395 4294967295 4395 4395 0 -38 0 0 0 9 2 1 1 1 0 7 3037 9 +136 2 2 33 310251 298792 244613 8680 28212 0 0 0 1 0 0 3 137 0 1 1 0 1 8610 8610 4294967295 8610 0 -37 0 0 0 9 2 1 1 1 0 6 3043 9 +137 2 2 34 1360247 1348785 1315917 2945 13954 0 0 0 1 0 0 3 138 0 1 1 0 1 2869 2869 4294967295 2869 0 -37 0 0 0 9 2 1 1 1 0 7 3038 9 +138 2 2 35 220238 208773 170681 476 16325 0 0 0 1 0 0 3 139 0 1 1 0 1 400 400 4294967295 400 0 -37 0 0 0 9 2 1 1 1 0 7 3138 9 +139 2 2 36 1420249 1408781 1366352 172 26721 0 0 0 1 0 0 3 140 0 1 1 0 1 99 99 4294967295 99 0 -38 0 0 0 9 2 1 1 1 0 7 3043 9 +140 2 2 37 200244 188774 141831 159 26738 0 0 0 1 0 0 3 141 0 1 1 0 1 87 87 4294967295 87 0 -37 0 0 0 9 2 1 1 1 0 7 3037 9 +141 2 2 38 320251 308777 195300 10460 86237 0 0 0 1 0 0 3 142 0 1 1 0 1 10386 10386 4294967295 10386 0 -37 0 0 0 9 2 1 1 1 0 6 3156 9 +142 2 2 39 180242 168945 126565 3986 22376 0 0 0 1 0 0 3 143 0 1 1 0 1 3906 3906 4294967295 3906 0 -37 0 0 0 9 2 1 1 1 0 7 3084 9 +143 2 2 40 240251 228950 176475 160 36750 0 0 0 1 0 0 3 144 0 1 1 0 1 87 87 4294967295 87 0 -38 0 0 0 9 2 1 1 1 0 6 3033 9 +144 2 2 41 210247 198943 145993 17001 19899 0 0 0 1 0 0 3 145 0 1 1 0 1 16929 16929 4294967295 16929 0 -38 0 0 0 9 2 1 1 1 0 7 3038 9 +146 2 2 43 200245 188936 146766 4692 22206 0 0 0 1 0 0 3 147 0 1 0 1 0 4637 4294967295 4637 4637 0 -38 0 0 0 9 2 1 1 1 0 7 3038 9 +147 2 2 44 180240 168928 135474 4658 12220 0 0 0 1 0 0 3 148 0 1 1 0 1 4591 4591 4294967295 4591 0 -37 0 0 0 9 2 1 1 1 0 7 3051 9 +148 2 2 45 250237 238921 191568 6812 18693 0 0 0 1 0 0 3 149 0 1 1 0 1 6739 6739 4294967295 6739 0 -38 0 0 0 9 2 1 1 1 0 7 4335 9 +149 2 2 46 210246 198928 151070 13629 13271 0 0 0 1 0 0 3 150 0 1 1 0 1 13558 13558 4294967295 13558 0 -39 0 0 0 9 2 1 1 1 0 7 3038 9 +150 2 2 47 310250 298929 225078 17289 39365 0 0 0 1 0 0 3 151 0 1 1 0 1 17212 17212 4294967295 17212 0 -37 0 0 0 9 2 1 1 1 0 7 3207 9 +151 2 2 48 220244 208921 169589 540 16369 0 0 0 1 0 0 3 152 0 1 1 0 1 459 459 4294967295 459 0 -36 0 0 0 9 2 1 1 1 0 7 3039 9 +153 2 2 50 200248 188918 139214 2307 24576 0 0 0 1 0 0 3 154 0 1 0 1 0 2252 4294967295 2252 2252 0 -38 0 0 0 9 2 1 1 1 0 7 3049 9 +154 1 3 0 3309804 3309804 139214 2307 24576 0 0 0 1 0 0 3 155 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 3 2 2 1 -1 0 3049 0 +155 2 3 1 190247 178911 139812 159 16739 0 0 0 1 0 0 3 156 0 1 1 0 1 87 87 4294967295 87 0 -37 0 0 0 9 3 2 2 1 0 7 3038 9 +157 2 3 3 250251 238909 186350 159 36742 0 0 0 1 0 0 3 158 0 1 1 0 1 87 87 4294967295 87 0 -38 0 0 0 9 3 2 2 1 0 6 3041 9 +161 2 3 7 280238 268885 222361 8592 16903 0 0 0 1 0 0 3 162 0 1 1 0 1 8518 8518 4294967295 8518 0 -39 0 0 0 9 3 2 2 1 0 6 4420 9 +162 2 3 8 250240 238885 192009 6667 20198 0 0 0 1 0 0 3 163 0 1 1 0 1 6597 6597 4294967295 6597 0 -38 0 0 0 9 3 2 2 1 0 6 3057 9 +166 2 3 12 250238 238871 200675 381 16416 0 0 0 1 0 0 3 167 0 1 1 0 1 304 304 4294967295 304 0 -42 0 0 0 9 3 2 2 1 0 7 3144 9 +167 2 3 13 200250 188880 128532 1162 35733 0 0 0 1 0 0 3 168 0 1 1 0 1 1092 1092 4294967295 1092 0 -42 0 0 0 9 3 2 2 1 0 7 3040 9 +168 2 3 14 250244 238871 135365 48391 37220 0 0 0 1 0 0 3 169 0 1 1 0 1 48317 48317 4294967295 48317 0 -40 0 0 0 9 3 2 2 1 0 7 3100 9 +169 2 3 15 190242 178866 130864 2316 24548 0 0 0 1 0 0 3 170 0 1 1 0 1 2238 2238 4294967295 2238 0 -42 0 0 0 9 3 2 2 1 0 7 3080 9 +170 2 3 16 240234 228854 178809 6556 18927 0 0 0 1 0 0 3 171 0 1 1 0 1 6481 6481 4294967295 6481 0 -38 0 0 0 9 3 2 2 1 0 6 4425 9 +172 2 3 18 160241 148856 116894 3885 13009 0 0 0 1 0 0 3 173 0 1 0 1 0 3832 4294967295 3832 3832 0 -40 0 0 0 9 3 2 2 1 0 6 3037 9 +174 2 3 20 200247 188857 140510 3265 23636 0 0 0 1 0 0 3 175 0 1 0 1 0 3209 4294967295 3209 3209 0 -40 0 0 0 9 3 2 2 1 0 7 3037 9 +175 2 3 21 250242 238849 126088 50821 45975 0 0 0 1 0 0 3 176 0 1 1 0 1 50750 50750 4294967295 50750 0 -39 0 0 0 9 3 2 2 1 0 7 3036 9 +176 2 3 22 1390250 1378853 1320076 11384 25513 0 0 0 1 0 0 3 177 0 1 1 0 1 11307 11307 4294967295 11307 0 -41 0 0 0 9 3 2 2 1 0 7 3042 9 +177 2 3 23 210251 198851 152377 2989 23902 0 0 0 1 0 0 3 178 0 1 1 0 1 2919 2919 4294967295 2919 0 -38 0 0 0 9 3 2 2 1 0 7 3046 9 +178 2 3 24 220247 208844 146232 4357 42387 0 0 0 1 0 0 3 179 0 1 1 0 1 4285 4285 4294967295 4285 0 -41 0 0 0 9 3 2 2 1 0 7 3037 9 +179 2 3 25 230244 218838 168535 10363 15146 0 0 0 1 0 0 3 180 0 1 1 0 1 10290 10290 4294967295 10290 0 -39 0 0 0 9 3 2 2 1 0 7 4348 9 +180 2 3 26 230251 218842 148014 25845 31058 0 0 0 1 0 0 3 181 0 1 1 0 1 25775 25775 4294967295 25775 0 -39 0 0 0 9 3 2 2 1 0 6 3035 9 +182 2 3 28 190251 178837 146094 316 16585 0 0 0 1 0 0 3 183 0 1 1 0 1 244 244 4294967295 244 0 -41 0 0 0 9 3 2 2 1 0 7 3041 9 +183 2 3 29 270251 258834 207264 1088 35814 0 0 0 1 0 0 3 184 0 1 1 0 1 1016 1016 4294967295 1016 0 -41 0 0 0 9 3 2 2 1 0 7 3040 9 +184 2 3 30 210246 198827 147503 20067 16834 0 0 0 1 0 0 3 185 0 1 1 0 1 19995 19995 4294967295 19995 0 -40 0 0 0 9 3 2 2 1 0 6 3037 9 +185 2 3 31 200238 188816 128137 17641 27910 0 0 0 1 0 0 3 186 0 1 1 0 1 17562 17562 4294967295 17562 0 -39 0 0 0 9 3 2 2 1 0 7 4364 9 +186 2 3 32 190247 178821 134613 6533 20357 0 0 0 1 0 0 3 187 0 1 1 0 1 6461 6461 4294967295 6461 0 -41 0 0 0 9 3 2 2 1 0 7 3039 9 +188 2 3 34 190241 178809 124270 23794 13099 0 0 0 1 0 0 3 189 0 1 0 1 0 23742 4294967295 23742 23742 0 -41 0 0 0 9 3 2 2 1 0 7 3037 9 +189 2 3 35 180240 168805 126536 9065 17714 0 0 0 1 0 0 3 190 0 1 1 0 1 8994 8994 4294967295 8994 0 -39 0 0 0 9 3 2 2 1 0 6 3055 9 +190 2 3 36 240251 228814 139033 32746 34157 0 0 0 1 0 0 3 191 0 1 1 0 1 32674 32674 4294967295 32674 0 -39 0 0 0 9 3 2 2 1 0 6 3038 9 +191 2 3 37 220250 208810 141092 24145 22744 0 0 0 1 0 0 3 192 0 1 1 0 1 24075 24075 4294967295 24075 0 -42 0 0 0 9 3 2 2 1 0 6 3045 9 +192 2 3 38 210255 198812 145581 8264 28631 0 0 0 1 0 0 3 193 0 1 1 0 1 8194 8194 4294967295 8194 0 -39 0 0 0 9 3 2 2 1 0 7 3049 9 +193 2 3 39 200234 188788 151741 4042 11538 0 0 0 1 0 0 3 194 0 1 1 0 1 3966 3966 4294967295 3966 0 -41 0 0 0 9 3 2 2 1 0 7 3118 9 +194 2 3 40 250234 238785 192607 14373 12244 0 0 0 1 0 0 3 195 0 1 1 0 1 14298 14298 4294967295 14298 0 -39 0 0 0 9 3 2 2 1 0 7 3206 9 +195 2 3 41 250250 238798 193814 147 26525 0 0 0 1 0 0 3 196 0 1 1 0 1 76 76 4294967295 76 0 -39 0 0 0 9 3 2 2 1 0 7 3261 9 +196 2 3 42 300251 288796 232732 162 36730 0 0 0 1 0 0 3 197 0 1 1 0 1 92 92 4294967295 92 0 -39 0 0 0 9 3 2 2 1 0 6 3043 9 +197 2 3 43 190238 178780 139669 3327 13533 0 0 0 1 0 0 3 198 0 1 1 0 1 3249 3249 4294967295 3249 0 -45 0 0 0 9 3 2 2 1 0 7 3080 9 +198 2 3 44 260242 248782 203374 1566 25300 0 0 0 1 0 0 3 199 0 1 1 0 1 1487 1487 4294967295 1487 0 -43 0 0 0 9 3 2 2 1 0 7 3080 9 +199 2 3 45 190247 178783 133762 14112 12789 0 0 0 1 0 0 3 200 0 1 1 0 1 14040 14040 4294967295 14040 0 -39 0 0 0 9 3 2 2 1 0 7 3037 9 +200 2 3 46 180238 168771 130784 3378 13478 0 0 0 1 0 0 3 201 0 1 1 0 1 3301 3301 4294967295 3301 0 -41 0 0 0 9 3 2 2 1 0 7 3084 9 +201 2 3 47 250240 238771 195226 8340 18436 0 0 0 1 0 0 3 202 0 1 1 0 1 8270 8270 4294967295 8270 0 -41 0 0 0 9 3 2 2 1 0 7 3057 9 +203 2 3 49 250243 238793 188170 24031 12863 0 0 0 1 0 0 3 204 0 1 0 1 0 23978 4294967295 23978 23978 0 -43 0 0 0 9 3 2 2 1 0 6 3040 9 +204 2 3 50 180240 168941 125344 6742 18756 0 0 0 1 0 0 3 205 0 1 1 0 1 6669 6669 4294967295 6669 0 -43 0 0 0 9 3 2 2 1 0 6 4422 9 +205 1 4 0 3529804 3529804 125344 6742 18756 0 0 0 1 0 0 3 206 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 4 3 3 1 -1 0 4422 0 +206 2 4 1 200247 188939 133303 25613 11287 0 0 0 1 0 0 3 207 0 1 1 0 1 25543 25543 4294967295 25543 0 -41 0 0 0 9 4 3 3 1 0 6 3036 9 +207 2 4 2 180238 168930 130130 2982 13875 0 0 0 1 0 0 3 208 0 1 1 0 1 2906 2906 4294967295 2906 0 -39 0 0 0 9 4 3 3 1 0 7 3083 9 +208 2 4 3 280246 268934 201760 15694 31107 0 0 0 1 0 0 3 209 0 1 1 0 1 15618 15618 4294967295 15618 0 -41 0 0 0 9 4 3 3 1 0 7 3144 9 +210 2 4 5 220247 208931 136830 27051 29850 0 0 0 1 0 0 3 211 0 1 0 1 0 26995 4294967295 26995 26995 0 -41 0 0 0 9 4 3 3 1 0 7 3037 9 +212 2 4 7 240242 228920 180280 2783 24077 0 0 0 1 0 0 3 213 0 1 1 0 1 2707 2707 4294967295 2707 0 -39 0 0 0 9 4 3 3 1 0 7 3084 9 +213 2 4 8 200251 188925 133592 7479 29422 0 0 0 1 0 0 3 214 0 1 1 0 1 7407 7407 4294967295 7407 0 -40 0 0 0 9 4 3 3 1 0 7 3039 9 +214 2 4 9 210245 198917 166349 2050 14836 0 0 0 1 0 0 3 215 0 1 1 0 1 1980 1980 4294967295 1980 0 -41 0 0 0 9 4 3 3 1 0 7 3044 9 +215 2 4 10 190253 178921 118018 20391 26519 0 0 0 1 0 0 3 216 0 1 1 0 1 20320 20320 4294967295 20320 0 -40 0 0 0 9 4 3 3 1 0 6 3034 9 +217 2 4 12 180253 168915 127180 3925 22978 0 0 0 1 0 0 3 218 0 1 1 0 1 3853 3853 4294967295 3853 0 -43 0 0 0 9 4 3 3 1 0 7 3039 9 +218 2 4 13 270250 258910 215423 231 26671 0 0 0 1 0 0 3 219 0 1 1 0 1 159 159 4294967295 159 0 -41 0 0 0 9 4 3 3 1 0 7 3041 9 +219 2 4 14 190254 178911 137227 240 26662 0 0 0 1 0 0 3 220 0 1 1 0 1 168 168 4294967295 168 0 -39 0 0 0 9 4 3 3 1 0 7 3038 9 +220 2 4 15 160249 148903 114012 5229 11678 0 0 0 1 0 0 3 221 0 1 1 0 1 5157 5157 4294967295 5157 0 -39 0 0 0 9 4 3 3 1 0 6 3034 9 +222 2 4 17 300250 288898 231039 5303 31588 0 0 0 1 0 0 3 223 0 1 0 1 0 5252 4294967295 5252 5252 0 -41 0 0 0 9 4 3 3 1 0 7 3042 9 +223 2 4 18 210248 198893 151640 174 26735 0 0 0 1 0 0 3 224 0 1 1 0 1 93 93 4294967295 93 0 -39 0 0 0 9 4 3 3 1 0 7 3040 9 +224 2 4 19 250244 238887 174223 20037 25455 0 0 0 1 0 0 3 225 0 1 1 0 1 19964 19964 4294967295 19964 0 -40 0 0 0 9 4 3 3 1 0 7 4426 9 +229 2 4 24 260244 248873 144772 17220 69678 0 0 0 1 0 0 3 230 0 1 1 0 1 17149 17149 4294967295 17149 0 -41 0 0 0 9 4 3 3 1 0 7 3037 9 +230 2 4 25 230238 218864 179996 1566 15290 0 0 0 1 0 0 3 231 0 1 1 0 1 1490 1490 4294967295 1490 0 -39 0 0 0 9 4 3 3 1 0 7 3084 9 +231 2 4 26 260252 248874 197629 15184 21620 0 0 0 1 0 0 3 232 0 1 1 0 1 15106 15106 4294967295 15106 0 -41 0 0 0 9 4 3 3 1 0 6 3055 9 +232 2 4 27 210247 198866 159019 1788 15116 0 0 0 1 0 0 3 233 0 1 1 0 1 1716 1716 4294967295 1716 0 -42 0 0 0 9 4 3 3 1 0 6 3034 9 +233 2 4 28 280251 268868 214757 8960 26576 0 0 0 1 0 0 3 234 0 1 1 0 1 8885 8885 4294967295 8885 0 -41 0 0 0 9 4 3 3 1 0 7 4332 9 +234 2 4 29 230238 218852 181565 4135 12739 0 0 0 1 0 0 3 235 0 1 1 0 1 4068 4068 4294967295 4068 0 -41 0 0 0 9 4 3 3 1 0 7 3053 9 +236 2 4 31 210243 198852 153217 6942 19955 0 0 0 1 0 0 3 237 0 1 0 1 0 6889 4294967295 6889 6889 0 -43 0 0 0 9 4 3 3 1 0 7 3036 9 +237 2 4 32 180238 168844 133090 343 16520 0 0 0 1 0 0 3 238 0 1 1 0 1 264 264 4294967295 264 0 -42 0 0 0 9 4 3 3 1 0 7 3080 9 +238 2 4 33 200245 188847 140580 11557 15340 0 0 0 1 0 0 3 239 0 1 1 0 1 11487 11487 4294967295 11487 0 -41 0 0 0 9 4 3 3 1 0 6 3037 9 +239 2 4 34 180242 168842 131565 4852 11682 0 0 0 1 0 0 3 240 0 1 1 0 1 4775 4775 4294967295 4775 0 -41 0 0 0 9 4 3 3 1 0 6 3402 9 +240 2 4 35 220251 208847 140807 15800 31104 0 0 0 1 0 0 3 241 0 1 1 0 1 15729 15729 4294967295 15729 0 -42 0 0 0 9 4 3 3 1 0 7 3037 9 +241 2 4 36 270236 258829 215582 5067 20432 0 0 0 1 0 0 3 242 0 1 1 0 1 4989 4989 4294967295 4989 0 -41 0 0 0 9 4 3 3 1 0 7 4412 9 +242 2 4 37 300241 288831 184573 46327 40460 0 0 0 1 0 0 3 243 0 1 1 0 1 46258 46258 4294967295 46258 0 -39 0 0 0 9 4 3 3 1 0 7 3037 9 +244 2 4 39 210245 198830 140981 21374 15521 0 0 0 1 0 0 3 245 0 1 0 1 0 21321 4294967295 21321 21321 0 -39 0 0 0 9 4 3 3 1 0 6 3039 9 +245 2 4 40 180236 168817 129345 2236 14622 0 0 0 1 0 0 3 246 0 1 1 0 1 2158 2158 4294967295 2158 0 -41 0 0 0 9 4 3 3 1 0 7 3079 9 +246 2 4 41 330239 318817 194318 7343 98158 0 0 0 1 0 0 3 247 0 1 1 0 1 7265 7265 4294967295 7265 0 -41 0 0 0 9 4 3 3 1 0 6 4408 9 +247 2 4 42 270236 258811 214723 5038 20463 0 0 0 1 0 0 3 248 0 1 1 0 1 4960 4960 4294967295 4960 0 -41 0 0 0 9 4 3 3 1 0 6 4411 9 +248 2 4 43 250242 238815 189159 5058 21798 0 0 0 1 0 0 3 249 0 1 1 0 1 4982 4982 4294967295 4982 0 -41 0 0 0 9 4 3 3 1 0 6 3083 9 +249 2 4 44 210251 198821 138127 23152 23754 0 0 0 1 0 0 3 250 0 1 1 0 1 23082 23082 4294967295 23082 0 -41 0 0 0 9 4 3 3 1 0 6 3034 9 +250 2 4 45 270240 258807 213166 10049 16591 0 0 0 1 0 0 3 251 0 1 1 0 1 9980 9980 4294967295 9980 0 -41 0 0 0 9 4 3 3 1 0 7 3056 9 +251 2 4 46 250240 238804 195564 9334 17443 0 0 0 1 0 0 3 252 0 1 1 0 1 9264 9264 4294967295 9264 0 -39 0 0 0 9 4 3 3 1 0 7 3056 9 +252 2 4 47 190251 178812 136350 215 26691 0 0 0 1 0 0 3 253 0 1 1 0 1 140 140 4294967295 140 0 -44 0 0 0 9 4 3 3 1 0 7 3037 9 +253 2 4 48 190246 178805 133804 159 26743 0 0 0 1 0 0 3 254 0 1 1 0 1 87 87 4294967295 87 0 -39 0 0 0 9 4 3 3 1 0 7 3036 9 +254 2 4 49 250249 238805 153265 27659 39233 0 0 0 1 0 0 3 255 0 1 1 0 1 27590 27590 4294967295 27590 0 -41 0 0 0 9 4 3 3 1 0 7 3043 9 +255 2 4 50 200246 188801 142791 2077 24823 0 0 0 1 0 0 3 256 0 1 1 0 1 2006 2006 4294967295 2006 0 -40 0 0 0 9 4 3 3 1 0 7 3038 9 +256 1 5 0 3239804 3239804 142791 2077 24823 0 0 0 1 0 0 3 257 0 0 0 0 255 4294967295 4294967295 4294967295 4294967295 0 0 0 0 0 0 5 1 7 1 -1 0 3038 0 +258 2 5 2 300246 288790 249012 1911 14988 0 0 0 1 0 0 3 259 0 1 0 1 0 1857 4294967295 1857 1857 0 -42 0 0 0 9 5 1 7 1 0 7 3037 9 +259 2 5 3 200245 188787 146439 3514 23355 0 0 0 1 0 0 3 260 0 1 1 0 1 3431 3431 4294967295 3431 0 -41 0 0 0 9 5 1 7 1 0 7 3080 9 +260 2 5 4 230251 218789 149909 7484 39415 0 0 0 1 0 0 3 261 0 1 1 0 1 7412 7412 4294967295 7412 0 -39 0 0 0 9 5 1 7 1 0 7 3044 9 +261 2 5 5 260239 248774 189389 6299 30550 0 0 0 1 0 0 3 262 0 1 0 1 0 6241 4294967295 6241 6241 0 -41 0 0 0 9 5 1 7 1 0 6 3083 9 +262 2 5 6 230238 218770 174352 4580 20914 0 0 0 1 0 0 3 263 0 1 1 0 1 4506 4506 4294967295 4506 0 -39 0 0 0 9 5 1 7 1 0 6 4421 9 +263 2 5 7 200244 188774 139627 3235 23660 0 0 0 1 0 0 3 264 0 1 1 0 1 3163 3163 4294967295 3163 0 -39 0 0 0 9 5 1 7 1 0 6 3039 9 +264 2 5 8 230245 218772 128566 621 66242 0 0 0 1 0 0 3 265 0 1 1 0 1 542 542 4294967295 542 0 -40 0 0 0 9 5 1 7 1 0 7 3084 9 +266 2 5 10 190232 178932 139588 1397 15447 0 0 0 1 0 0 3 267 0 1 0 1 0 1337 4294967295 1337 1337 0 -41 0 0 0 9 5 1 7 1 0 7 3084 9 +267 2 5 11 260244 248941 194340 9478 26071 0 0 0 1 0 0 3 268 0 1 1 0 1 9402 9402 4294967295 9402 0 -41 0 0 0 9 5 1 7 1 0 7 4374 9 +272 2 5 16 180242 168789 126356 7317 18185 0 0 0 1 0 0 3 273 0 1 1 0 1 7244 7244 4294967295 7244 0 -41 0 0 0 9 5 1 7 1 0 6 4347 9 +273 2 5 17 240237 228782 180699 11888 14741 0 0 0 1 0 0 3 274 0 1 1 0 1 11816 11816 4294967295 11816 0 -41 0 0 0 9 5 1 7 1 0 6 3203 9 +280 2 5 24 180240 168764 133297 5200 11657 0 0 0 1 0 0 3 281 0 1 1 0 1 5125 5125 4294967295 5125 0 -40 0 0 0 9 5 1 7 1 0 7 3083 9 +282 2 5 26 200245 188763 153352 1677 15208 0 0 0 1 0 0 3 283 0 1 0 1 0 1621 4294967295 1621 1621 0 -46 0 0 0 9 5 1 7 1 0 7 3047 9 +283 2 5 27 200249 188763 132527 8961 27938 0 0 0 1 0 0 3 284 0 1 1 0 1 8889 8889 4294967295 8889 0 -41 0 0 0 9 5 1 7 1 0 6 3041 9 +284 2 5 28 270237 258750 212834 11701 14947 0 0 0 1 0 0 3 285 0 1 1 0 1 11624 11624 4294967295 11624 0 -40 0 0 0 9 5 1 7 1 0 7 3184 9 +286 2 5 30 180249 168755 115961 1078 35825 0 0 0 1 0 0 3 287 0 1 1 0 1 1006 1006 4294967295 1006 0 -39 0 0 0 9 5 1 7 1 0 7 3037 9 +287 2 5 31 280238 268741 218845 5427 20132 0 0 0 1 0 0 3 288 0 1 1 0 1 5351 5351 4294967295 5351 0 -38 0 0 0 9 5 1 7 1 0 6 4355 9 +288 2 5 32 330250 318750 272845 1987 24910 0 0 0 1 0 0 3 289 0 1 1 0 1 1914 1914 4294967295 1914 0 -39 0 0 0 9 5 1 7 1 0 7 3041 9 +289 2 5 33 1440244 1428742 1386530 7289 19601 0 0 0 1 0 0 3 290 0 1 1 0 1 7215 7215 4294967295 7215 0 -39 0 0 0 9 5 1 7 1 0 6 3043 9 +303 2 5 47 190237 178864 127071 9867 26750 0 0 0 1 0 0 3 304 0 1 0 1 0 9810 4294967295 9810 9810 0 -38 0 0 0 9 5 1 7 1 0 6 3213 9 +304 2 5 48 200251 188875 131517 2590 34315 0 0 0 1 0 0 3 305 0 1 1 0 1 2518 2518 4294967295 2518 0 -38 0 0 0 9 5 1 7 1 0 7 3037 9 +305 2 5 49 190244 178865 125867 6785 28735 0 0 0 1 0 0 3 306 0 1 1 0 1 6711 6711 4294967295 6711 0 -36 0 0 0 9 5 1 7 1 0 6 4403 9 +308 2 6 1 180247 168858 124763 16 26563 0 0 0 1 0 0 3 309 0 1 1 0 1 4294967295 4294967295 4294967295 4294967295 0 -37 0 0 0 9 6 7 1 1 0 6 3347 9 +309 2 6 2 210251 198861 148256 5565 31341 0 0 0 1 0 0 3 310 0 1 1 0 1 5492 5492 4294967295 5492 0 -39 0 0 0 9 6 7 1 1 0 7 3037 9 +310 2 6 3 220247 208854 144186 20400 26045 0 0 0 1 0 0 3 311 0 1 1 0 1 20321 20321 4294967295 20321 0 -37 0 0 0 9 6 7 1 1 0 7 3262 9 +311 2 6 4 220242 208847 159473 1308 25513 0 0 0 1 0 0 3 312 0 1 1 0 1 1232 1232 4294967295 1232 0 -38 0 0 0 9 6 7 1 1 0 7 3125 9 +312 2 6 5 260248 248850 192770 1096 35816 0 0 0 1 0 0 3 313 0 1 1 0 1 1018 1018 4294967295 1018 0 -37 0 0 0 9 6 7 1 1 0 7 3043 9 +313 2 6 6 240240 228839 166560 7156 38355 0 0 0 1 0 0 3 314 0 1 1 0 1 7079 7079 4294967295 7079 0 -38 0 0 0 9 6 7 1 1 0 7 4402 9 +314 2 6 7 230247 218842 160186 299 36582 0 0 0 1 0 0 3 315 0 1 1 0 1 87 87 4294967295 87 0 -48 0 0 0 9 6 7 1 1 0 6 3041 9 +315 2 6 8 210251 198843 135955 6871 40035 0 0 0 1 0 0 3 316 0 1 1 0 1 6799 6799 4294967295 6799 0 -48 0 0 0 9 6 7 1 1 0 7 3037 9 +316 2 6 9 280245 268834 213793 13923 22714 0 0 0 1 0 0 3 317 0 1 1 0 1 13847 13847 4294967295 13847 0 -40 0 0 0 9 6 7 1 1 0 6 3201 9 +318 2 6 11 410248 398832 278285 58869 47929 0 0 0 1 0 0 3 319 0 1 0 1 0 58815 4294967295 58815 58815 0 -40 0 0 0 9 6 7 1 1 0 7 3038 9 +319 2 6 12 190244 178825 120006 12031 24606 0 0 0 1 0 0 3 320 0 1 1 0 1 11959 11959 4294967295 11959 0 -49 0 0 0 9 6 7 1 1 0 7 3197 9 +321 2 6 14 230247 218823 145058 20728 36173 0 0 0 1 0 0 3 322 0 1 0 1 0 20675 4294967295 20675 20675 0 -46 0 0 0 9 6 7 1 1 0 7 3036 9 +323 2 6 16 230247 218817 151858 16483 30412 0 0 0 1 0 0 3 324 0 1 0 1 0 16430 4294967295 16430 16430 0 -47 0 0 0 9 6 7 1 1 0 7 3037 9 +324 2 6 17 270243 258810 215426 3898 22950 0 0 0 1 0 0 3 325 0 1 1 0 1 3819 3819 4294967295 3819 0 -43 0 0 0 9 6 7 1 1 0 7 3086 9 +325 2 6 18 250242 238808 196797 695 26107 0 0 0 1 0 0 3 326 0 1 1 0 1 619 619 4294967295 619 0 -46 0 0 0 9 6 7 1 1 0 7 3143 9 +326 2 6 19 200251 188811 126659 11052 35850 0 0 0 1 0 0 3 327 0 1 1 0 1 10977 10977 4294967295 10977 0 -44 0 0 0 9 6 7 1 1 0 7 3041 9 +327 2 6 20 200242 188800 132083 3595 33273 0 0 0 1 0 0 3 328 0 1 1 0 1 3514 3514 4294967295 3514 0 -46 0 0 0 9 6 7 1 1 0 7 3078 9 +328 2 6 21 250251 238805 142024 6457 70448 0 0 0 1 0 0 3 329 0 1 1 0 1 6385 6385 4294967295 6385 0 -45 0 0 0 9 6 7 1 1 0 7 3037 9 +329 2 6 22 240244 228797 164486 7842 39019 0 0 0 1 0 0 3 330 0 1 1 0 1 7768 7768 4294967295 7768 0 -45 0 0 0 9 6 7 1 1 0 7 3083 9 +330 2 6 23 200251 188800 129823 9539 27363 0 0 0 1 0 0 3 331 0 1 1 0 1 9468 9468 4294967295 9468 0 -45 0 0 0 9 6 7 1 1 0 7 3038 9 +331 2 6 24 300245 288791 209844 7969 47546 0 0 0 1 0 0 3 332 0 1 1 0 1 7891 7891 4294967295 7891 0 -44 0 0 0 9 6 7 1 1 0 7 4400 9 +332 2 6 25 240245 228788 162710 14354 32417 0 0 0 1 0 0 3 333 0 1 1 0 1 14278 14278 4294967295 14278 0 -41 0 0 0 9 6 7 1 1 0 6 3083 9 +333 2 6 26 200253 188793 130420 10758 26147 0 0 0 1 0 0 3 334 0 1 1 0 1 10686 10686 4294967295 10686 0 -45 0 0 0 9 6 7 1 1 0 7 3037 9 +334 2 6 27 250253 238790 194356 322 26589 0 0 0 1 0 0 3 335 0 1 1 0 1 250 250 4294967295 250 0 -48 0 0 0 9 6 7 1 1 0 7 3034 9 +338 2 6 31 210250 198775 149849 345 26544 0 0 0 1 0 0 3 339 0 1 1 0 1 275 275 4294967295 275 0 -43 0 0 0 9 6 7 1 1 0 7 3045 9 +339 2 6 32 230244 218768 151924 12229 34638 0 0 0 1 0 0 3 340 0 1 1 0 1 12149 12149 4294967295 12149 0 -44 0 0 0 9 6 7 1 1 0 7 3081 9 +340 2 6 33 190251 178771 120934 1027 35878 0 0 0 1 0 0 3 341 0 1 1 0 1 955 955 4294967295 955 0 -41 0 0 0 9 6 7 1 1 0 7 3038 9 +341 2 6 34 240251 228768 172371 1385 35506 0 0 0 1 0 0 3 342 0 1 1 0 1 1316 1316 4294967295 1316 0 -45 0 0 0 9 6 7 1 1 0 7 3046 9 +342 2 6 35 200242 188757 129969 291 36576 0 0 0 1 0 0 3 343 0 1 1 0 1 212 212 4294967295 212 0 -41 0 0 0 9 6 7 1 1 0 7 3079 9 +344 2 6 37 280242 268751 214643 921 35939 0 0 0 1 0 0 3 345 0 1 1 0 1 845 845 4294967295 845 0 -47 0 0 0 9 6 7 1 1 0 7 3084 9 +345 2 6 38 280249 268754 175198 6597 68912 0 0 0 1 0 0 3 346 0 1 1 0 1 6525 6525 4294967295 6525 0 -44 0 0 0 9 6 7 1 1 0 6 4352 9 +346 2 6 39 190251 178753 134286 159 26746 0 0 0 1 0 0 3 347 0 1 1 0 1 87 87 4294967295 87 0 -42 0 0 0 9 6 7 1 1 0 7 3038 9 +347 2 6 40 210251 198750 146526 7271 29635 0 0 0 1 0 0 3 348 0 1 1 0 1 7199 7199 4294967295 7199 0 -45 0 0 0 9 6 7 1 1 0 7 3036 9 +348 2 6 41 190242 178740 133393 4074 22786 0 0 0 1 0 0 3 349 0 1 1 0 1 3999 3999 4294967295 3999 0 -45 0 0 0 9 6 7 1 1 0 7 3084 9 +349 2 6 42 260240 248735 189514 738 36110 0 0 0 1 0 0 3 350 0 1 1 0 1 662 662 4294967295 662 0 -39 0 0 0 9 6 7 1 1 0 7 3092 9 +350 2 6 43 220251 208742 164105 159 26742 0 0 0 1 0 0 3 351 0 1 1 0 1 87 87 4294967295 87 0 -40 0 0 0 9 6 7 1 1 0 7 3041 9 +351 2 6 44 210251 198739 142341 1326 35582 0 0 0 1 0 0 3 352 0 1 1 0 1 1254 1254 4294967295 1254 0 -43 0 0 0 9 6 7 1 1 0 6 3034 9 +353 2 6 46 190249 178732 122374 10920 25978 0 0 0 1 0 0 3 354 0 1 0 1 0 10867 4294967295 10867 10867 0 -40 0 0 0 9 6 7 1 1 0 6 3041 9 +354 2 6 47 290242 278722 209995 5241 40247 0 0 0 1 0 0 3 355 0 1 1 0 1 5166 5166 4294967295 5166 0 -40 0 0 0 9 6 7 1 1 0 6 4426 9 +355 2 6 48 310244 298721 176969 5603 99935 0 0 0 1 0 0 3 356 0 1 1 0 1 5526 5526 4294967295 5526 0 -42 0 0 0 9 6 7 1 1 0 6 4383 9 +356 2 6 49 200253 188727 138553 325 26565 0 0 0 1 0 0 3 357 0 1 1 0 1 255 255 4294967295 255 0 -42 0 0 0 9 6 7 1 1 0 7 3050 9 diff --git a/experiments/prepared_message_e2e.tsv b/experiments/prepared_message_e2e.tsv new file mode 100644 index 0000000..85e710e --- /dev/null +++ b/experiments/prepared_message_e2e.tsv @@ -0,0 +1,28 @@ +metric value +registration_ms 1048 +full_cycle_ms 11715 +prepared_message_ms_1 15090 +prepared_message_ms_2 2250 +prepared_message_ms_3 2250 +prepared_message_ms_4 2190 +prepared_message_ms_5 2340 +prepared_message_ms_6 2390 +prepared_message_ms_7 2240 +prepared_message_ms_8 2290 +prepared_message_ms_9 2340 +prepared_message_ms_10 2230 +prepared_min_ms 2190 +prepared_median_ms 2250 +prepared_p90_ms 2340 +prepared_max_ms 2390 +prepared_completed_esp 9 +prepared_completed_receiver 9 +receiver_full 1 +receiver_prepared 9 +receiver_missing 1 +receiver_duplicates 0 +bench_client_id prepared_message_bench_v6 +receiver_uid fd4e309f-1619-4cbb-ada7-c69134901490 +sender_uid bb28fcdf-3872-4214-adb1-9ee63f05f85e +prepared_block_reserved 10 +prepared_block_remaining 1 diff --git a/experiments/prepared_message_receiver/CMakeLists.txt b/experiments/prepared_message_receiver/CMakeLists.txt new file mode 100644 index 0000000..ed02ffc --- /dev/null +++ b/experiments/prepared_message_receiver/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright 2026 Aethernet Inc. +cmake_minimum_required(VERSION 3.16) +project(prepared_message_receiver LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(USER_CONFIG "${CMAKE_CURRENT_LIST_DIR}/user_config.h" CACHE PATH "" FORCE) +set(AE_DISTILLATION OFF CACHE BOOL "" FORCE) +set(AE_FILTRATION ON CACHE BOOL "" FORCE) +set(AE_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) +set(AE_BUILD_TESTS OFF CACHE BOOL "" FORCE) + +include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/CPM.cmake") +# Pin exact SHA. Override locally with -DCPM_aether-client-cpp_SOURCE=. +CPMAddPackage(URI "https://github.com/aethernetio/aether-client-cpp.git#157aadbec8e7b852d0f89274307ff7cb8103e5f7") + +if(TARGET aether AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(aether PRIVATE -Wno-error -Wno-cpp) +endif() + +add_executable(prepared_message_receiver main.cpp) +target_compile_definitions(prepared_message_receiver PRIVATE + "USER_CONFIG=\"${CMAKE_CURRENT_LIST_DIR}/user_config.h\"") +target_link_libraries(prepared_message_receiver PRIVATE aether) diff --git a/experiments/prepared_message_receiver/main.cpp b/experiments/prepared_message_receiver/main.cpp new file mode 100644 index 0000000..d898fc1 --- /dev/null +++ b/experiments/prepared_message_receiver/main.cpp @@ -0,0 +1,191 @@ +/* + * Copyright 2026 Aethernet Inc. + * + * Desktop Æther console receiver for prepared-message E2E bench. + * Expects UTF-8 payloads: FULL:0 and PREPARED:1..10 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) +# include +#endif + +#include "aether/all.h" + +using namespace std::chrono_literals; + +namespace { + +static constexpr auto kParentUid = + ae::Uid::FromString("b1ac52c8-8d94-bd39-4c01-a631ac594165"); +static constexpr char const* kClientName = "prepared_message_bench_rx_v1"; +static constexpr int kExpectedPrepared = 10; + +std::mutex g_mu; +std::vector> g_streams; + +bool g_full_seen = false; +std::array g_prepared_hits{}; // 1..10 +int g_prepared_unique = 0; +int g_duplicates = 0; +std::vector g_order; + +std::int64_t NowMs() { + return std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count(); +} + +void PrintSummary() { + int missing = 0; + std::string missing_list; + for (int i = 1; i <= kExpectedPrepared; ++i) { + if (g_prepared_hits[static_cast(i)] == 0) { + ++missing; + if (!missing_list.empty()) { + missing_list += ","; + } + missing_list += std::to_string(i); + } + } + std::cout << "RECEIVER\n"; + std::cout << " full=" << (g_full_seen ? 1 : 0) << "/1\n"; + std::cout << " prepared=" << g_prepared_unique << "/" << kExpectedPrepared + << "\n"; + std::cout << " missing=" << missing; + if (missing > 0) { + std::cout << " [" << missing_list << "]"; + } + std::cout << "\n"; + std::cout << " duplicates=" << g_duplicates << "\n"; + std::cout << " order="; + for (size_t i = 0; i < g_order.size(); ++i) { + if (i > 0) { + std::cout << ","; + } + std::cout << g_order[i]; + } + std::cout << "\n"; + std::cout.flush(); +} + +void OnMessage(ae::Uid sender, ae::DataBuffer const& data) { + auto text = std::string_view{reinterpret_cast(data.data()), + data.size()}; + auto const ts = NowMs(); + auto const sender_text = ae::Format("{}", sender); + + std::lock_guard lock{g_mu}; + if (text == "FULL:0") { + if (g_full_seen) { + ++g_duplicates; + } + g_full_seen = true; + g_order.emplace_back("FULL:0"); + std::cout << ae::Format( + "RECV sender={} sequence=0 type=FULL receive_ts_ms={}\n", sender_text, + ts); + } else if (text.rfind("PREPARED:", 0) == 0) { + auto const seq_sv = text.substr(std::string_view{"PREPARED:"}.size()); + int seq = 0; + try { + seq = std::stoi(std::string{seq_sv}); + } catch (...) { + seq = -1; + } + if (seq >= 1 && seq <= kExpectedPrepared) { + if (g_prepared_hits[static_cast(seq)] > 0) { + ++g_duplicates; + } else { + ++g_prepared_unique; + } + ++g_prepared_hits[static_cast(seq)]; + g_order.emplace_back(std::string{text}); + } + std::cout << ae::Format( + "RECV sender={} sequence={} type=PREPARED receive_ts_ms={}\n", + sender_text, seq, ts); + } else { + std::cout << ae::Format( + "RECV sender={} sequence=? type=UNKNOWN receive_ts_ms={} text={}\n", + sender_text, ts, text); + } + std::cout.flush(); + + if (g_full_seen && g_prepared_unique == kExpectedPrepared) { + PrintSummary(); + } +} + +std::filesystem::path ResolveSessionRoot() { +#if defined(_WIN32) + if (char const* env = std::getenv("AE_RECEIVER_SESSION_DIR")) { + return std::filesystem::path{env}; + } +#endif + return std::filesystem::current_path(); +} + +} // namespace + +int main() { + std::cout.setf(std::ios::unitbuf); +#if defined(_WIN32) + setvbuf(stdout, nullptr, _IONBF, 0); +#endif + auto const session_root = ResolveSessionRoot(); + std::filesystem::create_directories(session_root / "state"); + std::filesystem::current_path(session_root); + std::cerr << ae::Format("receiver_session_dir={}\n", session_root.string()); + std::cerr.flush(); + + auto aether_app = ae::AetherApp::Construct(ae::AetherAppContext{}); + ae::Client::ptr client; + aether_app->aether() + ->SelectClient(kParentUid, kClientName) + .result_event() + .Subscribe([&](ae::Result const& res) { + if (!res) { + std::cerr << "SelectClient failed\n"; + aether_app->Exit(1); + return; + } + client = res.value(); + std::cout << ae::Format("RECEIVER_UID={}\n", client->uid()); + std::cout.flush(); + client->connectivity_policy()->ResetRxTimings(); + client->connectivity_policy() + ->ConfigureRxTimings(ae::RequestPolicy::All{}) + .ForAllPriorities(ae::RxTimingConf::Every(1s).WithWindow(1s)); + client->message_stream_manager().new_port_event().Subscribe( + [&](ae::P2pPortHandle handle) { + auto sender = handle.destination(); + auto stream = std::make_unique( + *aether_app, client.Load(), sender, std::move(handle)); + stream->out_data_event().Subscribe( + [sender](auto const& d) { OnMessage(sender, d); }); + std::lock_guard lock{g_mu}; + g_streams.push_back(std::move(stream)); + }); + }); + + while (!aether_app->IsExited()) { + auto next = aether_app->Update(ae::Now()); + aether_app->WaitUntil(next); + } + { + std::lock_guard lock{g_mu}; + PrintSummary(); + } + return aether_app->ExitCode(); +} diff --git a/experiments/prepared_message_receiver/user_config.h b/experiments/prepared_message_receiver/user_config.h new file mode 100644 index 0000000..da553dd --- /dev/null +++ b/experiments/prepared_message_receiver/user_config.h @@ -0,0 +1,22 @@ +/* + * Copyright 2026 Aethernet Inc. + */ +#ifndef USER_CONFIG_H_ +#define USER_CONFIG_H_ + +#include "aether/config_consts.h" + +#define AE_CRYPTO_ASYNC AE_HYDRO_CRYPTO_PK +#define AE_CRYPTO_SYNC AE_HYDRO_CRYPTO_SK +#define AE_SIGNATURE AE_HYDRO_SIGNATURE +#define AE_KDF AE_HYDRO_KDF + +#define AE_TELE_ENABLED 1 +#define AE_TELE_LOG_CONSOLE 1 +#if defined NDEBUG +# define AE_TELE_DEBUG_MODULES 0 +#else +# define AE_TELE_DEBUG_MODULES AE_ALL +#endif + +#endif // USER_CONFIG_H_ diff --git a/experiments/prepared_message_receiver_uid.txt b/experiments/prepared_message_receiver_uid.txt new file mode 100644 index 0000000..7229664 --- /dev/null +++ b/experiments/prepared_message_receiver_uid.txt @@ -0,0 +1 @@ +fd4e309f-1619-4cbb-ada7-c69134901490 diff --git a/experiments/prepared_static_arp_5x20.tsv b/experiments/prepared_static_arp_5x20.tsv new file mode 100644 index 0000000..2326770 --- /dev/null +++ b/experiments/prepared_static_arp_5x20.tsv @@ -0,0 +1,18 @@ +metric before_669ccdc after_static_arp hold600_control +prepared_delivery 44/100 29/100 6/20 +full_delivery 5/5 6/5 (dup) 1/1 +warm_median_us 640476 650477 ~ +first_prepared_median_us 15100453 730476 ~ +used_static_arp_hits 0 32 6 +arp_fallback_hits 0 0 0 +wifi_fallback_hits 0 0 0 +bssid_hits 46 32 6 +static_ip_hits 46 32 6 +dhcp_skipped_hits 46 32 6 +missing 56 71 14 +duplicates 0 1 0 +out_of_order 0 0 0 +post_send_hold_ms 300 300 600 +registration_us 13962906 251137 253771 +full_median_us 4124003 3471545 3437457 +aether_sha 157aadbec8e7b852d0f89274307ff7cb8103e5f7 157aadbec8e7b852d0f89274307ff7cb8103e5f7 157aadbec8e7b852d0f89274307ff7cb8103e5f7 diff --git a/experiments/prepared_wifi_cache_5x20.tsv b/experiments/prepared_wifi_cache_5x20.tsv new file mode 100644 index 0000000..79a2b8d --- /dev/null +++ b/experiments/prepared_wifi_cache_5x20.tsv @@ -0,0 +1,38 @@ +metric value +registration_us 13962906 +full_us_1 5637828 +full_us_2 4124003 +full_us_3 4014012 +full_us_4 4104022 +full_us_5 4184009 +full_min_us 4014012 +full_median_us 4124003 +full_max_us 5637828 +first_prepared_us 15100453 +warm_prepared_n 46 +warm_prepared_min_us 610471 +warm_prepared_median_us 640476 +warm_prepared_p90_us 690482 +warm_prepared_p99_us 730476 +warm_prepared_max_us 730476 +all_prepared_n 47 +all_prepared_min_us 610471 +all_prepared_median_us 640476 +all_prepared_p90_us 690531 +all_prepared_p99_us 15100453 +all_prepared_max_us 15100453 +delivery_full 5/5 +delivery_prepared 44/100 +delivery_final 1/1 +delivery_missing 56 +delivery_duplicates 0 +delivery_out_of_order 0 +cache_bssid_hits 46 +cache_static_ip_hits 46 +cache_dhcp_skip_hits 46 +cache_fallbacks 0 +post_send_hold_ms 300 +receiver_uid 5aade50f-00d9-4624-b097-e203cdcf1e38 +bench_client_id prepared_wifi_cache_5x20_v1 +aether_sha 157aadbec8e7b852d0f89274307ff7cb8103e5f7 +warm_prepared_raw_us 640479 630478 630470 650471 650469 650471 640475 640476 640471 620471 660484 630474 640472 640470 630470 640477 670485 730467 630481 650412 680482 610471 650477 630471 630478 680473 620470 620475 650478 630477 690531 630479 650513 640481 640414 630477 690482 630481 730472 630485 640474 630472 670477 730476 680475 660470 diff --git a/experiments/prepared_wifi_cache_receiver_uid.txt b/experiments/prepared_wifi_cache_receiver_uid.txt new file mode 100644 index 0000000..df6bc95 --- /dev/null +++ b/experiments/prepared_wifi_cache_receiver_uid.txt @@ -0,0 +1 @@ +5aade50f-00d9-4624-b097-e203cdcf1e38 diff --git a/experiments/prepared_wifi_callback_wpa2.tsv b/experiments/prepared_wifi_callback_wpa2.tsv new file mode 100644 index 0000000..27eaccc --- /dev/null +++ b/experiments/prepared_wifi_callback_wpa2.tsv @@ -0,0 +1,14 @@ +name test_id n delivered plan connect_med txdone_med teardown_med cycle_med p90 max wifi_ready encode sendto nonce pre post_mode auth cb_seen cb_timeout missing duplicates ooo samples +VAL20_PRE200 101 20 19 20 127 1 77 420 440 490 20 20 20 20 200 1 3 20 0 1 0 0 19 +VAL100_PRE200 102 100 100 100 127 2 86 420 490 680 100 100 100 100 200 1 3 100 0 0 0 0 100 +VAL200_PRE200 103 200 189 200 127 1 97 430 490 780 200 200 200 200 200 1 3 200 0 11 0 0 189 +PRE150_S20 140 20 20 20 115 4 76 350 420 500 20 20 20 20 150 1 3 20 0 0 0 0 20 +PRE100_S20 130 20 20 20 128 0 85 320 350 390 20 20 20 20 100 1 3 20 0 0 0 0 20 +PRE75_S20 125 20 20 20 134 4 76 280 320 430 20 20 20 20 75 1 3 20 0 0 0 0 20 +PRE50_S20 120 20 16 20 133 6 71 270 330 390 20 20 20 20 50 1 3 20 0 4 0 0 16 +PRE25_S20 115 20 20 20 114 1 92 230 290 640 20 20 20 20 25 1 3 20 0 0 0 0 20 +PRE0_S20 110 20 3 20 126 0 59 220 230 240 20 20 20 20 0 1 3 20 0 17 0 0 4 +PRE25_N50 201 50 37 50 128 13 59 230 250 310 50 50 50 50 25 1 3 50 0 13 0 0 37 +PRE25_VAL200 202 200 182 200 131 20 58 230 270 390 200 200 200 200 25 1 3 200 0 18 0 0 182 +PRE10_N50 203 50 21 50 143 0 61 220 250 290 50 50 50 50 10 1 3 50 0 29 0 0 22 +PRE0_N50 204 50 7 50 130 0 85 220 250 1060 50 50 50 50 0 1 3 49 1 43 0 0 8 diff --git a/experiments/prepared_wifi_fastest_path.tsv b/experiments/prepared_wifi_fastest_path.tsv new file mode 100644 index 0000000..fa49715 --- /dev/null +++ b/experiments/prepared_wifi_fastest_path.tsv @@ -0,0 +1,38 @@ +Variant Association Auth PRE POST Delivered N ConnectMed CycleMed p90 max WifiReady Encode Sendto CbAny CbMatch PostMode +BASE 0x1a 7 200 300 20/20 20 262 840 920 960 20 20 20 0 0 0 +A1_BSSID 0x1b 7 200 300 19/20 20 278 840 870 920 20 20 20 0 0 0 +A2_FAST_SCAN 0x1e 7 200 300 20/20 20 270 850 880 1010 20 20 20 0 0 0 +A3_BSSID_FAST_SCAN 0x1f 7 200 300 19/20 20 276 860 880 890 20 20 20 0 0 0 +AUTH2_H2E 0x1a 7 200 300 18/20 20 269 840 910 950 20 20 20 0 0 0 +AUTH3_WPA2 0x1a 7 200 300 20/20 20 258 850 920 940 20 20 20 0 0 0 +AUTH3B_WPA3SAE_OFF 0x1a 7 200 300 20/20 20 253 830 900 940 20 20 20 0 0 0 +AUTH3B_WPA3SAE_OFF_VERIFIED 0x1a 3 200 300 20/20 20 128 710 810 910 20 20 20 0 0 0 +R0 0x1a 3 200 300 20/20 20 149 730 760 760 20 20 20 0 0 0 +R1 0x1a 3 200 300 20/20 20 149 720 750 780 20 20 20 0 0 0 +R3 0x1a 3 200 300 20/20 20 153 740 750 830 20 20 20 0 0 0 +CB0 0x9a 3 200 0 18/20 20 154 530 550 590 20 20 20 18 0 1 +PRE_200 0x1a 3 200 300 13/20 20 151 740 750 760 20 20 20 0 0 0 +PRE_200 0x1a 3 200 300 19/20 20 144 730 750 760 20 20 20 0 0 0 +PRE_200_R 0x1a 3 200 300 20/20 20 123 700 750 760 20 20 20 0 0 0 +PRE_150 0x1a 3 150 300 14/20 20 124 640 670 740 20 20 20 0 0 0 +POST_300 0x1a 3 200 300 20/20 20 120 700 740 780 20 20 20 0 0 0 +POST_250 0x1a 3 200 250 20/20 20 121 640 690 700 20 20 20 0 0 0 +POST_200 0x1a 3 200 200 20/20 20 132 620 650 790 20 20 20 0 0 0 +POST_150 0x1a 3 200 150 19/20 20 124 540 550 580 20 20 20 0 0 0 +POST_150_R 0x1a 3 200 150 20/20 20 125 550 580 590 20 20 20 0 0 0 +POST_100 0x1a 3 200 100 13/20 20 113 490 510 570 20 20 20 0 0 0 +2D_p175_q175 0x1a 3 175 175 18/20 20 127 530 550 560 20 20 20 0 0 0 +2D_p225_q125 0x1a 3 225 125 19/20 20 127 530 550 580 20 20 20 0 0 0 +2D_p150_q200 0x1a 3 150 200 20/20 20 125 540 580 600 20 20 20 0 0 0 +VAL100_PRIMARY 0x1a 3 200 150 94/100 100 131 560 620 900 100 100 100 0 0 0 +VAL100_SECONDARY 0x1a 3 150 200 97/100 100 131 560 610 650 100 100 100 0 0 0 +VAL100_SAFE_200_300 0x1a 3 200 300 98/100 100 138 730 770 930 100 100 100 0 0 0 +VAL100_SAFE_200_300_R 0x1a 3 200 300 96/100 100 124 720 750 840 100 100 100 0 0 0 +VAL100_MID_200_200 0x1a 3 200 200 91/100 100 125 620 660 790 100 100 100 0 0 0 +VAL100_FAST_200_150 0x1a 3 200 150 79/100 100 122 560 600 1210 100 100 100 0 0 0 +VAL100_FAST_150_200 0x1a 3 150 200 84/100 100 118 540 580 690 100 100 100 0 0 0 +VAL200 0x1a 3 200 300 198/200 200 125 710 750 870 200 200 200 0 0 0 +D1_AMPDU_TX_OFF 0x3a 3 200 300 198/200 200 125 710 750 870 20 20 20 0 0 0 +STORAGE_RAM 0x5a 3 200 300 198/200 200 125 710 750 870 20 20 20 0 0 0 +D1_AMPDU_TX_OFF_RERUN 0x3a 3 200 300 17/20 20 122 710 750 770 20 20 20 0 0 0 +STORAGE_RAM_RERUN 0x5a 3 200 300 19/20 20 112 670 720 770 20 20 20 0 0 0 diff --git a/experiments/recapture_full_loop.py b/experiments/recapture_full_loop.py new file mode 100644 index 0000000..037c781 --- /dev/null +++ b/experiments/recapture_full_loop.py @@ -0,0 +1,142 @@ +"""Restart receiver, hard-reset ESP, wait for FULL_DIAG / HOT.""" + +from __future__ import annotations + +import os +import re +import subprocess +import time +from pathlib import Path + +ROOT = Path(r"C:\Users\nickc\Projects\temperature-sensor-prepared") +PY = Path(r"C:\Espressif\python_env\idf6.0_py3.11_env\Scripts\python.exe") +RX_EXE = ROOT / "temperature_receiver" / "build-bisect" / "temperature_receiver.exe" +RX_SESSION = ROOT / "experiments" / "prepared_wifi_cache_rx_session" +RX_LOG = ROOT / "experiments" / "full_loop_diag_rx.log" +TSV = ROOT / "experiments" / "full_loop_diag.tsv" +PROGRESS = ROOT / "experiments" / "full_loop_diag_progress.log" +PORT = "COM7" +CCACHE = r"C:\Espressif\tools\ccache\4.12.1\ccache-4.12.1-windows-x86_64" + + +def env() -> dict: + e = os.environ.copy() + e["IDF_PATH"] = r"C:\Espressif\frameworks\esp-idf-v6.0.2" + e["IDF_TOOLS_PATH"] = r"C:\Espressif" + e["Path"] = ( + CCACHE + + r";C:\Espressif\tools\ninja\1.12.1;C:\Espressif\tools\cmake\3.30.2\bin;C:\msys64\ucrt64\bin;" + + e.get("Path", "") + ) + return e + + +def log(msg: str) -> None: + line = time.strftime("%H:%M:%S") + " " + msg + print(line, flush=True) + with PROGRESS.open("a", encoding="utf-8") as f: + f.write(line + "\n") + + +def kill_receiver() -> None: + subprocess.run( + ["taskkill", "/F", "/IM", "temperature_receiver.exe"], + capture_output=True, + text=True, + ) + time.sleep(2) + + +def start_receiver() -> None: + kill_receiver() + if TSV.exists(): + TSV.unlink() + RX_SESSION.mkdir(parents=True, exist_ok=True) + env2 = env() + env2["AE_RECEIVER_SESSION_DIR"] = str(RX_SESSION) + env2["AE_DS_TSV"] = str(TSV) + with RX_LOG.open("w", encoding="utf-8") as outf, ( + ROOT / "experiments" / "full_loop_diag_rx.log.err" + ).open("w", encoding="utf-8") as errf: + subprocess.Popen( + [str(RX_EXE)], + cwd=str(RX_SESSION), + env=env2, + stdout=outf, + stderr=errf, + ) + time.sleep(8) + log("receiver restarted") + + +def hard_reset() -> None: + # esptool hard_reset via chip_id (cheap) then flash stub exit + cmd = [ + str(PY), + "-m", + "esptool", + "--chip", + "esp32c6", + "-p", + PORT, + "run", + ] + r = subprocess.run(cmd, env=env(), capture_output=True, text=True) + log(f"esptool run rc={r.returncode}") + if r.returncode != 0: + # fallback: chip_id triggers reset on many boards + r2 = subprocess.run( + [ + str(PY), + "-m", + "esptool", + "--chip", + "esp32c6", + "-p", + PORT, + "chip-id", + ], + env=env(), + capture_output=True, + text=True, + ) + log(f"esptool chip-id rc={r2.returncode}") + + +def wait_capture(timeout_s: float = 240.0) -> None: + t0 = time.time() + last = (0, 0) + while time.time() - t0 < timeout_s: + text = RX_LOG.read_text(encoding="utf-8", errors="replace") if RX_LOG.exists() else "" + fulls = re.findall(r"^FULL_DIAG .+$", text, re.M) + hots = re.findall(r"^RECV HOT .+$", text, re.M) + nf, nh = len(fulls), len(hots) + if (nf, nh) != last: + last = (nf, nh) + log(f"progress full={nf} hot={nh}") + if fulls: + log(" " + fulls[-1][:260]) + if hots: + log(" " + hots[-1][:200]) + if nh >= 3: + log(f"STOP ok FULL={nf} HOT={nh}") + return + if nf >= 3 and nh == 0: + log(f"STOP diag-only FULL={nf}") + return + # also stop after 1 FULL with clear reason if still no HOT after another ~20s + time.sleep(1.0) + log(f"TIMEOUT FULL={last[0]} HOT={last[1]}") + + +def main() -> None: + log("=== recapture after hard reset ===") + start_receiver() + # Give receiver time to reach cloud before ESP boots/sends + time.sleep(10) + hard_reset() + wait_capture() + + +if __name__ == "__main__": + main() diff --git a/experiments/run_boot_wifi_opt.py b/experiments/run_boot_wifi_opt.py new file mode 100644 index 0000000..f79bf4a --- /dev/null +++ b/experiments/run_boot_wifi_opt.py @@ -0,0 +1,323 @@ +""" +One-flash boot/Wi-Fi HOT opt campaign orchestrator. +COM only for flash; after FLASH_OK never touch serial. +Progress = receiver TSV/log only. +""" + +from __future__ import annotations + +import os +import re +import subprocess +import sys +import time +from pathlib import Path + +ROOT = Path(r"C:\Users\nickc\Projects\temperature-sensor-prepared") +BUILD = ROOT / "build-esp32c6-save-bench-smoke" +AETHER = r"C:/Users/nickc/Projects/aether-client-cpp-prepared-packet-v0" +PY = Path(r"C:\Espressif\python_env\idf6.0_py3.11_env\Scripts\python.exe") +CMAKE = Path(r"C:\Espressif\tools\cmake\3.30.2\bin\cmake.exe") +NINJA = Path(r"C:\Espressif\tools\ninja\1.12.1\ninja.exe") +RX_EXE = ROOT / "temperature_receiver" / "build-bisect" / "temperature_receiver.exe" +RX_BUILD = ROOT / "temperature_receiver" / "build-bisect" +RX_SESSION = ROOT / "experiments" / "prepared_wifi_cache_rx_session" +IDF_PATH = r"C:\Espressif\frameworks\esp-idf-v6.0.2" +CCACHE = r"C:\Espressif\tools\ccache\4.12.1\ccache-4.12.1-windows-x86_64" +PROGRESS = ROOT / "experiments" / "boot_wifi_opt_progress.log" +RX_LOG = ROOT / "experiments" / "prepared_boot_wifi_opt_rx.log" +TSV = ROOT / "experiments" / "prepared_boot_wifi_opt.tsv" +PORT = "COM7" +VARIANTS = 11 +HOT_PER = 30 + + +def env() -> dict: + e = os.environ.copy() + e["IDF_PATH"] = IDF_PATH + e["IDF_TOOLS_PATH"] = r"C:\Espressif" + extra = [ + CCACHE, + r"C:\Espressif\tools\ninja\1.12.1", + r"C:\Espressif\tools\cmake\3.30.2\bin", + r"C:\msys64\ucrt64\bin", + ] + e["Path"] = ";".join(extra) + ";" + e.get("Path", "") + e.pop("CCACHE_DISABLE", None) + return e + + +def log(msg: str) -> None: + line = time.strftime("%H:%M:%S") + " " + msg + print(line, flush=True) + with PROGRESS.open("a", encoding="utf-8") as f: + f.write(line + "\n") + + +def force_sdk_fixes() -> None: + sdk = BUILD / "sdkconfig" + if not sdk.exists(): + return + text = sdk.read_text(encoding="utf-8") + reps = [ + ("CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y", "# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set"), + ("CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y", "# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set"), + ("CONFIG_RTC_CLK_SRC_INT_RC=y", "# CONFIG_RTC_CLK_SRC_INT_RC is not set"), + ("# CONFIG_RTC_CLK_SRC_EXT_CRYS is not set", "CONFIG_RTC_CLK_SRC_EXT_CRYS=y"), + ("CONFIG_ESP_BROWNOUT_DET=n", "CONFIG_ESP_BROWNOUT_DET=y"), + ("# CONFIG_ESP_BROWNOUT_DET is not set", "CONFIG_ESP_BROWNOUT_DET=y"), + ("CONFIG_PM_ENABLE=y", "# CONFIG_PM_ENABLE is not set"), + ] + for a, b in reps: + text = text.replace(a, b) + if "CONFIG_RTC_CLK_SRC_EXT_CRYS=y" not in text: + text += "\nCONFIG_RTC_CLK_SRC_EXT_CRYS=y\n" + # A4 CONFIG_RTC_CLK_CAL_CYCLES=0: first flash with forced 0 left COM awake + # and produced zero Aether telemetry; keep IDF effective default (1024). + if "CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y" not in text: + text += "\nCONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y\n" + sdk.write_text(text, encoding="utf-8") + + +def kill_receiver() -> None: + subprocess.run( + ["taskkill", "/F", "/IM", "temperature_receiver.exe"], + capture_output=True, + text=True, + ) + time.sleep(1) + + +def rebuild_receiver() -> None: + log("rebuild temperature_receiver") + r = subprocess.run( + [str(CMAKE), "--build", str(RX_BUILD), "--parallel"], + env=env(), + capture_output=True, + text=True, + ) + if r.returncode != 0: + (ROOT / "experiments" / "boot_wifi_opt_rx_build.err").write_text( + (r.stdout or "")[-8000:] + "\n" + (r.stderr or "")[-8000:], + encoding="utf-8", + ) + raise RuntimeError("receiver build failed") + log("receiver build ok") + + +def start_receiver() -> None: + kill_receiver() + RX_SESSION.mkdir(parents=True, exist_ok=True) + if TSV.exists(): + TSV.unlink() + env2 = env() + env2["AE_RECEIVER_SESSION_DIR"] = str(RX_SESSION) + env2["AE_DS_TSV"] = str(TSV) + with RX_LOG.open("w", encoding="utf-8") as outf, ( + ROOT / "experiments" / "prepared_boot_wifi_opt_rx.log.err" + ).open("w", encoding="utf-8") as errf: + subprocess.Popen( + [str(RX_EXE)], + cwd=str(RX_SESSION), + env=env2, + stdout=outf, + stderr=errf, + ) + t0 = time.time() + while time.time() - t0 < 60: + text = RX_LOG.read_text(encoding="utf-8", errors="replace") if RX_LOG.exists() else "" + if "RECEIVER_UID=" in text: + log("receiver ready") + return + time.sleep(1) + raise RuntimeError("receiver not ready") + + +def cmake_configure() -> None: + args = [ + str(CMAKE), + "-S", + str(ROOT), + "-B", + str(BUILD), + "-G", + "Ninja", + f"-DCPM_aether-client-cpp_SOURCE={AETHER}", + "-DAE_EXP_PREPARED_BOOT_WIFI_OPT=1", + "-DAE_EXP_PREPARED_MAC_RETRY_DIAG=", + "-DAE_EXP_PREPARED_TX_DONE_DIAG=", + "-DAE_EXP_PREPARED_DEEPSLEEP_5X50=", + "-DAE_EXP_PREPARED_WIFI_FASTEST=", + "-DAE_EXP_PREPARED_WIFI_BISECT=", + "-DAE_EXP_SKIP_DTOR_SAVE=1", + "-DSERVICE_UID=5aade50f-00d9-4624-b097-e203cdcf1e38", + "-DBENCH_CLIENT_ID=prepared_deepsleep_5x50_v1", + "-DAETHER_PREPARED_NONCE_RESERVE=40", + "-DWIFI_SSID=chirkov", + "-DWIFI_PASSWORD=kcdjepWz51", + "-DCMAKE_BUILD_TYPE=Release", + ] + log("cmake configure boot_wifi_opt") + r = subprocess.run(args, cwd=ROOT, env=env(), capture_output=True, text=True) + if r.returncode != 0: + (ROOT / "experiments" / "boot_wifi_opt_cmake.err").write_text( + (r.stdout or "") + "\n" + (r.stderr or ""), encoding="utf-8" + ) + raise RuntimeError("cmake failed") + force_sdk_fixes() + # Re-run cmake so Kconfig picks forced sdkconfig values when needed. + r2 = subprocess.run(args, cwd=ROOT, env=env(), capture_output=True, text=True) + if r2.returncode != 0: + raise RuntimeError("cmake reconfigure failed") + force_sdk_fixes() + log("cmake ok") + + +def ninja_build() -> None: + log("ninja build") + r = subprocess.run( + [str(NINJA), "-C", str(BUILD)], env=env(), capture_output=True, text=True + ) + if r.returncode != 0: + (ROOT / "experiments" / "boot_wifi_opt_build.err").write_text( + (r.stdout or "")[-16000:] + "\n" + (r.stderr or "")[-8000:], + encoding="utf-8", + ) + raise RuntimeError("ninja failed") + log("build ok") + # Snapshot effective boot/rtc flags + sdk = BUILD / "sdkconfig" + keys = [ + "CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP", + "CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS", + "CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF", + "CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE", + "CONFIG_ESPTOOLPY_FLASHMODE", + "CONFIG_ESPTOOLPY_FLASHFREQ", + "CONFIG_RTC_CLK_SRC_EXT_CRYS", + "CONFIG_RTC_CLK_CAL_CYCLES", + "CONFIG_SECURE_BOOT", + "CONFIG_FLASH_ENCRYPTION_ENABLED", + "CONFIG_ESP_WIFI_AMPDU_TX_ENABLED", + "CONFIG_ESP_WIFI_AMPDU_RX_ENABLED", + "CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM", + "CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM", + "CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM", + ] + lines = [] + text = sdk.read_text(encoding="utf-8", errors="replace") if sdk.exists() else "" + for k in keys: + for ln in text.splitlines(): + if k in ln and not ln.strip().startswith("#") or ln.startswith(f"# {k}"): + if k in ln: + lines.append(ln) + break + (ROOT / "experiments" / "boot_wifi_opt_sdkconfig_snapshot.txt").write_text( + "\n".join(lines) + "\n", encoding="utf-8" + ) + + +def wait_com_for_flash_only(timeout_s: float = 120.0) -> None: + log(f"pre-flash: waiting up to {int(timeout_s)}s for {PORT} (awake window)") + t0 = time.time() + while time.time() - t0 < timeout_s: + r = subprocess.run( + [ + "powershell", + "-NoProfile", + "-Command", + f"Get-PnpDevice -Class Ports -Status OK | Where-Object {{ $_.FriendlyName -match '{PORT}' }} | Select-Object -ExpandProperty FriendlyName", + ], + capture_output=True, + text=True, + ) + if PORT in (r.stdout or ""): + log(f"pre-flash: {PORT} present") + return + time.sleep(2.0) + raise RuntimeError(f"{PORT} not available for flash — wake/power-cycle ESP once") + + +def flash_once() -> None: + wait_com_for_flash_only() + log(f"flash {PORT} (COM allowed only here)") + cmd = [ + str(PY), + "-m", + "esptool", + "--chip", + "esp32c6", + "-p", + PORT, + "-b", + "460800", + "write-flash", + "--flash-size", + "4MB", + "0x0", + str(BUILD / "bootloader" / "bootloader.bin"), + "0x8000", + str(BUILD / "partition_table" / "partition-table.bin"), + "0x10000", + str(BUILD / "temperature_sensor.bin"), + ] + r = subprocess.run(cmd, env=env(), capture_output=True, text=True) + if r.returncode != 0: + (ROOT / "experiments" / "boot_wifi_opt_flash.err").write_text( + (r.stdout or "") + "\n" + (r.stderr or ""), encoding="utf-8" + ) + raise RuntimeError("flash failed") + log("FLASH_OK — closing COM; further progress via Aether only") + + +def progress_from_log() -> tuple[int, int, int]: + text = RX_LOG.read_text(encoding="utf-8", errors="replace") if RX_LOG.exists() else "" + fulls = len(re.findall(r"^BWO_FULL ", text, re.M)) + hots = len(re.findall(r"^BWO V", text, re.M)) + finals = len(re.findall(r"^BWO_FINAL|BENCH_DONE boot_wifi_opt", text, re.M)) + return fulls, hots, finals + + +def wait_campaign(timeout_s: float = 55 * 60) -> None: + log("wait Aether campaign (no COM)") + t0 = time.time() + last = (-1, -1, -1) + while time.time() - t0 < timeout_s: + f, h, fin = progress_from_log() + if (f, h, fin) != last: + last = (f, h, fin) + log(f"progress full={f} hot={h} final={fin}") + text = RX_LOG.read_text(encoding="utf-8", errors="replace") + lines = [ln for ln in text.splitlines() if ln.startswith("BWO V")] + if lines: + log(" " + lines[-1][:220]) + if fin > 0 or h >= VARIANTS * HOT_PER: + log(f"STOP campaign full={f} hot={h} final={fin}") + return + if f >= VARIANTS + 1 and h >= VARIANTS * HOT_PER - 5: + log(f"STOP near-complete full={f} hot={h}") + return + time.sleep(2.0) + log(f"TIMEOUT full={last[0]} hot={last[1]} final={last[2]}") + + +def main() -> int: + if PROGRESS.exists(): + PROGRESS.write_text("", encoding="utf-8") + rebuild_receiver() + start_receiver() + cmake_configure() + ninja_build() + flash_once() + wait_campaign() + kill_receiver() + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Exception as e: + log(f"ERROR {e}") + kill_receiver() + sys.exit(1) diff --git a/experiments/run_boot_wifi_val100.py b/experiments/run_boot_wifi_val100.py new file mode 100644 index 0000000..2b4fc40 --- /dev/null +++ b/experiments/run_boot_wifi_val100.py @@ -0,0 +1,269 @@ +"""VAL100 combined winners — one flash, no COM after FLASH_OK.""" + +from __future__ import annotations + +import os +import re +import subprocess +import sys +import time +from pathlib import Path + +ROOT = Path(r"C:\Users\nickc\Projects\temperature-sensor-prepared") +BUILD = ROOT / "build-esp32c6-save-bench-smoke" +AETHER = r"C:/Users/nickc/Projects/aether-client-cpp-prepared-packet-v0" +PY = Path(r"C:\Espressif\python_env\idf6.0_py3.11_env\Scripts\python.exe") +CMAKE = Path(r"C:\Espressif\tools\cmake\3.30.2\bin\cmake.exe") +NINJA = Path(r"C:\Espressif\tools\ninja\1.12.1\ninja.exe") +RX_EXE = ROOT / "temperature_receiver" / "build-bisect" / "temperature_receiver.exe" +RX_BUILD = ROOT / "temperature_receiver" / "build-bisect" +RX_SESSION = ROOT / "experiments" / "prepared_wifi_cache_rx_session" +IDF_PATH = r"C:\Espressif\frameworks\esp-idf-v6.0.2" +CCACHE = r"C:\Espressif\tools\ccache\4.12.1\ccache-4.12.1-windows-x86_64" +PROGRESS = ROOT / "experiments" / "boot_wifi_val100_progress.log" +RX_LOG = ROOT / "experiments" / "prepared_boot_wifi_val100_rx.log" +TSV = ROOT / "experiments" / "prepared_boot_wifi_val100.tsv" +PORT = "COM7" +HOT_TARGET = 100 + + +def env() -> dict: + e = os.environ.copy() + e["IDF_PATH"] = IDF_PATH + e["IDF_TOOLS_PATH"] = r"C:\Espressif" + extra = [ + CCACHE, + r"C:\Espressif\tools\ninja\1.12.1", + r"C:\Espressif\tools\cmake\3.30.2\bin", + r"C:\msys64\ucrt64\bin", + ] + e["Path"] = ";".join(extra) + ";" + e.get("Path", "") + e.pop("CCACHE_DISABLE", None) + return e + + +def log(msg: str) -> None: + line = time.strftime("%H:%M:%S") + " " + msg + print(line, flush=True) + with PROGRESS.open("a", encoding="utf-8") as f: + f.write(line + "\n") + + +def force_sdk_fixes() -> None: + sdk = BUILD / "sdkconfig" + if not sdk.exists(): + return + text = sdk.read_text(encoding="utf-8") + reps = [ + ("CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y", "# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set"), + ("CONFIG_RTC_CLK_SRC_INT_RC=y", "# CONFIG_RTC_CLK_SRC_INT_RC is not set"), + ("# CONFIG_RTC_CLK_SRC_EXT_CRYS is not set", "CONFIG_RTC_CLK_SRC_EXT_CRYS=y"), + ("# CONFIG_ESP_BROWNOUT_DET is not set", "CONFIG_ESP_BROWNOUT_DET=y"), + ("CONFIG_PM_ENABLE=y", "# CONFIG_PM_ENABLE is not set"), + ] + for a, b in reps: + text = text.replace(a, b) + if "CONFIG_RTC_CLK_SRC_EXT_CRYS=y" not in text: + text += "\nCONFIG_RTC_CLK_SRC_EXT_CRYS=y\n" + sdk.write_text(text, encoding="utf-8") + + +def kill_receiver() -> None: + subprocess.run( + ["taskkill", "/F", "/IM", "temperature_receiver.exe"], + capture_output=True, + text=True, + ) + time.sleep(1) + + +def rebuild_receiver() -> None: + log("rebuild temperature_receiver") + r = subprocess.run( + [str(CMAKE), "--build", str(RX_BUILD), "--parallel"], + env=env(), + capture_output=True, + text=True, + ) + if r.returncode != 0: + raise RuntimeError("receiver build failed") + log("receiver build ok") + + +def start_receiver() -> None: + kill_receiver() + RX_SESSION.mkdir(parents=True, exist_ok=True) + if TSV.exists(): + TSV.unlink() + env2 = env() + env2["AE_RECEIVER_SESSION_DIR"] = str(RX_SESSION) + env2["AE_DS_TSV"] = str(TSV) + with RX_LOG.open("w", encoding="utf-8") as outf, ( + ROOT / "experiments" / "prepared_boot_wifi_val100_rx.log.err" + ).open("w", encoding="utf-8") as errf: + subprocess.Popen( + [str(RX_EXE)], + cwd=str(RX_SESSION), + env=env2, + stdout=outf, + stderr=errf, + ) + t0 = time.time() + while time.time() - t0 < 60: + text = RX_LOG.read_text(encoding="utf-8", errors="replace") if RX_LOG.exists() else "" + if "RECEIVER_UID=" in text: + log("receiver ready") + return + time.sleep(1) + raise RuntimeError("receiver not ready") + + +def cmake_configure() -> None: + args = [ + str(CMAKE), + "-S", + str(ROOT), + "-B", + str(BUILD), + "-G", + "Ninja", + f"-DCPM_aether-client-cpp_SOURCE={AETHER}", + "-DAE_EXP_PREPARED_BOOT_WIFI_VAL100=1", + "-DAE_EXP_PREPARED_BOOT_WIFI_OPT=", + "-DAE_EXP_PREPARED_MAC_RETRY_DIAG=", + "-DAE_EXP_PREPARED_TX_DONE_DIAG=", + "-DAE_EXP_PREPARED_DEEPSLEEP_5X50=", + "-DAE_EXP_SKIP_DTOR_SAVE=1", + "-DSERVICE_UID=5aade50f-00d9-4624-b097-e203cdcf1e38", + "-DBENCH_CLIENT_ID=prepared_deepsleep_5x50_v1", + "-DAETHER_PREPARED_NONCE_RESERVE=110", + "-DWIFI_SSID=chirkov", + "-DWIFI_PASSWORD=kcdjepWz51", + "-DCMAKE_BUILD_TYPE=Release", + ] + log("cmake configure VAL100") + r = subprocess.run(args, cwd=ROOT, env=env(), capture_output=True, text=True) + if r.returncode != 0: + (ROOT / "experiments" / "boot_wifi_val100_cmake.err").write_text( + (r.stdout or "") + "\n" + (r.stderr or ""), encoding="utf-8" + ) + raise RuntimeError("cmake failed") + force_sdk_fixes() + log("cmake ok") + + +def ninja_build() -> None: + log("ninja build") + r = subprocess.run( + [str(NINJA), "-C", str(BUILD)], env=env(), capture_output=True, text=True + ) + if r.returncode != 0: + (ROOT / "experiments" / "boot_wifi_val100_build.err").write_text( + (r.stdout or "")[-16000:] + "\n" + (r.stderr or "")[-8000:], + encoding="utf-8", + ) + raise RuntimeError("ninja failed") + log("build ok") + + +def wait_com_for_flash_only(timeout_s: float = 180.0) -> None: + log(f"pre-flash: waiting up to {int(timeout_s)}s for {PORT}") + t0 = time.time() + while time.time() - t0 < timeout_s: + r = subprocess.run( + [ + "powershell", + "-NoProfile", + "-Command", + f"Get-PnpDevice -Class Ports -Status OK | Where-Object {{ $_.FriendlyName -match '{PORT}' }} | Select-Object -ExpandProperty FriendlyName", + ], + capture_output=True, + text=True, + ) + if PORT in (r.stdout or ""): + log(f"pre-flash: {PORT} present") + return + time.sleep(2.0) + raise RuntimeError(f"{PORT} not available — reset ESP once") + + +def flash_once() -> None: + wait_com_for_flash_only() + log(f"flash {PORT}") + cmd = [ + str(PY), + "-m", + "esptool", + "--chip", + "esp32c6", + "-p", + PORT, + "-b", + "460800", + "write-flash", + "--flash-size", + "4MB", + "0x0", + str(BUILD / "bootloader" / "bootloader.bin"), + "0x8000", + str(BUILD / "partition_table" / "partition-table.bin"), + "0x10000", + str(BUILD / "temperature_sensor.bin"), + ] + r = subprocess.run(cmd, env=env(), capture_output=True, text=True) + if r.returncode != 0: + (ROOT / "experiments" / "boot_wifi_val100_flash.err").write_text( + (r.stdout or "") + "\n" + (r.stderr or ""), encoding="utf-8" + ) + raise RuntimeError("flash failed") + log("FLASH_OK — no further COM") + + +def progress() -> tuple[int, int, int]: + text = RX_LOG.read_text(encoding="utf-8", errors="replace") if RX_LOG.exists() else "" + fulls = len(re.findall(r"^BWO_FULL ", text, re.M)) + hots = len(re.findall(r"^BWO V", text, re.M)) + finals = len(re.findall(r"^BWO_FINAL|BENCH_DONE boot_wifi_opt", text, re.M)) + return fulls, hots, finals + + +def wait_campaign(timeout_s: float = 25 * 60) -> None: + log("wait VAL100 (no COM)") + t0 = time.time() + last = (-1, -1, -1) + while time.time() - t0 < timeout_s: + f, h, fin = progress() + if (f, h, fin) != last: + last = (f, h, fin) + log(f"progress full={f} hot={h} final={fin}") + text = RX_LOG.read_text(encoding="utf-8", errors="replace") + lines = [ln for ln in text.splitlines() if ln.startswith("BWO V")] + if lines: + log(" " + lines[-1][:220]) + if fin > 0 or h >= HOT_TARGET: + log(f"STOP full={f} hot={h} final={fin}") + return + time.sleep(2.0) + log(f"TIMEOUT full={last[0]} hot={last[1]} final={last[2]}") + + +def main() -> int: + if PROGRESS.exists(): + PROGRESS.write_text("", encoding="utf-8") + rebuild_receiver() + start_receiver() + cmake_configure() + ninja_build() + flash_once() + wait_campaign() + kill_receiver() + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Exception as e: + log(f"ERROR {e}") + kill_receiver() + sys.exit(1) diff --git a/experiments/run_bssid_removed_verify.ps1 b/experiments/run_bssid_removed_verify.ps1 new file mode 100644 index 0000000..8ab943d --- /dev/null +++ b/experiments/run_bssid_removed_verify.ps1 @@ -0,0 +1,95 @@ +param( + [string]$Port = 'COM7', + [string]$ServiceUid = '3d284a4f-ebb4-451e-a2c5-aecb0d647a45', + [int]$CaptureSec = 600 +) +$ErrorActionPreference = 'Stop' +$env:Path = 'C:\Program Files\Git\cmd;C:\Espressif\python_env\idf6.0_py3.11_env\Scripts;' + $env:Path +$env:IDF_PATH = 'C:\Espressif\frameworks\esp-idf-v6.0.2' +. "$env:IDF_PATH\export.ps1" | Out-Null + +$proj = 'C:\Users\nickc\Projects\temperature-sensor-prepared' +$aether = 'C:/Users/nickc/Projects/aether-client-cpp-prepared-packet-v0' +$build = 'build-esp32c6-save-bench-smoke' +$exp = Join-Path $proj 'experiments\wifi_lifecycle' +New-Item -ItemType Directory -Force -Path $exp | Out-Null +$log = Join-Path $exp 'v40_bssid_removed_capture.log' +$rebootLog = Join-Path $exp 'v40_bssid_removed_reboot3.log' + +function Stop-EspMonitors { + Get-CimInstance Win32_Process -Filter "Name='python.exe'" | + Where-Object { $_.CommandLine -match 'esp_idf_monitor' } | + ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue } + Start-Sleep -Seconds 2 +} + +Set-Location $proj +Stop-EspMonitors + +# Production baseline driver after BSSID removal. Do NOT erase SPIFFS. +$cmakeArgs = @( + '-B', $build, + '-D', 'WIFI_SSID=chirkov', + '-D', 'WIFI_PASSWORD=kcdjepWz51', + '-D', "SERVICE_UID=$ServiceUid", + '-D', "CPM_aether-client-cpp_SOURCE=$aether", + '-D', 'AE_EXP_WIFI_LIFECYCLE=1', + '-D', 'AE_EXP_WIFI_LIFECYCLE_VARIANT=40', + '-D', 'AE_EXP_WIFI_LIFECYCLE_CYCLES=10', + '-D', 'AE_EXP_SKIP_DTOR_SAVE=1', + '-D', 'AE_EXP_WIFI_COOLDOWN_MS=0', + '-D', 'AE_EXP_WIFI_CANONICAL=0', + '-D', 'AE_EXP_FULL_CYCLES=', + '-D', 'AE_EXP_BENCH_STAGE=', + '-D', 'AE_EXP_SAVE_BENCH_N=', + '-D', 'AE_EXP_LEGACY_MAP_SYNC=', + '-D', 'AE_EXP_WIFI_IGNORE_BSSID=', + '-D', 'AE_EXP_WIFI_FEAT_BSSID_CACHE=' +) + +Write-Output 'BUILD variant=40 production BSSID-removed (no flash erase)' +idf.py @cmakeArgs build flash -p $Port +if ($LASTEXITCODE -ne 0) { throw 'build/flash failed' } + +Remove-Item $log -Force -ErrorAction SilentlyContinue +$elf = Join-Path $proj "$build\temperature_sensor.elf" +$mon = Start-Process -FilePath python -ArgumentList @('-u','-m','esp_idf_monitor','--port',$Port,'--baud','115200',$elf) -WorkingDirectory (Join-Path $proj $build) -RedirectStandardOutput $log -RedirectStandardError "$log.err" -PassThru -NoNewWindow +Start-Sleep -Seconds 2 +$prev = $ErrorActionPreference +$ErrorActionPreference = 'Continue' +python -m esptool --chip esp32c6 -p $Port run 2>&1 | Out-Null +$ErrorActionPreference = $prev + +$deadline = (Get-Date).AddSeconds($CaptureSec) +while ((Get-Date) -lt $deadline) { + if ((Test-Path $log) -and (Select-String -Path $log -Pattern 'WIFI_SUMMARY' -Quiet)) { break } + Start-Sleep -Seconds 5 +} +Stop-Process -Id $mon.Id -Force -ErrorAction SilentlyContinue +Start-Sleep -Seconds 2 + +Write-Output '--- 10-cycle result ---' +Select-String -Path $log -Pattern '^(cycle=|raw=|min=|median=|max=|completed=|WIFI_SUMMARY)' | ForEach-Object { $_.Line } + +Write-Output '--- reboot + 3 cycles (SPIFFS kept) ---' +Remove-Item $rebootLog -Force -ErrorAction SilentlyContinue +$mon2 = Start-Process -FilePath python -ArgumentList @('-u','-m','esp_idf_monitor','--port',$Port,'--baud','115200',$elf) -WorkingDirectory (Join-Path $proj $build) -RedirectStandardOutput $rebootLog -RedirectStandardError "$rebootLog.err" -PassThru -NoNewWindow +Start-Sleep -Seconds 2 +$ErrorActionPreference = 'Continue' +python -m esptool --chip esp32c6 -p $Port run 2>&1 | Out-Null +$ErrorActionPreference = $prev + +$deadline2 = (Get-Date).AddSeconds(180) +while ((Get-Date) -lt $deadline2) { + if (Test-Path $rebootLog) { + $n = @(Select-String -Path $rebootLog -Pattern '^cycle=\d+ init_to_release_ms=').Count + if ($n -ge 3) { break } + } + Start-Sleep -Seconds 3 +} +Stop-Process -Id $mon2.Id -Force -ErrorAction SilentlyContinue + +Write-Output '--- reboot 3-cycle lines ---' +Select-String -Path $rebootLog -Pattern '^cycle=\d+ init_to_release_ms=' | Select-Object -First 3 | ForEach-Object { $_.Line } +Write-Output "LOG10=$log" +Write-Output "LOG3=$rebootLog" diff --git a/experiments/run_callback_short_pre.py b/experiments/run_callback_short_pre.py new file mode 100644 index 0000000..36987a1 --- /dev/null +++ b/experiments/run_callback_short_pre.py @@ -0,0 +1,387 @@ +"""Short PRE search for late TX-done callback path (WPA2). N=50 screens + VAL200.""" + +from __future__ import annotations + +import json +import re +import sys +import time +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parent)) +from run_fastest_path import ( # noqa: E402 + BUILD, + ROOT, + RX_LOG, + cmake_configure, + ensure_receiver, + flash, + log, + ninja_build, +) + +RESULTS = ROOT / "experiments" / "prepared_wifi_callback_wpa2.tsv" +CHAT = ROOT / "experiments" / "callback_short_pre_chat.txt" +STATE = ROOT / "experiments" / "callback_short_pre_state.json" +PROGRESS = ROOT / "experiments" / "callback_short_pre_progress.log" + +RESULT_RE_EXT = re.compile( + r"TEST_RESULT test_id=(?P\d+) n=(?P\d+) delivered=(?P\d+)/(?P\d+) " + r"connect_med_ms=(?P\d+) cycle_med_ms=(?P\d+) p90_ms=(?P\d+) " + r"max_ms=(?P\d+) wifi_ready=(?P\d+) encode=(?P\d+) sendto=(?P\d+) " + r"nonce=(?P\d+) pre=(?P
\d+) post=(?P\d+) assoc=0x(?P[0-9a-fA-F]+) "
+    r"auth=(?P\d+) retry=(?P\d+) post_mode=(?P\d+) cb_any=(?P\d+) "
+    r"cb_match=(?P\d+)(?: cb_timeout=(?P\d+))?(?: txdone_med_ms=(?P\d+))?"
+    r"(?: teardown_med_ms=(?P\d+))?(?: missing=(?P\d+))?"
+    r"(?: duplicates=(?P\d+))?(?: ooo=(?P\d+))? samples=(?P\d+)"
+)
+
+BASE = {
+    "AE_EXP_FAST_USE_BSSID": "0",
+    "AE_EXP_FAST_FAST_SCAN": "0",
+    "AE_EXP_FAST_AUTH": "2",
+    "AE_EXP_FAST_RETRY": "10",
+    "AE_EXP_FAST_POST_MODE": "1",
+    "AE_EXP_FAST_POST_MS": "0",
+    "AE_EXP_FAST_AMPDU_TX_OFF": "0",
+    "AE_EXP_FAST_STORAGE_RAM": "0",
+    "AE_EXP_FAST_DISABLE_WPA3": "1",
+}
+
+OLD_PRE200_CYCLE = 430  # confirmed VAL200 callback PRE=200
+
+
+def force_wpa3_off() -> None:
+    sdk = BUILD / "sdkconfig"
+    if not sdk.exists():
+        return
+    text = sdk.read_text(encoding="utf-8")
+    text = text.replace(
+        "CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y",
+        "# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set",
+    )
+    text = text.replace(
+        "CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y",
+        "# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set",
+    )
+    sdk.write_text(text, encoding="utf-8")
+
+
+def count_results() -> int:
+    if not RX_LOG.exists():
+        return 0
+    text = RX_LOG.read_text(encoding="utf-8", errors="replace")
+    return len(list(RESULT_RE_EXT.finditer(text)))
+
+
+def wait_result_ext(
+    prev: int, timeout_s: int, expect_id: int | None, expect_n: int | None
+) -> dict:
+    deadline = time.time() + timeout_s
+    last_hb = 0.0
+    while time.time() < deadline:
+        now = time.time()
+        if now - last_hb >= 30:
+            last_hb = now
+            log(f"waiting TEST_RESULT prev={prev} left={int(deadline-now)}s")
+        if RX_LOG.exists():
+            text = RX_LOG.read_text(encoding="utf-8", errors="replace")
+            matches = list(RESULT_RE_EXT.finditer(text))
+            if len(matches) > prev:
+                for m in reversed(matches[prev:]):
+                    gd = m.groupdict()
+                    d = {}
+                    for k, v in gd.items():
+                        if v is None:
+                            d[k] = 0
+                        elif k == "assoc":
+                            d[k] = int(v, 16)
+                        else:
+                            d[k] = int(v)
+                    if expect_id is not None and d["id"] != expect_id:
+                        continue
+                    if expect_n is not None and d["n"] != expect_n:
+                        continue
+                    return d
+        time.sleep(2)
+    raise TimeoutError("no TEST_RESULT")
+
+
+def judge(r: dict) -> str:
+    plan = r.get("plan", 0)
+    if r.get("auth", 0) != 3:
+        return "INVALID_AUTH"
+    if r.get("wr", 0) < plan or r.get("enc", 0) < plan or r.get("st", 0) < plan:
+        return "LIFECYCLE_FAIL"
+    if r.get("cba", 0) < plan - 1:  # allow 1 miss on cb accounting
+        return "CALLBACK_WEAK"
+    if r.get("cbt", 0) > max(1, plan // 25):
+        return "TIMEOUT_HIGH"
+    # UDP losses OK; catastrophic = <70%
+    if r["del"] < int(plan * 0.70):
+        return "FAIL"
+    return "PASS"
+
+
+def write_chat(
+    test_no: int, remaining: int, name: str, r: dict, best: dict | None, nxt: str
+) -> None:
+    result = judge(r)
+    best_s = "none"
+    if best:
+        best_s = (
+            f"PRE={best.get('pre')} cycle={best.get('cyc')}ms "
+            f"del={best.get('del')}/{best.get('plan')} cb={best.get('cba')}"
+        )
+    lines = [
+        f"[TEST {test_no}/{test_no + remaining}] {name}",
+        f"delivery={r['del']}/{r['plan']}",
+        f"callback={r.get('cba', 0)}/{r.get('wr', r['plan'])}",
+        f"timeouts={r.get('cbt', 0)}",
+        f"missing={r.get('miss', r['plan'] - r['del'])} dup={r.get('dup', 0)} ooo={r.get('ooo', 0)}",
+        f"connect_med={r['conn']}",
+        f"txdone_med={r.get('txd', 0)}",
+        f"teardown_med={r.get('td', 0)}",
+        f"cycle_med={r['cyc']}",
+        f"p90={r['p90']}",
+        f"max={r['mx']}",
+        f"result={result}",
+        f"remaining={remaining}",
+        "BEST NOW:",
+        best_s,
+        f"NEXT: {nxt}",
+        "",
+    ]
+    text = "\n".join(lines)
+    CHAT.parent.mkdir(parents=True, exist_ok=True)
+    with CHAT.open("a", encoding="utf-8") as f:
+        f.write(text + "\n")
+    with PROGRESS.open("a", encoding="utf-8") as f:
+        f.write(text + "\n")
+    print(text, flush=True)
+
+
+def append_tsv(name: str, r: dict) -> None:
+    header = (
+        "name\ttest_id\tn\tdelivered\tplan\tconnect_med\ttxdone_med\tteardown_med\t"
+        "cycle_med\tp90\tmax\twifi_ready\tencode\tsendto\tnonce\tpre\tpost_mode\t"
+        "auth\tcb_seen\tcb_timeout\tmissing\tduplicates\tooo\tsamples\n"
+    )
+    need_header = not RESULTS.exists()
+    if RESULTS.exists():
+        first = RESULTS.read_text(encoding="utf-8").splitlines()[:1]
+        if first and "missing" not in first[0]:
+            # keep old file; append with extended header note via compatible columns
+            pass
+    if need_header:
+        RESULTS.write_text(header, encoding="utf-8")
+    line = (
+        f"{name}\t{r['id']}\t{r['n']}\t{r['del']}\t{r['plan']}\t{r['conn']}\t"
+        f"{r.get('txd',0)}\t{r.get('td',0)}\t{r['cyc']}\t{r['p90']}\t{r['mx']}\t"
+        f"{r['wr']}\t{r['enc']}\t{r['st']}\t{r['nonce']}\t{r['pre']}\t{r['pm']}\t"
+        f"{r['auth']}\t{r.get('cba',0)}\t{r.get('cbt',0)}\t"
+        f"{r.get('miss', r['plan']-r['del'])}\t{r.get('dup',0)}\t{r.get('ooo',0)}\t"
+        f"{r['samp']}\n"
+    )
+    with RESULTS.open("a", encoding="utf-8") as f:
+        f.write(line)
+
+
+def run_one(name: str, test_id: int, n: int, pre_ms: int, timeout_s: int) -> dict:
+    flags = {
+        **BASE,
+        "AE_EXP_FAST_TEST_ID": str(test_id),
+        "AE_EXP_FAST_N": str(n),
+        "AE_EXP_FAST_PRE_MS": str(pre_ms),
+    }
+    ensure_receiver()
+    cmake_configure(flags)
+    force_wpa3_off()
+    ninja_build()
+    force_wpa3_off()
+    prev = count_results()
+    flash()
+    r = wait_result_ext(prev, timeout_s, expect_id=test_id, expect_n=n)
+    r["pre"] = pre_ms
+    if "miss" not in r or r["miss"] == 0 and r["del"] < r["plan"]:
+        r["miss"] = r["plan"] - r["del"]
+    append_tsv(name, r)
+    return r
+
+
+def consider_best(best: dict | None, name: str, r: dict) -> dict:
+    if judge(r) not in ("PASS",):
+        return best if best else {
+            "name": name,
+            "pre": r["pre"],
+            "cyc": r["cyc"],
+            "del": r["del"],
+            "plan": r["plan"],
+            "cba": r.get("cba", 0),
+            "cbt": r.get("cbt", 0),
+            "conn": r["conn"],
+            "txd": r.get("txd", 0),
+            "p90": r["p90"],
+            "mx": r["mx"],
+        }
+    cand = {
+        "name": name,
+        "pre": r["pre"],
+        "cyc": r["cyc"],
+        "del": r["del"],
+        "plan": r["plan"],
+        "cba": r.get("cba", 0),
+        "cbt": r.get("cbt", 0),
+        "conn": r["conn"],
+        "txd": r.get("txd", 0),
+        "p90": r["p90"],
+        "mx": r["mx"],
+    }
+    if best is None:
+        return cand
+    # Prefer shorter PRE if cycle not worse by much and delivery OK; else faster cycle
+    if cand["pre"] < best["pre"] and cand["cyc"] <= best["cyc"] + 20:
+        return cand
+    if cand["cyc"] < best["cyc"]:
+        return cand
+    return best
+
+
+def screen_ok_for_val200(r: dict) -> bool:
+    return (
+        judge(r) == "PASS"
+        and r.get("auth", 0) == 3
+        and r.get("cba", 0) >= r["plan"] - 0
+        and r.get("cbt", 0) <= 1
+        and r["wr"] == r["plan"]
+        and r["enc"] == r["plan"]
+        and r["st"] == r["plan"]
+    )
+
+
+def main() -> int:
+    CHAT.write_text("", encoding="utf-8")
+    # Ensure TSV has extended header for new rows; keep prior history via append
+    if not RESULTS.exists():
+        RESULTS.write_text(
+            "name\ttest_id\tn\tdelivered\tplan\tconnect_med\ttxdone_med\tteardown_med\t"
+            "cycle_med\tp90\tmax\twifi_ready\tencode\tsendto\tnonce\tpre\tpost_mode\t"
+            "auth\tcb_seen\tcb_timeout\tmissing\tduplicates\tooo\tsamples\n",
+            encoding="utf-8",
+        )
+    else:
+        # Append a blank separator comment isn't valid TSV; just continue appending
+        pass
+
+    best: dict | None = None
+    results: dict = {}
+    test_no = 1
+    remaining = 6
+    val200_by_pre: dict[int, dict] = {}
+
+    # --- PRE25_N50 ---
+    name = "PRE25_N50"
+    log(f"=== {name} ===")
+    r25 = run_one(name, test_id=201, n=50, pre_ms=25, timeout_s=1800)
+    results[name] = r25
+    best = consider_best(best, name, r25)
+    write_chat(test_no, remaining - 1, name, r25, best, "PRE25_VAL200 if OK")
+    test_no += 1
+    remaining -= 1
+
+    if screen_ok_for_val200(r25):
+        name = "PRE25_VAL200"
+        log(f"=== {name} ===")
+        r = run_one(name, test_id=202, n=200, pre_ms=25, timeout_s=7200)
+        results[name] = r
+        val200_by_pre[25] = r
+        best = consider_best(best, name, r)
+        write_chat(test_no, remaining - 1, name, r, best, "PRE10_N50")
+        test_no += 1
+        remaining -= 1
+    else:
+        log("PRE25 screen not OK for VAL200 — skip VAL200")
+
+    # --- PRE10_N50 ---
+    name = "PRE10_N50"
+    log(f"=== {name} ===")
+    r10 = run_one(name, test_id=203, n=50, pre_ms=10, timeout_s=1800)
+    results[name] = r10
+    best = consider_best(best, name, r10)
+    write_chat(test_no, remaining - 1, name, r10, best, "PRE0_N50")
+    test_no += 1
+    remaining -= 1
+
+    # --- PRE0_N50 ---
+    name = "PRE0_N50"
+    log(f"=== {name} ===")
+    r0 = run_one(name, test_id=204, n=50, pre_ms=0, timeout_s=1800)
+    results[name] = r0
+    best = consider_best(best, name, r0)
+    write_chat(test_no, remaining - 1, name, r0, best, "VAL200 for best short PRE")
+    test_no += 1
+    remaining -= 1
+
+    # Pick best short PRE among 0/10/25 that passed screen
+    candidates = []
+    for pre, rr in ((0, r0), (10, r10), (25, r25)):
+        if screen_ok_for_val200(rr):
+            candidates.append((pre, rr))
+    # Prefer shortest PRE among passing screens
+    candidates.sort(key=lambda x: (x[0], x[1]["cyc"]))
+
+    winner_pre = 25
+    if candidates:
+        winner_pre = candidates[0][0]
+    else:
+        # fallback: least-bad by delivery then cycle
+        ranked = sorted(
+            [(0, r0), (10, r10), (25, r25)],
+            key=lambda x: (-x[1]["del"], x[1]["cyc"]),
+        )
+        winner_pre = ranked[0][0]
+
+    # VAL200 for winner if not already done (PRE25 may already have VAL200)
+    if winner_pre not in val200_by_pre and screen_ok_for_val200(
+        {0: r0, 10: r10, 25: r25}[winner_pre]
+    ):
+        name = f"PRE{winner_pre}_VAL200"
+        log(f"=== {name} ===")
+        r = run_one(
+            name, test_id=210 + winner_pre, n=200, pre_ms=winner_pre, timeout_s=7200
+        )
+        results[name] = r
+        val200_by_pre[winner_pre] = r
+        best = consider_best(best, name, r)
+        write_chat(test_no, remaining - 1, name, r, best, "report")
+        test_no += 1
+        remaining -= 1
+    elif winner_pre in val200_by_pre:
+        log(f"VAL200 already done for PRE={winner_pre}")
+        best = consider_best(best, f"PRE{winner_pre}_VAL200", val200_by_pre[winner_pre])
+    else:
+        log(f"No VAL200 for winner PRE={winner_pre} (screen not OK)")
+
+    # If PRE0 or PRE10 passed and is shorter than PRE25 and better, ensure VAL200
+    # (already handled by winner_pre)
+
+    STATE.write_text(
+        json.dumps(
+            {
+                "results": results,
+                "val200": {str(k): v for k, v in val200_by_pre.items()},
+                "winner_pre": winner_pre,
+                "best": best,
+                "old_pre200_cycle": OLD_PRE200_CYCLE,
+            },
+            indent=2,
+            default=str,
+        ),
+        encoding="utf-8",
+    )
+    log(f"DONE winner_pre={winner_pre} best={best}")
+    return 0
+
+
+if __name__ == "__main__":
+    raise SystemExit(main())
diff --git a/experiments/run_callback_wpa2.py b/experiments/run_callback_wpa2.py
new file mode 100644
index 0000000..9284022
--- /dev/null
+++ b/experiments/run_callback_wpa2.py
@@ -0,0 +1,357 @@
+"""Late TX-done callback prepared-send campaign (WPA2, PRE=200 then PRE sweep)."""
+
+from __future__ import annotations
+
+import json
+import re
+import sys
+import time
+from pathlib import Path
+
+sys.path.insert(0, str(Path(__file__).resolve().parent))
+from run_fastest_path import (  # noqa: E402
+    BUILD,
+    RESULT_RE,
+    ROOT,
+    RX_LOG,
+    cmake_configure,
+    ensure_receiver,
+    env,
+    flash,
+    log,
+    ninja_build,
+    wait_result,
+)
+
+RESULTS = ROOT / "experiments" / "prepared_wifi_callback_wpa2.tsv"
+CHAT = ROOT / "experiments" / "callback_wpa2_chat.txt"
+STATE = ROOT / "experiments" / "callback_wpa2_state.json"
+PROGRESS = ROOT / "experiments" / "callback_wpa2_progress.log"
+
+# Extended regex with new fields (falls back handled by groupdict defaults).
+RESULT_RE_EXT = re.compile(
+    r"TEST_RESULT test_id=(?P\d+) n=(?P\d+) delivered=(?P\d+)/(?P\d+) "
+    r"connect_med_ms=(?P\d+) cycle_med_ms=(?P\d+) p90_ms=(?P\d+) "
+    r"max_ms=(?P\d+) wifi_ready=(?P\d+) encode=(?P\d+) sendto=(?P\d+) "
+    r"nonce=(?P\d+) pre=(?P
\d+) post=(?P\d+) assoc=0x(?P[0-9a-fA-F]+) "
+    r"auth=(?P\d+) retry=(?P\d+) post_mode=(?P\d+) cb_any=(?P\d+) "
+    r"cb_match=(?P\d+)(?: cb_timeout=(?P\d+))?(?: txdone_med_ms=(?P\d+))?"
+    r"(?: teardown_med_ms=(?P\d+))? samples=(?P\d+)"
+)
+
+BASE = {
+    "AE_EXP_FAST_USE_BSSID": "0",
+    "AE_EXP_FAST_FAST_SCAN": "0",
+    "AE_EXP_FAST_AUTH": "2",
+    "AE_EXP_FAST_RETRY": "10",
+    "AE_EXP_FAST_POST_MODE": "1",  # kTxDoneCb — late install before sendto
+    "AE_EXP_FAST_POST_MS": "0",
+    "AE_EXP_FAST_AMPDU_TX_OFF": "0",
+    "AE_EXP_FAST_STORAGE_RAM": "0",
+    "AE_EXP_FAST_DISABLE_WPA3": "1",
+}
+
+OLD_WINNER_CYCLE = 710
+
+
+def force_wpa3_off() -> None:
+    sdk = BUILD / "sdkconfig"
+    if not sdk.exists():
+        return
+    text = sdk.read_text(encoding="utf-8")
+    text = text.replace(
+        "CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y",
+        "# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set",
+    )
+    text = text.replace(
+        "CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y",
+        "# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set",
+    )
+    sdk.write_text(text, encoding="utf-8")
+
+
+def count_results() -> int:
+    if not RX_LOG.exists():
+        return 0
+    text = RX_LOG.read_text(encoding="utf-8", errors="replace")
+    return len(list(RESULT_RE_EXT.finditer(text)))
+
+
+def wait_result_ext(
+    prev: int, timeout_s: int, expect_id: int | None, expect_n: int | None
+) -> dict:
+    deadline = time.time() + timeout_s
+    last_hb = 0.0
+    while time.time() < deadline:
+        now = time.time()
+        if now - last_hb >= 30:
+            last_hb = now
+            log(f"waiting TEST_RESULT prev={prev} left={int(deadline-now)}s")
+        if RX_LOG.exists():
+            text = RX_LOG.read_text(encoding="utf-8", errors="replace")
+            matches = list(RESULT_RE_EXT.finditer(text))
+            if len(matches) > prev:
+                for m in reversed(matches[prev:]):
+                    gd = m.groupdict()
+                    d = {}
+                    for k, v in gd.items():
+                        if v is None:
+                            d[k] = 0
+                        elif k == "assoc":
+                            d[k] = int(v, 16)
+                        else:
+                            d[k] = int(v)
+                    if expect_id is not None and d["id"] != expect_id:
+                        continue
+                    if expect_n is not None and d["n"] != expect_n:
+                        continue
+                    return d
+        time.sleep(2)
+    raise TimeoutError("no TEST_RESULT")
+
+
+def write_chat(test_no: int, remaining: int, name: str, r: dict, best: dict | None, nxt: str) -> None:
+    auth_ok = r.get("auth", 0) == 3
+    cb = r.get("cba", 0)
+    to = r.get("cbt", 0)
+    plan = r.get("plan", 0)
+    result = "PASS"
+    if not auth_ok:
+        result = "INVALID_AUTH"
+    elif plan >= 20 and cb < max(18, int(plan * 0.9)):
+        result = "CALLBACK_WEAK"
+    elif r["del"] < int(plan * 0.85):
+        result = "FAIL"
+    best_s = "none"
+    if best:
+        best_s = (
+            f"PRE={best.get('pre')} POST=callback cycle={best.get('cyc')}ms "
+            f"del={best.get('del')}/{best.get('plan')} cb={best.get('cba')}"
+        )
+    lines = [
+        f"[TEST {test_no}/{test_no + remaining}] CALLBACK_WPA2_{name}",
+        f"delivery={r['del']}/{r['plan']}",
+        f"callback={cb}/{r.get('wr', plan)}",
+        f"timeouts={to}",
+        f"connect_med={r['conn']}",
+        f"txdone_med={r.get('txd', 0)}",
+        f"cycle_med={r['cyc']}",
+        f"p90={r['p90']}",
+        f"auth={r.get('auth')} result={result}",
+        f"remaining={remaining}",
+        "BEST NOW:",
+        best_s,
+        f"NEXT: {nxt}",
+        "",
+    ]
+    text = "\n".join(lines)
+    CHAT.parent.mkdir(parents=True, exist_ok=True)
+    with CHAT.open("a", encoding="utf-8") as f:
+        f.write(text + "\n")
+    with PROGRESS.open("a", encoding="utf-8") as f:
+        f.write(text + "\n")
+    print(text, flush=True)
+
+
+def append_tsv(name: str, r: dict) -> None:
+    header = (
+        "name\ttest_id\tn\tdelivered\tplan\tconnect_med\ttxdone_med\tteardown_med\t"
+        "cycle_med\tp90\tmax\twifi_ready\tencode\tsendto\tnonce\tpre\tpost_mode\t"
+        "auth\tcb_seen\tcb_timeout\tsamples\n"
+    )
+    if not RESULTS.exists():
+        RESULTS.write_text(header, encoding="utf-8")
+    line = (
+        f"{name}\t{r['id']}\t{r['n']}\t{r['del']}\t{r['plan']}\t{r['conn']}\t"
+        f"{r.get('txd',0)}\t{r.get('td',0)}\t{r['cyc']}\t{r['p90']}\t{r['mx']}\t"
+        f"{r['wr']}\t{r['enc']}\t{r['st']}\t{r['nonce']}\t{r['pre']}\t{r['pm']}\t"
+        f"{r['auth']}\t{r.get('cba',0)}\t{r.get('cbt',0)}\t{r['samp']}\n"
+    )
+    with RESULTS.open("a", encoding="utf-8") as f:
+        f.write(line)
+
+
+def run_one(name: str, test_id: int, n: int, pre_ms: int, timeout_s: int) -> dict:
+    flags = {
+        **BASE,
+        "AE_EXP_FAST_TEST_ID": str(test_id),
+        "AE_EXP_FAST_N": str(n),
+        "AE_EXP_FAST_PRE_MS": str(pre_ms),
+    }
+    ensure_receiver()
+    cmake_configure(flags)
+    force_wpa3_off()
+    ninja_build()
+    # Re-apply after ninja may regenerate sdkconfig from defaults
+    force_wpa3_off()
+    prev = count_results()
+    flash()
+    r = wait_result_ext(prev, timeout_s, expect_id=test_id, expect_n=n)
+    r["pre"] = pre_ms
+    append_tsv(name, r)
+    return r
+
+
+def main() -> int:
+    RESULTS.write_text(
+        "name\ttest_id\tn\tdelivered\tplan\tconnect_med\ttxdone_med\tteardown_med\t"
+        "cycle_med\tp90\tmax\twifi_ready\tencode\tsendto\tnonce\tpre\tpost_mode\t"
+        "auth\tcb_seen\tcb_timeout\tsamples\n",
+        encoding="utf-8",
+    )
+    CHAT.write_text("", encoding="utf-8")
+    best: dict | None = None
+    test_no = 1
+    remaining = 12
+
+    # --- VAL20 screen ---
+    name = "VAL20_PRE200"
+    log(f"=== {name} ===")
+    r = run_one(name, test_id=101, n=20, pre_ms=200, timeout_s=900)
+    write_chat(test_no, remaining - 1, name, r, best, "VAL100 if cb>=18")
+    test_no += 1
+    remaining -= 1
+
+    if r.get("auth", 0) != 3:
+        log("INVALID: authmode != WPA2_PSK(3)")
+        STATE.write_text(json.dumps({"stop": "invalid_auth", "r": r}, indent=2), encoding="utf-8")
+        return 2
+    if r["wr"] < 20 or r["enc"] < 20 or r["st"] < 20 or r["nonce"] < 20:
+        log(f"SCREEN FAIL lifecycle wr={r['wr']} enc={r['enc']} st={r['st']} nonce={r['nonce']}")
+        STATE.write_text(json.dumps({"stop": "lifecycle", "r": r}, indent=2), encoding="utf-8")
+        return 3
+    if r.get("cba", 0) < 18:
+        log(f"SCREEN STOP callback_seen={r.get('cba')}/20")
+        STATE.write_text(json.dumps({"stop": "callback_weak", "r": r}, indent=2), encoding="utf-8")
+        return 4
+
+    best = {
+        "name": name,
+        "pre": 200,
+        "cyc": r["cyc"],
+        "conn": r["conn"],
+        "del": r["del"],
+        "plan": r["plan"],
+        "cba": r.get("cba", 0),
+        "cbt": r.get("cbt", 0),
+        "txd": r.get("txd", 0),
+        "p90": r["p90"],
+        "mx": r["mx"],
+    }
+
+    if r["del"] < 18:
+        log("delivery <18/20 — continue only if callback strong; stopping per screen gate soft")
+        # User: if delivery >=18 and callback almost always → continue
+        STATE.write_text(json.dumps({"stop": "delivery_screen", "r": r}, indent=2), encoding="utf-8")
+        return 5
+
+    # --- VAL100 ---
+    name = "VAL100_PRE200"
+    log(f"=== {name} ===")
+    r = run_one(name, test_id=102, n=100, pre_ms=200, timeout_s=3600)
+    write_chat(test_no, remaining - 1, name, r, best, "VAL200 if normal")
+    test_no += 1
+    remaining -= 1
+    if r.get("auth", 0) != 3:
+        log("INVALID auth on VAL100")
+        return 2
+    best = {
+        "name": name,
+        "pre": 200,
+        "cyc": r["cyc"],
+        "conn": r["conn"],
+        "del": r["del"],
+        "plan": r["plan"],
+        "cba": r.get("cba", 0),
+        "cbt": r.get("cbt", 0),
+        "txd": r.get("txd", 0),
+        "p90": r["p90"],
+        "mx": r["mx"],
+    }
+    STATE.write_text(json.dumps({"val100": r, "best": best}, indent=2), encoding="utf-8")
+
+    # Gate: callback mostly works
+    if r.get("cba", 0) < 90:
+        log("VAL100 callback weak — stop before VAL200")
+        return 6
+
+    # --- VAL200 ---
+    name = "VAL200_PRE200"
+    log(f"=== {name} ===")
+    r = run_one(name, test_id=103, n=200, pre_ms=200, timeout_s=7200)
+    write_chat(test_no, remaining - 1, name, r, best, "PRE sweep if stable")
+    test_no += 1
+    remaining -= 1
+    val200 = dict(r)
+    best = {
+        "name": name,
+        "pre": 200,
+        "cyc": r["cyc"],
+        "conn": r["conn"],
+        "del": r["del"],
+        "plan": r["plan"],
+        "cba": r.get("cba", 0),
+        "cbt": r.get("cbt", 0),
+        "txd": r.get("txd", 0),
+        "p90": r["p90"],
+        "mx": r["mx"],
+    }
+    saving = OLD_WINNER_CYCLE - r["cyc"]
+    log(
+        f"COMPARE old={OLD_WINNER_CYCLE} new={r['cyc']} saving={saving}ms "
+        f"({100.0 * saving / OLD_WINNER_CYCLE:.1f}%)"
+    )
+
+    # --- PRE sweep (screen 20) if callback stable ---
+    pre_sweep_results = []
+    if r.get("cba", 0) >= 180 and r["cyc"] < OLD_WINNER_CYCLE:
+        for pre in (150, 100, 75, 50, 25, 0):
+            name = f"PRE{pre}_S20"
+            log(f"=== {name} ===")
+            rr = run_one(name, test_id=110 + pre // 5, n=20, pre_ms=pre, timeout_s=900)
+            write_chat(test_no, max(0, remaining - 1), name, rr, best, f"next PRE")
+            test_no += 1
+            remaining = max(0, remaining - 1)
+            pre_sweep_results.append((pre, rr))
+            cb_ok = rr.get("cba", 0) >= 18
+            del_ok = rr["del"] >= 15  # UDP losses ok; not sharply worse
+            if not cb_ok:
+                log(f"PRE={pre} callback weak — stop sweep")
+                break
+            if cb_ok and del_ok and rr["cyc"] <= best["cyc"]:
+                best = {
+                    "name": name,
+                    "pre": pre,
+                    "cyc": rr["cyc"],
+                    "conn": rr["conn"],
+                    "del": rr["del"],
+                    "plan": rr["plan"],
+                    "cba": rr.get("cba", 0),
+                    "cbt": rr.get("cbt", 0),
+                    "txd": rr.get("txd", 0),
+                    "p90": rr["p90"],
+                    "mx": rr["mx"],
+                }
+            # If delivery collapses sharply vs VAL20 baseline 18+, stop
+            if rr["del"] < 12:
+                log(f"PRE={pre} delivery collapsed — stop sweep")
+                break
+
+    STATE.write_text(
+        json.dumps(
+            {
+                "val200": val200,
+                "best": best,
+                "pre_sweep": [(p, x) for p, x in pre_sweep_results],
+                "old_winner": OLD_WINNER_CYCLE,
+            },
+            indent=2,
+        ),
+        encoding="utf-8",
+    )
+    log(f"DONE best={best}")
+    return 0
+
+
+if __name__ == "__main__":
+    raise SystemExit(main())
diff --git a/experiments/run_deepsleep_5x50.py b/experiments/run_deepsleep_5x50.py
new file mode 100644
index 0000000..175e16c
--- /dev/null
+++ b/experiments/run_deepsleep_5x50.py
@@ -0,0 +1,280 @@
+"""Build/flash/monitor prepared deep-sleep 5x50 E2E (silent ESP, Æther receiver)."""
+
+from __future__ import annotations
+
+import os
+import re
+import subprocess
+import sys
+import time
+from pathlib import Path
+
+ROOT = Path(r"C:\Users\nickc\Projects\temperature-sensor-prepared")
+# Reuse existing IDF-configured ESP32-C6 build tree (do not create a desktop cmake dir).
+BUILD = ROOT / "build-esp32c6-save-bench-smoke"
+AETHER = r"C:/Users/nickc/Projects/aether-client-cpp-prepared-packet-v0"
+PY = Path(r"C:\Espressif\python_env\idf6.0_py3.11_env\Scripts\python.exe")
+CMAKE = Path(r"C:\Espressif\tools\cmake\3.30.2\bin\cmake.exe")
+NINJA = Path(r"C:\Espressif\tools\ninja\1.12.1\ninja.exe")
+RX_EXE = ROOT / "temperature_receiver" / "build-bisect" / "temperature_receiver.exe"
+RX_SESSION = ROOT / "experiments" / "prepared_wifi_cache_rx_session"
+RX_LOG = ROOT / "experiments" / "prepared_deepsleep_5x50_rx.log"
+TSV = ROOT / "experiments" / "prepared_deepsleep_5x50.tsv"
+PROGRESS = ROOT / "experiments" / "deepsleep_5x50_progress.log"
+CHAT = ROOT / "experiments" / "deepsleep_5x50_chat.txt"
+
+IDF_PATH = r"C:\Espressif\frameworks\esp-idf-v6.0.2"
+CCACHE = r"C:\Espressif\tools\ccache\4.12.1\ccache-4.12.1-windows-x86_64"
+
+RESULT_RE = re.compile(r"TEST_RESULT .* BENCH_DONE deepsleep_5x50|BENCH_DONE deepsleep_5x50")
+OUTER_RE = re.compile(r"\[OUTER (?P\d+)/5\]")
+
+
+def env() -> dict:
+    e = os.environ.copy()
+    e["IDF_PATH"] = IDF_PATH
+    e["IDF_TOOLS_PATH"] = r"C:\Espressif"
+    extra = [
+        CCACHE,
+        r"C:\Espressif\tools\ninja\1.12.1",
+        r"C:\Espressif\tools\cmake\3.30.2\bin",
+        r"C:\msys64\ucrt64\bin",
+    ]
+    e["Path"] = ";".join(extra) + ";" + e.get("Path", "")
+    e.pop("CCACHE_DISABLE", None)
+    return e
+
+
+def log(msg: str) -> None:
+    line = time.strftime("%H:%M:%S") + " " + msg
+    print(line, flush=True)
+    PROGRESS.parent.mkdir(parents=True, exist_ok=True)
+    with PROGRESS.open("a", encoding="utf-8") as f:
+        f.write(line + "\n")
+
+
+def force_sdk_fixes() -> None:
+    sdk = BUILD / "sdkconfig"
+    if not sdk.exists():
+        return
+    text = sdk.read_text(encoding="utf-8")
+    reps = [
+        ("CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y", "# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set"),
+        ("CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y", "# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set"),
+        ("CONFIG_RTC_CLK_SRC_INT_RC=y", "# CONFIG_RTC_CLK_SRC_INT_RC is not set"),
+        ("# CONFIG_RTC_CLK_SRC_EXT_CRYS is not set", "CONFIG_RTC_CLK_SRC_EXT_CRYS=y"),
+        ("CONFIG_ESP_BROWNOUT_DET=n", "CONFIG_ESP_BROWNOUT_DET=y"),
+        ("# CONFIG_ESP_BROWNOUT_DET is not set", "CONFIG_ESP_BROWNOUT_DET=y"),
+        ("CONFIG_PM_ENABLE=y", "# CONFIG_PM_ENABLE is not set"),
+    ]
+    for a, b in reps:
+        text = text.replace(a, b)
+    if "CONFIG_RTC_CLK_SRC_EXT_CRYS=y" not in text:
+        text += "\nCONFIG_RTC_CLK_SRC_EXT_CRYS=y\n"
+    sdk.write_text(text, encoding="utf-8")
+
+
+def show_effective() -> None:
+    sdk = BUILD / "sdkconfig"
+    keys = [
+        "CONFIG_RTC_CLK_SRC_EXT_CRYS",
+        "CONFIG_RTC_CLK_SRC_INT_RC",
+        "CONFIG_ESP_BROWNOUT_DET",
+        "CONFIG_ESP_BROWNOUT_DET_LVL_SEL_7",
+        "CONFIG_ESP_WIFI_ENABLE_WPA3_SAE",
+        "CONFIG_ESP_CONSOLE_NONE",
+        "CONFIG_LOG_DEFAULT_LEVEL_NONE",
+        "CONFIG_BOOTLOADER_LOG_LEVEL_NONE",
+        "CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160",
+        "CONFIG_PM_ENABLE",
+        "CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP",
+        "CONFIG_RTC_CLK_CAL_CYCLES",
+    ]
+    log("=== effective sdkconfig ===")
+    text = sdk.read_text(encoding="utf-8") if sdk.exists() else ""
+    for k in keys:
+        lines = [ln for ln in text.splitlines() if k in ln and not ln.strip().startswith("# ") or ln.startswith(f"# {k}")]
+        # simpler: grep style
+        matched = [ln for ln in text.splitlines() if k in ln]
+        for ln in matched[:3]:
+            log(ln)
+
+
+def cmake_configure() -> None:
+    args = [
+        str(CMAKE),
+        "-S",
+        str(ROOT),
+        "-B",
+        str(BUILD),
+        "-G",
+        "Ninja",
+        f"-DCPM_aether-client-cpp_SOURCE={AETHER}",
+        "-DAE_EXP_PREPARED_DEEPSLEEP_5X50=1",
+        "-DAE_EXP_PREPARED_WIFI_FASTEST=",
+        "-DAE_EXP_PREPARED_WIFI_BISECT=",
+        "-DAE_EXP_BISECT_CONSOLE=",
+        "-DAE_EXP_BISECT_SMOKE=",
+        "-DAE_EXP_SKIP_DTOR_SAVE=1",
+        "-DSERVICE_UID=5aade50f-00d9-4624-b097-e203cdcf1e38",
+        "-DBENCH_CLIENT_ID=prepared_deepsleep_5x50_v1",
+        "-DWIFI_SSID=chirkov",
+        "-DWIFI_PASSWORD=kcdjepWz51",
+        "-DCMAKE_BUILD_TYPE=Release",
+    ]
+    log("cmake configure deepsleep_5x50")
+    r = subprocess.run(args, cwd=ROOT, env=env(), capture_output=True, text=True)
+    if r.returncode != 0:
+        (ROOT / "experiments" / "deepsleep_cmake.err").write_text(
+            r.stdout + "\n" + r.stderr, encoding="utf-8"
+        )
+        raise RuntimeError("cmake failed")
+    log("cmake ok")
+
+
+def ninja_build() -> None:
+    r = subprocess.run(
+        [str(NINJA), "-C", str(BUILD)], env=env(), capture_output=True, text=True
+    )
+    if r.returncode != 0:
+        (ROOT / "experiments" / "deepsleep_build.err").write_text(
+            r.stdout[-12000:] + "\n" + r.stderr[-12000:], encoding="utf-8"
+        )
+        raise RuntimeError("ninja failed")
+    log("build ok")
+
+
+def flash() -> None:
+    cmd = [
+        str(PY),
+        "-m",
+        "esptool",
+        "--chip",
+        "esp32c6",
+        "-p",
+        "COM7",
+        "-b",
+        "460800",
+        "write-flash",
+        "--flash-size",
+        "4MB",
+        "0x0",
+        str(BUILD / "bootloader" / "bootloader.bin"),
+        "0x8000",
+        str(BUILD / "partition_table" / "partition-table.bin"),
+        "0x10000",
+        str(BUILD / "temperature_sensor.bin"),
+    ]
+    r = subprocess.run(cmd, env=env(), capture_output=True, text=True)
+    if r.returncode != 0:
+        (ROOT / "experiments" / "deepsleep_flash.err").write_text(
+            r.stdout + "\n" + r.stderr, encoding="utf-8"
+        )
+        raise RuntimeError("flash failed")
+    log("flash ok")
+
+
+def ensure_receiver() -> None:
+    out = subprocess.run(
+        ["tasklist", "/FI", "IMAGENAME eq temperature_receiver.exe"],
+        capture_output=True,
+        text=True,
+    ).stdout
+    if "temperature_receiver.exe" in out:
+        log("receiver already running")
+        return
+    RX_SESSION.mkdir(parents=True, exist_ok=True)
+    env2 = env()
+    env2["AE_RECEIVER_SESSION_DIR"] = str(RX_SESSION)
+    env2["AE_DS_TSV"] = str(TSV)
+    RX_LOG.parent.mkdir(parents=True, exist_ok=True)
+    with RX_LOG.open("a", encoding="utf-8") as outf, (
+        ROOT / "experiments" / "prepared_deepsleep_5x50_rx.log.err"
+    ).open("a", encoding="utf-8") as errf:
+        subprocess.Popen(
+            [str(RX_EXE)],
+            cwd=str(RX_SESSION),
+            env=env2,
+            stdout=outf,
+            stderr=errf,
+        )
+    time.sleep(4)
+    log("receiver started")
+
+
+def tsv_stats() -> dict:
+    if not TSV.exists():
+        return {}
+    rows = list(TSV.read_text(encoding="utf-8").splitlines())
+    if len(rows) < 2:
+        return {}
+    full = hot = 0
+    outers_full = set()
+    for line in rows[1:]:
+        parts = line.split("\t")
+        if len(parts) < 3:
+            continue
+        kind = parts[1]
+        outer = parts[2]
+        if kind == "1":
+            full += 1
+            outers_full.add(outer)
+        elif kind == "2":
+            hot += 1
+    return {"full": full, "hot": hot, "outers": outers_full}
+
+
+def wait_done(timeout_s: int = 1800) -> str:
+    deadline = time.time() + timeout_s
+    last_len = 0
+    last_outer = 0
+    while time.time() < deadline:
+        if RX_LOG.exists():
+            text = RX_LOG.read_text(encoding="utf-8", errors="replace")
+            if len(text) != last_len:
+                last_len = len(text)
+                for m in OUTER_RE.finditer(text):
+                    o = int(m.group("o"))
+                    if o > last_outer:
+                        last_outer = o
+                        idx = m.start()
+                        block = text[idx : idx + 350]
+                        with CHAT.open("a", encoding="utf-8") as f:
+                            f.write(block + "\n")
+                        print(block, flush=True)
+                if "BENCH_DONE deepsleep_5x50" in text:
+                    for line in reversed(text.splitlines()):
+                        if line.startswith("TEST_RESULT"):
+                            return line
+                    return "BENCH_DONE"
+        st = tsv_stats()
+        # Complete enough without FINAL: 5 FULL + >=245 HOT
+        if st.get("full", 0) >= 5 and st.get("hot", 0) >= 245:
+            log(f"TSV complete enough full={st['full']} hot={st['hot']}")
+            return f"TSV_COMPLETE full={st['full']} hot={st['hot']}"
+        time.sleep(5)
+    raise TimeoutError("no BENCH_DONE")
+
+
+def main() -> int:
+    CHAT.write_text("", encoding="utf-8")
+    if TSV.exists():
+        TSV.unlink()
+    ensure_receiver()
+    cmake_configure()
+    force_sdk_fixes()
+    show_effective()
+    ninja_build()
+    force_sdk_fixes()
+    show_effective()
+    flash()
+    log("waiting for 5x50 deepsleep run (~15-25 min)...")
+    result = wait_done(2400)
+    log("RESULT " + result)
+    with CHAT.open("a", encoding="utf-8") as f:
+        f.write(result + "\n")
+    return 0
+
+
+if __name__ == "__main__":
+    raise SystemExit(main())
diff --git a/experiments/run_fastest_continue.py b/experiments/run_fastest_continue.py
new file mode 100644
index 0000000..becb231
--- /dev/null
+++ b/experiments/run_fastest_continue.py
@@ -0,0 +1,397 @@
+"""Resume fastest-path campaign after AUTH3B WPA2 SAE-off verified win."""
+
+from __future__ import annotations
+
+import json
+import sys
+from pathlib import Path
+
+sys.path.insert(0, str(Path(__file__).resolve().parent))
+from run_fastest_path import (  # noqa: E402
+    CHAT,
+    RESULTS,
+    STATE,
+    cmake_configure,
+    ensure_receiver,
+    log,
+    ninja_build,
+    pass20,
+    run_test,
+    write_chat,
+)
+
+# Winner association+auth from AUTH3B verified: BASE caches + real WPA2
+# (CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=n). Security decision later; report only.
+CUR = {
+    "AE_EXP_FAST_PRE_MS": "200",
+    "AE_EXP_FAST_POST_MS": "300",
+    "AE_EXP_FAST_USE_BSSID": "0",
+    "AE_EXP_FAST_FAST_SCAN": "0",
+    "AE_EXP_FAST_AUTH": "2",
+    "AE_EXP_FAST_RETRY": "10",
+    "AE_EXP_FAST_POST_MODE": "0",
+    "AE_EXP_FAST_AMPDU_TX_OFF": "0",
+    "AE_EXP_FAST_STORAGE_RAM": "0",
+    "AE_EXP_FAST_DISABLE_WPA3": "1",
+}
+
+BEST = {
+    "name": "AUTH3B_WPA3SAE_OFF_VERIFIED",
+    "cyc": 710,
+    "conn": 128,
+    "del": 20,
+    "plan": 20,
+    "pre": 200,
+    "post": 300,
+    "pm": 0,
+    "p90": 810,
+    "auth": 3,
+}
+
+TEST_NO = 9
+REMAINING = 14
+
+
+def consider(name: str, r: dict) -> None:
+    global BEST
+    if not pass20(r) and r.get("plan", 20) <= 20 and r["del"] < r["plan"]:
+        return
+    if r["del"] < max(1, int(0.95 * r["plan"])):
+        return
+    clear = BEST is None or r["cyc"] + 20 < BEST["cyc"]
+    if clear or (BEST and r["cyc"] < BEST["cyc"] and r["del"] >= BEST["del"]):
+        BEST = dict(r)
+        BEST["name"] = name
+
+
+def report(name: str, r: dict, nxt: str) -> None:
+    global TEST_NO, REMAINING
+    consider(name, r)
+    REMAINING = max(0, REMAINING - 1)
+    write_chat(TEST_NO, REMAINING, name, r, BEST, nxt)
+    TEST_NO += 1
+    STATE.write_text(
+        json.dumps({"best": BEST, "cur": CUR, "last": name, "result": r}, indent=2),
+        encoding="utf-8",
+    )
+
+
+def force_wpa3_off() -> None:
+    """Ensure sdkconfig.defaults.wpa2only is applied via cmake flag."""
+    sdk = Path(
+        r"C:\Users\nickc\Projects\temperature-sensor-prepared"
+        r"\build-esp32c6-save-bench-smoke\sdkconfig"
+    )
+    text = sdk.read_text(encoding="utf-8")
+    text = text.replace(
+        "CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y",
+        "# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set",
+    )
+    text = text.replace(
+        "CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y",
+        "# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set",
+    )
+    sdk.write_text(text, encoding="utf-8")
+
+
+def restore_wpa3() -> None:
+    sdk = Path(
+        r"C:\Users\nickc\Projects\temperature-sensor-prepared"
+        r"\build-esp32c6-save-bench-smoke\sdkconfig"
+    )
+    text = sdk.read_text(encoding="utf-8")
+    text = text.replace(
+        "# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set",
+        "CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y",
+    )
+    text = text.replace(
+        "# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set",
+        "CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y",
+    )
+    if "CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y" not in text:
+        text += "\nCONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y\n"
+    sdk.write_text(text, encoding="utf-8")
+    cmake_configure(
+        {
+            **CUR,
+            "AE_EXP_FAST_DISABLE_WPA3": "",
+            "AE_EXP_FAST_AUTH": "0",
+            "AE_EXP_FAST_TEST_ID": "99",
+        }
+    )
+    # re-patch after cmake may re-enable from defaults without overlay
+    text = sdk.read_text(encoding="utf-8")
+    if "CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y" not in text:
+        text = text.replace(
+            "# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set",
+            "CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y",
+        )
+        sdk.write_text(text, encoding="utf-8")
+        cmake_configure(
+            {
+                **CUR,
+                "AE_EXP_FAST_DISABLE_WPA3": "",
+                "AE_EXP_FAST_AUTH": "0",
+                "AE_EXP_FAST_TEST_ID": "99",
+            }
+        )
+    log("WPA3 SAE restore attempted")
+
+
+def main() -> int:
+    log("=== FASTEST PATH CONTINUE from R0 ===")
+    ensure_receiver()
+    force_wpa3_off()
+
+    # 6. Retry
+    r0 = run_test("R0", {**CUR, "AE_EXP_FAST_TEST_ID": "8", "AE_EXP_FAST_RETRY": "0"}, 20)
+    report("R0", r0, "R1 retry=1 x20")
+    r1 = run_test("R1", {**CUR, "AE_EXP_FAST_TEST_ID": "9", "AE_EXP_FAST_RETRY": "1"}, 20)
+    report("R1", r1, "R3 retry=3 x20")
+    r3 = run_test("R3", {**CUR, "AE_EXP_FAST_TEST_ID": "10", "AE_EXP_FAST_RETRY": "3"}, 20)
+    report("R3", r3, "CB0 tx-done callback POST=0 x20")
+
+    retry = 10
+    if pass20(r0) and r0["wr"] >= 19:
+        retry = 0
+    elif pass20(r1) and r1["wr"] >= 19:
+        retry = 1
+    elif pass20(r3) and r3["wr"] >= 19:
+        retry = 3
+    # Prefer smallest retry that keeps delivery; don't pick by median alone
+    CUR["AE_EXP_FAST_RETRY"] = str(retry)
+    log(f"retry selected {retry}")
+
+    # 7. Callback
+    cb0 = run_test(
+        "CB0",
+        {
+            **CUR,
+            "AE_EXP_FAST_TEST_ID": "11",
+            "AE_EXP_FAST_POST_MODE": "1",
+            "AE_EXP_FAST_POST_MS": "0",
+        },
+        20,
+    )
+    cb_usable = pass20(cb0) and cb0.get("cbm", 0) >= 15
+    if not cb_usable:
+        log("CALLBACK_NOT_USABLE")
+        CUR["AE_EXP_FAST_POST_MODE"] = "0"
+        CUR["AE_EXP_FAST_POST_MS"] = "300"
+        report("CB0", cb0, "PRE sweep from 200ms (fixed POST=300)")
+    else:
+        CUR["AE_EXP_FAST_POST_MODE"] = "1"
+        CUR["AE_EXP_FAST_POST_MS"] = "0"
+        consider("CB0", cb0)
+        if cb0["del"] < 20:
+            report("CB0", cb0, "CB1 callback+10ms")
+            cb1 = run_test(
+                "CB1_10",
+                {**CUR, "AE_EXP_FAST_TEST_ID": "12", "AE_EXP_FAST_POST_MODE": "2"},
+                20,
+            )
+            if pass20(cb1):
+                CUR["AE_EXP_FAST_POST_MODE"] = "2"
+                report("CB1_10", cb1, "PRE sweep")
+            else:
+                report("CB1_10", cb1, "CB2 callback+25ms")
+                cb2 = run_test(
+                    "CB2_25",
+                    {**CUR, "AE_EXP_FAST_TEST_ID": "13", "AE_EXP_FAST_POST_MODE": "3"},
+                    20,
+                )
+                if pass20(cb2):
+                    CUR["AE_EXP_FAST_POST_MODE"] = "3"
+                    report("CB2_25", cb2, "PRE sweep")
+                else:
+                    CUR["AE_EXP_FAST_POST_MODE"] = "0"
+                    CUR["AE_EXP_FAST_POST_MS"] = "300"
+                    report("CB2_25", cb2, "callback weak — PRE with POST=300")
+        else:
+            report("CB0", cb0, "PRE sweep (callback POST)")
+
+    # 8. PRE sweep
+    best_pre = int(CUR["AE_EXP_FAST_PRE_MS"])
+    pre_vals = [200, 150, 100, 75, 50, 25, 0]
+    for i, pre in enumerate(pre_vals):
+        name = f"PRE_{pre}"
+        rr = run_test(
+            name,
+            {**CUR, "AE_EXP_FAST_TEST_ID": str(20 + i), "AE_EXP_FAST_PRE_MS": str(pre)},
+            20,
+        )
+        nxt = f"PRE_{pre_vals[i+1]}" if i + 1 < len(pre_vals) else "POST sweep or 2D"
+        if rr["del"] >= 20:
+            report(name, rr, nxt)
+            best_pre = pre
+            continue
+        if rr["del"] == 19:
+            report(name, rr, name + " repeat")
+            rr2 = run_test(
+                name + "_R",
+                {
+                    **CUR,
+                    "AE_EXP_FAST_TEST_ID": str(40 + i),
+                    "AE_EXP_FAST_PRE_MS": str(pre),
+                },
+                20,
+            )
+            if rr2["del"] >= 19:
+                report(name + "_R", rr2, nxt)
+                best_pre = pre
+                continue
+        report(name, rr, f"PRE stop at {pre}; use best_pre={best_pre}")
+        log(f"PRE {pre} too aggressive — stop")
+        break
+    CUR["AE_EXP_FAST_PRE_MS"] = str(best_pre)
+
+    # 9. POST sweep if fixed delay
+    best_post = int(CUR.get("AE_EXP_FAST_POST_MS", "300"))
+    if CUR.get("AE_EXP_FAST_POST_MODE", "0") == "0":
+        post_vals = [300, 250, 200, 150, 100, 75, 50, 25, 0]
+        for i, post in enumerate(post_vals):
+            name = f"POST_{post}"
+            rr = run_test(
+                name,
+                {
+                    **CUR,
+                    "AE_EXP_FAST_TEST_ID": str(50 + i),
+                    "AE_EXP_FAST_POST_MS": str(post),
+                },
+                20,
+            )
+            nxt = (
+                f"POST_{post_vals[i+1]}"
+                if i + 1 < len(post_vals)
+                else "2D neighbors"
+            )
+            if rr["del"] >= 20:
+                report(name, rr, nxt)
+                best_post = post
+                continue
+            if rr["del"] == 19:
+                report(name, rr, name + " repeat")
+                rr2 = run_test(
+                    name + "_R",
+                    {
+                        **CUR,
+                        "AE_EXP_FAST_TEST_ID": str(60 + i),
+                        "AE_EXP_FAST_POST_MS": str(post),
+                    },
+                    20,
+                )
+                if rr2["del"] >= 19:
+                    report(name + "_R", rr2, nxt)
+                    best_post = post
+                    continue
+            report(name, rr, f"POST stop; best_post={best_post}")
+            break
+        CUR["AE_EXP_FAST_POST_MS"] = str(best_post)
+
+    # 10. 2D neighbors
+    p = int(CUR["AE_EXP_FAST_PRE_MS"])
+    q = int(CUR.get("AE_EXP_FAST_POST_MS", "0"))
+    neighbors = []
+    if CUR.get("AE_EXP_FAST_POST_MODE", "0") == "0":
+        neighbors = [
+            (max(0, p - 25), q + 25),
+            (p + 25, max(0, q - 25)),
+            (max(0, p - 50), q + 50),
+            (p + 50, max(0, q - 50)),
+        ]
+    for i, (pp, qq) in enumerate(neighbors):
+        name = f"2D_p{pp}_q{qq}"
+        rr = run_test(
+            name,
+            {
+                **CUR,
+                "AE_EXP_FAST_TEST_ID": str(70 + i),
+                "AE_EXP_FAST_PRE_MS": str(pp),
+                "AE_EXP_FAST_POST_MS": str(qq),
+            },
+            20,
+        )
+        report(name, rr, "next 2D or VAL100")
+        if pass20(rr) and BEST and BEST.get("name") == name:
+            CUR["AE_EXP_FAST_PRE_MS"] = str(pp)
+            CUR["AE_EXP_FAST_POST_MS"] = str(qq)
+
+    # Align CUR to BEST delays if best is a PRE/POST/2D variant
+    if BEST:
+        if "pre" in BEST:
+            CUR["AE_EXP_FAST_PRE_MS"] = str(BEST["pre"])
+        if "post" in BEST and CUR.get("AE_EXP_FAST_POST_MODE", "0") == "0":
+            CUR["AE_EXP_FAST_POST_MS"] = str(BEST["post"])
+        if "pm" in BEST:
+            CUR["AE_EXP_FAST_POST_MODE"] = str(BEST["pm"])
+
+    # 11. Validation
+    log(f"validation flags={CUR}")
+    v100 = run_test(
+        "VAL100", {**CUR, "AE_EXP_FAST_TEST_ID": "80"}, 100, timeout_s=45 * 100 + 300
+    )
+    report("VAL100", v100, "VAL200 or VAL100_SAFE")
+    if v100["del"] < 98:
+        cur2 = dict(CUR)
+        cur2["AE_EXP_FAST_PRE_MS"] = "200"
+        if cur2.get("AE_EXP_FAST_POST_MODE", "0") == "0":
+            cur2["AE_EXP_FAST_POST_MS"] = "300"
+        v100b = run_test(
+            "VAL100_SAFE",
+            {**cur2, "AE_EXP_FAST_TEST_ID": "81"},
+            100,
+            timeout_s=45 * 100 + 300,
+        )
+        report("VAL100_SAFE", v100b, "VAL200")
+        if v100b["del"] > v100["del"]:
+            CUR.update(cur2)
+            v100 = v100b
+    if v100["del"] == 98:
+        v100r = run_test(
+            "VAL100_REPEAT",
+            {**CUR, "AE_EXP_FAST_TEST_ID": "82"},
+            100,
+            timeout_s=45 * 100 + 300,
+        )
+        report("VAL100_REPEAT", v100r, "VAL200")
+
+    v200 = run_test(
+        "VAL200", {**CUR, "AE_EXP_FAST_TEST_ID": "90"}, 200, timeout_s=45 * 200 + 300
+    )
+    report("VAL200", v200, "D1 AMPDU TX off")
+
+    # 12. AMPDU
+    d1 = run_test(
+        "D1_AMPDU_TX_OFF",
+        {**CUR, "AE_EXP_FAST_TEST_ID": "91", "AE_EXP_FAST_AMPDU_TX_OFF": "1"},
+        20,
+    )
+    report("D1_AMPDU_TX_OFF", d1, "STORAGE_RAM")
+
+    # 13. storage RAM
+    ram = run_test(
+        "STORAGE_RAM",
+        {**CUR, "AE_EXP_FAST_TEST_ID": "92", "AE_EXP_FAST_STORAGE_RAM": "1"},
+        20,
+    )
+    report("STORAGE_RAM", ram, "write report + restore WPA3")
+
+    log("=== SCREENING COMPLETE ===")
+    log(f"BEST {BEST}")
+    log(f"VAL200 {v200}")
+    STATE.write_text(
+        json.dumps({"best": BEST, "cur": CUR, "val200": v200}, indent=2),
+        encoding="utf-8",
+    )
+
+    # Restore WPA3 SAE for build tree (do not leave production-weakened)
+    restore_wpa3()
+    return 0
+
+
+if __name__ == "__main__":
+    try:
+        sys.exit(main())
+    except Exception as ex:
+        log(f"FATAL {ex}")
+        raise
diff --git a/experiments/run_fastest_continue2.py b/experiments/run_fastest_continue2.py
new file mode 100644
index 0000000..5a29067
--- /dev/null
+++ b/experiments/run_fastest_continue2.py
@@ -0,0 +1,350 @@
+"""Resume from PRE sweep with retry=10 (R0 caused 13/20 on PRE_200)."""
+
+from __future__ import annotations
+
+import json
+import sys
+from pathlib import Path
+
+sys.path.insert(0, str(Path(__file__).resolve().parent))
+from run_fastest_path import (  # noqa: E402
+    STATE,
+    append_tsv,
+    ensure_receiver,
+    log,
+    pass20,
+    run_test,
+    write_chat,
+)
+
+# Record orphaned PRE_200 retry=0 failure if not already in TSV
+RESULTS = Path(__file__).resolve().parent / "prepared_wifi_fastest_path.tsv"
+tsv = RESULTS.read_text(encoding="utf-8") if RESULTS.exists() else ""
+if "PRE_200\t" not in tsv and "PRE_200_R0FAIL" not in tsv:
+    append_tsv(
+        "PRE_200_R0FAIL",
+        {
+            "assoc": 0x1A,
+            "auth": 3,
+            "pre": 200,
+            "post": 300,
+            "del": 13,
+            "plan": 20,
+            "n": 20,
+            "conn": 151,
+            "cyc": 740,
+            "p90": 750,
+            "mx": 760,
+            "wr": 20,
+            "enc": 20,
+            "st": 20,
+            "cba": 0,
+            "cbm": 0,
+            "pm": 0,
+        },
+    )
+
+CUR = {
+    "AE_EXP_FAST_PRE_MS": "200",
+    "AE_EXP_FAST_POST_MS": "300",
+    "AE_EXP_FAST_USE_BSSID": "0",
+    "AE_EXP_FAST_FAST_SCAN": "0",
+    "AE_EXP_FAST_AUTH": "2",
+    "AE_EXP_FAST_RETRY": "10",  # R0 unreliable (13/20)
+    "AE_EXP_FAST_POST_MODE": "0",
+    "AE_EXP_FAST_AMPDU_TX_OFF": "0",
+    "AE_EXP_FAST_STORAGE_RAM": "0",
+    "AE_EXP_FAST_DISABLE_WPA3": "1",
+}
+
+BEST = {
+    "name": "AUTH3B_WPA3SAE_OFF_VERIFIED",
+    "cyc": 710,
+    "conn": 128,
+    "del": 20,
+    "plan": 20,
+    "pre": 200,
+    "post": 300,
+    "pm": 0,
+    "p90": 810,
+    "auth": 3,
+}
+
+TEST_NO = 13
+REMAINING = 12
+
+
+def consider(name: str, r: dict) -> None:
+    global BEST
+    if r["del"] < r["plan"] and r["plan"] <= 20:
+        return
+    if r["plan"] > 20 and r["del"] < int(0.95 * r["plan"]):
+        return
+    if BEST is None or r["cyc"] + 20 < BEST["cyc"] or (
+        r["cyc"] < BEST["cyc"] and r["del"] >= BEST.get("del", 0)
+    ):
+        BEST = dict(r)
+        BEST["name"] = name
+
+
+def report(name: str, r: dict, nxt: str) -> None:
+    global TEST_NO, REMAINING
+    consider(name, r)
+    REMAINING = max(0, REMAINING - 1)
+    write_chat(TEST_NO, REMAINING, name, r, BEST, nxt)
+    TEST_NO += 1
+    STATE.write_text(
+        json.dumps({"best": BEST, "cur": CUR, "last": name, "result": r}, indent=2),
+        encoding="utf-8",
+    )
+
+
+def force_wpa3_off() -> None:
+    sdk = Path(
+        r"C:\Users\nickc\Projects\temperature-sensor-prepared"
+        r"\build-esp32c6-save-bench-smoke\sdkconfig"
+    )
+    text = sdk.read_text(encoding="utf-8")
+    text = text.replace(
+        "CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y",
+        "# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set",
+    )
+    text = text.replace(
+        "CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y",
+        "# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set",
+    )
+    sdk.write_text(text, encoding="utf-8")
+
+
+def restore_wpa3() -> None:
+    from run_fastest_path import cmake_configure
+
+    sdk = Path(
+        r"C:\Users\nickc\Projects\temperature-sensor-prepared"
+        r"\build-esp32c6-save-bench-smoke\sdkconfig"
+    )
+    text = sdk.read_text(encoding="utf-8")
+    text = text.replace(
+        "# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set",
+        "CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y",
+    )
+    text = text.replace(
+        "# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set",
+        "CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y",
+    )
+    if "CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y" not in text:
+        text += "\nCONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y\n"
+    sdk.write_text(text, encoding="utf-8")
+    cmake_configure(
+        {
+            **CUR,
+            "AE_EXP_FAST_DISABLE_WPA3": "",
+            "AE_EXP_FAST_AUTH": "0",
+            "AE_EXP_FAST_TEST_ID": "99",
+        }
+    )
+    log("WPA3 SAE restore attempted")
+
+
+def main() -> int:
+    global TEST_NO
+    log("=== CONTINUE PRE sweep retry=10 (R0 was unreliable) ===")
+    write_chat(
+        13,
+        12,
+        "PRE_200_R0FAIL",
+        {
+            "del": 13,
+            "plan": 20,
+            "cyc": 740,
+            "conn": 151,
+            "p90": 750,
+            "pre": 200,
+            "post": 300,
+            "pm": 0,
+            "cbm": 0,
+        },
+        BEST,
+        "PRE_200 with retry=10",
+    )
+    TEST_NO = 14
+    ensure_receiver()
+    force_wpa3_off()
+
+    best_pre = 200
+    pre_vals = [200, 150, 100, 75, 50, 25, 0]
+    for i, pre in enumerate(pre_vals):
+        name = f"PRE_{pre}"
+        rr = run_test(
+            name,
+            {**CUR, "AE_EXP_FAST_TEST_ID": str(20 + i), "AE_EXP_FAST_PRE_MS": str(pre)},
+            20,
+            timeout_s=900,
+        )
+        nxt = f"PRE_{pre_vals[i+1]}" if i + 1 < len(pre_vals) else "POST sweep"
+        if rr["del"] >= 20:
+            report(name, rr, nxt)
+            best_pre = pre
+            continue
+        if rr["del"] == 19:
+            report(name, rr, name + " repeat")
+            rr2 = run_test(
+                name + "_R",
+                {
+                    **CUR,
+                    "AE_EXP_FAST_TEST_ID": str(40 + i),
+                    "AE_EXP_FAST_PRE_MS": str(pre),
+                },
+                20,
+                timeout_s=900,
+            )
+            if rr2["del"] >= 19:
+                report(name + "_R", rr2, nxt)
+                best_pre = pre
+                continue
+            report(name + "_R", rr2, f"PRE stop; best_pre={best_pre}")
+            break
+        report(name, rr, f"PRE stop at {pre}; best_pre={best_pre}")
+        log(f"PRE {pre} too aggressive — stop")
+        break
+    CUR["AE_EXP_FAST_PRE_MS"] = str(best_pre)
+
+    best_post = 300
+    post_vals = [300, 250, 200, 150, 100, 75, 50, 25, 0]
+    for i, post in enumerate(post_vals):
+        name = f"POST_{post}"
+        rr = run_test(
+            name,
+            {
+                **CUR,
+                "AE_EXP_FAST_TEST_ID": str(50 + i),
+                "AE_EXP_FAST_POST_MS": str(post),
+            },
+            20,
+            timeout_s=900,
+        )
+        nxt = f"POST_{post_vals[i+1]}" if i + 1 < len(post_vals) else "2D"
+        if rr["del"] >= 20:
+            report(name, rr, nxt)
+            best_post = post
+            continue
+        if rr["del"] == 19:
+            report(name, rr, name + " repeat")
+            rr2 = run_test(
+                name + "_R",
+                {
+                    **CUR,
+                    "AE_EXP_FAST_TEST_ID": str(60 + i),
+                    "AE_EXP_FAST_POST_MS": str(post),
+                },
+                20,
+                timeout_s=900,
+            )
+            if rr2["del"] >= 19:
+                report(name + "_R", rr2, nxt)
+                best_post = post
+                continue
+            report(name + "_R", rr2, f"POST stop; best_post={best_post}")
+            break
+        report(name, rr, f"POST stop; best_post={best_post}")
+        break
+    CUR["AE_EXP_FAST_POST_MS"] = str(best_post)
+
+    p = int(CUR["AE_EXP_FAST_PRE_MS"])
+    q = int(CUR["AE_EXP_FAST_POST_MS"])
+    for i, (pp, qq) in enumerate(
+        [
+            (max(0, p - 25), q + 25),
+            (p + 25, max(0, q - 25)),
+            (max(0, p - 50), q + 50),
+            (p + 50, max(0, q - 50)),
+        ]
+    ):
+        name = f"2D_p{pp}_q{qq}"
+        rr = run_test(
+            name,
+            {
+                **CUR,
+                "AE_EXP_FAST_TEST_ID": str(70 + i),
+                "AE_EXP_FAST_PRE_MS": str(pp),
+                "AE_EXP_FAST_POST_MS": str(qq),
+            },
+            20,
+            timeout_s=900,
+        )
+        report(name, rr, "next 2D or VAL100")
+        if pass20(rr) and BEST and BEST.get("name") == name:
+            CUR["AE_EXP_FAST_PRE_MS"] = str(pp)
+            CUR["AE_EXP_FAST_POST_MS"] = str(qq)
+
+    if BEST:
+        CUR["AE_EXP_FAST_PRE_MS"] = str(BEST.get("pre", CUR["AE_EXP_FAST_PRE_MS"]))
+        CUR["AE_EXP_FAST_POST_MS"] = str(BEST.get("post", CUR["AE_EXP_FAST_POST_MS"]))
+
+    log(f"validation flags={CUR}")
+    v100 = run_test(
+        "VAL100", {**CUR, "AE_EXP_FAST_TEST_ID": "80"}, 100, timeout_s=45 * 100 + 600
+    )
+    report("VAL100", v100, "VAL200 or SAFE")
+    if v100["del"] < 98:
+        cur2 = dict(CUR)
+        cur2["AE_EXP_FAST_PRE_MS"] = "200"
+        cur2["AE_EXP_FAST_POST_MS"] = "300"
+        v100b = run_test(
+            "VAL100_SAFE",
+            {**cur2, "AE_EXP_FAST_TEST_ID": "81"},
+            100,
+            timeout_s=45 * 100 + 600,
+        )
+        report("VAL100_SAFE", v100b, "VAL200")
+        if v100b["del"] > v100["del"]:
+            CUR.update(cur2)
+            v100 = v100b
+    if v100["del"] == 98:
+        v100r = run_test(
+            "VAL100_REPEAT",
+            {**CUR, "AE_EXP_FAST_TEST_ID": "82"},
+            100,
+            timeout_s=45 * 100 + 600,
+        )
+        report("VAL100_REPEAT", v100r, "VAL200")
+
+    v200 = run_test(
+        "VAL200", {**CUR, "AE_EXP_FAST_TEST_ID": "90"}, 200, timeout_s=45 * 200 + 600
+    )
+    report("VAL200", v200, "D1 AMPDU")
+
+    d1 = run_test(
+        "D1_AMPDU_TX_OFF",
+        {**CUR, "AE_EXP_FAST_TEST_ID": "91", "AE_EXP_FAST_AMPDU_TX_OFF": "1"},
+        20,
+        timeout_s=900,
+    )
+    report("D1_AMPDU_TX_OFF", d1, "STORAGE_RAM")
+
+    ram = run_test(
+        "STORAGE_RAM",
+        {**CUR, "AE_EXP_FAST_TEST_ID": "92", "AE_EXP_FAST_STORAGE_RAM": "1"},
+        20,
+        timeout_s=900,
+    )
+    report("STORAGE_RAM", ram, "report + restore WPA3")
+
+    # LWIP IRAM A/B via sdkconfig patch if needed — deferred to report writer
+    log("=== SCREENING COMPLETE ===")
+    log(f"BEST {BEST}")
+    log(f"VAL200 {v200}")
+    STATE.write_text(
+        json.dumps({"best": BEST, "cur": CUR, "val200": v200}, indent=2),
+        encoding="utf-8",
+    )
+    restore_wpa3()
+    return 0
+
+
+if __name__ == "__main__":
+    try:
+        sys.exit(main())
+    except Exception as ex:
+        log(f"FATAL {ex}")
+        raise
diff --git a/experiments/run_fastest_path.py b/experiments/run_fastest_path.py
new file mode 100644
index 0000000..229ff9a
--- /dev/null
+++ b/experiments/run_fastest_path.py
@@ -0,0 +1,655 @@
+"""Silent fastest-path prepared Wi-Fi campaign orchestrator (ESP32-C6)."""
+
+from __future__ import annotations
+
+import json
+import os
+import re
+import subprocess
+import sys
+import time
+from pathlib import Path
+
+ROOT = Path(r"C:\Users\nickc\Projects\temperature-sensor-prepared")
+BUILD = ROOT / "build-esp32c6-save-bench-smoke"
+AETHER = r"C:/Users/nickc/Projects/aether-client-cpp-prepared-packet-v0"
+PY = Path(r"C:\Espressif\python_env\idf6.0_py3.11_env\Scripts\python.exe")
+CMAKE = Path(r"C:\Espressif\tools\cmake\3.30.2\bin\cmake.exe")
+NINJA = Path(r"C:\Espressif\tools\ninja\1.12.1\ninja.exe")
+RX_EXE = ROOT / "temperature_receiver" / "build-bisect" / "temperature_receiver.exe"
+RX_SESSION = ROOT / "experiments" / "prepared_wifi_cache_rx_session"
+RX_LOG = ROOT / "experiments" / "prepared_wifi_fastest_rx.log"
+RESULTS = ROOT / "experiments" / "prepared_wifi_fastest_path.tsv"
+PROGRESS = ROOT / "experiments" / "fastest_progress.log"
+STATE = ROOT / "experiments" / "fastest_state.json"
+CHAT = ROOT / "experiments" / "fastest_chat.txt"
+
+IDF_PATH = r"C:\Espressif\frameworks\esp-idf-v6.0.2"
+CCACHE = r"C:\Espressif\tools\ccache\4.12.1\ccache-4.12.1-windows-x86_64"
+
+BASE_CMAKE = {
+    "CPM_aether-client-cpp_SOURCE": AETHER,
+    "AE_EXP_PREPARED_WIFI_FASTEST": "1",
+    "AE_EXP_PREPARED_WIFI_BISECT": "",
+    "AE_EXP_BISECT_CONSOLE": "",
+    "AE_EXP_BISECT_SMOKE": "",
+    "AE_EXP_SKIP_DTOR_SAVE": "1",
+    "SERVICE_UID": "5aade50f-00d9-4624-b097-e203cdcf1e38",
+    "BENCH_CLIENT_ID": "prepared_wifi_bisect_v1",
+    "WIFI_SSID": "chirkov",
+    "WIFI_PASSWORD": "kcdjepWz51",
+    "AETHER_PREPARED_POST_SEND_HOLD_MS": "300",
+    "AE_EXP_FAST_DISABLE_WPA3": "",
+}
+
+RESULT_RE = re.compile(
+    r"TEST_RESULT test_id=(?P\d+) n=(?P\d+) delivered=(?P\d+)/(?P\d+) "
+    r"connect_med_ms=(?P\d+) cycle_med_ms=(?P\d+) p90_ms=(?P\d+) "
+    r"max_ms=(?P\d+) wifi_ready=(?P\d+) encode=(?P\d+) sendto=(?P\d+) "
+    r"nonce=(?P\d+) pre=(?P
\d+) post=(?P\d+) assoc=0x(?P[0-9a-fA-F]+) "
+    r"auth=(?P\d+) retry=(?P\d+) post_mode=(?P\d+) cb_any=(?P\d+) "
+    r"cb_match=(?P\d+) samples=(?P\d+)"
+)
+
+
+def env() -> dict:
+    e = os.environ.copy()
+    e["IDF_PATH"] = IDF_PATH
+    e["IDF_TOOLS_PATH"] = r"C:\Espressif"
+    extra = [
+        CCACHE,
+        r"C:\Espressif\tools\ninja\1.12.1",
+        r"C:\Espressif\tools\cmake\3.30.2\bin",
+        r"C:\msys64\ucrt64\bin",
+    ]
+    e["Path"] = ";".join(extra) + ";" + e.get("Path", "")
+    e.pop("CCACHE_DISABLE", None)
+    return e
+
+
+def log(msg: str) -> None:
+    line = time.strftime("%H:%M:%S") + " " + msg
+    print(line, flush=True)
+    PROGRESS.parent.mkdir(parents=True, exist_ok=True)
+    with PROGRESS.open("a", encoding="utf-8") as f:
+        f.write(line + "\n")
+
+
+def write_chat(test_no: int, remaining: int, name: str, r: dict, best: dict | None, nxt: str) -> None:
+    result = "PASS" if r["del"] == r["plan"] and r["plan"] > 0 else "FAIL"
+    if name.startswith("CB") and r.get("cbm", 0) < 15:
+        result = "CALLBACK_NOT_USABLE"
+    best_s = "none"
+    if best:
+        best_s = (
+            f"{best.get('name','?')} cycle={best.get('cyc')}ms "
+            f"connect={best.get('conn')}ms del={best.get('del')}/{best.get('plan')}"
+        )
+    delta = ""
+    if best and best.get("name") != name:
+        delta = f"change vs best={r['cyc'] - best['cyc']:+d} ms"
+    elif best and best.get("name") == name:
+        delta = "change vs best=NEW BEST"
+    lines = [
+        f"[TEST {test_no}/{test_no + remaining}] {name}",
+        f"delivery={r['del']}/{r['plan']}",
+        f"median_cycle={r['cyc']} ms",
+        f"median_connect={r['conn']} ms",
+        f"p90={r['p90']}",
+        f"result={result}",
+        f"remaining={remaining}",
+        f"best={best_s}",
+        delta,
+        "BEST NOW:",
+        f"config={best.get('name') if best else 'none'}",
+        f"pre={best.get('pre') if best else '-'} post/callback={best.get('post') if best else '-'} mode={best.get('pm') if best else '-'}",
+        f"median={best.get('cyc') if best else '-'}",
+        f"NEXT: {nxt}",
+        "",
+    ]
+    text = "\n".join(x for x in lines if x is not None)
+    with CHAT.open("a", encoding="utf-8") as f:
+        f.write(text + "\n")
+    log("CHAT\n" + text)
+
+
+def cmake_configure(flags: dict) -> None:
+    args = [str(CMAKE), "-S", str(ROOT), "-B", str(BUILD), "-G", "Ninja"]
+    merged = dict(BASE_CMAKE)
+    merged.update(flags)
+    for k, v in merged.items():
+        args.append(f"-D{k}={v}")
+    log("cmake " + " ".join(f"{k}={v}" for k, v in flags.items()))
+    r = subprocess.run(args, cwd=ROOT, env=env(), capture_output=True, text=True)
+    if r.returncode != 0:
+        (ROOT / "experiments" / "fastest_cmake.err").write_text(
+            r.stdout + "\n" + r.stderr, encoding="utf-8"
+        )
+        raise RuntimeError("cmake failed")
+
+
+def ninja_build() -> None:
+    r = subprocess.run(
+        [str(NINJA), "-C", str(BUILD)],
+        env=env(),
+        capture_output=True,
+        text=True,
+    )
+    if r.returncode != 0:
+        (ROOT / "experiments" / "fastest_build.err").write_text(
+            r.stdout[-8000:] + "\n" + r.stderr[-8000:], encoding="utf-8"
+        )
+        raise RuntimeError("ninja failed")
+    log("build ok")
+
+
+def flash() -> None:
+    cmd = [
+        str(PY),
+        "-m",
+        "esptool",
+        "--chip",
+        "esp32c6",
+        "-p",
+        "COM7",
+        "-b",
+        "460800",
+        "write-flash",
+        "--flash-size",
+        "4MB",
+        "0x0",
+        str(BUILD / "bootloader" / "bootloader.bin"),
+        "0x8000",
+        str(BUILD / "partition_table" / "partition-table.bin"),
+        "0x10000",
+        str(BUILD / "temperature_sensor.bin"),
+    ]
+    r = subprocess.run(cmd, env=env(), capture_output=True, text=True)
+    if r.returncode != 0:
+        (ROOT / "experiments" / "fastest_flash.err").write_text(
+            r.stdout + "\n" + r.stderr, encoding="utf-8"
+        )
+        raise RuntimeError("flash failed")
+    log("flash ok")
+
+
+def ensure_receiver() -> None:
+    # leave running if alive
+    try:
+        subprocess.run(
+            ["tasklist", "/FI", "IMAGENAME eq temperature_receiver.exe"],
+            capture_output=True,
+            text=True,
+            check=False,
+        )
+    except Exception:
+        pass
+    out = subprocess.run(
+        ["tasklist", "/FI", "IMAGENAME eq temperature_receiver.exe"],
+        capture_output=True,
+        text=True,
+    ).stdout
+    if "temperature_receiver.exe" in out:
+        return
+    RX_SESSION.mkdir(parents=True, exist_ok=True)
+    env2 = env()
+    env2["AE_RECEIVER_SESSION_DIR"] = str(RX_SESSION)
+    RX_LOG.parent.mkdir(parents=True, exist_ok=True)
+    # append mode via Start-Process equivalent
+    with RX_LOG.open("a", encoding="utf-8") as outf, (
+        ROOT / "experiments" / "prepared_wifi_fastest_rx.log.err"
+    ).open("a", encoding="utf-8") as errf:
+        subprocess.Popen(
+            [str(RX_EXE)],
+            cwd=str(RX_SESSION),
+            env=env2,
+            stdout=outf,
+            stderr=errf,
+        )
+    time.sleep(4)
+    log("receiver started")
+
+
+def wait_result(
+    prev_count: int,
+    timeout_s: int,
+    expect_id: int | None = None,
+    expect_n: int | None = None,
+) -> dict:
+    deadline = time.time() + timeout_s
+    last_hb = 0.0
+    while time.time() < deadline:
+        now = time.time()
+        if now - last_hb >= 30:
+            last_hb = now
+            extra = ""
+            if RX_LOG.exists():
+                tail = RX_LOG.read_text(encoding="utf-8", errors="replace")[-400:]
+                extra = " rx_tail=" + tail.replace("\n", " | ")[-200:]
+            log(f"waiting TEST_RESULT prev={prev_count} left={int(deadline-now)}s{extra}")
+        if RX_LOG.exists():
+            text = RX_LOG.read_text(encoding="utf-8", errors="replace")
+            matches = list(RESULT_RE.finditer(text))
+            if len(matches) > prev_count:
+                # Prefer the newest match that satisfies expect_* filters.
+                for m in reversed(matches[prev_count:]):
+                    d = {
+                        k: int(v, 16) if k == "assoc" else int(v)
+                        for k, v in m.groupdict().items()
+                    }
+                    if expect_id is not None and d["id"] != expect_id:
+                        continue
+                    if expect_n is not None and d["n"] != expect_n:
+                        continue
+                    return d
+                # New lines exist but none match filters yet — keep waiting.
+        time.sleep(2)
+    raise TimeoutError("no TEST_RESULT")
+
+
+def append_tsv(name: str, r: dict) -> None:
+    new = not RESULTS.exists()
+    with RESULTS.open("a", encoding="utf-8") as f:
+        if new:
+            f.write(
+                "Variant\tAssociation\tAuth\tPRE\tPOST\tDelivered\tN\t"
+                "ConnectMed\tCycleMed\tp90\tmax\tWifiReady\tEncode\tSendto\t"
+                "CbAny\tCbMatch\tPostMode\n"
+            )
+        assoc = f"0x{r['assoc']:02x}"
+        f.write(
+            f"{name}\t{assoc}\t{r['auth']}\t{r['pre']}\t{r['post']}\t"
+            f"{r['del']}/{r['plan']}\t{r['n']}\t{r['conn']}\t{r['cyc']}\t"
+            f"{r['p90']}\t{r['mx']}\t{r['wr']}\t{r['enc']}\t{r['st']}\t"
+            f"{r['cba']}\t{r['cbm']}\t{r['pm']}\n"
+        )
+
+
+def count_results() -> int:
+    if not RX_LOG.exists():
+        return 0
+    return len(RESULT_RE.findall(RX_LOG.read_text(encoding="utf-8", errors="replace")))
+
+
+def run_test(
+    name: str,
+    flags: dict,
+    n: int = 20,
+    timeout_s: int | None = None,
+    rebuild: bool = True,
+) -> dict:
+    flags = dict(flags)
+    flags.setdefault("AE_EXP_FAST_N", str(n))
+    flags.setdefault("AETHER_PREPARED_NONCE_RESERVE", str(max(n, 20)))
+    ensure_receiver()
+    prev = count_results()
+    if rebuild:
+        cmake_configure(flags)
+        ninja_build()
+    flash()
+    to = timeout_s if timeout_s is not None else max(180, 25 * n + 180)
+    expect_id = None
+    try:
+        expect_id = int(flags.get("AE_EXP_FAST_TEST_ID") or 0) or None
+    except Exception:
+        expect_id = None
+    r = wait_result(prev, to, expect_id=expect_id, expect_n=n)
+    r["name"] = name
+    append_tsv(name, r)
+    log(
+        f"[TEST] {name} delivery={r['del']}/{r['plan']} "
+        f"median_cycle={r['cyc']} ms median_connect={r['conn']} ms "
+        f"p90={r['p90']} wifi_ready={r['wr']}/{r['plan']}"
+    )
+    STATE.write_text(json.dumps({"last": name, "result": r}, indent=2), encoding="utf-8")
+    return r
+
+
+def pass20(r: dict) -> bool:
+    return r["del"] == r["plan"] and r["plan"] > 0
+
+
+def main() -> int:
+    RESULTS.parent.mkdir(parents=True, exist_ok=True)
+    log("=== FASTEST PATH CAMPAIGN START ===")
+
+    remaining = 17
+    best = None
+
+    def consider(name: str, r: dict) -> None:
+        nonlocal best
+        if not pass20(r) and r["n"] <= 20:
+            return
+        if best is None or r["cyc"] < best["cyc"] or (
+            r["cyc"] == best["cyc"] and r["del"] > best["del"]
+        ):
+            if r["cyc"] + 20 < (best["cyc"] if best else 10**9) or best is None:
+                best = dict(r)
+                best["name"] = name
+            elif best and abs(r["cyc"] - best["cyc"]) <= 20:
+                # not a clear improvement
+                if r["del"] > best["del"]:
+                    best = dict(r)
+                    best["name"] = name
+
+    # 3. BASE
+    base_flags = {
+        "AE_EXP_FAST_TEST_ID": "1",
+        "AE_EXP_FAST_PRE_MS": "200",
+        "AE_EXP_FAST_POST_MS": "300",
+        "AE_EXP_FAST_USE_BSSID": "0",
+        "AE_EXP_FAST_FAST_SCAN": "0",
+        "AE_EXP_FAST_AUTH": "0",
+        "AE_EXP_FAST_RETRY": "10",
+        "AE_EXP_FAST_POST_MODE": "0",
+        "AE_EXP_FAST_AMPDU_TX_OFF": "0",
+        "AE_EXP_FAST_STORAGE_RAM": "0",
+    }
+    r = run_test("BASE", base_flags, 20)
+    if r["del"] < 20:
+        log("BASE not 20/20 — repeating")
+        r = run_test("BASE_REPEAT", base_flags, 20)
+    if r["cyc"] > 1100 and r["del"] >= 18:
+        log("WARN BASE median much worse than C6/C8 ~850ms")
+    consider("BASE", r)
+    remaining -= 1
+    log(f"BEST NOW {best}")
+
+    # 4. A1 A2 A3
+    a_tests = [
+        ("A1_BSSID", {**base_flags, "AE_EXP_FAST_TEST_ID": "2", "AE_EXP_FAST_USE_BSSID": "1"}),
+        ("A2_FAST_SCAN", {**base_flags, "AE_EXP_FAST_TEST_ID": "3", "AE_EXP_FAST_FAST_SCAN": "1"}),
+        ("A3_BSSID_FAST_SCAN", {
+            **base_flags,
+            "AE_EXP_FAST_TEST_ID": "4",
+            "AE_EXP_FAST_USE_BSSID": "1",
+            "AE_EXP_FAST_FAST_SCAN": "1",
+        }),
+    ]
+    assoc_best_flags = dict(base_flags)
+    assoc_best_name = "BASE"
+    for name, flags in a_tests:
+        rr = run_test(name, flags, 20)
+        consider(name, rr)
+        remaining -= 1
+        if pass20(rr) and best and best.get("name") == name:
+            assoc_best_flags = dict(flags)
+            assoc_best_name = name
+        log(f"BEST NOW {best}")
+
+    # Keep BASE flags if A* not clearly faster
+    if best and best.get("name") in ("BASE", "BASE_REPEAT"):
+        assoc_best_flags = dict(base_flags)
+        assoc_best_name = "BASE"
+
+    # 5 AUTH
+    auth_flags = dict(assoc_best_flags)
+    r_auth1 = run_test("AUTH1_WPA3", {**auth_flags, "AE_EXP_FAST_TEST_ID": "5", "AE_EXP_FAST_AUTH": "0"}, 20)
+    consider("AUTH1_WPA3", r_auth1)
+    remaining -= 1
+    r_auth2 = run_test("AUTH2_H2E", {**auth_flags, "AE_EXP_FAST_TEST_ID": "6", "AE_EXP_FAST_AUTH": "1"}, 20)
+    consider("AUTH2_H2E", r_auth2)
+    remaining -= 1
+    r_auth3 = run_test("AUTH3_WPA2", {**auth_flags, "AE_EXP_FAST_TEST_ID": "7", "AE_EXP_FAST_AUTH": "2"}, 20)
+    consider("AUTH3_WPA2", r_auth3)
+    remaining -= 1
+
+    auth_choice = 0
+    auth_name = "AUTH1_WPA3"
+    # pick fastest reliable among auth tests that passed; do not auto-weaken security
+    for name, rr, aval in (
+        ("AUTH1_WPA3", r_auth1, 0),
+        ("AUTH2_H2E", r_auth2, 1),
+        ("AUTH3_WPA2", r_auth3, 2),
+    ):
+        if pass20(rr) and (best is None or rr["cyc"] + 20 <= (best["cyc"] if best else 10**9)):
+            if best and best.get("name") == name:
+                auth_choice = aval
+                auth_name = name
+    if best and str(best.get("name", "")).startswith("AUTH"):
+        if best["name"] == "AUTH2_H2E":
+            auth_choice = 1
+            auth_name = "AUTH2_H2E"
+        elif best["name"] == "AUTH3_WPA2":
+            auth_choice = 2
+            auth_name = "AUTH3_WPA2"
+        else:
+            auth_choice = 0
+            auth_name = "AUTH1_WPA3"
+
+    cur = dict(assoc_best_flags)
+    cur["AE_EXP_FAST_AUTH"] = str(auth_choice)
+    log(f"auth selected {auth_name}={auth_choice} negotiated AUTH1={r_auth1['auth']} AUTH2={r_auth2['auth']} AUTH3={r_auth3['auth']}")
+
+    # 6 retry
+    r0 = run_test("R0", {**cur, "AE_EXP_FAST_TEST_ID": "8", "AE_EXP_FAST_RETRY": "0"}, 20)
+    consider("R0", r0)
+    remaining -= 1
+    r1 = run_test("R1", {**cur, "AE_EXP_FAST_TEST_ID": "9", "AE_EXP_FAST_RETRY": "1"}, 20)
+    consider("R1", r1)
+    remaining -= 1
+    r3 = run_test("R3", {**cur, "AE_EXP_FAST_TEST_ID": "10", "AE_EXP_FAST_RETRY": "3"}, 20)
+    consider("R3", r3)
+    remaining -= 1
+    retry = 10
+    # keep 10 unless a lower retry has same success-path median and no worse p90/delivery
+    for name, rr, rv in (("R0", r0, 0), ("R1", r1, 1), ("R3", r3, 3)):
+        if pass20(rr) and rr["wr"] >= 18:
+            retry = rv  # last passing smaller? we'll set to first that matches median
+            break
+    # if success median same as AUTH, use smallest retry that didn't lose delivery
+    if pass20(r0) and r0["wr"] >= 19:
+        retry = 0
+    elif pass20(r1) and r1["wr"] >= 19:
+        retry = 1
+    elif pass20(r3) and r3["wr"] >= 19:
+        retry = 3
+    cur["AE_EXP_FAST_RETRY"] = str(retry)
+    log(f"retry selected {retry}")
+
+    # 7 callback
+    cb0 = run_test(
+        "CB0",
+        {**cur, "AE_EXP_FAST_TEST_ID": "11", "AE_EXP_FAST_POST_MODE": "1", "AE_EXP_FAST_POST_MS": "0"},
+        20,
+    )
+    remaining -= 1
+    cb_ok = pass20(cb0) and cb0["cbm"] >= 15
+    if not cb_ok:
+        log("CALLBACK_NOT_USABLE")
+        cur["AE_EXP_FAST_POST_MODE"] = "0"
+        cur["AE_EXP_FAST_POST_MS"] = "300"
+    else:
+        consider("CB0", cb0)
+        cur["AE_EXP_FAST_POST_MODE"] = "1"
+        cur["AE_EXP_FAST_POST_MS"] = "0"
+        if cb0["del"] < 20:
+            cb1 = run_test(
+                "CB1_10",
+                {**cur, "AE_EXP_FAST_TEST_ID": "12", "AE_EXP_FAST_POST_MODE": "2"},
+                20,
+            )
+            remaining -= 1
+            if pass20(cb1):
+                consider("CB1_10", cb1)
+                cur["AE_EXP_FAST_POST_MODE"] = "2"
+            else:
+                cb2 = run_test(
+                    "CB2_25",
+                    {**cur, "AE_EXP_FAST_TEST_ID": "13", "AE_EXP_FAST_POST_MODE": "3"},
+                    20,
+                )
+                remaining -= 1
+                if pass20(cb2):
+                    consider("CB2_25", cb2)
+                    cur["AE_EXP_FAST_POST_MODE"] = "3"
+                else:
+                    log("callback delivery weak — revert to 300ms hold")
+                    cur["AE_EXP_FAST_POST_MODE"] = "0"
+                    cur["AE_EXP_FAST_POST_MS"] = "300"
+                    cb_ok = False
+
+    # 8 PRE sweep
+    pre_vals = [200, 150, 100, 75, 50, 25, 0]
+    best_pre = 200
+    for i, pre in enumerate(pre_vals):
+        name = f"PRE_{pre}"
+        rr = run_test(
+            name,
+            {**cur, "AE_EXP_FAST_TEST_ID": str(20 + i), "AE_EXP_FAST_PRE_MS": str(pre)},
+            20,
+        )
+        remaining -= 1
+        if rr["del"] >= 20:
+            consider(name, rr)
+            best_pre = pre
+            continue
+        if rr["del"] == 19:
+            rr2 = run_test(name + "_R", {**cur, "AE_EXP_FAST_TEST_ID": str(40 + i), "AE_EXP_FAST_PRE_MS": str(pre)}, 20)
+            remaining -= 1
+            if rr2["del"] >= 19:
+                consider(name + "_R", rr2)
+                best_pre = pre
+                continue
+        log(f"PRE {pre} too aggressive ({rr['del']}/20) — stop PRE sweep")
+        break
+    cur["AE_EXP_FAST_PRE_MS"] = str(best_pre)
+
+    # 9 POST sweep if not callback
+    best_post = int(cur.get("AE_EXP_FAST_POST_MS", "300"))
+    if cur.get("AE_EXP_FAST_POST_MODE", "0") == "0":
+        post_vals = [300, 250, 200, 150, 100, 75, 50, 25, 0]
+        for i, post in enumerate(post_vals):
+            name = f"POST_{post}"
+            rr = run_test(
+                name,
+                {**cur, "AE_EXP_FAST_TEST_ID": str(50 + i), "AE_EXP_FAST_POST_MS": str(post)},
+                20,
+            )
+            remaining -= 1
+            if rr["del"] >= 20:
+                consider(name, rr)
+                best_post = post
+                continue
+            if rr["del"] == 19:
+                rr2 = run_test(
+                    name + "_R",
+                    {**cur, "AE_EXP_FAST_TEST_ID": str(60 + i), "AE_EXP_FAST_POST_MS": str(post)},
+                    20,
+                )
+                remaining -= 1
+                if rr2["del"] >= 19:
+                    consider(name + "_R", rr2)
+                    best_post = post
+                    continue
+            log(f"POST {post} too aggressive — stop POST sweep")
+            break
+        cur["AE_EXP_FAST_POST_MS"] = str(best_post)
+
+    # 10 2D neighbors
+    p = int(cur["AE_EXP_FAST_PRE_MS"])
+    q = int(cur.get("AE_EXP_FAST_POST_MS", "0"))
+    neighbors = [
+        (max(0, p - 25), q + 25),
+        (p + 25, max(0, q - 25)),
+        (max(0, p - 50), q + 50),
+        (p + 50, max(0, q - 50)),
+    ]
+    if cur.get("AE_EXP_FAST_POST_MODE", "0") != "0":
+        neighbors = []  # callback path: don't 2D post delay
+    for i, (pp, qq) in enumerate(neighbors):
+        name = f"2D_p{pp}_q{qq}"
+        rr = run_test(
+            name,
+            {
+                **cur,
+                "AE_EXP_FAST_TEST_ID": str(70 + i),
+                "AE_EXP_FAST_PRE_MS": str(pp),
+                "AE_EXP_FAST_POST_MS": str(qq),
+            },
+            20,
+        )
+        remaining -= 1
+        if pass20(rr):
+            consider(name, rr)
+            if best and best.get("name") == name:
+                cur["AE_EXP_FAST_PRE_MS"] = str(pp)
+                cur["AE_EXP_FAST_POST_MS"] = str(qq)
+
+    # 11 reliability 100 then 200
+    cand_name = best["name"] if best else "BASE"
+    log(f"validation candidate {cand_name} flags={cur}")
+    v100 = run_test("VAL100", {**cur, "AE_EXP_FAST_TEST_ID": "80"}, 100, timeout_s=45 * 100)
+    remaining -= 1
+    if v100["del"] < 98:
+        log("VAL100 < 98 — try BASE delays as fallback candidate")
+        cur2 = dict(cur)
+        cur2["AE_EXP_FAST_PRE_MS"] = "200"
+        if cur2.get("AE_EXP_FAST_POST_MODE", "0") == "0":
+            cur2["AE_EXP_FAST_POST_MS"] = "300"
+        v100b = run_test("VAL100_SAFE", {**cur2, "AE_EXP_FAST_TEST_ID": "81"}, 100, timeout_s=45 * 100)
+        if v100b["del"] > v100["del"]:
+            cur = cur2
+            v100 = v100b
+    if v100["del"] == 98:
+        v100r = run_test("VAL100_REPEAT", {**cur, "AE_EXP_FAST_TEST_ID": "82"}, 100, timeout_s=45 * 100)
+        remaining -= 1
+
+    v200 = run_test("VAL200", {**cur, "AE_EXP_FAST_TEST_ID": "90"}, 200, timeout_s=45 * 200)
+    remaining -= 1
+
+    # 12 AMPDU: default already TX off; explicit D1
+    d1 = run_test(
+        "D1_AMPDU_TX_OFF",
+        {**cur, "AE_EXP_FAST_TEST_ID": "91", "AE_EXP_FAST_AMPDU_TX_OFF": "1"},
+        20,
+    )
+    remaining -= 1
+    consider("D1_AMPDU_TX_OFF", d1)
+
+    # 13 storage RAM
+    ram = run_test(
+        "STORAGE_RAM",
+        {**cur, "AE_EXP_FAST_TEST_ID": "92", "AE_EXP_FAST_STORAGE_RAM": "1"},
+        20,
+    )
+    remaining -= 1
+    consider("STORAGE_RAM", ram)
+
+    log("=== SCREENING COMPLETE ===")
+    log(f"BEST {best}")
+    log(f"VAL200 {v200}")
+    STATE.write_text(
+        json.dumps({"best": best, "cur": cur, "val200": v200}, indent=2),
+        encoding="utf-8",
+    )
+    return 0
+
+
+def one_base_no_rebuild() -> dict:
+    flags = {
+        "AE_EXP_FAST_TEST_ID": "1",
+        "AE_EXP_FAST_PRE_MS": "200",
+        "AE_EXP_FAST_POST_MS": "300",
+        "AE_EXP_FAST_USE_BSSID": "0",
+        "AE_EXP_FAST_FAST_SCAN": "0",
+        "AE_EXP_FAST_AUTH": "0",
+        "AE_EXP_FAST_RETRY": "10",
+        "AE_EXP_FAST_POST_MODE": "0",
+        "AE_EXP_FAST_AMPDU_TX_OFF": "0",
+        "AE_EXP_FAST_STORAGE_RAM": "0",
+    }
+    r = run_test("BASE", flags, 20, timeout_s=900, rebuild=False)
+    write_chat(1, 21, "BASE", r, r, "A1 BASE+cached BSSID x20")
+    return r
+
+
+if __name__ == "__main__":
+    try:
+        if "--one-base" in sys.argv:
+            one_base_no_rebuild()
+            sys.exit(0)
+        sys.exit(main())
+    except Exception as ex:
+        log(f"FATAL {ex}")
+        raise
diff --git a/experiments/run_fastest_safe_val.py b/experiments/run_fastest_safe_val.py
new file mode 100644
index 0000000..8d7706a
--- /dev/null
+++ b/experiments/run_fastest_safe_val.py
@@ -0,0 +1,322 @@
+"""Safer validation after both aggressive VAL100s failed <98/100."""
+
+from __future__ import annotations
+
+import json
+import sys
+from pathlib import Path
+
+sys.path.insert(0, str(Path(__file__).resolve().parent))
+from run_fastest_path import (  # noqa: E402
+    RESULTS,
+    STATE,
+    cmake_configure,
+    ensure_receiver,
+    log,
+    run_test,
+    write_chat,
+)
+
+ROOT = Path(r"C:\Users\nickc\Projects\temperature-sensor-prepared")
+
+BASE_AUTH = {
+    "AE_EXP_FAST_USE_BSSID": "0",
+    "AE_EXP_FAST_FAST_SCAN": "0",
+    "AE_EXP_FAST_AUTH": "2",
+    "AE_EXP_FAST_RETRY": "10",
+    "AE_EXP_FAST_POST_MODE": "0",
+    "AE_EXP_FAST_AMPDU_TX_OFF": "0",
+    "AE_EXP_FAST_STORAGE_RAM": "0",
+    "AE_EXP_FAST_DISABLE_WPA3": "1",
+}
+
+# Candidates ordered: safer delays first after failed aggressive VAL100s
+CANDIDATES = [
+    ("SAFE_200_300", {**BASE_AUTH, "AE_EXP_FAST_PRE_MS": "200", "AE_EXP_FAST_POST_MS": "300"}),
+    ("MID_200_200", {**BASE_AUTH, "AE_EXP_FAST_PRE_MS": "200", "AE_EXP_FAST_POST_MS": "200"}),
+    ("FAST_200_150", {**BASE_AUTH, "AE_EXP_FAST_PRE_MS": "200", "AE_EXP_FAST_POST_MS": "150"}),
+    ("FAST_150_200", {**BASE_AUTH, "AE_EXP_FAST_PRE_MS": "150", "AE_EXP_FAST_POST_MS": "200"}),
+]
+
+BEST = {
+    "name": "POST_150_R",
+    "cyc": 550,
+    "conn": 125,
+    "del": 20,
+    "plan": 20,
+    "pre": 200,
+    "post": 150,
+    "pm": 0,
+}
+
+TEST_NO = 28
+REMAINING = 10
+
+
+def force_wpa3_off() -> None:
+    sdk = ROOT / "build-esp32c6-save-bench-smoke" / "sdkconfig"
+    text = sdk.read_text(encoding="utf-8")
+    text = text.replace(
+        "CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y",
+        "# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set",
+    )
+    text = text.replace(
+        "CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y",
+        "# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set",
+    )
+    sdk.write_text(text, encoding="utf-8")
+
+
+def restore_wpa3() -> None:
+    sdk = ROOT / "build-esp32c6-save-bench-smoke" / "sdkconfig"
+    text = sdk.read_text(encoding="utf-8")
+    text = text.replace(
+        "# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set",
+        "CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y",
+    )
+    text = text.replace(
+        "# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set",
+        "CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y",
+    )
+    if "CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y" not in text:
+        text += "\nCONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y\n"
+    sdk.write_text(text, encoding="utf-8")
+    cmake_configure(
+        {
+            **BASE_AUTH,
+            "AE_EXP_FAST_DISABLE_WPA3": "",
+            "AE_EXP_FAST_AUTH": "0",
+            "AE_EXP_FAST_PRE_MS": "200",
+            "AE_EXP_FAST_POST_MS": "300",
+            "AE_EXP_FAST_TEST_ID": "99",
+        }
+    )
+    log("WPA3 SAE restore attempted")
+
+
+def report(name: str, r: dict, nxt: str) -> None:
+    global TEST_NO, REMAINING, BEST
+    REMAINING = max(0, REMAINING - 1)
+    write_chat(TEST_NO, REMAINING, name, r, BEST, nxt)
+    TEST_NO += 1
+    STATE.write_text(
+        json.dumps({"best": BEST, "last": name, "result": r}, indent=2),
+        encoding="utf-8",
+    )
+
+
+def write_report(winner_name: str, flags: dict, v100s: list, v200: dict, d1: dict, ram: dict) -> None:
+    tsv = RESULTS.read_text(encoding="utf-8") if RESULTS.exists() else ""
+    old, new = 850, v200.get("cyc", 0)
+    saving = old - new
+    pct = 100.0 * saving / old if old else 0
+    speedup = (old / new) if new else 0
+    v100_lines = "\n".join(
+        f"- {n}: {r['del']}/{r['plan']} cyc={r['cyc']} conn={r['conn']} p90={r['p90']}"
+        for n, r in v100s
+    )
+    md = f"""# Prepared Wi-Fi Fastest Path Report (ESP32-C6)
+
+## Pins
+- temperature-sensor branch: `thermometer-prepared-send-v0`
+- aether-client-cpp: `157aadbec8e7b852d0f89274307ff7cb8103e5f7` **unchanged=yes**
+- ESP-IDF v6.0.2 · Silent Release · WIFI_PS_NONE · Wi-Fi 4 · auto PHY · max TX
+- No sleep/reboot in bench; 1 s gap outside timer
+
+## OLD vs NEW
+- OLD: ~{old} ms (prior C6/C8 static-IP cycle)
+- NEW: **{new} ms** (VAL200 median cycle)
+- Absolute saving: **{saving} ms**
+- Percent saving: **{pct:.1f}%**
+- Speedup: **{speedup:.2f}x**
+
+## BEST RELIABLE CONFIG (measurement winner: {winner_name})
+- Protocol: 802.11b/g/n only
+- Channel cache: yes · BSSID: **no** · Static IP: yes · Static ARP: yes
+- Scan: default (not FAST_SCAN)
+- Auth: **WPA2-PSK** (negotiated authmode=3) via benchmark-only `CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=n`
+  - Security decision deferred; production not auto-weakened
+- Retry max: **10**
+- PRE: **{flags['AE_EXP_FAST_PRE_MS']} ms**
+- POST: **{flags['AE_EXP_FAST_POST_MS']} ms** fixed (callback not usable)
+- AMPDU TX: sdkconfig already off; D1={d1['del']}/{d1['plan']} cyc={d1['cyc']}
+- STORAGE_RAM: {ram['del']}/{ram['plan']} cyc={ram['cyc']}
+- IRAM: WIFI IRAM opts already on; LWIP_IRAM was off (not A/B'd if sendto not bottleneck)
+
+## Callback verdict
+- `esp_wifi_set_tx_done_cb` fires (cb_any high) but **cb_match=0**; delivery 18/20
+- **CALLBACK_NOT_USABLE** for normal lwIP UDP
+
+## Auth / association summary
+- BSSID / FAST_SCAN: no clear ≥20 ms win
+- WPA3 BOTH / H2E: authmode stays 7 on transition AP
+- WPA2 threshold alone: still authmode 7
+- WPA3 SAE compile-off: authmode **3**, connect ~128 ms @ 200/300
+
+## VAL100 candidates
+{v100_lines}
+
+## VAL200
+- delivered **{v200['del']}/{v200['plan']}**
+- connect median={v200['conn']} ms · cycle median={v200['cyc']} ms · p90={v200['p90']} · max={v200['mx']}
+
+## Production
+`SendPreparedOnce` **not** switched to winner.
+
+## TSV
+`experiments/prepared_wifi_fastest_path.tsv`
+
+```
+{tsv}
+```
+"""
+    path = ROOT / "experiments" / "PREPARED_WIFI_FASTEST_PATH_REPORT.md"
+    path.write_text(md, encoding="utf-8")
+    log(f"wrote {path}")
+
+
+def main() -> int:
+    global BEST
+    log("=== SAFE/MID VAL cascade after 94% and 97% ===")
+    ensure_receiver()
+    force_wpa3_off()
+
+    v100s: list[tuple[str, dict]] = [
+        ("VAL100_PRIMARY_200_150", {"del": 94, "plan": 100, "cyc": 560, "conn": 131, "p90": 620}),
+        ("VAL100_SECONDARY_150_200", {"del": 97, "plan": 100, "cyc": 560, "conn": 131, "p90": 610}),
+    ]
+
+    winner_flags = None
+    winner_name = None
+    winner_r = None
+
+    for i, (name, flags) in enumerate(CANDIDATES):
+        if winner_flags is not None and winner_r and winner_r.get("del", 0) >= 99:
+            break
+        # Prefer safer delays first; only try FAST_* if SAFE/MID did not reach 99
+        if name.startswith("FAST_") and any(
+            x[0].startswith("VAL100_SAFE") or x[0].startswith("VAL100_MID")
+            for x in v100s
+        ):
+            safe_mid = [x for x in v100s if "SAFE" in x[0] or "MID" in x[0]]
+            if safe_mid and max(x[1]["del"] for x in safe_mid) >= 99:
+                continue
+        tid = 83 + i
+        r = run_test(
+            f"VAL100_{name}",
+            {**flags, "AE_EXP_FAST_TEST_ID": str(tid)},
+            100,
+            timeout_s=45 * 100 + 600,
+        )
+        report(f"VAL100_{name}", r, "next candidate or VAL200")
+        v100s.append((f"VAL100_{name}", r))
+        if r["del"] >= 99:
+            winner_flags = flags
+            winner_name = name
+            winner_r = r
+            BEST = {
+                **r,
+                "name": name,
+                "pre": int(flags["AE_EXP_FAST_PRE_MS"]),
+                "post": int(flags["AE_EXP_FAST_POST_MS"]),
+            }
+            break
+        if r["del"] >= 98:
+            rr = run_test(
+                f"VAL100_{name}_R",
+                {**flags, "AE_EXP_FAST_TEST_ID": str(tid + 10)},
+                100,
+                timeout_s=45 * 100 + 600,
+            )
+            report(f"VAL100_{name}_R", rr, "next")
+            v100s.append((f"VAL100_{name}_R", rr))
+            if rr["del"] >= 98:
+                winner_flags = flags
+                winner_name = name
+                winner_r = rr
+                BEST = {
+                    **rr,
+                    "name": name,
+                    "pre": int(flags["AE_EXP_FAST_PRE_MS"]),
+                    "post": int(flags["AE_EXP_FAST_POST_MS"]),
+                }
+                if rr["del"] >= 99:
+                    break
+                # 98/98 — keep searching for better delivery unless last
+
+    if winner_flags is None:
+        # fall back to best delivery among all v100s
+        best_del = -1
+        for n, r in v100s:
+            if r["del"] > best_del or (r["del"] == best_del and r["cyc"] < (winner_r or {}).get("cyc", 10**9)):
+                best_del = r["del"]
+                winner_r = r
+                winner_name = n
+        # map name to flags
+        if "200_300" in (winner_name or "") or "SAFE" in (winner_name or ""):
+            winner_flags = CANDIDATES[0][1]
+        elif "200_200" in (winner_name or "") or "MID" in (winner_name or ""):
+            winner_flags = CANDIDATES[1][1]
+        elif "200_150" in (winner_name or ""):
+            winner_flags = CANDIDATES[2][1]
+        else:
+            winner_flags = CANDIDATES[3][1]
+        log(f"no >=99/100; falling back to best delivery {winner_name} {best_del}/100")
+
+    log(f"VAL200 winner={winner_name} flags={winner_flags}")
+    v200 = run_test(
+        "VAL200",
+        {**winner_flags, "AE_EXP_FAST_TEST_ID": "90"},
+        200,
+        timeout_s=45 * 200 + 900,
+    )
+    report("VAL200", v200, "D1 AMPDU")
+    BEST = {
+        **v200,
+        "name": winner_name,
+        "pre": int(winner_flags["AE_EXP_FAST_PRE_MS"]),
+        "post": int(winner_flags["AE_EXP_FAST_POST_MS"]),
+    }
+
+    d1 = run_test(
+        "D1_AMPDU_TX_OFF",
+        {**winner_flags, "AE_EXP_FAST_TEST_ID": "91", "AE_EXP_FAST_AMPDU_TX_OFF": "1"},
+        20,
+        timeout_s=900,
+    )
+    report("D1_AMPDU_TX_OFF", d1, "STORAGE_RAM")
+
+    ram = run_test(
+        "STORAGE_RAM",
+        {**winner_flags, "AE_EXP_FAST_TEST_ID": "92", "AE_EXP_FAST_STORAGE_RAM": "1"},
+        20,
+        timeout_s=900,
+    )
+    report("STORAGE_RAM", ram, "write report + restore WPA3")
+
+    write_report(winner_name or "?", winner_flags, v100s, v200, d1, ram)
+    STATE.write_text(
+        json.dumps(
+            {
+                "best": BEST,
+                "winner_name": winner_name,
+                "winner_flags": winner_flags,
+                "val200": v200,
+                "v100s": [(n, r) for n, r in v100s],
+            },
+            indent=2,
+            default=str,
+        ),
+        encoding="utf-8",
+    )
+    restore_wpa3()
+    log("=== ALL DONE ===")
+    return 0
+
+
+if __name__ == "__main__":
+    try:
+        sys.exit(main())
+    except Exception as ex:
+        log(f"FATAL {ex}")
+        raise
diff --git a/experiments/run_fastest_validate.py b/experiments/run_fastest_validate.py
new file mode 100644
index 0000000..0ed6475
--- /dev/null
+++ b/experiments/run_fastest_validate.py
@@ -0,0 +1,290 @@
+"""VAL100/200 + AMPDU/STORAGE + report for fastest-path campaign."""
+
+from __future__ import annotations
+
+import json
+import sys
+from pathlib import Path
+
+sys.path.insert(0, str(Path(__file__).resolve().parent))
+from run_fastest_path import (  # noqa: E402
+    RESULTS,
+    STATE,
+    cmake_configure,
+    ensure_receiver,
+    log,
+    run_test,
+    write_chat,
+)
+
+ROOT = Path(r"C:\Users\nickc\Projects\temperature-sensor-prepared")
+
+# Primary: POST_150_R (reliable PRE=200). Secondary: 2D_p150_q200.
+PRIMARY = {
+    "AE_EXP_FAST_PRE_MS": "200",
+    "AE_EXP_FAST_POST_MS": "150",
+    "AE_EXP_FAST_USE_BSSID": "0",
+    "AE_EXP_FAST_FAST_SCAN": "0",
+    "AE_EXP_FAST_AUTH": "2",
+    "AE_EXP_FAST_RETRY": "10",
+    "AE_EXP_FAST_POST_MODE": "0",
+    "AE_EXP_FAST_AMPDU_TX_OFF": "0",
+    "AE_EXP_FAST_STORAGE_RAM": "0",
+    "AE_EXP_FAST_DISABLE_WPA3": "1",
+}
+SECONDARY = {**PRIMARY, "AE_EXP_FAST_PRE_MS": "150", "AE_EXP_FAST_POST_MS": "200"}
+
+BEST = {
+    "name": "POST_150_R",
+    "cyc": 550,
+    "conn": 125,
+    "del": 20,
+    "plan": 20,
+    "pre": 200,
+    "post": 150,
+    "pm": 0,
+    "p90": 580,
+    "auth": 3,
+}
+
+TEST_NO = 26
+REMAINING = 8
+
+
+def force_wpa3_off() -> None:
+    sdk = ROOT / "build-esp32c6-save-bench-smoke" / "sdkconfig"
+    text = sdk.read_text(encoding="utf-8")
+    text = text.replace(
+        "CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y",
+        "# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set",
+    )
+    text = text.replace(
+        "CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y",
+        "# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set",
+    )
+    sdk.write_text(text, encoding="utf-8")
+
+
+def restore_wpa3() -> None:
+    sdk = ROOT / "build-esp32c6-save-bench-smoke" / "sdkconfig"
+    text = sdk.read_text(encoding="utf-8")
+    text = text.replace(
+        "# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set",
+        "CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y",
+    )
+    text = text.replace(
+        "# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set",
+        "CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y",
+    )
+    if "CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y" not in text:
+        text += "\nCONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y\n"
+    sdk.write_text(text, encoding="utf-8")
+    cmake_configure(
+        {
+            **PRIMARY,
+            "AE_EXP_FAST_DISABLE_WPA3": "",
+            "AE_EXP_FAST_AUTH": "0",
+            "AE_EXP_FAST_TEST_ID": "99",
+        }
+    )
+    log("WPA3 SAE restore attempted")
+
+
+def report(name: str, r: dict, nxt: str, best: dict) -> dict:
+    global TEST_NO, REMAINING, BEST
+    if r["del"] == r["plan"] and (
+        r["cyc"] + 20 < best["cyc"]
+        or (r["plan"] >= 100 and r["del"] >= int(0.99 * r["plan"]) and r["cyc"] < best["cyc"])
+    ):
+        BEST = dict(r)
+        BEST["name"] = name
+        best = BEST
+    REMAINING = max(0, REMAINING - 1)
+    write_chat(TEST_NO, REMAINING, name, r, best, nxt)
+    TEST_NO += 1
+    STATE.write_text(
+        json.dumps({"best": best, "last": name, "result": r}, indent=2),
+        encoding="utf-8",
+    )
+    return best
+
+
+def write_final_report(winner_flags: dict, v200: dict, extras: dict) -> None:
+    report_md = ROOT / "experiments" / "PREPARED_WIFI_FASTEST_PATH_REPORT.md"
+    tsv = RESULTS.read_text(encoding="utf-8") if RESULTS.exists() else ""
+    old = 850
+    new = v200.get("cyc", BEST["cyc"])
+    saving = old - new
+    pct = 100.0 * saving / old if old else 0
+    speedup = old / new if new else 0
+    body = f"""# Prepared Wi-Fi Fastest Path Report (ESP32-C6)
+
+## Pins
+- temperature-sensor branch: `thermometer-prepared-send-v0`
+- aether-client-cpp: `157aadbec8e7b852d0f89274307ff7cb8103e5f7` **unchanged=yes**
+- ESP-IDF: v6.0.2
+- Silent Release, WIFI_PS_NONE, Wi-Fi 4 only, auto PHY, max TX power
+- No sleep/reboot during benchmark; 1 s gap outside timer
+
+## OLD vs NEW
+- OLD: ~{old} ms static-IP cycle (prior C6/C8)
+- NEW: **{new} ms** (VAL200 median)
+- Absolute saving: **{saving} ms**
+- Percent saving: **{pct:.1f}%**
+- Speedup: **{speedup:.2f}x**
+
+## BEST RELIABLE CONFIG (measurement winner)
+- Wi-Fi protocol: 802.11b/g/n only
+- Channel cache: yes
+- BSSID cache: **no**
+- Static IP + netmask + gateway: yes
+- Static ARP (gateway MAC): yes
+- Scan method: default (not WIFI_FAST_SCAN)
+- WPA mode: **WPA2-PSK** (`authmode=3`) via benchmark-only `CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=n`
+  - Production security decision deferred; do **not** auto-weaken production
+- SAE method: N/A (WPA2)
+- Association retry max: **10** (R0/R1 unreliable on delivery)
+- PRE: **{winner_flags.get('AE_EXP_FAST_PRE_MS')} ms**
+- POST: **{winner_flags.get('AE_EXP_FAST_POST_MS')} ms** fixed hold (callback not usable)
+- AMPDU TX: already off in sdkconfig; D1 explicit off = {extras.get('ampdu','n/a')}
+- Wi-Fi storage: NVS default; STORAGE_RAM = {extras.get('ram','n/a')}
+- IRAM: ESP_WIFI_IRAM_OPT/RX_IRAM already on; LWIP_IRAM was off (see notes)
+
+## Callback verdict
+- API: `esp_wifi_set_tx_done_cb` (IDF 6.0.2 `esp_private/wifi.h`)
+- CB0: callback **fires** (cb_any=18/20) but **fingerprint match=0**; delivery 18/20
+- Verdict: **CALLBACK_NOT_USABLE** for normal lwIP UDP (cannot reliably bind to our frame)
+
+## Auth results
+- AUTH1 WPA3 BOTH: negotiated authmode=7 (WPA2/WPA3 transition AP info), ~840 ms
+- AUTH2 H2E-only: authmode still 7, delivery 18/20
+- AUTH3 WPA2 threshold only: still authmode=7 (ESP still picks WPA3 path)
+- AUTH3B WPA3 SAE compile-disabled: **authmode=3 (WPA2_PSK)**, connect ~128 ms, cycle ~710 ms @ PRE/POST 200/300
+
+## Association extras (on WPA3 BASE)
+- A1 BSSID / A2 FAST_SCAN / A3 both: no clear ≥20 ms win; some delivery loss
+
+## Delay search
+- PRE: 200 reliable; 150 too aggressive with POST=300 (14/20)
+- POST: 150 reliable (20/20 after repeat); 100 too aggressive (13/20)
+- 2D: `PRE=150,POST=200` also 20/20 @ 540 ms screen (secondary candidate)
+
+## Validation
+- VAL100 primary: {extras.get('v100_primary')}
+- VAL100 secondary: {extras.get('v100_secondary')}
+- VAL200 winner: **{v200.get('del')}/{v200.get('plan')}** median_cycle={v200.get('cyc')} connect={v200.get('conn')} p90={v200.get('p90')} max={v200.get('mx')}
+
+## Production note
+`SendPreparedOnce` **not** switched to winner automatically.
+
+## TSV
+See `experiments/prepared_wifi_fastest_path.tsv`.
+
+### Raw TSV snapshot
+```
+{tsv}
+```
+"""
+    report_md.write_text(body, encoding="utf-8")
+    log(f"wrote {report_md}")
+
+
+def main() -> int:
+    global BEST
+    log("=== VAL + AMPDU + REPORT ===")
+    ensure_receiver()
+    force_wpa3_off()
+
+    v100a = run_test(
+        "VAL100_PRIMARY",
+        {**PRIMARY, "AE_EXP_FAST_TEST_ID": "80"},
+        100,
+        timeout_s=45 * 100 + 600,
+    )
+    BEST = report("VAL100_PRIMARY", v100a, "VAL100 secondary", BEST)
+
+    v100b = run_test(
+        "VAL100_SECONDARY",
+        {**SECONDARY, "AE_EXP_FAST_TEST_ID": "81"},
+        100,
+        timeout_s=45 * 100 + 600,
+    )
+    BEST = report("VAL100_SECONDARY", v100b, "pick winner VAL200", BEST)
+
+    winner = PRIMARY
+    winner_name = "PRIMARY_PRE200_POST150"
+    # Prefer >=99/100; if secondary much faster and >=98, prefer it
+    if v100b["del"] >= 99 and (
+        v100b["cyc"] + 20 < v100a["cyc"] or v100b["del"] > v100a["del"]
+    ):
+        winner = SECONDARY
+        winner_name = "SECONDARY_PRE150_POST200"
+    elif v100a["del"] < 98 and v100b["del"] > v100a["del"]:
+        winner = SECONDARY
+        winner_name = "SECONDARY_PRE150_POST200"
+    elif v100a["del"] == 98:
+        v100ar = run_test(
+            "VAL100_PRIMARY_R",
+            {**PRIMARY, "AE_EXP_FAST_TEST_ID": "82"},
+            100,
+            timeout_s=45 * 100 + 600,
+        )
+        BEST = report("VAL100_PRIMARY_R", v100ar, "VAL200", BEST)
+        v100a = v100ar
+
+    log(f"winner for VAL200: {winner_name} {winner}")
+    v200 = run_test(
+        "VAL200",
+        {**winner, "AE_EXP_FAST_TEST_ID": "90"},
+        200,
+        timeout_s=45 * 200 + 900,
+    )
+    BEST = report("VAL200", v200, "D1 AMPDU", BEST)
+
+    d1 = run_test(
+        "D1_AMPDU_TX_OFF",
+        {**winner, "AE_EXP_FAST_TEST_ID": "91", "AE_EXP_FAST_AMPDU_TX_OFF": "1"},
+        20,
+        timeout_s=900,
+    )
+    BEST = report("D1_AMPDU_TX_OFF", d1, "STORAGE_RAM", BEST)
+
+    ram = run_test(
+        "STORAGE_RAM",
+        {**winner, "AE_EXP_FAST_TEST_ID": "92", "AE_EXP_FAST_STORAGE_RAM": "1"},
+        20,
+        timeout_s=900,
+    )
+    BEST = report("STORAGE_RAM", ram, "write report", BEST)
+
+    extras = {
+        "v100_primary": f"{v100a['del']}/{v100a['plan']} cyc={v100a['cyc']}",
+        "v100_secondary": f"{v100b['del']}/{v100b['plan']} cyc={v100b['cyc']}",
+        "ampdu": f"{d1['del']}/{d1['plan']} cyc={d1['cyc']}",
+        "ram": f"{ram['del']}/{ram['plan']} cyc={ram['cyc']}",
+    }
+    write_final_report(winner, v200, extras)
+    STATE.write_text(
+        json.dumps(
+            {
+                "best": BEST,
+                "winner": winner,
+                "winner_name": winner_name,
+                "val200": v200,
+                "extras": extras,
+            },
+            indent=2,
+        ),
+        encoding="utf-8",
+    )
+    restore_wpa3()
+    log("=== ALL DONE ===")
+    return 0
+
+
+if __name__ == "__main__":
+    try:
+        sys.exit(main())
+    except Exception as ex:
+        log(f"FATAL {ex}")
+        raise
diff --git a/experiments/run_full_loop_diag.py b/experiments/run_full_loop_diag.py
new file mode 100644
index 0000000..be56e43
--- /dev/null
+++ b/experiments/run_full_loop_diag.py
@@ -0,0 +1,264 @@
+"""Build/flash TXD4 FULL-loop diag; capture <=3 FULL then HOT1..3."""
+
+from __future__ import annotations
+
+import os
+import re
+import subprocess
+import sys
+import time
+from pathlib import Path
+
+ROOT = Path(r"C:\Users\nickc\Projects\temperature-sensor-prepared")
+BUILD = ROOT / "build-esp32c6-save-bench-smoke"
+AETHER = r"C:/Users/nickc/Projects/aether-client-cpp-prepared-packet-v0"
+PY = Path(r"C:\Espressif\python_env\idf6.0_py3.11_env\Scripts\python.exe")
+CMAKE = Path(r"C:\Espressif\tools\cmake\3.30.2\bin\cmake.exe")
+NINJA = Path(r"C:\Espressif\tools\ninja\1.12.1\ninja.exe")
+RX_EXE = ROOT / "temperature_receiver" / "build-bisect" / "temperature_receiver.exe"
+RX_BUILD = ROOT / "temperature_receiver" / "build-bisect"
+RX_SESSION = ROOT / "experiments" / "prepared_wifi_cache_rx_session"
+IDF_PATH = r"C:\Espressif\frameworks\esp-idf-v6.0.2"
+CCACHE = r"C:\Espressif\tools\ccache\4.12.1\ccache-4.12.1-windows-x86_64"
+PROGRESS = ROOT / "experiments" / "full_loop_diag_progress.log"
+RX_LOG = ROOT / "experiments" / "full_loop_diag_rx.log"
+TSV = ROOT / "experiments" / "full_loop_diag.tsv"
+PORT = "COM7"
+
+
+def env() -> dict:
+    e = os.environ.copy()
+    e["IDF_PATH"] = IDF_PATH
+    e["IDF_TOOLS_PATH"] = r"C:\Espressif"
+    extra = [
+        CCACHE,
+        r"C:\Espressif\tools\ninja\1.12.1",
+        r"C:\Espressif\tools\cmake\3.30.2\bin",
+        r"C:\msys64\ucrt64\bin",
+    ]
+    e["Path"] = ";".join(extra) + ";" + e.get("Path", "")
+    e.pop("CCACHE_DISABLE", None)
+    return e
+
+
+def log(msg: str) -> None:
+    line = time.strftime("%H:%M:%S") + " " + msg
+    print(line, flush=True)
+    PROGRESS.parent.mkdir(parents=True, exist_ok=True)
+    with PROGRESS.open("a", encoding="utf-8") as f:
+        f.write(line + "\n")
+
+
+def force_sdk_fixes() -> None:
+    sdk = BUILD / "sdkconfig"
+    if not sdk.exists():
+        return
+    text = sdk.read_text(encoding="utf-8")
+    reps = [
+        ("CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y", "# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set"),
+        ("CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y", "# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set"),
+        ("CONFIG_RTC_CLK_SRC_INT_RC=y", "# CONFIG_RTC_CLK_SRC_INT_RC is not set"),
+        ("# CONFIG_RTC_CLK_SRC_EXT_CRYS is not set", "CONFIG_RTC_CLK_SRC_EXT_CRYS=y"),
+        ("CONFIG_ESP_BROWNOUT_DET=n", "CONFIG_ESP_BROWNOUT_DET=y"),
+        ("# CONFIG_ESP_BROWNOUT_DET is not set", "CONFIG_ESP_BROWNOUT_DET=y"),
+        ("CONFIG_PM_ENABLE=y", "# CONFIG_PM_ENABLE is not set"),
+    ]
+    for a, b in reps:
+        text = text.replace(a, b)
+    if "CONFIG_RTC_CLK_SRC_EXT_CRYS=y" not in text:
+        text += "\nCONFIG_RTC_CLK_SRC_EXT_CRYS=y\n"
+    sdk.write_text(text, encoding="utf-8")
+
+
+def kill_receiver() -> None:
+    subprocess.run(
+        ["taskkill", "/F", "/IM", "temperature_receiver.exe"],
+        capture_output=True,
+        text=True,
+    )
+    time.sleep(1)
+
+
+def rebuild_receiver() -> None:
+    log("rebuild temperature_receiver")
+    r = subprocess.run(
+        [str(CMAKE), "--build", str(RX_BUILD), "--parallel"],
+        env=env(),
+        capture_output=True,
+        text=True,
+    )
+    if r.returncode != 0:
+        (ROOT / "experiments" / "full_loop_rx_build.err").write_text(
+            (r.stdout or "")[-8000:] + "\n" + (r.stderr or "")[-8000:],
+            encoding="utf-8",
+        )
+        raise RuntimeError("receiver build failed")
+    log("receiver build ok")
+
+
+def start_receiver() -> None:
+    kill_receiver()
+    RX_SESSION.mkdir(parents=True, exist_ok=True)
+    if TSV.exists():
+        TSV.unlink()
+    env2 = env()
+    env2["AE_RECEIVER_SESSION_DIR"] = str(RX_SESSION)
+    env2["AE_DS_TSV"] = str(TSV)
+    with RX_LOG.open("w", encoding="utf-8") as outf, (
+        ROOT / "experiments" / "full_loop_diag_rx.log.err"
+    ).open("w", encoding="utf-8") as errf:
+        subprocess.Popen(
+            [str(RX_EXE)],
+            cwd=str(RX_SESSION),
+            env=env2,
+            stdout=outf,
+            stderr=errf,
+        )
+    time.sleep(4)
+    log("receiver started")
+
+
+def cmake_configure() -> None:
+    args = [
+        str(CMAKE),
+        "-S",
+        str(ROOT),
+        "-B",
+        str(BUILD),
+        "-G",
+        "Ninja",
+        f"-DCPM_aether-client-cpp_SOURCE={AETHER}",
+        "-DAE_EXP_PREPARED_TX_DONE_DIAG=1",
+        "-DAE_EXP_TX_DIAG_MODE=0",
+        "-DAE_EXP_PREPARED_DEEPSLEEP_5X50=",
+        "-DAE_EXP_PREPARED_WIFI_FASTEST=",
+        "-DAE_EXP_PREPARED_WIFI_BISECT=",
+        "-DAE_EXP_BISECT_CONSOLE=",
+        "-DAE_EXP_BISECT_SMOKE=",
+        "-DAE_EXP_SKIP_DTOR_SAVE=1",
+        "-DSERVICE_UID=5aade50f-00d9-4624-b097-e203cdcf1e38",
+        "-DBENCH_CLIENT_ID=prepared_deepsleep_5x50_v1",
+        "-DAETHER_PREPARED_NONCE_RESERVE=60",
+        "-DWIFI_SSID=chirkov",
+        "-DWIFI_PASSWORD=kcdjepWz51",
+        "-DCMAKE_BUILD_TYPE=Release",
+    ]
+    log("cmake configure full_loop_diag")
+    r = subprocess.run(args, cwd=ROOT, env=env(), capture_output=True, text=True)
+    if r.returncode != 0:
+        (ROOT / "experiments" / "full_loop_cmake.err").write_text(
+            (r.stdout or "") + "\n" + (r.stderr or ""), encoding="utf-8"
+        )
+        raise RuntimeError("cmake failed")
+    force_sdk_fixes()
+    log("cmake ok")
+
+
+def ninja_build() -> None:
+    log("ninja build")
+    r = subprocess.run(
+        [str(NINJA), "-C", str(BUILD)], env=env(), capture_output=True, text=True
+    )
+    if r.returncode != 0:
+        (ROOT / "experiments" / "full_loop_build.err").write_text(
+            (r.stdout or "")[-12000:] + "\n" + (r.stderr or "")[-12000:],
+            encoding="utf-8",
+        )
+        raise RuntimeError("ninja failed")
+    log("build ok")
+
+
+def flash() -> None:
+    log(f"flash {PORT}")
+    cmd = [
+        str(PY),
+        "-m",
+        "esptool",
+        "--chip",
+        "esp32c6",
+        "-p",
+        PORT,
+        "-b",
+        "460800",
+        "write-flash",
+        "--flash-size",
+        "4MB",
+        "0x0",
+        str(BUILD / "bootloader" / "bootloader.bin"),
+        "0x8000",
+        str(BUILD / "partition_table" / "partition-table.bin"),
+        "0x10000",
+        str(BUILD / "temperature_sensor.bin"),
+    ]
+    r = subprocess.run(cmd, env=env(), capture_output=True, text=True)
+    if r.returncode != 0:
+        (ROOT / "experiments" / "full_loop_flash.err").write_text(
+            (r.stdout or "") + "\n" + (r.stderr or ""), encoding="utf-8"
+        )
+        raise RuntimeError("flash failed")
+    log("FLASH_OK")
+
+
+def parse_counts(text: str) -> tuple[int, int, list[str], list[str]]:
+    fulls = re.findall(r"^FULL_DIAG .+$", text, re.M)
+    hots = re.findall(r"^RECV HOT .+$", text, re.M)
+    return len(fulls), len(hots), fulls, hots
+
+
+def wait_capture(max_full: int = 3, need_hot: int = 3, timeout_s: float = 180.0) -> None:
+    log(
+        f"wait capture max_full={max_full} need_hot={need_hot} "
+        "(power-cycle board once if needed after flash)"
+    )
+    t0 = time.time()
+    last_full = 0
+    while time.time() - t0 < timeout_s:
+        text = RX_LOG.read_text(encoding="utf-8", errors="replace") if RX_LOG.exists() else ""
+        nf, nh, fulls, hots = parse_counts(text)
+        if nf != last_full:
+            last_full = nf
+            log(f"progress full={nf} hot={nh}")
+            if fulls:
+                log("  " + fulls[-1][:240])
+        if nh >= need_hot:
+            log(f"STOP ok FULL={nf} HOT={nh}")
+            for line in fulls[:3]:
+                log("  " + line[:240])
+            for line in hots[:3]:
+                log("  " + line[:240])
+            return
+        if nf >= max_full and nh == 0:
+            log(f"STOP at {nf} FULL with HOT=0 (diag only)")
+            for line in fulls[:3]:
+                log("  " + line[:240])
+            return
+        time.sleep(1.0)
+    text = RX_LOG.read_text(encoding="utf-8", errors="replace") if RX_LOG.exists() else ""
+    nf, nh, fulls, hots = parse_counts(text)
+    log(f"TIMEOUT FULL={nf} HOT={nh}")
+    for line in fulls[:3]:
+        log("  " + line[:240])
+    for line in hots[:3]:
+        log("  " + line[:240])
+
+
+def main() -> int:
+    if PROGRESS.exists():
+        PROGRESS.write_text("", encoding="utf-8")
+    rebuild_receiver()
+    start_receiver()
+    cmake_configure()
+    ninja_build()
+    flash()
+    wait_capture()
+    kill_receiver()
+    return 0
+
+
+if __name__ == "__main__":
+    try:
+        sys.exit(main())
+    except Exception as e:
+        log(f"ERROR {e}")
+        kill_receiver()
+        sys.exit(1)
diff --git a/experiments/run_ignore_bssid_control.ps1 b/experiments/run_ignore_bssid_control.ps1
new file mode 100644
index 0000000..b0b2e51
--- /dev/null
+++ b/experiments/run_ignore_bssid_control.ps1
@@ -0,0 +1,102 @@
+param(
+  [string]$Port = 'COM7',
+  [string]$ServiceUid = '3d284a4f-ebb4-451e-a2c5-aecb0d647a45',
+  [int]$CaptureSec = 600
+)
+$ErrorActionPreference = 'Stop'
+$env:Path = 'C:\Program Files\Git\cmd;C:\Espressif\python_env\idf6.0_py3.11_env\Scripts;' + $env:Path
+$env:IDF_PATH = 'C:\Espressif\frameworks\esp-idf-v6.0.2'
+. "$env:IDF_PATH\export.ps1" | Out-Null
+
+$proj = 'C:\Users\nickc\Projects\temperature-sensor-prepared'
+$aether = 'C:/Users/nickc/Projects/aether-client-cpp-prepared-packet-v0'
+$build = 'build-esp32c6-save-bench-smoke'
+$exp = Join-Path $proj 'experiments\wifi_lifecycle'
+New-Item -ItemType Directory -Force -Path $exp | Out-Null
+$log = Join-Path $exp 'v30_ignore_bssid_capture.log'
+$rebootLog = Join-Path $exp 'v30_ignore_bssid_reboot3.log'
+
+function Stop-EspMonitors {
+  Get-CimInstance Win32_Process -Filter "Name='python.exe'" |
+    Where-Object { $_.CommandLine -match 'esp_idf_monitor' } |
+    ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
+  Start-Sleep -Seconds 2
+}
+
+Set-Location $proj
+Stop-EspMonitors
+
+# Baseline driver + ignore BSSID only. Do NOT erase flash / SPIFFS.
+$cmakeArgs = @(
+  '-B', $build,
+  '-D', 'WIFI_SSID=chirkov',
+  '-D', 'WIFI_PASSWORD=kcdjepWz51',
+  '-D', "SERVICE_UID=$ServiceUid",
+  '-D', "CPM_aether-client-cpp_SOURCE=$aether",
+  '-D', 'AE_EXP_WIFI_LIFECYCLE=1',
+  '-D', 'AE_EXP_WIFI_LIFECYCLE_VARIANT=30',
+  '-D', 'AE_EXP_WIFI_LIFECYCLE_CYCLES=10',
+  '-D', 'AE_EXP_SKIP_DTOR_SAVE=1',
+  '-D', 'AE_EXP_WIFI_COOLDOWN_MS=0',
+  '-D', 'AE_EXP_WIFI_CANONICAL=0',
+  '-D', 'AE_EXP_WIFI_IGNORE_BSSID=1',
+  '-D', 'AE_EXP_WIFI_FEAT_AMPDU_OFF=0',
+  '-D', 'AE_EXP_WIFI_FEAT_SCAN_THRESHOLD=0',
+  '-D', 'AE_EXP_WIFI_FEAT_CONNECT_RETRY10=0',
+  '-D', 'AE_EXP_WIFI_FEAT_FAIL_DISCONNECT=0',
+  '-D', 'AE_EXP_WIFI_FEAT_BSSID_CACHE=0',
+  '-D', 'AE_EXP_WIFI_FEAT_LEGACY_DEINIT=0',
+  '-D', 'AE_EXP_WIFI_FEAT_LEGACY_HANDLERS=0',
+  '-D', 'AE_EXP_FULL_CYCLES=',
+  '-D', 'AE_EXP_BENCH_STAGE=',
+  '-D', 'AE_EXP_SAVE_BENCH_N=',
+  '-D', 'AE_EXP_LEGACY_MAP_SYNC='
+)
+
+Write-Output 'BUILD variant=30 baseline+IGNORE_BSSID (no flash erase)'
+idf.py @cmakeArgs build flash -p $Port
+if ($LASTEXITCODE -ne 0) { throw 'build/flash failed' }
+
+Remove-Item $log -Force -ErrorAction SilentlyContinue
+$elf = Join-Path $proj "$build\temperature_sensor.elf"
+$mon = Start-Process -FilePath python -ArgumentList @('-u','-m','esp_idf_monitor','--port',$Port,'--baud','115200',$elf) -WorkingDirectory (Join-Path $proj $build) -RedirectStandardOutput $log -RedirectStandardError "$log.err" -PassThru -NoNewWindow
+Start-Sleep -Seconds 2
+$prev = $ErrorActionPreference
+$ErrorActionPreference = 'Continue'
+python -m esptool --chip esp32c6 -p $Port run 2>&1 | Out-Null
+$ErrorActionPreference = $prev
+
+$deadline = (Get-Date).AddSeconds($CaptureSec)
+while ((Get-Date) -lt $deadline) {
+  if ((Test-Path $log) -and (Select-String -Path $log -Pattern 'WIFI_SUMMARY' -Quiet)) { break }
+  Start-Sleep -Seconds 5
+}
+Stop-Process -Id $mon.Id -Force -ErrorAction SilentlyContinue
+Start-Sleep -Seconds 2
+
+Write-Output '--- 10-cycle result ---'
+Select-String -Path $log -Pattern '^(cycle=|raw=|min=|median=|max=|completed=|WIFI_SUMMARY)' | ForEach-Object { $_.Line }
+
+# Reboot check: 3 cycles, SPIFFS preserved (no erase)
+Write-Output '--- reboot + 3 cycles (SPIFFS kept) ---'
+Remove-Item $rebootLog -Force -ErrorAction SilentlyContinue
+$mon2 = Start-Process -FilePath python -ArgumentList @('-u','-m','esp_idf_monitor','--port',$Port,'--baud','115200',$elf) -WorkingDirectory (Join-Path $proj $build) -RedirectStandardOutput $rebootLog -RedirectStandardError "$rebootLog.err" -PassThru -NoNewWindow
+Start-Sleep -Seconds 2
+$ErrorActionPreference = 'Continue'
+python -m esptool --chip esp32c6 -p $Port run 2>&1 | Out-Null
+$ErrorActionPreference = $prev
+
+$deadline2 = (Get-Date).AddSeconds(180)
+while ((Get-Date) -lt $deadline2) {
+  if (Test-Path $rebootLog) {
+    $n = @(Select-String -Path $rebootLog -Pattern '^cycle=\d+ init_to_release_ms=').Count
+    if ($n -ge 3) { break }
+  }
+  Start-Sleep -Seconds 3
+}
+Stop-Process -Id $mon2.Id -Force -ErrorAction SilentlyContinue
+
+Write-Output '--- reboot 3-cycle lines ---'
+Select-String -Path $rebootLog -Pattern '^cycle=\d+ init_to_release_ms=' | Select-Object -First 3 | ForEach-Object { $_.Line }
+Write-Output "LOG10=$log"
+Write-Output "LOG3=$rebootLog"
diff --git a/experiments/run_mac_retry_diag.py b/experiments/run_mac_retry_diag.py
new file mode 100644
index 0000000..61c5c5d
--- /dev/null
+++ b/experiments/run_mac_retry_diag.py
@@ -0,0 +1,326 @@
+"""
+One-flash MAC retry campaign orchestrator.
+COM only for flash; after FLASH_OK never touch serial.
+Progress = receiver TSV/log only.
+"""
+
+from __future__ import annotations
+
+import os
+import re
+import subprocess
+import sys
+import time
+from pathlib import Path
+
+ROOT = Path(r"C:\Users\nickc\Projects\temperature-sensor-prepared")
+BUILD = ROOT / "build-esp32c6-save-bench-smoke"
+AETHER = r"C:/Users/nickc/Projects/aether-client-cpp-prepared-packet-v0"
+PY = Path(r"C:\Espressif\python_env\idf6.0_py3.11_env\Scripts\python.exe")
+CMAKE = Path(r"C:\Espressif\tools\cmake\3.30.2\bin\cmake.exe")
+NINJA = Path(r"C:\Espressif\tools\ninja\1.12.1\ninja.exe")
+RX_EXE = ROOT / "temperature_receiver" / "build-bisect" / "temperature_receiver.exe"
+RX_BUILD = ROOT / "temperature_receiver" / "build-bisect"
+RX_SESSION = ROOT / "experiments" / "prepared_wifi_cache_rx_session"
+IDF_PATH = r"C:\Espressif\frameworks\esp-idf-v6.0.2"
+CCACHE = r"C:\Espressif\tools\ccache\4.12.1\ccache-4.12.1-windows-x86_64"
+PROGRESS = ROOT / "experiments" / "mac_retry_diag_progress.log"
+RX_LOG = ROOT / "experiments" / "prepared_mac_retry_diag_rx.log"
+TSV = ROOT / "experiments" / "prepared_mac_retry_diag.tsv"
+PORT = "COM7"
+VARIANTS = 7
+HOT_PER = 50
+
+
+def env() -> dict:
+    e = os.environ.copy()
+    e["IDF_PATH"] = IDF_PATH
+    e["IDF_TOOLS_PATH"] = r"C:\Espressif"
+    extra = [
+        CCACHE,
+        r"C:\Espressif\tools\ninja\1.12.1",
+        r"C:\Espressif\tools\cmake\3.30.2\bin",
+        r"C:\msys64\ucrt64\bin",
+    ]
+    e["Path"] = ";".join(extra) + ";" + e.get("Path", "")
+    e.pop("CCACHE_DISABLE", None)
+    return e
+
+
+def log(msg: str) -> None:
+    line = time.strftime("%H:%M:%S") + " " + msg
+    print(line, flush=True)
+    with PROGRESS.open("a", encoding="utf-8") as f:
+        f.write(line + "\n")
+
+
+def force_sdk_fixes() -> None:
+    sdk = BUILD / "sdkconfig"
+    if not sdk.exists():
+        return
+    text = sdk.read_text(encoding="utf-8")
+    reps = [
+        ("CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y", "# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set"),
+        ("CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y", "# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set"),
+        ("CONFIG_RTC_CLK_SRC_INT_RC=y", "# CONFIG_RTC_CLK_SRC_INT_RC is not set"),
+        ("# CONFIG_RTC_CLK_SRC_EXT_CRYS is not set", "CONFIG_RTC_CLK_SRC_EXT_CRYS=y"),
+        ("CONFIG_ESP_BROWNOUT_DET=n", "CONFIG_ESP_BROWNOUT_DET=y"),
+        ("# CONFIG_ESP_BROWNOUT_DET is not set", "CONFIG_ESP_BROWNOUT_DET=y"),
+        ("CONFIG_PM_ENABLE=y", "# CONFIG_PM_ENABLE is not set"),
+    ]
+    for a, b in reps:
+        text = text.replace(a, b)
+    if "CONFIG_RTC_CLK_SRC_EXT_CRYS=y" not in text:
+        text += "\nCONFIG_RTC_CLK_SRC_EXT_CRYS=y\n"
+    sdk.write_text(text, encoding="utf-8")
+
+
+def kill_receiver() -> None:
+    subprocess.run(
+        ["taskkill", "/F", "/IM", "temperature_receiver.exe"],
+        capture_output=True,
+        text=True,
+    )
+    time.sleep(1)
+
+
+def rebuild_receiver() -> None:
+    log("rebuild temperature_receiver")
+    r = subprocess.run(
+        [str(CMAKE), "--build", str(RX_BUILD), "--parallel"],
+        env=env(),
+        capture_output=True,
+        text=True,
+    )
+    if r.returncode != 0:
+        (ROOT / "experiments" / "mac_retry_rx_build.err").write_text(
+            (r.stdout or "")[-8000:] + "\n" + (r.stderr or "")[-8000:],
+            encoding="utf-8",
+        )
+        raise RuntimeError("receiver build failed")
+    log("receiver build ok")
+
+
+def start_receiver() -> None:
+    kill_receiver()
+    RX_SESSION.mkdir(parents=True, exist_ok=True)
+    if TSV.exists():
+        TSV.unlink()
+    env2 = env()
+    env2["AE_RECEIVER_SESSION_DIR"] = str(RX_SESSION)
+    env2["AE_DS_TSV"] = str(TSV)
+    with RX_LOG.open("w", encoding="utf-8") as outf, (
+        ROOT / "experiments" / "prepared_mac_retry_diag_rx.log.err"
+    ).open("w", encoding="utf-8") as errf:
+        subprocess.Popen(
+            [str(RX_EXE)],
+            cwd=str(RX_SESSION),
+            env=env2,
+            stdout=outf,
+            stderr=errf,
+        )
+    # Wait until RECEIVER_UID appears (cloud ready) — no COM.
+    t0 = time.time()
+    while time.time() - t0 < 60:
+        text = RX_LOG.read_text(encoding="utf-8", errors="replace") if RX_LOG.exists() else ""
+        if "RECEIVER_UID=" in text:
+            log("receiver ready")
+            return
+        time.sleep(1)
+    raise RuntimeError("receiver not ready")
+
+
+def cmake_configure() -> None:
+    args = [
+        str(CMAKE),
+        "-S",
+        str(ROOT),
+        "-B",
+        str(BUILD),
+        "-G",
+        "Ninja",
+        f"-DCPM_aether-client-cpp_SOURCE={AETHER}",
+        "-DAE_EXP_PREPARED_MAC_RETRY_DIAG=1",
+        "-DAE_EXP_PREPARED_TX_DONE_DIAG=",
+        "-DAE_EXP_PREPARED_DEEPSLEEP_5X50=",
+        "-DAE_EXP_PREPARED_WIFI_FASTEST=",
+        "-DAE_EXP_PREPARED_WIFI_BISECT=",
+        "-DAE_EXP_SKIP_DTOR_SAVE=1",
+        "-DSERVICE_UID=5aade50f-00d9-4624-b097-e203cdcf1e38",
+        "-DBENCH_CLIENT_ID=prepared_deepsleep_5x50_v1",
+        "-DAETHER_PREPARED_NONCE_RESERVE=60",
+        "-DWIFI_SSID=chirkov",
+        "-DWIFI_PASSWORD=kcdjepWz51",
+        "-DCMAKE_BUILD_TYPE=Release",
+    ]
+    log("cmake configure mac_retry_diag")
+    r = subprocess.run(args, cwd=ROOT, env=env(), capture_output=True, text=True)
+    if r.returncode != 0:
+        (ROOT / "experiments" / "mac_retry_cmake.err").write_text(
+            (r.stdout or "") + "\n" + (r.stderr or ""), encoding="utf-8"
+        )
+        raise RuntimeError("cmake failed")
+    force_sdk_fixes()
+    log("cmake ok")
+
+
+def ninja_build() -> None:
+    log("ninja build")
+    r = subprocess.run(
+        [str(NINJA), "-C", str(BUILD)], env=env(), capture_output=True, text=True
+    )
+    if r.returncode != 0:
+        (ROOT / "experiments" / "mac_retry_build.err").write_text(
+            (r.stdout or "")[-16000:] + "\n" + (r.stderr or "")[-8000:],
+            encoding="utf-8",
+        )
+        raise RuntimeError("ninja failed")
+    log("build ok")
+
+
+def verify_symbol() -> None:
+    """Prefer nm on linked ELF / map for esp_wifi_internal_set_retry_counter."""
+    elf = BUILD / "temperature_sensor.elf"
+    mapf = BUILD / "temperature_sensor.map"
+    found = False
+    detail = ""
+    if mapf.exists():
+        text = mapf.read_text(encoding="utf-8", errors="replace")
+        if "esp_wifi_internal_set_retry_counter" in text:
+            found = True
+            for line in text.splitlines():
+                if "esp_wifi_internal_set_retry_counter" in line:
+                    detail = line.strip()
+                    break
+    if not found and elf.exists():
+        # try llvm-nm / xtensa/riscv nm from IDF
+        for nm in [
+            Path(r"C:\Espressif\tools\riscv32-esp-elf\esp-14.2.0_20241119\riscv32-esp-elf\bin\riscv32-esp-elf-nm.exe"),
+        ]:
+            if not nm.exists():
+                continue
+            r = subprocess.run(
+                [str(nm), str(elf)], capture_output=True, text=True, env=env()
+            )
+            if "esp_wifi_internal_set_retry_counter" in (r.stdout or ""):
+                found = True
+                for line in (r.stdout or "").splitlines():
+                    if "esp_wifi_internal_set_retry_counter" in line:
+                        detail = line.strip()
+                        break
+                break
+    log(f"symbol_resolved={'yes' if found else 'no'} detail={detail[:160]}")
+    if not found:
+        raise RuntimeError("esp_wifi_internal_set_retry_counter not resolved")
+
+
+def wait_com_for_flash_only(timeout_s: float = 120.0) -> None:
+    """Pre-flash only: COM may be absent while ESP deep-sleeps. After FLASH_OK
+    this function must never be called again."""
+    log(f"pre-flash: waiting up to {int(timeout_s)}s for {PORT} (awake window)")
+    t0 = time.time()
+    while time.time() - t0 < timeout_s:
+        r = subprocess.run(
+            [
+                "powershell",
+                "-NoProfile",
+                "-Command",
+                f"Get-PnpDevice -Class Ports -Status OK | Where-Object {{ $_.FriendlyName -match '{PORT}' }} | Select-Object -ExpandProperty FriendlyName",
+            ],
+            capture_output=True,
+            text=True,
+        )
+        if PORT in (r.stdout or ""):
+            log(f"pre-flash: {PORT} present")
+            return
+        time.sleep(2.0)
+    raise RuntimeError(f"{PORT} not available for flash — wake/power-cycle ESP once")
+
+
+def flash_once() -> None:
+    wait_com_for_flash_only()
+    log(f"flash {PORT} (COM allowed only here)")
+    cmd = [
+        str(PY),
+        "-m",
+        "esptool",
+        "--chip",
+        "esp32c6",
+        "-p",
+        PORT,
+        "-b",
+        "460800",
+        "write-flash",
+        "--flash-size",
+        "4MB",
+        "0x0",
+        str(BUILD / "bootloader" / "bootloader.bin"),
+        "0x8000",
+        str(BUILD / "partition_table" / "partition-table.bin"),
+        "0x10000",
+        str(BUILD / "temperature_sensor.bin"),
+    ]
+    r = subprocess.run(cmd, env=env(), capture_output=True, text=True)
+    if r.returncode != 0:
+        (ROOT / "experiments" / "mac_retry_flash.err").write_text(
+            (r.stdout or "") + "\n" + (r.stderr or ""), encoding="utf-8"
+        )
+        raise RuntimeError("flash failed")
+    log("FLASH_OK — closing COM; further progress via Aether only")
+
+
+def progress_from_log() -> tuple[int, int, int]:
+    text = RX_LOG.read_text(encoding="utf-8", errors="replace") if RX_LOG.exists() else ""
+    fulls = len(re.findall(r"^MAC_FULL ", text, re.M))
+    hots = len(re.findall(r"^RETRY ", text, re.M))
+    finals = len(re.findall(r"^MAC_FINAL|BENCH_DONE mac_retry", text, re.M))
+    return fulls, hots, finals
+
+
+def wait_campaign(timeout_s: float = 45 * 60) -> None:
+    log("wait Aether campaign (no COM)")
+    t0 = time.time()
+    last = (-1, -1, -1)
+    while time.time() - t0 < timeout_s:
+        f, h, fin = progress_from_log()
+        if (f, h, fin) != last:
+            last = (f, h, fin)
+            log(f"progress full={f} hot={h} final={fin}")
+            # print last RETRY line
+            text = RX_LOG.read_text(encoding="utf-8", errors="replace")
+            lines = [ln for ln in text.splitlines() if ln.startswith("RETRY ")]
+            if lines:
+                log("  " + lines[-1][:200])
+        if fin > 0 or h >= VARIANTS * HOT_PER:
+            log(f"STOP campaign full={f} hot={h} final={fin}")
+            return
+        # Also stop if we have summaries for all variants via FULL prev=
+        if f >= VARIANTS + 1 and h >= VARIANTS * HOT_PER - 5:
+            log(f"STOP near-complete full={f} hot={h}")
+            return
+        time.sleep(2.0)
+    log(f"TIMEOUT full={last[0]} hot={last[1]} final={last[2]}")
+
+
+def main() -> int:
+    if PROGRESS.exists():
+        PROGRESS.write_text("", encoding="utf-8")
+    rebuild_receiver()
+    start_receiver()
+    cmake_configure()
+    ninja_build()
+    verify_symbol()
+    flash_once()
+    # IMPORTANT: do not touch COM after this point
+    wait_campaign()
+    kill_receiver()
+    return 0
+
+
+if __name__ == "__main__":
+    try:
+        sys.exit(main())
+    except Exception as e:
+        log(f"ERROR {e}")
+        kill_receiver()
+        sys.exit(1)
diff --git a/experiments/run_prepared_message_e2e.ps1 b/experiments/run_prepared_message_e2e.ps1
new file mode 100644
index 0000000..a1f50d3
--- /dev/null
+++ b/experiments/run_prepared_message_e2e.ps1
@@ -0,0 +1,112 @@
+param(
+  [string]$Port = 'COM7',
+  [string]$ServiceUid = '',
+  [string]$BenchClientId = 'prepared_message_bench_v6',
+  [int]$CaptureSec = 900
+)
+$ErrorActionPreference = 'Stop'
+$env:Path = 'C:\Program Files\Git\cmd;C:\msys64\ucrt64\bin;C:\Espressif\python_env\idf6.0_py3.11_env\Scripts;' + $env:Path
+$env:IDF_PATH = 'C:\Espressif\frameworks\esp-idf-v6.0.2'
+. "$env:IDF_PATH\export.ps1" | Out-Null
+
+$proj = 'C:\Users\nickc\Projects\temperature-sensor-prepared'
+$aether = 'C:/Users/nickc/Projects/aether-client-cpp-prepared-packet-v0'
+$buildEsp = 'build-esp32c6-save-bench-smoke'
+$rxRoot = Join-Path $proj 'experiments\prepared_message_receiver'
+$rxBuild = Join-Path $rxRoot 'build-mingw'
+$rxSession = Join-Path $proj 'experiments\prepared_message_rx_session'
+$exp = Join-Path $proj 'experiments'
+$espLog = Join-Path $exp 'prepared_message_e2e_esp.log'
+$rxLog = Join-Path $exp 'prepared_message_e2e_receiver.log'
+
+function Stop-EspMonitors {
+  Get-CimInstance Win32_Process -Filter "Name='python.exe'" |
+    Where-Object { $_.CommandLine -match 'esp_idf_monitor|idf_monitor|serial' } |
+    ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
+  Get-Process prepared_message_receiver -ErrorAction SilentlyContinue |
+    Stop-Process -Force -ErrorAction SilentlyContinue
+  Start-Sleep -Seconds 2
+}
+
+New-Item -ItemType Directory -Force -Path $exp, $rxSession | Out-Null
+Set-Location $proj
+Stop-EspMonitors
+
+Write-Output 'BUILD desktop prepared_message_receiver'
+New-Item -ItemType Directory -Force -Path $rxBuild | Out-Null
+cmake -S $rxRoot -B $rxBuild -G Ninja `
+  -DCMAKE_BUILD_TYPE=Release `
+  "-DCPM_aether-client-cpp_SOURCE=$aether"
+if ($LASTEXITCODE -ne 0) { throw 'receiver cmake failed' }
+cmake --build $rxBuild --parallel
+if ($LASTEXITCODE -ne 0) { throw 'receiver build failed' }
+
+$env:AE_RECEIVER_SESSION_DIR = $rxSession
+$rxExe = Join-Path $proj 'temperature_receiver\build-prepared-e2e\temperature_receiver.exe'
+Remove-Item $rxLog -ErrorAction SilentlyContinue
+$rxProc = Start-Process -FilePath $rxExe -RedirectStandardOutput $rxLog `
+  -RedirectStandardError ($rxLog + '.err') -PassThru -NoNewWindow
+Write-Output "receiver pid=$($rxProc.Id)"
+
+# Wait for RECEIVER_UID (allow cloud registration on desktop)
+$uid = $ServiceUid
+$deadline = (Get-Date).AddMinutes(10)
+while ([string]::IsNullOrWhiteSpace($uid) -and (Get-Date) -lt $deadline) {
+  Start-Sleep -Seconds 2
+  if (Test-Path $rxLog) {
+    $m = Select-String -Path $rxLog -Pattern 'RECEIVER_UID=([0-9a-fA-F\-]+)' |
+      Select-Object -Last 1
+    if ($m) { $uid = $m.Matches[0].Groups[1].Value }
+  }
+}
+if ([string]::IsNullOrWhiteSpace($uid)) {
+  throw 'receiver UID not ready'
+}
+Set-Content -Path (Join-Path $exp 'prepared_message_receiver_uid.txt') -Value $uid
+Write-Output "SERVICE_UID=$uid"
+
+Write-Output 'BUILD ESP prepared-message E2E (no flash erase)'
+$cmakeArgs = @(
+  '-B', $buildEsp,
+  '-D', 'WIFI_SSID=chirkov',
+  '-D', 'WIFI_PASSWORD=kcdjepWz51',
+  '-D', "SERVICE_UID=$uid",
+  '-D', "BENCH_CLIENT_ID=$BenchClientId",
+  '-D', "CPM_aether-client-cpp_SOURCE=$aether",
+  '-D', 'AE_EXP_PREPARED_MESSAGE_E2E=1',
+  '-D', 'AE_EXP_SKIP_DTOR_SAVE=1',
+  '-D', 'AE_EXP_WIFI_LIFECYCLE=',
+  '-D', 'AE_EXP_FULL_CYCLES=',
+  '-D', 'AETHER_PREPARED_NONCE_RESERVE=10'
+)
+idf.py @cmakeArgs reconfigure
+if ($LASTEXITCODE -ne 0) { throw 'esp reconfigure failed' }
+idf.py -B $buildEsp build
+if ($LASTEXITCODE -ne 0) { throw 'esp build failed' }
+idf.py -B $buildEsp -p $Port flash
+if ($LASTEXITCODE -ne 0) { throw 'esp flash failed' }
+
+Remove-Item $espLog -ErrorAction SilentlyContinue
+$mon = Start-Process -FilePath 'python' -ArgumentList @(
+  "$env:IDF_PATH\tools\idf_monitor.py", '-p', $Port, '-b', '115200',
+  '--print_filter', '*:I'
+) -RedirectStandardOutput $espLog -RedirectStandardError ($espLog + '.err') `
+  -PassThru -NoNewWindow
+
+Write-Output "monitor pid=$($mon.Id); capture ${CaptureSec}s"
+$done = $false
+$end = (Get-Date).AddSeconds($CaptureSec)
+while ((Get-Date) -lt $end) {
+  Start-Sleep -Seconds 5
+  if (Test-Path $espLog) {
+    if (Select-String -Path $espLog -Pattern 'PREPARED_E2E_DONE' -Quiet) {
+      $done = $true
+      break
+    }
+  }
+}
+
+Stop-EspMonitors
+Write-Output "done=$done"
+Write-Output "esp_log=$espLog"
+Write-Output "rx_log=$rxLog"
diff --git a/experiments/run_tx_done_diag.py b/experiments/run_tx_done_diag.py
new file mode 100644
index 0000000..9944ecf
--- /dev/null
+++ b/experiments/run_tx_done_diag.py
@@ -0,0 +1,288 @@
+"""Build/flash/monitor TX-done diagnostic runs A (FIRST_ANY) and B (FIRST_SUCCESS)."""
+
+from __future__ import annotations
+
+import os
+import subprocess
+import sys
+import time
+from pathlib import Path
+
+ROOT = Path(r"C:\Users\nickc\Projects\temperature-sensor-prepared")
+BUILD = ROOT / "build-esp32c6-save-bench-smoke"
+AETHER = r"C:/Users/nickc/Projects/aether-client-cpp-prepared-packet-v0"
+PY = Path(r"C:\Espressif\python_env\idf6.0_py3.11_env\Scripts\python.exe")
+CMAKE = Path(r"C:\Espressif\tools\cmake\3.30.2\bin\cmake.exe")
+NINJA = Path(r"C:\Espressif\tools\ninja\1.12.1\ninja.exe")
+RX_EXE = ROOT / "temperature_receiver" / "build-bisect" / "temperature_receiver.exe"
+RX_BUILD = ROOT / "temperature_receiver" / "build-bisect"
+RX_SESSION = ROOT / "experiments" / "prepared_wifi_cache_rx_session"
+IDF_PATH = r"C:\Espressif\frameworks\esp-idf-v6.0.2"
+CCACHE = r"C:\Espressif\tools\ccache\4.12.1\ccache-4.12.1-windows-x86_64"
+
+PROGRESS = ROOT / "experiments" / "tx_done_diag_progress.log"
+
+
+def env() -> dict:
+    e = os.environ.copy()
+    e["IDF_PATH"] = IDF_PATH
+    e["IDF_TOOLS_PATH"] = r"C:\Espressif"
+    extra = [
+        CCACHE,
+        r"C:\Espressif\tools\ninja\1.12.1",
+        r"C:\Espressif\tools\cmake\3.30.2\bin",
+        r"C:\msys64\ucrt64\bin",
+    ]
+    e["Path"] = ";".join(extra) + ";" + e.get("Path", "")
+    e.pop("CCACHE_DISABLE", None)
+    return e
+
+
+def log(msg: str) -> None:
+    line = time.strftime("%H:%M:%S") + " " + msg
+    print(line, flush=True)
+    PROGRESS.parent.mkdir(parents=True, exist_ok=True)
+    with PROGRESS.open("a", encoding="utf-8") as f:
+        f.write(line + "\n")
+
+
+def force_sdk_fixes() -> None:
+    sdk = BUILD / "sdkconfig"
+    if not sdk.exists():
+        return
+    text = sdk.read_text(encoding="utf-8")
+    reps = [
+        ("CONFIG_ESP_WIFI_ENABLE_WPA3_SAE=y", "# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set"),
+        ("CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y", "# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set"),
+        ("CONFIG_RTC_CLK_SRC_INT_RC=y", "# CONFIG_RTC_CLK_SRC_INT_RC is not set"),
+        ("# CONFIG_RTC_CLK_SRC_EXT_CRYS is not set", "CONFIG_RTC_CLK_SRC_EXT_CRYS=y"),
+        ("CONFIG_ESP_BROWNOUT_DET=n", "CONFIG_ESP_BROWNOUT_DET=y"),
+        ("# CONFIG_ESP_BROWNOUT_DET is not set", "CONFIG_ESP_BROWNOUT_DET=y"),
+        ("CONFIG_PM_ENABLE=y", "# CONFIG_PM_ENABLE is not set"),
+    ]
+    for a, b in reps:
+        text = text.replace(a, b)
+    if "CONFIG_RTC_CLK_SRC_EXT_CRYS=y" not in text:
+        text += "\nCONFIG_RTC_CLK_SRC_EXT_CRYS=y\n"
+    sdk.write_text(text, encoding="utf-8")
+
+
+def rebuild_receiver() -> None:
+    log("rebuild temperature_receiver")
+    r = subprocess.run(
+        [str(CMAKE), "--build", str(RX_BUILD), "--parallel"],
+        env=env(),
+        capture_output=True,
+        text=True,
+    )
+    if r.returncode != 0:
+        (ROOT / "experiments" / "tx_diag_rx_build.err").write_text(
+            r.stdout[-8000:] + "\n" + r.stderr[-8000:], encoding="utf-8"
+        )
+        raise RuntimeError("receiver build failed")
+    log("receiver build ok")
+
+
+def kill_receiver() -> None:
+    subprocess.run(
+        ["taskkill", "/F", "/IM", "temperature_receiver.exe"],
+        capture_output=True,
+        text=True,
+    )
+    time.sleep(1)
+
+
+def start_receiver(tsv: Path, rx_log: Path) -> None:
+    kill_receiver()
+    RX_SESSION.mkdir(parents=True, exist_ok=True)
+    env2 = env()
+    env2["AE_RECEIVER_SESSION_DIR"] = str(RX_SESSION)
+    env2["AE_DS_TSV"] = str(tsv)
+    with rx_log.open("w", encoding="utf-8") as outf, (
+        ROOT / "experiments" / "prepared_tx_done_diag_rx.log.err"
+    ).open("w", encoding="utf-8") as errf:
+        subprocess.Popen(
+            [str(RX_EXE)],
+            cwd=str(RX_SESSION),
+            env=env2,
+            stdout=outf,
+            stderr=errf,
+        )
+    time.sleep(4)
+    log(f"receiver started tsv={tsv.name}")
+
+
+def cmake_configure(mode: int) -> None:
+    args = [
+        str(CMAKE),
+        "-S",
+        str(ROOT),
+        "-B",
+        str(BUILD),
+        "-G",
+        "Ninja",
+        f"-DCPM_aether-client-cpp_SOURCE={AETHER}",
+        "-DAE_EXP_PREPARED_TX_DONE_DIAG=1",
+        f"-DAE_EXP_TX_DIAG_MODE={mode}",
+        "-DAE_EXP_PREPARED_DEEPSLEEP_5X50=",
+        "-DAE_EXP_PREPARED_WIFI_FASTEST=",
+        "-DAE_EXP_PREPARED_WIFI_BISECT=",
+        "-DAE_EXP_BISECT_CONSOLE=",
+        "-DAE_EXP_BISECT_SMOKE=",
+        "-DAE_EXP_SKIP_DTOR_SAVE=1",
+        "-DSERVICE_UID=5aade50f-00d9-4624-b097-e203cdcf1e38",
+        f"-DBENCH_CLIENT_ID=prepared_deepsleep_5x50_v1",
+        "-DAETHER_PREPARED_NONCE_RESERVE=60",
+        "-DWIFI_SSID=chirkov",
+        "-DWIFI_PASSWORD=kcdjepWz51",
+        "-DCMAKE_BUILD_TYPE=Release",
+    ]
+    log(f"cmake configure tx_done_diag mode={mode}")
+    r = subprocess.run(args, cwd=ROOT, env=env(), capture_output=True, text=True)
+    if r.returncode != 0:
+        (ROOT / "experiments" / "tx_diag_cmake.err").write_text(
+            r.stdout + "\n" + r.stderr, encoding="utf-8"
+        )
+        raise RuntimeError("cmake failed")
+    log("cmake ok")
+
+
+def ninja_build() -> None:
+    r = subprocess.run(
+        [str(NINJA), "-C", str(BUILD)], env=env(), capture_output=True, text=True
+    )
+    if r.returncode != 0:
+        (ROOT / "experiments" / "tx_diag_build.err").write_text(
+            r.stdout[-12000:] + "\n" + r.stderr[-12000:], encoding="utf-8"
+        )
+        raise RuntimeError("ninja failed")
+    log("build ok")
+
+
+def flash() -> None:
+    cmd = [
+        str(PY),
+        "-m",
+        "esptool",
+        "--chip",
+        "esp32c6",
+        "-p",
+        "COM7",
+        "-b",
+        "460800",
+        "write-flash",
+        "--flash-size",
+        "4MB",
+        "0x0",
+        str(BUILD / "bootloader" / "bootloader.bin"),
+        "0x8000",
+        str(BUILD / "partition_table" / "partition-table.bin"),
+        "0x10000",
+        str(BUILD / "temperature_sensor.bin"),
+    ]
+    r = subprocess.run(cmd, env=env(), capture_output=True, text=True)
+    if r.returncode != 0:
+        (ROOT / "experiments" / "tx_diag_flash.err").write_text(
+            r.stdout + "\n" + r.stderr, encoding="utf-8"
+        )
+        raise RuntimeError("flash failed")
+    log("flash ok")
+
+
+def tsv_stats(tsv: Path) -> dict:
+    if not tsv.exists():
+        return {}
+    rows = list(tsv.read_text(encoding="utf-8").splitlines())
+    if len(rows) < 2:
+        return {}
+    full = hot = hot_diag = 0
+    for line in rows[1:]:
+        parts = line.split("\t")
+        if len(parts) < 2:
+            continue
+        if parts[1] == "1":
+            # Prefer outer==1 campaign rows when present
+            if len(parts) > 2 and parts[2] == "1":
+                full += 1
+            elif len(parts) <= 2:
+                full += 1
+        elif parts[1] == "2":
+            hot += 1
+            # diag rows have first_status != 255 (col 21) or tx_cb_total > 0
+            if len(parts) > 21:
+                try:
+                    first_st = int(parts[21])
+                    cb_total = int(parts[18]) if len(parts) > 18 else 0
+                except ValueError:
+                    first_st, cb_total = 255, 0
+                if first_st != 255 or cb_total > 0:
+                    hot_diag += 1
+    return {"full": full, "hot": hot, "hot_diag": hot_diag}
+
+
+def wait_done(tsv: Path, rx_log: Path, timeout_s: int = 900) -> str:
+    deadline = time.time() + timeout_s
+    last_hot = -1
+    while time.time() < deadline:
+        if rx_log.exists():
+            text = rx_log.read_text(encoding="utf-8", errors="replace")
+            if "BENCH_DONE tx_done_diag" in text:
+                for line in reversed(text.splitlines()):
+                    if line.startswith("TEST_RESULT"):
+                        return line
+                return "BENCH_DONE"
+        st = tsv_stats(tsv)
+        hot_diag = st.get("hot_diag", 0)
+        if hot_diag != last_hot:
+            last_hot = hot_diag
+            log(
+                f"progress full={st.get('full', 0)} hot={st.get('hot', 0)} "
+                f"hot_diag={hot_diag}"
+            )
+        if st.get("full", 0) >= 1 and hot_diag >= 48:
+            time.sleep(8)
+            st2 = tsv_stats(tsv)
+            if st2.get("hot_diag", 0) >= 48:
+                log(
+                    f"TSV complete enough full={st2['full']} "
+                    f"hot_diag={st2['hot_diag']}"
+                )
+                return (
+                    f"TSV_COMPLETE full={st2['full']} "
+                    f"hot_diag={st2['hot_diag']}"
+                )
+        time.sleep(5)
+    raise TimeoutError("no BENCH_DONE / incomplete TSV")
+
+
+def run_mode(mode: int, label: str) -> str:
+    tsv = ROOT / "experiments" / f"prepared_tx_done_diag_{label}.tsv"
+    rx_log = ROOT / "experiments" / f"prepared_tx_done_diag_{label}_rx.log"
+    if tsv.exists():
+        tsv.unlink()
+    start_receiver(tsv, rx_log)
+    cmake_configure(mode)
+    force_sdk_fixes()
+    ninja_build()
+    force_sdk_fixes()
+    flash()
+    log(f"waiting for mode {label} (~4-8 min)...")
+    result = wait_done(tsv, rx_log, 1200)
+    log(f"RESULT {label}: {result}")
+    return result
+
+
+def main() -> int:
+    PROGRESS.write_text("", encoding="utf-8")
+    rebuild_receiver()
+    # MODE A FIRST_ANY (0), then MODE B FIRST_SUCCESS (1)
+    ra = run_mode(0, "A_FIRST_ANY")
+    # brief gap so AP forgets STA
+    time.sleep(8)
+    rb = run_mode(1, "B_FIRST_SUCCESS")
+    log(f"ALL_DONE A={ra} B={rb}")
+    return 0
+
+
+if __name__ == "__main__":
+    raise SystemExit(main())
diff --git a/experiments/run_wifi_bisect.ps1 b/experiments/run_wifi_bisect.ps1
new file mode 100644
index 0000000..190d3ff
--- /dev/null
+++ b/experiments/run_wifi_bisect.ps1
@@ -0,0 +1,40 @@
+$ErrorActionPreference = 'Stop'
+$script = Join-Path $PSScriptRoot 'run_wifi_lifecycle.ps1'
+
+function Get-Feat($run, [string]$key) {
+  if ($run.ContainsKey($key)) { return [int]$run[$key] }
+  return 0
+}
+
+$runs = @(
+  @{ Variant = 10; Name = 'canonical+AMPDU_OFF'; FeatAmpdu = 1 },
+  @{ Variant = 11; Name = 'canonical+SCAN_THRESHOLD'; FeatThreshold = 1 },
+  @{ Variant = 12; Name = 'canonical+CONNECT_RETRY10'; FeatRetry10 = 1 },
+  @{ Variant = 13; Name = 'canonical+FAIL_DISCONNECT'; FeatFailDisc = 1 },
+  @{ Variant = 14; Name = 'canonical+BSSID_CACHE'; FeatBssid = 1 },
+  @{
+    Variant = 15
+    Name = 'canonical+ALL_FEATS'
+    FeatAmpdu = 1
+    FeatThreshold = 1
+    FeatRetry10 = 1
+    FeatFailDisc = 1
+    FeatBssid = 1
+  }
+)
+
+foreach ($run in $runs) {
+  Write-Output "=== BISECT $($run.Name) variant=$($run.Variant) ==="
+  & $script -Variant $run.Variant -Canonical 1 -CooldownMs 0 `
+    -FeatAmpdu (Get-Feat $run 'FeatAmpdu') `
+    -FeatThreshold (Get-Feat $run 'FeatThreshold') `
+    -FeatRetry10 (Get-Feat $run 'FeatRetry10') `
+    -FeatFailDisc (Get-Feat $run 'FeatFailDisc') `
+    -FeatBssid (Get-Feat $run 'FeatBssid')
+  if ($LASTEXITCODE -ne 0) {
+    Write-Output "WARN: variant $($run.Variant) script exit=$LASTEXITCODE (check log)"
+  }
+}
+
+Write-Output '=== BISECT DONE ==='
+Get-Content (Join-Path $PSScriptRoot 'wifi_lifecycle\wifi_lifecycle_results.tsv')
diff --git a/experiments/run_wifi_lifecycle.ps1 b/experiments/run_wifi_lifecycle.ps1
new file mode 100644
index 0000000..fd74540
--- /dev/null
+++ b/experiments/run_wifi_lifecycle.ps1
@@ -0,0 +1,102 @@
+param(
+  [int]$Variant = 0,
+  [int]$Canonical = 0,
+  [int]$CooldownMs = 0,
+  [int]$FeatAmpdu = 0,
+  [int]$FeatThreshold = 0,
+  [int]$FeatRetry10 = 0,
+  [int]$FeatFailDisc = 0,
+  [int]$FeatBssid = 0,
+  [int]$FeatLegacyDeinit = 0,
+  [int]$FeatLegacyHandlers = 0,
+  [string]$Port = 'COM7',
+  [string]$ServiceUid = '3d284a4f-ebb4-451e-a2c5-aecb0d647a45',
+  [int]$CaptureSec = 900
+)
+$ErrorActionPreference = 'Stop'
+$env:Path = 'C:\Program Files\Git\cmd;C:\Espressif\python_env\idf6.0_py3.11_env\Scripts;' + $env:Path
+$env:IDF_PATH = 'C:\Espressif\frameworks\esp-idf-v6.0.2'
+. "$env:IDF_PATH\export.ps1" | Out-Null
+
+$proj = 'C:\Users\nickc\Projects\temperature-sensor-prepared'
+$aether = 'C:/Users/nickc/Projects/aether-client-cpp-prepared-packet-v0'
+$build = 'build-esp32c6-save-bench-smoke'
+$exp = Join-Path $proj 'experiments\wifi_lifecycle'
+New-Item -ItemType Directory -Force -Path $exp | Out-Null
+$log = Join-Path $exp "v${Variant}_capture.log"
+$tsv = Join-Path $exp 'wifi_lifecycle_results.tsv'
+
+function Stop-EspMonitors {
+  Get-CimInstance Win32_Process -Filter "Name='python.exe'" |
+    Where-Object { $_.CommandLine -match 'esp_idf_monitor' } |
+    ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
+  Start-Sleep -Seconds 2
+}
+
+Set-Location $proj
+$args = @(
+  '-B', $build,
+  '-D', 'WIFI_SSID=chirkov',
+  '-D', 'WIFI_PASSWORD=kcdjepWz51',
+  '-D', "SERVICE_UID=$ServiceUid",
+  '-D', "CPM_aether-client-cpp_SOURCE=$aether",
+  '-D', 'AE_EXP_WIFI_LIFECYCLE=1',
+  '-D', "AE_EXP_WIFI_LIFECYCLE_VARIANT=$Variant",
+  '-D', 'AE_EXP_WIFI_LIFECYCLE_CYCLES=10',
+  '-D', 'AE_EXP_SKIP_DTOR_SAVE=1',
+  '-D', "AE_EXP_WIFI_COOLDOWN_MS=$CooldownMs",
+  '-D', "AE_EXP_WIFI_CANONICAL=$Canonical",
+  '-D', "AE_EXP_WIFI_FEAT_AMPDU_OFF=$FeatAmpdu",
+  '-D', "AE_EXP_WIFI_FEAT_SCAN_THRESHOLD=$FeatThreshold",
+  '-D', "AE_EXP_WIFI_FEAT_CONNECT_RETRY10=$FeatRetry10",
+  '-D', "AE_EXP_WIFI_FEAT_FAIL_DISCONNECT=$FeatFailDisc",
+  '-D', "AE_EXP_WIFI_FEAT_BSSID_CACHE=$FeatBssid",
+  '-D', "AE_EXP_WIFI_FEAT_LEGACY_DEINIT=$FeatLegacyDeinit",
+  '-D', "AE_EXP_WIFI_FEAT_LEGACY_HANDLERS=$FeatLegacyHandlers",
+  '-D', 'AE_EXP_FULL_CYCLES=',
+  '-D', 'AE_EXP_BENCH_STAGE=',
+  '-D', 'AE_EXP_SAVE_BENCH_N=',
+  '-D', 'AE_EXP_LEGACY_MAP_SYNC='
+)
+Write-Output "BUILD variant=$Variant canonical=$Canonical cooldown_ms=$CooldownMs"
+Stop-EspMonitors
+idf.py @args build flash -p $Port
+if ($LASTEXITCODE -ne 0) { throw "build/flash failed" }
+
+Remove-Item $log -Force -ErrorAction SilentlyContinue
+$elf = Join-Path $proj "$build\temperature_sensor.elf"
+$mon = Start-Process -FilePath python -ArgumentList @('-u','-m','esp_idf_monitor','--port',$Port,'--baud','115200',$elf) -WorkingDirectory (Join-Path $proj $build) -RedirectStandardOutput $log -RedirectStandardError "$log.err" -PassThru -NoNewWindow
+Start-Sleep -Seconds 2
+$prevEap = $ErrorActionPreference
+$ErrorActionPreference = 'Continue'
+python -m esptool --chip esp32c6 -p $Port run 2>&1 | Out-Null
+$ErrorActionPreference = $prevEap
+$deadline = (Get-Date).AddSeconds($CaptureSec)
+$summary = $false
+while ((Get-Date) -lt $deadline) {
+  if (Test-Path $log) {
+    if (Select-String -Path $log -Pattern 'WIFI_SUMMARY' -Quiet) { $summary = $true; break }
+  }
+  Start-Sleep -Seconds 10
+}
+Stop-Process -Id $mon.Id -Force -ErrorAction SilentlyContinue
+
+$cycles = @()
+if (Test-Path $log) {
+  $cycles = Select-String -Path $log -Pattern '^WIFI_CYCLE\t' | ForEach-Object { $_.Line }
+  $sumLine = (Select-String -Path $log -Pattern '^WIFI_SUMMARY\t' | Select-Object -Last 1).Line
+}
+Write-Output "SUMMARY=$sumLine"
+$cycles | ForEach-Object { Write-Output $_ }
+
+if ($sumLine) {
+  if (-not (Test-Path $tsv) -or (Get-Item $tsv).Length -eq 0) {
+    "variant`tcompleted`tmin`tmedian`tmax`traw_times`tverdict" | Out-File $tsv -Encoding utf8
+  }
+  $raw = ($cycles | ForEach-Object { ($_ -split "`t" | Where-Object { $_ -match 'init_to_release_ms=' }) -replace 'init_to_release_ms=','' }) -join ','
+  $parts = $sumLine -split "`t"
+  $get = { param($k) ($parts | Where-Object { $_ -like "$k=*" }) -replace "$k=",'' }
+  $row = "{0}`t{1}`t{2}`t{3}`t{4}`t{5}`t" -f $Variant, (&$get 'completed'), (&$get 'min'), (&$get 'median'), (&$get 'max'), $raw
+  Add-Content $tsv $row
+}
+Write-Output "LOG=$log"
diff --git a/experiments/wifi_lifecycle/v30_ignore_bssid_capture.log b/experiments/wifi_lifecycle/v30_ignore_bssid_capture.log
new file mode 100644
index 0000000..eea2cdf
--- /dev/null
+++ b/experiments/wifi_lifecycle/v30_ignore_bssid_capture.log
@@ -0,0 +1,47 @@
+ESP-ROM:esp32c6-20220919
+Build:Sep 19 2022
+rst:0x15 (USB_UART_HPSYS),boot:0x6f (SPI_FAST_FLASH_BOOT)
+Saved PC:0x40808998
+SPIWP:0xee
+mode:DIO, clock div:2
+load:0x40875730,len:0xf4
+load:0x4086b910,len:0x9f8
+load:0x4086e610,len:0x2694
+entry 0x4086b910
+WIFI_BENCH_START	variant=30	cooldown_ms=0
+cycle=1 init_to_release_ms=3410 result=OK
+WIFI_CYCLE	variant=30	cycle=1	init_to_release_ms=3410
+cycle=2 init_to_release_ms=3369 result=OK
+WIFI_CYCLE	variant=30	cycle=2	init_to_release_ms=3369
+cycle=3 init_to_release_ms=3419 result=OK
+WIFI_CYCLE	variant=30	cycle=3	init_to_release_ms=3419
+cycle=4 init_to_release_ms=3389 result=OK
+WIFI_CYCLE	variant=30	cycle=4	init_to_release_ms=3389
+cycle=5 init_to_release_ms=3359 result=OK
+WIFI_CYCLE	variant=30	cycle=5	init_to_release_ms=3359
+cycle=6 init_to_release_ms=3349 result=OK
+WIFI_CYCLE	variant=30	cycle=6	init_to_release_ms=3349
+cycle=7 init_to_release_ms=3339 result=OK
+WIFI_CYCLE	variant=30	cycle=7	init_to_release_ms=3339
+cycle=8 init_to_release_ms=3319 result=OK
+WIFI_CYCLE	variant=30	cycle=8	init_to_release_ms=3319
+cycle=9 init_to_release_ms=3379 result=OK
+WIFI_CYCLE	variant=30	cycle=9	init_to_release_ms=3379
+cycle=10 init_to_release_ms=3439 result=OK
+WIFI_CYCLE	variant=30	cycle=10	init_to_release_ms=3439
+WIFI_SUMMARY	variant=30	completed=10	min=3319	median=3374	max=3439
+raw=3410,3369,3419,3389,3359,3349,3339,3319,3379,3439
+min=3319
+median=3374
+max=3439
+completed=10
+WIFI_RAW	variant=30	cycle=1	init_to_release_ms=3410
+WIFI_RAW	variant=30	cycle=2	init_to_release_ms=3369
+WIFI_RAW	variant=30	cycle=3	init_to_release_ms=3419
+WIFI_RAW	variant=30	cycle=4	init_to_release_ms=3389
+WIFI_RAW	variant=30	cycle=5	init_to_release_ms=3359
+WIFI_RAW	variant=30	cycle=6	init_to_release_ms=3349
+WIFI_RAW	variant=30	cycle=7	init_to_release_ms=3339
+WIFI_RAW	variant=30	cycle=8	init_to_release_ms=3319
+WIFI_RAW	variant=30	cycle=9	init_to_release_ms=3379
+WIFI_RAW	variant=30	cycle=10	init_to_release_ms=3439
diff --git a/experiments/wifi_lifecycle/v30_ignore_bssid_reboot3.log b/experiments/wifi_lifecycle/v30_ignore_bssid_reboot3.log
new file mode 100644
index 0000000..bbdbb73
--- /dev/null
+++ b/experiments/wifi_lifecycle/v30_ignore_bssid_reboot3.log
@@ -0,0 +1,17 @@
+ESP-ROM:esp32c6-20220919
+Build:Sep 19 2022
+rst:0x15 (USB_UART_HPSYS),boot:0x6f (SPI_FAST_FLASH_BOOT)
+Saved PC:0x4201534a
+SPIWP:0xee
+mode:DIO, clock div:2
+load:0x40875730,len:0xf4
+load:0x4086b910,len:0x9f8
+load:0x4086e610,len:0x2694
+entry 0x4086b910
+WIFI_BENCH_START	variant=30	cooldown_ms=0
+cycle=1 init_to_release_ms=3410 result=OK
+WIFI_CYCLE	variant=30	cycle=1	init_to_release_ms=3410
+cycle=2 init_to_release_ms=3339 result=OK
+WIFI_CYCLE	variant=30	cycle=2	init_to_release_ms=3339
+cycle=3 init_to_release_ms=3319 result=OK
+WIFI_CYCLE	variant=30	cycle=3	init_to_release_ms=3319
diff --git a/experiments/wifi_lifecycle/v40_bssid_removed_capture.log b/experiments/wifi_lifecycle/v40_bssid_removed_capture.log
new file mode 100644
index 0000000..6be91ea
--- /dev/null
+++ b/experiments/wifi_lifecycle/v40_bssid_removed_capture.log
@@ -0,0 +1,47 @@
+ESP-ROM:esp32c6-20220919
+Build:Sep 19 2022
+rst:0x15 (USB_UART_HPSYS),boot:0x6f (SPI_FAST_FLASH_BOOT)
+Saved PC:0x40802414
+SPIWP:0xee
+mode:DIO, clock div:2
+load:0x40875730,len:0xf4
+load:0x4086b910,len:0x9f8
+load:0x4086e610,len:0x2694
+entry 0x4086b910
+WIFI_BENCH_START	variant=40	cooldown_ms=0
+cycle=1 init_to_release_ms=3705 result=OK
+WIFI_CYCLE	variant=40	cycle=1	init_to_release_ms=3705
+cycle=2 init_to_release_ms=3579 result=OK
+WIFI_CYCLE	variant=40	cycle=2	init_to_release_ms=3579
+cycle=3 init_to_release_ms=3499 result=OK
+WIFI_CYCLE	variant=40	cycle=3	init_to_release_ms=3499
+cycle=4 init_to_release_ms=3489 result=OK
+WIFI_CYCLE	variant=40	cycle=4	init_to_release_ms=3489
+cycle=5 init_to_release_ms=3769 result=OK
+WIFI_CYCLE	variant=40	cycle=5	init_to_release_ms=3769
+cycle=6 init_to_release_ms=3599 result=OK
+WIFI_CYCLE	variant=40	cycle=6	init_to_release_ms=3599
+cycle=7 init_to_release_ms=3779 result=OK
+WIFI_CYCLE	variant=40	cycle=7	init_to_release_ms=3779
+cycle=8 init_to_release_ms=3489 result=OK
+WIFI_CYCLE	variant=40	cycle=8	init_to_release_ms=3489
+cycle=9 init_to_release_ms=3779 result=OK
+WIFI_CYCLE	variant=40	cycle=9	init_to_release_ms=3779
+cycle=10 init_to_release_ms=3579 result=OK
+WIFI_CYCLE	variant=40	cycle=10	init_to_release_ms=3579
+WIFI_SUMMARY	variant=40	completed=10	min=3489	median=3589	max=3779
+raw=3705,3579,3499,3489,3769,3599,3779,3489,3779,3579
+min=3489
+median=3589
+max=3779
+completed=10
+WIFI_RAW	variant=40	cycle=1	init_to_release_ms=3705
+WIFI_RAW	variant=40	cycle=2	init_to_release_ms=3579
+WIFI_RAW	variant=40	cycle=3	init_to_release_ms=3499
+WIFI_RAW	variant=40	cycle=4	init_to_release_ms=3489
+WIFI_RAW	variant=40	cycle=5	init_to_release_ms=3769
+WIFI_RAW	variant=40	cycle=6	init_to_release_ms=3599
+WIFI_RAW	variant=40	cycle=7	init_to_release_ms=3779
+WIFI_RAW	variant=40	cycle=8	init_to_release_ms=3489
+WIFI_RAW	variant=40	cycle=9	init_to_release_ms=3779
+WIFI_RAW	variant=40	cycle=10	init_to_release_ms=3579
diff --git a/experiments/wifi_lifecycle/v40_bssid_removed_reboot3.log b/experiments/wifi_lifecycle/v40_bssid_removed_reboot3.log
new file mode 100644
index 0000000..ab19c38
--- /dev/null
+++ b/experiments/wifi_lifecycle/v40_bssid_removed_reboot3.log
@@ -0,0 +1,17 @@
+ESP-ROM:esp32c6-20220919
+Build:Sep 19 2022
+rst:0x15 (USB_UART_HPSYS),boot:0x6f (SPI_FAST_FLASH_BOOT)
+Saved PC:0x420168e4
+SPIWP:0xee
+mode:DIO, clock div:2
+load:0x40875730,len:0xf4
+load:0x4086b910,len:0x9f8
+load:0x4086e610,len:0x2694
+entry 0x4086b910
+WIFI_BENCH_START	variant=40	cooldown_ms=0
+cycle=1 init_to_release_ms=3650 result=OK
+WIFI_CYCLE	variant=40	cycle=1	init_to_release_ms=3650
+cycle=2 init_to_release_ms=3519 result=OK
+WIFI_CYCLE	variant=40	cycle=2	init_to_release_ms=3519
+cycle=3 init_to_release_ms=3559 result=OK
+WIFI_CYCLE	variant=40	cycle=3	init_to_release_ms=3559
diff --git a/experiments/wifi_lifecycle/wifi_lifecycle_results.tsv b/experiments/wifi_lifecycle/wifi_lifecycle_results.tsv
new file mode 100644
index 0000000..955bdc4
--- /dev/null
+++ b/experiments/wifi_lifecycle/wifi_lifecycle_results.tsv
@@ -0,0 +1,11 @@
+variant	completed	min	median	max	raw_times	verdict
+0	10	29669	30114	31538	31538,29739,29729,30089,30139,30159,30159,29889,29669,30139	baseline ~30s/cycle
+1	10	3359	3469	3629	3509,3519,3359,3579,3399,3459,3479,3459,3629,3439	canonical ~3.5s/cycle
+2	10	3042	3532	3792	3792,3522,3562,3562,3482,3542,3632,3412,3092,3042	canonical+cooldown ~3.5s (cooldown outside timer)
+10	10	3399	3484	4189	4189,3469,3399,3459,3499,3629,3429,3419,3729,3759	canonical+AMPDU_OFF ~3.5s
+11	10	3429	3494	3579	3578,3509,3579,3459,3429,3499,3489,3579,3479,3459	canonical+SCAN_THRESHOLD ~3.5s
+12	10	3319	3469	3569	3469,3469,3569,3479,3479,3429,3449,3479,3329,3319	canonical+CONNECT_RETRY10 ~3.5s
+13	10	3409	3479	3559	3440,3469,3489,3509,3559,3469,3469,3559,3409,3519	canonical+FAIL_DISCONNECT ~3.5s
+14	0			 		canonical+BSSID_CACHE hung after WIFI_BENCH_START
+17	10	3349	3389	3490	3490,3349,3459,3399,3379,3379,3399,3369,3479,3369	
+18	10	3349	3394	3479	3448,3409,3429,3479,3409,3349,3379,3379,3379,3379	
diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt
index 299d92e..6bb3f20 100644
--- a/main/CMakeLists.txt
+++ b/main/CMakeLists.txt
@@ -16,9 +16,74 @@ cmake_minimum_required(VERSION 3.16.0)
 
 list(APPEND src_list
   "main.cpp"
-  "controller.cpp"
 )
 
+if(AE_EXP_PREPARED_WIFI_CACHE_5X20)
+  list(APPEND src_list
+    "prepared_wifi_cache_5x20_bench.cpp"
+    "prepared_send/prepared_send.cpp"
+  )
+elseif(AE_EXP_PREPARED_KEEP_WIFI_UP_5X20)
+  list(APPEND src_list
+    "prepared_keep_wifi_up_5x20_bench.cpp"
+    "prepared_send/prepared_send.cpp"
+  )
+elseif(AE_EXP_PREPARED_WIFI_FASTEST)
+  list(APPEND src_list
+    "prepared_wifi_fastest_path_bench.cpp"
+    "prepared_send/prepared_send.cpp"
+  )
+elseif(AE_EXP_PREPARED_DEEPSLEEP_5X50)
+  list(APPEND src_list
+    "prepared_deepsleep_5x50_bench.cpp"
+    "experiment_early_entry.cpp"
+    "prepared_send/prepared_send.cpp"
+  )
+elseif(AE_EXP_PREPARED_TX_DONE_DIAG)
+  list(APPEND src_list
+    "prepared_tx_done_diag_bench.cpp"
+    "experiment_early_entry.cpp"
+    "prepared_send/prepared_send.cpp"
+  )
+elseif(AE_EXP_PREPARED_MAC_RETRY_DIAG)
+  list(APPEND src_list
+    "prepared_mac_retry_diag_bench.cpp"
+    "experiment_early_entry.cpp"
+    "prepared_send/prepared_send.cpp"
+  )
+elseif(AE_EXP_PREPARED_BOOT_WIFI_OPT)
+  list(APPEND src_list
+    "prepared_boot_wifi_opt_bench.cpp"
+    "experiment_early_entry.cpp"
+    "prepared_send/prepared_send.cpp"
+  )
+elseif(AE_EXP_PREPARED_BOOT_WIFI_VAL100)
+  list(APPEND src_list
+    "prepared_boot_wifi_val100_bench.cpp"
+    "experiment_early_entry.cpp"
+    "prepared_send/prepared_send.cpp"
+  )
+elseif(AE_EXP_PREPARED_WIFI_BISECT)
+  list(APPEND src_list
+    "prepared_wifi_single_factor_bisect_bench.cpp"
+    "prepared_send/prepared_send.cpp"
+  )
+elseif(AE_EXP_PREPARED_MESSAGE_E2E)
+  list(APPEND src_list
+    "prepared_message_e2e_bench.cpp"
+    "prepared_send/prepared_send.cpp"
+  )
+elseif(AE_EXP_WIFI_LIFECYCLE)
+  list(APPEND src_list "wifi_lifecycle_bench.cpp")
+elseif(AE_EXP_FULL_CYCLES)
+  list(APPEND src_list "thermometer_full_cycles.cpp")
+else()
+  list(APPEND src_list
+    "controller.cpp"
+    "prepared_send/prepared_send.cpp"
+  )
+endif()
+
 list(APPEND bme68x_srcs
   "../third-party/BME68x_SensorAPI/bme68x.c"
 )
@@ -47,7 +112,8 @@ if(NOT CM_PLATFORM)
 
   include(../cmake/CPM.cmake)
 
-  CPMAddPackage(URI "https://github.com/aethernetio/aether-client-cpp.git#main")
+  # Pin exact SHA. Override locally with -DCPM_aether-client-cpp_SOURCE=.
+  CPMAddPackage(URI "https://github.com/aethernetio/aether-client-cpp.git#157aadbec8e7b852d0f89274307ff7cb8103e5f7")
 
   add_executable(${PROJECT_NAME} ${src_list} ${sleeping_src} ${sensors_src})
   set(TARGET_NAME ${PROJECT_NAME})
@@ -65,24 +131,24 @@ else()
       INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/.."
       REQUIRES soc ulp
       PRIV_REQUIRES
-        esp_driver_tsens
-        esp_driver_gpio
-        esp_http_server
-        esp_event
-        esp_timer
-        esp_netif
-        esp_hw_support
-        driver)
+        idf::driver
+        idf::esp_driver_i2c
+        idf::esp_driver_tsens
+        idf::esp_driver_gpio
+        idf::esp_driver_usb_serial_jtag
+        idf::esp_http_server
+        idf::esp_event
+        idf::esp_timer
+        idf::esp_netif
+        idf::esp_hw_support)
 
     set(TARGET_NAME "${COMPONENT_LIB}")
-
     include(../cmake/CPM.cmake)
-    CPMAddPackage(URI "https://github.com/aethernetio/aether-client-cpp.git#main")
+    # Pin exact SHA. Override locally with -DCPM_aether-client-cpp_SOURCE=.
+    CPMAddPackage(URI "https://github.com/aethernetio/aether-client-cpp.git#157aadbec8e7b852d0f89274307ff7cb8103e5f7")
 
     target_link_libraries(${TARGET_NAME} PRIVATE aether)
 
-    ulp_add_project("ulp_main" "${CMAKE_CURRENT_LIST_DIR}/../ulp")
-
     if (NOT "${WIFI_SSID}" STREQUAL "")
       target_compile_definitions(${TARGET_NAME} PRIVATE "WIFI_SSID=\"${WIFI_SSID}\"")
     endif()
@@ -93,6 +159,19 @@ else()
       target_compile_definitions(${TARGET_NAME} PRIVATE "BOARD=${BOARD}")
     endif()
 
+    # Define the path to the board configuration file in the build folder
+    set(ULP_BOARD_FILE "${CMAKE_BINARY_DIR}/ulp_board_config.cmake")
+
+    # Write the value of the BOARD variable to this file
+    if(NOT "${BOARD}" STREQUAL "")
+      file(WRITE "${ULP_BOARD_FILE}" "set(BOARD \"${BOARD}\")\n")
+    else()
+      file(WRITE "${ULP_BOARD_FILE}" "set(BOARD \"\")\n")
+    endif()
+
+    # We call the project addition as usual
+    ulp_add_project("ulp_main" "${CMAKE_CURRENT_LIST_DIR}/../ulp")
+
   else()
     #Other platforms
     message(FATAL_ERROR "Platform ${CM_PLATFORM} is not supported")
@@ -102,3 +181,146 @@ endif()
 if (NOT "${SERVICE_UID}" STREQUAL "")
   target_compile_definitions(${TARGET_NAME} PRIVATE "SERVICE_UID=\"${SERVICE_UID}\"")
 endif()
+
+# Experiment 2 Save measurement optional flags (do NOT set AE_EXP_DIAG here).
+# Apply PUBLIC on aether so library instrumentation sees the same defs.
+# Example: -DAE_EXP_SAVE_STATS=1 -DAE_EXP_SKIP_DTOR_SAVE=1
+set(AE_EXP_SAVE_STATS "" CACHE STRING "Enable AE_EXP_SAVE_STATS (set to 1)")
+set(AE_EXP_SKIP_DTOR_SAVE "" CACHE STRING "Skip AetherApp dtor Save (set to 1)")
+set(AE_EXP_LEGACY_MAP_SYNC "" CACHE STRING "Enable AE_EXP_LEGACY_MAP_SYNC (set to 1)")
+set(AE_EXP_CALL_COUNT_MODE "" CACHE STRING "Call-count mode 1/2/3 (optional)")
+set(AE_EXP_FULL_CYCLES "" CACHE STRING "FULL cycle count (e.g. 30); disables Save bench when set")
+set(AE_EXP_BENCH_STAGE "" CACHE STRING "Enable UART stage markers (set to 1)")
+set(AE_EXP_SAVE_BENCH_N "" CACHE STRING "Save bench samples per scenario (default 50, smoke=2)")
+set(AE_EXP_SAVE_BENCH_CD_CHUNK "" CACHE STRING "C/D chunk size (default 10)")
+set(AE_EXP_WIFI_LIFECYCLE "" CACHE STRING "Wi-Fi lifecycle bench harness (set to 1)")
+set(AE_EXP_WIFI_LIFECYCLE_VARIANT "" CACHE STRING "Wi-Fi lifecycle variant id (0=baseline)")
+set(AE_EXP_WIFI_LIFECYCLE_CYCLES "" CACHE STRING "Wi-Fi lifecycle cycles (default 10)")
+set(AE_EXP_WIFI_COOLDOWN_MS "" CACHE STRING "Cooldown between cycles, outside timer (ms)")
+set(AE_EXP_PREPARED_MESSAGE_E2E "" CACHE STRING "No-sleep prepared-message E2E bench (set to 1)")
+set(AE_EXP_PREPARED_WIFI_CACHE_5X20 "" CACHE STRING "Silent 5x20 prepared Wi-Fi cache bench (set to 1)")
+set(AE_EXP_PREPARED_KEEP_WIFI_UP_5X20 "" CACHE STRING "Silent 5x20 keep-Wi-Fi-up prepared bench (set to 1)")
+set(AE_EXP_PREPARED_WIFI_BISECT "" CACHE STRING "Silent single-factor prepared Wi-Fi bisect (set to 1)")
+set(AE_EXP_PREPARED_WIFI_FASTEST "" CACHE STRING "Silent fastest-path prepared campaign (set to 1)")
+set(AE_EXP_PREPARED_DEEPSLEEP_5X50 "" CACHE STRING "Silent deep-sleep 5x50 prepared E2E (set to 1)")
+set(AE_EXP_PREPARED_TX_DONE_DIAG "" CACHE STRING "Silent TX-done callback diagnostic 1x50 (set to 1)")
+set(AE_EXP_PREPARED_MAC_RETRY_DIAG "" CACHE STRING "Silent MAC retry-limit diagnostic 7x50 (set to 1)")
+set(AE_EXP_PREPARED_BOOT_WIFI_OPT "" CACHE STRING "Silent boot/wifi HOT opt campaign 11x30 (set to 1)")
+set(AE_EXP_PREPARED_BOOT_WIFI_VAL100 "" CACHE STRING "Silent VAL100 combined boot/wifi winners (set to 1)")
+set(AE_EXP_TX_DIAG_MODE "" CACHE STRING "TX-done diag mode 0=FIRST_ANY 1=FIRST_SUCCESS")
+set(AE_EXP_FAST_N "" CACHE STRING "Fastest-path prepared count")
+set(AE_EXP_FAST_TEST_ID "" CACHE STRING "Fastest-path test id")
+set(AE_EXP_FAST_PRE_MS "" CACHE STRING "Fastest-path pre-send delay ms")
+set(AE_EXP_FAST_POST_MS "" CACHE STRING "Fastest-path post-send delay ms")
+set(AE_EXP_FAST_USE_BSSID "" CACHE STRING "Fastest-path cached BSSID (0/1)")
+set(AE_EXP_FAST_FAST_SCAN "" CACHE STRING "Fastest-path WIFI_FAST_SCAN (0/1)")
+set(AE_EXP_FAST_AUTH "" CACHE STRING "Fastest-path auth 0=WPA3 1=H2E 2=WPA2")
+set(AE_EXP_FAST_RETRY "" CACHE STRING "Fastest-path association retry max")
+set(AE_EXP_FAST_POST_MODE "" CACHE STRING "Fastest-path post 0=delay 1=cb 2=cb+10 3=cb+25")
+set(AE_EXP_FAST_AMPDU_TX_OFF "" CACHE STRING "Fastest-path AMPDU TX off (0/1)")
+set(AE_EXP_FAST_STORAGE_RAM "" CACHE STRING "Fastest-path WIFI_STORAGE_RAM (0/1)")
+set(AE_EXP_BISECT_CONSOLE "" CACHE STRING "Bisect USB stage markers (set to 1)")
+set(AE_EXP_BISECT_SMOKE "" CACHE STRING "Bisect smoke B1/2 prepared (set to 1)")
+set(BENCH_CLIENT_ID "" CACHE STRING "Bench SelectClient id (default prepared_message_bench_v1)")
+set(AE_EXP_WIFI_CANONICAL "" CACHE STRING "Canonical ESP-IDF Wi-Fi driver (set to 1)")
+set(AE_EXP_WIFI_FEAT_AMPDU_OFF "" CACHE STRING "Canonical+bisect: AMPDU off")
+set(AE_EXP_WIFI_FEAT_SCAN_THRESHOLD "" CACHE STRING "Canonical+bisect: scan threshold")
+set(AE_EXP_WIFI_FEAT_CONNECT_RETRY10 "" CACHE STRING "Canonical+bisect: 10 connect retries")
+set(AE_EXP_WIFI_FEAT_FAIL_DISCONNECT "" CACHE STRING "Canonical+bisect: fail disconnect path")
+set(AE_EXP_WIFI_FEAT_LEGACY_DEINIT "" CACHE STRING "Canonical+bisect: baseline Deinit")
+set(AE_EXP_WIFI_FEAT_LEGACY_HANDLERS "" CACHE STRING "Canonical+bisect: non-instance handlers")
+
+function(ae_exp_define_if_set flag_name)
+  if(NOT "${${flag_name}}" STREQUAL "")
+    target_compile_definitions(aether PUBLIC "${flag_name}=${${flag_name}}")
+    target_compile_definitions(${TARGET_NAME} PRIVATE "${flag_name}=${${flag_name}}")
+  endif()
+endfunction()
+
+ae_exp_define_if_set(AE_EXP_SAVE_STATS)
+ae_exp_define_if_set(AE_EXP_SKIP_DTOR_SAVE)
+ae_exp_define_if_set(AE_EXP_LEGACY_MAP_SYNC)
+ae_exp_define_if_set(AE_EXP_CALL_COUNT_MODE)
+ae_exp_define_if_set(AE_EXP_FULL_CYCLES)
+ae_exp_define_if_set(AE_EXP_BENCH_STAGE)
+ae_exp_define_if_set(AE_EXP_SAVE_BENCH_N)
+ae_exp_define_if_set(AE_EXP_SAVE_BENCH_CD_CHUNK)
+ae_exp_define_if_set(AE_EXP_WIFI_CANONICAL)
+ae_exp_define_if_set(AE_EXP_WIFI_FEAT_AMPDU_OFF)
+ae_exp_define_if_set(AE_EXP_WIFI_FEAT_SCAN_THRESHOLD)
+ae_exp_define_if_set(AE_EXP_WIFI_FEAT_CONNECT_RETRY10)
+ae_exp_define_if_set(AE_EXP_WIFI_FEAT_FAIL_DISCONNECT)
+ae_exp_define_if_set(AE_EXP_WIFI_FEAT_LEGACY_DEINIT)
+ae_exp_define_if_set(AE_EXP_WIFI_FEAT_LEGACY_HANDLERS)
+ae_exp_define_if_set(AE_EXP_WIFI_LIFECYCLE)
+ae_exp_define_if_set(AE_EXP_WIFI_LIFECYCLE_VARIANT)
+ae_exp_define_if_set(AE_EXP_WIFI_LIFECYCLE_CYCLES)
+ae_exp_define_if_set(AE_EXP_WIFI_COOLDOWN_MS)
+ae_exp_define_if_set(AE_EXP_PREPARED_MESSAGE_E2E)
+ae_exp_define_if_set(AE_EXP_PREPARED_WIFI_CACHE_5X20)
+ae_exp_define_if_set(AE_EXP_PREPARED_KEEP_WIFI_UP_5X20)
+ae_exp_define_if_set(AE_EXP_PREPARED_WIFI_BISECT)
+ae_exp_define_if_set(AE_EXP_PREPARED_WIFI_FASTEST)
+ae_exp_define_if_set(AE_EXP_PREPARED_DEEPSLEEP_5X50)
+ae_exp_define_if_set(AE_EXP_PREPARED_TX_DONE_DIAG)
+ae_exp_define_if_set(AE_EXP_PREPARED_MAC_RETRY_DIAG)
+ae_exp_define_if_set(AE_EXP_PREPARED_BOOT_WIFI_OPT)
+ae_exp_define_if_set(AE_EXP_PREPARED_BOOT_WIFI_VAL100)
+ae_exp_define_if_set(AE_EXP_TX_DIAG_MODE)
+ae_exp_define_if_set(AE_EXP_FAST_N)
+ae_exp_define_if_set(AE_EXP_FAST_TEST_ID)
+ae_exp_define_if_set(AE_EXP_FAST_PRE_MS)
+ae_exp_define_if_set(AE_EXP_FAST_POST_MS)
+ae_exp_define_if_set(AE_EXP_FAST_USE_BSSID)
+ae_exp_define_if_set(AE_EXP_FAST_FAST_SCAN)
+ae_exp_define_if_set(AE_EXP_FAST_AUTH)
+ae_exp_define_if_set(AE_EXP_FAST_RETRY)
+ae_exp_define_if_set(AE_EXP_FAST_POST_MODE)
+ae_exp_define_if_set(AE_EXP_FAST_AMPDU_TX_OFF)
+ae_exp_define_if_set(AE_EXP_FAST_STORAGE_RAM)
+ae_exp_define_if_set(AE_EXP_BISECT_CONSOLE)
+ae_exp_define_if_set(AE_EXP_BISECT_SMOKE)
+  if(AE_EXP_PREPARED_WIFI_CACHE_5X20 STREQUAL "1" OR
+   AE_EXP_PREPARED_KEEP_WIFI_UP_5X20 STREQUAL "1" OR
+   AE_EXP_PREPARED_WIFI_FASTEST STREQUAL "1" OR
+   AE_EXP_PREPARED_DEEPSLEEP_5X50 STREQUAL "1" OR
+   AE_EXP_PREPARED_TX_DONE_DIAG STREQUAL "1" OR
+   AE_EXP_PREPARED_MAC_RETRY_DIAG STREQUAL "1" OR
+   AE_EXP_PREPARED_BOOT_WIFI_OPT STREQUAL "1" OR
+   AE_EXP_PREPARED_BOOT_WIFI_VAL100 STREQUAL "1" OR
+   (AE_EXP_PREPARED_WIFI_BISECT STREQUAL "1" AND
+    NOT AE_EXP_BISECT_CONSOLE STREQUAL "1"))
+  target_compile_definitions(aether PUBLIC "AE_EXP_SILENT=1")
+  target_compile_definitions(${TARGET_NAME} PRIVATE "AE_EXP_SILENT=1")
+endif()
+if(NOT "${BENCH_CLIENT_ID}" STREQUAL "")
+  target_compile_definitions(${TARGET_NAME} PRIVATE
+    "BENCH_CLIENT_ID=\"${BENCH_CLIENT_ID}\"")
+endif()
+
+# Continuous prepared-send E2E test defaults (override via -D...).
+if(NOT DEFINED AETHER_PREPARED_NONCE_RESERVE)
+  set(AETHER_PREPARED_NONCE_RESERVE 10 CACHE STRING "Prepared nonce reserve count")
+endif()
+if(NOT DEFINED AETHER_PREPARED_HOT_SLEEP_SECONDS)
+  set(AETHER_PREPARED_HOT_SLEEP_SECONDS 10 CACHE STRING "Deep sleep seconds after send")
+endif()
+if(NOT DEFINED AETHER_PREPARED_POST_SEND_HOLD_MS)
+  set(AETHER_PREPARED_POST_SEND_HOLD_MS 300 CACHE STRING "Post-send TX hold ms on prepared path")
+endif()
+if(NOT DEFINED AETHER_PREPARED_WIFI_PS)
+  set(AETHER_PREPARED_WIFI_PS 0 CACHE STRING "Prepared WiFi PS mode (0=NONE,1=MIN,2=MAX)")
+endif()
+if(NOT DEFINED AETHER_PREPARED_HOT_WIFI_TIMEOUT_MS)
+  set(AETHER_PREPARED_HOT_WIFI_TIMEOUT_MS 15000 CACHE STRING "Prepared WiFi connect timeout ms")
+endif()
+if(NOT DEFINED AETHER_PREPARED_HOT_WIFI_MAX_RETRY)
+  set(AETHER_PREPARED_HOT_WIFI_MAX_RETRY 10 CACHE STRING "Prepared WiFi max association retries")
+endif()
+target_compile_definitions(${TARGET_NAME} PRIVATE
+  "AETHER_PREPARED_NONCE_RESERVE=${AETHER_PREPARED_NONCE_RESERVE}"
+  "AETHER_PREPARED_HOT_SLEEP_SECONDS=${AETHER_PREPARED_HOT_SLEEP_SECONDS}"
+  "AETHER_PREPARED_POST_SEND_HOLD_MS=${AETHER_PREPARED_POST_SEND_HOLD_MS}"
+  "AETHER_PREPARED_WIFI_PS=${AETHER_PREPARED_WIFI_PS}"
+  "AETHER_PREPARED_HOT_WIFI_TIMEOUT_MS=${AETHER_PREPARED_HOT_WIFI_TIMEOUT_MS}"
+  "AETHER_PREPARED_HOT_WIFI_MAX_RETRY=${AETHER_PREPARED_HOT_WIFI_MAX_RETRY}")
diff --git a/main/bench_payload.h b/main/bench_payload.h
new file mode 100644
index 0000000..7ad7d6d
--- /dev/null
+++ b/main/bench_payload.h
@@ -0,0 +1,764 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * Compact binary benchmark payloads for prepared Wi-Fi experiments.
+ * All multi-byte fields are little-endian.
+ */
+
+#ifndef TEMP_SENSOR_BENCH_PAYLOAD_H_
+#define TEMP_SENSOR_BENCH_PAYLOAD_H_
+
+#include 
+#include 
+#include 
+
+namespace temp_sensor::bench {
+
+static constexpr std::uint8_t kMagic = 0xAE;
+static constexpr std::uint8_t kBisectMagic = 0xAF;
+
+enum class MsgType : std::uint8_t {
+  kFull = 1,
+  kPrepared = 2,
+  kFinal = 3,
+};
+
+enum class CacheFlags : std::uint8_t {
+  kNone = 0,
+  kUsedBssid = 1 << 0,
+  kUsedStaticIp = 1 << 1,
+  kDhcpSkipped = 1 << 2,
+  kUsedStaticArp = 1 << 3,
+  kArpFallback = 1 << 4,
+  kWifiFallback = 1 << 5,
+};
+
+enum class BisectMsgType : std::uint8_t {
+  kFull = 1,
+  kPrepared = 2,
+  kFinal = 3,
+  kMeta = 4,
+  kVariantSummary = 5,
+};
+
+enum class BisectVariant : std::uint8_t {
+  kB0 = 0,
+  kB1,
+  kC1,
+  kC2,
+  kC3,
+  kC4,
+  kC5,
+  kC6,
+  kC7,
+  kC8,
+  kP1,
+  kP2,
+  kP3,
+  kCount,
+};
+
+enum class BisectFactorBits : std::uint8_t {
+  kBssid = 1 << 0,
+  kChannel = 1 << 1,
+  kFastScan = 1 << 2,
+  kStaticIp = 1 << 3,
+  kStaticArp = 1 << 4,
+  kPsMaxModem = 1 << 5,
+  kAmpduOff = 1 << 6,
+  kFixed1M = 1 << 7,
+};
+
+enum class BisectStatusBits : std::uint8_t {
+  kWifiReady = 1 << 0,
+  kEncodeOk = 1 << 1,
+  kSendtoOk = 1 << 2,
+  kChannelMatch = 1 << 3,
+};
+
+#pragma pack(push, 1)
+struct Payload {
+  std::uint8_t magic{kMagic};
+  std::uint8_t type{0};
+  std::uint8_t outer_cycle{0};
+  std::uint8_t prepared_index{0};
+  std::uint16_t sequence_global{0};
+  std::uint32_t registration_us{0};
+  std::uint32_t previous_full_us{0};
+  std::uint32_t previous_prepared_us{0};
+  std::uint8_t cache_flags{0};
+};
+
+struct BisectPayload {
+  std::uint8_t magic{kBisectMagic};
+  std::uint8_t type{0};
+  std::uint8_t variant_id{0};
+  std::uint8_t prepared_index{0};
+  std::uint16_t sequence_global{0};
+  std::uint32_t time_us{0};
+  std::uint32_t aux_us{0};
+  std::uint8_t requested_channel{0};
+  std::uint8_t actual_channel{0};
+  std::uint8_t status_flags{0};
+  std::uint8_t factor_bits{0};
+  std::uint8_t wifi_ready_count{0};
+  std::uint8_t encode_count{0};
+  std::uint8_t sendto_count{0};
+  std::uint8_t nonce_consumed{0};
+  std::uint32_t cached_ip{0};
+  std::uint8_t cached_bssid[6]{};
+  std::uint8_t cached_channel{0};
+  std::uint8_t pre_delay_ms{0};
+};
+#pragma pack(pop)
+
+static constexpr std::uint8_t kFastMagic = 0xB1;
+
+enum class FastMsgType : std::uint8_t {
+  kFull = 1,
+  kPrepared = 2,
+  kFinal = 3,
+};
+
+enum class FastAssocBits : std::uint8_t {
+  kBssid = 1 << 0,
+  kChannel = 1 << 1,
+  kFastScan = 1 << 2,
+  kStaticIp = 1 << 3,
+  kStaticArp = 1 << 4,
+  kAmpduTxOff = 1 << 5,
+  kStorageRam = 1 << 6,
+  kCallback = 1 << 7,
+};
+
+#pragma pack(push, 1)
+struct FastPayload {
+  std::uint8_t magic{kFastMagic};
+  std::uint8_t type{0};
+  std::uint8_t test_id{0};
+  std::uint8_t prepared_index{0};
+  std::uint16_t sequence_global{0};
+  std::uint32_t cycle_us{0};
+  std::uint32_t connect_us{0};
+  std::uint16_t pre_ms{0};
+  std::uint16_t post_ms{0};
+  std::uint8_t status_flags{0};
+  std::uint8_t assoc_bits{0};
+  std::uint8_t auth_negotiated{0};
+  std::uint8_t retry_max{0};
+  std::uint16_t wifi_ready_count{0};
+  std::uint16_t encode_count{0};
+  std::uint16_t sendto_count{0};
+  std::uint16_t nonce_consumed{0};
+  std::uint8_t cb_any{0};
+  std::uint8_t cb_match{0};
+  std::uint8_t cb_count{0};
+  std::uint8_t post_mode{0};
+  std::uint32_t encode_send_us{0};
+  std::uint32_t tx_done_wait_us{0};
+  std::uint32_t teardown_us{0};
+  std::uint8_t cb_timeout{0};
+  std::uint8_t reserved0{0};
+  std::uint8_t reserved1{0};
+  std::uint8_t reserved2{0};
+};
+#pragma pack(pop)
+
+static_assert(sizeof(Payload) == 19, "bench payload size");
+static_assert(sizeof(BisectPayload) == 34, "bisect payload size");
+static_assert(sizeof(FastPayload) == 50, "fast payload size");
+
+inline char const* BisectVariantName(std::uint8_t id) {
+  switch (static_cast(id)) {
+    case BisectVariant::kB0:
+      return "B0";
+    case BisectVariant::kB1:
+      return "B1";
+    case BisectVariant::kC1:
+      return "C1";
+    case BisectVariant::kC2:
+      return "C2";
+    case BisectVariant::kC3:
+      return "C3";
+    case BisectVariant::kC4:
+      return "C4";
+    case BisectVariant::kC5:
+      return "C5";
+    case BisectVariant::kC6:
+      return "C6";
+    case BisectVariant::kC7:
+      return "C7";
+    case BisectVariant::kC8:
+      return "C8";
+    case BisectVariant::kP1:
+      return "P1";
+    case BisectVariant::kP2:
+      return "P2";
+    case BisectVariant::kP3:
+      return "P3";
+    default:
+      return "?";
+  }
+}
+
+inline char const* BisectVariantChange(std::uint8_t id) {
+  switch (static_cast(id)) {
+    case BisectVariant::kB0:
+      return "no cache, 0ms pre-delay";
+    case BisectVariant::kB1:
+      return "no cache, 200ms pre-delay";
+    case BisectVariant::kC1:
+      return "BSSID only";
+    case BisectVariant::kC2:
+      return "CHANNEL only";
+    case BisectVariant::kC3:
+      return "BSSID+CHANNEL";
+    case BisectVariant::kC4:
+      return "FAST_SCAN only";
+    case BisectVariant::kC5:
+      return "STATIC_IP only";
+    case BisectVariant::kC6:
+      return "STATIC_IP+ARP (dep C5)";
+    case BisectVariant::kC7:
+      return "BSSID+STATIC_IP";
+    case BisectVariant::kC8:
+      return "CHANNEL+STATIC_IP";
+    case BisectVariant::kP1:
+      return "PS_MAX_MODEM";
+    case BisectVariant::kP2:
+      return "AMPDU_OFF";
+    case BisectVariant::kP3:
+      return "FIXED_1M";
+    default:
+      return "?";
+  }
+}
+
+inline std::vector EncodeVec(Payload const& p) {
+  std::vector out(sizeof(Payload));
+  std::memcpy(out.data(), &p, sizeof(Payload));
+  return out;
+}
+
+template 
+inline Buffer Encode(Payload const& p) {
+  Buffer out(sizeof(Payload));
+  std::memcpy(out.data(), &p, sizeof(Payload));
+  return out;
+}
+
+template 
+inline bool Decode(Buffer const& data, Payload& out) {
+  if (data.size() < sizeof(Payload)) {
+    return false;
+  }
+  std::memcpy(&out, data.data(), sizeof(Payload));
+  return out.magic == kMagic;
+}
+
+template 
+inline Buffer EncodeBisect(BisectPayload const& p) {
+  Buffer out(sizeof(BisectPayload));
+  std::memcpy(out.data(), &p, sizeof(BisectPayload));
+  return out;
+}
+
+template 
+inline bool DecodeBisect(Buffer const& data, BisectPayload& out) {
+  if (data.size() < sizeof(BisectPayload)) {
+    return false;
+  }
+  std::memcpy(&out, data.data(), sizeof(BisectPayload));
+  return out.magic == kBisectMagic;
+}
+
+template 
+inline Buffer EncodeFast(FastPayload const& p) {
+  Buffer out(sizeof(FastPayload));
+  std::memcpy(out.data(), &p, sizeof(FastPayload));
+  return out;
+}
+
+template 
+inline bool DecodeFast(Buffer const& data, FastPayload& out) {
+  if (data.size() < sizeof(FastPayload)) {
+    return false;
+  }
+  std::memcpy(&out, data.data(), sizeof(FastPayload));
+  return out.magic == kFastMagic;
+}
+
+static constexpr std::uint8_t kDsMagic = 0xD5;
+
+enum class DsMsgType : std::uint8_t {
+  kFull = 1,
+  kHot = 2,
+  kFinal = 3,
+  kRecovery = 4,
+};
+
+enum class DsFlags : std::uint8_t {
+  kBrownout = 1 << 0,
+  kCallbackSeen = 1 << 1,
+  kCallbackTimeout = 1 << 2,
+  kCacheValid = 1 << 3,
+  kStateValid = 1 << 4,
+};
+
+enum class DsPendingKind : std::uint8_t {
+  kNone = 0,
+  kFull = 1,
+  kHot = 2,
+};
+
+#pragma pack(push, 1)
+struct DsPayload {
+  std::uint8_t magic{kDsMagic};
+  std::uint8_t type{0};
+  std::uint8_t outer_cycle{0};
+  std::uint8_t hot_index{0};
+  std::uint16_t sequence_global{0};
+  std::uint16_t record_id{0};
+  std::uint8_t reset_reason{0};
+  std::uint8_t wake_cause{0};
+  std::uint8_t flags{0};
+  std::uint8_t brownout_count{0};
+  std::uint8_t unexpected_reset_count{0};
+  std::uint8_t negotiated_auth{0};
+  std::uint32_t requested_sleep_us{0};
+  std::uint32_t sleep_elapsed_to_app_us{0};
+  std::uint32_t sleep_to_app_overhead_us{0};
+  std::uint32_t app_entry_esp_timer_us{0};
+  std::uint32_t pending_user_cycle_us{0};
+  std::uint32_t pending_wifi_cycle_us{0};
+  std::uint32_t connect_us{0};
+  std::uint32_t tx_done_wait_us{0};
+  std::uint32_t teardown_us{0};
+  std::uint16_t prepared_message_left{0};
+  std::uint8_t pending_kind{0};
+  std::uint8_t pending_outer{0};
+  std::uint8_t pending_hot_index{0};
+  std::uint8_t reserved{0};
+};
+#pragma pack(pop)
+
+static_assert(sizeof(DsPayload) == 56, "ds payload size");
+
+template 
+inline Buffer EncodeDs(DsPayload const& p) {
+  Buffer out(sizeof(DsPayload));
+  std::memcpy(out.data(), &p, sizeof(DsPayload));
+  return out;
+}
+
+template 
+inline bool DecodeDs(Buffer const& data, DsPayload& out) {
+  if (data.size() < sizeof(DsPayload)) {
+    return false;
+  }
+  std::memcpy(&out, data.data(), sizeof(DsPayload));
+  return out.magic == kDsMagic;
+}
+
+// TX-done diagnostic deep-sleep payload (experiment only).
+static constexpr std::uint8_t kTxDiagMagic = 0xD6;
+
+enum class TxDiagMsgType : std::uint8_t {
+  kFull = 1,
+  kHot = 2,
+  kFinal = 3,
+};
+
+enum class TxDiagFlags : std::uint8_t {
+  kBrownout = 1 << 0,
+  kCallbackSeen = 1 << 1,
+  kCallbackTimeout = 1 << 2,
+  kCacheValid = 1 << 3,
+  kStateValid = 1 << 4,
+};
+
+// Why firmware chose FULL instead of HOT (set at decision site).
+enum class FullReason : std::uint8_t {
+  kNone = 0,
+  kColdBoot = 1,
+  kRtcStateInvalid = 2,
+  kRtcWifiCacheInvalid = 3,
+  kPreparedBlockInvalid = 4,
+  kPreparedNonceEmpty = 5,
+  kUnexpectedResetReason = 6,
+  kPhaseInvalid = 7,
+  kHotWifiFailed = 8,
+  kHotEncodeFailed = 9,
+  kHotSendFailed = 10,
+  kCallbackTimeoutRecovery = 11,
+  kForcedRecovery = 12,
+  kStateBoundsInvalid = 13,
+  kWifiCacheCaptureFailed = 14,
+  kPreparedExportFailed = 15,
+  kUnknown = 255,
+};
+
+inline char const* FullReasonName(std::uint8_t r) {
+  switch (static_cast(r)) {
+    case FullReason::kNone:
+      return "NONE";
+    case FullReason::kColdBoot:
+      return "COLD_BOOT";
+    case FullReason::kRtcStateInvalid:
+      return "RTC_STATE_INVALID";
+    case FullReason::kRtcWifiCacheInvalid:
+      return "RTC_WIFI_CACHE_INVALID";
+    case FullReason::kPreparedBlockInvalid:
+      return "PREPARED_BLOCK_INVALID";
+    case FullReason::kPreparedNonceEmpty:
+      return "PREPARED_NONCE_EMPTY";
+    case FullReason::kUnexpectedResetReason:
+      return "UNEXPECTED_RESET";
+    case FullReason::kPhaseInvalid:
+      return "PHASE_INVALID";
+    case FullReason::kHotWifiFailed:
+      return "HOT_WIFI_FAILED";
+    case FullReason::kHotEncodeFailed:
+      return "HOT_ENCODE_FAILED";
+    case FullReason::kHotSendFailed:
+      return "HOT_SEND_FAILED";
+    case FullReason::kCallbackTimeoutRecovery:
+      return "CALLBACK_TIMEOUT_RECOVERY";
+    case FullReason::kForcedRecovery:
+      return "FORCED_RECOVERY";
+    case FullReason::kStateBoundsInvalid:
+      return "STATE_BOUNDS_INVALID";
+    case FullReason::kWifiCacheCaptureFailed:
+      return "WIFI_CACHE_CAPTURE_FAILED";
+    case FullReason::kPreparedExportFailed:
+      return "PREPARED_EXPORT_FAILED";
+    default:
+      return "UNKNOWN";
+  }
+}
+
+#pragma pack(push, 1)
+struct TxDiagPayload {
+  std::uint8_t magic{kTxDiagMagic};
+  std::uint8_t type{0};
+  std::uint8_t outer_cycle{0};
+  std::uint8_t hot_index{0};
+  std::uint16_t sequence_global{0};
+  std::uint16_t record_id{0};
+  std::uint8_t reset_reason{0};
+  std::uint8_t wake_cause{0};
+  std::uint8_t flags{0};
+  std::uint8_t brownout_count{0};
+  std::uint8_t unexpected_reset_count{0};
+  std::uint8_t negotiated_auth{0};
+  std::uint32_t requested_sleep_us{0};
+  std::uint32_t sleep_elapsed_to_app_us{0};
+  std::uint32_t sleep_to_app_overhead_us{0};
+  std::uint32_t app_entry_esp_timer_us{0};
+  std::uint32_t pending_user_cycle_us{0};
+  std::uint32_t pending_wifi_cycle_us{0};
+  std::uint32_t connect_us{0};
+  std::uint32_t tx_done_wait_us{0};
+  std::uint32_t teardown_us{0};
+  std::uint16_t prepared_message_left{0};
+  std::uint8_t pending_kind{0};
+  std::uint8_t pending_outer{0};
+  std::uint8_t pending_hot_index{0};
+  std::uint8_t diag_mode{0};
+  std::uint8_t tx_cb_total{0};
+  std::uint8_t tx_cb_success{0};
+  std::uint8_t tx_cb_failed{0};
+  std::uint8_t first_status{0xff};
+  std::uint32_t first_cb_delta_us{0xffffffffu};
+  std::uint32_t first_success_delta_us{0xffffffffu};
+  std::uint32_t first_failed_delta_us{0xffffffffu};
+  std::uint32_t last_cb_delta_us{0xffffffffu};
+  std::uint8_t callbacks_after_success{0};
+  std::int8_t rssi{0};
+  std::uint8_t disconnect_count{0};
+  std::uint8_t last_disconnect_reason{0};
+  std::uint8_t reconnect_count{0};
+  std::uint8_t ap_primary{0};
+  std::uint8_t cb_timeout{0};
+  std::uint8_t full_reason{0};
+  std::uint8_t rtc_state_crc_ok{0};
+  std::uint8_t rtc_state_valid{0};
+  std::uint8_t rtc_wifi_crc_ok{0};
+  std::uint8_t rtc_wifi_valid{0};
+  std::uint8_t prepared_block_valid{0};
+  std::uint8_t phase{0};
+  std::uint32_t rtc_state_magic{0};
+  std::uint16_t rtc_state_version{0};
+  std::uint32_t rtc_wifi_magic{0};
+  std::uint16_t rtc_wifi_version{0};
+  std::uint8_t pre_sleep_phase{0};
+  std::uint8_t pre_sleep_outer{0};
+  std::uint8_t pre_sleep_hot{0};
+  std::uint8_t pre_sleep_prepared_left{0};
+  std::uint32_t pre_sleep_state_crc{0};
+  std::uint32_t pre_sleep_wifi_crc{0};
+  std::uint32_t app_entry_rtc_us{0};
+};
+#pragma pack(pop)
+
+static_assert(sizeof(TxDiagPayload) == 118, "txdiag payload size");
+
+template 
+inline Buffer EncodeTxDiag(TxDiagPayload const& p) {
+  Buffer out(sizeof(TxDiagPayload));
+  std::memcpy(out.data(), &p, sizeof(TxDiagPayload));
+  return out;
+}
+
+template 
+inline bool DecodeTxDiag(Buffer const& data, TxDiagPayload& out) {
+  if (data.size() < sizeof(TxDiagPayload)) {
+    return false;
+  }
+  std::memcpy(&out, data.data(), sizeof(TxDiagPayload));
+  return out.magic == kTxDiagMagic;
+}
+
+// MAC retry-limit diagnostic payload (experiment only).
+static constexpr std::uint8_t kMacRetryMagic = 0xD7;
+
+enum class MacRetryMsgType : std::uint8_t {
+  kFull = 1,
+  kHot = 2,
+  kFinal = 3,
+};
+
+enum class MacRetryVariant : std::uint8_t {
+  kControl = 0,
+  k0_0 = 1,
+  k1_1 = 2,
+  k2_2 = 3,
+  k3_3 = 4,
+  k1_7 = 5,
+  k7_1 = 6,
+  kCount = 7,
+};
+
+inline char const* MacRetryVariantName(std::uint8_t id) {
+  switch (static_cast(id)) {
+    case MacRetryVariant::kControl:
+      return "CONTROL";
+    case MacRetryVariant::k0_0:
+      return "0/0";
+    case MacRetryVariant::k1_1:
+      return "1/1";
+    case MacRetryVariant::k2_2:
+      return "2/2";
+    case MacRetryVariant::k3_3:
+      return "3/3";
+    case MacRetryVariant::k1_7:
+      return "1/7";
+    case MacRetryVariant::k7_1:
+      return "7/1";
+    default:
+      return "?";
+  }
+}
+
+#pragma pack(push, 1)
+struct MacRetryPayload {
+  std::uint8_t magic{kMacRetryMagic};
+  std::uint8_t type{0};
+  std::uint8_t variant_id{0};
+  std::uint8_t hot_index{0};
+  std::uint16_t sequence_global{0};
+  std::uint16_t record_id{0};
+  std::uint8_t short_retry{0};
+  std::uint8_t long_retry{0};
+  std::uint8_t retry_function_called{0};
+  std::int16_t retry_set_rc{-1};
+  std::uint32_t retry_cfg_us{0};
+  std::uint8_t reset_reason{0};
+  std::uint8_t wake_cause{0};
+  std::uint8_t brownout_count{0};
+  std::uint8_t flags{0};
+  std::uint32_t pending_user_cycle_us{0};
+  std::uint32_t pending_wifi_cycle_us{0};
+  std::uint32_t connect_us{0};
+  std::uint32_t encode_send_us{0};
+  std::uint32_t tx_done_wait_us{0};
+  std::uint32_t teardown_us{0};
+  std::uint8_t tx_cb_total{0};
+  std::uint8_t tx_cb_success{0};
+  std::uint8_t tx_cb_failed{0};
+  std::uint8_t first_status{0xff};
+  std::uint8_t cb_timeout{0};
+  std::uint32_t first_cb_delta_us{0xffffffffu};
+  std::uint32_t first_success_delta_us{0xffffffffu};
+  std::uint32_t first_failed_delta_us{0xffffffffu};
+  std::uint32_t last_cb_delta_us{0xffffffffu};
+  std::int8_t rssi{0};
+  std::uint8_t actual_channel{0};
+  std::uint8_t authmode{0};
+  std::uint8_t disconnect_count{0};
+  std::uint8_t reconnect_count{0};
+  std::uint16_t prepared_message_left{0};
+  std::uint8_t prev_variant_id{0xff};
+  std::uint8_t prev_hot_send_count{0};
+  std::uint8_t prev_hot_attempt_count{0};
+  std::uint8_t prev_tx_success_count{0};
+  std::uint8_t prev_tx_fail_count{0};
+  std::uint8_t prev_cb_timeout_count{0};
+  std::uint32_t prev_txdone_sum_us{0};
+  std::uint8_t pending_kind{0};
+  std::uint8_t pending_variant{0};
+  std::uint8_t pending_hot_index{0};
+  std::uint8_t pad0{0};
+};
+#pragma pack(pop)
+
+static_assert(sizeof(MacRetryPayload) == 87, "macretry payload size");
+
+template 
+inline Buffer EncodeMacRetry(MacRetryPayload const& p) {
+  Buffer out(sizeof(MacRetryPayload));
+  std::memcpy(out.data(), &p, sizeof(MacRetryPayload));
+  return out;
+}
+
+template 
+inline bool DecodeMacRetry(Buffer const& data, MacRetryPayload& out) {
+  if (data.size() < sizeof(MacRetryPayload)) {
+    return false;
+  }
+  std::memcpy(&out, data.data(), sizeof(MacRetryPayload));
+  return out.magic == kMacRetryMagic;
+}
+
+
+// Boot / Wi-Fi HOT-path optimization campaign payload (experiment only).
+static constexpr std::uint8_t kBootWifiOptMagic = 0xD8;
+
+enum class BootWifiOptMsgType : std::uint8_t {
+  kFull = 1,
+  kHot = 2,
+  kFinal = 3,
+};
+
+enum class BootWifiOptVariant : std::uint8_t {
+  kD0Control = 0,
+  kD1StorageRam = 1,
+  kD2NvsOff = 2,
+  kD3RamNvsOff = 3,
+  kG1Ht20 = 4,
+  kH1CsOff = 5,
+  kH2CsOn = 6,
+  kE1TxHalf = 7,
+  kE2TxMin = 8,
+  kE3RxHalf = 9,
+  kE4RxMin = 10,
+  kCount = 11,
+};
+
+inline char const* BootWifiOptVariantName(std::uint8_t id) {
+  switch (static_cast(id)) {
+    case BootWifiOptVariant::kD0Control:
+      return "D0_CONTROL";
+    case BootWifiOptVariant::kD1StorageRam:
+      return "D1_STORAGE_RAM";
+    case BootWifiOptVariant::kD2NvsOff:
+      return "D2_NVS_OFF";
+    case BootWifiOptVariant::kD3RamNvsOff:
+      return "D3_RAM_NVS_OFF";
+    case BootWifiOptVariant::kG1Ht20:
+      return "G1_HT20";
+    case BootWifiOptVariant::kH1CsOff:
+      return "H1_CS_OFF";
+    case BootWifiOptVariant::kH2CsOn:
+      return "H2_CS_ON";
+    case BootWifiOptVariant::kE1TxHalf:
+      return "E1_TX_HALF";
+    case BootWifiOptVariant::kE2TxMin:
+      return "E2_TX_MIN";
+    case BootWifiOptVariant::kE3RxHalf:
+      return "E3_RX_HALF";
+    case BootWifiOptVariant::kE4RxMin:
+      return "E4_RX_MIN";
+    default:
+      if (id == 0xff) {
+        return "VAL100_COMBINED";
+      }
+      return "?";
+  }
+}
+
+#pragma pack(push, 1)
+struct BootWifiOptPayload {
+  std::uint8_t magic{kBootWifiOptMagic};
+  std::uint8_t type{0};
+  std::uint8_t variant_id{0};
+  std::uint8_t hot_index{0};
+  std::uint16_t sequence_global{0};
+  std::uint16_t record_id{0};
+  std::uint8_t reset_reason{0};
+  std::uint8_t wake_cause{0};
+  std::uint8_t brownout_count{0};
+  std::uint8_t flags{0};
+  std::uint32_t sleep_elapsed_to_app_us{0};
+  std::uint32_t sleep_to_app_overhead_us{0};
+  std::int64_t app_entry_esp_timer_us{0};
+  std::uint32_t pending_user_cycle_us{0};
+  std::uint32_t pending_wifi_cycle_us{0};
+  std::uint32_t wifi_init_us{0};
+  std::uint32_t connect_us{0};
+  std::uint32_t encode_send_us{0};
+  std::uint32_t tx_done_wait_us{0};
+  std::uint32_t teardown_us{0};
+  std::uint32_t heap_before_wifi{0};
+  std::uint32_t heap_after_wifi{0};
+  std::uint8_t tx_cb_total{0};
+  std::uint8_t tx_cb_success{0};
+  std::uint8_t tx_cb_failed{0};
+  std::uint8_t first_status{0xff};
+  std::uint8_t cb_timeout{0};
+  std::int8_t rssi{0};
+  std::uint8_t actual_channel{0};
+  std::uint8_t authmode{0};
+  std::uint8_t disconnect_count{0};
+  std::uint8_t reconnect_count{0};
+  std::uint16_t prepared_message_left{0};
+  std::uint8_t prev_variant_id{0xff};
+  std::uint8_t prev_hot_send_count{0};
+  std::uint8_t prev_hot_attempt_count{0};
+  std::uint8_t prev_tx_success_count{0};
+  std::uint8_t prev_tx_fail_count{0};
+  std::uint8_t prev_cb_timeout_count{0};
+  std::uint32_t prev_txdone_sum_us{0};
+  std::uint8_t pending_kind{0};
+  std::uint8_t pending_variant{0};
+  std::uint8_t pending_hot_index{0};
+  std::uint8_t setting_flags{0};  // bit0 storage_ram bit1 nvs_off bit2 ht20 ...
+  std::uint8_t static_rx_buf{0};
+  std::uint8_t dynamic_rx_buf{0};
+  std::uint8_t dynamic_tx_buf{0};
+  std::int8_t dynamic_cs{-1};
+};
+#pragma pack(pop)
+
+static_assert(sizeof(BootWifiOptPayload) >= 80, "bootwifiopt payload size");
+
+template 
+inline Buffer EncodeBootWifiOpt(BootWifiOptPayload const& p) {
+  Buffer out(sizeof(BootWifiOptPayload));
+  std::memcpy(out.data(), &p, sizeof(BootWifiOptPayload));
+  return out;
+}
+
+template 
+inline bool DecodeBootWifiOpt(Buffer const& data, BootWifiOptPayload& out) {
+  if (data.size() < sizeof(BootWifiOptPayload)) {
+    return false;
+  }
+  std::memcpy(&out, data.data(), sizeof(BootWifiOptPayload));
+  return out.magic == kBootWifiOptMagic;
+}
+
+
+}  // namespace temp_sensor::bench
+
+#endif  // TEMP_SENSOR_BENCH_PAYLOAD_H_
diff --git a/main/boards/aether_esp32_c6.h b/main/boards/aether_esp32_c6.h
index 5e813c5..62ffd0a 100644
--- a/main/boards/aether_esp32_c6.h
+++ b/main/boards/aether_esp32_c6.h
@@ -20,8 +20,6 @@
 #  error "Illegal CPU! It must be an ESP32C6."
 #endif
 
-#include "hal/i2c_types.h"
-
 #ifndef BOARD_HAS_ULP
 #  define BOARD_HAS_ULP 0
 #endif
@@ -36,7 +34,7 @@
 #endif
 // --- Sensors ---
 #define BOARD_HAS_SHTC3 0
-#define BOARD_HAS_SHT45 1
+#define BOARD_HAS_SHT45 0
 #define BOARD_HAS_STCC4 1
 #define BOARD_HAS_BME688 0
 // --- Hardware Settings ---
diff --git a/main/boards/nano_esp32_c6.h b/main/boards/nano_esp32_c6.h
index d0ae5a5..cb9b0d2 100644
--- a/main/boards/nano_esp32_c6.h
+++ b/main/boards/nano_esp32_c6.h
@@ -20,7 +20,6 @@
 #  error "Illegal CPU! It must be an ESP32C6."
 #endif
 
-#include "hal/i2c_types.h"
 #include "soc/gpio_num.h"
 
 #ifndef BOARD_HAS_ULP
diff --git a/main/controller.cpp b/main/controller.cpp
index 3d0ab38..06c7915 100644
--- a/main/controller.cpp
+++ b/main/controller.cpp
@@ -16,10 +16,15 @@
 
 #include 
 #include 
+#include 
 
 #include "aether/all.h"
+#include "aether/env.h"
 #include "sensors/sensors.h"
 #include "sleeping/sleeping.h"
+#include "prepared_send/prepared_send.h"
+
+using namespace std::chrono_literals;
 
 /**
  * Standard uid for test application.
@@ -27,7 +32,7 @@
  * For real applications you should register your own uid \see aethernet.io
  */
 static constexpr auto kParentUid =
-    ae::Uid::FromString("3ac93165-3d37-4970-87a6-fa4ee27744e4");
+    ae::Uid::FromString("b1ac52c8-8d94-bd39-4c01-a631ac594165");
 /**
  * \brief Uid of aether service for store the temperature values.
  * TODO: add actual uid
@@ -36,7 +41,7 @@ static constexpr auto kServiceUid =
 #ifdef SERVICE_UID
     ae::Uid::FromString(SERVICE_UID);
 #else
-    ae::Uid::FromString("e839f1a9-e0ec-4ff6-b85c-d49efaabf24f");
+    ae::Uid::FromString("73791462-71a0-4014-b1aa-104ba9e62475");
 #endif
 
 #ifdef ESP_PLATFORM
@@ -46,25 +51,92 @@ static const auto kWifiCreds = ae::WifiCreds{
 };
 static const auto kWifiInit = ae::WiFiInit{
     std::vector{{kWifiCreds, {}}},
-    ae::WiFiPowerSaveParam{},
+    {},
 };
 #endif
 
+struct WorkMode {
+  using type = std::uint8_t;
+  static constexpr type kTx = 0x1, kRx = 0x2, kTxRx = 0x3;
+
+  static std::string_view ToText(type v) {
+    switch (v) {
+      case WorkMode::kTx:
+        return "TX";
+      case WorkMode::kRx:
+        return "RX";
+      case WorkMode::kTxRx:
+        return "TX+RX";
+      default:
+        return "NONE";
+    }
+  }
+};
+
+static constexpr ae::Duration kTxInterval = 30s;
+static RTC_STORAGE_ATTR ae::TimePoint next_tx_time = {};
+
+// Client selection handler
+void ClientSelected(ae::Result res);
 // Update temperature sensor
 void UpdateSensors();
 // Message from aether service received
 void MessageReceived(ae::DataBuffer const& buffer);
 // Send the message value to the aether service
-void SendValue(std::int16_t temperature);
+void SendValue(std::string const& temperature);
+// Make all required work and ready to sleep
+void SleepReady();
 // Go to sleep method
-void GoToSleep(ae::Uap::Timer uap_timer);
+void GoToSleep(ae::TimePoint time_point);
+
+static std::shared_ptr aether_app;
+static ae::Client::ptr client;
+static std::unique_ptr message_stream;
 
-static ae::RcPtr aether_app;
-static ae::RcPtr message_stream;
+#ifndef AETHER_PREPARED_HOT_SLEEP_SECONDS
+#  define AETHER_PREPARED_HOT_SLEEP_SECONDS 30
+#endif
+
+static constexpr auto kPreparedHotSleepSeconds =
+    std::chrono::seconds{AETHER_PREPARED_HOT_SLEEP_SECONDS};
+
+static constexpr std::size_t kPreparedNonceReserve =
+#ifdef AETHER_PREPARED_NONCE_RESERVE
+    AETHER_PREPARED_NONCE_RESERVE;
+#else
+    32;
+#endif
+
+void ReadHotSensors(std::string* temperature, uint32_t* humidity,
+                    uint32_t* pressure, uint32_t* co2,
+                    uint32_t* gas_resistance) {
+  *temperature = "Prepared 25.67";
+}
 
 void setup() {
-  std::cout << ae::Format("Setup {:%Y-%m-%d %H:%M:%S}") << ae::Now()
-            << std::endl;
+  std::cout << ae::Format("Setup {}") << ae::Now() << std::endl;
+
+#if defined(ESP_PLATFORM)
+  // Prepared-send hot path: try to send current temperature without creating
+  // full AetherApp. Any error falls back to the normal full boot below.
+  {
+    std::string hot_temperature = {};
+    ReadHotSensors(&hot_temperature, nullptr, nullptr, nullptr, nullptr);
+
+    auto hot_status =
+        temp_sensor::prepared_send::TryHotWakePreparedSend(hot_temperature);
+
+    std::cout << ae::Format(" >>> Prepared hot path status: {}\n",
+                            temp_sensor::prepared_send::ToString(hot_status));
+
+    if (hot_status == temp_sensor::prepared_send::HotSendStatus::kSent) {
+      auto sleep_until =
+          std::chrono::system_clock::now() + kPreparedHotSleepSeconds;
+      DeepSleep(sleep_until, sleep_until, 3000);
+      return;
+    }
+  }
+#endif
 
   aether_app = ae::AetherApp::Construct(
       ae::AetherAppContext{}
@@ -80,59 +152,14 @@ void setup() {
                 kWifiInit);
           })
 #  endif
-          .UapFactory([](ae::AetherAppContext const& context) {
-            auto uap = context.aether()->uap;
-            if (uap.is_valid()) {
-              return uap;
-            }
-            // configure uap
-            // 60secs for send/receive
-            // then 2 times by 30 seconds for send only
-            return ae::Uap::ptr::Create(
-                ae::CreateWith{context.domain()}.with_id(ae::GlobalId::kUap),
-                context.aether(),
-                std::initializer_list{
-                    ae::Interval{.type = ae::IntervalType::kSendReceive,
-                                 .duration = std::chrono::seconds{60},
-                                 .window = std::chrono::seconds{10}},
-                    ae::Interval{.type = ae::IntervalType::kSendOnly,
-                                 .duration = std::chrono::seconds{30}},
-                    ae::Interval{.type = ae::IntervalType::kSendOnly,
-                                 .duration = std::chrono::seconds{30}}});
-          })
 #endif
   );
 
-  // setup sleep on uap event
-  aether_app->aether()->uap->sleep_event().Subscribe(GoToSleep);
-
   // select controller's client
-  auto& select_client =
-      aether_app->aether()->SelectClient(kParentUid, "Controller");
-
-  select_client.result_event().Subscribe(
-      [&](ae::Result&& res) {
-        if (res) {
-          ae::Client::ptr client = std::move(res).value();
-          client.WithLoaded([](auto const& c) {
-            std::cout << Format(
-                "\n\n>>>>>>>\n>>>>>>> Client Loaded UID:{} \n>>>>>>> Visit "
-                "https://aethernet.io/smarthub.html?uuid={} \n<<<<<\n\n",
-                c->uid(), kServiceUid);
-
-            // open message stream to aether service client
-            message_stream =
-                c->message_stream_manager().CreateStream(kServiceUid);
-            message_stream->out_data_event().Subscribe(MessageReceived);
-
-            // measure temperature and send updated value
-            UpdateSensors();
-          });
-        } else {
-          std::cerr << " !!! Client selection error";
-          aether_app->Exit(1);
-        }
-      });
+  aether_app->aether()
+      ->SelectClient(kParentUid, "Controller")
+      .result_event()
+      .Subscribe(&ClientSelected);
 }
 
 void loop() {
@@ -145,14 +172,72 @@ void loop() {
     aether_app->WaitUntil(new_time);
   } else {
     // cleanup resources
-    message_stream.Reset();
-    aether_app.Reset();
+    message_stream.reset();
+    aether_app.reset();
   }
 }
 
+void ClientSelected(ae::Result res) {
+  if (!res) {
+    std::cerr << " !!! Client selection error\n";
+    aether_app->Exit(1);
+    return;
+  }
+
+  client = std::move(res).value();
+  auto client_ptr = client.Load();
+  if (!client_ptr) {
+    std::cerr << " !!! Client wasn't loaded";
+    aether_app->Exit(2);
+  }
+
+  std::cout << ae::Format(
+      "\n\n>>>>>>>\n>>>>>>> Client Loaded UID:{} \n>>>>>>> Visit "
+      "https://aethernet.io/smarthub.html?uuid={} \n<<<<<\n\n",
+      client_ptr->uid(), kServiceUid);
+
+  // Config connectivity policy, open 5s RX window every 60s.
+  client_ptr->connectivity_policy()
+      ->ConfigureRxTimings(ae::RequestPolicy::All{})
+      .ForAllPriorities(ae::RxTimingConf::Every(60s).WithWindow(5s));
+
+  // check current work_mode
+  // it's always TX if we woke up
+  auto work_mode = WorkMode::kTx;
+  auto current_time = ae::Now();
+  static constexpr ae::Duration threshold = 5s;
+  auto cp_status = client_ptr->connectivity_policy()->GetStatus();
+  // if it's next_service_time it's also RX
+  if ((current_time + threshold) >= cp_status.next_service_time) {
+    work_mode = work_mode | WorkMode::kRx;
+  }
+  std::cout << ae::Format(">>>> Run in {} work mode\n",
+                          WorkMode::ToText(work_mode));
+
+  if ((work_mode & WorkMode::kRx) != 0) {
+    // open message stream for receive and send
+    message_stream = std::make_unique(
+        *aether_app, client_ptr, kServiceUid,
+        client_ptr->message_stream_manager().CreatePort(kServiceUid));
+    message_stream->out_data_event().Subscribe(MessageReceived);
+  } else {
+    // open message stream for send only
+    message_stream = std::make_unique(
+        *aether_app, client_ptr, kServiceUid, ae::P2pPortHandle{});
+  }
+
+  // measure temperature and send updated value
+  UpdateSensors();
+}
+
+void ReadSensors(std::string* temperature, uint32_t* humidity,
+                 uint32_t* pressure, uint32_t* co2, uint32_t* gas_resistance) {
+  *temperature = "Full 25.67";
+}
+
 // implemented in sensors/
 void UpdateSensors() {
-  std::int16_t temperature = {};
+  std::string temperature = {};
   ReadSensors(&temperature, nullptr, nullptr, nullptr, nullptr);
   std::cout << ae::Format(" >>> Temperature: [{}]\n", temperature);
   // TODO: add check if wakeup cause is ulp then send value
@@ -164,54 +249,64 @@ void MessageReceived(ae::DataBuffer const& buffer) {
   std::cout << ae::Format(" >>> Received message from service: [{}]\n", buffer);
 }
 
-void SendValue(std::int16_t temperature) {
+void SendValue(std::string const& temperature) {
   // The stream is not initialized yet
   if (!message_stream) {
     return;
   }
 
-  struct Header {
-    std::uint8_t const root_code = 0x3;
-    std::uint8_t const size = sizeof(std::uint8_t) + sizeof(std::int16_t);
-    std::uint8_t const dev_code = 0x10;
-    AE_REFLECT_MEMBERS(root_code, size, dev_code)
-  };
-  static constexpr auto header = Header{};
-
-  auto message = ae::DataBuffer{};
-  message.reserve(sizeof(header) + 2);
-  {
-    auto writer = ae::VectorWriter<>{message};
-    auto stream = ae::omstream{writer};
-    // write message header and temperature value
-    // temperature in range -100.0 to 100.0 x100 (-10000 to 10000)
-    stream << header << temperature;
-  }
+  auto message =
+      temp_sensor::prepared_send::MakeTemperaturePayload(temperature);
+  std::cout << ae::Format(" [CALL-CHAIN] SendValue payload_size={}\n",
+                          message.size());
 
   message_stream->Write(std::move(message)).status_event().Subscribe([](auto) {
+    // Export/refresh prepared block after the full send path has a valid
+    // stream. If export fails, keep normal behavior and just sleep.
+    if (client.is_valid() && message_stream) {
+      temp_sensor::prepared_send::ExportPreparedSendBlock(
+          client, message_stream->destination(), kPreparedNonceReserve);
+    }
+
     // with any result ready to sleep
-    aether_app->aether()->uap->SleepReady();
+    SleepReady();
   });
+
+  next_tx_time = ae::Now() + kTxInterval;
 }
 
-void GoToSleep(ae::Uap::Timer uap_timer) {
+void SleepReady() {
+  auto go_to_sleep = [](auto next_rx_time) noexcept {
+    auto next_time = std::min(next_tx_time, next_rx_time);
+    std::cout << ae::Format(
+        ">> Go to sleep no wait, next_tx_time {}, next_rx_time {}\n",
+        next_tx_time, next_rx_time);
+    GoToSleep(next_time);
+  };
+
+  auto status = client->connectivity_policy()->GetStatus();
+  if (status.can_suspend) {
+    go_to_sleep(status.next_service_time);
+  } else {
+    std::cout << ">>> Wait for can suspend\n";
+    client->connectivity_policy()->suspend_allowed_event().Subscribe([&]() {
+      go_to_sleep(client->connectivity_policy()->GetStatus().next_service_time);
+    });
+  }
+}
+
+void GoToSleep(ae::TimePoint time_point) {
   std::cout << " >>> Going to sleep...\n";
 
   if (!aether_app) {
     return;
   }
-
-  // get the interval with the specified offset
-  // offset is required to account the Save operation
-  auto interval = uap_timer.interval(std::chrono::seconds{10});
   // save current aether state
   aether_app->aether().Save();
+
   // Go to sleep
-  auto sleep_until = interval.until();
-  std::cout << ae::Format(
-      " >>> Sleep from {:%Y-%m-%d %H:%M:%S} until {:%Y-%m-%d %H:%M:%S}...\n",
-      ae::Now(), sleep_until);
+  std::cout << ae::Format(" >>> Sleep from {} until {}...\n", ae::Now(),
+                          time_point);
   // TODO: add separate sleep duration
-  DeepSleep(interval.until(), interval.until(),
-            3000);  // wait till time or 30 deegrees
+  DeepSleep(time_point, time_point, 3000);  // wait till time or 30 deegrees
 }
diff --git a/main/experiment_early_entry.cpp b/main/experiment_early_entry.cpp
new file mode 100644
index 0000000..a0f6012
--- /dev/null
+++ b/main/experiment_early_entry.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * Early app_main capture for deep-sleep prepared experiments.
+ */
+
+#include "experiment_early_entry.h"
+
+#if defined(ESP_PLATFORM) && \
+    (defined(AE_EXP_PREPARED_DEEPSLEEP_5X50) || \
+     defined(AE_EXP_PREPARED_TX_DONE_DIAG) || \
+     defined(AE_EXP_PREPARED_MAC_RETRY_DIAG) || \
+     defined(AE_EXP_PREPARED_BOOT_WIFI_OPT) || \
+     defined(AE_EXP_PREPARED_BOOT_WIFI_VAL100))
+
+#  include 
+#  include 
+#  include 
+
+extern "C" std::uint64_t esp_rtc_get_time_us(void);
+
+namespace {
+ExperimentEarlyEntrySnapshot g_early{};
+}
+
+extern "C" void ExperimentEarlyAppEntry() {
+  g_early.app_entry_esp_timer_us = esp_timer_get_time();
+  g_early.app_entry_rtc_us = esp_rtc_get_time_us();
+  g_early.reset_reason = static_cast(esp_reset_reason());
+  g_early.wakeup_cause =
+      static_cast(esp_sleep_get_wakeup_cause());
+  g_early.valid = 1;
+}
+
+ExperimentEarlyEntrySnapshot const& GetExperimentEarlyEntrySnapshot() {
+  return g_early;
+}
+
+#endif
diff --git a/main/experiment_early_entry.h b/main/experiment_early_entry.h
new file mode 100644
index 0000000..c2a069a
--- /dev/null
+++ b/main/experiment_early_entry.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * First-instruction app_main hook for deep-sleep timing experiments.
+ * No heap, no logging, no formatting.
+ */
+
+#ifndef TEMP_SENSOR_EXPERIMENT_EARLY_ENTRY_H_
+#define TEMP_SENSOR_EXPERIMENT_EARLY_ENTRY_H_
+
+#include 
+
+struct ExperimentEarlyEntrySnapshot {
+  std::int64_t app_entry_esp_timer_us{0};
+  std::uint64_t app_entry_rtc_us{0};
+  std::uint8_t reset_reason{0};
+  std::uint8_t wakeup_cause{0};
+  std::uint8_t valid{0};
+};
+
+#if defined(ESP_PLATFORM) && \
+    (defined(AE_EXP_PREPARED_DEEPSLEEP_5X50) || \
+     defined(AE_EXP_PREPARED_TX_DONE_DIAG) || \
+     defined(AE_EXP_PREPARED_MAC_RETRY_DIAG) || \
+     defined(AE_EXP_PREPARED_BOOT_WIFI_OPT) || \
+     defined(AE_EXP_PREPARED_BOOT_WIFI_VAL100))
+extern "C" void ExperimentEarlyAppEntry();
+ExperimentEarlyEntrySnapshot const& GetExperimentEarlyEntrySnapshot();
+#else
+inline void ExperimentEarlyAppEntry() {}
+inline ExperimentEarlyEntrySnapshot const& GetExperimentEarlyEntrySnapshot() {
+  static ExperimentEarlyEntrySnapshot empty{};
+  return empty;
+}
+#endif
+#endif  // TEMP_SENSOR_EXPERIMENT_EARLY_ENTRY_H_
diff --git a/main/main.cpp b/main/main.cpp
index ef245cd..fa6deb7 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -20,11 +20,15 @@
 #  include 
 #endif
 
+#include "experiment_early_entry.h"
+
 extern void setup();
 extern void loop();
 
 #if defined ESP_PLATFORM
 extern "C" void app_main(void) {
+  ExperimentEarlyAppEntry();
+
   esp_task_wdt_config_t config_wdt = {
       /*.timeout_ms = */ 60000,
       /*.idle_core_mask = */ 0,  // i.e. do not watch any idle task
diff --git a/main/prepared_boot_wifi_opt_bench.cpp b/main/prepared_boot_wifi_opt_bench.cpp
new file mode 100644
index 0000000..be64055
--- /dev/null
+++ b/main/prepared_boot_wifi_opt_bench.cpp
@@ -0,0 +1,1013 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * Silent boot / Wi-Fi HOT-path optimization campaign (ESP32-C6).
+ * Runtime variants D/G/H/E x 30 HOT; FULL between variants; 3 s deep sleep.
+ * Compile-time A/B/C documented in report (one-flash campaign).
+ * Metrics travel in BootWifiOptPayload 0xD8; UART is silent.
+ */
+
+#include 
+#include 
+#include 
+
+#include "aether/all.h"
+#include "aether/ae_exp_wifi.h"
+#include "aether/config.h"
+#include "aether/env.h"
+#include "bench_payload.h"
+#include "experiment_early_entry.h"
+#include "prepared_send/prepared_send.h"
+
+#if defined(ESP_PLATFORM)
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#endif
+
+using namespace std::chrono_literals;
+
+#if defined(ESP_PLATFORM)
+extern "C" std::uint64_t esp_rtc_get_time_us(void);
+#endif
+
+namespace temp_sensor {
+namespace {
+
+static constexpr auto kParentUid =
+    ae::Uid::FromString("b1ac52c8-8d94-bd39-4c01-a631ac594165");
+
+#ifndef BENCH_CLIENT_ID
+#  define BENCH_CLIENT_ID "prepared_deepsleep_5x50_v1"
+#endif
+static constexpr char const* kBenchClientId = BENCH_CLIENT_ID;
+
+#if defined(SERVICE_UID)
+static constexpr auto kServiceUid = ae::Uid::FromString(SERVICE_UID);
+#else
+static constexpr auto kServiceUid =
+    ae::Uid::FromString("5aade50f-00d9-4624-b097-e203cdcf1e38");
+#endif
+
+static constexpr std::uint8_t kVariantCount = 11;
+static constexpr std::uint8_t kHotPerVariant = 30;
+static constexpr std::uint8_t kMaxHotAttempts = 40;
+static constexpr std::uint32_t kSleepUs = 3000000;
+static constexpr std::uint32_t kRtcMagic = 0x42574F31u;  // "BWO1"
+static constexpr std::uint16_t kRtcVersion = 1;
+
+enum class Phase : std::uint16_t {
+  kRegister = 0,
+  kFull = 1,
+  kHot = 2,
+  kFinal = 3,
+  kDone = 4,
+};
+
+struct VariantCfg {
+  bool storage_ram;
+  bool nvs_enable;
+  bool force_ht20;
+  std::int8_t dynamic_cs;  // -1 default, 0 off, 1 on
+  std::uint8_t static_rx;
+  std::uint8_t dynamic_rx;
+  std::uint8_t dynamic_tx;
+};
+
+static constexpr VariantCfg kVariants[kVariantCount] = {
+    {false, true, false, -1, 0, 0, 0},   // D0
+    {true, true, false, -1, 0, 0, 0},    // D1
+    {false, false, false, -1, 0, 0, 0},  // D2
+    {true, false, false, -1, 0, 0, 0},   // D3
+    {false, true, true, -1, 0, 0, 0},    // G1
+    {false, true, false, 0, 0, 0, 0},    // H1
+    {false, true, false, 1, 0, 0, 0},    // H2
+    {false, true, false, -1, 0, 0, 16},  // E1 TX half (32->16)
+    {false, true, false, -1, 0, 0, 8},   // E2 TX min-ish
+    {false, true, false, -1, 5, 16, 0},  // E3 RX half
+    {false, true, false, -1, 3, 8, 0},   // E4 RX min-ish
+};
+
+struct RtcState {
+  std::uint32_t magic;
+  std::uint16_t version;
+  std::uint16_t phase;
+  std::uint8_t variant_id;
+  std::uint8_t hot_index;
+  std::uint8_t hot_attempt_count;
+  std::uint8_t hot_send_count;
+  std::uint16_t sequence_global;
+  std::uint16_t next_record_id;
+  std::uint32_t requested_sleep_us;
+  std::uint64_t sleep_arm_rtc_us;
+  std::uint8_t pending_valid;
+  std::uint8_t pending_kind;
+  std::uint8_t pending_variant;
+  std::uint8_t pending_hot_index;
+  std::uint32_t pending_user_cycle_us;
+  std::uint32_t pending_wifi_cycle_us;
+  std::uint32_t pending_wifi_init_us;
+  std::uint32_t pending_connect_us;
+  std::uint32_t pending_encode_us;
+  std::uint32_t pending_txdone_us;
+  std::uint32_t pending_teardown_us;
+  std::uint32_t pending_heap_before;
+  std::uint32_t pending_heap_after;
+  std::uint8_t pending_cb_seen;
+  std::uint8_t pending_cb_timeout;
+  std::uint8_t pending_auth;
+  std::uint8_t brownout_count;
+  std::uint8_t unexpected_reset_count;
+  std::uint8_t current_boot_brownout;
+  std::uint8_t registered;
+  std::uint8_t final_fail_count;
+  std::uint8_t var_tx_success;
+  std::uint8_t var_tx_fail;
+  std::uint8_t var_cb_timeout;
+  std::uint8_t pad0;
+  std::uint32_t var_txdone_sum_us;
+  std::uint8_t prev_variant_id;
+  std::uint8_t prev_hot_send_count;
+  std::uint8_t prev_hot_attempt_count;
+  std::uint8_t prev_tx_success_count;
+  std::uint8_t prev_tx_fail_count;
+  std::uint8_t prev_cb_timeout_count;
+  std::uint32_t prev_txdone_sum_us;
+  std::uint32_t crc;
+};
+
+struct PendingDiag {
+  std::uint8_t valid{0};
+  std::uint8_t tx_cb_total{0};
+  std::uint8_t tx_cb_success{0};
+  std::uint8_t tx_cb_failed{0};
+  std::uint8_t first_status{0xff};
+  std::uint8_t cb_timeout{0};
+  std::uint8_t disconnect_count{0};
+  std::uint8_t reconnect_count{0};
+  std::int8_t rssi{0};
+  std::uint8_t actual_channel{0};
+};
+
+#if defined(ESP_PLATFORM)
+RTC_DATA_ATTR static RtcState g_rtc{};
+RTC_DATA_ATTR static prepared_send::PreparedWifiRtcCache g_rtc_wifi_cache{};
+RTC_DATA_ATTR static PendingDiag g_pending_diag{};
+
+static const auto kWifiInit = ae::WiFiInit{
+    std::vector{{ae::WifiCreds{WIFI_SSID, WIFI_PASSWORD}, {}}},
+    {},
+};
+
+static bool g_had_aether_app = false;
+static std::shared_ptr g_app;
+static ae::Client::ptr g_client;
+static std::unique_ptr g_stream;
+static ae::Subscription g_select_sub;
+static ae::Subscription g_stream_sub;
+static ae::Subscription g_write_sub;
+
+static bool g_write_armed = false;
+static bool g_write_ok = false;
+static bool g_exit_success = false;
+static bool g_pending_register_finish = false;
+static bool g_pending_full_post_write = false;
+static bool g_pending_final_exit = false;
+static bool g_done = false;
+
+static ExperimentEarlyEntrySnapshot g_early{};
+static std::uint32_t g_sleep_elapsed_us = 0;
+static std::uint32_t g_sleep_overhead_us = 0;
+static prepared_send::FastPathConfig g_cfg{};
+static prepared_send::BisectWifiCacheSnapshot g_wifi_snapshot{};
+
+static std::uint32_t Crc32Bytes(void const* data, std::size_t len) {
+  auto const* p = static_cast(data);
+  std::uint32_t crc = 0xffffffffu;
+  for (std::size_t i = 0; i < len; ++i) {
+    crc ^= p[i];
+    for (int b = 0; b < 8; ++b) {
+      std::uint32_t const mask = -(crc & 1u);
+      crc = (crc >> 1) ^ (0xedb88320u & mask);
+    }
+  }
+  return ~crc;
+}
+
+static std::uint32_t ComputeCrc(RtcState const& st) {
+  RtcState tmp = st;
+  tmp.crc = 0;
+  return Crc32Bytes(&tmp, sizeof(tmp));
+}
+
+static void SetCrc(RtcState& st) { st.crc = ComputeCrc(st); }
+
+static bool ValidateRtcState(RtcState const& st) {
+  if (st.magic != kRtcMagic || st.version != kRtcVersion) {
+    return false;
+  }
+  if (ComputeCrc(st) != st.crc) {
+    return false;
+  }
+  if (st.phase > static_cast(Phase::kDone)) {
+    return false;
+  }
+  if (st.variant_id >= kVariantCount &&
+      st.phase != static_cast(Phase::kFinal) &&
+      st.phase != static_cast(Phase::kDone)) {
+    return false;
+  }
+  if (st.hot_index > kHotPerVariant) {
+    return false;
+  }
+  return true;
+}
+
+static void ClearPending(RtcState& st) {
+  st.pending_valid = 0;
+  st.pending_kind = 0;
+  st.pending_variant = 0;
+  st.pending_hot_index = 0;
+  st.pending_user_cycle_us = 0;
+  st.pending_wifi_cycle_us = 0;
+  st.pending_wifi_init_us = 0;
+  st.pending_connect_us = 0;
+  st.pending_encode_us = 0;
+  st.pending_txdone_us = 0;
+  st.pending_teardown_us = 0;
+  st.pending_heap_before = 0;
+  st.pending_heap_after = 0;
+  st.pending_cb_seen = 0;
+  st.pending_cb_timeout = 0;
+  st.pending_auth = 0;
+  g_pending_diag = PendingDiag{};
+}
+
+static void InitRtcFresh(Phase phase) {
+  g_rtc = RtcState{};
+  g_rtc.magic = kRtcMagic;
+  g_rtc.version = kRtcVersion;
+  g_rtc.phase = static_cast(phase);
+  g_rtc.variant_id = 0;
+  g_rtc.hot_index = 1;
+  g_rtc.next_record_id = 1;
+  g_rtc.prev_variant_id = 0xff;
+  ClearPending(g_rtc);
+  SetCrc(g_rtc);
+}
+
+[[noreturn]] static void PrepareRtcStateAndDeepSleep(std::uint32_t requested_us) {
+  g_rtc.requested_sleep_us = requested_us;
+  esp_sleep_enable_timer_wakeup(requested_us);
+  g_rtc.sleep_arm_rtc_us = esp_rtc_get_time_us();
+  SetCrc(g_rtc);
+#  if SOC_PM_SUPPORT_RTC_SLOW_MEM_PD
+  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON);
+#  endif
+#  if SOC_PM_SUPPORT_RTC_FAST_MEM_PD
+  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_ON);
+#  endif
+  (void)esp_deep_sleep_try_to_start();
+  esp_deep_sleep_start();
+  for (;;) {
+  }
+}
+
+static void ForceFullRecovery() {
+  ClearPending(g_rtc);
+  g_rtc.phase = static_cast(Phase::kFull);
+  if (g_rtc.variant_id >= kVariantCount) {
+    g_rtc.variant_id = 0;
+  }
+  g_rtc.hot_index = 1;
+  g_rtc.hot_attempt_count = 0;
+  g_rtc.hot_send_count = 0;
+  g_rtc.var_tx_success = 0;
+  g_rtc.var_tx_fail = 0;
+  g_rtc.var_cb_timeout = 0;
+  g_rtc.var_txdone_sum_us = 0;
+  SetCrc(g_rtc);
+}
+
+static void SnapshotPrevVariant() {
+  g_rtc.prev_variant_id = g_rtc.variant_id;
+  g_rtc.prev_hot_send_count = g_rtc.hot_send_count;
+  g_rtc.prev_hot_attempt_count = g_rtc.hot_attempt_count;
+  g_rtc.prev_tx_success_count = g_rtc.var_tx_success;
+  g_rtc.prev_tx_fail_count = g_rtc.var_tx_fail;
+  g_rtc.prev_cb_timeout_count = g_rtc.var_cb_timeout;
+  g_rtc.prev_txdone_sum_us = g_rtc.var_txdone_sum_us;
+}
+
+static void AdvanceToNextVariantOrFinal() {
+  SnapshotPrevVariant();
+  if (g_rtc.variant_id + 1 < kVariantCount) {
+    ++g_rtc.variant_id;
+    g_rtc.phase = static_cast(Phase::kFull);
+    g_rtc.hot_index = 1;
+    g_rtc.hot_attempt_count = 0;
+    g_rtc.hot_send_count = 0;
+    g_rtc.var_tx_success = 0;
+    g_rtc.var_tx_fail = 0;
+    g_rtc.var_cb_timeout = 0;
+    g_rtc.var_txdone_sum_us = 0;
+  } else {
+    g_rtc.phase = static_cast(Phase::kFinal);
+    g_rtc.hot_index = 1;
+  }
+  SetCrc(g_rtc);
+}
+
+static std::uint16_t NextSeq() {
+  ++g_rtc.sequence_global;
+  return g_rtc.sequence_global;
+}
+
+static void AdvanceRecordIdAfterFlush() {
+  if (g_rtc.next_record_id < 0xffffu) {
+    ++g_rtc.next_record_id;
+  }
+}
+
+static VariantCfg const& CurrentVariant() {
+  auto id = g_rtc.variant_id;
+  if (id >= kVariantCount) {
+    id = 0;
+  }
+  return kVariants[id];
+}
+
+static std::uint8_t SettingFlags(VariantCfg const& v) {
+  std::uint8_t f = 0;
+  if (v.storage_ram) {
+    f |= 1;
+  }
+  if (!v.nvs_enable) {
+    f |= 2;
+  }
+  if (v.force_ht20) {
+    f |= 4;
+  }
+  if (v.dynamic_cs == 0) {
+    f |= 8;
+  }
+  if (v.dynamic_cs == 1) {
+    f |= 16;
+  }
+  if (v.dynamic_tx != 0) {
+    f |= 32;
+  }
+  if (v.static_rx != 0 || v.dynamic_rx != 0) {
+    f |= 64;
+  }
+  return f;
+}
+
+static ae::DataBuffer MakePayload(bench::BootWifiOptMsgType type) {
+  bench::BootWifiOptPayload p{};
+  p.type = static_cast(type);
+  p.variant_id = g_rtc.variant_id;
+  p.hot_index = g_rtc.hot_index;
+  p.sequence_global = NextSeq();
+  p.record_id = g_rtc.pending_valid ? g_rtc.next_record_id : 0;
+  auto const& v = CurrentVariant();
+  p.reset_reason = g_early.reset_reason;
+  p.wake_cause = g_early.wakeup_cause;
+  p.brownout_count = g_rtc.brownout_count;
+  p.sleep_elapsed_to_app_us = g_sleep_elapsed_us;
+  p.sleep_to_app_overhead_us = g_sleep_overhead_us;
+  p.app_entry_esp_timer_us = g_early.app_entry_esp_timer_us;
+  p.setting_flags = SettingFlags(v);
+  p.static_rx_buf = v.static_rx;
+  p.dynamic_rx_buf = v.dynamic_rx;
+  p.dynamic_tx_buf = v.dynamic_tx;
+  p.dynamic_cs = v.dynamic_cs;
+  std::uint8_t flags = 0;
+  if (g_rtc.current_boot_brownout) {
+    flags |= 1;
+  }
+  if (g_rtc.pending_cb_seen) {
+    flags |= 2;
+  }
+  if (g_rtc.pending_cb_timeout) {
+    flags |= 4;
+  }
+  p.flags = flags;
+  p.prev_variant_id = g_rtc.prev_variant_id;
+  p.prev_hot_send_count = g_rtc.prev_hot_send_count;
+  p.prev_hot_attempt_count = g_rtc.prev_hot_attempt_count;
+  p.prev_tx_success_count = g_rtc.prev_tx_success_count;
+  p.prev_tx_fail_count = g_rtc.prev_tx_fail_count;
+  p.prev_cb_timeout_count = g_rtc.prev_cb_timeout_count;
+  p.prev_txdone_sum_us = g_rtc.prev_txdone_sum_us;
+  p.prepared_message_left = static_cast(
+      prepared_send::PreparedMessageLeft() > 0xffffu
+          ? 0xffffu
+          : prepared_send::PreparedMessageLeft());
+
+  if (g_rtc.pending_valid) {
+    p.pending_kind = g_rtc.pending_kind;
+    p.pending_variant = g_rtc.pending_variant;
+    p.pending_hot_index = g_rtc.pending_hot_index;
+    p.pending_user_cycle_us = g_rtc.pending_user_cycle_us;
+    p.pending_wifi_cycle_us = g_rtc.pending_wifi_cycle_us;
+    p.wifi_init_us = g_rtc.pending_wifi_init_us;
+    p.connect_us = g_rtc.pending_connect_us;
+    p.encode_send_us = g_rtc.pending_encode_us;
+    p.tx_done_wait_us = g_rtc.pending_txdone_us;
+    p.teardown_us = g_rtc.pending_teardown_us;
+    p.heap_before_wifi = g_rtc.pending_heap_before;
+    p.heap_after_wifi = g_rtc.pending_heap_after;
+    p.authmode = g_rtc.pending_auth;
+    if (g_pending_diag.valid) {
+      p.tx_cb_total = g_pending_diag.tx_cb_total;
+      p.tx_cb_success = g_pending_diag.tx_cb_success;
+      p.tx_cb_failed = g_pending_diag.tx_cb_failed;
+      p.first_status = g_pending_diag.first_status;
+      p.cb_timeout = g_pending_diag.cb_timeout;
+      p.rssi = g_pending_diag.rssi;
+      p.actual_channel = g_pending_diag.actual_channel;
+      p.disconnect_count = g_pending_diag.disconnect_count;
+      p.reconnect_count = g_pending_diag.reconnect_count;
+    }
+  }
+  return bench::EncodeBootWifiOpt(p);
+}
+
+static std::uint32_t UserCycleFromAppEntry() {
+  auto const now = esp_timer_get_time();
+  auto const entry = g_early.app_entry_esp_timer_us;
+  if (now < entry) {
+    return 0;
+  }
+  auto const delta = now - entry;
+  return delta > 0xffffffffll ? 0xffffffffu
+                              : static_cast(delta);
+}
+
+static void StorePendingHot(prepared_send::FastSendResult const& result,
+                            std::uint32_t user_cycle_us) {
+  g_rtc.pending_valid = 1;
+  g_rtc.pending_kind = 2;
+  g_rtc.pending_variant = g_rtc.variant_id;
+  g_rtc.pending_hot_index = g_rtc.hot_index;
+  g_rtc.pending_user_cycle_us = user_cycle_us;
+  g_rtc.pending_wifi_cycle_us = result.cycle_us;
+  g_rtc.pending_wifi_init_us = result.wifi_init_us;
+  g_rtc.pending_connect_us = result.connect_us;
+  g_rtc.pending_encode_us = result.encode_send_us;
+  g_rtc.pending_txdone_us = result.tx_done_wait_us;
+  g_rtc.pending_teardown_us = result.teardown_us;
+  g_rtc.pending_heap_before = result.heap_before_wifi;
+  g_rtc.pending_heap_after = result.heap_after_wifi;
+  g_rtc.pending_cb_seen = result.cb_any;
+  g_rtc.pending_cb_timeout = result.cb_timeout;
+  g_rtc.pending_auth = result.negotiated_auth;
+  g_pending_diag = PendingDiag{};
+  g_pending_diag.valid = 1;
+  g_pending_diag.tx_cb_total = result.tx_cb_total;
+  g_pending_diag.tx_cb_success = result.tx_cb_success;
+  g_pending_diag.tx_cb_failed = result.tx_cb_failed;
+  g_pending_diag.first_status = result.first_status;
+  g_pending_diag.cb_timeout = result.cb_timeout;
+  g_pending_diag.rssi = result.rssi;
+  g_pending_diag.actual_channel = result.actual_channel;
+  g_pending_diag.disconnect_count = result.disconnect_count;
+  g_pending_diag.reconnect_count = result.reconnect_count;
+}
+
+static void StorePendingFull(std::uint32_t user_cycle_us) {
+  g_rtc.pending_valid = 1;
+  g_rtc.pending_kind = 1;
+  g_rtc.pending_variant = g_rtc.variant_id;
+  g_rtc.pending_hot_index = 0;
+  g_rtc.pending_user_cycle_us = user_cycle_us;
+  g_rtc.pending_wifi_cycle_us = user_cycle_us;
+  g_pending_diag = PendingDiag{};
+}
+
+static void ReleaseApp() {
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  g_app.reset();
+}
+
+static void PreConstructCleanup() {
+  if (!g_had_aether_app) {
+    return;
+  }
+#  if !AE_WIFI_USE_FULL_DEINIT
+  esp_netif_deinit();
+  esp_event_loop_delete_default();
+#  endif
+}
+
+static void ConstructAether() {
+  PreConstructCleanup();
+  g_had_aether_app = true;
+  g_app = ae::AetherApp::Construct(
+      ae::AetherAppContext{}
+#  if AE_DISTILLATION
+          .AddAdapterFactory([&](ae::AetherAppContext const& ctx) {
+            return ae::WifiAdapter::ptr::Create(
+                ae::CreateWith{ctx.domain()}.with_id(
+                    ae::GlobalId::kWiFiAdapter),
+                ctx.aether(), ctx.poller(), ctx.dns_resolver(), kWifiInit);
+          })
+#  endif
+  );
+}
+
+static prepared_send::FastPathConfig MakeFastConfig() {
+  prepared_send::FastPathConfig c{};
+  c.use_bssid = false;
+  c.use_channel = true;
+  c.use_fast_scan = false;
+  c.use_static_ip = true;
+  c.use_static_arp = true;
+  c.ampdu_tx_off = false;
+  c.ampdu_rx_off = false;
+  c.amsdu_tx_off = false;
+  c.auth = prepared_send::FastAuthMode::kWpa2;
+  c.retry_max = 10;
+  c.pre_delay_ms = 25;
+  c.post_delay_ms = 0;
+  c.post_mode = prepared_send::FastPostMode::kTxDoneCb;
+  c.tx_done_wait = prepared_send::FastTxDoneWaitMode::kFirstAny;
+  c.set_mac_retry_limit = false;
+  auto const& v = CurrentVariant();
+  c.wifi_storage_ram = v.storage_ram;
+  c.wifi_nvs_enable = v.nvs_enable;
+  c.force_ht20 = v.force_ht20;
+  c.dynamic_cs = v.dynamic_cs;
+  c.static_rx_buf_num = v.static_rx;
+  c.dynamic_rx_buf_num = v.dynamic_rx;
+  c.dynamic_tx_buf_num = v.dynamic_tx;
+  return c;
+}
+
+static void DoFullWrite() {
+  if (g_write_armed) {
+    return;
+  }
+  g_write_armed = true;
+  auto payload = MakePayload(bench::BootWifiOptMsgType::kFull);
+  auto& wa = g_stream->Write(std::move(payload));
+  g_write_sub = wa.status_event().Subscribe([](ae::WriteAction::Status st) {
+    g_write_ok = (st == ae::WriteAction::Status::kSuccess);
+    g_pending_full_post_write = true;
+  });
+}
+
+static void MaybeFullWrite() {
+  if (!g_stream || g_write_armed) {
+    return;
+  }
+  if (!g_stream->stream_info().is_writable) {
+    return;
+  }
+  DoFullWrite();
+}
+
+static void OnFullClientReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  auto client = g_client.Load();
+  g_stream = std::make_unique(*g_app, client, kServiceUid,
+                                             ae::P2pPortHandle{});
+  g_stream_sub =
+      g_stream->stream_update_event().Subscribe([]() { MaybeFullWrite(); });
+  MaybeFullWrite();
+}
+
+static void StartRegister() {
+  g_write_armed = false;
+  g_pending_register_finish = false;
+  g_exit_success = false;
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       g_client = std::move(res).value();
+                       g_pending_register_finish = true;
+                     });
+}
+
+static void StartFull() {
+  g_write_armed = false;
+  g_write_ok = false;
+  g_pending_full_post_write = false;
+  g_exit_success = false;
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnFullClientReady(std::move(res).value());
+                     });
+}
+
+static void StartFinal() {
+  g_write_armed = false;
+  g_write_ok = false;
+  g_pending_final_exit = false;
+  g_exit_success = false;
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       g_client = std::move(res).value();
+                       auto client = g_client.Load();
+                       g_stream = std::make_unique(
+                           *g_app, client, kServiceUid, ae::P2pPortHandle{});
+                       g_stream_sub = g_stream->stream_update_event().Subscribe(
+                           []() {
+                             if (!g_stream || g_write_armed) {
+                               return;
+                             }
+                             if (!g_stream->stream_info().is_writable) {
+                               return;
+                             }
+                             g_write_armed = true;
+                             auto& wa = g_stream->Write(
+                                 MakePayload(bench::BootWifiOptMsgType::kFinal));
+                             g_write_sub = wa.status_event().Subscribe(
+                                 [](ae::WriteAction::Status st) {
+                                   g_write_ok =
+                                       (st == ae::WriteAction::Status::kSuccess);
+                                   g_pending_final_exit = true;
+                                 });
+                           });
+                     });
+}
+
+static void FinishRegisterInLoop() {
+  auto client = g_client.Load();
+  if (!client) {
+    g_app->Exit(1);
+    return;
+  }
+  g_app->aether().Save();
+  g_exit_success = true;
+  g_app->Exit(0);
+}
+
+static void FinishFullPostWriteInLoop() {
+  if (!g_write_ok) {
+    g_app->Exit(1);
+    return;
+  }
+  bool captured = false;
+  for (int i = 0; i < 10 && !captured; ++i) {
+    captured = prepared_send::CapturePreparedWifiRtcCache(&g_rtc_wifi_cache);
+    if (!captured) {
+      vTaskDelay(pdMS_TO_TICKS(200));
+    }
+  }
+  bool exported = false;
+  for (std::size_t n : {std::size_t{40}, std::size_t{35}, std::size_t{30}}) {
+    if (prepared_send::ExportPreparedSendBlock(g_client, kServiceUid, n)) {
+      exported = true;
+      break;
+    }
+  }
+  if (!exported || !captured || !prepared_send::HasPreparedSendBlock() ||
+      prepared_send::PreparedMessageLeft() == 0) {
+    g_app->Exit(1);
+    return;
+  }
+  g_exit_success = true;
+  g_app->Exit(0);
+}
+
+static void FinishFinalInLoop() {
+  if (!g_write_ok) {
+    g_app->Exit(1);
+    return;
+  }
+  g_exit_success = true;
+  g_app->Exit(0);
+}
+
+static void AfterRegisterComplete() {
+  ReleaseApp();
+  g_rtc.registered = 1;
+  g_rtc.phase = static_cast(Phase::kFull);
+  g_rtc.variant_id = 0;
+  g_rtc.hot_index = 1;
+  ClearPending(g_rtc);
+  SetCrc(g_rtc);
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void AfterFullComplete() {
+  ReleaseApp();
+  prepared_send::ReleaseFullAetherWifiForHotPath();
+  if (g_rtc.pending_valid) {
+    AdvanceRecordIdAfterFlush();
+  }
+  StorePendingFull(UserCycleFromAppEntry());
+  g_rtc.phase = static_cast(Phase::kHot);
+  g_rtc.hot_index = 1;
+  g_rtc.hot_attempt_count = 0;
+  g_rtc.hot_send_count = 0;
+  g_rtc.var_tx_success = 0;
+  g_rtc.var_tx_fail = 0;
+  g_rtc.var_cb_timeout = 0;
+  g_rtc.var_txdone_sum_us = 0;
+  SetCrc(g_rtc);
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void AfterFinalComplete() {
+  ReleaseApp();
+  if (g_rtc.pending_valid) {
+    AdvanceRecordIdAfterFlush();
+  }
+  ClearPending(g_rtc);
+  g_rtc.phase = static_cast(Phase::kDone);
+  SetCrc(g_rtc);
+  g_done = true;
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void AfterFinalFailed() {
+  ReleaseApp();
+  if (g_rtc.final_fail_count < 255) {
+    ++g_rtc.final_fail_count;
+  }
+  if (g_rtc.final_fail_count >= 3) {
+    ClearPending(g_rtc);
+    g_rtc.phase = static_cast(Phase::kDone);
+    SetCrc(g_rtc);
+    g_done = true;
+  }
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void RunHotOnce() {
+  if (!prepared_send::PreparedWifiRtcCacheIsValid(g_rtc_wifi_cache) ||
+      !prepared_send::HasPreparedSendBlock() ||
+      prepared_send::PreparedMessageLeft() == 0) {
+    ForceFullRecovery();
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  if (g_rtc.hot_attempt_count >= kMaxHotAttempts) {
+    AdvanceToNextVariantOrFinal();
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  if (g_rtc.hot_attempt_count < 255) {
+    ++g_rtc.hot_attempt_count;
+  }
+  SetCrc(g_rtc);
+
+  g_cfg = MakeFastConfig();
+  g_wifi_snapshot =
+      prepared_send::SnapshotFromPreparedWifiRtcCache(g_rtc_wifi_cache);
+  auto payload = MakePayload(bench::BootWifiOptMsgType::kHot);
+  auto const result =
+      prepared_send::SendPreparedOnceWithFastPath(g_cfg, payload,
+                                                    &g_wifi_snapshot);
+
+  if (result.status == prepared_send::HotSendStatus::kWifiFailed) {
+    SetCrc(g_rtc);
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  if (result.status != prepared_send::HotSendStatus::kSent) {
+    SetCrc(g_rtc);
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  auto const user_cycle = UserCycleFromAppEntry();
+  bool const flushed_prior = g_rtc.pending_valid != 0;
+  StorePendingHot(result, user_cycle);
+  if (flushed_prior) {
+    AdvanceRecordIdAfterFlush();
+  }
+
+  if (g_rtc.hot_send_count < 255) {
+    ++g_rtc.hot_send_count;
+  }
+  if (result.first_status == 1) {
+    if (g_rtc.var_tx_success < 255) {
+      ++g_rtc.var_tx_success;
+    }
+  } else if (result.first_status == 0) {
+    if (g_rtc.var_tx_fail < 255) {
+      ++g_rtc.var_tx_fail;
+    }
+  }
+  if (result.cb_timeout) {
+    if (g_rtc.var_cb_timeout < 255) {
+      ++g_rtc.var_cb_timeout;
+    }
+  }
+  g_rtc.var_txdone_sum_us += result.tx_done_wait_us;
+
+  if (g_rtc.hot_index < 255) {
+    ++g_rtc.hot_index;
+  }
+
+  if (g_rtc.hot_send_count >= kHotPerVariant ||
+      g_rtc.hot_attempt_count >= kMaxHotAttempts) {
+    AdvanceToNextVariantOrFinal();
+  }
+  SetCrc(g_rtc);
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void PrepareRtcOnBoot() {
+  g_early = GetExperimentEarlyEntrySnapshot();
+  g_sleep_elapsed_us = 0;
+  g_sleep_overhead_us = 0;
+  if (g_early.valid && g_rtc.sleep_arm_rtc_us != 0 &&
+      g_early.app_entry_rtc_us >= g_rtc.sleep_arm_rtc_us) {
+    auto const elapsed = g_early.app_entry_rtc_us - g_rtc.sleep_arm_rtc_us;
+    g_sleep_elapsed_us =
+        elapsed > 0xffffffffull ? 0xffffffffu : static_cast(elapsed);
+    if (g_sleep_elapsed_us > g_rtc.requested_sleep_us) {
+      g_sleep_overhead_us = g_sleep_elapsed_us - g_rtc.requested_sleep_us;
+    }
+  }
+
+  auto const reset =
+      static_cast(g_early.reset_reason);
+  bool const valid = ValidateRtcState(g_rtc);
+  g_rtc.current_boot_brownout = 0;
+
+  if (reset == ESP_RST_BROWNOUT) {
+    if (valid) {
+      if (g_rtc.brownout_count < 255) {
+        ++g_rtc.brownout_count;
+      }
+      ClearPending(g_rtc);
+    } else {
+      InitRtcFresh(Phase::kFull);
+      g_rtc.brownout_count = 1;
+    }
+    g_rtc.current_boot_brownout = 1;
+    ForceFullRecovery();
+  } else if (!g_early.valid || reset != ESP_RST_DEEPSLEEP || !valid) {
+    bool const first_poweron = (reset == ESP_RST_POWERON);
+    if (first_poweron && (!valid || !g_rtc.registered)) {
+      InitRtcFresh(Phase::kRegister);
+    } else if (!valid) {
+      InitRtcFresh(Phase::kFull);
+      g_rtc.registered = 1;
+      SetCrc(g_rtc);
+    } else {
+      if (g_rtc.unexpected_reset_count < 255) {
+        ++g_rtc.unexpected_reset_count;
+      }
+      ForceFullRecovery();
+    }
+  }
+  SetCrc(g_rtc);
+}
+
+#endif  // ESP_PLATFORM
+
+}  // namespace
+}  // namespace temp_sensor
+
+#if defined(ESP_PLATFORM)
+
+void setup() {
+  using namespace temp_sensor;
+  nvs_flash_init();
+  g_done = false;
+  g_pending_register_finish = false;
+  g_pending_full_post_write = false;
+  g_pending_final_exit = false;
+  PrepareRtcOnBoot();
+  g_cfg = MakeFastConfig();
+
+  auto const phase = static_cast(g_rtc.phase);
+  if (phase == Phase::kDone) {
+    g_done = true;
+    return;
+  }
+  if (phase == Phase::kRegister) {
+    StartRegister();
+    return;
+  }
+  if (phase == Phase::kFull) {
+    StartFull();
+    return;
+  }
+  if (phase == Phase::kFinal) {
+    StartFinal();
+    return;
+  }
+}
+
+void loop() {
+  using namespace temp_sensor;
+  if (g_done) {
+    vTaskDelay(pdMS_TO_TICKS(1000));
+    return;
+  }
+
+  auto const phase = static_cast(g_rtc.phase);
+  if (phase == Phase::kHot) {
+    RunHotOnce();
+    return;
+  }
+
+  auto process_deferred = []() {
+    if (g_app && g_pending_register_finish) {
+      g_pending_register_finish = false;
+      FinishRegisterInLoop();
+      return true;
+    }
+    if (g_app && g_pending_full_post_write) {
+      g_pending_full_post_write = false;
+      FinishFullPostWriteInLoop();
+      return true;
+    }
+    if (g_app && g_pending_final_exit) {
+      g_pending_final_exit = false;
+      FinishFinalInLoop();
+      return true;
+    }
+    return false;
+  };
+
+  if (process_deferred()) {
+    return;
+  }
+  if (!g_app) {
+    return;
+  }
+  if (!g_app->IsExited()) {
+    auto t = g_app->Update(ae::Now());
+    if (process_deferred()) {
+      return;
+    }
+    if (!g_app->IsExited()) {
+      g_app->WaitUntil(t);
+    }
+    return;
+  }
+
+  if (phase == Phase::kRegister) {
+    if (g_exit_success) {
+      AfterRegisterComplete();
+    } else {
+      ReleaseApp();
+      PrepareRtcStateAndDeepSleep(kSleepUs);
+    }
+    return;
+  }
+  if (phase == Phase::kFull) {
+    if (g_exit_success) {
+      AfterFullComplete();
+    } else {
+      ReleaseApp();
+      ForceFullRecovery();
+      PrepareRtcStateAndDeepSleep(kSleepUs);
+    }
+    return;
+  }
+  if (phase == Phase::kFinal) {
+    if (g_exit_success) {
+      AfterFinalComplete();
+    } else {
+      AfterFinalFailed();
+    }
+    return;
+  }
+}
+
+#else
+
+void setup() {}
+void loop() {}
+
+#endif
diff --git a/main/prepared_boot_wifi_val100_bench.cpp b/main/prepared_boot_wifi_val100_bench.cpp
new file mode 100644
index 0000000..eb6e10f
--- /dev/null
+++ b/main/prepared_boot_wifi_val100_bench.cpp
@@ -0,0 +1,946 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * VAL100: combined boot/wifi HOT winners from prepared_boot_wifi_opt campaign.
+ * D1 STORAGE_RAM + G1 HT20 + H1 dynamic_cs=false + E3 RX half.
+ * 100 HOT; FULL once; 3 s deep sleep. Payload 0xD8.
+ */
+
+#include 
+#include 
+#include 
+
+#include "aether/all.h"
+#include "aether/ae_exp_wifi.h"
+#include "aether/config.h"
+#include "aether/env.h"
+#include "bench_payload.h"
+#include "experiment_early_entry.h"
+#include "prepared_send/prepared_send.h"
+
+#if defined(ESP_PLATFORM)
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#endif
+
+using namespace std::chrono_literals;
+
+#if defined(ESP_PLATFORM)
+extern "C" std::uint64_t esp_rtc_get_time_us(void);
+#endif
+
+namespace temp_sensor {
+namespace {
+
+static constexpr auto kParentUid =
+    ae::Uid::FromString("b1ac52c8-8d94-bd39-4c01-a631ac594165");
+
+#ifndef BENCH_CLIENT_ID
+#  define BENCH_CLIENT_ID "prepared_deepsleep_5x50_v1"
+#endif
+static constexpr char const* kBenchClientId = BENCH_CLIENT_ID;
+
+#if defined(SERVICE_UID)
+static constexpr auto kServiceUid = ae::Uid::FromString(SERVICE_UID);
+#else
+static constexpr auto kServiceUid =
+    ae::Uid::FromString("5aade50f-00d9-4624-b097-e203cdcf1e38");
+#endif
+
+static constexpr std::uint8_t kVariantCount = 1;
+static constexpr std::uint8_t kHotPerVariant = 100;
+static constexpr std::uint8_t kMaxHotAttempts = 120;
+static constexpr std::uint32_t kSleepUs = 3000000;
+static constexpr std::uint32_t kRtcMagic = 0x42575631u;  // "BWV1"
+static constexpr std::uint16_t kRtcVersion = 1;
+
+enum class Phase : std::uint16_t {
+  kRegister = 0,
+  kFull = 1,
+  kHot = 2,
+  kFinal = 3,
+  kDone = 4,
+};
+
+// Combined winner: STORAGE_RAM + HT20 + CS off + RX half.
+static constexpr bool kStorageRam = true;
+static constexpr bool kNvsEnable = true;
+static constexpr bool kForceHt20 = true;
+static constexpr std::int8_t kDynamicCs = 0;
+static constexpr std::uint8_t kStaticRx = 5;
+static constexpr std::uint8_t kDynamicRx = 16;
+static constexpr std::uint8_t kDynamicTx = 0;
+
+struct RtcState {
+  std::uint32_t magic;
+  std::uint16_t version;
+  std::uint16_t phase;
+  std::uint8_t variant_id;
+  std::uint8_t hot_index;
+  std::uint8_t hot_attempt_count;
+  std::uint8_t hot_send_count;
+  std::uint16_t sequence_global;
+  std::uint16_t next_record_id;
+  std::uint32_t requested_sleep_us;
+  std::uint64_t sleep_arm_rtc_us;
+  std::uint8_t pending_valid;
+  std::uint8_t pending_kind;
+  std::uint8_t pending_variant;
+  std::uint8_t pending_hot_index;
+  std::uint32_t pending_user_cycle_us;
+  std::uint32_t pending_wifi_cycle_us;
+  std::uint32_t pending_wifi_init_us;
+  std::uint32_t pending_connect_us;
+  std::uint32_t pending_encode_us;
+  std::uint32_t pending_txdone_us;
+  std::uint32_t pending_teardown_us;
+  std::uint32_t pending_heap_before;
+  std::uint32_t pending_heap_after;
+  std::uint8_t pending_cb_seen;
+  std::uint8_t pending_cb_timeout;
+  std::uint8_t pending_auth;
+  std::uint8_t brownout_count;
+  std::uint8_t unexpected_reset_count;
+  std::uint8_t current_boot_brownout;
+  std::uint8_t registered;
+  std::uint8_t final_fail_count;
+  std::uint8_t var_tx_success;
+  std::uint8_t var_tx_fail;
+  std::uint8_t var_cb_timeout;
+  std::uint8_t pad0;
+  std::uint32_t var_txdone_sum_us;
+  std::uint8_t prev_variant_id;
+  std::uint8_t prev_hot_send_count;
+  std::uint8_t prev_hot_attempt_count;
+  std::uint8_t prev_tx_success_count;
+  std::uint8_t prev_tx_fail_count;
+  std::uint8_t prev_cb_timeout_count;
+  std::uint32_t prev_txdone_sum_us;
+  std::uint32_t crc;
+};
+
+struct PendingDiag {
+  std::uint8_t valid{0};
+  std::uint8_t tx_cb_total{0};
+  std::uint8_t tx_cb_success{0};
+  std::uint8_t tx_cb_failed{0};
+  std::uint8_t first_status{0xff};
+  std::uint8_t cb_timeout{0};
+  std::uint8_t disconnect_count{0};
+  std::uint8_t reconnect_count{0};
+  std::int8_t rssi{0};
+  std::uint8_t actual_channel{0};
+};
+
+#if defined(ESP_PLATFORM)
+RTC_DATA_ATTR static RtcState g_rtc{};
+RTC_DATA_ATTR static prepared_send::PreparedWifiRtcCache g_rtc_wifi_cache{};
+RTC_DATA_ATTR static PendingDiag g_pending_diag{};
+
+static const auto kWifiInit = ae::WiFiInit{
+    std::vector{{ae::WifiCreds{WIFI_SSID, WIFI_PASSWORD}, {}}},
+    {},
+};
+
+static bool g_had_aether_app = false;
+static std::shared_ptr g_app;
+static ae::Client::ptr g_client;
+static std::unique_ptr g_stream;
+static ae::Subscription g_select_sub;
+static ae::Subscription g_stream_sub;
+static ae::Subscription g_write_sub;
+
+static bool g_write_armed = false;
+static bool g_write_ok = false;
+static bool g_exit_success = false;
+static bool g_pending_register_finish = false;
+static bool g_pending_full_post_write = false;
+static bool g_pending_final_exit = false;
+static bool g_done = false;
+
+static ExperimentEarlyEntrySnapshot g_early{};
+static std::uint32_t g_sleep_elapsed_us = 0;
+static std::uint32_t g_sleep_overhead_us = 0;
+static prepared_send::FastPathConfig g_cfg{};
+static prepared_send::BisectWifiCacheSnapshot g_wifi_snapshot{};
+
+static std::uint32_t Crc32Bytes(void const* data, std::size_t len) {
+  auto const* p = static_cast(data);
+  std::uint32_t crc = 0xffffffffu;
+  for (std::size_t i = 0; i < len; ++i) {
+    crc ^= p[i];
+    for (int b = 0; b < 8; ++b) {
+      std::uint32_t const mask = -(crc & 1u);
+      crc = (crc >> 1) ^ (0xedb88320u & mask);
+    }
+  }
+  return ~crc;
+}
+
+static std::uint32_t ComputeCrc(RtcState const& st) {
+  RtcState tmp = st;
+  tmp.crc = 0;
+  return Crc32Bytes(&tmp, sizeof(tmp));
+}
+
+static void SetCrc(RtcState& st) { st.crc = ComputeCrc(st); }
+
+static bool ValidateRtcState(RtcState const& st) {
+  if (st.magic != kRtcMagic || st.version != kRtcVersion) {
+    return false;
+  }
+  if (ComputeCrc(st) != st.crc) {
+    return false;
+  }
+  if (st.phase > static_cast(Phase::kDone)) {
+    return false;
+  }
+  if (st.variant_id >= kVariantCount &&
+      st.phase != static_cast(Phase::kFinal) &&
+      st.phase != static_cast(Phase::kDone)) {
+    return false;
+  }
+  if (st.hot_index > kHotPerVariant) {
+    return false;
+  }
+  return true;
+}
+
+static void ClearPending(RtcState& st) {
+  st.pending_valid = 0;
+  st.pending_kind = 0;
+  st.pending_variant = 0;
+  st.pending_hot_index = 0;
+  st.pending_user_cycle_us = 0;
+  st.pending_wifi_cycle_us = 0;
+  st.pending_wifi_init_us = 0;
+  st.pending_connect_us = 0;
+  st.pending_encode_us = 0;
+  st.pending_txdone_us = 0;
+  st.pending_teardown_us = 0;
+  st.pending_heap_before = 0;
+  st.pending_heap_after = 0;
+  st.pending_cb_seen = 0;
+  st.pending_cb_timeout = 0;
+  st.pending_auth = 0;
+  g_pending_diag = PendingDiag{};
+}
+
+static void InitRtcFresh(Phase phase) {
+  g_rtc = RtcState{};
+  g_rtc.magic = kRtcMagic;
+  g_rtc.version = kRtcVersion;
+  g_rtc.phase = static_cast(phase);
+  g_rtc.variant_id = 0;
+  g_rtc.hot_index = 1;
+  g_rtc.next_record_id = 1;
+  g_rtc.prev_variant_id = 0xff;
+  ClearPending(g_rtc);
+  SetCrc(g_rtc);
+}
+
+[[noreturn]] static void PrepareRtcStateAndDeepSleep(std::uint32_t requested_us) {
+  g_rtc.requested_sleep_us = requested_us;
+  esp_sleep_enable_timer_wakeup(requested_us);
+  g_rtc.sleep_arm_rtc_us = esp_rtc_get_time_us();
+  SetCrc(g_rtc);
+#  if SOC_PM_SUPPORT_RTC_SLOW_MEM_PD
+  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON);
+#  endif
+#  if SOC_PM_SUPPORT_RTC_FAST_MEM_PD
+  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_ON);
+#  endif
+  (void)esp_deep_sleep_try_to_start();
+  esp_deep_sleep_start();
+  for (;;) {
+  }
+}
+
+static void ForceFullRecovery() {
+  ClearPending(g_rtc);
+  g_rtc.phase = static_cast(Phase::kFull);
+  g_rtc.variant_id = 0;
+  g_rtc.hot_index = 1;
+  g_rtc.hot_attempt_count = 0;
+  g_rtc.hot_send_count = 0;
+  g_rtc.var_tx_success = 0;
+  g_rtc.var_tx_fail = 0;
+  g_rtc.var_cb_timeout = 0;
+  g_rtc.var_txdone_sum_us = 0;
+  SetCrc(g_rtc);
+}
+
+static void SnapshotPrevVariant() {
+  g_rtc.prev_variant_id = g_rtc.variant_id;
+  g_rtc.prev_hot_send_count = g_rtc.hot_send_count;
+  g_rtc.prev_hot_attempt_count = g_rtc.hot_attempt_count;
+  g_rtc.prev_tx_success_count = g_rtc.var_tx_success;
+  g_rtc.prev_tx_fail_count = g_rtc.var_tx_fail;
+  g_rtc.prev_cb_timeout_count = g_rtc.var_cb_timeout;
+  g_rtc.prev_txdone_sum_us = g_rtc.var_txdone_sum_us;
+}
+
+static void AdvanceToNextVariantOrFinal() {
+  SnapshotPrevVariant();
+  g_rtc.phase = static_cast(Phase::kFinal);
+  g_rtc.hot_index = 1;
+  SetCrc(g_rtc);
+}
+
+static std::uint16_t NextSeq() {
+  ++g_rtc.sequence_global;
+  return g_rtc.sequence_global;
+}
+
+static void AdvanceRecordIdAfterFlush() {
+  if (g_rtc.next_record_id < 0xffffu) {
+    ++g_rtc.next_record_id;
+  }
+}
+
+static ae::DataBuffer MakePayload(bench::BootWifiOptMsgType type) {
+  bench::BootWifiOptPayload p{};
+  p.type = static_cast(type);
+  p.variant_id = 0xff;  // VAL100 marker
+  p.hot_index = g_rtc.hot_index;
+  p.sequence_global = NextSeq();
+  p.record_id = g_rtc.pending_valid ? g_rtc.next_record_id : 0;
+  p.reset_reason = g_early.reset_reason;
+  p.wake_cause = g_early.wakeup_cause;
+  p.brownout_count = g_rtc.brownout_count;
+  p.sleep_elapsed_to_app_us = g_sleep_elapsed_us;
+  p.sleep_to_app_overhead_us = g_sleep_overhead_us;
+  p.app_entry_esp_timer_us = g_early.app_entry_esp_timer_us;
+  p.setting_flags = static_cast(
+      (kStorageRam ? 1 : 0) | (kNvsEnable ? 0 : 2) | (kForceHt20 ? 4 : 0) |
+      (kDynamicCs == 0 ? 8 : 0) | (kDynamicCs == 1 ? 16 : 0) | 64);
+  p.static_rx_buf = kStaticRx;
+  p.dynamic_rx_buf = kDynamicRx;
+  p.dynamic_tx_buf = kDynamicTx;
+  p.dynamic_cs = kDynamicCs;
+  std::uint8_t flags = 0;
+  if (g_rtc.current_boot_brownout) {
+    flags |= 1;
+  }
+  if (g_rtc.pending_cb_seen) {
+    flags |= 2;
+  }
+  if (g_rtc.pending_cb_timeout) {
+    flags |= 4;
+  }
+  p.flags = flags;
+  p.prev_variant_id = g_rtc.prev_variant_id;
+  p.prev_hot_send_count = g_rtc.prev_hot_send_count;
+  p.prev_hot_attempt_count = g_rtc.prev_hot_attempt_count;
+  p.prev_tx_success_count = g_rtc.prev_tx_success_count;
+  p.prev_tx_fail_count = g_rtc.prev_tx_fail_count;
+  p.prev_cb_timeout_count = g_rtc.prev_cb_timeout_count;
+  p.prev_txdone_sum_us = g_rtc.prev_txdone_sum_us;
+  p.prepared_message_left = static_cast(
+      prepared_send::PreparedMessageLeft() > 0xffffu
+          ? 0xffffu
+          : prepared_send::PreparedMessageLeft());
+
+  if (g_rtc.pending_valid) {
+    p.pending_kind = g_rtc.pending_kind;
+    p.pending_variant = g_rtc.pending_variant;
+    p.pending_hot_index = g_rtc.pending_hot_index;
+    p.pending_user_cycle_us = g_rtc.pending_user_cycle_us;
+    p.pending_wifi_cycle_us = g_rtc.pending_wifi_cycle_us;
+    p.wifi_init_us = g_rtc.pending_wifi_init_us;
+    p.connect_us = g_rtc.pending_connect_us;
+    p.encode_send_us = g_rtc.pending_encode_us;
+    p.tx_done_wait_us = g_rtc.pending_txdone_us;
+    p.teardown_us = g_rtc.pending_teardown_us;
+    p.heap_before_wifi = g_rtc.pending_heap_before;
+    p.heap_after_wifi = g_rtc.pending_heap_after;
+    p.authmode = g_rtc.pending_auth;
+    if (g_pending_diag.valid) {
+      p.tx_cb_total = g_pending_diag.tx_cb_total;
+      p.tx_cb_success = g_pending_diag.tx_cb_success;
+      p.tx_cb_failed = g_pending_diag.tx_cb_failed;
+      p.first_status = g_pending_diag.first_status;
+      p.cb_timeout = g_pending_diag.cb_timeout;
+      p.rssi = g_pending_diag.rssi;
+      p.actual_channel = g_pending_diag.actual_channel;
+      p.disconnect_count = g_pending_diag.disconnect_count;
+      p.reconnect_count = g_pending_diag.reconnect_count;
+    }
+  }
+  return bench::EncodeBootWifiOpt(p);
+}
+
+static std::uint32_t UserCycleFromAppEntry() {
+  auto const now = esp_timer_get_time();
+  auto const entry = g_early.app_entry_esp_timer_us;
+  if (now < entry) {
+    return 0;
+  }
+  auto const delta = now - entry;
+  return delta > 0xffffffffll ? 0xffffffffu
+                              : static_cast(delta);
+}
+
+static void StorePendingHot(prepared_send::FastSendResult const& result,
+                            std::uint32_t user_cycle_us) {
+  g_rtc.pending_valid = 1;
+  g_rtc.pending_kind = 2;
+  g_rtc.pending_variant = 0;
+  g_rtc.pending_hot_index = g_rtc.hot_index;
+  g_rtc.pending_user_cycle_us = user_cycle_us;
+  g_rtc.pending_wifi_cycle_us = result.cycle_us;
+  g_rtc.pending_wifi_init_us = result.wifi_init_us;
+  g_rtc.pending_connect_us = result.connect_us;
+  g_rtc.pending_encode_us = result.encode_send_us;
+  g_rtc.pending_txdone_us = result.tx_done_wait_us;
+  g_rtc.pending_teardown_us = result.teardown_us;
+  g_rtc.pending_heap_before = result.heap_before_wifi;
+  g_rtc.pending_heap_after = result.heap_after_wifi;
+  g_rtc.pending_cb_seen = result.cb_any;
+  g_rtc.pending_cb_timeout = result.cb_timeout;
+  g_rtc.pending_auth = result.negotiated_auth;
+  g_pending_diag = PendingDiag{};
+  g_pending_diag.valid = 1;
+  g_pending_diag.tx_cb_total = result.tx_cb_total;
+  g_pending_diag.tx_cb_success = result.tx_cb_success;
+  g_pending_diag.tx_cb_failed = result.tx_cb_failed;
+  g_pending_diag.first_status = result.first_status;
+  g_pending_diag.cb_timeout = result.cb_timeout;
+  g_pending_diag.rssi = result.rssi;
+  g_pending_diag.actual_channel = result.actual_channel;
+  g_pending_diag.disconnect_count = result.disconnect_count;
+  g_pending_diag.reconnect_count = result.reconnect_count;
+}
+
+static void StorePendingFull(std::uint32_t user_cycle_us) {
+  g_rtc.pending_valid = 1;
+  g_rtc.pending_kind = 1;
+  g_rtc.pending_variant = 0;
+  g_rtc.pending_hot_index = 0;
+  g_rtc.pending_user_cycle_us = user_cycle_us;
+  g_rtc.pending_wifi_cycle_us = user_cycle_us;
+  g_pending_diag = PendingDiag{};
+}
+
+static void ReleaseApp() {
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  g_app.reset();
+}
+
+static void PreConstructCleanup() {
+  if (!g_had_aether_app) {
+    return;
+  }
+#  if !AE_WIFI_USE_FULL_DEINIT
+  esp_netif_deinit();
+  esp_event_loop_delete_default();
+#  endif
+}
+
+static void ConstructAether() {
+  PreConstructCleanup();
+  g_had_aether_app = true;
+  g_app = ae::AetherApp::Construct(
+      ae::AetherAppContext{}
+#  if AE_DISTILLATION
+          .AddAdapterFactory([&](ae::AetherAppContext const& ctx) {
+            return ae::WifiAdapter::ptr::Create(
+                ae::CreateWith{ctx.domain()}.with_id(
+                    ae::GlobalId::kWiFiAdapter),
+                ctx.aether(), ctx.poller(), ctx.dns_resolver(), kWifiInit);
+          })
+#  endif
+  );
+}
+
+static prepared_send::FastPathConfig MakeFastConfig() {
+  prepared_send::FastPathConfig c{};
+  c.use_bssid = false;
+  c.use_channel = true;
+  c.use_fast_scan = false;
+  c.use_static_ip = true;
+  c.use_static_arp = true;
+  c.auth = prepared_send::FastAuthMode::kWpa2;
+  c.retry_max = 10;
+  c.pre_delay_ms = 25;
+  c.post_delay_ms = 0;
+  c.post_mode = prepared_send::FastPostMode::kTxDoneCb;
+  c.tx_done_wait = prepared_send::FastTxDoneWaitMode::kFirstAny;
+  c.set_mac_retry_limit = false;
+  c.wifi_storage_ram = kStorageRam;
+  c.wifi_nvs_enable = kNvsEnable;
+  c.force_ht20 = kForceHt20;
+  c.dynamic_cs = kDynamicCs;
+  c.static_rx_buf_num = kStaticRx;
+  c.dynamic_rx_buf_num = kDynamicRx;
+  c.dynamic_tx_buf_num = kDynamicTx;
+  return c;
+}
+
+static void DoFullWrite() {
+  if (g_write_armed) {
+    return;
+  }
+  g_write_armed = true;
+  auto payload = MakePayload(bench::BootWifiOptMsgType::kFull);
+  auto& wa = g_stream->Write(std::move(payload));
+  g_write_sub = wa.status_event().Subscribe([](ae::WriteAction::Status st) {
+    g_write_ok = (st == ae::WriteAction::Status::kSuccess);
+    g_pending_full_post_write = true;
+  });
+}
+
+static void MaybeFullWrite() {
+  if (!g_stream || g_write_armed) {
+    return;
+  }
+  if (!g_stream->stream_info().is_writable) {
+    return;
+  }
+  DoFullWrite();
+}
+
+static void OnFullClientReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  auto client = g_client.Load();
+  g_stream = std::make_unique(*g_app, client, kServiceUid,
+                                             ae::P2pPortHandle{});
+  g_stream_sub =
+      g_stream->stream_update_event().Subscribe([]() { MaybeFullWrite(); });
+  MaybeFullWrite();
+}
+
+static void StartRegister() {
+  g_write_armed = false;
+  g_pending_register_finish = false;
+  g_exit_success = false;
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       g_client = std::move(res).value();
+                       g_pending_register_finish = true;
+                     });
+}
+
+static void StartFull() {
+  g_write_armed = false;
+  g_write_ok = false;
+  g_pending_full_post_write = false;
+  g_exit_success = false;
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnFullClientReady(std::move(res).value());
+                     });
+}
+
+static void StartFinal() {
+  g_write_armed = false;
+  g_write_ok = false;
+  g_pending_final_exit = false;
+  g_exit_success = false;
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       g_client = std::move(res).value();
+                       auto client = g_client.Load();
+                       g_stream = std::make_unique(
+                           *g_app, client, kServiceUid, ae::P2pPortHandle{});
+                       g_stream_sub = g_stream->stream_update_event().Subscribe(
+                           []() {
+                             if (!g_stream || g_write_armed) {
+                               return;
+                             }
+                             if (!g_stream->stream_info().is_writable) {
+                               return;
+                             }
+                             g_write_armed = true;
+                             auto& wa = g_stream->Write(
+                                 MakePayload(bench::BootWifiOptMsgType::kFinal));
+                             g_write_sub = wa.status_event().Subscribe(
+                                 [](ae::WriteAction::Status st) {
+                                   g_write_ok =
+                                       (st == ae::WriteAction::Status::kSuccess);
+                                   g_pending_final_exit = true;
+                                 });
+                           });
+                     });
+}
+
+static void FinishRegisterInLoop() {
+  auto client = g_client.Load();
+  if (!client) {
+    g_app->Exit(1);
+    return;
+  }
+  g_app->aether().Save();
+  g_exit_success = true;
+  g_app->Exit(0);
+}
+
+static void FinishFullPostWriteInLoop() {
+  if (!g_write_ok) {
+    g_app->Exit(1);
+    return;
+  }
+  bool captured = false;
+  for (int i = 0; i < 10 && !captured; ++i) {
+    captured = prepared_send::CapturePreparedWifiRtcCache(&g_rtc_wifi_cache);
+    if (!captured) {
+      vTaskDelay(pdMS_TO_TICKS(200));
+    }
+  }
+  bool exported = false;
+  for (std::size_t n : {std::size_t{110}, std::size_t{100}, std::size_t{80}}) {
+    if (prepared_send::ExportPreparedSendBlock(g_client, kServiceUid, n)) {
+      exported = true;
+      break;
+    }
+  }
+  if (!exported || !captured || !prepared_send::HasPreparedSendBlock() ||
+      prepared_send::PreparedMessageLeft() == 0) {
+    g_app->Exit(1);
+    return;
+  }
+  g_exit_success = true;
+  g_app->Exit(0);
+}
+
+static void FinishFinalInLoop() {
+  if (!g_write_ok) {
+    g_app->Exit(1);
+    return;
+  }
+  g_exit_success = true;
+  g_app->Exit(0);
+}
+
+static void AfterRegisterComplete() {
+  ReleaseApp();
+  g_rtc.registered = 1;
+  g_rtc.phase = static_cast(Phase::kFull);
+  g_rtc.variant_id = 0;
+  g_rtc.hot_index = 1;
+  ClearPending(g_rtc);
+  SetCrc(g_rtc);
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void AfterFullComplete() {
+  ReleaseApp();
+  prepared_send::ReleaseFullAetherWifiForHotPath();
+  if (g_rtc.pending_valid) {
+    AdvanceRecordIdAfterFlush();
+  }
+  StorePendingFull(UserCycleFromAppEntry());
+  g_rtc.phase = static_cast(Phase::kHot);
+  g_rtc.hot_index = 1;
+  g_rtc.hot_attempt_count = 0;
+  g_rtc.hot_send_count = 0;
+  g_rtc.var_tx_success = 0;
+  g_rtc.var_tx_fail = 0;
+  g_rtc.var_cb_timeout = 0;
+  g_rtc.var_txdone_sum_us = 0;
+  SetCrc(g_rtc);
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void AfterFinalComplete() {
+  ReleaseApp();
+  if (g_rtc.pending_valid) {
+    AdvanceRecordIdAfterFlush();
+  }
+  ClearPending(g_rtc);
+  g_rtc.phase = static_cast(Phase::kDone);
+  SetCrc(g_rtc);
+  g_done = true;
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void AfterFinalFailed() {
+  ReleaseApp();
+  if (g_rtc.final_fail_count < 255) {
+    ++g_rtc.final_fail_count;
+  }
+  if (g_rtc.final_fail_count >= 3) {
+    ClearPending(g_rtc);
+    g_rtc.phase = static_cast(Phase::kDone);
+    SetCrc(g_rtc);
+    g_done = true;
+  }
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void RunHotOnce() {
+  if (!prepared_send::PreparedWifiRtcCacheIsValid(g_rtc_wifi_cache) ||
+      !prepared_send::HasPreparedSendBlock() ||
+      prepared_send::PreparedMessageLeft() == 0) {
+    ForceFullRecovery();
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  if (g_rtc.hot_attempt_count >= kMaxHotAttempts) {
+    AdvanceToNextVariantOrFinal();
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  if (g_rtc.hot_attempt_count < 255) {
+    ++g_rtc.hot_attempt_count;
+  }
+  SetCrc(g_rtc);
+
+  g_cfg = MakeFastConfig();
+  g_wifi_snapshot =
+      prepared_send::SnapshotFromPreparedWifiRtcCache(g_rtc_wifi_cache);
+  auto payload = MakePayload(bench::BootWifiOptMsgType::kHot);
+  auto const result =
+      prepared_send::SendPreparedOnceWithFastPath(g_cfg, payload,
+                                                    &g_wifi_snapshot);
+
+  if (result.status == prepared_send::HotSendStatus::kWifiFailed) {
+    SetCrc(g_rtc);
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  if (result.status != prepared_send::HotSendStatus::kSent) {
+    SetCrc(g_rtc);
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  auto const user_cycle = UserCycleFromAppEntry();
+  bool const flushed_prior = g_rtc.pending_valid != 0;
+  StorePendingHot(result, user_cycle);
+  if (flushed_prior) {
+    AdvanceRecordIdAfterFlush();
+  }
+
+  if (g_rtc.hot_send_count < 255) {
+    ++g_rtc.hot_send_count;
+  }
+  if (result.first_status == 1) {
+    if (g_rtc.var_tx_success < 255) {
+      ++g_rtc.var_tx_success;
+    }
+  } else if (result.first_status == 0) {
+    if (g_rtc.var_tx_fail < 255) {
+      ++g_rtc.var_tx_fail;
+    }
+  }
+  if (result.cb_timeout) {
+    if (g_rtc.var_cb_timeout < 255) {
+      ++g_rtc.var_cb_timeout;
+    }
+  }
+  g_rtc.var_txdone_sum_us += result.tx_done_wait_us;
+
+  if (g_rtc.hot_index < 255) {
+    ++g_rtc.hot_index;
+  }
+
+  if (g_rtc.hot_send_count >= kHotPerVariant ||
+      g_rtc.hot_attempt_count >= kMaxHotAttempts) {
+    AdvanceToNextVariantOrFinal();
+  }
+  SetCrc(g_rtc);
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void PrepareRtcOnBoot() {
+  g_early = GetExperimentEarlyEntrySnapshot();
+  g_sleep_elapsed_us = 0;
+  g_sleep_overhead_us = 0;
+  if (g_early.valid && g_rtc.sleep_arm_rtc_us != 0 &&
+      g_early.app_entry_rtc_us >= g_rtc.sleep_arm_rtc_us) {
+    auto const elapsed = g_early.app_entry_rtc_us - g_rtc.sleep_arm_rtc_us;
+    g_sleep_elapsed_us =
+        elapsed > 0xffffffffull ? 0xffffffffu : static_cast(elapsed);
+    if (g_sleep_elapsed_us > g_rtc.requested_sleep_us) {
+      g_sleep_overhead_us = g_sleep_elapsed_us - g_rtc.requested_sleep_us;
+    }
+  }
+
+  auto const reset =
+      static_cast(g_early.reset_reason);
+  bool const valid = ValidateRtcState(g_rtc);
+  g_rtc.current_boot_brownout = 0;
+
+  if (reset == ESP_RST_BROWNOUT) {
+    if (valid) {
+      if (g_rtc.brownout_count < 255) {
+        ++g_rtc.brownout_count;
+      }
+      ClearPending(g_rtc);
+    } else {
+      InitRtcFresh(Phase::kFull);
+      g_rtc.brownout_count = 1;
+    }
+    g_rtc.current_boot_brownout = 1;
+    ForceFullRecovery();
+  } else if (!g_early.valid || reset != ESP_RST_DEEPSLEEP || !valid) {
+    bool const first_poweron = (reset == ESP_RST_POWERON);
+    if (first_poweron && (!valid || !g_rtc.registered)) {
+      InitRtcFresh(Phase::kRegister);
+    } else if (!valid) {
+      InitRtcFresh(Phase::kFull);
+      g_rtc.registered = 1;
+      SetCrc(g_rtc);
+    } else {
+      if (g_rtc.unexpected_reset_count < 255) {
+        ++g_rtc.unexpected_reset_count;
+      }
+      ForceFullRecovery();
+    }
+  }
+  SetCrc(g_rtc);
+}
+
+#endif  // ESP_PLATFORM
+
+}  // namespace
+}  // namespace temp_sensor
+
+#if defined(ESP_PLATFORM)
+
+void setup() {
+  using namespace temp_sensor;
+  nvs_flash_init();
+  g_done = false;
+  g_pending_register_finish = false;
+  g_pending_full_post_write = false;
+  g_pending_final_exit = false;
+  PrepareRtcOnBoot();
+  g_cfg = MakeFastConfig();
+
+  auto const phase = static_cast(g_rtc.phase);
+  if (phase == Phase::kDone) {
+    g_done = true;
+    return;
+  }
+  if (phase == Phase::kRegister) {
+    StartRegister();
+    return;
+  }
+  if (phase == Phase::kFull) {
+    StartFull();
+    return;
+  }
+  if (phase == Phase::kFinal) {
+    StartFinal();
+    return;
+  }
+}
+
+void loop() {
+  using namespace temp_sensor;
+  if (g_done) {
+    vTaskDelay(pdMS_TO_TICKS(1000));
+    return;
+  }
+
+  auto const phase = static_cast(g_rtc.phase);
+  if (phase == Phase::kHot) {
+    RunHotOnce();
+    return;
+  }
+
+  auto process_deferred = []() {
+    if (g_app && g_pending_register_finish) {
+      g_pending_register_finish = false;
+      FinishRegisterInLoop();
+      return true;
+    }
+    if (g_app && g_pending_full_post_write) {
+      g_pending_full_post_write = false;
+      FinishFullPostWriteInLoop();
+      return true;
+    }
+    if (g_app && g_pending_final_exit) {
+      g_pending_final_exit = false;
+      FinishFinalInLoop();
+      return true;
+    }
+    return false;
+  };
+
+  if (process_deferred()) {
+    return;
+  }
+  if (!g_app) {
+    return;
+  }
+  if (!g_app->IsExited()) {
+    auto t = g_app->Update(ae::Now());
+    if (process_deferred()) {
+      return;
+    }
+    if (!g_app->IsExited()) {
+      g_app->WaitUntil(t);
+    }
+    return;
+  }
+
+  if (phase == Phase::kRegister) {
+    if (g_exit_success) {
+      AfterRegisterComplete();
+    } else {
+      ReleaseApp();
+      PrepareRtcStateAndDeepSleep(kSleepUs);
+    }
+    return;
+  }
+  if (phase == Phase::kFull) {
+    if (g_exit_success) {
+      AfterFullComplete();
+    } else {
+      ReleaseApp();
+      ForceFullRecovery();
+      PrepareRtcStateAndDeepSleep(kSleepUs);
+    }
+    return;
+  }
+  if (phase == Phase::kFinal) {
+    if (g_exit_success) {
+      AfterFinalComplete();
+    } else {
+      AfterFinalFailed();
+    }
+    return;
+  }
+}
+
+#else
+
+void setup() {}
+void loop() {}
+
+#endif
diff --git a/main/prepared_deepsleep_5x50_bench.cpp b/main/prepared_deepsleep_5x50_bench.cpp
new file mode 100644
index 0000000..8d8d58e
--- /dev/null
+++ b/main/prepared_deepsleep_5x50_bench.cpp
@@ -0,0 +1,916 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * Silent deep-sleep prepared E2E experiment (ESP32-C6).
+ * 5 measured FULL cycles × 50 HOT prepared sends, 3 s deep sleep between
+ * wakes. Metrics travel in DsPayload; UART is silent.
+ */
+
+#include 
+#include 
+#include 
+
+#include "aether/all.h"
+#include "aether/ae_exp_wifi.h"
+#include "aether/config.h"
+#include "aether/env.h"
+#include "bench_payload.h"
+#include "experiment_early_entry.h"
+#include "prepared_send/prepared_send.h"
+
+#if defined(ESP_PLATFORM)
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#endif
+
+using namespace std::chrono_literals;
+
+#if defined(ESP_PLATFORM)
+extern "C" std::uint64_t esp_rtc_get_time_us(void);
+#endif
+
+namespace temp_sensor {
+namespace {
+
+static constexpr auto kParentUid =
+    ae::Uid::FromString("b1ac52c8-8d94-bd39-4c01-a631ac594165");
+
+#ifndef BENCH_CLIENT_ID
+#  define BENCH_CLIENT_ID "prepared_deepsleep_5x50_v1"
+#endif
+static constexpr char const* kBenchClientId = BENCH_CLIENT_ID;
+
+#if defined(SERVICE_UID)
+static constexpr auto kServiceUid = ae::Uid::FromString(SERVICE_UID);
+#else
+static constexpr auto kServiceUid =
+    ae::Uid::FromString("5aade50f-00d9-4624-b097-e203cdcf1e38");
+#endif
+
+static constexpr std::uint8_t kOuterCycles = 5;
+static constexpr std::uint8_t kHotPerOuter = 50;
+static constexpr std::uint8_t kMaxHotAttemptsPerBlock = 60;
+static constexpr std::uint32_t kSleepUs = 3000000;
+
+static constexpr std::uint32_t kRtcMagic = 0x44533350u;  // "DS3P"
+static constexpr std::uint16_t kRtcVersion = 1;
+
+enum class Phase : std::uint16_t {
+  kRegister = 0,
+  kFull = 1,
+  kHot = 2,
+  kFinal = 3,
+  kDone = 4,
+};
+
+struct RtcState {
+  std::uint32_t magic;
+  std::uint16_t version;
+  std::uint16_t phase;
+  std::uint8_t outer_cycle;
+  std::uint8_t hot_index;
+  std::uint8_t hot_attempt_count;
+  std::uint8_t hot_send_count;
+  std::uint16_t sequence_global;
+  std::uint16_t next_record_id;
+  std::uint32_t requested_sleep_us;
+  std::uint64_t sleep_arm_rtc_us;
+  std::uint8_t pending_valid;
+  std::uint8_t pending_kind;
+  std::uint8_t pending_outer;
+  std::uint8_t pending_hot_index;
+  std::uint32_t pending_user_cycle_us;
+  std::uint32_t pending_wifi_cycle_us;
+  std::uint32_t pending_connect_us;
+  std::uint32_t pending_txdone_us;
+  std::uint32_t pending_teardown_us;
+  std::uint8_t pending_cb_seen;
+  std::uint8_t pending_cb_timeout;
+  std::uint8_t pending_auth;
+  std::uint8_t brownout_count;
+  std::uint8_t unexpected_reset_count;
+  std::uint8_t recovery_full_count;
+  std::uint8_t current_boot_brownout;
+  std::uint8_t registered;
+  std::uint8_t final_fail_count;
+  std::uint8_t pad0;
+  std::uint16_t pad1;
+  std::uint32_t crc;
+};
+
+#if defined(ESP_PLATFORM)
+RTC_DATA_ATTR static RtcState g_rtc{};
+RTC_DATA_ATTR static prepared_send::PreparedWifiRtcCache g_rtc_wifi_cache{};
+
+static const auto kWifiInit = ae::WiFiInit{
+    std::vector{{ae::WifiCreds{WIFI_SSID, WIFI_PASSWORD}, {}}},
+    {},
+};
+
+static bool g_had_aether_app = false;
+
+static std::shared_ptr g_app;
+static ae::Client::ptr g_client;
+static std::unique_ptr g_stream;
+static ae::Subscription g_select_sub;
+static ae::Subscription g_stream_sub;
+static ae::Subscription g_write_sub;
+
+static bool g_write_armed = false;
+static bool g_write_ok = false;
+static bool g_exit_success = false;
+static bool g_pending_register_finish = false;
+static bool g_pending_full_post_write = false;
+static bool g_pending_final_exit = false;
+static bool g_done = false;
+
+static ExperimentEarlyEntrySnapshot g_early{};
+static std::uint32_t g_sleep_elapsed_us = 0;
+static std::uint32_t g_sleep_overhead_us = 0;
+static prepared_send::FastPathConfig g_cfg{};
+static prepared_send::BisectWifiCacheSnapshot g_wifi_snapshot{};
+
+static std::uint32_t Crc32Bytes(void const* data, std::size_t len) {
+  auto const* p = static_cast(data);
+  std::uint32_t crc = 0xffffffffu;
+  for (std::size_t i = 0; i < len; ++i) {
+    crc ^= p[i];
+    for (int b = 0; b < 8; ++b) {
+      std::uint32_t const mask = -(crc & 1u);
+      crc = (crc >> 1) ^ (0xedb88320u & mask);
+    }
+  }
+  return ~crc;
+}
+
+static std::uint32_t ComputeCrc(RtcState const& st) {
+  RtcState tmp = st;
+  tmp.crc = 0;
+  return Crc32Bytes(&tmp, sizeof(tmp));
+}
+
+static void SetCrc(RtcState& st) { st.crc = ComputeCrc(st); }
+
+static bool ValidateRtcState(RtcState const& st) {
+  if (st.magic != kRtcMagic || st.version != kRtcVersion) {
+    return false;
+  }
+  if (ComputeCrc(st) != st.crc) {
+    return false;
+  }
+  if (st.phase > static_cast(Phase::kDone)) {
+    return false;
+  }
+  if (st.outer_cycle > kOuterCycles) {
+    return false;
+  }
+  if (st.hot_index > kHotPerOuter) {
+    return false;
+  }
+  return true;
+}
+
+static void ClearPending(RtcState& st) {
+  st.pending_valid = 0;
+  st.pending_kind = static_cast(bench::DsPendingKind::kNone);
+  st.pending_outer = 0;
+  st.pending_hot_index = 0;
+  st.pending_user_cycle_us = 0;
+  st.pending_wifi_cycle_us = 0;
+  st.pending_connect_us = 0;
+  st.pending_txdone_us = 0;
+  st.pending_teardown_us = 0;
+  st.pending_cb_seen = 0;
+  st.pending_cb_timeout = 0;
+  st.pending_auth = 0;
+}
+
+static void InitRtcFresh(Phase phase) {
+  g_rtc = RtcState{};
+  g_rtc.magic = kRtcMagic;
+  g_rtc.version = kRtcVersion;
+  g_rtc.phase = static_cast(phase);
+  g_rtc.outer_cycle = (phase == Phase::kFull || phase == Phase::kHot) ? 1 : 0;
+  g_rtc.hot_index = 1;
+  g_rtc.hot_attempt_count = 0;
+  g_rtc.hot_send_count = 0;
+  g_rtc.sequence_global = 0;
+  g_rtc.next_record_id = 1;
+  g_rtc.requested_sleep_us = 0;
+  g_rtc.sleep_arm_rtc_us = 0;
+  ClearPending(g_rtc);
+  g_rtc.brownout_count = 0;
+  g_rtc.unexpected_reset_count = 0;
+  g_rtc.recovery_full_count = 0;
+  g_rtc.current_boot_brownout = 0;
+  g_rtc.registered = 0;
+  g_rtc.final_fail_count = 0;
+  SetCrc(g_rtc);
+}
+
+[[noreturn]] static void PrepareRtcStateAndDeepSleep(
+    std::uint32_t requested_us) {
+  g_rtc.requested_sleep_us = requested_us;
+  esp_sleep_enable_timer_wakeup(requested_us);
+  g_rtc.sleep_arm_rtc_us = esp_rtc_get_time_us();
+  SetCrc(g_rtc);
+
+#  if SOC_PM_SUPPORT_RTC_SLOW_MEM_PD
+  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON);
+#  endif
+#  if SOC_PM_SUPPORT_RTC_FAST_MEM_PD
+  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_ON);
+#  endif
+
+  esp_err_t const ret = esp_deep_sleep_try_to_start();
+  (void)ret;
+  esp_deep_sleep_start();
+  for (;;) {
+  }
+}
+
+static void ForceFullRecovery() {
+  ClearPending(g_rtc);
+  g_rtc.phase = static_cast(Phase::kFull);
+  if (g_rtc.outer_cycle == 0 || g_rtc.outer_cycle > kOuterCycles) {
+    g_rtc.outer_cycle = 1;
+  }
+  g_rtc.hot_index = 1;
+  g_rtc.hot_attempt_count = 0;
+  g_rtc.hot_send_count = 0;
+  if (g_rtc.recovery_full_count < 255) {
+    ++g_rtc.recovery_full_count;
+  }
+  SetCrc(g_rtc);
+}
+
+static void ComputeWakeMetrics() {
+  g_sleep_elapsed_us = 0;
+  g_sleep_overhead_us = 0;
+  auto const reset =
+      static_cast(g_early.reset_reason);
+  if (reset == ESP_RST_DEEPSLEEP && g_rtc.sleep_arm_rtc_us != 0 &&
+      g_early.app_entry_rtc_us >= g_rtc.sleep_arm_rtc_us) {
+    auto const elapsed = g_early.app_entry_rtc_us - g_rtc.sleep_arm_rtc_us;
+    g_sleep_elapsed_us =
+        elapsed > 0xffffffffull ? 0xffffffffu
+                                : static_cast(elapsed);
+    if (g_sleep_elapsed_us > g_rtc.requested_sleep_us) {
+      g_sleep_overhead_us = g_sleep_elapsed_us - g_rtc.requested_sleep_us;
+    }
+  }
+}
+
+static std::uint16_t NextSeq() {
+  ++g_rtc.sequence_global;
+  return g_rtc.sequence_global;
+}
+
+static void AdvanceRecordIdAfterFlush() {
+  if (g_rtc.next_record_id < 0xffffu) {
+    ++g_rtc.next_record_id;
+  }
+}
+
+static void FillWakeFields(bench::DsPayload& p) {
+  p.reset_reason = g_early.reset_reason;
+  p.wake_cause = g_early.wakeup_cause;
+  p.brownout_count = g_rtc.brownout_count;
+  p.unexpected_reset_count = g_rtc.unexpected_reset_count;
+  p.requested_sleep_us = g_rtc.requested_sleep_us;
+  p.sleep_elapsed_to_app_us = g_sleep_elapsed_us;
+  p.sleep_to_app_overhead_us = g_sleep_overhead_us;
+  p.app_entry_esp_timer_us =
+      g_early.app_entry_esp_timer_us < 0
+          ? 0
+          : static_cast(g_early.app_entry_esp_timer_us);
+
+  std::uint8_t flags = 0;
+  if (g_rtc.current_boot_brownout) {
+    flags |= static_cast(bench::DsFlags::kBrownout);
+  }
+  if (prepared_send::PreparedWifiRtcCacheIsValid(g_rtc_wifi_cache)) {
+    flags |= static_cast(bench::DsFlags::kCacheValid);
+  }
+  if (ValidateRtcState(g_rtc)) {
+    flags |= static_cast(bench::DsFlags::kStateValid);
+  }
+  p.flags = flags;
+}
+
+static void FillPendingFields(bench::DsPayload& p) {
+  if (!g_rtc.pending_valid) {
+    p.pending_kind = static_cast(bench::DsPendingKind::kNone);
+    p.pending_outer = 0;
+    p.pending_hot_index = 0;
+    p.pending_user_cycle_us = 0;
+    p.pending_wifi_cycle_us = 0;
+    p.connect_us = 0;
+    p.tx_done_wait_us = 0;
+    p.teardown_us = 0;
+    p.negotiated_auth = 0;
+    return;
+  }
+  p.pending_kind = g_rtc.pending_kind;
+  p.pending_outer = g_rtc.pending_outer;
+  p.pending_hot_index = g_rtc.pending_hot_index;
+  p.pending_user_cycle_us = g_rtc.pending_user_cycle_us;
+  p.pending_wifi_cycle_us = g_rtc.pending_wifi_cycle_us;
+  p.connect_us = g_rtc.pending_connect_us;
+  p.tx_done_wait_us = g_rtc.pending_txdone_us;
+  p.teardown_us = g_rtc.pending_teardown_us;
+  p.negotiated_auth = g_rtc.pending_auth;
+  if (g_rtc.pending_cb_seen) {
+    p.flags |= static_cast(bench::DsFlags::kCallbackSeen);
+  }
+  if (g_rtc.pending_cb_timeout) {
+    p.flags |= static_cast(bench::DsFlags::kCallbackTimeout);
+  }
+}
+
+static ae::DataBuffer MakeDsPayload(bench::DsMsgType type) {
+  bench::DsPayload p{};
+  p.type = static_cast(type);
+  p.outer_cycle = g_rtc.outer_cycle;
+  p.hot_index = g_rtc.hot_index;
+  p.sequence_global = NextSeq();
+  // Assign id without advancing until the send that flushes pending succeeds
+  // (HOT Wi-Fi retries must reuse the same record_id).
+  p.record_id = g_rtc.pending_valid ? g_rtc.next_record_id : 0;
+  FillWakeFields(p);
+  FillPendingFields(p);
+  p.prepared_message_left =
+      static_cast(prepared_send::PreparedMessageLeft() > 0xffffu
+                                     ? 0xffffu
+                                     : prepared_send::PreparedMessageLeft());
+  return bench::EncodeDs(p);
+}
+
+static void StorePendingFull(std::uint32_t user_cycle_us) {
+  g_rtc.pending_valid = 1;
+  g_rtc.pending_kind = static_cast(bench::DsPendingKind::kFull);
+  g_rtc.pending_outer = g_rtc.outer_cycle;
+  g_rtc.pending_hot_index = 0;
+  g_rtc.pending_user_cycle_us = user_cycle_us;
+  g_rtc.pending_wifi_cycle_us = user_cycle_us;
+  g_rtc.pending_connect_us = 0;
+  g_rtc.pending_txdone_us = 0;
+  g_rtc.pending_teardown_us = 0;
+  g_rtc.pending_cb_seen = 0;
+  g_rtc.pending_cb_timeout = 0;
+  g_rtc.pending_auth = 0;
+}
+
+static void StorePendingHot(prepared_send::FastSendResult const& result,
+                            std::uint32_t user_cycle_us) {
+  g_rtc.pending_valid = 1;
+  g_rtc.pending_kind = static_cast(bench::DsPendingKind::kHot);
+  g_rtc.pending_outer = g_rtc.outer_cycle;
+  g_rtc.pending_hot_index = g_rtc.hot_index;
+  g_rtc.pending_user_cycle_us = user_cycle_us;
+  g_rtc.pending_wifi_cycle_us = result.cycle_us;
+  g_rtc.pending_connect_us = result.connect_us;
+  g_rtc.pending_txdone_us = result.tx_done_wait_us;
+  g_rtc.pending_teardown_us = result.teardown_us;
+  g_rtc.pending_cb_seen = result.cb_any;
+  g_rtc.pending_cb_timeout = result.cb_timeout;
+  g_rtc.pending_auth = result.negotiated_auth;
+}
+
+static void ReleaseApp() {
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  g_app.reset();
+}
+
+static void PreConstructCleanup() {
+  if (!g_had_aether_app) {
+    return;
+  }
+#  if !AE_WIFI_USE_FULL_DEINIT
+  esp_netif_deinit();
+  esp_event_loop_delete_default();
+#  endif
+}
+
+static void ConstructAether() {
+  PreConstructCleanup();
+  g_had_aether_app = true;
+  g_app = ae::AetherApp::Construct(
+      ae::AetherAppContext{}
+#  if AE_DISTILLATION
+          .AddAdapterFactory([&](ae::AetherAppContext const& ctx) {
+            return ae::WifiAdapter::ptr::Create(
+                ae::CreateWith{ctx.domain()}.with_id(
+                    ae::GlobalId::kWiFiAdapter),
+                ctx.aether(), ctx.poller(), ctx.dns_resolver(), kWifiInit);
+          })
+#  endif
+  );
+}
+
+static prepared_send::FastPathConfig MakeFastConfig() {
+  prepared_send::FastPathConfig c{};
+  c.use_bssid = false;
+  c.use_channel = true;
+  c.use_fast_scan = false;
+  c.use_static_ip = true;
+  c.use_static_arp = true;
+  c.ampdu_tx_off = false;
+  c.wifi_storage_ram = false;
+  c.auth = prepared_send::FastAuthMode::kWpa2;
+  c.retry_max = 10;
+  c.pre_delay_ms = 25;
+  c.post_delay_ms = 0;
+  c.post_mode = prepared_send::FastPostMode::kTxDoneCb;
+  return c;
+}
+
+static void DoFullWrite() {
+  if (g_write_armed) {
+    return;
+  }
+  g_write_armed = true;
+  auto payload = MakeDsPayload(bench::DsMsgType::kFull);
+  auto& wa = g_stream->Write(std::move(payload));
+  g_write_sub = wa.status_event().Subscribe([](ae::WriteAction::Status st) {
+    g_write_ok = (st == ae::WriteAction::Status::kSuccess);
+    g_pending_full_post_write = true;
+  });
+}
+
+static void MaybeFullWrite() {
+  if (!g_stream || g_write_armed) {
+    return;
+  }
+  if (!g_stream->stream_info().is_writable) {
+    return;
+  }
+  DoFullWrite();
+}
+
+static void OnFullClientReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  auto client = g_client.Load();
+  g_stream = std::make_unique(*g_app, client, kServiceUid,
+                                             ae::P2pPortHandle{});
+  g_stream_sub =
+      g_stream->stream_update_event().Subscribe([]() { MaybeFullWrite(); });
+  MaybeFullWrite();
+}
+
+static void StartRegister() {
+  g_write_armed = false;
+  g_pending_register_finish = false;
+  g_exit_success = false;
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       g_client = std::move(res).value();
+                       g_pending_register_finish = true;
+                     });
+}
+
+static void StartFull() {
+  g_write_armed = false;
+  g_pending_full_post_write = false;
+  g_write_ok = false;
+  g_exit_success = false;
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnFullClientReady(std::move(res).value());
+                     });
+}
+
+static void DoFinalWrite() {
+  if (g_write_armed) {
+    return;
+  }
+  g_write_armed = true;
+  auto& wa = g_stream->Write(MakeDsPayload(bench::DsMsgType::kFinal));
+  g_write_sub = wa.status_event().Subscribe([](ae::WriteAction::Status st) {
+    g_write_ok = (st == ae::WriteAction::Status::kSuccess);
+    g_pending_final_exit = true;
+  });
+}
+
+static void MaybeFinalWrite() {
+  if (!g_stream || g_write_armed) {
+    return;
+  }
+  if (!g_stream->stream_info().is_writable) {
+    return;
+  }
+  DoFinalWrite();
+}
+
+static void OnFinalClientReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  auto client = g_client.Load();
+  g_stream = std::make_unique(*g_app, client, kServiceUid,
+                                             ae::P2pPortHandle{});
+  g_stream_sub =
+      g_stream->stream_update_event().Subscribe([]() { MaybeFinalWrite(); });
+  MaybeFinalWrite();
+}
+
+static void StartFinal() {
+  g_write_armed = false;
+  g_pending_final_exit = false;
+  g_write_ok = false;
+  g_exit_success = false;
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnFinalClientReady(std::move(res).value());
+                     });
+}
+
+static void FinishRegisterInLoop() {
+  g_app->aether().Save();
+  g_exit_success = true;
+  g_app->Exit(0);
+}
+
+static void FinishFullPostWriteInLoop() {
+  if (!g_write_ok) {
+    g_app->Exit(1);
+    return;
+  }
+  if (!prepared_send::CapturePreparedWifiRtcCache(&g_rtc_wifi_cache)) {
+    g_app->Exit(1);
+    return;
+  }
+  if (!prepared_send::ExportPreparedSendBlock(g_client, kServiceUid,
+                                              kHotPerOuter)) {
+    g_app->Exit(1);
+    return;
+  }
+  if (!prepared_send::HasPreparedSendBlock() ||
+      prepared_send::PreparedMessageLeft() !=
+          static_cast(kHotPerOuter)) {
+    g_app->Exit(1);
+    return;
+  }
+  g_app->aether().Save();
+  g_exit_success = true;
+  g_app->Exit(0);
+}
+
+static void FinishFinalInLoop() {
+  if (!g_write_ok) {
+    g_app->Exit(1);
+    return;
+  }
+  g_exit_success = true;
+  g_app->Exit(0);
+}
+
+static std::uint32_t UserCycleFromAppEntry() {
+  auto const now = esp_timer_get_time();
+  auto const entry = g_early.app_entry_esp_timer_us;
+  if (now < entry) {
+    return 0;
+  }
+  auto const delta = now - entry;
+  return delta > 0xffffffffll ? 0xffffffffu
+                              : static_cast(delta);
+}
+
+static void AfterRegisterComplete() {
+  ReleaseApp();
+  g_rtc.registered = 1;
+  g_rtc.phase = static_cast(Phase::kFull);
+  g_rtc.outer_cycle = 1;
+  g_rtc.hot_index = 1;
+  g_rtc.hot_attempt_count = 0;
+  g_rtc.hot_send_count = 0;
+  ClearPending(g_rtc);
+  SetCrc(g_rtc);
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void AfterFullComplete() {
+  ReleaseApp();
+  prepared_send::ReleaseFullAetherWifiForHotPath();
+  if (g_rtc.pending_valid) {
+    AdvanceRecordIdAfterFlush();
+  }
+  auto const user_cycle = UserCycleFromAppEntry();
+  StorePendingFull(user_cycle);
+  g_rtc.phase = static_cast(Phase::kHot);
+  g_rtc.hot_index = 1;
+  g_rtc.hot_attempt_count = 0;
+  g_rtc.hot_send_count = 0;
+  SetCrc(g_rtc);
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void AfterFinalComplete() {
+  ReleaseApp();
+  if (g_rtc.pending_valid) {
+    AdvanceRecordIdAfterFlush();
+  }
+  ClearPending(g_rtc);
+  g_rtc.final_fail_count = 0;
+  g_rtc.phase = static_cast(Phase::kDone);
+  SetCrc(g_rtc);
+  g_done = true;
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void AfterFinalFailed() {
+  ReleaseApp();
+  if (g_rtc.final_fail_count < 255) {
+    ++g_rtc.final_fail_count;
+  }
+  // After several Aether FINAL failures, stop the campaign so metrics already
+  // delivered (via pending on HOT/FULL) are not blocked forever.
+  if (g_rtc.final_fail_count >= 5) {
+    ClearPending(g_rtc);
+    g_rtc.phase = static_cast(Phase::kDone);
+    SetCrc(g_rtc);
+    g_done = true;
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+  SetCrc(g_rtc);
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static bool WifiFailedBeforeEncode(prepared_send::FastSendResult const& r) {
+  if (r.status == prepared_send::HotSendStatus::kWifiFailed) {
+    return true;
+  }
+  bool const encode_ok =
+      (r.status_flags &
+       static_cast(bench::BisectStatusBits::kEncodeOk)) != 0;
+  return !encode_ok && r.status != prepared_send::HotSendStatus::kSent;
+}
+
+static void RunHotOnce() {
+  if (!prepared_send::PreparedWifiRtcCacheIsValid(g_rtc_wifi_cache)) {
+    ForceFullRecovery();
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+  g_wifi_snapshot =
+      prepared_send::SnapshotFromPreparedWifiRtcCache(g_rtc_wifi_cache);
+  if (!g_wifi_snapshot.valid_ip || g_wifi_snapshot.channel == 0) {
+    ForceFullRecovery();
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+  if (!prepared_send::HasPreparedSendBlock() ||
+      prepared_send::PreparedMessageLeft() == 0) {
+    ForceFullRecovery();
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+  if (g_rtc.hot_attempt_count >= kMaxHotAttemptsPerBlock) {
+    ForceFullRecovery();
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  if (g_rtc.hot_attempt_count < 255) {
+    ++g_rtc.hot_attempt_count;
+  }
+  SetCrc(g_rtc);
+
+  auto payload = MakeDsPayload(bench::DsMsgType::kHot);
+  auto const result =
+      prepared_send::SendPreparedOnceWithFastPath(g_cfg, payload,
+                                                    &g_wifi_snapshot);
+
+  if (result.status == prepared_send::HotSendStatus::kSent) {
+    auto const user_cycle = UserCycleFromAppEntry();
+    if (g_rtc.hot_send_count < 255) {
+      ++g_rtc.hot_send_count;
+    }
+    bool const flushed_prior = g_rtc.pending_valid != 0;
+    StorePendingHot(result, user_cycle);
+    if (flushed_prior) {
+      AdvanceRecordIdAfterFlush();
+    }
+
+    if (g_rtc.hot_index < 255) {
+      ++g_rtc.hot_index;
+    }
+    if (g_rtc.hot_index > kHotPerOuter) {
+      if (g_rtc.outer_cycle < kOuterCycles) {
+        ++g_rtc.outer_cycle;
+        g_rtc.phase = static_cast(Phase::kFull);
+        g_rtc.hot_index = 1;
+        g_rtc.hot_attempt_count = 0;
+        g_rtc.hot_send_count = 0;
+      } else {
+        g_rtc.phase = static_cast(Phase::kFinal);
+      }
+    }
+    SetCrc(g_rtc);
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  if (WifiFailedBeforeEncode(result)) {
+    SetCrc(g_rtc);
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  // Encode/send failure after Wi-Fi: do not advance; retry same index.
+  SetCrc(g_rtc);
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void PrepareRtcOnBoot() {
+  g_early = GetExperimentEarlyEntrySnapshot();
+  auto const reset =
+      static_cast(g_early.reset_reason);
+  bool const valid = ValidateRtcState(g_rtc);
+
+  g_rtc.current_boot_brownout = 0;
+
+  if (reset == ESP_RST_BROWNOUT) {
+    if (valid) {
+      if (g_rtc.brownout_count < 255) {
+        ++g_rtc.brownout_count;
+      }
+      ClearPending(g_rtc);
+    } else {
+      InitRtcFresh(Phase::kFull);
+      g_rtc.brownout_count = 1;
+      g_rtc.outer_cycle = 1;
+    }
+    g_rtc.current_boot_brownout = 1;
+    ForceFullRecovery();
+  } else if (reset != ESP_RST_DEEPSLEEP || !valid) {
+    bool const first_poweron = (reset == ESP_RST_POWERON);
+    if (first_poweron && (!valid || !g_rtc.registered)) {
+      InitRtcFresh(Phase::kRegister);
+    } else if (!valid) {
+      InitRtcFresh(Phase::kFull);
+      g_rtc.unexpected_reset_count = 1;
+      g_rtc.outer_cycle = 1;
+      g_rtc.registered = 1;  // SPIFFS client may already exist
+      SetCrc(g_rtc);
+    } else {
+      if (g_rtc.unexpected_reset_count < 255) {
+        ++g_rtc.unexpected_reset_count;
+      }
+      ForceFullRecovery();
+    }
+  }
+  // else: DEEPSLEEP + valid — continue phase as stored
+
+  ComputeWakeMetrics();
+  SetCrc(g_rtc);
+}
+
+#endif  // ESP_PLATFORM
+
+}  // namespace
+}  // namespace temp_sensor
+
+#if defined(ESP_PLATFORM)
+
+void setup() {
+  using namespace temp_sensor;
+  nvs_flash_init();
+  g_cfg = MakeFastConfig();
+  g_done = false;
+  g_pending_register_finish = false;
+  g_pending_full_post_write = false;
+  g_pending_final_exit = false;
+  PrepareRtcOnBoot();
+
+  auto const phase = static_cast(g_rtc.phase);
+  if (phase == Phase::kDone) {
+    g_done = true;
+    return;
+  }
+  if (phase == Phase::kRegister) {
+    StartRegister();
+    return;
+  }
+  if (phase == Phase::kFull) {
+    StartFull();
+    return;
+  }
+  if (phase == Phase::kFinal) {
+    StartFinal();
+    return;
+  }
+  // HOT is handled synchronously in loop().
+}
+
+void loop() {
+  using namespace temp_sensor;
+  if (g_done) {
+    vTaskDelay(pdMS_TO_TICKS(1000));
+    return;
+  }
+
+  auto const phase = static_cast(g_rtc.phase);
+  if (phase == Phase::kHot) {
+    RunHotOnce();
+    return;
+  }
+
+  auto process_deferred = []() {
+    if (g_app && g_pending_register_finish) {
+      g_pending_register_finish = false;
+      FinishRegisterInLoop();
+      return true;
+    }
+    if (g_app && g_pending_full_post_write) {
+      g_pending_full_post_write = false;
+      FinishFullPostWriteInLoop();
+      return true;
+    }
+    if (g_app && g_pending_final_exit) {
+      g_pending_final_exit = false;
+      FinishFinalInLoop();
+      return true;
+    }
+    return false;
+  };
+
+  if (process_deferred()) {
+    return;
+  }
+
+  if (!g_app) {
+    return;
+  }
+
+  if (!g_app->IsExited()) {
+    auto t = g_app->Update(ae::Now());
+    if (process_deferred()) {
+      return;
+    }
+    if (!g_app->IsExited()) {
+      g_app->WaitUntil(t);
+    }
+    return;
+  }
+
+  if (phase == Phase::kRegister) {
+    if (g_exit_success) {
+      AfterRegisterComplete();
+    } else {
+      ReleaseApp();
+      PrepareRtcStateAndDeepSleep(kSleepUs);
+    }
+    return;
+  }
+  if (phase == Phase::kFull) {
+    if (g_exit_success) {
+      AfterFullComplete();
+    } else {
+      ReleaseApp();
+      ForceFullRecovery();
+      PrepareRtcStateAndDeepSleep(kSleepUs);
+    }
+    return;
+  }
+  if (phase == Phase::kFinal) {
+    if (g_exit_success) {
+      AfterFinalComplete();
+    } else {
+      AfterFinalFailed();
+    }
+    return;
+  }
+}
+
+#else
+
+void setup() {}
+void loop() {}
+
+#endif
diff --git a/main/prepared_keep_wifi_up_5x20_bench.cpp b/main/prepared_keep_wifi_up_5x20_bench.cpp
new file mode 100644
index 0000000..bdacd0d
--- /dev/null
+++ b/main/prepared_keep_wifi_up_5x20_bench.cpp
@@ -0,0 +1,473 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * Silent 5x20 prepared KEEP-WIFI-UP experiment (ESP32-C6):
+ * 1 registration, 5 FULL cycles each preparing 20 messages.
+ * Wi-Fi associates once per outer cycle; 20 UDP sends reuse the association.
+ * Per-message timing is encode+sendto only (no post-send hold).
+ * All timings travel in binary application payloads (no UART results).
+ */
+
+#include 
+#include 
+
+#include "aether/all.h"
+#include "aether/ae_exp_wifi.h"
+#include "aether/config.h"
+#include "aether/env.h"
+#include "bench_payload.h"
+#include "prepared_send/prepared_send.h"
+
+#if defined(ESP_PLATFORM)
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#endif
+
+using namespace std::chrono_literals;
+
+namespace temp_sensor {
+namespace {
+
+static constexpr auto kParentUid =
+    ae::Uid::FromString("b1ac52c8-8d94-bd39-4c01-a631ac594165");
+
+#ifndef BENCH_CLIENT_ID
+#  define BENCH_CLIENT_ID "prepared_keep_wifi_up_5x20_v1"
+#endif
+static constexpr char const* kBenchClientId = BENCH_CLIENT_ID;
+
+#if defined(SERVICE_UID)
+static constexpr auto kServiceUid = ae::Uid::FromString(SERVICE_UID);
+#else
+static constexpr auto kServiceUid =
+    ae::Uid::FromString("3d284a4f-ebb4-451e-a2c5-aecb0d647a45");
+#endif
+
+static constexpr int kOuterCycles = 5;
+static constexpr int kPreparedPerCycle = 20;
+static constexpr int kPreparedGapMs = 1000;
+
+#if defined(ESP_PLATFORM)
+static const auto kWifiInit = ae::WiFiInit{
+    std::vector{{ae::WifiCreds{WIFI_SSID, WIFI_PASSWORD}, {}}},
+    {},
+};
+
+static bool g_had_aether_app = false;
+
+static void PreConstructCleanup() {
+  if (!g_had_aether_app) {
+    return;
+  }
+#  if !AE_WIFI_USE_FULL_DEINIT
+  esp_netif_deinit();
+  esp_event_loop_delete_default();
+#  endif
+}
+
+static std::int64_t NowUs() { return esp_timer_get_time(); }
+#else
+static std::int64_t NowUs() { return 0; }
+#endif
+
+enum class Phase : std::uint8_t {
+  kRegister,
+  kFullCycle,
+  kPrepared,
+  kFinal,
+  kDone,
+};
+
+static std::shared_ptr g_app;
+static ae::Client::ptr g_client;
+static std::unique_ptr g_stream;
+static ae::Subscription g_select_sub;
+static ae::Subscription g_stream_sub;
+static ae::Subscription g_write_sub;
+
+static Phase g_phase = Phase::kRegister;
+static bool g_registration_pending = false;
+static bool g_write_armed = false;
+static bool g_done = false;
+
+static int g_outer = 0;
+static int g_prepared_index = 0;
+static bool g_prepared_waiting_gap = false;
+#if defined(ESP_PLATFORM)
+static TickType_t g_prepared_gap_until = 0;
+#endif
+
+static std::uint16_t g_seq = 0;
+static std::uint32_t g_registration_us = 0;
+static std::uint32_t g_last_full_us = 0;
+static std::uint32_t g_last_prepared_us = 0;
+static std::uint32_t g_last_session_start_us = 0;
+static std::uint32_t g_pending_full_us = 0;
+static bool g_have_pending_full = false;
+static std::uint8_t g_sticky_cache_flags = 0;
+static bool g_wifi_session_open = false;
+
+static std::int64_t g_t0 = 0;
+
+static void ReleaseApp() {
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  g_app.reset();
+}
+
+static std::uint16_t NextSeq() { return ++g_seq; }
+
+static ae::DataBuffer MakeFullPayload(int outer) {
+  bench::Payload p{};
+  p.type = static_cast(bench::MsgType::kFull);
+  p.outer_cycle = static_cast(outer);
+  p.prepared_index = 0;
+  p.sequence_global = NextSeq();
+  p.registration_us = (outer == 1) ? g_registration_us : 0;
+  p.previous_full_us = g_have_pending_full ? g_pending_full_us : 0;
+  p.previous_prepared_us = g_last_prepared_us;
+  p.cache_flags = g_sticky_cache_flags;
+  g_have_pending_full = false;
+  return bench::Encode(p);
+}
+
+static ae::DataBuffer MakePreparedPayload(int outer, int index) {
+  bench::Payload p{};
+  p.type = static_cast(bench::MsgType::kPrepared);
+  p.outer_cycle = static_cast(outer);
+  p.prepared_index = static_cast(index);
+  p.sequence_global = NextSeq();
+  // For index==1: previous_full_us carries wifi session start µs.
+  p.previous_full_us = (index == 1) ? g_last_session_start_us : 0;
+  p.previous_prepared_us = (index == 1) ? 0 : g_last_prepared_us;
+  // cache_flags describe the Wi-Fi session (set at Begin).
+  p.cache_flags = g_sticky_cache_flags;
+  return bench::Encode(p);
+}
+
+static ae::DataBuffer MakeFinalPayload() {
+  bench::Payload p{};
+  p.type = static_cast(bench::MsgType::kFinal);
+  p.outer_cycle = kOuterCycles;
+  p.prepared_index = kPreparedPerCycle;
+  p.sequence_global = NextSeq();
+  p.registration_us = g_registration_us;
+  p.previous_full_us = g_have_pending_full ? g_pending_full_us : g_last_full_us;
+  p.previous_prepared_us = g_last_prepared_us;
+  p.cache_flags = g_sticky_cache_flags;
+  return bench::Encode(p);
+}
+
+static void ConstructAether() {
+#if defined(ESP_PLATFORM)
+  PreConstructCleanup();
+#endif
+  g_had_aether_app = true;
+  g_app = ae::AetherApp::Construct(
+      ae::AetherAppContext{}
+#if AE_DISTILLATION && defined(ESP_PLATFORM)
+          .AddAdapterFactory([&](ae::AetherAppContext const& ctx) {
+            return ae::WifiAdapter::ptr::Create(
+                ae::CreateWith{ctx.domain()}.with_id(
+                    ae::GlobalId::kWiFiAdapter),
+                ctx.aether(), ctx.poller(), ctx.dns_resolver(), kWifiInit);
+          })
+#endif
+  );
+}
+
+static void OnRegisterReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  g_app->aether().Save();
+  g_app->Exit(0);
+}
+
+static void DoFullWrite() {
+  if (g_write_armed) {
+    return;
+  }
+  g_write_armed = true;
+  auto payload = MakeFullPayload(g_outer);
+  auto& wa = g_stream->Write(std::move(payload));
+  g_write_sub = wa.status_event().Subscribe([](ae::WriteAction::Status st) {
+    if (st != ae::WriteAction::Status::kSuccess) {
+      g_app->Exit(1);
+      return;
+    }
+    if (!prepared_send::ExportPreparedSendBlock(g_client, kServiceUid,
+                                                kPreparedPerCycle)) {
+      g_app->Exit(1);
+      return;
+    }
+    if (!prepared_send::HasPreparedSendBlock() ||
+        prepared_send::PreparedMessageLeft() !=
+            static_cast(kPreparedPerCycle)) {
+      g_app->Exit(1);
+      return;
+    }
+    // Export association/IP/gateway-MAC into local prepared cache while FULL
+    // Wi-Fi is still up so prepared #1 can take the fast path.
+    (void)prepared_send::CapturePreparedWifiCacheFromActiveConnection();
+    g_app->aether().Save();
+    g_app->Exit(0);
+  });
+}
+
+static void MaybeFullWrite() {
+  if (!g_stream || g_write_armed) {
+    return;
+  }
+  if (!g_stream->stream_info().is_writable) {
+    return;
+  }
+  DoFullWrite();
+}
+
+static void OnFullClientReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  auto client = g_client.Load();
+  g_stream = std::make_unique(*g_app, client, kServiceUid,
+                                             ae::P2pPortHandle{});
+  g_stream_sub =
+      g_stream->stream_update_event().Subscribe([]() { MaybeFullWrite(); });
+  MaybeFullWrite();
+}
+
+static void StartRegister() {
+  g_phase = Phase::kRegister;
+  g_write_armed = false;
+  g_t0 = NowUs();
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnRegisterReady(std::move(res).value());
+                     });
+}
+
+static void StartFullCycle(int outer) {
+  g_phase = Phase::kFullCycle;
+  g_outer = outer;
+  g_write_armed = false;
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  g_t0 = NowUs();
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnFullClientReady(std::move(res).value());
+                     });
+}
+
+static void StartPreparedPhase() {
+  g_phase = Phase::kPrepared;
+  g_prepared_index = 1;
+  g_prepared_waiting_gap = false;
+  g_sticky_cache_flags = 0;
+  g_wifi_session_open = false;
+  g_last_session_start_us = 0;
+#if defined(ESP_PLATFORM)
+  prepared_send::ReleaseFullAetherWifiForHotPath();
+  if (!prepared_send::BeginPreparedWifiSession()) {
+    // Session failed — leave session closed; sends will report wifi-failed.
+    g_wifi_session_open = false;
+  } else {
+    g_wifi_session_open = true;
+    g_last_session_start_us = prepared_send::LastWifiSessionStartUs();
+    g_sticky_cache_flags = prepared_send::LastSendCacheFlags();
+  }
+#endif
+}
+
+static void DoFinalWrite() {
+  if (g_write_armed) {
+    return;
+  }
+  g_write_armed = true;
+  auto payload = MakeFinalPayload();
+  auto& wa = g_stream->Write(std::move(payload));
+  g_write_sub =
+      wa.status_event().Subscribe([](ae::WriteAction::Status) { g_app->Exit(0); });
+}
+
+static void MaybeFinalWrite() {
+  if (!g_stream || g_write_armed) {
+    return;
+  }
+  if (!g_stream->stream_info().is_writable) {
+    return;
+  }
+  DoFinalWrite();
+}
+
+static void OnFinalClientReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  auto client = g_client.Load();
+  g_stream = std::make_unique(*g_app, client, kServiceUid,
+                                             ae::P2pPortHandle{});
+  g_stream_sub =
+      g_stream->stream_update_event().Subscribe([]() { MaybeFinalWrite(); });
+  MaybeFinalWrite();
+}
+
+static void StartFinal() {
+  g_phase = Phase::kFinal;
+  g_write_armed = false;
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnFinalClientReady(std::move(res).value());
+                     });
+}
+
+void BeginAppMainTiming() {}
+void FinalizeCycleBeforeSleep() {}
+#if defined(ESP_PLATFORM)
+void EnterDeepSleep() {}
+#endif
+
+void setup() {
+#if defined(ESP_PLATFORM)
+  nvs_flash_init();
+  prepared_send::InvalidatePreparedWifiCache();
+#endif
+  g_done = false;
+  g_seq = 0;
+  g_registration_pending = true;
+  g_last_prepared_us = 0;
+  g_have_pending_full = false;
+  g_sticky_cache_flags = 0;
+}
+
+void loop() {
+  if (g_done) {
+    return;
+  }
+
+  if (g_registration_pending) {
+    g_registration_pending = false;
+    StartRegister();
+    return;
+  }
+
+  if (g_phase == Phase::kPrepared) {
+#if defined(ESP_PLATFORM)
+    if (g_prepared_waiting_gap) {
+      if (xTaskGetTickCount() < g_prepared_gap_until) {
+        vTaskDelay(pdMS_TO_TICKS(20));
+        return;
+      }
+      g_prepared_waiting_gap = false;
+    }
+#endif
+
+    if (g_prepared_index > kPreparedPerCycle) {
+#if defined(ESP_PLATFORM)
+      if (g_wifi_session_open) {
+        prepared_send::EndPreparedWifiSession();
+        g_wifi_session_open = false;
+      }
+#endif
+      if (g_outer < kOuterCycles) {
+        StartFullCycle(g_outer + 1);
+      } else {
+        StartFinal();
+      }
+      return;
+    }
+
+    int const i = g_prepared_index;
+    auto payload = MakePreparedPayload(g_outer, i);
+    auto const t0 = NowUs();
+#if defined(ESP_PLATFORM)
+    auto const status =
+        prepared_send::SendPreparedPacketOnActiveWifi(payload);
+#else
+    auto const status = prepared_send::HotSendStatus::kUnsupported;
+#endif
+    auto const us = static_cast(NowUs() - t0);
+    (void)status;
+    g_last_prepared_us = us;
+
+    ++g_prepared_index;
+    if (g_prepared_index <= kPreparedPerCycle) {
+#if defined(ESP_PLATFORM)
+      g_prepared_waiting_gap = true;
+      g_prepared_gap_until =
+          xTaskGetTickCount() + pdMS_TO_TICKS(kPreparedGapMs);
+#endif
+    }
+    return;
+  }
+
+  if (!g_app) {
+    return;
+  }
+
+  if (!g_app->IsExited()) {
+    auto t = g_app->Update(ae::Now());
+    g_app->WaitUntil(t);
+    return;
+  }
+
+  if (g_phase == Phase::kRegister) {
+    ReleaseApp();
+    g_registration_us = static_cast(NowUs() - g_t0);
+    StartFullCycle(1);
+    return;
+  }
+
+  if (g_phase == Phase::kFullCycle) {
+    ReleaseApp();
+    auto const full_us = static_cast(NowUs() - g_t0);
+    g_last_full_us = full_us;
+    g_pending_full_us = full_us;
+    g_have_pending_full = true;
+    StartPreparedPhase();
+    return;
+  }
+
+  if (g_phase == Phase::kFinal) {
+    ReleaseApp();
+    g_phase = Phase::kDone;
+    g_done = true;
+  }
+}
+
+}  // namespace
+}  // namespace temp_sensor
+
+void setup() { temp_sensor::setup(); }
+void loop() { temp_sensor::loop(); }
diff --git a/main/prepared_mac_retry_diag_bench.cpp b/main/prepared_mac_retry_diag_bench.cpp
new file mode 100644
index 0000000..28de7ea
--- /dev/null
+++ b/main/prepared_mac_retry_diag_bench.cpp
@@ -0,0 +1,972 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * Silent MAC retry-limit diagnostic (ESP32-C6).
+ * 7 variants x 50 HOT sendto; FULL between variants; 3 s deep sleep.
+ * FIRST_ANY only. esp_wifi_internal_set_retry_counter per variant (not CONTROL).
+ * Metrics travel in MacRetryPayload 0xD7; UART is silent.
+ */
+
+#include 
+#include 
+#include 
+
+#include "aether/all.h"
+#include "aether/ae_exp_wifi.h"
+#include "aether/config.h"
+#include "aether/env.h"
+#include "bench_payload.h"
+#include "experiment_early_entry.h"
+#include "prepared_send/prepared_send.h"
+
+#if defined(ESP_PLATFORM)
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#endif
+
+using namespace std::chrono_literals;
+
+#if defined(ESP_PLATFORM)
+extern "C" std::uint64_t esp_rtc_get_time_us(void);
+#endif
+
+namespace temp_sensor {
+namespace {
+
+static constexpr auto kParentUid =
+    ae::Uid::FromString("b1ac52c8-8d94-bd39-4c01-a631ac594165");
+
+#ifndef BENCH_CLIENT_ID
+#  define BENCH_CLIENT_ID "prepared_deepsleep_5x50_v1"
+#endif
+static constexpr char const* kBenchClientId = BENCH_CLIENT_ID;
+
+#if defined(SERVICE_UID)
+static constexpr auto kServiceUid = ae::Uid::FromString(SERVICE_UID);
+#else
+static constexpr auto kServiceUid =
+    ae::Uid::FromString("5aade50f-00d9-4624-b097-e203cdcf1e38");
+#endif
+
+static constexpr std::uint8_t kVariantCount = 7;
+static constexpr std::uint8_t kHotPerVariant = 50;
+static constexpr std::uint8_t kMaxHotAttempts = 60;
+static constexpr std::uint32_t kSleepUs = 3000000;
+static constexpr std::uint32_t kRtcMagic = 0x4D525431u;  // "MRT1"
+static constexpr std::uint16_t kRtcVersion = 1;
+
+enum class Phase : std::uint16_t {
+  kRegister = 0,
+  kFull = 1,
+  kHot = 2,
+  kFinal = 3,
+  kDone = 4,
+};
+
+struct VariantCfg {
+  bool set_limit;
+  std::uint8_t short_r;
+  std::uint8_t long_r;
+};
+
+static constexpr VariantCfg kVariants[kVariantCount] = {
+    {false, 0, 0},  // CONTROL
+    {true, 0, 0},
+    {true, 1, 1},
+    {true, 2, 2},
+    {true, 3, 3},
+    {true, 1, 7},
+    {true, 7, 1},
+};
+
+struct RtcState {
+  std::uint32_t magic;
+  std::uint16_t version;
+  std::uint16_t phase;
+  std::uint8_t variant_id;
+  std::uint8_t hot_index;
+  std::uint8_t hot_attempt_count;
+  std::uint8_t hot_send_count;
+  std::uint16_t sequence_global;
+  std::uint16_t next_record_id;
+  std::uint32_t requested_sleep_us;
+  std::uint64_t sleep_arm_rtc_us;
+  std::uint8_t pending_valid;
+  std::uint8_t pending_kind;
+  std::uint8_t pending_variant;
+  std::uint8_t pending_hot_index;
+  std::uint32_t pending_user_cycle_us;
+  std::uint32_t pending_wifi_cycle_us;
+  std::uint32_t pending_connect_us;
+  std::uint32_t pending_encode_us;
+  std::uint32_t pending_txdone_us;
+  std::uint32_t pending_teardown_us;
+  std::uint8_t pending_cb_seen;
+  std::uint8_t pending_cb_timeout;
+  std::uint8_t pending_auth;
+  std::uint8_t brownout_count;
+  std::uint8_t unexpected_reset_count;
+  std::uint8_t current_boot_brownout;
+  std::uint8_t registered;
+  std::uint8_t final_fail_count;
+  std::uint8_t var_tx_success;
+  std::uint8_t var_tx_fail;
+  std::uint8_t var_cb_timeout;
+  std::uint8_t pad0;
+  std::uint32_t var_txdone_sum_us;
+  std::uint8_t prev_variant_id;
+  std::uint8_t prev_hot_send_count;
+  std::uint8_t prev_hot_attempt_count;
+  std::uint8_t prev_tx_success_count;
+  std::uint8_t prev_tx_fail_count;
+  std::uint8_t prev_cb_timeout_count;
+  std::uint32_t prev_txdone_sum_us;
+  std::uint32_t crc;
+};
+
+struct PendingDiag {
+  std::uint8_t valid{0};
+  std::uint8_t tx_cb_total{0};
+  std::uint8_t tx_cb_success{0};
+  std::uint8_t tx_cb_failed{0};
+  std::uint8_t first_status{0xff};
+  std::uint8_t cb_timeout{0};
+  std::uint8_t disconnect_count{0};
+  std::uint8_t reconnect_count{0};
+  std::int8_t rssi{0};
+  std::uint8_t actual_channel{0};
+  std::uint8_t retry_called{0};
+  std::int16_t retry_set_rc{-1};
+  std::uint8_t short_retry{0};
+  std::uint8_t long_retry{0};
+  std::uint32_t retry_cfg_us{0};
+  std::uint32_t first_cb_delta_us{0xffffffffu};
+  std::uint32_t first_success_delta_us{0xffffffffu};
+  std::uint32_t first_failed_delta_us{0xffffffffu};
+  std::uint32_t last_cb_delta_us{0xffffffffu};
+};
+
+#if defined(ESP_PLATFORM)
+RTC_DATA_ATTR static RtcState g_rtc{};
+RTC_DATA_ATTR static prepared_send::PreparedWifiRtcCache g_rtc_wifi_cache{};
+RTC_DATA_ATTR static PendingDiag g_pending_diag{};
+
+static const auto kWifiInit = ae::WiFiInit{
+    std::vector{{ae::WifiCreds{WIFI_SSID, WIFI_PASSWORD}, {}}},
+    {},
+};
+
+static bool g_had_aether_app = false;
+static std::shared_ptr g_app;
+static ae::Client::ptr g_client;
+static std::unique_ptr g_stream;
+static ae::Subscription g_select_sub;
+static ae::Subscription g_stream_sub;
+static ae::Subscription g_write_sub;
+
+static bool g_write_armed = false;
+static bool g_write_ok = false;
+static bool g_exit_success = false;
+static bool g_pending_register_finish = false;
+static bool g_pending_full_post_write = false;
+static bool g_pending_final_exit = false;
+static bool g_done = false;
+
+static ExperimentEarlyEntrySnapshot g_early{};
+static prepared_send::FastPathConfig g_cfg{};
+static prepared_send::BisectWifiCacheSnapshot g_wifi_snapshot{};
+
+static std::uint32_t Crc32Bytes(void const* data, std::size_t len) {
+  auto const* p = static_cast(data);
+  std::uint32_t crc = 0xffffffffu;
+  for (std::size_t i = 0; i < len; ++i) {
+    crc ^= p[i];
+    for (int b = 0; b < 8; ++b) {
+      std::uint32_t const mask = -(crc & 1u);
+      crc = (crc >> 1) ^ (0xedb88320u & mask);
+    }
+  }
+  return ~crc;
+}
+
+static std::uint32_t ComputeCrc(RtcState const& st) {
+  RtcState tmp = st;
+  tmp.crc = 0;
+  return Crc32Bytes(&tmp, sizeof(tmp));
+}
+
+static void SetCrc(RtcState& st) { st.crc = ComputeCrc(st); }
+
+static bool ValidateRtcState(RtcState const& st) {
+  if (st.magic != kRtcMagic || st.version != kRtcVersion) {
+    return false;
+  }
+  if (ComputeCrc(st) != st.crc) {
+    return false;
+  }
+  if (st.phase > static_cast(Phase::kDone)) {
+    return false;
+  }
+  if (st.variant_id >= kVariantCount &&
+      st.phase != static_cast(Phase::kFinal) &&
+      st.phase != static_cast(Phase::kDone)) {
+    return false;
+  }
+  if (st.hot_index > kHotPerVariant) {
+    return false;
+  }
+  return true;
+}
+
+static void ClearPending(RtcState& st) {
+  st.pending_valid = 0;
+  st.pending_kind = 0;
+  st.pending_variant = 0;
+  st.pending_hot_index = 0;
+  st.pending_user_cycle_us = 0;
+  st.pending_wifi_cycle_us = 0;
+  st.pending_connect_us = 0;
+  st.pending_encode_us = 0;
+  st.pending_txdone_us = 0;
+  st.pending_teardown_us = 0;
+  st.pending_cb_seen = 0;
+  st.pending_cb_timeout = 0;
+  st.pending_auth = 0;
+  g_pending_diag = PendingDiag{};
+}
+
+static void InitRtcFresh(Phase phase) {
+  g_rtc = RtcState{};
+  g_rtc.magic = kRtcMagic;
+  g_rtc.version = kRtcVersion;
+  g_rtc.phase = static_cast(phase);
+  g_rtc.variant_id = 0;
+  g_rtc.hot_index = 1;
+  g_rtc.next_record_id = 1;
+  g_rtc.prev_variant_id = 0xff;
+  ClearPending(g_rtc);
+  SetCrc(g_rtc);
+}
+
+[[noreturn]] static void PrepareRtcStateAndDeepSleep(std::uint32_t requested_us) {
+  g_rtc.requested_sleep_us = requested_us;
+  esp_sleep_enable_timer_wakeup(requested_us);
+  g_rtc.sleep_arm_rtc_us = esp_rtc_get_time_us();
+  SetCrc(g_rtc);
+#  if SOC_PM_SUPPORT_RTC_SLOW_MEM_PD
+  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON);
+#  endif
+#  if SOC_PM_SUPPORT_RTC_FAST_MEM_PD
+  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_ON);
+#  endif
+  (void)esp_deep_sleep_try_to_start();
+  esp_deep_sleep_start();
+  for (;;) {
+  }
+}
+
+static void ForceFullRecovery() {
+  ClearPending(g_rtc);
+  g_rtc.phase = static_cast(Phase::kFull);
+  if (g_rtc.variant_id >= kVariantCount) {
+    g_rtc.variant_id = 0;
+  }
+  g_rtc.hot_index = 1;
+  g_rtc.hot_attempt_count = 0;
+  g_rtc.hot_send_count = 0;
+  g_rtc.var_tx_success = 0;
+  g_rtc.var_tx_fail = 0;
+  g_rtc.var_cb_timeout = 0;
+  g_rtc.var_txdone_sum_us = 0;
+  SetCrc(g_rtc);
+}
+
+static void SnapshotPrevVariant() {
+  g_rtc.prev_variant_id = g_rtc.variant_id;
+  g_rtc.prev_hot_send_count = g_rtc.hot_send_count;
+  g_rtc.prev_hot_attempt_count = g_rtc.hot_attempt_count;
+  g_rtc.prev_tx_success_count = g_rtc.var_tx_success;
+  g_rtc.prev_tx_fail_count = g_rtc.var_tx_fail;
+  g_rtc.prev_cb_timeout_count = g_rtc.var_cb_timeout;
+  g_rtc.prev_txdone_sum_us = g_rtc.var_txdone_sum_us;
+}
+
+static void AdvanceToNextVariantOrFinal() {
+  SnapshotPrevVariant();
+  if (g_rtc.variant_id + 1 < kVariantCount) {
+    ++g_rtc.variant_id;
+    g_rtc.phase = static_cast(Phase::kFull);
+    g_rtc.hot_index = 1;
+    g_rtc.hot_attempt_count = 0;
+    g_rtc.hot_send_count = 0;
+    g_rtc.var_tx_success = 0;
+    g_rtc.var_tx_fail = 0;
+    g_rtc.var_cb_timeout = 0;
+    g_rtc.var_txdone_sum_us = 0;
+  } else {
+    g_rtc.phase = static_cast(Phase::kFinal);
+    g_rtc.hot_index = 1;
+  }
+  SetCrc(g_rtc);
+}
+
+static std::uint16_t NextSeq() {
+  ++g_rtc.sequence_global;
+  return g_rtc.sequence_global;
+}
+
+static void AdvanceRecordIdAfterFlush() {
+  if (g_rtc.next_record_id < 0xffffu) {
+    ++g_rtc.next_record_id;
+  }
+}
+
+static VariantCfg const& CurrentVariant() {
+  auto id = g_rtc.variant_id;
+  if (id >= kVariantCount) {
+    id = 0;
+  }
+  return kVariants[id];
+}
+
+static ae::DataBuffer MakePayload(bench::MacRetryMsgType type) {
+  bench::MacRetryPayload p{};
+  p.type = static_cast(type);
+  p.variant_id = g_rtc.variant_id;
+  p.hot_index = g_rtc.hot_index;
+  p.sequence_global = NextSeq();
+  p.record_id = g_rtc.pending_valid ? g_rtc.next_record_id : 0;
+  auto const& v = CurrentVariant();
+  p.short_retry = v.short_r;
+  p.long_retry = v.long_r;
+  p.retry_function_called = v.set_limit ? 1 : 0;
+  p.reset_reason = g_early.reset_reason;
+  p.wake_cause = g_early.wakeup_cause;
+  p.brownout_count = g_rtc.brownout_count;
+  std::uint8_t flags = 0;
+  if (g_rtc.current_boot_brownout) {
+    flags |= 1;
+  }
+  if (g_rtc.pending_cb_seen) {
+    flags |= 2;
+  }
+  if (g_rtc.pending_cb_timeout) {
+    flags |= 4;
+  }
+  p.flags = flags;
+  p.prev_variant_id = g_rtc.prev_variant_id;
+  p.prev_hot_send_count = g_rtc.prev_hot_send_count;
+  p.prev_hot_attempt_count = g_rtc.prev_hot_attempt_count;
+  p.prev_tx_success_count = g_rtc.prev_tx_success_count;
+  p.prev_tx_fail_count = g_rtc.prev_tx_fail_count;
+  p.prev_cb_timeout_count = g_rtc.prev_cb_timeout_count;
+  p.prev_txdone_sum_us = g_rtc.prev_txdone_sum_us;
+  p.prepared_message_left = static_cast(
+      prepared_send::PreparedMessageLeft() > 0xffffu
+          ? 0xffffu
+          : prepared_send::PreparedMessageLeft());
+
+  if (g_rtc.pending_valid) {
+    p.pending_kind = g_rtc.pending_kind;
+    p.pending_variant = g_rtc.pending_variant;
+    p.pending_hot_index = g_rtc.pending_hot_index;
+    p.pending_user_cycle_us = g_rtc.pending_user_cycle_us;
+    p.pending_wifi_cycle_us = g_rtc.pending_wifi_cycle_us;
+    p.connect_us = g_rtc.pending_connect_us;
+    p.encode_send_us = g_rtc.pending_encode_us;
+    p.tx_done_wait_us = g_rtc.pending_txdone_us;
+    p.teardown_us = g_rtc.pending_teardown_us;
+    p.authmode = g_rtc.pending_auth;
+    if (g_pending_diag.valid) {
+      p.retry_function_called = g_pending_diag.retry_called;
+      p.retry_set_rc = g_pending_diag.retry_set_rc;
+      p.short_retry = g_pending_diag.short_retry;
+      p.long_retry = g_pending_diag.long_retry;
+      p.retry_cfg_us = g_pending_diag.retry_cfg_us;
+      p.tx_cb_total = g_pending_diag.tx_cb_total;
+      p.tx_cb_success = g_pending_diag.tx_cb_success;
+      p.tx_cb_failed = g_pending_diag.tx_cb_failed;
+      p.first_status = g_pending_diag.first_status;
+      p.cb_timeout = g_pending_diag.cb_timeout;
+      p.first_cb_delta_us = g_pending_diag.first_cb_delta_us;
+      p.first_success_delta_us = g_pending_diag.first_success_delta_us;
+      p.first_failed_delta_us = g_pending_diag.first_failed_delta_us;
+      p.last_cb_delta_us = g_pending_diag.last_cb_delta_us;
+      p.rssi = g_pending_diag.rssi;
+      p.actual_channel = g_pending_diag.actual_channel;
+      p.disconnect_count = g_pending_diag.disconnect_count;
+      p.reconnect_count = g_pending_diag.reconnect_count;
+    }
+  }
+  return bench::EncodeMacRetry(p);
+}
+
+static std::uint32_t UserCycleFromAppEntry() {
+  auto const now = esp_timer_get_time();
+  auto const entry = g_early.app_entry_esp_timer_us;
+  if (now < entry) {
+    return 0;
+  }
+  auto const delta = now - entry;
+  return delta > 0xffffffffll ? 0xffffffffu
+                              : static_cast(delta);
+}
+
+static void StorePendingHot(prepared_send::FastSendResult const& result,
+                            std::uint32_t user_cycle_us) {
+  g_rtc.pending_valid = 1;
+  g_rtc.pending_kind = 2;
+  g_rtc.pending_variant = g_rtc.variant_id;
+  g_rtc.pending_hot_index = g_rtc.hot_index;
+  g_rtc.pending_user_cycle_us = user_cycle_us;
+  g_rtc.pending_wifi_cycle_us = result.cycle_us;
+  g_rtc.pending_connect_us = result.connect_us;
+  g_rtc.pending_encode_us = result.encode_send_us;
+  g_rtc.pending_txdone_us = result.tx_done_wait_us;
+  g_rtc.pending_teardown_us = result.teardown_us;
+  g_rtc.pending_cb_seen = result.cb_any;
+  g_rtc.pending_cb_timeout = result.cb_timeout;
+  g_rtc.pending_auth = result.negotiated_auth;
+  g_pending_diag = PendingDiag{};
+  g_pending_diag.valid = 1;
+  g_pending_diag.retry_called = result.mac_retry_called;
+  g_pending_diag.retry_set_rc = result.mac_retry_set_rc;
+  g_pending_diag.short_retry = result.mac_short_retry;
+  g_pending_diag.long_retry = result.mac_long_retry;
+  g_pending_diag.retry_cfg_us = result.retry_cfg_us;
+  g_pending_diag.tx_cb_total = result.tx_cb_total;
+  g_pending_diag.tx_cb_success = result.tx_cb_success;
+  g_pending_diag.tx_cb_failed = result.tx_cb_failed;
+  g_pending_diag.first_status = result.first_status;
+  g_pending_diag.cb_timeout = result.cb_timeout;
+  g_pending_diag.first_cb_delta_us = result.first_cb_delta_us;
+  g_pending_diag.first_success_delta_us = result.first_success_delta_us;
+  g_pending_diag.first_failed_delta_us = result.first_failed_delta_us;
+  g_pending_diag.last_cb_delta_us = result.last_cb_delta_us;
+  g_pending_diag.rssi = result.rssi;
+  g_pending_diag.actual_channel = result.actual_channel;
+  g_pending_diag.disconnect_count = result.disconnect_count;
+  g_pending_diag.reconnect_count = result.reconnect_count;
+}
+
+static void StorePendingFull(std::uint32_t user_cycle_us) {
+  g_rtc.pending_valid = 1;
+  g_rtc.pending_kind = 1;
+  g_rtc.pending_variant = g_rtc.variant_id;
+  g_rtc.pending_hot_index = 0;
+  g_rtc.pending_user_cycle_us = user_cycle_us;
+  g_rtc.pending_wifi_cycle_us = user_cycle_us;
+  g_pending_diag = PendingDiag{};
+}
+
+static void ReleaseApp() {
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  g_app.reset();
+}
+
+static void PreConstructCleanup() {
+  if (!g_had_aether_app) {
+    return;
+  }
+#  if !AE_WIFI_USE_FULL_DEINIT
+  esp_netif_deinit();
+  esp_event_loop_delete_default();
+#  endif
+}
+
+static void ConstructAether() {
+  PreConstructCleanup();
+  g_had_aether_app = true;
+  g_app = ae::AetherApp::Construct(
+      ae::AetherAppContext{}
+#  if AE_DISTILLATION
+          .AddAdapterFactory([&](ae::AetherAppContext const& ctx) {
+            return ae::WifiAdapter::ptr::Create(
+                ae::CreateWith{ctx.domain()}.with_id(
+                    ae::GlobalId::kWiFiAdapter),
+                ctx.aether(), ctx.poller(), ctx.dns_resolver(), kWifiInit);
+          })
+#  endif
+  );
+}
+
+static prepared_send::FastPathConfig MakeFastConfig() {
+  prepared_send::FastPathConfig c{};
+  c.use_bssid = false;
+  c.use_channel = true;
+  c.use_fast_scan = false;
+  c.use_static_ip = true;
+  c.use_static_arp = true;
+  c.ampdu_tx_off = false;
+  c.wifi_storage_ram = false;
+  c.auth = prepared_send::FastAuthMode::kWpa2;
+  c.retry_max = 10;
+  c.pre_delay_ms = 25;
+  c.post_delay_ms = 0;
+  c.post_mode = prepared_send::FastPostMode::kTxDoneCb;
+  c.tx_done_wait = prepared_send::FastTxDoneWaitMode::kFirstAny;
+  auto const& v = CurrentVariant();
+  c.set_mac_retry_limit = v.set_limit;
+  c.mac_short_retry = v.short_r;
+  c.mac_long_retry = v.long_r;
+  return c;
+}
+
+static void DoFullWrite() {
+  if (g_write_armed) {
+    return;
+  }
+  g_write_armed = true;
+  auto payload = MakePayload(bench::MacRetryMsgType::kFull);
+  auto& wa = g_stream->Write(std::move(payload));
+  g_write_sub = wa.status_event().Subscribe([](ae::WriteAction::Status st) {
+    g_write_ok = (st == ae::WriteAction::Status::kSuccess);
+    g_pending_full_post_write = true;
+  });
+}
+
+static void MaybeFullWrite() {
+  if (!g_stream || g_write_armed) {
+    return;
+  }
+  if (!g_stream->stream_info().is_writable) {
+    return;
+  }
+  DoFullWrite();
+}
+
+static void OnFullClientReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  auto client = g_client.Load();
+  g_stream = std::make_unique(*g_app, client, kServiceUid,
+                                             ae::P2pPortHandle{});
+  g_stream_sub =
+      g_stream->stream_update_event().Subscribe([]() { MaybeFullWrite(); });
+  MaybeFullWrite();
+}
+
+static void StartRegister() {
+  g_write_armed = false;
+  g_pending_register_finish = false;
+  g_exit_success = false;
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       g_client = std::move(res).value();
+                       g_pending_register_finish = true;
+                     });
+}
+
+static void StartFull() {
+  g_write_armed = false;
+  g_write_ok = false;
+  g_pending_full_post_write = false;
+  g_exit_success = false;
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnFullClientReady(std::move(res).value());
+                     });
+}
+
+static void StartFinal() {
+  g_write_armed = false;
+  g_write_ok = false;
+  g_pending_final_exit = false;
+  g_exit_success = false;
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       g_client = std::move(res).value();
+                       auto client = g_client.Load();
+                       g_stream = std::make_unique(
+                           *g_app, client, kServiceUid, ae::P2pPortHandle{});
+                       g_stream_sub = g_stream->stream_update_event().Subscribe(
+                           []() {
+                             if (!g_stream || g_write_armed) {
+                               return;
+                             }
+                             if (!g_stream->stream_info().is_writable) {
+                               return;
+                             }
+                             g_write_armed = true;
+                             auto& wa = g_stream->Write(
+                                 MakePayload(bench::MacRetryMsgType::kFinal));
+                             g_write_sub = wa.status_event().Subscribe(
+                                 [](ae::WriteAction::Status st) {
+                                   g_write_ok =
+                                       (st == ae::WriteAction::Status::kSuccess);
+                                   g_pending_final_exit = true;
+                                 });
+                           });
+                     });
+}
+
+static void FinishRegisterInLoop() {
+  auto client = g_client.Load();
+  if (!client) {
+    g_app->Exit(1);
+    return;
+  }
+  g_app->aether().Save();
+  g_exit_success = true;
+  g_app->Exit(0);
+}
+
+static void FinishFullPostWriteInLoop() {
+  if (!g_write_ok) {
+    g_app->Exit(1);
+    return;
+  }
+  bool captured = false;
+  for (int i = 0; i < 10 && !captured; ++i) {
+    captured = prepared_send::CapturePreparedWifiRtcCache(&g_rtc_wifi_cache);
+    if (!captured) {
+      vTaskDelay(pdMS_TO_TICKS(200));
+    }
+  }
+  bool exported = false;
+  for (std::size_t n : {std::size_t{60}, std::size_t{50}, std::size_t{30}}) {
+    if (prepared_send::ExportPreparedSendBlock(g_client, kServiceUid, n)) {
+      exported = true;
+      break;
+    }
+  }
+  if (!exported || !captured || !prepared_send::HasPreparedSendBlock() ||
+      prepared_send::PreparedMessageLeft() == 0) {
+    g_app->Exit(1);
+    return;
+  }
+  g_exit_success = true;
+  g_app->Exit(0);
+}
+
+static void FinishFinalInLoop() {
+  if (!g_write_ok) {
+    g_app->Exit(1);
+    return;
+  }
+  g_exit_success = true;
+  g_app->Exit(0);
+}
+
+static void AfterRegisterComplete() {
+  ReleaseApp();
+  g_rtc.registered = 1;
+  g_rtc.phase = static_cast(Phase::kFull);
+  g_rtc.variant_id = 0;
+  g_rtc.hot_index = 1;
+  ClearPending(g_rtc);
+  SetCrc(g_rtc);
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void AfterFullComplete() {
+  ReleaseApp();
+  prepared_send::ReleaseFullAetherWifiForHotPath();
+  if (g_rtc.pending_valid) {
+    AdvanceRecordIdAfterFlush();
+  }
+  StorePendingFull(UserCycleFromAppEntry());
+  g_rtc.phase = static_cast(Phase::kHot);
+  g_rtc.hot_index = 1;
+  g_rtc.hot_attempt_count = 0;
+  g_rtc.hot_send_count = 0;
+  g_rtc.var_tx_success = 0;
+  g_rtc.var_tx_fail = 0;
+  g_rtc.var_cb_timeout = 0;
+  g_rtc.var_txdone_sum_us = 0;
+  SetCrc(g_rtc);
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void AfterFinalComplete() {
+  ReleaseApp();
+  if (g_rtc.pending_valid) {
+    AdvanceRecordIdAfterFlush();
+  }
+  ClearPending(g_rtc);
+  g_rtc.phase = static_cast(Phase::kDone);
+  SetCrc(g_rtc);
+  g_done = true;
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void AfterFinalFailed() {
+  ReleaseApp();
+  if (g_rtc.final_fail_count < 255) {
+    ++g_rtc.final_fail_count;
+  }
+  if (g_rtc.final_fail_count >= 3) {
+    ClearPending(g_rtc);
+    g_rtc.phase = static_cast(Phase::kDone);
+    SetCrc(g_rtc);
+    g_done = true;
+  }
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void RunHotOnce() {
+  if (!prepared_send::PreparedWifiRtcCacheIsValid(g_rtc_wifi_cache) ||
+      !prepared_send::HasPreparedSendBlock() ||
+      prepared_send::PreparedMessageLeft() == 0) {
+    ForceFullRecovery();
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  if (g_rtc.hot_attempt_count >= kMaxHotAttempts) {
+    AdvanceToNextVariantOrFinal();
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  if (g_rtc.hot_attempt_count < 255) {
+    ++g_rtc.hot_attempt_count;
+  }
+  SetCrc(g_rtc);
+
+  g_cfg = MakeFastConfig();
+  g_wifi_snapshot =
+      prepared_send::SnapshotFromPreparedWifiRtcCache(g_rtc_wifi_cache);
+  auto payload = MakePayload(bench::MacRetryMsgType::kHot);
+  auto const result =
+      prepared_send::SendPreparedOnceWithFastPath(g_cfg, payload,
+                                                    &g_wifi_snapshot);
+
+  if (result.status == prepared_send::HotSendStatus::kWifiFailed) {
+    // Assoc failure: do not count as sendto; retry same wake index.
+    SetCrc(g_rtc);
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  if (result.status != prepared_send::HotSendStatus::kSent) {
+    // Encode/send failure after Wi-Fi: still not a completed sendto count.
+    SetCrc(g_rtc);
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  // sendto completed (fire-and-forget) — never app-retry this packet.
+  auto const user_cycle = UserCycleFromAppEntry();
+  bool const flushed_prior = g_rtc.pending_valid != 0;
+  StorePendingHot(result, user_cycle);
+  if (flushed_prior) {
+    AdvanceRecordIdAfterFlush();
+  }
+
+  if (g_rtc.hot_send_count < 255) {
+    ++g_rtc.hot_send_count;
+  }
+  if (result.first_status == 1) {
+    if (g_rtc.var_tx_success < 255) {
+      ++g_rtc.var_tx_success;
+    }
+  } else if (result.first_status == 0) {
+    if (g_rtc.var_tx_fail < 255) {
+      ++g_rtc.var_tx_fail;
+    }
+  }
+  if (result.cb_timeout) {
+    if (g_rtc.var_cb_timeout < 255) {
+      ++g_rtc.var_cb_timeout;
+    }
+  }
+  g_rtc.var_txdone_sum_us += result.tx_done_wait_us;
+
+  if (g_rtc.hot_index < 255) {
+    ++g_rtc.hot_index;
+  }
+
+  if (g_rtc.hot_send_count >= kHotPerVariant ||
+      g_rtc.hot_attempt_count >= kMaxHotAttempts) {
+    AdvanceToNextVariantOrFinal();
+  }
+  SetCrc(g_rtc);
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void PrepareRtcOnBoot() {
+  g_early = GetExperimentEarlyEntrySnapshot();
+  auto const reset =
+      static_cast(g_early.reset_reason);
+  bool const valid = ValidateRtcState(g_rtc);
+  g_rtc.current_boot_brownout = 0;
+
+  if (reset == ESP_RST_BROWNOUT) {
+    if (valid) {
+      if (g_rtc.brownout_count < 255) {
+        ++g_rtc.brownout_count;
+      }
+      ClearPending(g_rtc);
+    } else {
+      InitRtcFresh(Phase::kFull);
+      g_rtc.brownout_count = 1;
+    }
+    g_rtc.current_boot_brownout = 1;
+    ForceFullRecovery();
+  } else if (!g_early.valid || reset != ESP_RST_DEEPSLEEP || !valid) {
+    bool const first_poweron = (reset == ESP_RST_POWERON);
+    if (first_poweron && (!valid || !g_rtc.registered)) {
+      InitRtcFresh(Phase::kRegister);
+    } else if (!valid) {
+      InitRtcFresh(Phase::kFull);
+      g_rtc.registered = 1;
+      SetCrc(g_rtc);
+    } else {
+      if (g_rtc.unexpected_reset_count < 255) {
+        ++g_rtc.unexpected_reset_count;
+      }
+      ForceFullRecovery();
+    }
+  }
+  SetCrc(g_rtc);
+}
+
+#endif  // ESP_PLATFORM
+
+}  // namespace
+}  // namespace temp_sensor
+
+#if defined(ESP_PLATFORM)
+
+void setup() {
+  using namespace temp_sensor;
+  nvs_flash_init();
+  g_done = false;
+  g_pending_register_finish = false;
+  g_pending_full_post_write = false;
+  g_pending_final_exit = false;
+  PrepareRtcOnBoot();
+  g_cfg = MakeFastConfig();
+
+  auto const phase = static_cast(g_rtc.phase);
+  if (phase == Phase::kDone) {
+    g_done = true;
+    return;
+  }
+  if (phase == Phase::kRegister) {
+    StartRegister();
+    return;
+  }
+  if (phase == Phase::kFull) {
+    StartFull();
+    return;
+  }
+  if (phase == Phase::kFinal) {
+    StartFinal();
+    return;
+  }
+}
+
+void loop() {
+  using namespace temp_sensor;
+  if (g_done) {
+    vTaskDelay(pdMS_TO_TICKS(1000));
+    return;
+  }
+
+  auto const phase = static_cast(g_rtc.phase);
+  if (phase == Phase::kHot) {
+    RunHotOnce();
+    return;
+  }
+
+  auto process_deferred = []() {
+    if (g_app && g_pending_register_finish) {
+      g_pending_register_finish = false;
+      FinishRegisterInLoop();
+      return true;
+    }
+    if (g_app && g_pending_full_post_write) {
+      g_pending_full_post_write = false;
+      FinishFullPostWriteInLoop();
+      return true;
+    }
+    if (g_app && g_pending_final_exit) {
+      g_pending_final_exit = false;
+      FinishFinalInLoop();
+      return true;
+    }
+    return false;
+  };
+
+  if (process_deferred()) {
+    return;
+  }
+  if (!g_app) {
+    return;
+  }
+  if (!g_app->IsExited()) {
+    auto t = g_app->Update(ae::Now());
+    if (process_deferred()) {
+      return;
+    }
+    if (!g_app->IsExited()) {
+      g_app->WaitUntil(t);
+    }
+    return;
+  }
+
+  if (phase == Phase::kRegister) {
+    if (g_exit_success) {
+      AfterRegisterComplete();
+    } else {
+      ReleaseApp();
+      PrepareRtcStateAndDeepSleep(kSleepUs);
+    }
+    return;
+  }
+  if (phase == Phase::kFull) {
+    if (g_exit_success) {
+      AfterFullComplete();
+    } else {
+      ReleaseApp();
+      ForceFullRecovery();
+      PrepareRtcStateAndDeepSleep(kSleepUs);
+    }
+    return;
+  }
+  if (phase == Phase::kFinal) {
+    if (g_exit_success) {
+      AfterFinalComplete();
+    } else {
+      AfterFinalFailed();
+    }
+    return;
+  }
+}
+
+#else
+
+void setup() {}
+void loop() {}
+
+#endif
diff --git a/main/prepared_message_e2e_bench.cpp b/main/prepared_message_e2e_bench.cpp
new file mode 100644
index 0000000..e0428e9
--- /dev/null
+++ b/main/prepared_message_e2e_bench.cpp
@@ -0,0 +1,465 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * No-sleep prepared-message E2E bench on ESP32-C6:
+ * 1) one registration
+ * 2) one FULL cycle + PrepareSendMessageBlock(10)
+ * 3) ten prepared sends without AetherApp (1s gap outside timer)
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "aether/all.h"
+#include "aether/ae_exp_wifi.h"
+#include "aether/config.h"
+#include "aether/env.h"
+#include "prepared_send/prepared_send.h"
+#include "wifi_lifecycle_out.h"
+
+#if defined(ESP_PLATFORM)
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#endif
+
+using namespace std::chrono_literals;
+
+namespace temp_sensor {
+namespace {
+
+static constexpr auto kParentUid =
+    ae::Uid::FromString("b1ac52c8-8d94-bd39-4c01-a631ac594165");
+
+#ifndef BENCH_CLIENT_ID
+#  define BENCH_CLIENT_ID "prepared_message_bench_v1"
+#endif
+static constexpr char const* kBenchClientId = BENCH_CLIENT_ID;
+
+#if defined(SERVICE_UID)
+static constexpr auto kServiceUid = ae::Uid::FromString(SERVICE_UID);
+#else
+static constexpr auto kServiceUid =
+    ae::Uid::FromString("3d284a4f-ebb4-451e-a2c5-aecb0d647a45");
+#endif
+
+static constexpr int kPreparedCount = 10;
+static constexpr int kPreparedGapMs = 1000;
+
+#if defined(ESP_PLATFORM)
+static const auto kWifiInit = ae::WiFiInit{
+    std::vector{{ae::WifiCreds{WIFI_SSID, WIFI_PASSWORD}, {}}},
+    {},
+};
+
+static bool g_had_aether_app = false;
+
+static void PreConstructCleanup() {
+  if (!g_had_aether_app) {
+    return;
+  }
+#  if !AE_WIFI_USE_FULL_DEINIT
+  esp_netif_deinit();
+  esp_event_loop_delete_default();
+#  endif
+}
+
+static std::int64_t NowUs() { return esp_timer_get_time(); }
+#endif
+
+enum class Phase : std::uint8_t {
+  kRegister,
+  kFullCycle,
+  kPrepared,
+  kDone,
+};
+
+static std::shared_ptr g_app;
+static ae::Client::ptr g_client;
+static std::unique_ptr g_stream;
+static ae::Subscription g_select_sub;
+static ae::Subscription g_stream_sub;
+static ae::Subscription g_write_sub;
+
+static Phase g_phase = Phase::kRegister;
+static bool g_registration_pending = false;
+static bool g_write_armed = false;
+static bool g_done = false;
+static int g_prepared_index = 0;  // next PREPARED sequence to send (1..10)
+static bool g_prepared_waiting_gap = false;
+#if defined(ESP_PLATFORM)
+static TickType_t g_prepared_gap_until = 0;
+#endif
+
+static std::uint32_t g_registration_ms = 0;
+static std::uint32_t g_full_cycle_ms = 0;
+static std::array g_prepared_ms{};
+static int g_prepared_completed = 0;
+
+#if defined(ESP_PLATFORM)
+static std::int64_t g_t0 = 0;
+#endif
+
+static void ReleaseApp() {
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  g_app.reset();
+}
+
+static void StartRegister();
+static void StartFullCycle();
+static void StartPreparedPhase();
+static void TickPreparedPhase();
+static void PrintFinal();
+
+static void OnRegisterReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  auto const uid_text = ae::Format("{}", g_client->uid());
+  WifiLifecyclePrintf("REGISTRATION_CLIENT_UID=%s\n", uid_text.c_str());
+  g_app->aether().Save();
+  g_app->Exit(0);
+}
+
+static void DoFullWrite() {
+  if (g_write_armed) {
+    return;
+  }
+  g_write_armed = true;
+  auto payload = prepared_send::MakeBenchPayload("FULL", 0);
+  auto& wa = g_stream->Write(std::move(payload));
+  g_write_sub = wa.status_event().Subscribe([](ae::WriteAction::Status st) {
+    if (st != ae::WriteAction::Status::kSuccess) {
+      WifiLifecyclePrintf("FULL_CYCLE_ERR write_fail\n");
+      g_app->Exit(1);
+      return;
+    }
+
+    if (!prepared_send::ExportPreparedSendBlock(g_client, kServiceUid,
+                                                kPreparedCount)) {
+      WifiLifecyclePrintf("FULL_CYCLE_ERR prepare_block_fail\n");
+      g_app->Exit(1);
+      return;
+    }
+
+    auto const left = prepared_send::PreparedMessageLeft();
+    if (!prepared_send::HasPreparedSendBlock() || left != kPreparedCount) {
+      WifiLifecyclePrintf(
+          "FULL_CYCLE_ERR block_invalid left=%lu expected=%d\n",
+          static_cast(left), kPreparedCount);
+      g_app->Exit(1);
+      return;
+    }
+
+    WifiLifecyclePrintf("PREPARED_BLOCK reserved=%d remaining=%lu\n",
+                        kPreparedCount, static_cast(left));
+    g_app->aether().Save();
+    g_app->Exit(0);
+  });
+}
+
+static void MaybeFullWrite() {
+  if (!g_stream || g_write_armed) {
+    return;
+  }
+  if (!g_stream->stream_info().is_writable) {
+    return;
+  }
+  DoFullWrite();
+}
+
+static void OnFullClientReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  auto client = g_client.Load();
+  g_stream = std::make_unique(*g_app, client, kServiceUid,
+                                             ae::P2pPortHandle{});
+  g_stream_sub =
+      g_stream->stream_update_event().Subscribe([]() { MaybeFullWrite(); });
+  MaybeFullWrite();
+}
+
+static void StartRegister() {
+  g_phase = Phase::kRegister;
+  g_write_armed = false;
+#if defined(ESP_PLATFORM)
+  PreConstructCleanup();
+  g_t0 = NowUs();
+#endif
+  WifiLifecyclePrintf("REGISTRATION_START client_id=%s\n", kBenchClientId);
+  WifiLifecyclePrintf("REGISTRATION_BEFORE_CONSTRUCT\n");
+  g_had_aether_app = true;
+  g_app = ae::AetherApp::Construct(
+      ae::AetherAppContext{}
+#if AE_DISTILLATION && defined(ESP_PLATFORM)
+          .AddAdapterFactory([&](ae::AetherAppContext const& ctx) {
+            return ae::WifiAdapter::ptr::Create(
+                ae::CreateWith{ctx.domain()}.with_id(
+                    ae::GlobalId::kWiFiAdapter),
+                ctx.aether(), ctx.poller(), ctx.dns_resolver(), kWifiInit);
+          })
+#endif
+  );
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         WifiLifecyclePrintf("REGISTRATION_ERR select_fail\n");
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnRegisterReady(std::move(res).value());
+                     });
+  WifiLifecyclePrintf("REGISTRATION_AFTER_CONSTRUCT\n");
+}
+
+static void StartFullCycle() {
+  g_phase = Phase::kFullCycle;
+  g_write_armed = false;
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+#if defined(ESP_PLATFORM)
+  PreConstructCleanup();
+  g_t0 = NowUs();
+#endif
+  WifiLifecyclePrintf("FULL_CYCLE_START\n");
+  g_app = ae::AetherApp::Construct(
+      ae::AetherAppContext{}
+#if AE_DISTILLATION && defined(ESP_PLATFORM)
+          .AddAdapterFactory([&](ae::AetherAppContext const& ctx) {
+            return ae::WifiAdapter::ptr::Create(
+                ae::CreateWith{ctx.domain()}.with_id(
+                    ae::GlobalId::kWiFiAdapter),
+                ctx.aether(), ctx.poller(), ctx.dns_resolver(), kWifiInit);
+          })
+#endif
+  );
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         WifiLifecyclePrintf("FULL_CYCLE_ERR select_fail\n");
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnFullClientReady(std::move(res).value());
+                     });
+}
+
+static std::uint32_t Percentile(std::array vals,
+                                int count, int pct) {
+  if (count <= 0) {
+    return 0;
+  }
+  std::sort(vals.begin(), vals.begin() + count);
+  auto const idx = (pct * (count - 1) + 99) / 100;
+  return vals[static_cast(idx)];
+}
+
+static void PrintFinal() {
+  std::uint32_t min_ms = UINT32_MAX;
+  std::uint32_t max_ms = 0;
+  for (int i = 0; i < g_prepared_completed; ++i) {
+    auto const v = g_prepared_ms[static_cast(i)];
+    min_ms = std::min(min_ms, v);
+    max_ms = std::max(max_ms, v);
+  }
+  if (g_prepared_completed == 0) {
+    min_ms = 0;
+  }
+  auto const median =
+      Percentile(g_prepared_ms, g_prepared_completed, 50);
+  auto const p90 = Percentile(g_prepared_ms, g_prepared_completed, 90);
+
+  WifiLifecyclePrintf("REGISTRATION\n");
+  WifiLifecyclePrintf("  time_ms=%lu\n",
+                      static_cast(g_registration_ms));
+  WifiLifecyclePrintf("FULL CYCLE\n");
+  WifiLifecyclePrintf("  time_ms=%lu\n",
+                      static_cast(g_full_cycle_ms));
+  WifiLifecyclePrintf("PREPARED\n");
+  WifiLifecyclePrintf("  raw=[");
+  for (int i = 0; i < g_prepared_completed; ++i) {
+    if (i > 0) {
+      WifiLifecyclePrintf(", ");
+    }
+    WifiLifecyclePrintf(
+        "%lu",
+        static_cast(g_prepared_ms[static_cast(i)]));
+  }
+  WifiLifecyclePrintf("]\n");
+  WifiLifecyclePrintf("  min=%lu\n", static_cast(min_ms));
+  WifiLifecyclePrintf("  median=%lu\n", static_cast(median));
+  WifiLifecyclePrintf("  p90=%lu\n", static_cast(p90));
+  WifiLifecyclePrintf("  max=%lu\n", static_cast(max_ms));
+  WifiLifecyclePrintf("  completed=%d/%d\n", g_prepared_completed,
+                      kPreparedCount);
+  WifiLifecyclePrintf("prepared block:\n");
+  WifiLifecyclePrintf("  reserved=%d\n", kPreparedCount);
+  WifiLifecyclePrintf(
+      "  remaining=%lu\n",
+      static_cast(prepared_send::PreparedMessageLeft()));
+  WifiLifecyclePrintf("PREPARED_E2E_DONE\n");
+}
+
+static void StartPreparedPhase() {
+  g_phase = Phase::kPrepared;
+  g_prepared_index = 1;
+  g_prepared_waiting_gap = false;
+#if defined(ESP_PLATFORM)
+  prepared_send::ReleaseFullAetherWifiForHotPath();
+#endif
+  WifiLifecyclePrintf("PREPARED_LOOP_START count=%d\n", kPreparedCount);
+}
+
+static void TickPreparedPhase() {
+  if (g_done || g_phase != Phase::kPrepared) {
+    return;
+  }
+
+#if defined(ESP_PLATFORM)
+  if (g_prepared_waiting_gap) {
+    if (xTaskGetTickCount() < g_prepared_gap_until) {
+      vTaskDelay(pdMS_TO_TICKS(20));
+      return;
+    }
+    g_prepared_waiting_gap = false;
+  }
+#endif
+
+  if (g_prepared_index > kPreparedCount) {
+    PrintFinal();
+    g_phase = Phase::kDone;
+    g_done = true;
+    return;
+  }
+
+  int const i = g_prepared_index;
+#if defined(ESP_PLATFORM)
+  auto const t0 = NowUs();
+#endif
+  auto payload = prepared_send::MakeBenchPayload("PREPARED", i);
+  auto const status = prepared_send::SendPreparedOnce(payload);
+#if defined(ESP_PLATFORM)
+  auto const ms = static_cast((NowUs() - t0) / 1000);
+#else
+  auto const ms = 0U;
+#endif
+  auto const left = prepared_send::PreparedMessageLeft();
+  auto const status_text = std::string{prepared_send::ToString(status)};
+  WifiLifecyclePrintf(
+      "PREPARED %d time_ms=%lu status=%s message_left=%lu\n", i,
+      static_cast(ms), status_text.c_str(),
+      static_cast(left));
+  if (status == prepared_send::HotSendStatus::kSent &&
+      g_prepared_completed < kPreparedCount) {
+    g_prepared_ms[static_cast(g_prepared_completed)] = ms;
+    ++g_prepared_completed;
+  }
+
+  ++g_prepared_index;
+  if (g_prepared_index <= kPreparedCount) {
+#if defined(ESP_PLATFORM)
+    g_prepared_waiting_gap = true;
+    g_prepared_gap_until =
+        xTaskGetTickCount() + pdMS_TO_TICKS(kPreparedGapMs);
+#else
+    g_prepared_waiting_gap = false;
+#endif
+  }
+}
+
+void BeginAppMainTiming() {}
+void FinalizeCycleBeforeSleep() {}
+#if defined(ESP_PLATFORM)
+void EnterDeepSleep() {}
+#endif
+
+void setup() {
+#if defined(ESP_PLATFORM)
+  nvs_flash_init();
+#endif
+  auto const service_text = ae::Format("{}", kServiceUid);
+  WifiLifecyclePrintf("PREPARED_E2E_START client_id=%s service=%s\n",
+                      kBenchClientId, service_text.c_str());
+  g_done = false;
+  g_prepared_index = 0;
+  g_prepared_waiting_gap = false;
+  g_prepared_completed = 0;
+  g_registration_pending = true;
+}
+
+void loop() {
+  if (g_done) {
+    return;
+  }
+
+  if (g_registration_pending) {
+    g_registration_pending = false;
+    StartRegister();
+    return;
+  }
+
+  if (g_phase == Phase::kPrepared) {
+    TickPreparedPhase();
+    return;
+  }
+
+  if (!g_app) {
+    return;
+  }
+
+  if (!g_app->IsExited()) {
+    auto t = g_app->Update(ae::Now());
+    g_app->WaitUntil(t);
+    return;
+  }
+
+  if (g_phase == Phase::kRegister) {
+    ReleaseApp();
+#if defined(ESP_PLATFORM)
+    g_registration_ms = static_cast((NowUs() - g_t0) / 1000);
+#else
+    g_registration_ms = 0;
+#endif
+    WifiLifecyclePrintf("REGISTRATION time_ms=%lu\n",
+                        static_cast(g_registration_ms));
+    StartFullCycle();
+    return;
+  }
+
+  if (g_phase == Phase::kFullCycle) {
+    ReleaseApp();
+#if defined(ESP_PLATFORM)
+    g_full_cycle_ms = static_cast((NowUs() - g_t0) / 1000);
+#else
+    g_full_cycle_ms = 0;
+#endif
+    WifiLifecyclePrintf("FULL CYCLE time_ms=%lu\n",
+                        static_cast(g_full_cycle_ms));
+    // No further AetherApp construction — prepared hot path only.
+    StartPreparedPhase();
+  }
+}
+
+}  // namespace
+
+}  // namespace temp_sensor
+
+void setup() { temp_sensor::setup(); }
+void loop() { temp_sensor::loop(); }
diff --git a/main/prepared_send/prepared_send.cpp b/main/prepared_send/prepared_send.cpp
new file mode 100644
index 0000000..e9431b9
--- /dev/null
+++ b/main/prepared_send/prepared_send.cpp
@@ -0,0 +1,1996 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * Experimental ESP32 prepared-send integration.
+ *
+ * This file intentionally keeps the hot path isolated from controller.cpp.
+ * If hot path fails for any reason, controller.cpp falls back to normal
+ * full-Aether boot.
+ */
+
+#include "prepared_send/prepared_send.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "aether-miscpp/serialization/binary_archive.h"
+#include "aether-miscpp/misc/defer.h"
+
+#include "aether/all.h"
+#include "aether/prepared_packet/packet_encoder.h"
+#include "aether/prepared_packet/prepared_send_message.h"
+#include "bench_payload.h"
+
+#if !defined(ESP_PLATFORM)
+#  include 
+#endif
+
+#if defined(ESP_PLATFORM)
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  if !defined(AE_EXP_SILENT)
+#    include 
+#  endif
+#endif
+
+namespace temp_sensor::prepared_send {
+
+void ClearPreparedSendBlock();
+
+#if defined(ESP_PLATFORM) && !defined(AE_EXP_SILENT)
+static constexpr char const* kTag = "prepared-send";
+#  define PS_LOGI(...) ESP_LOGI(kTag, __VA_ARGS__)
+#  define PS_LOGW(...) ESP_LOGW(kTag, __VA_ARGS__)
+#  define PS_LOGE(...) ESP_LOGE(kTag, __VA_ARGS__)
+#  define PS_LOGD(...) ESP_LOGD(kTag, __VA_ARGS__)
+#else
+#  define PS_LOGI(...) \
+    do {               \
+    } while (0)
+#  define PS_LOGW(...) \
+    do {               \
+    } while (0)
+#  define PS_LOGE(...) \
+    do {               \
+    } while (0)
+#  define PS_LOGD(...) \
+    do {               \
+    } while (0)
+#endif
+
+#ifndef AETHER_PREPARED_NONCE_RESERVE
+#  define AETHER_PREPARED_NONCE_RESERVE 30
+#endif
+
+#ifndef AETHER_PREPARED_HOT_WIFI_TIMEOUT_MS
+#  define AETHER_PREPARED_HOT_WIFI_TIMEOUT_MS 15000
+#endif
+
+#ifndef AETHER_PREPARED_HOT_WIFI_MAX_RETRY
+#  define AETHER_PREPARED_HOT_WIFI_MAX_RETRY 10
+#endif
+
+#ifndef AETHER_PREPARED_ARP_TIMEOUT_MS
+#  define AETHER_PREPARED_ARP_TIMEOUT_MS 500
+#endif
+
+static std::uint8_t g_last_send_cache_flags = 0;
+static bool g_prepared_wifi_session_active = false;
+
+#if defined(ESP_PLATFORM)
+// Per hot-cycle Wi-Fi event counters (reset at StartFastWifi).
+std::atomic g_wifi_disconnect_count{0};
+std::atomic g_wifi_last_disconnect_reason{0};
+std::atomic g_wifi_reconnect_count{0};
+#endif
+static std::uint32_t g_last_wifi_session_start_us = 0;
+
+#if defined(ESP_PLATFORM)
+static RTC_NOINIT_ATTR ae::prepared_packet::PreparedSendMessageBlock
+    g_prepared_send_message_block;
+
+static RTC_DATA_ATTR esp_netif_ip_info_t rtc_ip_info = {};
+static RTC_DATA_ATTR WiFiBaseStation base_station{};
+static RTC_DATA_ATTR std::uint8_t gateway_mac[6] = {};
+static RTC_NOINIT_ATTR bool address_is_valid;
+static RTC_NOINIT_ATTR bool bs_is_valid;
+static RTC_NOINIT_ATTR bool gateway_mac_valid;
+
+static_assert(sizeof(ae::prepared_packet::PreparedSendMessageBlock) <= 8 * 1024,
+              "PreparedSendMessageBlock must fit in ESP32 RTC slow memory");
+#else
+static ae::prepared_packet::PreparedSendMessageBlock g_prepared_send_message_block;
+#endif
+
+#if defined(ESP_PLATFORM)
+void InvalidatePreparedWifiCache();  // defined below
+#endif
+
+namespace {
+
+#if defined(ESP_PLATFORM)
+
+bool FillUdpDestination(ae::prepared_packet::PreparedEndpoint const& endpoint,
+                        sockaddr* dest_addr, socklen_t* dest_len) {
+  if (endpoint.address.Index() == ae::AddrVersion::kIpV4) {
+    auto* dest = reinterpret_cast(dest_addr);
+    std::memset(dest, 0, sizeof(*dest));
+    dest->sin_family = AF_INET;
+    dest->sin_port = htons(endpoint.port);
+    std::memcpy(&dest->sin_addr.s_addr,
+                &endpoint.address.Get().ipv4_value, 4);
+    *dest_len = sizeof(*dest);
+    return true;
+  }
+
+  if (endpoint.address.Index() == ae::AddrVersion::kIpV6) {
+    auto* dest = reinterpret_cast(dest_addr);
+    std::memset(dest, 0, sizeof(*dest));
+    dest->sin6_family = AF_INET6;
+    dest->sin6_port = htons(endpoint.port);
+    std::memcpy(&dest->sin6_addr.s6_addr,
+                &endpoint.address.Get().ipv6_value, 16);
+    *dest_len = sizeof(*dest);
+    return true;
+  }
+
+  return false;
+}
+
+static EventGroupHandle_t g_wifi_event_group = nullptr;
+static esp_netif_t* g_wifi_netif = nullptr;
+static esp_event_handler_instance_t g_wifi_any_id_handler = nullptr;
+static esp_event_handler_instance_t g_wifi_got_ip_handler = nullptr;
+static bool g_wifi_initialized = false;
+static bool g_wifi_started = false;
+static std::uint32_t g_last_wifi_init_us = 0;
+static std::uint32_t g_last_heap_before_wifi = 0;
+static std::uint32_t g_last_heap_after_wifi = 0;
+static bool g_default_event_loop_created = false;
+static int g_wifi_retry_count = 0;
+static bool g_wait_got_ip = true;
+static bool g_using_bssid_cache = false;
+static int g_max_wifi_retry = AETHER_PREPARED_HOT_WIFI_MAX_RETRY;
+static constexpr EventBits_t kWifiReadyBit = BIT0;
+static constexpr EventBits_t kWifiFailBit = BIT1;
+
+void CaptureApIntoCache() {
+  wifi_ap_record_t ap_info{};
+  if (esp_wifi_sta_get_ap_info(&ap_info) != ESP_OK) {
+    return;
+  }
+  base_station.target_channel = ap_info.primary;
+  std::memcpy(base_station.target_bssid, ap_info.bssid,
+              sizeof(base_station.target_bssid));
+  bs_is_valid = true;
+}
+
+struct GatewayMacLookupCtx {
+  struct netif* lwip_netif{nullptr};
+  ip4_addr_t gw{};
+  std::uint8_t mac[6]{};
+  bool found{false};
+};
+
+esp_err_t LookupGatewayMacTcpip(void* arg) {
+  auto* ctx = static_cast(arg);
+  struct eth_addr* eth_ret = nullptr;
+  ip4_addr_t const* ip_ret = nullptr;
+  auto const idx =
+      etharp_find_addr(ctx->lwip_netif, &ctx->gw, ð_ret, &ip_ret);
+  if (idx >= 0 && eth_ret != nullptr) {
+    std::memcpy(ctx->mac, eth_ret->addr, sizeof(ctx->mac));
+    ctx->found = true;
+  }
+  return ESP_OK;
+}
+
+esp_err_t RequestGatewayArpTcpip(void* arg) {
+  auto* ctx = static_cast(arg);
+  (void)etharp_request(ctx->lwip_netif, &ctx->gw);
+  return ESP_OK;
+}
+
+struct StaticArpInstallCtx {
+  ip4_addr_t gw{};
+  struct eth_addr eth{};
+  err_t err{ERR_VAL};
+};
+
+esp_err_t InstallStaticGatewayArpTcpip(void* arg) {
+  auto* ctx = static_cast(arg);
+  ctx->err = etharp_add_static_entry(&ctx->gw, &ctx->eth);
+  return ESP_OK;
+}
+
+bool LookupGatewayMac(esp_netif_t* esp_netif, std::uint8_t out_mac[6]) {
+  if (esp_netif == nullptr || rtc_ip_info.gw.addr == 0) {
+    return false;
+  }
+  auto* lwip_netif =
+      static_cast(esp_netif_get_netif_impl(esp_netif));
+  if (lwip_netif == nullptr) {
+    return false;
+  }
+
+  GatewayMacLookupCtx ctx{};
+  ctx.lwip_netif = lwip_netif;
+  ctx.gw.addr = rtc_ip_info.gw.addr;
+  if (esp_netif_tcpip_exec(&LookupGatewayMacTcpip, &ctx) != ESP_OK ||
+      !ctx.found) {
+    return false;
+  }
+  std::memcpy(out_mac, ctx.mac, 6);
+  return true;
+}
+
+bool ResolveAndCacheGatewayMac(esp_netif_t* esp_netif) {
+  std::uint8_t mac[6]{};
+  if (LookupGatewayMac(esp_netif, mac)) {
+    std::memcpy(gateway_mac, mac, sizeof(gateway_mac));
+    gateway_mac_valid = true;
+    return true;
+  }
+
+  auto* lwip_netif =
+      static_cast(esp_netif_get_netif_impl(esp_netif));
+  if (lwip_netif == nullptr || rtc_ip_info.gw.addr == 0) {
+    return false;
+  }
+
+  GatewayMacLookupCtx req{};
+  req.lwip_netif = lwip_netif;
+  req.gw.addr = rtc_ip_info.gw.addr;
+  (void)esp_netif_tcpip_exec(&RequestGatewayArpTcpip, &req);
+
+  auto const deadline =
+      std::chrono::steady_clock::now() +
+      std::chrono::milliseconds(AETHER_PREPARED_ARP_TIMEOUT_MS);
+  while (std::chrono::steady_clock::now() < deadline) {
+    vTaskDelay(pdMS_TO_TICKS(20));
+    if (LookupGatewayMac(esp_netif, mac)) {
+      std::memcpy(gateway_mac, mac, sizeof(gateway_mac));
+      gateway_mac_valid = true;
+      return true;
+    }
+  }
+  return false;
+}
+
+bool InstallStaticGatewayArp() {
+  if (!gateway_mac_valid || !address_is_valid || rtc_ip_info.gw.addr == 0) {
+    return false;
+  }
+  StaticArpInstallCtx ctx{};
+  ctx.gw.addr = rtc_ip_info.gw.addr;
+  std::memcpy(ctx.eth.addr, gateway_mac, sizeof(gateway_mac));
+  if (esp_netif_tcpip_exec(&InstallStaticGatewayArpTcpip, &ctx) != ESP_OK) {
+    return false;
+  }
+  return ctx.err == ERR_OK;
+}
+
+// Ensure gateway L2 destination is known before UDP sendto.
+// Prefer cached MAC + static ARP; otherwise resolve via ARP (do not drop).
+bool EnsureGatewayArpReady(esp_netif_t* esp_netif) {
+  if (gateway_mac_valid && InstallStaticGatewayArp()) {
+    g_last_send_cache_flags |=
+        static_cast(bench::CacheFlags::kUsedStaticArp);
+    return true;
+  }
+
+  g_last_send_cache_flags |=
+      static_cast(bench::CacheFlags::kArpFallback);
+  if (ResolveAndCacheGatewayMac(esp_netif)) {
+    (void)InstallStaticGatewayArp();
+  }
+  // Do not discard the message if ARP is still unresolved; sendto may queue.
+  return true;
+}
+
+void WifiEventHandler(void*, esp_event_base_t event_base, std::int32_t event_id,
+                      void* event_data) {
+  if (g_wifi_event_group == nullptr) {
+    return;
+  }
+
+  if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
+    g_wifi_retry_count = 0;
+    auto err = esp_wifi_connect();
+    if (err != ESP_OK) {
+      PS_LOGE("Wi-Fi hot path connect start failed: %s", esp_err_to_name(err));
+      xEventGroupSetBits(g_wifi_event_group, kWifiFailBit);
+    }
+  } else if (event_base == WIFI_EVENT &&
+             event_id == WIFI_EVENT_STA_CONNECTED) {
+    CaptureApIntoCache();
+    if (!g_wait_got_ip) {
+      xEventGroupSetBits(g_wifi_event_group, kWifiReadyBit);
+    }
+  } else if (event_base == WIFI_EVENT &&
+             event_id == WIFI_EVENT_STA_DISCONNECTED) {
+    auto const* event =
+        static_cast(event_data);
+    auto const reason = event != nullptr ? static_cast(event->reason) : -1;
+    g_wifi_disconnect_count.fetch_add(1, std::memory_order_relaxed);
+    if (reason >= 0 && reason <= 255) {
+      g_wifi_last_disconnect_reason.store(static_cast(reason),
+                                          std::memory_order_relaxed);
+    }
+
+    if (g_wifi_retry_count < g_max_wifi_retry) {
+      ++g_wifi_retry_count;
+      g_wifi_reconnect_count.fetch_add(1, std::memory_order_relaxed);
+      PS_LOGW("Wi-Fi hot path disconnected reason=%d; retry %d/%d", reason,
+              g_wifi_retry_count, g_max_wifi_retry);
+      auto err = esp_wifi_connect();
+      if (err != ESP_OK) {
+        PS_LOGE("Wi-Fi hot path reconnect failed: %s", esp_err_to_name(err));
+        xEventGroupSetBits(g_wifi_event_group, kWifiFailBit);
+      }
+    } else {
+      PS_LOGE("Wi-Fi hot path retry limit reached; reason=%d", reason);
+      xEventGroupSetBits(g_wifi_event_group, kWifiFailBit);
+    }
+  } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
+    auto* event = static_cast(event_data);
+    rtc_ip_info.ip = event->ip_info.ip;
+    rtc_ip_info.netmask = event->ip_info.netmask;
+    rtc_ip_info.gw = event->ip_info.gw;
+    address_is_valid = true;
+    CaptureApIntoCache();
+    PS_LOGI("Wi-Fi hot path GOT_IP after %d retries", g_wifi_retry_count);
+    xEventGroupSetBits(g_wifi_event_group, kWifiReadyBit);
+  }
+}
+
+void CleanupHotPathWifiRuntime() {
+  if (g_wifi_any_id_handler != nullptr) {
+    esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID,
+                                          g_wifi_any_id_handler);
+    g_wifi_any_id_handler = nullptr;
+  }
+
+  if (g_wifi_got_ip_handler != nullptr) {
+    esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP,
+                                          g_wifi_got_ip_handler);
+    g_wifi_got_ip_handler = nullptr;
+  }
+
+  if (g_wifi_started) {
+    auto err = esp_wifi_stop();
+    (void)err;
+    g_wifi_started = false;
+  }
+
+  if (g_wifi_initialized) {
+    auto err = esp_wifi_deinit();
+    (void)err;
+    g_wifi_initialized = false;
+  }
+
+  if (g_wifi_netif != nullptr) {
+    esp_netif_destroy_default_wifi(g_wifi_netif);
+    g_wifi_netif = nullptr;
+  }
+
+  if (g_wifi_event_group != nullptr) {
+    vEventGroupDelete(g_wifi_event_group);
+    g_wifi_event_group = nullptr;
+  }
+
+  g_wifi_retry_count = 0;
+
+  if (g_default_event_loop_created) {
+    esp_event_loop_delete_default();
+    g_default_event_loop_created = false;
+  }
+}
+
+bool StartWifiAttempt(bool use_bssid_cache, bool use_static_ip) {
+#  ifndef WIFI_SSID
+  return false;
+#  endif
+#  ifndef WIFI_PASSWORD
+  return false;
+#  endif
+
+  CleanupHotPathWifiRuntime();
+
+  g_wait_got_ip = !use_static_ip;
+  g_using_bssid_cache = use_bssid_cache;
+  g_max_wifi_retry = use_bssid_cache ? 1 : AETHER_PREPARED_HOT_WIFI_MAX_RETRY;
+
+  wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+  wifi_config_t wifi_config{};
+
+  auto err = nvs_flash_init();
+  if (err == ESP_ERR_NVS_NO_FREE_PAGES ||
+      err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+    ESP_ERROR_CHECK(nvs_flash_erase());
+    err = nvs_flash_init();
+  }
+  if (err != ESP_OK && err != ESP_ERR_NVS_NO_FREE_PAGES) {
+    return false;
+  }
+
+  (void)esp_netif_init();
+  err = esp_event_loop_create_default();
+  if (err == ESP_OK) {
+    g_default_event_loop_created = true;
+  } else if (err != ESP_ERR_INVALID_STATE) {
+    return false;
+  }
+
+  g_wifi_event_group = xEventGroupCreate();
+  if (g_wifi_event_group == nullptr) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  g_wifi_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
+  if (g_wifi_netif == nullptr) {
+    g_wifi_netif = esp_netif_create_default_wifi_sta();
+  }
+  if (g_wifi_netif == nullptr) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  if (use_static_ip && address_is_valid) {
+    esp_netif_dhcpc_stop(g_wifi_netif);
+    esp_netif_ip_info_t ip_info = {
+        .ip = {.addr = rtc_ip_info.ip.addr},
+        .netmask = {.addr = rtc_ip_info.netmask.addr},
+        .gw = {.addr = rtc_ip_info.gw.addr}};
+    esp_netif_set_ip_info(g_wifi_netif, &ip_info);
+  }
+
+  cfg.ampdu_rx_enable = 0;
+  cfg.ampdu_tx_enable = 0;
+
+  err = esp_wifi_init(&cfg);
+  if (err == ESP_ERR_WIFI_INIT_STATE) {
+    g_wifi_initialized = true;
+  } else if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  } else {
+    g_wifi_initialized = true;
+  }
+
+  err = esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID,
+                                            &WifiEventHandler, nullptr,
+                                            &g_wifi_any_id_handler);
+  if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  err = esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
+                                            &WifiEventHandler, nullptr,
+                                            &g_wifi_got_ip_handler);
+  if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  std::strncpy(reinterpret_cast(wifi_config.sta.ssid), WIFI_SSID,
+               sizeof(wifi_config.sta.ssid));
+  std::strncpy(reinterpret_cast(wifi_config.sta.password), WIFI_PASSWORD,
+               sizeof(wifi_config.sta.password));
+
+  if (use_bssid_cache && bs_is_valid) {
+    wifi_config.sta.scan_method = WIFI_FAST_SCAN;
+    wifi_config.sta.bssid_set = true;
+    wifi_config.sta.channel = base_station.target_channel;
+    std::memcpy(wifi_config.sta.bssid, base_station.target_bssid,
+                sizeof(base_station.target_bssid));
+  }
+
+  err = esp_wifi_set_mode(WIFI_MODE_STA);
+  if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  err = esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
+  if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  esp_wifi_set_protocol(
+      WIFI_IF_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
+
+  err = esp_wifi_start();
+  if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+  g_wifi_started = true;
+
+  (void)esp_wifi_set_max_tx_power(80);
+  (void)esp_wifi_set_ps(WIFI_PS_MAX_MODEM);
+
+  EventBits_t bits = xEventGroupWaitBits(
+      g_wifi_event_group, kWifiReadyBit | kWifiFailBit, pdFALSE, pdFALSE,
+      pdMS_TO_TICKS(AETHER_PREPARED_HOT_WIFI_TIMEOUT_MS));
+
+  esp_wifi_internal_set_fix_rate(WIFI_IF_STA, true, (wifi_phy_rate_t)0x0);
+
+  if ((bits & kWifiReadyBit) == 0) {
+    return false;
+  }
+
+  // After DHCP (cold) or whenever IP is known, refresh gateway MAC cache.
+  if (address_is_valid && g_wifi_netif != nullptr) {
+    if (!gateway_mac_valid || !use_static_ip) {
+      (void)ResolveAndCacheGatewayMac(g_wifi_netif);
+    }
+  }
+  return true;
+}
+
+bool EnsureWifiConnectedForHotPath() {
+  g_last_send_cache_flags = 0;
+
+  bool const have_bssid = bs_is_valid;
+  bool const have_ip = address_is_valid;
+
+  if (have_bssid || have_ip) {
+    if (StartWifiAttempt(have_bssid, have_ip)) {
+      if (have_bssid) {
+        g_last_send_cache_flags |=
+            static_cast(bench::CacheFlags::kUsedBssid);
+      }
+      if (have_ip) {
+        g_last_send_cache_flags |=
+            static_cast(bench::CacheFlags::kUsedStaticIp) |
+            static_cast(bench::CacheFlags::kDhcpSkipped);
+      }
+      (void)EnsureGatewayArpReady(g_wifi_netif);
+      return true;
+    }
+
+    // Cached BSSID/channel (and/or static IP) failed — invalidate and fall back.
+    CleanupHotPathWifiRuntime();
+    InvalidatePreparedWifiCache();
+    g_last_send_cache_flags =
+        static_cast(bench::CacheFlags::kWifiFallback);
+  }
+
+  if (!StartWifiAttempt(/*use_bssid_cache=*/false, /*use_static_ip=*/false)) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+  (void)EnsureGatewayArpReady(g_wifi_netif);
+  return true;
+}
+
+// Encode + socket/sendto/close only. Does not touch Wi-Fi lifetime.
+HotSendStatus EncodeAndUdpSend(ae::DataBuffer const& payload) {
+  if (!g_prepared_send_message_block.is_valid()) {
+    return HotSendStatus::kNoPreparedBlock;
+  }
+
+  if (g_prepared_send_message_block.Resolve()->message_left == 0) {
+    return HotSendStatus::kNonceExhausted;
+  }
+
+  ae::DataBuffer packet;
+  auto encode_result = ae::prepared_packet::EncodePacket(
+      g_prepared_send_message_block, payload, packet);
+
+  if (!encode_result) {
+    ClearPreparedSendBlock();
+    return HotSendStatus::kEncodeFailed;
+  }
+
+  auto const resolved_block = g_prepared_send_message_block.Resolve();
+  auto endpoint = resolved_block->endpoint;
+
+  sockaddr_storage dest_storage{};
+  socklen_t dest_len = 0;
+  if (!FillUdpDestination(endpoint, reinterpret_cast(&dest_storage),
+                          &dest_len)) {
+    return HotSendStatus::kSendFailed;
+  }
+
+  int sock = socket(
+      endpoint.address.Index() == ae::AddrVersion::kIpV6 ? AF_INET6 : AF_INET,
+      SOCK_DGRAM, IPPROTO_IP);
+  if (sock < 0) {
+    return HotSendStatus::kSendFailed;
+  }
+
+  auto sent = sendto(sock, packet.data(), packet.size(), 0,
+                     reinterpret_cast(&dest_storage), dest_len);
+  close(sock);
+
+  if (sent != static_cast(packet.size())) {
+    return HotSendStatus::kSendFailed;
+  }
+  return HotSendStatus::kSent;
+}
+
+#if defined(ESP_PLATFORM)
+// Late TX-done diagnostic state (fixed-size; no heap/log in callback).
+struct TxDoneDiag {
+  std::atomic total{0};
+  std::atomic success{0};
+  std::atomic failed{0};
+  std::atomic first_cb_us{0};
+  std::atomic first_success_us{0};
+  std::atomic first_failed_us{0};
+  std::atomic last_cb_us{0};
+  std::atomic first_status{-1};  // -1 none, 0 fail, 1 success
+};
+
+std::atomic g_fast_tx_done_seen{false};      // any callback
+std::atomic g_fast_tx_done_success{false};   // first success
+std::atomic g_fast_cb_count{0};
+std::atomic g_tx_wait_mode{0};  // FastTxDoneWaitMode as int
+TxDoneDiag g_tx_diag{};
+
+void ResetTxDoneDiag() {
+  g_tx_diag.total.store(0, std::memory_order_relaxed);
+  g_tx_diag.success.store(0, std::memory_order_relaxed);
+  g_tx_diag.failed.store(0, std::memory_order_relaxed);
+  g_tx_diag.first_cb_us.store(0, std::memory_order_relaxed);
+  g_tx_diag.first_success_us.store(0, std::memory_order_relaxed);
+  g_tx_diag.first_failed_us.store(0, std::memory_order_relaxed);
+  g_tx_diag.last_cb_us.store(0, std::memory_order_relaxed);
+  g_tx_diag.first_status.store(-1, std::memory_order_relaxed);
+  g_fast_tx_done_seen.store(false, std::memory_order_release);
+  g_fast_tx_done_success.store(false, std::memory_order_release);
+  g_fast_cb_count.store(0, std::memory_order_relaxed);
+}
+
+void FastTxDoneCb(std::uint8_t, std::uint8_t*, std::uint16_t*, bool txStatus) {
+  auto const now = esp_timer_get_time();
+  g_tx_diag.total.fetch_add(1, std::memory_order_relaxed);
+  g_fast_cb_count.fetch_add(1, std::memory_order_relaxed);
+  g_tx_diag.last_cb_us.store(now, std::memory_order_relaxed);
+
+  int expected_first = -1;
+  if (g_tx_diag.first_status.compare_exchange_strong(
+          expected_first, txStatus ? 1 : 0, std::memory_order_relaxed)) {
+    g_tx_diag.first_cb_us.store(now, std::memory_order_relaxed);
+  }
+
+  if (txStatus) {
+    g_tx_diag.success.fetch_add(1, std::memory_order_relaxed);
+    std::int64_t expected_fs = 0;
+    if (g_tx_diag.first_success_us.compare_exchange_strong(
+            expected_fs, now, std::memory_order_relaxed)) {
+      g_fast_tx_done_success.store(true, std::memory_order_release);
+    }
+  } else {
+    g_tx_diag.failed.fetch_add(1, std::memory_order_relaxed);
+    std::int64_t expected_ff = 0;
+    (void)g_tx_diag.first_failed_us.compare_exchange_strong(
+        expected_ff, now, std::memory_order_relaxed);
+  }
+
+  g_fast_tx_done_seen.store(true, std::memory_order_release);
+}
+
+void ResetFastTxDone() { ResetTxDoneDiag(); }
+
+static std::uint32_t DeltaOrMissing(std::int64_t abs_us,
+                                    std::int64_t sendto_return_us) {
+  if (abs_us <= 0) {
+    return 0xffffffffu;
+  }
+  auto const d = abs_us - sendto_return_us;
+  if (d < 0) {
+    return 0xffffffffu;
+  }
+  return d > 0xffffffffll ? 0xffffffffu : static_cast(d);
+}
+
+static void FillTxDoneTiming(FastSendResult* timing, std::int64_t sendto_return_us,
+                             bool condition_met, std::uint8_t after_success,
+                             FastTxDoneWaitMode wait_mode) {
+  if (timing == nullptr) {
+    return;
+  }
+  auto const total = g_tx_diag.total.load(std::memory_order_relaxed);
+  auto const success = g_tx_diag.success.load(std::memory_order_relaxed);
+  auto const failed = g_tx_diag.failed.load(std::memory_order_relaxed);
+  auto const first_st = g_tx_diag.first_status.load(std::memory_order_relaxed);
+  timing->diag_mode = static_cast(wait_mode);
+  timing->tx_cb_total = total > 255 ? 255 : static_cast(total);
+  timing->tx_cb_success =
+      success > 255 ? 255 : static_cast(success);
+  timing->tx_cb_failed = failed > 255 ? 255 : static_cast(failed);
+  timing->first_status =
+      first_st < 0 ? 0xff : static_cast(first_st);
+  timing->first_cb_delta_us = DeltaOrMissing(
+      g_tx_diag.first_cb_us.load(std::memory_order_relaxed), sendto_return_us);
+  timing->first_success_delta_us = DeltaOrMissing(
+      g_tx_diag.first_success_us.load(std::memory_order_relaxed),
+      sendto_return_us);
+  timing->first_failed_delta_us = DeltaOrMissing(
+      g_tx_diag.first_failed_us.load(std::memory_order_relaxed),
+      sendto_return_us);
+  timing->last_cb_delta_us = DeltaOrMissing(
+      g_tx_diag.last_cb_us.load(std::memory_order_relaxed), sendto_return_us);
+  timing->callbacks_after_success = after_success;
+  timing->cb_any = condition_met ? 1 : 0;
+  timing->cb_timeout = condition_met ? 0 : 1;
+  timing->cb_count = timing->tx_cb_total;
+  timing->cb_match = 0;
+}
+
+HotSendStatus EncodeAndUdpSendTracked(ae::DataBuffer const& payload) {
+  if (!g_prepared_send_message_block.is_valid()) {
+    return HotSendStatus::kNoPreparedBlock;
+  }
+  if (g_prepared_send_message_block.Resolve()->message_left == 0) {
+    return HotSendStatus::kNonceExhausted;
+  }
+
+  ae::DataBuffer packet;
+  auto encode_result = ae::prepared_packet::EncodePacket(
+      g_prepared_send_message_block, payload, packet);
+  if (!encode_result) {
+    ClearPreparedSendBlock();
+    return HotSendStatus::kEncodeFailed;
+  }
+
+  auto const resolved_block = g_prepared_send_message_block.Resolve();
+  auto endpoint = resolved_block->endpoint;
+
+  sockaddr_storage dest_storage{};
+  socklen_t dest_len = 0;
+  if (!FillUdpDestination(endpoint, reinterpret_cast(&dest_storage),
+                          &dest_len)) {
+    return HotSendStatus::kSendFailed;
+  }
+
+  int sock = socket(
+      endpoint.address.Index() == ae::AddrVersion::kIpV6 ? AF_INET6 : AF_INET,
+      SOCK_DGRAM, IPPROTO_IP);
+  if (sock < 0) {
+    return HotSendStatus::kSendFailed;
+  }
+
+  auto sent = sendto(sock, packet.data(), packet.size(), 0,
+                     reinterpret_cast(&dest_storage), dest_len);
+  close(sock);
+
+  if (sent != static_cast(packet.size())) {
+    return HotSendStatus::kSendFailed;
+  }
+  return HotSendStatus::kSent;
+}
+
+// Encode → socket → set_tx_done_cb → sendto → wait condition → unset → close.
+// MODE A (kFirstAny): wait first callback regardless of txStatus.
+// MODE B (kFirstSuccess): wait first txStatus==true, then 5 ms observe window.
+// Safety timeout: 100 ms from sendto return. Socket open until unregister.
+#if defined(ESP_PLATFORM)
+extern "C" esp_err_t esp_wifi_internal_set_retry_counter(uint8_t short_retry,
+                                                         uint8_t long_retry);
+#endif
+
+// Prefer: EncodePacket + socket, then optional MAC retry counter, then
+// ResetFastTxDone + tx-done cb + immediate sendto. No Wi-Fi ops between
+// set_retry_counter and sendto. CONTROL leaves set_mac_retry_limit=false.
+HotSendStatus EncodeAndUdpSendWithLateTxDone(ae::DataBuffer const& payload,
+                                             FastSendResult* timing,
+                                             FastPathConfig const& cfg) {
+  auto const wait_mode = cfg.tx_done_wait;
+  if (!g_prepared_send_message_block.is_valid()) {
+    return HotSendStatus::kNoPreparedBlock;
+  }
+  if (g_prepared_send_message_block.Resolve()->message_left == 0) {
+    return HotSendStatus::kNonceExhausted;
+  }
+
+  auto const t_encode0 = esp_timer_get_time();
+
+  ae::DataBuffer packet;
+  auto encode_result = ae::prepared_packet::EncodePacket(
+      g_prepared_send_message_block, payload, packet);
+  if (!encode_result) {
+    ClearPreparedSendBlock();
+    return HotSendStatus::kEncodeFailed;
+  }
+
+  auto const resolved_block = g_prepared_send_message_block.Resolve();
+  auto endpoint = resolved_block->endpoint;
+
+  sockaddr_storage dest_storage{};
+  socklen_t dest_len = 0;
+  if (!FillUdpDestination(endpoint, reinterpret_cast(&dest_storage),
+                          &dest_len)) {
+    return HotSendStatus::kSendFailed;
+  }
+
+  int sock = socket(
+      endpoint.address.Index() == ae::AddrVersion::kIpV6 ? AF_INET6 : AF_INET,
+      SOCK_DGRAM, IPPROTO_IP);
+  if (sock < 0) {
+    return HotSendStatus::kSendFailed;
+  }
+
+  if (timing != nullptr) {
+    timing->mac_retry_called = 0;
+    timing->mac_retry_set_rc = -1;
+    timing->mac_short_retry = cfg.mac_short_retry;
+    timing->mac_long_retry = cfg.mac_long_retry;
+    timing->retry_cfg_us = 0;
+  }
+  if (cfg.set_mac_retry_limit) {
+    auto const t_rc0 = esp_timer_get_time();
+    esp_err_t const rc = esp_wifi_internal_set_retry_counter(
+        cfg.mac_short_retry, cfg.mac_long_retry);
+    auto const t_rc1 = esp_timer_get_time();
+    if (timing != nullptr) {
+      timing->mac_retry_called = 1;
+      timing->mac_retry_set_rc = static_cast(rc);
+      auto const d = t_rc1 - t_rc0;
+      timing->retry_cfg_us = d < 0 ? 0 : static_cast(d);
+    }
+  }
+
+  ResetFastTxDone();
+  g_tx_wait_mode.store(static_cast(wait_mode), std::memory_order_relaxed);
+  (void)esp_wifi_set_tx_done_cb(&FastTxDoneCb);
+
+  auto sent = sendto(sock, packet.data(), packet.size(), 0,
+                     reinterpret_cast(&dest_storage), dest_len);
+  auto const t_send_ret = esp_timer_get_time();
+  if (timing != nullptr) {
+    auto const es = t_send_ret - t_encode0;
+    timing->encode_send_us =
+        es < 0 ? 0 : static_cast(es);
+  }
+
+  if (sent != static_cast(packet.size())) {
+    (void)esp_wifi_set_tx_done_cb(nullptr);
+    close(sock);
+    return HotSendStatus::kSendFailed;
+  }
+
+  constexpr std::int64_t kMaxUs = 100000;
+  constexpr std::int64_t kObserveUs = 5000;
+  bool condition_met = false;
+  std::uint32_t total_at_success = 0;
+
+  auto condition_ready = [&]() -> bool {
+    if (wait_mode == FastTxDoneWaitMode::kFirstSuccess) {
+      return g_fast_tx_done_success.load(std::memory_order_acquire);
+    }
+    return g_fast_tx_done_seen.load(std::memory_order_acquire);
+  };
+
+  while ((esp_timer_get_time() - t_send_ret) < kMaxUs) {
+    if (condition_ready()) {
+      condition_met = true;
+      break;
+    }
+    vTaskDelay(pdMS_TO_TICKS(1));
+  }
+
+  if (condition_met && wait_mode == FastTxDoneWaitMode::kFirstSuccess) {
+    total_at_success = g_tx_diag.total.load(std::memory_order_relaxed);
+    auto const t_obs0 = esp_timer_get_time();
+    while ((esp_timer_get_time() - t_obs0) < kObserveUs) {
+      vTaskDelay(pdMS_TO_TICKS(1));
+    }
+  }
+
+  auto const t_cb_done = esp_timer_get_time();
+  (void)esp_wifi_set_tx_done_cb(nullptr);
+  close(sock);
+
+  std::uint8_t after_success = 0;
+  if (condition_met && wait_mode == FastTxDoneWaitMode::kFirstSuccess) {
+    auto const total_end = g_tx_diag.total.load(std::memory_order_relaxed);
+    auto const delta =
+        total_end > total_at_success ? (total_end - total_at_success) : 0u;
+    after_success = delta > 255 ? 255 : static_cast(delta);
+  }
+
+  if (timing != nullptr) {
+    auto const wait = t_cb_done - t_send_ret;
+    timing->tx_done_wait_us =
+        wait < 0 ? 0 : static_cast(wait);
+    FillTxDoneTiming(timing, t_send_ret, condition_met, after_success,
+                     wait_mode);
+  }
+  return HotSendStatus::kSent;
+}
+#endif
+
+#else
+
+bool EnsureWifiConnectedForHotPath() { return true; }
+
+void CleanupHotPathWifiRuntime() {}
+
+HotSendStatus EncodeAndUdpSend(ae::DataBuffer const&) {
+  return HotSendStatus::kUnsupported;
+}
+
+#endif
+
+}  // namespace
+
+std::string_view ToString(HotSendStatus status) {
+  switch (status) {
+    case HotSendStatus::kSent:
+      return "sent";
+    case HotSendStatus::kNoPreparedBlock:
+      return "no-prepared-block";
+    case HotSendStatus::kNonceExhausted:
+      return "nonce-exhausted";
+    case HotSendStatus::kEncodeFailed:
+      return "encode-failed";
+    case HotSendStatus::kPersistFailed:
+      return "persist-failed";
+    case HotSendStatus::kWifiFailed:
+      return "wifi-failed";
+    case HotSendStatus::kSendFailed:
+      return "send-failed";
+    case HotSendStatus::kUnsupported:
+      return "unsupported";
+  }
+  return "unknown";
+}
+
+std::uint8_t LastSendCacheFlags() { return g_last_send_cache_flags; }
+
+struct Header {
+  AE_REFLECT_MEMBERS(root_code, size, dev_code)
+  std::uint8_t const root_code = 0x3;
+  std::uint8_t const size = sizeof(std::uint8_t) + sizeof(std::int16_t);
+  std::uint8_t const dev_code = 0x10;
+};
+
+ae::DataBuffer MakeTemperaturePayload(std::string const& temperature) {
+  static constexpr auto header = Header{};
+
+  auto message = ae::DataBuffer{};
+  message.reserve(sizeof(header) + temperature.size());
+  {
+    auto archive =
+        ae::seri::BinaryArchive{ae::seri::BinaryVectorBuffer<>{message}};
+    archive.Save(header);
+    archive.Save(temperature);
+  }
+  return message;
+}
+
+bool HasPreparedSendBlock() { return g_prepared_send_message_block.is_valid(); }
+
+std::uint32_t PreparedMessageLeft() {
+  if (!g_prepared_send_message_block.is_valid()) {
+    return 0;
+  }
+  return g_prepared_send_message_block.Resolve()->message_left;
+}
+
+void ClearPreparedSendBlock() {
+  g_prepared_send_message_block.raw.magic = {};
+}
+
+bool ExportPreparedSendBlock(ae::Client::ptr const& client, ae::Uid destination,
+                             std::size_t reserve_message_count) {
+  auto prep_res = ae::prepared_packet::PrepareSendMessageBlock(
+      client, destination, reserve_message_count);
+
+  if (!prep_res) {
+    PS_LOGE("PrepareSendMessage failed ec=%d", prep_res.error().ec);
+    return false;
+  }
+
+  g_prepared_send_message_block = std::move(prep_res).value();
+  return true;
+}
+
+ae::DataBuffer MakeBenchPayload(std::string_view kind, int sequence) {
+  auto text = ae::Format("{}:{}", kind, sequence);
+  return ae::DataBuffer{text.begin(), text.end()};
+}
+
+#if defined(ESP_PLATFORM)
+void InvalidatePreparedWifiCache() {
+  address_is_valid = false;
+  bs_is_valid = false;
+  gateway_mac_valid = false;
+  std::memset(&rtc_ip_info, 0, sizeof(rtc_ip_info));
+  std::memset(&base_station, 0, sizeof(base_station));
+  std::memset(gateway_mac, 0, sizeof(gateway_mac));
+}
+
+bool CapturePreparedWifiCacheFromActiveConnection() {
+  esp_netif_t* netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
+  if (netif == nullptr) {
+    return false;
+  }
+
+  esp_netif_ip_info_t ip_info{};
+  if (esp_netif_get_ip_info(netif, &ip_info) != ESP_OK ||
+      ip_info.ip.addr == 0) {
+    return false;
+  }
+
+  rtc_ip_info = ip_info;
+  address_is_valid = true;
+  CaptureApIntoCache();
+  if (!bs_is_valid) {
+    return false;
+  }
+
+  // Prefer existing ARP entry from the live FULL session; request if needed.
+  if (!ResolveAndCacheGatewayMac(netif)) {
+    // Still keep BSSID/IP cache; prepared path can fall back to ARP wait.
+    gateway_mac_valid = false;
+  }
+  return true;
+}
+
+void ReleaseFullAetherWifiForHotPath() {
+  auto err = esp_wifi_stop();
+  (void)err;
+  err = esp_wifi_deinit();
+  (void)err;
+  if (esp_netif_t* netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
+      netif != nullptr) {
+    esp_netif_destroy(netif);
+  }
+  esp_netif_deinit();
+  err = esp_event_loop_delete_default();
+  (void)err;
+  vTaskDelay(pdMS_TO_TICKS(50));
+}
+#endif
+
+HotSendStatus SendPreparedOnce(ae::DataBuffer const& payload) {
+#if defined(ESP_PLATFORM)
+  if (!g_prepared_send_message_block.is_valid()) {
+    return HotSendStatus::kNoPreparedBlock;
+  }
+
+  if (g_prepared_send_message_block.Resolve()->message_left == 0) {
+    return HotSendStatus::kNonceExhausted;
+  }
+
+  // Connect BEFORE EncodePacket so a failed Wi-Fi attempt does not burn a nonce.
+  if (!EnsureWifiConnectedForHotPath()) {
+    return HotSendStatus::kWifiFailed;
+  }
+
+  auto fail_after_wifi = ae_defer_at[] { CleanupHotPathWifiRuntime(); };
+
+  auto const status = EncodeAndUdpSend(payload);
+  if (status != HotSendStatus::kSent) {
+    return status;
+  }
+
+#  ifndef AETHER_PREPARED_POST_SEND_HOLD_MS
+#    define AETHER_PREPARED_POST_SEND_HOLD_MS 300
+#  endif
+  std::this_thread::sleep_for(
+      std::chrono::milliseconds(AETHER_PREPARED_POST_SEND_HOLD_MS));
+
+  return HotSendStatus::kSent;
+#else
+  (void)payload;
+  return HotSendStatus::kUnsupported;
+#endif
+}
+
+#if defined(ESP_PLATFORM)
+void EndPreparedWifiSession();
+
+bool BeginPreparedWifiSession() {
+  if (g_prepared_wifi_session_active) {
+    EndPreparedWifiSession();
+  }
+  g_last_wifi_session_start_us = 0;
+  auto const t0 = esp_timer_get_time();
+  if (!EnsureWifiConnectedForHotPath()) {
+    return false;
+  }
+  auto const elapsed = esp_timer_get_time() - t0;
+  g_last_wifi_session_start_us =
+      elapsed < 0 ? 0
+                  : static_cast(
+                        elapsed > static_cast(
+                                      std::numeric_limits::max())
+                            ? std::numeric_limits::max()
+                            : elapsed);
+  g_prepared_wifi_session_active = true;
+  return true;
+}
+
+HotSendStatus SendPreparedPacketOnActiveWifi(ae::DataBuffer const& payload) {
+  if (!g_prepared_wifi_session_active) {
+    return HotSendStatus::kWifiFailed;
+  }
+  return EncodeAndUdpSend(payload);
+}
+
+void EndPreparedWifiSession() {
+  CleanupHotPathWifiRuntime();
+  g_prepared_wifi_session_active = false;
+}
+
+std::uint32_t LastWifiSessionStartUs() { return g_last_wifi_session_start_us; }
+
+namespace {
+
+struct BisectFactorConfig {
+  bool use_bssid{false};
+  bool use_channel{false};
+  bool use_fast_scan{false};
+  bool use_static_ip{false};
+  bool use_static_arp{false};
+  bool ps_max_modem{false};
+  bool ampdu_off{false};
+  bool fixed_1m{false};
+  std::uint8_t pre_delay_ms{200};
+};
+
+BisectWifiCacheSnapshot g_bisect_cache{};
+std::uint8_t g_bisect_actual_channel = 0;
+
+BisectFactorConfig MakeBisectConfig(WifiBisectVariant variant) {
+  BisectFactorConfig c{};
+  switch (variant) {
+    case WifiBisectVariant::kB0:
+      c.pre_delay_ms = 0;
+      break;
+    case WifiBisectVariant::kB1:
+      break;
+    case WifiBisectVariant::kC1:
+      c.use_bssid = true;
+      break;
+    case WifiBisectVariant::kC2:
+      c.use_channel = true;
+      break;
+    case WifiBisectVariant::kC3:
+      c.use_bssid = true;
+      c.use_channel = true;
+      break;
+    case WifiBisectVariant::kC4:
+      c.use_fast_scan = true;
+      break;
+    case WifiBisectVariant::kC5:
+      c.use_static_ip = true;
+      break;
+    case WifiBisectVariant::kC6:
+      c.use_static_ip = true;
+      c.use_static_arp = true;
+      break;
+    case WifiBisectVariant::kC7:
+      c.use_bssid = true;
+      c.use_static_ip = true;
+      break;
+    case WifiBisectVariant::kC8:
+      c.use_channel = true;
+      c.use_static_ip = true;
+      break;
+    case WifiBisectVariant::kP1:
+      c.ps_max_modem = true;
+      break;
+    case WifiBisectVariant::kP2:
+      c.ampdu_off = true;
+      break;
+    case WifiBisectVariant::kP3:
+      c.fixed_1m = true;
+      break;
+    case WifiBisectVariant::kCount:
+      break;
+  }
+  return c;
+}
+
+std::uint8_t BisectFactorBitsOf(BisectFactorConfig const& c) {
+  using F = bench::BisectFactorBits;
+  std::uint8_t bits = 0;
+  if (c.use_bssid) {
+    bits |= static_cast(F::kBssid);
+  }
+  if (c.use_channel) {
+    bits |= static_cast(F::kChannel);
+  }
+  if (c.use_fast_scan) {
+    bits |= static_cast(F::kFastScan);
+  }
+  if (c.use_static_ip) {
+    bits |= static_cast(F::kStaticIp);
+  }
+  if (c.use_static_arp) {
+    bits |= static_cast(F::kStaticArp);
+  }
+  if (c.ps_max_modem) {
+    bits |= static_cast(F::kPsMaxModem);
+  }
+  if (c.ampdu_off) {
+    bits |= static_cast(F::kAmpduOff);
+  }
+  if (c.fixed_1m) {
+    bits |= static_cast(F::kFixed1M);
+  }
+  return bits;
+}
+
+std::uint8_t ReadActualChannel() {
+  wifi_ap_record_t ap_info{};
+  if (esp_wifi_sta_get_ap_info(&ap_info) != ESP_OK) {
+    return 0;
+  }
+  return ap_info.primary;
+}
+
+bool StartBisectWifi(BisectFactorConfig const& cfg) {
+#  ifndef WIFI_SSID
+  return false;
+#  endif
+#  ifndef WIFI_PASSWORD
+  return false;
+#  endif
+
+  CleanupHotPathWifiRuntime();
+  g_bisect_actual_channel = 0;
+
+  bool const need_static_ip = cfg.use_static_ip && g_bisect_cache.valid_ip;
+  g_wait_got_ip = !need_static_ip;
+  g_using_bssid_cache = cfg.use_bssid && g_bisect_cache.valid_bssid;
+  g_max_wifi_retry = AETHER_PREPARED_HOT_WIFI_MAX_RETRY;
+
+  wifi_init_config_t wifi_init_cfg = WIFI_INIT_CONFIG_DEFAULT();
+  if (cfg.ampdu_off) {
+    wifi_init_cfg.ampdu_rx_enable = 0;
+    wifi_init_cfg.ampdu_tx_enable = 0;
+  }
+
+  auto err = nvs_flash_init();
+  if (err == ESP_ERR_NVS_NO_FREE_PAGES ||
+      err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+    ESP_ERROR_CHECK(nvs_flash_erase());
+    err = nvs_flash_init();
+  }
+  if (err != ESP_OK && err != ESP_ERR_NVS_NO_FREE_PAGES) {
+    return false;
+  }
+
+  (void)esp_netif_init();
+  err = esp_event_loop_create_default();
+  if (err == ESP_OK) {
+    g_default_event_loop_created = true;
+  } else if (err != ESP_ERR_INVALID_STATE) {
+    return false;
+  }
+
+  g_wifi_event_group = xEventGroupCreate();
+  if (g_wifi_event_group == nullptr) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  g_wifi_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
+  if (g_wifi_netif == nullptr) {
+    g_wifi_netif = esp_netif_create_default_wifi_sta();
+  }
+  if (g_wifi_netif == nullptr) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  if (need_static_ip) {
+    esp_netif_dhcpc_stop(g_wifi_netif);
+    esp_netif_ip_info_t ip_info = {
+        .ip = {.addr = g_bisect_cache.ip},
+        .netmask = {.addr = g_bisect_cache.netmask},
+        .gw = {.addr = g_bisect_cache.gateway}};
+    esp_netif_set_ip_info(g_wifi_netif, &ip_info);
+    rtc_ip_info = ip_info;
+    address_is_valid = true;
+  }
+
+  err = esp_wifi_init(&wifi_init_cfg);
+  if (err == ESP_ERR_WIFI_INIT_STATE) {
+    g_wifi_initialized = true;
+  } else if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  } else {
+    g_wifi_initialized = true;
+  }
+
+  err = esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID,
+                                            &WifiEventHandler, nullptr,
+                                            &g_wifi_any_id_handler);
+  if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  err = esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
+                                            &WifiEventHandler, nullptr,
+                                            &g_wifi_got_ip_handler);
+  if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  wifi_config_t wifi_config{};
+  std::strncpy(reinterpret_cast(wifi_config.sta.ssid), WIFI_SSID,
+               sizeof(wifi_config.sta.ssid));
+  std::strncpy(reinterpret_cast(wifi_config.sta.password), WIFI_PASSWORD,
+               sizeof(wifi_config.sta.password));
+  wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA3_PSK;
+
+  if (cfg.use_fast_scan) {
+    wifi_config.sta.scan_method = WIFI_FAST_SCAN;
+  }
+
+  if (cfg.use_bssid && g_bisect_cache.valid_bssid) {
+    wifi_config.sta.bssid_set = true;
+    std::memcpy(wifi_config.sta.bssid, g_bisect_cache.bssid,
+                sizeof(wifi_config.sta.bssid));
+  }
+
+  if (cfg.use_channel && g_bisect_cache.valid_bssid) {
+    wifi_config.sta.channel = g_bisect_cache.channel;
+  }
+
+  err = esp_wifi_set_mode(WIFI_MODE_STA);
+  if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  err = esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
+  if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  (void)esp_wifi_set_protocol(
+      WIFI_IF_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
+
+  err = esp_wifi_start();
+  if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+  g_wifi_started = true;
+
+  (void)esp_wifi_set_max_tx_power(80);
+  (void)esp_wifi_set_ps(cfg.ps_max_modem ? WIFI_PS_MAX_MODEM : WIFI_PS_NONE);
+
+  EventBits_t bits = xEventGroupWaitBits(
+      g_wifi_event_group, kWifiReadyBit | kWifiFailBit, pdFALSE, pdFALSE,
+      pdMS_TO_TICKS(AETHER_PREPARED_HOT_WIFI_TIMEOUT_MS));
+
+  if (cfg.fixed_1m) {
+    (void)esp_wifi_internal_set_fix_rate(WIFI_IF_STA, true,
+                                         WIFI_PHY_RATE_1M_L);
+  }
+
+  if ((bits & kWifiReadyBit) == 0) {
+    return false;
+  }
+
+  g_bisect_actual_channel = ReadActualChannel();
+
+  if (cfg.use_static_arp && g_bisect_cache.valid_gw_mac &&
+      g_bisect_cache.valid_ip) {
+    std::memcpy(gateway_mac, g_bisect_cache.gw_mac, sizeof(gateway_mac));
+    gateway_mac_valid = true;
+    (void)InstallStaticGatewayArp();
+  }
+
+  return true;
+}
+
+std::uint8_t ReadNegotiatedAuth() {
+  wifi_ap_record_t ap_info{};
+  if (esp_wifi_sta_get_ap_info(&ap_info) != ESP_OK) {
+    return 0;
+  }
+  return static_cast(ap_info.authmode);
+}
+
+bool StartFastWifi(FastPathConfig const& cfg,
+                   BisectWifiCacheSnapshot const* cache_override) {
+#  ifndef WIFI_SSID
+  return false;
+#  endif
+#  ifndef WIFI_PASSWORD
+  return false;
+#  endif
+
+  BisectWifiCacheSnapshot const& cache =
+      cache_override != nullptr ? *cache_override : g_bisect_cache;
+
+  CleanupHotPathWifiRuntime();
+  g_bisect_actual_channel = 0;
+  g_wifi_disconnect_count.store(0, std::memory_order_relaxed);
+  g_wifi_last_disconnect_reason.store(0, std::memory_order_relaxed);
+  g_wifi_reconnect_count.store(0, std::memory_order_relaxed);
+
+  bool const need_static_ip = cfg.use_static_ip && cache.valid_ip;
+  g_wait_got_ip = !need_static_ip;
+  g_using_bssid_cache = cfg.use_bssid && cache.valid_bssid;
+  g_max_wifi_retry = cfg.retry_max;
+
+  wifi_init_config_t wifi_init_cfg = WIFI_INIT_CONFIG_DEFAULT();
+  if (cfg.ampdu_tx_off) {
+    wifi_init_cfg.ampdu_tx_enable = 0;
+  }
+  if (cfg.ampdu_rx_off) {
+    wifi_init_cfg.ampdu_rx_enable = 0;
+    wifi_init_cfg.rx_ba_win = 0;
+  } else if (cfg.rx_ba_win != 0) {
+    wifi_init_cfg.rx_ba_win = cfg.rx_ba_win;
+  }
+  if (cfg.amsdu_tx_off) {
+    wifi_init_cfg.amsdu_tx_enable = 0;
+  }
+  wifi_init_cfg.nvs_enable = cfg.wifi_nvs_enable ? 1 : 0;
+  if (cfg.static_rx_buf_num != 0) {
+    wifi_init_cfg.static_rx_buf_num = cfg.static_rx_buf_num;
+  }
+  if (cfg.dynamic_rx_buf_num != 0) {
+    wifi_init_cfg.dynamic_rx_buf_num = cfg.dynamic_rx_buf_num;
+  }
+  if (cfg.dynamic_tx_buf_num != 0) {
+    wifi_init_cfg.dynamic_tx_buf_num = cfg.dynamic_tx_buf_num;
+  }
+
+  auto const heap_before = esp_get_free_heap_size();
+  auto const t_wifi_init0 = esp_timer_get_time();
+
+  auto err = nvs_flash_init();
+  if (err == ESP_ERR_NVS_NO_FREE_PAGES ||
+      err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
+    ESP_ERROR_CHECK(nvs_flash_erase());
+    err = nvs_flash_init();
+  }
+  if (err != ESP_OK && err != ESP_ERR_NVS_NO_FREE_PAGES) {
+    return false;
+  }
+
+  (void)esp_netif_init();
+  err = esp_event_loop_create_default();
+  if (err == ESP_OK) {
+    g_default_event_loop_created = true;
+  } else if (err != ESP_ERR_INVALID_STATE) {
+    return false;
+  }
+
+  g_wifi_event_group = xEventGroupCreate();
+  if (g_wifi_event_group == nullptr) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  g_wifi_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
+  if (g_wifi_netif == nullptr) {
+    g_wifi_netif = esp_netif_create_default_wifi_sta();
+  }
+  if (g_wifi_netif == nullptr) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  if (need_static_ip) {
+    esp_netif_dhcpc_stop(g_wifi_netif);
+    esp_netif_ip_info_t ip_info = {
+        .ip = {.addr = cache.ip},
+        .netmask = {.addr = cache.netmask},
+        .gw = {.addr = cache.gateway}};
+    esp_netif_set_ip_info(g_wifi_netif, &ip_info);
+    rtc_ip_info = ip_info;
+    address_is_valid = true;
+  }
+
+  err = esp_wifi_init(&wifi_init_cfg);
+  auto const t_wifi_init1 = esp_timer_get_time();
+  g_last_wifi_init_us =
+      (t_wifi_init1 > t_wifi_init0)
+          ? static_cast(t_wifi_init1 - t_wifi_init0)
+          : 0;
+  g_last_heap_before_wifi = heap_before;
+  g_last_heap_after_wifi = esp_get_free_heap_size();
+  if (err == ESP_ERR_WIFI_INIT_STATE) {
+    g_wifi_initialized = true;
+  } else if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  } else {
+    g_wifi_initialized = true;
+  }
+
+  if (cfg.wifi_storage_ram) {
+    (void)esp_wifi_set_storage(WIFI_STORAGE_RAM);
+  }
+
+  err = esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID,
+                                            &WifiEventHandler, nullptr,
+                                            &g_wifi_any_id_handler);
+  if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  err = esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP,
+                                            &WifiEventHandler, nullptr,
+                                            &g_wifi_got_ip_handler);
+  if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  wifi_config_t wifi_config{};
+  std::strncpy(reinterpret_cast(wifi_config.sta.ssid), WIFI_SSID,
+               sizeof(wifi_config.sta.ssid));
+  std::strncpy(reinterpret_cast(wifi_config.sta.password), WIFI_PASSWORD,
+               sizeof(wifi_config.sta.password));
+
+  wifi_config.sta.pmf_cfg.capable = true;
+  if (cfg.auth == FastAuthMode::kWpa2) {
+    wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA2_PSK;
+    wifi_config.sta.sae_pwe_h2e = WPA3_SAE_PWE_UNSPECIFIED;
+    wifi_config.sta.pmf_cfg.required = false;
+  } else if (cfg.auth == FastAuthMode::kWpa3H2eOnly) {
+    wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA3_PSK;
+    wifi_config.sta.sae_pwe_h2e = WPA3_SAE_PWE_HASH_TO_ELEMENT;
+    wifi_config.sta.pmf_cfg.required = true;
+  } else {
+    wifi_config.sta.threshold.authmode = WIFI_AUTH_WPA3_PSK;
+    wifi_config.sta.sae_pwe_h2e = WPA3_SAE_PWE_BOTH;
+    wifi_config.sta.pmf_cfg.required = true;
+  }
+
+  if (cfg.use_fast_scan) {
+    wifi_config.sta.scan_method = WIFI_FAST_SCAN;
+  }
+
+  if (cfg.use_bssid && cache.valid_bssid) {
+    wifi_config.sta.bssid_set = true;
+    std::memcpy(wifi_config.sta.bssid, cache.bssid,
+                sizeof(wifi_config.sta.bssid));
+  }
+
+  if (cfg.use_channel && cache.channel != 0) {
+    wifi_config.sta.channel = cache.channel;
+  }
+
+  err = esp_wifi_set_mode(WIFI_MODE_STA);
+  if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  err = esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
+  if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+
+  (void)esp_wifi_set_protocol(
+      WIFI_IF_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
+
+  err = esp_wifi_start();
+  if (err != ESP_OK) {
+    CleanupHotPathWifiRuntime();
+    return false;
+  }
+  g_wifi_started = true;
+
+  (void)esp_wifi_set_max_tx_power(80);
+  (void)esp_wifi_set_ps(WIFI_PS_NONE);
+  if (cfg.force_ht20) {
+    (void)esp_wifi_set_bandwidth(WIFI_IF_STA, WIFI_BW20);
+  }
+  if (cfg.dynamic_cs == 0) {
+    (void)esp_wifi_set_dynamic_cs(false);
+  } else if (cfg.dynamic_cs == 1) {
+    (void)esp_wifi_set_dynamic_cs(true);
+  }
+  // TX-done callback is installed immediately before sendto() for callback
+  // post modes — never here (association / PRE would fire unrelated TX).
+
+  EventBits_t bits = xEventGroupWaitBits(
+      g_wifi_event_group, kWifiReadyBit | kWifiFailBit, pdFALSE, pdFALSE,
+      pdMS_TO_TICKS(AETHER_PREPARED_HOT_WIFI_TIMEOUT_MS));
+
+  if ((bits & kWifiReadyBit) == 0) {
+    return false;
+  }
+
+  g_bisect_actual_channel = ReadActualChannel();
+
+  if (cfg.use_static_arp && cache.valid_gw_mac && cache.valid_ip) {
+    std::memcpy(gateway_mac, cache.gw_mac, sizeof(gateway_mac));
+    gateway_mac_valid = true;
+    (void)InstallStaticGatewayArp();
+  }
+
+  return true;
+}
+
+}  // namespace
+
+bool FreezeBisectWifiCacheFromActiveConnection() {
+  g_bisect_cache = {};
+  esp_netif_t* netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
+  if (netif == nullptr) {
+    return false;
+  }
+
+  esp_netif_ip_info_t ip_info{};
+  if (esp_netif_get_ip_info(netif, &ip_info) != ESP_OK ||
+      ip_info.ip.addr == 0) {
+    return false;
+  }
+
+  wifi_ap_record_t ap_info{};
+  if (esp_wifi_sta_get_ap_info(&ap_info) != ESP_OK) {
+    return false;
+  }
+
+  g_bisect_cache.valid_ip = true;
+  g_bisect_cache.ip = ip_info.ip.addr;
+  g_bisect_cache.netmask = ip_info.netmask.addr;
+  g_bisect_cache.gateway = ip_info.gw.addr;
+
+  g_bisect_cache.valid_bssid = true;
+  g_bisect_cache.channel = ap_info.primary;
+  std::memcpy(g_bisect_cache.bssid, ap_info.bssid,
+              sizeof(g_bisect_cache.bssid));
+
+  // Also refresh production RTC cache helpers used by ARP install.
+  rtc_ip_info = ip_info;
+  address_is_valid = true;
+  CaptureApIntoCache();
+  if (ResolveAndCacheGatewayMac(netif)) {
+    g_bisect_cache.valid_gw_mac = true;
+    std::memcpy(g_bisect_cache.gw_mac, gateway_mac,
+                sizeof(g_bisect_cache.gw_mac));
+  }
+  return true;
+}
+
+BisectWifiCacheSnapshot GetBisectWifiCacheSnapshot() { return g_bisect_cache; }
+
+BisectSendResult SendPreparedOnceWithBisectFactor(
+    WifiBisectVariant variant, ae::DataBuffer const& payload) {
+  BisectSendResult out{};
+  auto const cfg = MakeBisectConfig(variant);
+  out.pre_delay_ms = cfg.pre_delay_ms;
+  out.factor_bits = BisectFactorBitsOf(cfg);
+  out.requested_channel =
+      (cfg.use_channel && g_bisect_cache.valid_bssid) ? g_bisect_cache.channel
+                                                      : 0;
+
+  if (!g_prepared_send_message_block.is_valid()) {
+    out.status = HotSendStatus::kNoPreparedBlock;
+    return out;
+  }
+  if (g_prepared_send_message_block.Resolve()->message_left == 0) {
+    out.status = HotSendStatus::kNonceExhausted;
+    return out;
+  }
+
+  auto const t0 = esp_timer_get_time();
+  if (!StartBisectWifi(cfg)) {
+    CleanupHotPathWifiRuntime();
+    out.status = HotSendStatus::kWifiFailed;
+    out.actual_channel = g_bisect_actual_channel;
+    auto const elapsed = esp_timer_get_time() - t0;
+    out.total_us = elapsed < 0 ? 0 : static_cast(elapsed);
+    return out;
+  }
+
+  out.status_flags |=
+      static_cast(bench::BisectStatusBits::kWifiReady);
+  out.actual_channel = g_bisect_actual_channel;
+  if (out.requested_channel != 0 &&
+      out.requested_channel == out.actual_channel) {
+    out.status_flags |=
+        static_cast(bench::BisectStatusBits::kChannelMatch);
+  }
+
+  if (cfg.pre_delay_ms > 0) {
+    vTaskDelay(pdMS_TO_TICKS(cfg.pre_delay_ms));
+  }
+
+  auto const encode_status = EncodeAndUdpSend(payload);
+  if (encode_status == HotSendStatus::kSent) {
+    out.status_flags |=
+        static_cast(bench::BisectStatusBits::kEncodeOk) |
+        static_cast(bench::BisectStatusBits::kSendtoOk);
+  } else if (encode_status == HotSendStatus::kEncodeFailed) {
+    // encode failed after wifi ready
+  } else if (encode_status == HotSendStatus::kSendFailed) {
+    out.status_flags |=
+        static_cast(bench::BisectStatusBits::kEncodeOk);
+  }
+
+#  ifndef AETHER_PREPARED_POST_SEND_HOLD_MS
+#    define AETHER_PREPARED_POST_SEND_HOLD_MS 300
+#  endif
+  if (encode_status == HotSendStatus::kSent) {
+    vTaskDelay(pdMS_TO_TICKS(AETHER_PREPARED_POST_SEND_HOLD_MS));
+  }
+
+  CleanupHotPathWifiRuntime();
+
+  auto const elapsed = esp_timer_get_time() - t0;
+  out.total_us = elapsed < 0 ? 0 : static_cast(elapsed);
+  out.status = encode_status;
+  return out;
+}
+
+FastSendResult SendPreparedOnceWithFastPath(
+    FastPathConfig const& cfg, ae::DataBuffer const& payload,
+    BisectWifiCacheSnapshot const* wifi_cache) {
+  FastSendResult out{};
+  BisectWifiCacheSnapshot const& cache =
+      wifi_cache != nullptr ? *wifi_cache : g_bisect_cache;
+  out.requested_channel =
+      (cfg.use_channel && cache.channel != 0) ? cache.channel : 0;
+
+  if (!g_prepared_send_message_block.is_valid()) {
+    out.status = HotSendStatus::kNoPreparedBlock;
+    return out;
+  }
+  if (g_prepared_send_message_block.Resolve()->message_left == 0) {
+    out.status = HotSendStatus::kNonceExhausted;
+    return out;
+  }
+
+  auto const t0 = esp_timer_get_time();
+  if (!StartFastWifi(cfg, wifi_cache)) {
+    CleanupHotPathWifiRuntime();
+    out.status = HotSendStatus::kWifiFailed;
+    out.actual_channel = g_bisect_actual_channel;
+    out.negotiated_auth = ReadNegotiatedAuth();
+    auto const elapsed = esp_timer_get_time() - t0;
+    out.cycle_us = elapsed < 0 ? 0 : static_cast(elapsed);
+    out.connect_us = out.cycle_us;
+    return out;
+  }
+
+  auto const t_ready = esp_timer_get_time();
+  {
+    auto const elapsed = t_ready - t0;
+    out.connect_us = elapsed < 0 ? 0 : static_cast(elapsed);
+  }
+  out.wifi_init_us = g_last_wifi_init_us;
+  out.heap_before_wifi = g_last_heap_before_wifi;
+  out.heap_after_wifi = g_last_heap_after_wifi;
+  out.status_flags |=
+      static_cast(bench::BisectStatusBits::kWifiReady);
+  out.actual_channel = g_bisect_actual_channel;
+  out.negotiated_auth = ReadNegotiatedAuth();
+  {
+    auto const d = g_wifi_disconnect_count.load(std::memory_order_relaxed);
+    out.disconnect_count = d > 255 ? 255 : static_cast(d);
+  }
+  out.last_disconnect_reason =
+      g_wifi_last_disconnect_reason.load(std::memory_order_relaxed);
+  {
+    auto const r = g_wifi_reconnect_count.load(std::memory_order_relaxed);
+    out.reconnect_count = r > 255 ? 255 : static_cast(r);
+  }
+
+  {
+    wifi_ap_record_t ap{};
+    if (esp_wifi_sta_get_ap_info(&ap) == ESP_OK) {
+      out.rssi = ap.rssi;
+      out.ap_primary = ap.primary;
+    }
+  }
+
+  if (cfg.pre_delay_ms > 0) {
+    vTaskDelay(pdMS_TO_TICKS(cfg.pre_delay_ms));
+  }
+
+  HotSendStatus encode_status = HotSendStatus::kWifiFailed;
+  auto const t_post0 = esp_timer_get_time();
+  if (cfg.post_mode != FastPostMode::kFixedDelay) {
+    encode_status =
+        EncodeAndUdpSendWithLateTxDone(payload, &out, cfg);
+    std::uint16_t extra_ms = 0;
+    if (cfg.post_mode == FastPostMode::kTxDoneCbPlus10) {
+      extra_ms = 10;
+    } else if (cfg.post_mode == FastPostMode::kTxDoneCbPlus25) {
+      extra_ms = 25;
+    }
+    if (extra_ms > 0) {
+      vTaskDelay(pdMS_TO_TICKS(extra_ms));
+    }
+  } else {
+    encode_status = EncodeAndUdpSendTracked(payload);
+    auto const t_send_done = esp_timer_get_time();
+    {
+      auto const es = t_send_done - t_post0;
+      out.encode_send_us = es < 0 ? 0 : static_cast(es);
+    }
+    if (encode_status == HotSendStatus::kSent && cfg.post_delay_ms > 0) {
+      vTaskDelay(pdMS_TO_TICKS(cfg.post_delay_ms));
+    }
+  }
+
+  if (encode_status == HotSendStatus::kSent) {
+    out.status_flags |=
+        static_cast(bench::BisectStatusBits::kEncodeOk) |
+        static_cast(bench::BisectStatusBits::kSendtoOk);
+  } else if (encode_status == HotSendStatus::kSendFailed) {
+    out.status_flags |=
+        static_cast(bench::BisectStatusBits::kEncodeOk);
+  } else if (encode_status == HotSendStatus::kEncodeFailed) {
+    // encode failed: no sendto bit
+  }
+
+  auto const t_teardown0 = esp_timer_get_time();
+  CleanupHotPathWifiRuntime();
+  auto const t_end = esp_timer_get_time();
+  {
+    auto const td = t_end - t_teardown0;
+    out.teardown_us = td < 0 ? 0 : static_cast(td);
+  }
+
+  auto const elapsed = t_end - t0;
+  out.cycle_us = elapsed < 0 ? 0 : static_cast(elapsed);
+  out.status = encode_status;
+  return out;
+}
+
+namespace {
+std::uint32_t Crc32Bytes(void const* data, std::size_t len) {
+  auto const* p = static_cast(data);
+  std::uint32_t crc = 0xffffffffu;
+  for (std::size_t i = 0; i < len; ++i) {
+    crc ^= p[i];
+    for (int b = 0; b < 8; ++b) {
+      std::uint32_t const mask = -(crc & 1u);
+      crc = (crc >> 1) ^ (0xedb88320u & mask);
+    }
+  }
+  return ~crc;
+}
+}  // namespace
+
+bool PreparedWifiRtcCacheIsValid(PreparedWifiRtcCache const& cache) {
+  if (cache.magic != kPreparedWifiRtcMagic ||
+      cache.version != kPreparedWifiRtcVersion) {
+    return false;
+  }
+  PreparedWifiRtcCache tmp = cache;
+  tmp.crc = 0;
+  auto const expect = Crc32Bytes(&tmp, sizeof(tmp));
+  if (expect != cache.crc) {
+    return false;
+  }
+  bool const have_ip = (cache.flags & 1u) != 0;
+  bool const have_ch = (cache.flags & 2u) != 0;
+  bool const have_gw = (cache.flags & 4u) != 0;
+  (void)have_gw;
+  // Gateway MAC is preferred but optional: hot path can ARP on miss.
+  return have_ip && have_ch && cache.channel != 0 && cache.ip != 0;
+}
+
+BisectWifiCacheSnapshot SnapshotFromPreparedWifiRtcCache(
+    PreparedWifiRtcCache const& cache) {
+  BisectWifiCacheSnapshot s{};
+  if (!PreparedWifiRtcCacheIsValid(cache)) {
+    return s;
+  }
+  s.valid_ip = true;
+  s.valid_gw_mac = (cache.flags & 4u) != 0;
+  s.valid_bssid = (cache.flags & 8u) != 0;
+  s.channel = cache.channel;
+  s.ip = cache.ip;
+  s.netmask = cache.netmask;
+  s.gateway = cache.gateway;
+  std::memcpy(s.gw_mac, cache.gw_mac, sizeof(s.gw_mac));
+  std::memcpy(s.bssid, cache.bssid, sizeof(s.bssid));
+  return s;
+}
+
+bool CapturePreparedWifiRtcCache(PreparedWifiRtcCache* out) {
+  if (out == nullptr) {
+    return false;
+  }
+  if (!FreezeBisectWifiCacheFromActiveConnection()) {
+    // Fallback: production-style capture then freeze again.
+    if (!CapturePreparedWifiCacheFromActiveConnection()) {
+      return false;
+    }
+    if (!FreezeBisectWifiCacheFromActiveConnection()) {
+      return false;
+    }
+  }
+  // Some APs report primary=0 briefly; HOT path needs a non-zero channel.
+  if (g_bisect_cache.channel == 0) {
+    wifi_ap_record_t ap{};
+    if (esp_wifi_sta_get_ap_info(&ap) == ESP_OK && ap.primary != 0) {
+      g_bisect_cache.channel = ap.primary;
+    } else {
+      g_bisect_cache.channel = 1;
+    }
+  }
+  PreparedWifiRtcCache c{};
+  c.magic = kPreparedWifiRtcMagic;
+  c.version = kPreparedWifiRtcVersion;
+  c.flags = 0;
+  if (g_bisect_cache.valid_ip) {
+    c.flags |= 1u;
+    c.ip = g_bisect_cache.ip;
+    c.netmask = g_bisect_cache.netmask;
+    c.gateway = g_bisect_cache.gateway;
+  }
+  if (g_bisect_cache.channel != 0) {
+    c.flags |= 2u;
+    c.channel = g_bisect_cache.channel;
+  }
+  if (g_bisect_cache.valid_gw_mac) {
+    c.flags |= 4u;
+    std::memcpy(c.gw_mac, g_bisect_cache.gw_mac, sizeof(c.gw_mac));
+  }
+  if (g_bisect_cache.valid_bssid) {
+    c.flags |= 8u;
+    std::memcpy(c.bssid, g_bisect_cache.bssid, sizeof(c.bssid));
+  }
+  c.crc = 0;
+  c.crc = Crc32Bytes(&c, sizeof(c));
+  *out = c;
+  return PreparedWifiRtcCacheIsValid(*out);
+}
+#endif
+
+HotSendStatus TryHotWakePreparedSend(
+    [[maybe_unused]] std::string const& temperature) {
+#if defined(ESP_PLATFORM)
+  esp_reset_reason_t reset = esp_reset_reason();
+
+  // Production deep-sleep semantics: only preserve local Wi-Fi RTC cache across
+  // deep-sleep wakes. Cold / other resets invalidate the local prepared cache.
+  if (reset != ESP_RST_DEEPSLEEP) {
+    InvalidatePreparedWifiCache();
+  }
+
+  return SendPreparedOnce(MakeTemperaturePayload(temperature));
+#else
+  return HotSendStatus::kUnsupported;
+#endif
+}
+
+}  // namespace temp_sensor::prepared_send
diff --git a/main/prepared_send/prepared_send.h b/main/prepared_send/prepared_send.h
new file mode 100644
index 0000000..3ab5f76
--- /dev/null
+++ b/main/prepared_send/prepared_send.h
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * Experimental prepared-send hot path for battery thermometer.
+ *
+ * Scope:
+ * - full boot prepares/exports PreparedSendMessageBlock for the service stream;
+ * - following ESP32 wakeups try to send one UDP prepared packet without
+ *   constructing full AetherApp;
+ * - any error falls back to normal full Aether boot;
+ * - no-sleep benchmarks call SendPreparedOnce() with the same encode/UDP path.
+ */
+
+#ifndef TEMP_SENSOR_PREPARED_SEND_H_
+#define TEMP_SENSOR_PREPARED_SEND_H_
+
+#include 
+#include 
+#include 
+
+#include "aether/all.h"
+
+namespace temp_sensor::prepared_send {
+
+enum class HotSendStatus {
+  kSent,
+  kNoPreparedBlock,
+  kNonceExhausted,
+  kEncodeFailed,
+  kPersistFailed,
+  kWifiFailed,
+  kSendFailed,
+  kUnsupported,
+};
+
+std::string_view ToString(HotSendStatus status);
+
+// Build the same binary temperature payload as SendValue().
+ae::DataBuffer MakeTemperaturePayload(std::string const& temperature);
+
+// UTF-8 benchmark payload: "FULL:0" / "PREPARED:N" (legacy E2E).
+ae::DataBuffer MakeBenchPayload(std::string_view kind, int sequence);
+
+// Shared encode + Wi-Fi + UDP + post-send hold + Wi-Fi runtime cleanup.
+HotSendStatus SendPreparedOnce(ae::DataBuffer const& payload);
+
+// Last send cache usage bits (bench CacheFlags). Valid after SendPreparedOnce /
+// BeginPreparedWifiSession / SendPreparedPacketOnActiveWifi.
+std::uint8_t LastSendCacheFlags();
+
+#if defined(ESP_PLATFORM)
+// Bench-only: keep one Wi-Fi association across many prepared UDP sends.
+// Does not replace production SendPreparedOnce().
+bool BeginPreparedWifiSession();
+HotSendStatus SendPreparedPacketOnActiveWifi(ae::DataBuffer const& payload);
+void EndPreparedWifiSession();
+// Duration of the last successful BeginPreparedWifiSession() (µs).
+std::uint32_t LastWifiSessionStartUs();
+
+// No-sleep bench: AetherApp release may leave ESP-IDF Wi-Fi/netif up.
+void ReleaseFullAetherWifiForHotPath();
+
+// Invalidate retained BSSID/channel/IP/gateway-MAC cache.
+void InvalidatePreparedWifiCache();
+
+// Export Wi-Fi association + IP + gateway MAC from the still-active FULL path.
+// Call before destroying Aether Wi-Fi so prepared #1 can use the fast path.
+bool CapturePreparedWifiCacheFromActiveConnection();
+
+// Bench-only single-factor Wi-Fi bisect (does not alter SendPreparedOnce).
+enum class WifiBisectVariant : std::uint8_t {
+  kB0 = 0,
+  kB1,
+  kC1,
+  kC2,
+  kC3,
+  kC4,
+  kC5,
+  kC6,
+  kC7,
+  kC8,
+  kP1,
+  kP2,
+  kP3,
+  kCount,
+};
+
+struct BisectWifiCacheSnapshot {
+  bool valid_bssid{false};
+  bool valid_ip{false};
+  bool valid_gw_mac{false};
+  std::uint8_t bssid[6]{};
+  std::uint8_t channel{0};
+  std::uint32_t ip{0};
+  std::uint32_t netmask{0};
+  std::uint32_t gateway{0};
+  std::uint8_t gw_mac[6]{};
+};
+
+struct BisectSendResult {
+  HotSendStatus status{HotSendStatus::kWifiFailed};
+  std::uint32_t total_us{0};
+  std::uint8_t requested_channel{0};
+  std::uint8_t actual_channel{0};
+  std::uint8_t status_flags{0};
+  std::uint8_t factor_bits{0};
+  std::uint8_t pre_delay_ms{0};
+};
+
+bool FreezeBisectWifiCacheFromActiveConnection();
+BisectWifiCacheSnapshot GetBisectWifiCacheSnapshot();
+
+// One reconnect prepared send under a single-factor Wi-Fi config.
+// Wi-Fi failure before EncodePacket does not consume a prepared nonce.
+BisectSendResult SendPreparedOnceWithBisectFactor(
+    WifiBisectVariant variant, ae::DataBuffer const& payload);
+
+enum class FastAuthMode : std::uint8_t {
+  kWpa3Both = 0,
+  kWpa3H2eOnly = 1,
+  kWpa2 = 2,
+};
+
+enum class FastPostMode : std::uint8_t {
+  kFixedDelay = 0,
+  kTxDoneCb = 1,
+  kTxDoneCbPlus10 = 2,
+  kTxDoneCbPlus25 = 3,
+};
+
+// Diagnostic wait policy for late TX-done callback (experiment only).
+enum class FastTxDoneWaitMode : std::uint8_t {
+  kFirstAny = 0,      // current production-like: first callback
+  kFirstSuccess = 1,  // wait first txStatus==true + 5 ms observe
+};
+
+struct FastPathConfig {
+  bool use_bssid{false};
+  bool use_channel{true};
+  bool use_fast_scan{false};
+  bool use_static_ip{true};
+  bool use_static_arp{true};
+  bool ampdu_tx_off{false};
+  bool ampdu_rx_off{false};
+  bool amsdu_tx_off{false};
+  bool wifi_storage_ram{false};
+  bool wifi_nvs_enable{true};
+  bool force_ht20{false};
+  // -1 = leave default; 0 = false; 1 = true
+  std::int8_t dynamic_cs{-1};
+  // 0 = use WIFI_INIT_CONFIG_DEFAULT values
+  std::uint8_t static_rx_buf_num{0};
+  std::uint8_t dynamic_rx_buf_num{0};
+  std::uint8_t dynamic_tx_buf_num{0};
+  std::uint8_t rx_ba_win{0};  // 0 = default; used when ampdu_rx enabled or F6
+  FastAuthMode auth{FastAuthMode::kWpa3Both};
+  std::uint8_t retry_max{10};
+  std::uint16_t pre_delay_ms{200};
+  std::uint16_t post_delay_ms{300};
+  FastPostMode post_mode{FastPostMode::kFixedDelay};
+  FastTxDoneWaitMode tx_done_wait{FastTxDoneWaitMode::kFirstAny};
+  bool set_mac_retry_limit{false};
+  std::uint8_t mac_short_retry{0};
+  std::uint8_t mac_long_retry{0};
+};
+
+struct FastSendResult {
+  HotSendStatus status{HotSendStatus::kWifiFailed};
+  std::uint32_t cycle_us{0};
+  std::uint32_t connect_us{0};
+  std::uint32_t wifi_init_us{0};
+  std::uint32_t encode_send_us{0};
+  std::uint32_t tx_done_wait_us{0};
+  std::uint32_t teardown_us{0};
+  std::uint8_t requested_channel{0};
+  std::uint8_t actual_channel{0};
+  std::uint8_t negotiated_auth{0};
+  std::uint8_t status_flags{0};
+  std::uint8_t cb_any{0};
+  std::uint8_t cb_match{0};
+  std::uint8_t cb_timeout{0};
+  std::uint8_t cb_count{0};
+  std::uint8_t diag_mode{0};
+  std::uint8_t first_status{0xff};
+  std::uint8_t tx_cb_total{0};
+  std::uint8_t tx_cb_success{0};
+  std::uint8_t tx_cb_failed{0};
+  std::uint8_t callbacks_after_success{0};
+  std::uint32_t first_cb_delta_us{0xffffffffu};
+  std::uint32_t first_success_delta_us{0xffffffffu};
+  std::uint32_t first_failed_delta_us{0xffffffffu};
+  std::uint32_t last_cb_delta_us{0xffffffffu};
+  std::int8_t rssi{0};
+  std::uint8_t ap_primary{0};
+  std::uint8_t disconnect_count{0};
+  std::uint8_t last_disconnect_reason{0};
+  std::uint8_t reconnect_count{0};
+  std::int16_t mac_retry_set_rc{-1};
+  std::uint8_t mac_short_retry{0};
+  std::uint8_t mac_long_retry{0};
+  std::uint8_t mac_retry_called{0};
+  std::uint32_t retry_cfg_us{0};
+  std::uint32_t heap_before_wifi{0};
+  std::uint32_t heap_after_wifi{0};
+};
+
+// BASE = cached channel + static IPv4/netmask/gw + static ARP. No BSSID.
+// Wi-Fi 4, WIFI_PS_NONE, auto PHY rate, max TX power. Timer excludes 1 s gap.
+// Optional wifi_cache overrides the in-RAM bisect cache (for deep-sleep RTC).
+FastSendResult SendPreparedOnceWithFastPath(
+    FastPathConfig const& cfg, ae::DataBuffer const& payload,
+    BisectWifiCacheSnapshot const* wifi_cache = nullptr);
+
+// RTC-retained Wi-Fi cache for deep-sleep experiments (not BSSID reconnect).
+struct PreparedWifiRtcCache {
+  std::uint32_t magic{0};
+  std::uint16_t version{0};
+  std::uint16_t flags{0};  // bit0=ip, bit1=channel, bit2=gw_mac, bit3=bssid_diag
+  std::uint8_t channel{0};
+  std::uint8_t bssid[6]{};
+  std::uint8_t gw_mac[6]{};
+  std::uint32_t ip{0};
+  std::uint32_t netmask{0};
+  std::uint32_t gateway{0};
+  std::uint32_t crc{0};
+};
+
+static constexpr std::uint32_t kPreparedWifiRtcMagic = 0x57434631u;  // WCF1
+static constexpr std::uint16_t kPreparedWifiRtcVersion = 1;
+
+bool CapturePreparedWifiRtcCache(PreparedWifiRtcCache* out);
+bool PreparedWifiRtcCacheIsValid(PreparedWifiRtcCache const& cache);
+BisectWifiCacheSnapshot SnapshotFromPreparedWifiRtcCache(
+    PreparedWifiRtcCache const& cache);
+#endif
+
+HotSendStatus TryHotWakePreparedSend(std::string const& temperature);
+
+bool ExportPreparedSendBlock(ae::Client::ptr const& client, ae::Uid destination,
+                             std::size_t reserve_message_count);
+
+bool HasPreparedSendBlock();
+std::uint32_t PreparedMessageLeft();
+
+struct WiFiBaseStation {
+  uint8_t target_bssid[6];
+  uint8_t target_channel;
+};
+}  // namespace temp_sensor::prepared_send
+
+#endif  // TEMP_SENSOR_PREPARED_SEND_H_
diff --git a/main/prepared_tx_done_diag_bench.cpp b/main/prepared_tx_done_diag_bench.cpp
new file mode 100644
index 0000000..8d77658
--- /dev/null
+++ b/main/prepared_tx_done_diag_bench.cpp
@@ -0,0 +1,1175 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * Silent TX-done callback diagnostic (ESP32-C6).
+ * 1 FULL + 50 HOT prepared sends, 3 s deep sleep between wakes.
+ * MODE A = FIRST_ANY, MODE B = FIRST_SUCCESS (AE_EXP_TX_DIAG_MODE).
+ * Metrics travel in TxDiagPayload 0xD6; UART is silent.
+ */
+
+#include 
+#include 
+#include 
+
+#include "aether/all.h"
+#include "aether/ae_exp_wifi.h"
+#include "aether/config.h"
+#include "aether/env.h"
+#include "bench_payload.h"
+#include "experiment_early_entry.h"
+#include "prepared_send/prepared_send.h"
+
+#if defined(ESP_PLATFORM)
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#endif
+
+using namespace std::chrono_literals;
+
+#if defined(ESP_PLATFORM)
+extern "C" std::uint64_t esp_rtc_get_time_us(void);
+#endif
+
+namespace temp_sensor {
+namespace {
+
+static constexpr auto kParentUid =
+    ae::Uid::FromString("b1ac52c8-8d94-bd39-4c01-a631ac594165");
+
+#ifndef BENCH_CLIENT_ID
+#  define BENCH_CLIENT_ID "prepared_tx_done_diag_v1"
+#endif
+static constexpr char const* kBenchClientId = BENCH_CLIENT_ID;
+
+#if defined(SERVICE_UID)
+static constexpr auto kServiceUid = ae::Uid::FromString(SERVICE_UID);
+#else
+static constexpr auto kServiceUid =
+    ae::Uid::FromString("5aade50f-00d9-4624-b097-e203cdcf1e38");
+#endif
+
+static constexpr std::uint8_t kOuterCycles = 1;
+static constexpr std::uint8_t kHotPerOuter = 50;
+static constexpr std::uint8_t kMaxHotAttemptsPerBlock = 60;
+static constexpr std::uint32_t kSleepUs = 3000000;
+
+static constexpr std::uint32_t kRtcMagic = 0x54584434u;  // "TXD4"
+static constexpr std::uint16_t kRtcVersion = 1;
+
+enum class Phase : std::uint16_t {
+  kRegister = 0,
+  kFull = 1,
+  kHot = 2,
+  kFinal = 3,
+  kDone = 4,
+};
+
+struct RtcState {
+  std::uint32_t magic;
+  std::uint16_t version;
+  std::uint16_t phase;
+  std::uint8_t outer_cycle;
+  std::uint8_t hot_index;
+  std::uint8_t hot_attempt_count;
+  std::uint8_t hot_send_count;
+  std::uint16_t sequence_global;
+  std::uint16_t next_record_id;
+  std::uint32_t requested_sleep_us;
+  std::uint64_t sleep_arm_rtc_us;
+  std::uint8_t pending_valid;
+  std::uint8_t pending_kind;
+  std::uint8_t pending_outer;
+  std::uint8_t pending_hot_index;
+  std::uint32_t pending_user_cycle_us;
+  std::uint32_t pending_wifi_cycle_us;
+  std::uint32_t pending_connect_us;
+  std::uint32_t pending_txdone_us;
+  std::uint32_t pending_teardown_us;
+  std::uint8_t pending_cb_seen;
+  std::uint8_t pending_cb_timeout;
+  std::uint8_t pending_auth;
+  std::uint8_t brownout_count;
+  std::uint8_t unexpected_reset_count;
+  std::uint8_t recovery_full_count;
+  std::uint8_t current_boot_brownout;
+  std::uint8_t registered;
+  std::uint8_t final_fail_count;
+  std::uint8_t pad0;
+  std::uint16_t pad1;
+  std::uint32_t crc;
+};
+
+#if defined(ESP_PLATFORM)
+RTC_DATA_ATTR static RtcState g_rtc{};
+RTC_DATA_ATTR static prepared_send::PreparedWifiRtcCache g_rtc_wifi_cache{};
+
+// Separate from RtcState so campaign CRC layout matches deep-sleep E2E.
+struct PendingTxDiag {
+  std::uint8_t valid{0};
+  std::uint8_t diag_mode{0};
+  std::uint8_t tx_cb_total{0};
+  std::uint8_t tx_cb_success{0};
+  std::uint8_t tx_cb_failed{0};
+  std::uint8_t first_status{0xff};
+  std::uint8_t callbacks_after{0};
+  std::uint8_t disconnect_count{0};
+  std::uint8_t last_disc_reason{0};
+  std::uint8_t reconnect_count{0};
+  std::int8_t rssi{0};
+  std::uint8_t ap_primary{0};
+  std::uint8_t cb_timeout{0};
+  std::uint8_t pad{0};
+  std::uint32_t first_cb_delta_us{0xffffffffu};
+  std::uint32_t first_success_delta_us{0xffffffffu};
+  std::uint32_t first_failed_delta_us{0xffffffffu};
+  std::uint32_t last_cb_delta_us{0xffffffffu};
+};
+RTC_DATA_ATTR static PendingTxDiag g_pending_diag{};
+RTC_DATA_ATTR static std::uint8_t g_last_full_reason{0};
+
+struct PreSleepSnap {
+  std::uint8_t phase{0};
+  std::uint8_t outer{0};
+  std::uint8_t hot{0};
+  std::uint8_t prepared_left{0};
+  std::uint32_t state_crc{0};
+  std::uint32_t wifi_crc{0};
+};
+RTC_DATA_ATTR static PreSleepSnap g_pre_sleep{};
+
+struct BootSnap {
+  std::uint8_t reset_reason{0};
+  std::uint8_t wakeup_cause{0};
+  std::uint8_t early_valid{0};
+  std::uint8_t rtc_state_crc_ok{0};
+  std::uint8_t rtc_state_valid{0};
+  std::uint8_t rtc_wifi_crc_ok{0};
+  std::uint8_t rtc_wifi_valid{0};
+  std::uint8_t prepared_block_valid{0};
+  std::uint8_t phase{0};
+  std::uint8_t outer{0};
+  std::uint8_t hot{0};
+  std::uint16_t prepared_left{0};
+  std::uint32_t rtc_state_magic{0};
+  std::uint16_t rtc_state_version{0};
+  std::uint32_t rtc_wifi_magic{0};
+  std::uint16_t rtc_wifi_version{0};
+};
+static BootSnap g_boot_snap{};
+
+static const auto kWifiInit = ae::WiFiInit{
+    std::vector{{ae::WifiCreds{WIFI_SSID, WIFI_PASSWORD}, {}}},
+    {},
+};
+
+static bool g_had_aether_app = false;
+
+static std::shared_ptr g_app;
+static ae::Client::ptr g_client;
+static std::unique_ptr g_stream;
+static ae::Subscription g_select_sub;
+static ae::Subscription g_stream_sub;
+static ae::Subscription g_write_sub;
+
+static bool g_write_armed = false;
+static bool g_write_ok = false;
+static bool g_exit_success = false;
+static bool g_pending_register_finish = false;
+static bool g_pending_full_post_write = false;
+static bool g_pending_final_exit = false;
+static bool g_done = false;
+
+static ExperimentEarlyEntrySnapshot g_early{};
+static std::uint32_t g_sleep_elapsed_us = 0;
+static std::uint32_t g_sleep_overhead_us = 0;
+static prepared_send::FastPathConfig g_cfg{};
+static prepared_send::BisectWifiCacheSnapshot g_wifi_snapshot{};
+
+static std::uint32_t Crc32Bytes(void const* data, std::size_t len) {
+  auto const* p = static_cast(data);
+  std::uint32_t crc = 0xffffffffu;
+  for (std::size_t i = 0; i < len; ++i) {
+    crc ^= p[i];
+    for (int b = 0; b < 8; ++b) {
+      std::uint32_t const mask = -(crc & 1u);
+      crc = (crc >> 1) ^ (0xedb88320u & mask);
+    }
+  }
+  return ~crc;
+}
+
+static std::uint32_t ComputeCrc(RtcState const& st) {
+  RtcState tmp = st;
+  tmp.crc = 0;
+  return Crc32Bytes(&tmp, sizeof(tmp));
+}
+
+static void SetCrc(RtcState& st) { st.crc = ComputeCrc(st); }
+
+static bool ValidateRtcState(RtcState const& st) {
+  if (st.magic != kRtcMagic || st.version != kRtcVersion) {
+    return false;
+  }
+  if (ComputeCrc(st) != st.crc) {
+    return false;
+  }
+  if (st.phase > static_cast(Phase::kDone)) {
+    return false;
+  }
+  if (st.outer_cycle > kOuterCycles) {
+    return false;
+  }
+  if (st.hot_index > kHotPerOuter) {
+    return false;
+  }
+  return true;
+}
+
+static void ClearPending(RtcState& st) {
+  st.pending_valid = 0;
+  st.pending_kind = static_cast(bench::DsPendingKind::kNone);
+  st.pending_outer = 0;
+  st.pending_hot_index = 0;
+  st.pending_user_cycle_us = 0;
+  st.pending_wifi_cycle_us = 0;
+  st.pending_connect_us = 0;
+  st.pending_txdone_us = 0;
+  st.pending_teardown_us = 0;
+  st.pending_cb_seen = 0;
+  st.pending_cb_timeout = 0;
+  st.pending_auth = 0;
+  g_pending_diag = PendingTxDiag{};
+}
+
+
+static void InitRtcFresh(Phase phase) {
+  g_rtc = RtcState{};
+  g_rtc.magic = kRtcMagic;
+  g_rtc.version = kRtcVersion;
+  g_rtc.phase = static_cast(phase);
+  g_rtc.outer_cycle = (phase == Phase::kFull || phase == Phase::kHot) ? 1 : 0;
+  g_rtc.hot_index = 1;
+  g_rtc.hot_attempt_count = 0;
+  g_rtc.hot_send_count = 0;
+  g_rtc.sequence_global = 0;
+  g_rtc.next_record_id = 1;
+  g_rtc.requested_sleep_us = 0;
+  g_rtc.sleep_arm_rtc_us = 0;
+  ClearPending(g_rtc);
+  g_rtc.brownout_count = 0;
+  g_rtc.unexpected_reset_count = 0;
+  g_rtc.recovery_full_count = 0;
+  g_rtc.current_boot_brownout = 0;
+  g_rtc.registered = 0;
+  g_rtc.final_fail_count = 0;
+  SetCrc(g_rtc);
+}
+
+[[noreturn]] static void PrepareRtcStateAndDeepSleep(
+    std::uint32_t requested_us) {
+  g_rtc.requested_sleep_us = requested_us;
+  esp_sleep_enable_timer_wakeup(requested_us);
+  g_rtc.sleep_arm_rtc_us = esp_rtc_get_time_us();
+  SetCrc(g_rtc);
+  g_pre_sleep.phase = static_cast(g_rtc.phase);
+  g_pre_sleep.outer = g_rtc.outer_cycle;
+  g_pre_sleep.hot = g_rtc.hot_index;
+  auto const left = prepared_send::PreparedMessageLeft();
+  g_pre_sleep.prepared_left =
+      left > 255 ? 255 : static_cast(left);
+  g_pre_sleep.state_crc = g_rtc.crc;
+  g_pre_sleep.wifi_crc = g_rtc_wifi_cache.crc;
+
+#  if SOC_PM_SUPPORT_RTC_SLOW_MEM_PD
+  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON);
+#  endif
+#  if SOC_PM_SUPPORT_RTC_FAST_MEM_PD
+  esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_ON);
+#  endif
+
+  esp_err_t const ret = esp_deep_sleep_try_to_start();
+  (void)ret;
+  esp_deep_sleep_start();
+  for (;;) {
+  }
+}
+
+static void ForceFullRecovery(bench::FullReason reason) {
+  g_last_full_reason = static_cast(reason);
+  ClearPending(g_rtc);
+  g_rtc.phase = static_cast(Phase::kFull);
+  if (g_rtc.outer_cycle == 0 || g_rtc.outer_cycle > kOuterCycles) {
+    g_rtc.outer_cycle = 1;
+  }
+  g_rtc.hot_index = 1;
+  g_rtc.hot_attempt_count = 0;
+  g_rtc.hot_send_count = 0;
+  if (g_rtc.recovery_full_count < 255) {
+    ++g_rtc.recovery_full_count;
+  }
+  SetCrc(g_rtc);
+}
+
+static void ComputeWakeMetrics() {
+  g_sleep_elapsed_us = 0;
+  g_sleep_overhead_us = 0;
+  auto const reset =
+      static_cast(g_early.reset_reason);
+  if (reset == ESP_RST_DEEPSLEEP && g_rtc.sleep_arm_rtc_us != 0 &&
+      g_early.app_entry_rtc_us >= g_rtc.sleep_arm_rtc_us) {
+    auto const elapsed = g_early.app_entry_rtc_us - g_rtc.sleep_arm_rtc_us;
+    g_sleep_elapsed_us =
+        elapsed > 0xffffffffull ? 0xffffffffu
+                                : static_cast(elapsed);
+    if (g_sleep_elapsed_us > g_rtc.requested_sleep_us) {
+      g_sleep_overhead_us = g_sleep_elapsed_us - g_rtc.requested_sleep_us;
+    }
+  }
+}
+
+static std::uint16_t NextSeq() {
+  ++g_rtc.sequence_global;
+  return g_rtc.sequence_global;
+}
+
+static void AdvanceRecordIdAfterFlush() {
+  if (g_rtc.next_record_id < 0xffffu) {
+    ++g_rtc.next_record_id;
+  }
+}
+
+static void FillWakeFields(bench::TxDiagPayload& p) {
+  // Prefer boot snapshot (pre-mutation) for FULL diagnostics.
+  p.reset_reason = g_boot_snap.reset_reason;
+  p.wake_cause = g_boot_snap.wakeup_cause;
+  p.brownout_count = g_rtc.brownout_count;
+  p.unexpected_reset_count = g_rtc.unexpected_reset_count;
+  p.requested_sleep_us = g_rtc.requested_sleep_us;
+  p.sleep_elapsed_to_app_us = g_sleep_elapsed_us;
+  p.sleep_to_app_overhead_us = g_sleep_overhead_us;
+  p.app_entry_esp_timer_us =
+      g_early.app_entry_esp_timer_us < 0
+          ? 0
+          : static_cast(g_early.app_entry_esp_timer_us);
+
+  std::uint8_t flags = 0;
+  if (g_rtc.current_boot_brownout) {
+    flags |= static_cast(bench::TxDiagFlags::kBrownout);
+  }
+  if (g_boot_snap.rtc_wifi_valid) {
+    flags |= static_cast(bench::TxDiagFlags::kCacheValid);
+  }
+  if (g_boot_snap.rtc_state_valid) {
+    flags |= static_cast(bench::TxDiagFlags::kStateValid);
+  }
+  p.flags = flags;
+
+  p.full_reason = g_last_full_reason;
+  // Boot-time phase (before ForceFullRecovery / InitRtcFresh).
+  p.phase = g_boot_snap.phase;
+  p.rtc_state_magic = g_boot_snap.rtc_state_magic;
+  p.rtc_state_version = g_boot_snap.rtc_state_version;
+  p.rtc_state_crc_ok = g_boot_snap.rtc_state_crc_ok;
+  p.rtc_state_valid = g_boot_snap.rtc_state_valid;
+  p.rtc_wifi_magic = g_boot_snap.rtc_wifi_magic;
+  p.rtc_wifi_version = g_boot_snap.rtc_wifi_version;
+  p.rtc_wifi_crc_ok = g_boot_snap.rtc_wifi_crc_ok;
+  p.rtc_wifi_valid = g_boot_snap.rtc_wifi_valid;
+  p.prepared_block_valid = g_boot_snap.prepared_block_valid;
+  p.prepared_message_left = g_boot_snap.prepared_left;
+  p.pre_sleep_phase = g_pre_sleep.phase;
+  p.pre_sleep_outer = g_pre_sleep.outer;
+  p.pre_sleep_hot = g_pre_sleep.hot;
+  p.pre_sleep_prepared_left = g_pre_sleep.prepared_left;
+  p.pre_sleep_state_crc = g_pre_sleep.state_crc;
+  p.pre_sleep_wifi_crc = g_pre_sleep.wifi_crc;
+  p.app_entry_rtc_us =
+      g_early.app_entry_rtc_us > 0xffffffffull
+          ? 0xffffffffu
+          : static_cast(g_early.app_entry_rtc_us);
+}
+
+static void FillPendingFields(bench::TxDiagPayload& p) {
+  if (!g_rtc.pending_valid) {
+    p.pending_kind = static_cast(bench::DsPendingKind::kNone);
+    p.pending_outer = 0;
+    p.pending_hot_index = 0;
+    p.pending_user_cycle_us = 0;
+    p.pending_wifi_cycle_us = 0;
+    p.connect_us = 0;
+    p.tx_done_wait_us = 0;
+    p.teardown_us = 0;
+    p.negotiated_auth = 0;
+    return;
+  }
+  p.pending_kind = g_rtc.pending_kind;
+  p.pending_outer = g_rtc.pending_outer;
+  p.pending_hot_index = g_rtc.pending_hot_index;
+  p.pending_user_cycle_us = g_rtc.pending_user_cycle_us;
+  p.pending_wifi_cycle_us = g_rtc.pending_wifi_cycle_us;
+  p.connect_us = g_rtc.pending_connect_us;
+  p.tx_done_wait_us = g_rtc.pending_txdone_us;
+  p.teardown_us = g_rtc.pending_teardown_us;
+  p.negotiated_auth = g_rtc.pending_auth;
+  if (g_pending_diag.valid) {
+    p.diag_mode = g_pending_diag.diag_mode;
+    p.tx_cb_total = g_pending_diag.tx_cb_total;
+    p.tx_cb_success = g_pending_diag.tx_cb_success;
+    p.tx_cb_failed = g_pending_diag.tx_cb_failed;
+    p.first_status = g_pending_diag.first_status;
+    p.first_cb_delta_us = g_pending_diag.first_cb_delta_us;
+    p.first_success_delta_us = g_pending_diag.first_success_delta_us;
+    p.first_failed_delta_us = g_pending_diag.first_failed_delta_us;
+    p.last_cb_delta_us = g_pending_diag.last_cb_delta_us;
+    p.callbacks_after_success = g_pending_diag.callbacks_after;
+    p.rssi = g_pending_diag.rssi;
+    p.disconnect_count = g_pending_diag.disconnect_count;
+    p.last_disconnect_reason = g_pending_diag.last_disc_reason;
+    p.reconnect_count = g_pending_diag.reconnect_count;
+    p.ap_primary = g_pending_diag.ap_primary;
+    p.cb_timeout = g_pending_diag.cb_timeout;
+  }
+  if (g_rtc.pending_cb_seen) {
+    p.flags |= static_cast(bench::TxDiagFlags::kCallbackSeen);
+  }
+  if (g_rtc.pending_cb_timeout) {
+    p.flags |= static_cast(bench::TxDiagFlags::kCallbackTimeout);
+  }
+}
+
+static ae::DataBuffer MakeTxDiagPayload(bench::TxDiagMsgType type) {
+  bench::TxDiagPayload p{};
+  p.type = static_cast(type);
+  if (type == bench::TxDiagMsgType::kFull) {
+    // Boot-time counters (pre ForceFullRecovery mutation).
+    p.outer_cycle = g_boot_snap.outer;
+    p.hot_index = g_boot_snap.hot;
+  } else {
+    p.outer_cycle = g_rtc.outer_cycle;
+    p.hot_index = g_rtc.hot_index;
+  }
+  p.sequence_global = NextSeq();
+  // Assign id without advancing until the send that flushes pending succeeds
+  // (HOT Wi-Fi retries must reuse the same record_id).
+  p.record_id = g_rtc.pending_valid ? g_rtc.next_record_id : 0;
+  FillWakeFields(p);
+  FillPendingFields(p);
+  if (type != bench::TxDiagMsgType::kFull) {
+    p.prepared_message_left = static_cast(
+        prepared_send::PreparedMessageLeft() > 0xffffu
+            ? 0xffffu
+            : prepared_send::PreparedMessageLeft());
+  }
+  return bench::EncodeTxDiag(p);
+}
+
+static void StorePendingFull(std::uint32_t user_cycle_us) {
+  g_rtc.pending_valid = 1;
+  g_rtc.pending_kind = static_cast(bench::DsPendingKind::kFull);
+  g_rtc.pending_outer = g_rtc.outer_cycle;
+  g_rtc.pending_hot_index = 0;
+  g_rtc.pending_user_cycle_us = user_cycle_us;
+  g_rtc.pending_wifi_cycle_us = user_cycle_us;
+  g_rtc.pending_connect_us = 0;
+  g_rtc.pending_txdone_us = 0;
+  g_rtc.pending_teardown_us = 0;
+  g_rtc.pending_cb_seen = 0;
+  g_rtc.pending_cb_timeout = 0;
+  g_rtc.pending_auth = 0;
+}
+
+static void StorePendingHot(prepared_send::FastSendResult const& result,
+                            std::uint32_t user_cycle_us) {
+  g_rtc.pending_valid = 1;
+  g_rtc.pending_kind = static_cast(bench::DsPendingKind::kHot);
+  g_rtc.pending_outer = g_rtc.outer_cycle;
+  g_rtc.pending_hot_index = g_rtc.hot_index;
+  g_rtc.pending_user_cycle_us = user_cycle_us;
+  g_rtc.pending_wifi_cycle_us = result.cycle_us;
+  g_rtc.pending_connect_us = result.connect_us;
+  g_rtc.pending_txdone_us = result.tx_done_wait_us;
+  g_rtc.pending_teardown_us = result.teardown_us;
+  g_rtc.pending_cb_seen = result.cb_any;
+  g_rtc.pending_cb_timeout = result.cb_timeout;
+  g_rtc.pending_auth = result.negotiated_auth;
+  g_pending_diag = PendingTxDiag{};
+  g_pending_diag.valid = 1;
+  g_pending_diag.diag_mode = result.diag_mode;
+  g_pending_diag.tx_cb_total = result.tx_cb_total;
+  g_pending_diag.tx_cb_success = result.tx_cb_success;
+  g_pending_diag.tx_cb_failed = result.tx_cb_failed;
+  g_pending_diag.first_status = result.first_status;
+  g_pending_diag.callbacks_after = result.callbacks_after_success;
+  g_pending_diag.disconnect_count = result.disconnect_count;
+  g_pending_diag.last_disc_reason = result.last_disconnect_reason;
+  g_pending_diag.reconnect_count = result.reconnect_count;
+  g_pending_diag.rssi = result.rssi;
+  g_pending_diag.ap_primary = result.ap_primary;
+  g_pending_diag.cb_timeout = result.cb_timeout;
+  g_pending_diag.first_cb_delta_us = result.first_cb_delta_us;
+  g_pending_diag.first_success_delta_us = result.first_success_delta_us;
+  g_pending_diag.first_failed_delta_us = result.first_failed_delta_us;
+  g_pending_diag.last_cb_delta_us = result.last_cb_delta_us;
+}
+
+static void ReleaseApp() {
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  g_app.reset();
+}
+
+static void PreConstructCleanup() {
+  if (!g_had_aether_app) {
+    return;
+  }
+#  if !AE_WIFI_USE_FULL_DEINIT
+  esp_netif_deinit();
+  esp_event_loop_delete_default();
+#  endif
+}
+
+static void ConstructAether() {
+  PreConstructCleanup();
+  g_had_aether_app = true;
+  g_app = ae::AetherApp::Construct(
+      ae::AetherAppContext{}
+#  if AE_DISTILLATION
+          .AddAdapterFactory([&](ae::AetherAppContext const& ctx) {
+            return ae::WifiAdapter::ptr::Create(
+                ae::CreateWith{ctx.domain()}.with_id(
+                    ae::GlobalId::kWiFiAdapter),
+                ctx.aether(), ctx.poller(), ctx.dns_resolver(), kWifiInit);
+          })
+#  endif
+  );
+}
+
+static prepared_send::FastPathConfig MakeFastConfig() {
+  prepared_send::FastPathConfig c{};
+  c.use_bssid = false;
+  c.use_channel = true;
+  c.use_fast_scan = false;
+  c.use_static_ip = true;
+  c.use_static_arp = true;
+  c.ampdu_tx_off = false;
+  c.wifi_storage_ram = false;
+  c.auth = prepared_send::FastAuthMode::kWpa2;
+  c.retry_max = 10;
+  c.pre_delay_ms = 25;
+  c.post_delay_ms = 0;
+  c.post_mode = prepared_send::FastPostMode::kTxDoneCb;
+#if defined(AE_EXP_TX_DIAG_MODE) && (AE_EXP_TX_DIAG_MODE == 1)
+  c.tx_done_wait = prepared_send::FastTxDoneWaitMode::kFirstSuccess;
+#else
+  c.tx_done_wait = prepared_send::FastTxDoneWaitMode::kFirstAny;
+#endif
+  return c;
+}
+
+static void DoFullWrite() {
+  if (g_write_armed) {
+    return;
+  }
+  g_write_armed = true;
+  auto payload = MakeTxDiagPayload(bench::TxDiagMsgType::kFull);
+  auto& wa = g_stream->Write(std::move(payload));
+  g_write_sub = wa.status_event().Subscribe([](ae::WriteAction::Status st) {
+    g_write_ok = (st == ae::WriteAction::Status::kSuccess);
+    g_pending_full_post_write = true;
+  });
+}
+
+static void MaybeFullWrite() {
+  if (!g_stream || g_write_armed) {
+    return;
+  }
+  if (!g_stream->stream_info().is_writable) {
+    return;
+  }
+  DoFullWrite();
+}
+
+static void OnFullClientReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  auto client = g_client.Load();
+  g_stream = std::make_unique(*g_app, client, kServiceUid,
+                                             ae::P2pPortHandle{});
+  g_stream_sub =
+      g_stream->stream_update_event().Subscribe([]() { MaybeFullWrite(); });
+  MaybeFullWrite();
+}
+
+static void StartRegister() {
+  g_write_armed = false;
+  g_pending_register_finish = false;
+  g_exit_success = false;
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       g_client = std::move(res).value();
+                       g_pending_register_finish = true;
+                     });
+}
+
+static void StartFull() {
+  g_write_armed = false;
+  g_pending_full_post_write = false;
+  g_write_ok = false;
+  g_exit_success = false;
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnFullClientReady(std::move(res).value());
+                     });
+}
+
+static void DoFinalWrite() {
+  if (g_write_armed) {
+    return;
+  }
+  g_write_armed = true;
+  auto& wa = g_stream->Write(MakeTxDiagPayload(bench::TxDiagMsgType::kFinal));
+  g_write_sub = wa.status_event().Subscribe([](ae::WriteAction::Status st) {
+    g_write_ok = (st == ae::WriteAction::Status::kSuccess);
+    g_pending_final_exit = true;
+  });
+}
+
+static void MaybeFinalWrite() {
+  if (!g_stream || g_write_armed) {
+    return;
+  }
+  if (!g_stream->stream_info().is_writable) {
+    return;
+  }
+  DoFinalWrite();
+}
+
+static void OnFinalClientReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  auto client = g_client.Load();
+  g_stream = std::make_unique(*g_app, client, kServiceUid,
+                                             ae::P2pPortHandle{});
+  g_stream_sub =
+      g_stream->stream_update_event().Subscribe([]() { MaybeFinalWrite(); });
+  MaybeFinalWrite();
+}
+
+static void StartFinal() {
+  g_write_armed = false;
+  g_pending_final_exit = false;
+  g_write_ok = false;
+  g_exit_success = false;
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnFinalClientReady(std::move(res).value());
+                     });
+}
+
+static void FinishRegisterInLoop() {
+  g_app->aether().Save();
+  g_exit_success = true;
+  g_app->Exit(0);
+}
+
+static void FinishFullPostWriteInLoop() {
+  if (!g_write_ok) {
+    g_last_full_reason =
+        static_cast(bench::FullReason::kForcedRecovery);
+    g_app->Exit(1);
+    return;
+  }
+  bool captured = false;
+  for (int i = 0; i < 10 && !captured; ++i) {
+    captured = prepared_send::CapturePreparedWifiRtcCache(&g_rtc_wifi_cache);
+    if (!captured) {
+      vTaskDelay(pdMS_TO_TICKS(200));
+    }
+  }
+  bool exported = false;
+  for (std::size_t n : {std::size_t{50}, std::size_t{30}, std::size_t{20},
+                        std::size_t{10}}) {
+    if (prepared_send::ExportPreparedSendBlock(g_client, kServiceUid, n)) {
+      exported = true;
+      break;
+    }
+  }
+  if (!exported) {
+    g_last_full_reason = static_cast(
+        bench::FullReason::kPreparedExportFailed);
+    g_app->Exit(1);
+    return;
+  }
+  auto const left = prepared_send::PreparedMessageLeft();
+  if (!prepared_send::HasPreparedSendBlock() || left == 0) {
+    g_last_full_reason = static_cast(
+        bench::FullReason::kPreparedBlockInvalid);
+    g_app->Exit(1);
+    return;
+  }
+  g_rtc.pad0 = left > 255 ? 255 : static_cast(left);
+  if (!captured) {
+    g_last_full_reason = static_cast(
+        bench::FullReason::kWifiCacheCaptureFailed);
+    g_app->Exit(1);
+    return;
+  }
+  g_last_full_reason =
+      static_cast(bench::FullReason::kNone);
+  g_exit_success = true;
+  g_app->Exit(0);
+}
+
+static void FinishFinalInLoop() {
+  if (!g_write_ok) {
+    g_app->Exit(1);
+    return;
+  }
+  g_exit_success = true;
+  g_app->Exit(0);
+}
+
+static std::uint32_t UserCycleFromAppEntry() {
+  auto const now = esp_timer_get_time();
+  auto const entry = g_early.app_entry_esp_timer_us;
+  if (now < entry) {
+    return 0;
+  }
+  auto const delta = now - entry;
+  return delta > 0xffffffffll ? 0xffffffffu
+                              : static_cast(delta);
+}
+
+static void AfterRegisterComplete() {
+  ReleaseApp();
+  g_rtc.registered = 1;
+  g_rtc.phase = static_cast(Phase::kFull);
+  g_rtc.outer_cycle = 1;
+  g_rtc.hot_index = 1;
+  g_rtc.hot_attempt_count = 0;
+  g_rtc.hot_send_count = 0;
+  ClearPending(g_rtc);
+  SetCrc(g_rtc);
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void AfterFullComplete() {
+  ReleaseApp();
+  prepared_send::ReleaseFullAetherWifiForHotPath();
+  if (g_rtc.pending_valid) {
+    AdvanceRecordIdAfterFlush();
+  }
+  auto const user_cycle = UserCycleFromAppEntry();
+  StorePendingFull(user_cycle);
+  g_rtc.phase = static_cast(Phase::kHot);
+  g_rtc.hot_index = 1;
+  g_rtc.hot_attempt_count = 0;
+  g_rtc.hot_send_count = 0;
+  SetCrc(g_rtc);
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void AfterFinalComplete() {
+  ReleaseApp();
+  if (g_rtc.pending_valid) {
+    AdvanceRecordIdAfterFlush();
+  }
+  ClearPending(g_rtc);
+  g_rtc.final_fail_count = 0;
+  g_rtc.phase = static_cast(Phase::kDone);
+  SetCrc(g_rtc);
+  g_done = true;
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void AfterFinalFailed() {
+  ReleaseApp();
+  if (g_rtc.final_fail_count < 255) {
+    ++g_rtc.final_fail_count;
+  }
+  // After several Aether FINAL failures, stop the campaign so metrics already
+  // delivered (via pending on HOT/FULL) are not blocked forever.
+  if (g_rtc.final_fail_count >= 5) {
+    ClearPending(g_rtc);
+    g_rtc.phase = static_cast(Phase::kDone);
+    SetCrc(g_rtc);
+    g_done = true;
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+  SetCrc(g_rtc);
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static bool WifiFailedBeforeEncode(prepared_send::FastSendResult const& r) {
+  if (r.status == prepared_send::HotSendStatus::kWifiFailed) {
+    return true;
+  }
+  bool const encode_ok =
+      (r.status_flags &
+       static_cast(bench::BisectStatusBits::kEncodeOk)) != 0;
+  return !encode_ok && r.status != prepared_send::HotSendStatus::kSent;
+}
+
+static void RunHotOnce() {
+  if (!prepared_send::PreparedWifiRtcCacheIsValid(g_rtc_wifi_cache)) {
+    ForceFullRecovery(bench::FullReason::kRtcWifiCacheInvalid);
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+  g_wifi_snapshot =
+      prepared_send::SnapshotFromPreparedWifiRtcCache(g_rtc_wifi_cache);
+  if (!g_wifi_snapshot.valid_ip || g_wifi_snapshot.channel == 0) {
+    ForceFullRecovery(bench::FullReason::kRtcWifiCacheInvalid);
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+  if (!prepared_send::HasPreparedSendBlock()) {
+    ForceFullRecovery(bench::FullReason::kPreparedBlockInvalid);
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+  if (prepared_send::PreparedMessageLeft() == 0) {
+    ForceFullRecovery(bench::FullReason::kPreparedNonceEmpty);
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+  if (g_rtc.hot_attempt_count >= kMaxHotAttemptsPerBlock) {
+    ForceFullRecovery(bench::FullReason::kForcedRecovery);
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  if (g_rtc.hot_attempt_count < 255) {
+    ++g_rtc.hot_attempt_count;
+  }
+  SetCrc(g_rtc);
+
+  auto payload = MakeTxDiagPayload(bench::TxDiagMsgType::kHot);
+  auto const result =
+      prepared_send::SendPreparedOnceWithFastPath(g_cfg, payload,
+                                                    &g_wifi_snapshot);
+
+  if (result.status == prepared_send::HotSendStatus::kSent) {
+    auto const user_cycle = UserCycleFromAppEntry();
+    if (g_rtc.hot_send_count < 255) {
+      ++g_rtc.hot_send_count;
+    }
+    bool const flushed_prior = g_rtc.pending_valid != 0;
+    StorePendingHot(result, user_cycle);
+    if (flushed_prior) {
+      AdvanceRecordIdAfterFlush();
+    }
+
+    if (g_rtc.hot_index < 255) {
+      ++g_rtc.hot_index;
+    }
+    auto const hot_target =
+        g_rtc.pad0 != 0 ? g_rtc.pad0 : kHotPerOuter;
+    if (g_rtc.hot_index > hot_target) {
+      if (g_rtc.outer_cycle < kOuterCycles) {
+        ++g_rtc.outer_cycle;
+        g_rtc.phase = static_cast(Phase::kFull);
+        g_rtc.hot_index = 1;
+        g_rtc.hot_attempt_count = 0;
+        g_rtc.hot_send_count = 0;
+        g_last_full_reason =
+            static_cast(bench::FullReason::kNone);
+      } else {
+        // Keep RTC bounds valid across deep sleep (hot_index<=kHotPerOuter).
+        g_rtc.phase = static_cast(Phase::kFinal);
+        g_rtc.hot_index = 1;
+        g_rtc.hot_attempt_count = 0;
+      }
+    }
+    SetCrc(g_rtc);
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  if (result.status == prepared_send::HotSendStatus::kWifiFailed) {
+    ForceFullRecovery(bench::FullReason::kHotWifiFailed);
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+  if (result.status == prepared_send::HotSendStatus::kEncodeFailed) {
+    ForceFullRecovery(bench::FullReason::kHotEncodeFailed);
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+  if (result.status == prepared_send::HotSendStatus::kSendFailed) {
+    ForceFullRecovery(bench::FullReason::kHotSendFailed);
+    PrepareRtcStateAndDeepSleep(kSleepUs);
+  }
+
+  // Encode/send failure after Wi-Fi: do not advance; retry same index.
+  SetCrc(g_rtc);
+  PrepareRtcStateAndDeepSleep(kSleepUs);
+}
+
+static void PrepareRtcOnBoot() {
+  g_early = GetExperimentEarlyEntrySnapshot();
+
+  // Boot snapshot BEFORE mutating RTC state.
+  g_boot_snap = BootSnap{};
+  g_boot_snap.reset_reason = g_early.reset_reason;
+  g_boot_snap.wakeup_cause = g_early.wakeup_cause;
+  g_boot_snap.early_valid = g_early.valid;
+  g_boot_snap.rtc_state_magic = g_rtc.magic;
+  g_boot_snap.rtc_state_version = g_rtc.version;
+  g_boot_snap.rtc_state_crc_ok = (ComputeCrc(g_rtc) == g_rtc.crc) ? 1 : 0;
+  g_boot_snap.rtc_state_valid = ValidateRtcState(g_rtc) ? 1 : 0;
+  g_boot_snap.phase = static_cast(g_rtc.phase);
+  g_boot_snap.outer = g_rtc.outer_cycle;
+  g_boot_snap.hot = g_rtc.hot_index;
+  g_boot_snap.prepared_block_valid =
+      prepared_send::HasPreparedSendBlock() ? 1 : 0;
+  g_boot_snap.prepared_left = static_cast(
+      prepared_send::PreparedMessageLeft() > 0xffffu
+          ? 0xffffu
+          : prepared_send::PreparedMessageLeft());
+  g_boot_snap.rtc_wifi_magic = g_rtc_wifi_cache.magic;
+  g_boot_snap.rtc_wifi_version = g_rtc_wifi_cache.version;
+  {
+    prepared_send::PreparedWifiRtcCache tmp = g_rtc_wifi_cache;
+    auto const stored = tmp.crc;
+    tmp.crc = 0;
+    g_boot_snap.rtc_wifi_crc_ok =
+        (Crc32Bytes(&tmp, sizeof(tmp)) == stored) ? 1 : 0;
+  }
+  g_boot_snap.rtc_wifi_valid =
+      prepared_send::PreparedWifiRtcCacheIsValid(g_rtc_wifi_cache) ? 1 : 0;
+
+  auto const reset =
+      static_cast(g_early.reset_reason);
+  bool const valid = ValidateRtcState(g_rtc);
+
+  g_rtc.current_boot_brownout = 0;
+
+  // Sequential decision: first failing check wins FullReason.
+  if (reset == ESP_RST_BROWNOUT) {
+    if (valid) {
+      if (g_rtc.brownout_count < 255) {
+        ++g_rtc.brownout_count;
+      }
+      ClearPending(g_rtc);
+    } else {
+      InitRtcFresh(Phase::kFull);
+      g_rtc.brownout_count = 1;
+      g_rtc.outer_cycle = 1;
+    }
+    g_rtc.current_boot_brownout = 1;
+    ForceFullRecovery(bench::FullReason::kForcedRecovery);
+  } else if (!g_early.valid) {
+    // Early hook did not run — treat as unexpected (should not happen after
+    // AE_EXP_PREPARED_TX_DONE_DIAG early-entry enable).
+    if (valid) {
+      ForceFullRecovery(bench::FullReason::kUnexpectedResetReason);
+    } else {
+      InitRtcFresh(Phase::kFull);
+      g_rtc.outer_cycle = 1;
+      g_rtc.registered = 1;
+      g_last_full_reason =
+          static_cast(bench::FullReason::kUnexpectedResetReason);
+      SetCrc(g_rtc);
+    }
+  } else if (reset != ESP_RST_DEEPSLEEP) {
+    bool const first_poweron = (reset == ESP_RST_POWERON);
+    if (first_poweron && (!valid || !g_rtc.registered)) {
+      InitRtcFresh(Phase::kRegister);
+      g_last_full_reason =
+          static_cast(bench::FullReason::kColdBoot);
+    } else if (!valid) {
+      InitRtcFresh(Phase::kFull);
+      g_rtc.unexpected_reset_count = 1;
+      g_rtc.outer_cycle = 1;
+      g_rtc.registered = 1;
+      g_last_full_reason =
+          static_cast(bench::FullReason::kRtcStateInvalid);
+      SetCrc(g_rtc);
+    } else {
+      if (g_rtc.unexpected_reset_count < 255) {
+        ++g_rtc.unexpected_reset_count;
+      }
+      ForceFullRecovery(bench::FullReason::kUnexpectedResetReason);
+    }
+  } else if (!valid) {
+    // Deep-sleep wake but RTC state invalid.
+    if (g_rtc.magic != kRtcMagic || g_rtc.version != kRtcVersion) {
+      InitRtcFresh(Phase::kFull);
+      g_rtc.outer_cycle = 1;
+      g_rtc.registered = 1;
+      g_last_full_reason =
+          static_cast(bench::FullReason::kRtcStateInvalid);
+      SetCrc(g_rtc);
+    } else if (ComputeCrc(g_rtc) != g_rtc.crc) {
+      InitRtcFresh(Phase::kFull);
+      g_rtc.outer_cycle = 1;
+      g_rtc.registered = 1;
+      g_last_full_reason =
+          static_cast(bench::FullReason::kRtcStateInvalid);
+      SetCrc(g_rtc);
+    } else {
+      InitRtcFresh(Phase::kFull);
+      g_rtc.outer_cycle = 1;
+      g_rtc.registered = 1;
+      g_last_full_reason =
+          static_cast(bench::FullReason::kStateBoundsInvalid);
+      SetCrc(g_rtc);
+    }
+  }
+  // else: DEEPSLEEP + valid — continue phase as stored (HOT/FULL/FINAL)
+
+  ComputeWakeMetrics();
+  SetCrc(g_rtc);
+}
+
+#endif  // ESP_PLATFORM
+
+}  // namespace
+}  // namespace temp_sensor
+
+#if defined(ESP_PLATFORM)
+
+void setup() {
+  using namespace temp_sensor;
+  nvs_flash_init();
+  g_cfg = MakeFastConfig();
+  g_done = false;
+  g_pending_register_finish = false;
+  g_pending_full_post_write = false;
+  g_pending_final_exit = false;
+  PrepareRtcOnBoot();
+
+  auto const phase = static_cast(g_rtc.phase);
+  if (phase == Phase::kDone) {
+    g_done = true;
+    return;
+  }
+  if (phase == Phase::kRegister) {
+    StartRegister();
+    return;
+  }
+  if (phase == Phase::kFull) {
+    StartFull();
+    return;
+  }
+  if (phase == Phase::kFinal) {
+    StartFinal();
+    return;
+  }
+  // HOT is handled synchronously in loop().
+}
+
+void loop() {
+  using namespace temp_sensor;
+  if (g_done) {
+    vTaskDelay(pdMS_TO_TICKS(1000));
+    return;
+  }
+
+  auto const phase = static_cast(g_rtc.phase);
+  if (phase == Phase::kHot) {
+    RunHotOnce();
+    return;
+  }
+
+  auto process_deferred = []() {
+    if (g_app && g_pending_register_finish) {
+      g_pending_register_finish = false;
+      FinishRegisterInLoop();
+      return true;
+    }
+    if (g_app && g_pending_full_post_write) {
+      g_pending_full_post_write = false;
+      FinishFullPostWriteInLoop();
+      return true;
+    }
+    if (g_app && g_pending_final_exit) {
+      g_pending_final_exit = false;
+      FinishFinalInLoop();
+      return true;
+    }
+    return false;
+  };
+
+  if (process_deferred()) {
+    return;
+  }
+
+  if (!g_app) {
+    return;
+  }
+
+  if (!g_app->IsExited()) {
+    auto t = g_app->Update(ae::Now());
+    if (process_deferred()) {
+      return;
+    }
+    if (!g_app->IsExited()) {
+      g_app->WaitUntil(t);
+    }
+    return;
+  }
+
+  if (phase == Phase::kRegister) {
+    if (g_exit_success) {
+      AfterRegisterComplete();
+    } else {
+      ReleaseApp();
+      PrepareRtcStateAndDeepSleep(kSleepUs);
+    }
+    return;
+  }
+  if (phase == Phase::kFull) {
+    if (g_exit_success) {
+      AfterFullComplete();
+    } else {
+      ReleaseApp();
+      // Keep reason set during FinishFullPostWriteInLoop; else forced.
+      auto const reason =
+          g_last_full_reason != 0
+              ? static_cast(g_last_full_reason)
+              : bench::FullReason::kForcedRecovery;
+      ForceFullRecovery(reason);
+      PrepareRtcStateAndDeepSleep(kSleepUs);
+    }
+    return;
+  }
+  if (phase == Phase::kFinal) {
+    if (g_exit_success) {
+      AfterFinalComplete();
+    } else {
+      AfterFinalFailed();
+    }
+    return;
+  }
+}
+
+#else
+
+void setup() {}
+void loop() {}
+
+#endif
diff --git a/main/prepared_wifi_cache_5x20_bench.cpp b/main/prepared_wifi_cache_5x20_bench.cpp
new file mode 100644
index 0000000..8ab31d4
--- /dev/null
+++ b/main/prepared_wifi_cache_5x20_bench.cpp
@@ -0,0 +1,447 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * Silent 5x20 prepared Wi-Fi cache experiment (ESP32-C6):
+ * 1 registration, 5 FULL cycles each preparing 20 messages, 100 prepared sends.
+ * All timings travel in binary application payloads (no UART results).
+ */
+
+#include 
+#include 
+
+#include "aether/all.h"
+#include "aether/ae_exp_wifi.h"
+#include "aether/config.h"
+#include "aether/env.h"
+#include "bench_payload.h"
+#include "prepared_send/prepared_send.h"
+
+#if defined(ESP_PLATFORM)
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#endif
+
+using namespace std::chrono_literals;
+
+namespace temp_sensor {
+namespace {
+
+static constexpr auto kParentUid =
+    ae::Uid::FromString("b1ac52c8-8d94-bd39-4c01-a631ac594165");
+
+#ifndef BENCH_CLIENT_ID
+#  define BENCH_CLIENT_ID "prepared_wifi_cache_5x20_v1"
+#endif
+static constexpr char const* kBenchClientId = BENCH_CLIENT_ID;
+
+#if defined(SERVICE_UID)
+static constexpr auto kServiceUid = ae::Uid::FromString(SERVICE_UID);
+#else
+static constexpr auto kServiceUid =
+    ae::Uid::FromString("3d284a4f-ebb4-451e-a2c5-aecb0d647a45");
+#endif
+
+static constexpr int kOuterCycles = 5;
+static constexpr int kPreparedPerCycle = 20;
+static constexpr int kPreparedGapMs = 1000;
+
+#if defined(ESP_PLATFORM)
+static const auto kWifiInit = ae::WiFiInit{
+    std::vector{{ae::WifiCreds{WIFI_SSID, WIFI_PASSWORD}, {}}},
+    {},
+};
+
+static bool g_had_aether_app = false;
+
+static void PreConstructCleanup() {
+  if (!g_had_aether_app) {
+    return;
+  }
+#  if !AE_WIFI_USE_FULL_DEINIT
+  esp_netif_deinit();
+  esp_event_loop_delete_default();
+#  endif
+}
+
+static std::int64_t NowUs() { return esp_timer_get_time(); }
+#else
+static std::int64_t NowUs() { return 0; }
+#endif
+
+enum class Phase : std::uint8_t {
+  kRegister,
+  kFullCycle,
+  kPrepared,
+  kFinal,
+  kDone,
+};
+
+static std::shared_ptr g_app;
+static ae::Client::ptr g_client;
+static std::unique_ptr g_stream;
+static ae::Subscription g_select_sub;
+static ae::Subscription g_stream_sub;
+static ae::Subscription g_write_sub;
+
+static Phase g_phase = Phase::kRegister;
+static bool g_registration_pending = false;
+static bool g_write_armed = false;
+static bool g_done = false;
+
+static int g_outer = 0;
+static int g_prepared_index = 0;
+static bool g_prepared_waiting_gap = false;
+#if defined(ESP_PLATFORM)
+static TickType_t g_prepared_gap_until = 0;
+#endif
+
+static std::uint16_t g_seq = 0;
+static std::uint32_t g_registration_us = 0;
+static std::uint32_t g_last_full_us = 0;
+static std::uint32_t g_last_prepared_us = 0;
+static std::uint32_t g_pending_full_us = 0;
+static bool g_have_pending_full = false;
+static std::uint8_t g_sticky_cache_flags = 0;
+
+static std::int64_t g_t0 = 0;
+
+static void ReleaseApp() {
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  g_app.reset();
+}
+
+static std::uint16_t NextSeq() { return ++g_seq; }
+
+static ae::DataBuffer MakeFullPayload(int outer) {
+  bench::Payload p{};
+  p.type = static_cast(bench::MsgType::kFull);
+  p.outer_cycle = static_cast(outer);
+  p.prepared_index = 0;
+  p.sequence_global = NextSeq();
+  p.registration_us = (outer == 1) ? g_registration_us : 0;
+  p.previous_full_us = g_have_pending_full ? g_pending_full_us : 0;
+  p.previous_prepared_us = g_last_prepared_us;
+  p.cache_flags = g_sticky_cache_flags;
+  g_have_pending_full = false;
+  return bench::Encode(p);
+}
+
+static ae::DataBuffer MakePreparedPayload(int outer, int index) {
+  bench::Payload p{};
+  p.type = static_cast(bench::MsgType::kPrepared);
+  p.outer_cycle = static_cast(outer);
+  p.prepared_index = static_cast(index);
+  p.sequence_global = NextSeq();
+  p.previous_prepared_us = (index == 1) ? 0 : g_last_prepared_us;
+  // cache_flags describe the *previous* prepared Wi-Fi attempt (index-1).
+  p.cache_flags = (index == 1) ? 0 : g_sticky_cache_flags;
+  return bench::Encode(p);
+}
+
+static ae::DataBuffer MakeFinalPayload() {
+  bench::Payload p{};
+  p.type = static_cast(bench::MsgType::kFinal);
+  p.outer_cycle = kOuterCycles;
+  p.prepared_index = kPreparedPerCycle;
+  p.sequence_global = NextSeq();
+  p.registration_us = g_registration_us;
+  p.previous_full_us = g_have_pending_full ? g_pending_full_us : g_last_full_us;
+  p.previous_prepared_us = g_last_prepared_us;
+  p.cache_flags = g_sticky_cache_flags;
+  return bench::Encode(p);
+}
+
+static void ConstructAether() {
+#if defined(ESP_PLATFORM)
+  PreConstructCleanup();
+#endif
+  g_had_aether_app = true;
+  g_app = ae::AetherApp::Construct(
+      ae::AetherAppContext{}
+#if AE_DISTILLATION && defined(ESP_PLATFORM)
+          .AddAdapterFactory([&](ae::AetherAppContext const& ctx) {
+            return ae::WifiAdapter::ptr::Create(
+                ae::CreateWith{ctx.domain()}.with_id(
+                    ae::GlobalId::kWiFiAdapter),
+                ctx.aether(), ctx.poller(), ctx.dns_resolver(), kWifiInit);
+          })
+#endif
+  );
+}
+
+static void OnRegisterReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  g_app->aether().Save();
+  g_app->Exit(0);
+}
+
+static void DoFullWrite() {
+  if (g_write_armed) {
+    return;
+  }
+  g_write_armed = true;
+  auto payload = MakeFullPayload(g_outer);
+  auto& wa = g_stream->Write(std::move(payload));
+  g_write_sub = wa.status_event().Subscribe([](ae::WriteAction::Status st) {
+    if (st != ae::WriteAction::Status::kSuccess) {
+      g_app->Exit(1);
+      return;
+    }
+    if (!prepared_send::ExportPreparedSendBlock(g_client, kServiceUid,
+                                                kPreparedPerCycle)) {
+      g_app->Exit(1);
+      return;
+    }
+    if (!prepared_send::HasPreparedSendBlock() ||
+        prepared_send::PreparedMessageLeft() !=
+            static_cast(kPreparedPerCycle)) {
+      g_app->Exit(1);
+      return;
+    }
+    // Export association/IP/gateway-MAC into local prepared cache while FULL
+    // Wi-Fi is still up so prepared #1 can take the fast path.
+    (void)prepared_send::CapturePreparedWifiCacheFromActiveConnection();
+    g_app->aether().Save();
+    g_app->Exit(0);
+  });
+}
+
+static void MaybeFullWrite() {
+  if (!g_stream || g_write_armed) {
+    return;
+  }
+  if (!g_stream->stream_info().is_writable) {
+    return;
+  }
+  DoFullWrite();
+}
+
+static void OnFullClientReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  auto client = g_client.Load();
+  g_stream = std::make_unique(*g_app, client, kServiceUid,
+                                             ae::P2pPortHandle{});
+  g_stream_sub =
+      g_stream->stream_update_event().Subscribe([]() { MaybeFullWrite(); });
+  MaybeFullWrite();
+}
+
+static void StartRegister() {
+  g_phase = Phase::kRegister;
+  g_write_armed = false;
+  g_t0 = NowUs();
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnRegisterReady(std::move(res).value());
+                     });
+}
+
+static void StartFullCycle(int outer) {
+  g_phase = Phase::kFullCycle;
+  g_outer = outer;
+  g_write_armed = false;
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  g_t0 = NowUs();
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnFullClientReady(std::move(res).value());
+                     });
+}
+
+static void StartPreparedPhase() {
+  g_phase = Phase::kPrepared;
+  g_prepared_index = 1;
+  g_prepared_waiting_gap = false;
+  g_sticky_cache_flags = 0;
+#if defined(ESP_PLATFORM)
+  prepared_send::ReleaseFullAetherWifiForHotPath();
+#endif
+}
+
+static void DoFinalWrite() {
+  if (g_write_armed) {
+    return;
+  }
+  g_write_armed = true;
+  auto payload = MakeFinalPayload();
+  auto& wa = g_stream->Write(std::move(payload));
+  g_write_sub =
+      wa.status_event().Subscribe([](ae::WriteAction::Status) { g_app->Exit(0); });
+}
+
+static void MaybeFinalWrite() {
+  if (!g_stream || g_write_armed) {
+    return;
+  }
+  if (!g_stream->stream_info().is_writable) {
+    return;
+  }
+  DoFinalWrite();
+}
+
+static void OnFinalClientReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  auto client = g_client.Load();
+  g_stream = std::make_unique(*g_app, client, kServiceUid,
+                                             ae::P2pPortHandle{});
+  g_stream_sub =
+      g_stream->stream_update_event().Subscribe([]() { MaybeFinalWrite(); });
+  MaybeFinalWrite();
+}
+
+static void StartFinal() {
+  g_phase = Phase::kFinal;
+  g_write_armed = false;
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnFinalClientReady(std::move(res).value());
+                     });
+}
+
+void BeginAppMainTiming() {}
+void FinalizeCycleBeforeSleep() {}
+#if defined(ESP_PLATFORM)
+void EnterDeepSleep() {}
+#endif
+
+void setup() {
+#if defined(ESP_PLATFORM)
+  nvs_flash_init();
+  prepared_send::InvalidatePreparedWifiCache();
+#endif
+  g_done = false;
+  g_seq = 0;
+  g_registration_pending = true;
+  g_last_prepared_us = 0;
+  g_have_pending_full = false;
+  g_sticky_cache_flags = 0;
+}
+
+void loop() {
+  if (g_done) {
+    return;
+  }
+
+  if (g_registration_pending) {
+    g_registration_pending = false;
+    StartRegister();
+    return;
+  }
+
+  if (g_phase == Phase::kPrepared) {
+#if defined(ESP_PLATFORM)
+    if (g_prepared_waiting_gap) {
+      if (xTaskGetTickCount() < g_prepared_gap_until) {
+        vTaskDelay(pdMS_TO_TICKS(20));
+        return;
+      }
+      g_prepared_waiting_gap = false;
+    }
+#endif
+
+    if (g_prepared_index > kPreparedPerCycle) {
+      if (g_outer < kOuterCycles) {
+        StartFullCycle(g_outer + 1);
+      } else {
+        StartFinal();
+      }
+      return;
+    }
+
+    int const i = g_prepared_index;
+    auto payload = MakePreparedPayload(g_outer, i);
+    auto const t0 = NowUs();
+    auto const status = prepared_send::SendPreparedOnce(payload);
+    auto const us = static_cast(NowUs() - t0);
+    (void)status;
+    g_last_prepared_us = us;
+    g_sticky_cache_flags = prepared_send::LastSendCacheFlags();
+
+    ++g_prepared_index;
+    if (g_prepared_index <= kPreparedPerCycle) {
+#if defined(ESP_PLATFORM)
+      g_prepared_waiting_gap = true;
+      g_prepared_gap_until =
+          xTaskGetTickCount() + pdMS_TO_TICKS(kPreparedGapMs);
+#endif
+    }
+    return;
+  }
+
+  if (!g_app) {
+    return;
+  }
+
+  if (!g_app->IsExited()) {
+    auto t = g_app->Update(ae::Now());
+    g_app->WaitUntil(t);
+    return;
+  }
+
+  if (g_phase == Phase::kRegister) {
+    ReleaseApp();
+    g_registration_us = static_cast(NowUs() - g_t0);
+    StartFullCycle(1);
+    return;
+  }
+
+  if (g_phase == Phase::kFullCycle) {
+    ReleaseApp();
+    auto const full_us = static_cast(NowUs() - g_t0);
+    g_last_full_us = full_us;
+    g_pending_full_us = full_us;
+    g_have_pending_full = true;
+    StartPreparedPhase();
+    return;
+  }
+
+  if (g_phase == Phase::kFinal) {
+    ReleaseApp();
+    g_phase = Phase::kDone;
+    g_done = true;
+  }
+}
+
+}  // namespace
+}  // namespace temp_sensor
+
+void setup() { temp_sensor::setup(); }
+void loop() { temp_sensor::loop(); }
diff --git a/main/prepared_wifi_fastest_path_bench.cpp b/main/prepared_wifi_fastest_path_bench.cpp
new file mode 100644
index 0000000..21fed3d
--- /dev/null
+++ b/main/prepared_wifi_fastest_path_bench.cpp
@@ -0,0 +1,649 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * Silent fastest-path prepared reconnect bench (ESP32-C6).
+ * One compile-time variant per flash. Results travel in FastPayload.
+ *
+ * BASE: cached channel + static IPv4 + static ARP, no BSSID.
+ * Wi-Fi 4, WIFI_PS_NONE, auto PHY, max TX power. 1 s gap outside timer.
+ */
+
+#include 
+#include 
+#include 
+
+#include "aether/all.h"
+#include "aether/ae_exp_wifi.h"
+#include "aether/config.h"
+#include "aether/env.h"
+#include "bench_payload.h"
+#include "prepared_send/prepared_send.h"
+
+#if defined(ESP_PLATFORM)
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#endif
+
+using namespace std::chrono_literals;
+
+namespace temp_sensor {
+namespace {
+
+static constexpr auto kParentUid =
+    ae::Uid::FromString("b1ac52c8-8d94-bd39-4c01-a631ac594165");
+
+#ifndef BENCH_CLIENT_ID
+#  define BENCH_CLIENT_ID "prepared_wifi_bisect_v1"
+#endif
+static constexpr char const* kBenchClientId = BENCH_CLIENT_ID;
+
+#if defined(SERVICE_UID)
+static constexpr auto kServiceUid = ae::Uid::FromString(SERVICE_UID);
+#else
+static constexpr auto kServiceUid =
+    ae::Uid::FromString("3d284a4f-ebb4-451e-a2c5-aecb0d647a45");
+#endif
+
+#ifndef AE_EXP_FAST_N
+#  define AE_EXP_FAST_N 20
+#endif
+#ifndef AE_EXP_FAST_TEST_ID
+#  define AE_EXP_FAST_TEST_ID 0
+#endif
+#ifndef AE_EXP_FAST_PRE_MS
+#  define AE_EXP_FAST_PRE_MS 200
+#endif
+#ifndef AE_EXP_FAST_POST_MS
+#  define AE_EXP_FAST_POST_MS 300
+#endif
+#ifndef AE_EXP_FAST_USE_BSSID
+#  define AE_EXP_FAST_USE_BSSID 0
+#endif
+#ifndef AE_EXP_FAST_FAST_SCAN
+#  define AE_EXP_FAST_FAST_SCAN 0
+#endif
+#ifndef AE_EXP_FAST_AUTH
+#  define AE_EXP_FAST_AUTH 0
+#endif
+#ifndef AE_EXP_FAST_RETRY
+#  define AE_EXP_FAST_RETRY 10
+#endif
+#ifndef AE_EXP_FAST_POST_MODE
+#  define AE_EXP_FAST_POST_MODE 0
+#endif
+#ifndef AE_EXP_FAST_AMPDU_TX_OFF
+#  define AE_EXP_FAST_AMPDU_TX_OFF 0
+#endif
+#ifndef AE_EXP_FAST_STORAGE_RAM
+#  define AE_EXP_FAST_STORAGE_RAM 0
+#endif
+
+static constexpr int kPreparedPerVariant = AE_EXP_FAST_N;
+static constexpr int kPreparedGapMs = 1000;
+static constexpr std::uint8_t kTestId =
+    static_cast(AE_EXP_FAST_TEST_ID);
+
+#if defined(ESP_PLATFORM)
+static const auto kWifiInit = ae::WiFiInit{
+    std::vector{{ae::WifiCreds{WIFI_SSID, WIFI_PASSWORD}, {}}},
+    {},
+};
+
+static bool g_had_aether_app = false;
+
+static void PreConstructCleanup() {
+  if (!g_had_aether_app) {
+    return;
+  }
+#  if !AE_WIFI_USE_FULL_DEINIT
+  esp_netif_deinit();
+  esp_event_loop_delete_default();
+#  endif
+}
+
+static std::int64_t NowUs() { return esp_timer_get_time(); }
+#else
+static std::int64_t NowUs() { return 0; }
+#endif
+
+enum class Phase : std::uint8_t {
+  kRegister,
+  kFullCycle,
+  kPrepared,
+  kFinal,
+  kDone,
+};
+
+static std::shared_ptr g_app;
+static ae::Client::ptr g_client;
+static std::unique_ptr g_stream;
+static ae::Subscription g_select_sub;
+static ae::Subscription g_stream_sub;
+static ae::Subscription g_write_sub;
+
+static Phase g_phase = Phase::kRegister;
+static bool g_registration_pending = false;
+static bool g_write_armed = false;
+static bool g_done = false;
+
+static bool g_pending_register_finish = false;
+static bool g_pending_full_post_write = false;
+static bool g_full_write_ok = false;
+static bool g_pending_final_exit = false;
+
+static int g_prepared_index = 0;
+static bool g_prepared_waiting_gap = false;
+#if defined(ESP_PLATFORM)
+static TickType_t g_prepared_gap_until = 0;
+#endif
+
+static std::uint16_t g_seq = 0;
+static std::uint32_t g_registration_us = 0;
+static std::uint32_t g_pending_full_us = 0;
+static bool g_have_pending_full = false;
+
+static std::uint16_t g_wifi_ready_count = 0;
+static std::uint16_t g_encode_count = 0;
+static std::uint16_t g_sendto_count = 0;
+static std::uint16_t g_nonce_start = 0;
+static std::uint16_t g_cb_seen_count = 0;
+static std::uint16_t g_cb_timeout_count = 0;
+static std::uint16_t g_auth_ok_count = 0;
+
+static prepared_send::FastSendResult g_last_result{};
+static prepared_send::BisectWifiCacheSnapshot g_cache{};
+static prepared_send::FastPathConfig g_cfg{};
+static std::uint8_t g_assoc_bits = 0;
+
+static std::int64_t g_t0 = 0;
+
+static void ReleaseApp() {
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  g_app.reset();
+}
+
+static std::uint16_t NextSeq() { return ++g_seq; }
+
+static prepared_send::FastPathConfig MakeFastConfig() {
+  prepared_send::FastPathConfig c{};
+  c.use_bssid = AE_EXP_FAST_USE_BSSID != 0;
+  c.use_channel = true;
+  c.use_fast_scan = AE_EXP_FAST_FAST_SCAN != 0;
+  c.use_static_ip = true;
+  c.use_static_arp = true;
+  c.ampdu_tx_off = AE_EXP_FAST_AMPDU_TX_OFF != 0;
+  c.wifi_storage_ram = AE_EXP_FAST_STORAGE_RAM != 0;
+  c.auth = static_cast(AE_EXP_FAST_AUTH);
+  c.retry_max = static_cast(AE_EXP_FAST_RETRY);
+  c.pre_delay_ms = static_cast(AE_EXP_FAST_PRE_MS);
+  c.post_delay_ms = static_cast(AE_EXP_FAST_POST_MS);
+  c.post_mode = static_cast(AE_EXP_FAST_POST_MODE);
+  return c;
+}
+
+static std::uint8_t AssocBitsOf(prepared_send::FastPathConfig const& c) {
+  using F = bench::FastAssocBits;
+  std::uint8_t bits = 0;
+  if (c.use_bssid) {
+    bits |= static_cast(F::kBssid);
+  }
+  if (c.use_channel) {
+    bits |= static_cast(F::kChannel);
+  }
+  if (c.use_fast_scan) {
+    bits |= static_cast(F::kFastScan);
+  }
+  if (c.use_static_ip) {
+    bits |= static_cast(F::kStaticIp);
+  }
+  if (c.use_static_arp) {
+    bits |= static_cast(F::kStaticArp);
+  }
+  if (c.ampdu_tx_off) {
+    bits |= static_cast(F::kAmpduTxOff);
+  }
+  if (c.wifi_storage_ram) {
+    bits |= static_cast(F::kStorageRam);
+  }
+  if (c.post_mode != prepared_send::FastPostMode::kFixedDelay) {
+    bits |= static_cast(F::kCallback);
+  }
+  return bits;
+}
+
+static void FillCommon(bench::FastPayload& p) {
+  p.test_id = kTestId;
+  p.pre_ms = g_cfg.pre_delay_ms;
+  // post_ms=0 means POST=callback for late tx-done mode.
+  p.post_ms = (g_cfg.post_mode == prepared_send::FastPostMode::kFixedDelay)
+                  ? g_cfg.post_delay_ms
+                  : 0;
+  p.assoc_bits = g_assoc_bits;
+  p.retry_max = g_cfg.retry_max;
+  p.post_mode = static_cast(g_cfg.post_mode);
+}
+
+static ae::DataBuffer MakeFullPayload() {
+  bench::FastPayload p{};
+  p.type = static_cast(bench::FastMsgType::kFull);
+  FillCommon(p);
+  p.prepared_index = static_cast(
+      kPreparedPerVariant > 255 ? 255 : kPreparedPerVariant);
+  p.sequence_global = NextSeq();
+  p.cycle_us = g_have_pending_full ? g_pending_full_us : 0;
+  p.connect_us = g_registration_us;
+  g_have_pending_full = false;
+  return bench::EncodeFast(p);
+}
+
+static ae::DataBuffer MakePreparedPayload(int index) {
+  bench::FastPayload p{};
+  p.type = static_cast(bench::FastMsgType::kPrepared);
+  FillCommon(p);
+  p.prepared_index = static_cast(index);
+  p.sequence_global = NextSeq();
+  if (index > 1) {
+    p.cycle_us = g_last_result.cycle_us;
+    p.connect_us = g_last_result.connect_us;
+    p.encode_send_us = g_last_result.encode_send_us;
+    p.tx_done_wait_us = g_last_result.tx_done_wait_us;
+    p.teardown_us = g_last_result.teardown_us;
+    p.status_flags = g_last_result.status_flags;
+    p.auth_negotiated = g_last_result.negotiated_auth;
+    p.cb_any = g_last_result.cb_any;
+    p.cb_match = g_last_result.cb_match;
+    p.cb_count = g_last_result.cb_count;
+    p.cb_timeout = g_last_result.cb_timeout;
+  }
+  return bench::EncodeFast(p);
+}
+
+static ae::DataBuffer MakeFinalPayload() {
+  bench::FastPayload p{};
+  p.type = static_cast(bench::FastMsgType::kFinal);
+  FillCommon(p);
+  p.prepared_index = static_cast(
+      kPreparedPerVariant > 255 ? 255 : kPreparedPerVariant);
+  p.sequence_global = NextSeq();
+  p.cycle_us = g_last_result.cycle_us;
+  p.connect_us = g_last_result.connect_us;
+  p.encode_send_us = g_last_result.encode_send_us;
+  p.tx_done_wait_us = g_last_result.tx_done_wait_us;
+  p.teardown_us = g_last_result.teardown_us;
+  p.status_flags = g_last_result.status_flags;
+  p.auth_negotiated = g_last_result.negotiated_auth;
+  p.wifi_ready_count = g_wifi_ready_count;
+  p.encode_count = g_encode_count;
+  p.sendto_count = g_sendto_count;
+  auto const left = prepared_send::PreparedMessageLeft();
+  std::uint32_t consumed = 0;
+  if (g_nonce_start >= left) {
+    consumed = g_nonce_start - left;
+  } else {
+    consumed = g_encode_count;
+  }
+  p.nonce_consumed = consumed > 0xffffu ? 0xffffu
+                                        : static_cast(consumed);
+  p.cb_any = static_cast(g_cb_seen_count > 255 ? 255
+                                                             : g_cb_seen_count);
+  p.cb_match = 0;
+  p.cb_count = 0;
+  p.cb_timeout = static_cast(
+      g_cb_timeout_count > 255 ? 255 : g_cb_timeout_count);
+  return bench::EncodeFast(p);
+}
+
+static void ConstructAether() {
+#if defined(ESP_PLATFORM)
+  PreConstructCleanup();
+#endif
+  g_had_aether_app = true;
+  g_app = ae::AetherApp::Construct(
+      ae::AetherAppContext{}
+#if AE_DISTILLATION && defined(ESP_PLATFORM)
+          .AddAdapterFactory([&](ae::AetherAppContext const& ctx) {
+            return ae::WifiAdapter::ptr::Create(
+                ae::CreateWith{ctx.domain()}.with_id(
+                    ae::GlobalId::kWiFiAdapter),
+                ctx.aether(), ctx.poller(), ctx.dns_resolver(), kWifiInit);
+          })
+#endif
+  );
+}
+
+static void DoFullWrite() {
+  if (g_write_armed) {
+    return;
+  }
+  g_write_armed = true;
+  auto payload = MakeFullPayload();
+  auto& wa = g_stream->Write(std::move(payload));
+  g_write_sub = wa.status_event().Subscribe([](ae::WriteAction::Status st) {
+    g_full_write_ok = (st == ae::WriteAction::Status::kSuccess);
+    g_pending_full_post_write = true;
+  });
+}
+
+static void MaybeFullWrite() {
+  if (!g_stream || g_write_armed) {
+    return;
+  }
+  if (!g_stream->stream_info().is_writable) {
+    return;
+  }
+  DoFullWrite();
+}
+
+static void OnFullClientReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  auto client = g_client.Load();
+  g_stream = std::make_unique(*g_app, client, kServiceUid,
+                                             ae::P2pPortHandle{});
+  g_stream_sub =
+      g_stream->stream_update_event().Subscribe([]() { MaybeFullWrite(); });
+  MaybeFullWrite();
+}
+
+static void StartRegister() {
+  g_phase = Phase::kRegister;
+  g_write_armed = false;
+  g_pending_register_finish = false;
+  g_t0 = NowUs();
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       g_client = std::move(res).value();
+                       g_pending_register_finish = true;
+                     });
+}
+
+static void StartFullCycle() {
+  g_phase = Phase::kFullCycle;
+  g_write_armed = false;
+  g_pending_full_post_write = false;
+  g_full_write_ok = false;
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  g_t0 = NowUs();
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnFullClientReady(std::move(res).value());
+                     });
+}
+
+static void StartPreparedPhase() {
+  g_phase = Phase::kPrepared;
+  g_prepared_index = 1;
+  g_prepared_waiting_gap = false;
+  g_wifi_ready_count = 0;
+  g_encode_count = 0;
+  g_sendto_count = 0;
+  g_cb_seen_count = 0;
+  g_cb_timeout_count = 0;
+  g_auth_ok_count = 0;
+  g_last_result = {};
+  g_nonce_start =
+      static_cast(prepared_send::PreparedMessageLeft());
+#if defined(ESP_PLATFORM)
+  prepared_send::ReleaseFullAetherWifiForHotPath();
+  vTaskDelay(pdMS_TO_TICKS(200));
+#endif
+}
+
+static void DoFinalWrite() {
+  if (g_write_armed) {
+    return;
+  }
+  g_write_armed = true;
+  auto& wa = g_stream->Write(MakeFinalPayload());
+  g_write_sub = wa.status_event().Subscribe([](ae::WriteAction::Status) {
+    g_pending_final_exit = true;
+  });
+}
+
+static void MaybeFinalWrite() {
+  if (!g_stream || g_write_armed) {
+    return;
+  }
+  if (!g_stream->stream_info().is_writable) {
+    return;
+  }
+  DoFinalWrite();
+}
+
+static void OnFinalClientReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  auto client = g_client.Load();
+  g_stream = std::make_unique(*g_app, client, kServiceUid,
+                                             ae::P2pPortHandle{});
+  g_stream_sub =
+      g_stream->stream_update_event().Subscribe([]() { MaybeFinalWrite(); });
+  MaybeFinalWrite();
+}
+
+static void StartFinal() {
+  g_phase = Phase::kFinal;
+  g_write_armed = false;
+  g_pending_final_exit = false;
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnFinalClientReady(std::move(res).value());
+                     });
+}
+
+static void FinishRegisterInLoop() {
+  g_app->aether().Save();
+  g_app->Exit(0);
+}
+
+static void FinishFullPostWriteInLoop() {
+  if (!g_full_write_ok) {
+    g_app->Exit(1);
+    return;
+  }
+  if (!prepared_send::ExportPreparedSendBlock(g_client, kServiceUid,
+                                              kPreparedPerVariant)) {
+    g_app->Exit(1);
+    return;
+  }
+  if (!prepared_send::HasPreparedSendBlock() ||
+      prepared_send::PreparedMessageLeft() !=
+          static_cast(kPreparedPerVariant)) {
+    g_app->Exit(1);
+    return;
+  }
+  if (!prepared_send::FreezeBisectWifiCacheFromActiveConnection()) {
+    g_app->Exit(1);
+    return;
+  }
+  g_cache = prepared_send::GetBisectWifiCacheSnapshot();
+  g_app->aether().Save();
+  g_app->Exit(0);
+}
+
+}  // namespace
+}  // namespace temp_sensor
+
+void setup() {
+  using namespace temp_sensor;
+  g_cfg = MakeFastConfig();
+  g_assoc_bits = AssocBitsOf(g_cfg);
+#if defined(ESP_PLATFORM)
+  nvs_flash_init();
+  prepared_send::InvalidatePreparedWifiCache();
+#endif
+  g_done = false;
+  g_seq = 0;
+  g_registration_pending = true;
+  g_pending_register_finish = false;
+  g_pending_full_post_write = false;
+  g_pending_final_exit = false;
+}
+
+void loop() {
+  using namespace temp_sensor;
+  if (g_done) {
+    return;
+  }
+
+  if (g_registration_pending) {
+    g_registration_pending = false;
+    StartRegister();
+    return;
+  }
+
+  auto process_deferred = []() {
+    if (g_app && g_pending_register_finish) {
+      g_pending_register_finish = false;
+      FinishRegisterInLoop();
+      return true;
+    }
+    if (g_app && g_pending_full_post_write) {
+      g_pending_full_post_write = false;
+      FinishFullPostWriteInLoop();
+      return true;
+    }
+    if (g_app && g_pending_final_exit) {
+      g_pending_final_exit = false;
+      g_app->Exit(0);
+      return true;
+    }
+    return false;
+  };
+
+  if (process_deferred()) {
+    return;
+  }
+
+  if (g_phase == Phase::kPrepared) {
+#if defined(ESP_PLATFORM)
+    if (g_prepared_waiting_gap) {
+      if (xTaskGetTickCount() < g_prepared_gap_until) {
+        vTaskDelay(pdMS_TO_TICKS(20));
+        return;
+      }
+      g_prepared_waiting_gap = false;
+    }
+#endif
+
+    if (g_prepared_index > kPreparedPerVariant) {
+      StartFinal();
+      return;
+    }
+
+    int const i = g_prepared_index;
+    auto payload = MakePreparedPayload(i);
+#if defined(ESP_PLATFORM)
+    auto const result =
+        prepared_send::SendPreparedOnceWithFastPath(g_cfg, payload);
+#else
+    prepared_send::FastSendResult result{};
+    result.status = prepared_send::HotSendStatus::kUnsupported;
+#endif
+    g_last_result = result;
+    if (result.status_flags &
+        static_cast(bench::BisectStatusBits::kWifiReady)) {
+      ++g_wifi_ready_count;
+    }
+    if (result.status_flags &
+        static_cast(bench::BisectStatusBits::kEncodeOk)) {
+      ++g_encode_count;
+    }
+    if (result.status_flags &
+        static_cast(bench::BisectStatusBits::kSendtoOk)) {
+      ++g_sendto_count;
+    }
+    if (result.cb_any) {
+      ++g_cb_seen_count;
+    }
+    if (result.cb_timeout) {
+      ++g_cb_timeout_count;
+    }
+    if (result.negotiated_auth == 3) {
+      ++g_auth_ok_count;
+    }
+
+    ++g_prepared_index;
+    if (g_prepared_index <= kPreparedPerVariant) {
+#if defined(ESP_PLATFORM)
+      g_prepared_waiting_gap = true;
+      g_prepared_gap_until =
+          xTaskGetTickCount() + pdMS_TO_TICKS(kPreparedGapMs);
+#endif
+    }
+    return;
+  }
+
+  if (!g_app) {
+    return;
+  }
+
+  if (!g_app->IsExited()) {
+    auto t = g_app->Update(ae::Now());
+    if (process_deferred()) {
+      return;
+    }
+    if (!g_app->IsExited()) {
+      g_app->WaitUntil(t);
+    }
+    return;
+  }
+
+  if (g_phase == Phase::kRegister) {
+    ReleaseApp();
+    g_registration_us = static_cast(NowUs() - g_t0);
+    StartFullCycle();
+    return;
+  }
+
+  if (g_phase == Phase::kFullCycle) {
+    ReleaseApp();
+    auto const full_us = static_cast(NowUs() - g_t0);
+    g_pending_full_us = full_us;
+    g_have_pending_full = true;
+    StartPreparedPhase();
+    return;
+  }
+
+  if (g_phase == Phase::kFinal) {
+    ReleaseApp();
+    g_phase = Phase::kDone;
+    g_done = true;
+  }
+}
diff --git a/main/prepared_wifi_single_factor_bisect_bench.cpp b/main/prepared_wifi_single_factor_bisect_bench.cpp
new file mode 100644
index 0000000..34c1127
--- /dev/null
+++ b/main/prepared_wifi_single_factor_bisect_bench.cpp
@@ -0,0 +1,640 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * Silent single-factor Wi-Fi bisect for prepared reconnect sends (ESP32-C6).
+ * Each variant differs from the same canonical baseline by exactly one factor
+ * (except documented dependent combinations C3/C6/C7/C8).
+ *
+ * AE_EXP_BISECT_SMOKE=1  → B1 only, 2 prepared sends.
+ * AE_EXP_BISECT_CONSOLE=1 → USB stage markers (no AE_EXP_SILENT).
+ */
+
+#include 
+#include 
+#include 
+
+#include "aether/all.h"
+#include "aether/ae_exp_wifi.h"
+#include "aether/config.h"
+#include "aether/env.h"
+#include "bench_payload.h"
+#include "prepared_send/prepared_send.h"
+
+#if defined(ESP_PLATFORM)
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  if defined(AE_EXP_BISECT_CONSOLE)
+#    include 
+#  endif
+#endif
+
+using namespace std::chrono_literals;
+
+namespace temp_sensor {
+namespace {
+
+static constexpr auto kParentUid =
+    ae::Uid::FromString("b1ac52c8-8d94-bd39-4c01-a631ac594165");
+
+#ifndef BENCH_CLIENT_ID
+#  define BENCH_CLIENT_ID "prepared_wifi_bisect_v1"
+#endif
+static constexpr char const* kBenchClientId = BENCH_CLIENT_ID;
+
+#if defined(SERVICE_UID)
+static constexpr auto kServiceUid = ae::Uid::FromString(SERVICE_UID);
+#else
+static constexpr auto kServiceUid =
+    ae::Uid::FromString("3d284a4f-ebb4-451e-a2c5-aecb0d647a45");
+#endif
+
+static constexpr int kAllVariantCount =
+    static_cast(prepared_send::WifiBisectVariant::kCount);
+
+#if defined(AE_EXP_BISECT_SMOKE) && AE_EXP_BISECT_SMOKE
+// Smoke: B1 only, 2 prepared reconnect sends.
+static constexpr int kFirstVariant =
+    static_cast(prepared_send::WifiBisectVariant::kB1);
+static constexpr int kLastVariantExclusive = kFirstVariant + 1;
+static constexpr int kPreparedPerVariant = 2;
+#else
+static constexpr int kFirstVariant = 0;
+static constexpr int kLastVariantExclusive = kAllVariantCount;
+static constexpr int kPreparedPerVariant = 20;
+#endif
+
+static constexpr int kPreparedGapMs = 1000;
+
+#if defined(ESP_PLATFORM) && defined(AE_EXP_BISECT_CONSOLE)
+static void Stage(char const* msg) {
+  std::printf("%s\n", msg);
+  std::fflush(stdout);
+}
+static void Stage2(char const* a, char const* b) {
+  std::printf("%s %s\n", a, b);
+  std::fflush(stdout);
+}
+#else
+static void Stage(char const*) {}
+static void Stage2(char const*, char const*) {}
+#endif
+
+#if defined(ESP_PLATFORM)
+static const auto kWifiInit = ae::WiFiInit{
+    std::vector{{ae::WifiCreds{WIFI_SSID, WIFI_PASSWORD}, {}}},
+    {},
+};
+
+static bool g_had_aether_app = false;
+
+static void PreConstructCleanup() {
+  if (!g_had_aether_app) {
+    return;
+  }
+#  if !AE_WIFI_USE_FULL_DEINIT
+  esp_netif_deinit();
+  esp_event_loop_delete_default();
+#  endif
+}
+
+static std::int64_t NowUs() { return esp_timer_get_time(); }
+#else
+static std::int64_t NowUs() { return 0; }
+#endif
+
+enum class Phase : std::uint8_t {
+  kRegister,
+  kFullCycle,
+  kPrepared,
+  kFinal,
+  kDone,
+};
+
+static std::shared_ptr g_app;
+static ae::Client::ptr g_client;
+static std::unique_ptr g_stream;
+static ae::Subscription g_select_sub;
+static ae::Subscription g_stream_sub;
+static ae::Subscription g_write_sub;
+
+static Phase g_phase = Phase::kRegister;
+static bool g_registration_pending = false;
+static bool g_write_armed = false;
+static bool g_done = false;
+
+// Deferred work: never Prepare/Freeze/Save/Exit inside Write callbacks.
+static bool g_pending_register_finish = false;
+static bool g_pending_full_post_write = false;
+static bool g_full_write_ok = false;
+static bool g_pending_final_exit = false;
+
+static int g_variant = kFirstVariant;
+static int g_prepared_index = 0;
+static bool g_prepared_waiting_gap = false;
+#if defined(ESP_PLATFORM)
+static TickType_t g_prepared_gap_until = 0;
+#endif
+
+static std::uint16_t g_seq = 0;
+static std::uint32_t g_registration_us = 0;
+static std::uint32_t g_last_full_us = 0;
+static std::uint32_t g_last_prepared_us = 0;
+static std::uint32_t g_pending_full_us = 0;
+static bool g_have_pending_full = false;
+
+static std::uint8_t g_wifi_ready_count = 0;
+static std::uint8_t g_encode_count = 0;
+static std::uint8_t g_sendto_count = 0;
+static std::uint8_t g_nonce_start = 0;
+
+static prepared_send::BisectSendResult g_last_result{};
+static prepared_send::BisectWifiCacheSnapshot g_cache{};
+
+static std::uint8_t g_prev_wifi_ready = 0;
+static std::uint8_t g_prev_encode = 0;
+static std::uint8_t g_prev_sendto = 0;
+static std::uint8_t g_prev_nonce = 0;
+static bool g_have_prev_summary = false;
+
+static std::int64_t g_t0 = 0;
+
+static void ReleaseApp() {
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  g_app.reset();
+}
+
+static std::uint16_t NextSeq() { return ++g_seq; }
+
+static prepared_send::WifiBisectVariant CurrentVariant() {
+  return static_cast(g_variant);
+}
+
+static char const* CurrentVariantName() {
+  return bench::BisectVariantName(static_cast(g_variant));
+}
+
+static ae::DataBuffer MakeFullPayload() {
+  bench::BisectPayload p{};
+  p.type = static_cast(bench::BisectMsgType::kFull);
+  p.variant_id = static_cast(g_variant);
+  p.sequence_global = NextSeq();
+  p.time_us = g_have_pending_full ? g_pending_full_us : 0;
+  p.aux_us = (g_variant == kFirstVariant) ? g_registration_us : 0;
+  if (g_have_prev_summary) {
+    p.wifi_ready_count = g_prev_wifi_ready;
+    p.encode_count = g_prev_encode;
+    p.sendto_count = g_prev_sendto;
+    p.nonce_consumed = g_prev_nonce;
+  }
+  p.cached_ip = g_cache.ip;
+  p.cached_channel = g_cache.channel;
+  p.requested_channel = g_cache.channel;
+  p.actual_channel = g_cache.channel;
+  std::memcpy(p.cached_bssid, g_cache.bssid, sizeof(p.cached_bssid));
+  p.pre_delay_ms =
+      (CurrentVariant() == prepared_send::WifiBisectVariant::kB0) ? 0 : 200;
+  g_have_pending_full = false;
+  return bench::EncodeBisect(p);
+}
+
+static ae::DataBuffer MakePreparedPayload(int index) {
+  bench::BisectPayload p{};
+  p.type = static_cast(bench::BisectMsgType::kPrepared);
+  p.variant_id = static_cast(g_variant);
+  p.prepared_index = static_cast(index);
+  p.sequence_global = NextSeq();
+  if (index == 1) {
+    p.cached_ip = g_cache.ip;
+    p.cached_channel = g_cache.channel;
+    std::memcpy(p.cached_bssid, g_cache.bssid, sizeof(p.cached_bssid));
+    p.pre_delay_ms =
+        (CurrentVariant() == prepared_send::WifiBisectVariant::kB0) ? 0 : 200;
+  } else {
+    p.time_us = g_last_prepared_us;
+    p.requested_channel = g_last_result.requested_channel;
+    p.actual_channel = g_last_result.actual_channel;
+    p.status_flags = g_last_result.status_flags;
+    p.factor_bits = g_last_result.factor_bits;
+    p.pre_delay_ms = g_last_result.pre_delay_ms;
+  }
+  return bench::EncodeBisect(p);
+}
+
+static ae::DataBuffer MakeFinalPayload() {
+  bench::BisectPayload p{};
+  p.type = static_cast(bench::BisectMsgType::kFinal);
+  p.variant_id = static_cast(g_variant > 0 ? g_variant - 1
+                                                         : kFirstVariant);
+  p.prepared_index = kPreparedPerVariant;
+  p.sequence_global = NextSeq();
+  p.time_us = g_last_prepared_us;
+  p.aux_us = g_registration_us;
+  p.requested_channel = g_last_result.requested_channel;
+  p.actual_channel = g_last_result.actual_channel;
+  p.status_flags = g_last_result.status_flags;
+  p.factor_bits = g_last_result.factor_bits;
+  p.pre_delay_ms = g_last_result.pre_delay_ms;
+  p.wifi_ready_count = g_wifi_ready_count;
+  p.encode_count = g_encode_count;
+  p.sendto_count = g_sendto_count;
+  auto const left = prepared_send::PreparedMessageLeft();
+  p.nonce_consumed = g_nonce_start >= left
+                         ? static_cast(g_nonce_start - left)
+                         : g_encode_count;
+  return bench::EncodeBisect(p);
+}
+
+static void ConstructAether() {
+  Stage("CONSTRUCT_BEGIN");
+#if defined(ESP_PLATFORM)
+  PreConstructCleanup();
+#endif
+  g_had_aether_app = true;
+  g_app = ae::AetherApp::Construct(
+      ae::AetherAppContext{}
+#if AE_DISTILLATION && defined(ESP_PLATFORM)
+          .AddAdapterFactory([&](ae::AetherAppContext const& ctx) {
+            return ae::WifiAdapter::ptr::Create(
+                ae::CreateWith{ctx.domain()}.with_id(
+                    ae::GlobalId::kWiFiAdapter),
+                ctx.aether(), ctx.poller(), ctx.dns_resolver(), kWifiInit);
+          })
+#endif
+  );
+  Stage("CONSTRUCT_DONE");
+}
+
+static void DoFullWrite() {
+  if (g_write_armed) {
+    return;
+  }
+  g_write_armed = true;
+  Stage("FULL_WRITE_BEGIN");
+  auto payload = MakeFullPayload();
+  auto& wa = g_stream->Write(std::move(payload));
+  g_write_sub = wa.status_event().Subscribe([](ae::WriteAction::Status st) {
+    // Defer Prepare/Freeze/Save/Exit into the main loop — never nest them
+    // inside the Write completion path.
+    g_full_write_ok = (st == ae::WriteAction::Status::kSuccess);
+    g_pending_full_post_write = true;
+  });
+}
+
+static void MaybeFullWrite() {
+  if (!g_stream || g_write_armed) {
+    return;
+  }
+  if (!g_stream->stream_info().is_writable) {
+    return;
+  }
+  Stage("STREAM_WRITABLE");
+  DoFullWrite();
+}
+
+static void OnFullClientReady(ae::Client::ptr client_ptr) {
+  Stage("SELECT_DONE");
+  g_client = std::move(client_ptr);
+  Stage("STREAM_BEGIN");
+  auto client = g_client.Load();
+  g_stream = std::make_unique(*g_app, client, kServiceUid,
+                                             ae::P2pPortHandle{});
+  g_stream_sub =
+      g_stream->stream_update_event().Subscribe([]() { MaybeFullWrite(); });
+  MaybeFullWrite();
+}
+
+static void StartRegister() {
+  g_phase = Phase::kRegister;
+  g_write_armed = false;
+  g_pending_register_finish = false;
+  g_t0 = NowUs();
+  ConstructAether();
+  Stage("SELECT_BEGIN");
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         Stage("SELECT_FAIL");
+                         g_app->Exit(1);
+                         return;
+                       }
+                       Stage("SELECT_RESULT");
+                       g_client = std::move(res).value();
+                       g_pending_register_finish = true;
+                     });
+}
+
+static void StartFullCycle() {
+  g_phase = Phase::kFullCycle;
+  g_write_armed = false;
+  g_pending_full_post_write = false;
+  g_full_write_ok = false;
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  g_t0 = NowUs();
+  Stage2("BISECT_VARIANT_BEGIN", CurrentVariantName());
+  ConstructAether();
+  Stage("SELECT_BEGIN");
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         Stage("SELECT_FAIL");
+                         g_app->Exit(1);
+                         return;
+                       }
+                       Stage("SELECT_RESULT");
+                       OnFullClientReady(std::move(res).value());
+                     });
+}
+
+static void StartPreparedPhase() {
+  g_phase = Phase::kPrepared;
+  g_prepared_index = 1;
+  g_prepared_waiting_gap = false;
+  g_wifi_ready_count = 0;
+  g_encode_count = 0;
+  g_sendto_count = 0;
+  g_last_prepared_us = 0;
+  g_last_result = {};
+  g_nonce_start =
+      static_cast(prepared_send::PreparedMessageLeft());
+  Stage("RELEASE_BEGIN");
+#if defined(ESP_PLATFORM)
+  prepared_send::ReleaseFullAetherWifiForHotPath();
+  // Let IDF finish tearing down before the first bisect STA init.
+  vTaskDelay(pdMS_TO_TICKS(200));
+#endif
+  Stage("RELEASE_DONE");
+}
+
+static void DoFinalWrite() {
+  if (g_write_armed) {
+    return;
+  }
+  g_write_armed = true;
+  auto& wa = g_stream->Write(MakeFinalPayload());
+  g_write_sub = wa.status_event().Subscribe([](ae::WriteAction::Status) {
+    g_pending_final_exit = true;
+  });
+}
+
+static void MaybeFinalWrite() {
+  if (!g_stream || g_write_armed) {
+    return;
+  }
+  if (!g_stream->stream_info().is_writable) {
+    return;
+  }
+  DoFinalWrite();
+}
+
+static void OnFinalClientReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  auto client = g_client.Load();
+  g_stream = std::make_unique(*g_app, client, kServiceUid,
+                                             ae::P2pPortHandle{});
+  g_stream_sub =
+      g_stream->stream_update_event().Subscribe([]() { MaybeFinalWrite(); });
+  MaybeFinalWrite();
+}
+
+static void StartFinal() {
+  g_phase = Phase::kFinal;
+  g_write_armed = false;
+  g_pending_final_exit = false;
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  ConstructAether();
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kBenchClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnFinalClientReady(std::move(res).value());
+                     });
+}
+
+static void StorePrevSummaryAndAdvance() {
+  Stage2("BISECT_VARIANT_DONE", CurrentVariantName());
+  g_prev_wifi_ready = g_wifi_ready_count;
+  g_prev_encode = g_encode_count;
+  g_prev_sendto = g_sendto_count;
+  auto const left = prepared_send::PreparedMessageLeft();
+  g_prev_nonce = g_nonce_start >= left
+                     ? static_cast(g_nonce_start - left)
+                     : g_encode_count;
+  g_have_prev_summary = true;
+  ++g_variant;
+  if (g_variant >= kLastVariantExclusive) {
+    StartFinal();
+  } else {
+    StartFullCycle();
+  }
+}
+
+static void FinishRegisterInLoop() {
+  Stage("SELECT_DONE");
+  Stage("SAVE_BEGIN");
+  g_app->aether().Save();
+  Stage("SAVE_DONE");
+  g_app->Exit(0);
+}
+
+static void FinishFullPostWriteInLoop() {
+  Stage("FULL_WRITE_DONE");
+  if (!g_full_write_ok) {
+    g_app->Exit(1);
+    return;
+  }
+  Stage("PREPARE_BLOCK_BEGIN");
+  if (!prepared_send::ExportPreparedSendBlock(g_client, kServiceUid,
+                                              kPreparedPerVariant)) {
+    g_app->Exit(1);
+    return;
+  }
+  if (!prepared_send::HasPreparedSendBlock() ||
+      prepared_send::PreparedMessageLeft() !=
+          static_cast(kPreparedPerVariant)) {
+    g_app->Exit(1);
+    return;
+  }
+  Stage("PREPARE_BLOCK_DONE");
+  if (!prepared_send::FreezeBisectWifiCacheFromActiveConnection()) {
+    g_app->Exit(1);
+    return;
+  }
+  g_cache = prepared_send::GetBisectWifiCacheSnapshot();
+  Stage("SAVE_BEGIN");
+  g_app->aether().Save();
+  Stage("SAVE_DONE");
+  g_app->Exit(0);
+}
+
+void setup() {
+  Stage("BOOT");
+#if defined(ESP_PLATFORM)
+  nvs_flash_init();
+  prepared_send::InvalidatePreparedWifiCache();
+#endif
+  g_done = false;
+  g_seq = 0;
+  g_registration_pending = true;
+  g_variant = kFirstVariant;
+  g_have_prev_summary = false;
+  g_pending_register_finish = false;
+  g_pending_full_post_write = false;
+  g_pending_final_exit = false;
+}
+
+void loop() {
+  if (g_done) {
+    return;
+  }
+
+  if (g_registration_pending) {
+    g_registration_pending = false;
+    StartRegister();
+    return;
+  }
+
+  auto process_deferred = []() {
+    if (g_app && g_pending_register_finish) {
+      g_pending_register_finish = false;
+      FinishRegisterInLoop();
+      return true;
+    }
+    if (g_app && g_pending_full_post_write) {
+      g_pending_full_post_write = false;
+      FinishFullPostWriteInLoop();
+      return true;
+    }
+    if (g_app && g_pending_final_exit) {
+      g_pending_final_exit = false;
+      g_app->Exit(0);
+      return true;
+    }
+    return false;
+  };
+
+  // Catch deferred work that was armed before this tick.
+  if (process_deferred()) {
+    return;
+  }
+
+  if (g_phase == Phase::kPrepared) {
+#if defined(ESP_PLATFORM)
+    if (g_prepared_waiting_gap) {
+      if (xTaskGetTickCount() < g_prepared_gap_until) {
+        vTaskDelay(pdMS_TO_TICKS(20));
+        return;
+      }
+      g_prepared_waiting_gap = false;
+    }
+#endif
+
+    if (g_prepared_index > kPreparedPerVariant) {
+      StorePrevSummaryAndAdvance();
+      return;
+    }
+
+    int const i = g_prepared_index;
+    auto payload = MakePreparedPayload(i);
+#if defined(ESP_PLATFORM)
+    auto const result = prepared_send::SendPreparedOnceWithBisectFactor(
+        CurrentVariant(), payload);
+#else
+    prepared_send::BisectSendResult result{};
+    result.status = prepared_send::HotSendStatus::kUnsupported;
+#endif
+    g_last_result = result;
+    g_last_prepared_us = result.total_us;
+    if (result.status_flags &
+        static_cast(bench::BisectStatusBits::kWifiReady)) {
+      ++g_wifi_ready_count;
+    }
+    if (result.status_flags &
+        static_cast(bench::BisectStatusBits::kEncodeOk)) {
+      ++g_encode_count;
+    }
+    if (result.status_flags &
+        static_cast(bench::BisectStatusBits::kSendtoOk)) {
+      ++g_sendto_count;
+    }
+
+    ++g_prepared_index;
+    if (g_prepared_index <= kPreparedPerVariant) {
+#if defined(ESP_PLATFORM)
+      g_prepared_waiting_gap = true;
+      g_prepared_gap_until =
+          xTaskGetTickCount() + pdMS_TO_TICKS(kPreparedGapMs);
+#endif
+    }
+    return;
+  }
+
+  if (!g_app) {
+    return;
+  }
+
+  if (!g_app->IsExited()) {
+    auto t = g_app->Update(ae::Now());
+    // SelectClient / Write may arm deferred work during Update — run it before
+    // WaitUntil so we do not stall on the next wake delay.
+    if (process_deferred()) {
+      return;
+    }
+    if (!g_app->IsExited()) {
+      g_app->WaitUntil(t);
+    }
+    return;
+  }
+
+  if (g_phase == Phase::kRegister) {
+    ReleaseApp();
+    g_registration_us = static_cast(NowUs() - g_t0);
+    StartFullCycle();
+    return;
+  }
+
+  if (g_phase == Phase::kFullCycle) {
+    ReleaseApp();
+    auto const full_us = static_cast(NowUs() - g_t0);
+    g_last_full_us = full_us;
+    g_pending_full_us = full_us;
+    g_have_pending_full = true;
+    StartPreparedPhase();
+    return;
+  }
+
+  if (g_phase == Phase::kFinal) {
+    ReleaseApp();
+    g_phase = Phase::kDone;
+    g_done = true;
+  }
+}
+
+}  // namespace
+}  // namespace temp_sensor
+
+void setup() { temp_sensor::setup(); }
+void loop() { temp_sensor::loop(); }
diff --git a/main/sensors/utils.h b/main/sensors/utils.h
index 4757403..febc790 100644
--- a/main/sensors/utils.h
+++ b/main/sensors/utils.h
@@ -17,8 +17,16 @@
 #if defined ESP_PLATFORM
 
 #  include 
-#  include 
 #  include 
+#  if ULP_COMP == 1
+#    include 
+#    define I2C_BUS_HANDLE int
+#    define I2C_HANDLE_PORT i2c_port_t
+#  elif ULP_COMP == 0
+#    include 
+#    define I2C_BUS_HANDLE i2c_master_bus_handle_t*
+#    define I2C_HANDLE_PORT i2c_master_dev_handle_t
+#  endif
 
 #  ifdef __cplusplus
 extern "C" {
diff --git a/main/sleeping/esp_main_sleep.cpp b/main/sleeping/esp_main_sleep.cpp
index f6655aa..50eebdf 100644
--- a/main/sleeping/esp_main_sleep.cpp
+++ b/main/sleeping/esp_main_sleep.cpp
@@ -17,6 +17,7 @@
 #include "sleeping/sleeping.h"
 
 #include 
+#include 
 
 #include "aether/all.h"
 
@@ -48,9 +49,15 @@
 static const char* TAG = "ESP_MAIN_SLEEP";
 
 int DeepSleep(time_point soft_sleep_tp, time_point, std::int16_t) {
-  auto time_us = std::chrono::duration_cast(
-                     soft_sleep_tp - std::chrono::system_clock::now())
-                     .count();
+  auto time_us = std::invoke([&]() -> std::uint64_t {
+    auto current_time = std::chrono::system_clock::now();
+    if (soft_sleep_tp < current_time) {
+      return 0;
+    }
+    return std::chrono::duration_cast(soft_sleep_tp -
+                                                                 current_time)
+        .count();
+  });
 
   esp_sleep_enable_timer_wakeup(time_us);
   ESP_LOGI(TAG, "Timer wakeup enabled: %llu us", time_us);
diff --git a/main/user_config.h b/main/user_config.h
index 8579c3e..41591b2 100644
--- a/main/user_config.h
+++ b/main/user_config.h
@@ -54,7 +54,7 @@
 #  define BOARD_M5STACK_ATOM_LITE 4
 
 #  ifndef BOARD
-#    define BOARD BOARD_NANO_ESP32_C6
+#    define BOARD BOARD_AETHER_ESP32_C6
 #  endif
 
 #  if BOARD == BOARD_AETHER_ESP32_C6
diff --git a/main/wifi_lifecycle_bench.cpp b/main/wifi_lifecycle_bench.cpp
new file mode 100644
index 0000000..13a89a6
--- /dev/null
+++ b/main/wifi_lifecycle_bench.cpp
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * Wi-Fi lifecycle benchmark: single metric init_to_release_ms, 10 cycles.
+ */
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "aether/all.h"
+#include "aether/ae_exp_wifi.h"
+#include "aether/config.h"
+#include "aether/env.h"
+#include "aether-miscpp/serialization/binary_archive.h"
+#include "wifi_lifecycle_out.h"
+
+#if defined(ESP_PLATFORM)
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#  include 
+#endif
+
+using namespace std::chrono_literals;
+
+namespace temp_sensor {
+namespace {
+
+static constexpr auto kParentUid =
+    ae::Uid::FromString("b1ac52c8-8d94-bd39-4c01-a631ac594165");
+static constexpr char const* kClientId = "Controller";
+
+#if defined(SERVICE_UID)
+static constexpr auto kServiceUid = ae::Uid::FromString(SERVICE_UID);
+#else
+static constexpr auto kServiceUid =
+    ae::Uid::FromString("015f10b0-73cc-4917-8804-5ecb19ede984");
+#endif
+
+#if defined(AE_EXP_WIFI_LIFECYCLE_CYCLES)
+static constexpr int kMeasureCycles = AE_EXP_WIFI_LIFECYCLE_CYCLES;
+#else
+static constexpr int kMeasureCycles = 10;
+#endif
+
+#if defined(AE_EXP_WIFI_COOLDOWN_MS)
+static constexpr int kCooldownMs = AE_EXP_WIFI_COOLDOWN_MS;
+#else
+static constexpr int kCooldownMs = 0;
+#endif
+
+#if defined(AE_EXP_WIFI_LIFECYCLE_VARIANT)
+static constexpr int kVariant = AE_EXP_WIFI_LIFECYCLE_VARIANT;
+#else
+static constexpr int kVariant = 0;
+#endif
+
+#if defined(ESP_PLATFORM)
+static const auto kWifiInit = ae::WiFiInit{
+    std::vector{{ae::WifiCreds{WIFI_SSID, WIFI_PASSWORD}, {}}},
+    {},
+};
+
+static void PreConstructCleanup() {
+  if (kCooldownMs > 0) {
+    vTaskDelay(pdMS_TO_TICKS(kCooldownMs));
+  }
+#  if !AE_WIFI_USE_FULL_DEINIT
+  // Legacy driver Deinit leaves default event loop / netif; clear before next
+  // Construct so the stack can be recreated.
+  esp_netif_deinit();
+  esp_event_loop_delete_default();
+#  endif
+}
+
+static std::int64_t NowUs() { return esp_timer_get_time(); }
+#endif
+
+struct Ping {
+  AE_REFLECT_MEMBERS(root_code, size, dev_code, index)
+  std::uint8_t root_code{0x3};
+  std::uint8_t size{4};
+  std::uint8_t dev_code{0x15};
+  std::uint32_t index{0};
+};
+
+enum class Phase : std::uint8_t { kRegister, kMeasure, kDone };
+
+static std::shared_ptr g_app;
+static ae::Client::ptr g_client;
+static std::unique_ptr g_stream;
+static ae::Subscription g_select_sub;
+static ae::Subscription g_stream_sub;
+static ae::Subscription g_write_sub;
+
+static Phase g_phase = Phase::kRegister;
+static int g_cycle = 0;
+static bool g_write_armed = false;
+static bool g_done = false;
+
+static std::array g_times_ms{};
+static int g_completed = 0;
+
+#if defined(ESP_PLATFORM)
+static std::int64_t g_t0 = 0;
+#endif
+
+static ae::DataBuffer MakePing(std::uint32_t index) {
+  Ping ping{};
+  ping.index = index;
+  ae::DataBuffer msg{};
+  auto archive = ae::seri::BinaryArchive{ae::seri::BinaryVectorBuffer<>{msg}};
+  archive.Save(ping);
+  return msg;
+}
+
+static void ReleaseMeasuredApp() {
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+  g_app.reset();
+}
+
+static void FinishCycleAndNext();
+static void StartMeasureCycle(int cycle);
+
+static void DoWrite() {
+  if (g_write_armed) {
+    return;
+  }
+  g_write_armed = true;
+  auto& wa = g_stream->Write(MakePing(static_cast(g_cycle)));
+  g_write_sub = wa.status_event().Subscribe([](ae::WriteAction::Status st) {
+    if (st != ae::WriteAction::Status::kSuccess) {
+      WifiLifecyclePrintf("cycle=%d init_to_release_ms=0 result=FAIL\n", g_cycle);
+      WifiLifecyclePrintf("WIFI_CYCLE_ERR\tcycle=%d\twrite_fail\n", g_cycle);
+      g_app->Exit(1);
+      return;
+    }
+    g_app->aether().Save();
+    g_app->Exit(0);
+  });
+}
+
+static void MaybeWrite() {
+  if (!g_stream || g_write_armed) {
+    return;
+  }
+  if (!g_stream->stream_info().is_writable) {
+    return;
+  }
+  DoWrite();
+}
+
+static void OnClientReady(ae::Client::ptr client_ptr) {
+  g_client = std::move(client_ptr);
+  if (g_phase == Phase::kRegister) {
+    g_app->aether().Save();
+    g_app->Exit(0);
+    return;
+  }
+
+  auto client = g_client.Load();
+  g_stream = std::make_unique(*g_app, client, kServiceUid,
+                                             ae::P2pPortHandle{});
+  g_stream_sub =
+      g_stream->stream_update_event().Subscribe([]() { MaybeWrite(); });
+  MaybeWrite();
+}
+
+static void StartMeasureCycle(int cycle) {
+  g_phase = Phase::kMeasure;
+  g_cycle = cycle;
+  g_write_armed = false;
+  g_select_sub.Reset();
+  g_stream_sub.Reset();
+  g_write_sub.Reset();
+  g_stream.reset();
+  g_client = {};
+
+#if defined(ESP_PLATFORM)
+  PreConstructCleanup();
+  g_t0 = NowUs();
+#endif
+
+  g_app = ae::AetherApp::Construct(
+      ae::AetherAppContext{}
+#if AE_DISTILLATION && defined(ESP_PLATFORM)
+          .AddAdapterFactory([&](ae::AetherAppContext const& ctx) {
+            return ae::WifiAdapter::ptr::Create(
+                ae::CreateWith{ctx.domain()}.with_id(
+                    ae::GlobalId::kWiFiAdapter),
+                ctx.aether(), ctx.poller(), ctx.dns_resolver(), kWifiInit);
+          })
+#endif
+  );
+
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         WifiLifecyclePrintf(
+                             "cycle=%d init_to_release_ms=0 result=FAIL\n",
+                             g_cycle);
+                         WifiLifecyclePrintf("WIFI_CYCLE_ERR\tcycle=%d\tselect\n",
+                                             g_cycle);
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnClientReady(std::move(res).value());
+                     });
+}
+
+static void StartRegisterCycle() {
+  g_phase = Phase::kRegister;
+  g_cycle = 0;
+  g_write_armed = false;
+#if defined(ESP_PLATFORM)
+  PreConstructCleanup();
+#endif
+  g_app = ae::AetherApp::Construct(
+      ae::AetherAppContext{}
+#if AE_DISTILLATION && defined(ESP_PLATFORM)
+          .AddAdapterFactory([&](ae::AetherAppContext const& ctx) {
+            return ae::WifiAdapter::ptr::Create(
+                ae::CreateWith{ctx.domain()}.with_id(
+                    ae::GlobalId::kWiFiAdapter),
+                ctx.aether(), ctx.poller(), ctx.dns_resolver(), kWifiInit);
+          })
+#endif
+  );
+  g_select_sub = g_app->aether()
+                     ->SelectClient(kParentUid, kClientId)
+                     .result_event()
+                     .Subscribe([](ae::Result res) {
+                       if (!res) {
+                         g_app->Exit(1);
+                         return;
+                       }
+                       OnClientReady(std::move(res).value());
+                     });
+}
+
+static std::uint32_t MedianMs() {
+  std::array sorted{};
+  for (int i = 0; i < g_completed; ++i) {
+    sorted[static_cast(i)] = g_times_ms[static_cast(i)];
+  }
+  std::sort(sorted.begin(), sorted.begin() + g_completed);
+  if (g_completed == 0) {
+    return 0;
+  }
+  if (g_completed % 2 == 1) {
+    return sorted[static_cast(g_completed / 2)];
+  }
+  auto const a = sorted[static_cast(g_completed / 2 - 1)];
+  auto const b = sorted[static_cast(g_completed / 2)];
+  return (a + b) / 2;
+}
+
+static void PrintSummary() {
+  std::uint32_t min_ms = UINT32_MAX;
+  std::uint32_t max_ms = 0;
+  for (int i = 0; i < g_completed; ++i) {
+    auto const v = g_times_ms[static_cast(i)];
+    min_ms = std::min(min_ms, v);
+    max_ms = std::max(max_ms, v);
+  }
+  if (g_completed == 0) {
+    min_ms = 0;
+  }
+  WifiLifecyclePrintf("WIFI_SUMMARY\tvariant=%d\tcompleted=%d\tmin=%lu\tmedian=%lu\tmax=%lu\n",
+                      kVariant, g_completed, static_cast(min_ms),
+                      static_cast(MedianMs()),
+                      static_cast(max_ms));
+  WifiLifecyclePrintf("raw=");
+  for (int i = 0; i < g_completed; ++i) {
+    if (i > 0) {
+      WifiLifecyclePrintf(",");
+    }
+    WifiLifecyclePrintf(
+        "%lu",
+        static_cast(g_times_ms[static_cast(i)]));
+  }
+  WifiLifecyclePrintf("\n");
+  WifiLifecyclePrintf("min=%lu\n", static_cast(min_ms));
+  WifiLifecyclePrintf("median=%lu\n",
+                      static_cast(MedianMs()));
+  WifiLifecyclePrintf("max=%lu\n", static_cast(max_ms));
+  WifiLifecyclePrintf("completed=%d\n", g_completed);
+  for (int i = 0; i < g_completed; ++i) {
+    WifiLifecyclePrintf("WIFI_RAW\tvariant=%d\tcycle=%d\tinit_to_release_ms=%lu\n",
+                        kVariant, i + 1,
+                        static_cast(
+                            g_times_ms[static_cast(i)]));
+  }
+}
+
+static void FinishCycleAndNext() {
+  if (g_phase == Phase::kRegister) {
+    ReleaseMeasuredApp();
+    StartMeasureCycle(1);
+    return;
+  }
+
+  ReleaseMeasuredApp();
+
+#if defined(ESP_PLATFORM)
+  auto const ms = static_cast((NowUs() - g_t0) / 1000);
+#else
+  auto const ms = 0U;
+#endif
+
+  if (g_completed < kMeasureCycles) {
+    g_times_ms[static_cast(g_completed)] = ms;
+    WifiLifecyclePrintf("cycle=%d init_to_release_ms=%lu result=OK\n", g_cycle,
+                        static_cast(ms));
+    WifiLifecyclePrintf("WIFI_CYCLE\tvariant=%d\tcycle=%d\tinit_to_release_ms=%lu\n",
+                        kVariant, g_cycle, static_cast(ms));
+    ++g_completed;
+  }
+
+  if (g_cycle < kMeasureCycles) {
+    StartMeasureCycle(g_cycle + 1);
+    return;
+  }
+
+  PrintSummary();
+  g_done = true;
+  g_phase = Phase::kDone;
+}
+
+}  // namespace
+
+void BeginAppMainTiming() {}
+void FinalizeCycleBeforeSleep() {}
+#if defined(ESP_PLATFORM)
+void EnterDeepSleep() {}
+#endif
+
+void setup() {
+#if defined(ESP_PLATFORM)
+  nvs_flash_init();
+#endif
+  WifiLifecyclePrintf("WIFI_BENCH_START\tvariant=%d\tcooldown_ms=%d\n", kVariant,
+                      kCooldownMs);
+  g_done = false;
+  g_completed = 0;
+  StartRegisterCycle();
+}
+
+void loop() {
+  if (g_done || !g_app) {
+    return;
+  }
+  if (!g_app->IsExited()) {
+    auto t = g_app->Update(ae::Now());
+    g_app->WaitUntil(t);
+    return;
+  }
+  FinishCycleAndNext();
+}
+
+}  // namespace temp_sensor
+
+void setup() { temp_sensor::setup(); }
+void loop() { temp_sensor::loop(); }
diff --git a/main/wifi_lifecycle_out.h b/main/wifi_lifecycle_out.h
new file mode 100644
index 0000000..e970b61
--- /dev/null
+++ b/main/wifi_lifecycle_out.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * USB Serial JTAG output for Wi-Fi lifecycle benchmark (works with CONSOLE_NONE).
+ */
+#ifndef TEMP_SENSOR_WIFI_LIFECYCLE_OUT_H_
+#define TEMP_SENSOR_WIFI_LIFECYCLE_OUT_H_
+
+#if defined(ESP_PLATFORM)
+#  include 
+#  include 
+
+#  include 
+#  include 
+
+inline void WifiLifecycleEnsureUsbSerial() {
+  static bool installed = false;
+  if (!installed) {
+    usb_serial_jtag_driver_config_t cfg = USB_SERIAL_JTAG_DRIVER_CONFIG_DEFAULT();
+    usb_serial_jtag_driver_install(&cfg);
+    installed = true;
+  }
+}
+
+inline void WifiLifecycleWriteRaw(char const* data, size_t len) {
+  if (data != nullptr && len > 0) {
+    WifiLifecycleEnsureUsbSerial();
+    usb_serial_jtag_write_bytes(data, len, portMAX_DELAY);
+  }
+}
+
+inline void WifiLifecyclePrintf(char const* fmt, ...) {
+  char buf[160];
+  va_list args;
+  va_start(args, fmt);
+  int const n = vsnprintf(buf, sizeof(buf), fmt, args);
+  va_end(args);
+  if (n > 0) {
+    WifiLifecycleWriteRaw(buf, static_cast(n));
+  }
+}
+#else
+inline void WifiLifecyclePrintf(char const* /*fmt*/, ...) {}
+#endif
+
+#endif  // TEMP_SENSOR_WIFI_LIFECYCLE_OUT_H_
diff --git a/sdkconfig.defaults b/sdkconfig.defaults
index 86072ad..50d28b8 100644
--- a/sdkconfig.defaults
+++ b/sdkconfig.defaults
@@ -32,6 +32,7 @@ CONFIG_PARTITION_TABLE_MD5=y
 
 
 CONFIG_ESP_MAIN_TASK_STACK_SIZE=10112
+CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096
 
 CONFIG_HTTPD_MAX_REQ_HDR_LEN=2048
 CONFIG_HTTPD_MAX_URI_LEN=2048
@@ -58,3 +59,80 @@ CONFIG_LOG_DEFAULT_LEVEL=3
 CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=n
 CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG=y
 CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED=y
+
+# Disable BOD
+#CONFIG_ESP_BROWNOUT_DET=n
+
+#==============================Optimization=========================================
+
+# 1. Compiler optimization (Critical for execution speed)
+CONFIG_COMPILER_OPTIMIZATION_SIZE=y
+CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE=y
+
+# 2. Bootloader acceleration
+# Skip image validation when exiting Deep Sleep (saves ~100-150ms)
+CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y
+CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON=y
+CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y
+
+# 3. Disable logging (UART is the main bottleneck at startup)
+CONFIG_LOG_DEFAULT_LEVEL_NONE=y
+CONFIG_LOG_MAXIMUM_LEVEL_0=y
+
+# 4. Radio and Wi-Fi (No-NVS mode)
+# Move PHY calibration to RTC RAM (eliminates Flash accesses)
+# CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE_IN_RTC=y
+# Completely disable Wi-Fi stack dependency on NVS
+# CONFIG_ESP_WIFI_NVS_ENABLED=n
+
+# 5. ESP32-C6 specific settings for fast startup
+CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y
+CONFIG_ESP32C6_REV_MIN_0=y
+
+CONFIG_ESP_WIFI_AMPDU_TX_ENABLED=n
+CONFIG_ESP_WIFI_AMPDU_RX_ENABLED=n
+# Use partial calibration (takes data from NVS, doesn't re-measure)
+CONFIG_ESP_PHY_RF_CAL_PARTIAL=y
+# Disable verbose PHY logs
+CONFIG_ESP_PHY_LOG_VERBOSE=n
+CONFIG_RTC_CLK_CAL_THRESHOLD=0
+CONFIG_ESP_PHY_ENABLE_USB_CONTROLLER=n
+
+# Force power-down of Flash in deep sleep
+CONFIG_ESP_SLEEP_POWER_DOWN_FLASH=y
+
+# Power down VDDSDIO (memory controller) during sleep
+CONFIG_ESP_SLEEP_PD_DOMAIN_VDDSDIO=y
+
+# Use internal RC oscillator (most power-efficient sleep clocking option)
+CONFIG_RTC_CLK_SRC_INT_RC=y
+
+# Disable clocking of unused RTC-domain peripherals
+CONFIG_RTC_CLK_CAL_THRESHOLD=0
+
+# Redirect console to UART0 or disable entirely (None)
+# This frees built-in USB-JTAG resources
+CONFIG_ESP_CONSOLE_UART_DEFAULT=y
+CONFIG_ESP_CONSOLE_SECONDARY_NONE=y
+
+# Disable USB-Serial-JTAG clocking in sleep mode
+CONFIG_ESP_PHY_ENABLE_USB_CONTROLLER=n
+
+# Minimize power stabilization time (Brownout)
+CONFIG_ESP_BROWNOUT_DET=n
+CONFIG_ESP_BROWNOUT_DET_LVL_SEL_7=y
+
+
+CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y
+# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_40=y
+
+CONFIG_ESPTOOLPY_FLASHMODE_DIO=y
+## CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
+CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
+CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
+
+CONFIG_PM_ENABLE=y
+# CONFIG_PM_DFS_INIT_FREQ_MAX_40=y
+
+CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
+CONFIG_FREERTOS_IDLE_TASK_REPLICATION=n
diff --git a/sdkconfig.defaults.bench b/sdkconfig.defaults.bench
new file mode 100644
index 0000000..6670f42
--- /dev/null
+++ b/sdkconfig.defaults.bench
@@ -0,0 +1,13 @@
+# Bench harness overrides: USB console for AE_EXP_BENCH_STAGE printf markers.
+# Applied after sdkconfig.defaults when SDKCONFIG_DEFAULTS includes this file.
+
+# CONFIG_ESP_CONSOLE_NONE is not set
+CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
+CONFIG_ESP_CONSOLE_SECONDARY_NONE=y
+
+CONFIG_ESP_MAIN_TASK_STACK_SIZE=16384
+
+CONFIG_LOG_DEFAULT_LEVEL_INFO=y
+CONFIG_LOG_DEFAULT_LEVEL=3
+CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y
+CONFIG_BOOTLOADER_LOG_LEVEL=3
diff --git a/sdkconfig.defaults.deepsleep_5x50 b/sdkconfig.defaults.deepsleep_5x50
new file mode 100644
index 0000000..1698082
--- /dev/null
+++ b/sdkconfig.defaults.deepsleep_5x50
@@ -0,0 +1,21 @@
+# Deep-sleep 5x50 prepared E2E overlay (applied after silent+fastest+wpa2only).
+
+# External RTC crystal (do not use INT_RC for this experiment).
+CONFIG_RTC_CLK_SRC_EXT_CRYS=y
+# CONFIG_RTC_CLK_SRC_INT_RC is not set
+CONFIG_RTC_CLK_CAL_CYCLES=0
+
+# Hardware brownout detector ON.
+CONFIG_ESP_BROWNOUT_DET=y
+CONFIG_ESP_BROWNOUT_DET_LVL_SEL_7=y
+
+# No power management / DFS during measurement.
+# CONFIG_PM_ENABLE is not set
+# CONFIG_FREERTOS_USE_TICKLESS_IDLE is not set
+
+# Deep-sleep boot acceleration.
+CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y
+
+# CPU 160 MHz (also in fastest overlay; keep explicit).
+CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y
+CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=160
diff --git a/sdkconfig.defaults.fastest b/sdkconfig.defaults.fastest
new file mode 100644
index 0000000..4ae8a5a
--- /dev/null
+++ b/sdkconfig.defaults.fastest
@@ -0,0 +1,6 @@
+# Fastest-path measurement extras on top of sdkconfig.defaults.silent.
+# CPU: 160 MHz, no DFS / no power-management experiments.
+
+# CONFIG_PM_ENABLE is not set
+CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_160=y
+CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=160
diff --git a/sdkconfig.defaults.silent b/sdkconfig.defaults.silent
new file mode 100644
index 0000000..c274f60
--- /dev/null
+++ b/sdkconfig.defaults.silent
@@ -0,0 +1,17 @@
+# Silent measurement build: no console / no logging.
+
+CONFIG_ESP_CONSOLE_NONE=y
+CONFIG_ESP_CONSOLE_SECONDARY_NONE=y
+
+CONFIG_LOG_DEFAULT_LEVEL_NONE=y
+CONFIG_LOG_DEFAULT_LEVEL=0
+CONFIG_LOG_MAXIMUM_LEVEL=0
+
+CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y
+CONFIG_BOOTLOADER_LOG_LEVEL=0
+
+CONFIG_ESP_MAIN_TASK_STACK_SIZE=16384
+
+# Needed so etharp_add_static_entry is compiled (via DHCPS_STATIC_ENTRIES mapping
+# in ESP-IDF lwipopts). Already typically enabled; keep explicit for silent builds.
+CONFIG_LWIP_DHCPS_STATIC_ENTRIES=y
diff --git a/sdkconfig.defaults.wpa2only b/sdkconfig.defaults.wpa2only
new file mode 100644
index 0000000..0a9081c
--- /dev/null
+++ b/sdkconfig.defaults.wpa2only
@@ -0,0 +1,3 @@
+# Benchmark-only overlay. Do not use for production firmware.
+# CONFIG_ESP_WIFI_ENABLE_WPA3_SAE is not set
+# CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE is not set
diff --git a/system/partitions.csv b/system/partitions.csv
index 1ebf306..bd65597 100644
--- a/system/partitions.csv
+++ b/system/partitions.csv
@@ -2,5 +2,5 @@
 # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
 nvs,      data, nvs,     ,        0x6000,
 phy_init, data, phy,     ,        0x1000,
-factory,  app,  factory, ,        2M,
-storage,  data, spiffs,  ,        1900K  
\ No newline at end of file
+factory,  app,  factory, ,        3M,
+storage,  data, spiffs,  ,        900K  
\ No newline at end of file
diff --git a/temperature_receiver/CMakeLists.txt b/temperature_receiver/CMakeLists.txt
new file mode 100644
index 0000000..038e8ca
--- /dev/null
+++ b/temperature_receiver/CMakeLists.txt
@@ -0,0 +1,29 @@
+# Copyright 2026 Aethernet Inc.
+cmake_minimum_required(VERSION 3.16)
+project(temperature_receiver LANGUAGES CXX)
+
+set(CMAKE_CXX_STANDARD 20)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+set(USER_CONFIG "${CMAKE_CURRENT_LIST_DIR}/user_config.h" CACHE PATH "" FORCE)
+set(AE_DISTILLATION OFF CACHE BOOL "" FORCE)
+set(AE_FILTRATION ON CACHE BOOL "" FORCE)
+
+include("${CMAKE_CURRENT_LIST_DIR}/../cmake/CPM.cmake")
+# Pin exact SHA. Override locally with -DCPM_aether-client-cpp_SOURCE=.
+  CPMAddPackage(URI "https://github.com/aethernetio/aether-client-cpp.git#157aadbec8e7b852d0f89274307ff7cb8103e5f7")
+
+# MinGW + Parallel STL emits #pragma message noise that breaks -Werror builds.
+if(TARGET aether AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+  target_compile_options(aether PRIVATE -Wno-error -Wno-cpp)
+endif()
+
+add_executable(temperature_receiver main.cpp)
+target_include_directories(temperature_receiver PRIVATE
+  "${CMAKE_CURRENT_LIST_DIR}/../main")
+target_compile_definitions(temperature_receiver PRIVATE
+  "USER_CONFIG=\"${CMAKE_CURRENT_LIST_DIR}/user_config.h\"")
+target_link_libraries(temperature_receiver PRIVATE aether)
+
+# Keep aether state under ./state next to the binary cwd.
+# FileSystemStdStorage always uses relative "state/" directory.
diff --git a/temperature_receiver/main.cpp b/temperature_receiver/main.cpp
new file mode 100644
index 0000000..ff6c946
--- /dev/null
+++ b/temperature_receiver/main.cpp
@@ -0,0 +1,666 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ *
+ * Desktop Æther receiver for prepared boot/wifi opt (0xD8), MAC-retry (0xD7),
+ * TX-done (0xD6) and deep-sleep E2E (0xD5). Deduplicates by record_id; appends TSV.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#if defined(_WIN32)
+#  include 
+#endif
+
+#include "aether/all.h"
+#include "bench_payload.h"
+
+using namespace std::chrono_literals;
+
+namespace {
+
+static constexpr auto kParentUid =
+    ae::Uid::FromString("b1ac52c8-8d94-bd39-4c01-a631ac594165");
+static constexpr char const* kClientName = "prepared_wifi_cache_rx_v1";
+
+struct Meas {
+  std::uint16_t record_id{0};
+  std::uint8_t kind{0};
+  std::uint8_t outer{0};
+  std::uint8_t hot{0};
+  std::uint32_t user_us{0};
+  std::uint32_t wifi_us{0};
+  std::uint32_t connect_us{0};
+  std::uint32_t txdone_us{0};
+  std::uint32_t teardown_us{0};
+  std::uint32_t sleep_elapsed_us{0};
+  std::uint32_t sleep_overhead_us{0};
+  std::uint32_t app_entry_us{0};
+  std::uint8_t cb_seen{0};
+  std::uint8_t cb_timeout{0};
+  std::uint8_t brownout{0};
+  std::uint8_t auth{0};
+  std::uint8_t diag_mode{0};
+  std::uint8_t tx_cb_total{0};
+  std::uint8_t tx_cb_success{0};
+  std::uint8_t tx_cb_failed{0};
+  std::uint8_t first_status{0xff};
+  std::uint32_t first_cb_delta_us{0xffffffffu};
+  std::uint32_t first_success_delta_us{0xffffffffu};
+  std::uint32_t first_failed_delta_us{0xffffffffu};
+  std::uint32_t last_cb_delta_us{0xffffffffu};
+  std::uint8_t callbacks_after_success{0};
+  std::int8_t rssi{0};
+  std::uint8_t disconnect_count{0};
+  std::uint8_t last_disconnect_reason{0};
+  std::uint8_t reconnect_count{0};
+  std::uint8_t ap_primary{0};
+  std::uint16_t seq{0};
+  std::uint8_t variant{0};
+  std::uint8_t short_retry{0};
+  std::uint8_t long_retry{0};
+  std::uint8_t retry_called{0};
+  std::int16_t retry_set_rc{-1};
+  std::uint32_t retry_cfg_us{0};
+  std::uint32_t encode_us{0};
+  std::uint8_t actual_channel{0};
+  std::uint32_t wifi_init_us{0};
+  std::uint32_t heap_before{0};
+  std::uint32_t heap_after{0};
+};
+
+std::mutex g_mu;
+std::vector> g_streams;
+std::set g_seen_records;
+std::vector g_meas;
+int g_full_recv = 0;
+int g_hot_recv = 0;
+int g_final_recv = 0;
+int g_dup_records = 0;
+int g_ooo = 0;
+int g_max_record = 0;
+int g_brownout_boots = 0;
+
+std::filesystem::path TsvPath() {
+#if defined(_WIN32)
+  if (char const* env = std::getenv("AE_DS_TSV")) {
+    return std::filesystem::path{env};
+  }
+#endif
+  return std::filesystem::path{"prepared_mac_retry_diag.tsv"};
+}
+
+std::uint32_t PercentileUs(std::vector v, int pct) {
+  if (v.empty()) {
+    return 0;
+  }
+  std::sort(v.begin(), v.end());
+  auto const i = static_cast((v.size() - 1) * pct / 100);
+  return v[i];
+}
+
+void EnsureTsvHeader() {
+  auto const path = TsvPath();
+  if (std::filesystem::exists(path) && std::filesystem::file_size(path) > 0) {
+    return;
+  }
+  std::ofstream out(path, std::ios::app);
+  out << "record_id\tkind\touter\thot\tuser_us\twifi_us\tconnect_us\ttxdone_us\t"
+         "teardown_us\tsleep_elapsed_us\tsleep_overhead_us\tapp_entry_us\t"
+         "cb_seen\tcb_timeout\tbrownout\tauth\tseq\tdiag_mode\ttx_cb_total\t"
+         "tx_cb_success\ttx_cb_failed\tfirst_status\tfirst_cb_delta_us\t"
+         "first_success_delta_us\tfirst_failed_delta_us\tlast_cb_delta_us\t"
+         "callbacks_after_success\trssi\tdisconnect_count\t"
+         "last_disconnect_reason\treconnect_count\tap_primary\t"
+         "variant\tshort_retry\tlong_retry\tretry_called\tretry_set_rc\t"
+         "retry_cfg_us\tencode_us\tactual_channel\twifi_init_us\t"
+         "heap_before\theap_after\n";
+}
+
+void AppendTsv(Meas const& m) {
+  EnsureTsvHeader();
+  std::ofstream out(TsvPath(), std::ios::app);
+  out << m.record_id << '\t' << static_cast(m.kind) << '\t'
+      << static_cast(m.outer) << '\t' << static_cast(m.hot) << '\t'
+      << m.user_us << '\t' << m.wifi_us << '\t' << m.connect_us << '\t'
+      << m.txdone_us << '\t' << m.teardown_us << '\t' << m.sleep_elapsed_us
+      << '\t' << m.sleep_overhead_us << '\t' << m.app_entry_us << '\t'
+      << static_cast(m.cb_seen) << '\t' << static_cast(m.cb_timeout)
+      << '\t' << static_cast(m.brownout) << '\t'
+      << static_cast(m.auth) << '\t' << m.seq << '\t'
+      << static_cast(m.diag_mode) << '\t'
+      << static_cast(m.tx_cb_total) << '\t'
+      << static_cast(m.tx_cb_success) << '\t'
+      << static_cast(m.tx_cb_failed) << '\t'
+      << static_cast(m.first_status) << '\t' << m.first_cb_delta_us << '\t'
+      << m.first_success_delta_us << '\t' << m.first_failed_delta_us << '\t'
+      << m.last_cb_delta_us << '\t'
+      << static_cast(m.callbacks_after_success) << '\t'
+      << static_cast(m.rssi) << '\t'
+      << static_cast(m.disconnect_count) << '\t'
+      << static_cast(m.last_disconnect_reason) << '\t'
+      << static_cast(m.reconnect_count) << '\t'
+      << static_cast(m.ap_primary) << '\t'
+      << static_cast(m.variant) << '\t'
+      << static_cast(m.short_retry) << '\t'
+      << static_cast(m.long_retry) << '\t'
+      << static_cast(m.retry_called) << '\t'
+      << static_cast(m.retry_set_rc) << '\t' << m.retry_cfg_us << '\t'
+      << m.encode_us << '\t' << static_cast(m.actual_channel) << '\t'
+      << m.wifi_init_us << '\t' << m.heap_before << '\t' << m.heap_after
+      << '\n';
+}
+
+void NoteRecord(Meas m) {
+  if (m.record_id == 0 || m.kind == 0) {
+    return;
+  }
+  if (g_seen_records.count(m.record_id)) {
+    ++g_dup_records;
+    return;
+  }
+  g_seen_records.insert(m.record_id);
+  if (static_cast(m.record_id) < g_max_record) {
+    ++g_ooo;
+  }
+  if (static_cast(m.record_id) > g_max_record) {
+    g_max_record = m.record_id;
+  }
+  if (m.brownout) {
+    ++g_brownout_boots;
+  }
+  g_meas.push_back(m);
+  AppendTsv(m);
+}
+
+void PrintFinalStats(char const* tag) {
+  std::vector full_user;
+  std::vector hot_user;
+  std::vector hot_wifi;
+  std::vector connect;
+  std::vector txdone;
+  std::vector first_success;
+  std::vector first_cb;
+  std::vector last_cb;
+  std::vector rssi_pos;
+  int cb = 0;
+  int to = 0;
+  int first_ok = 0;
+  int first_fail = 0;
+  int cb_total_sum = 0;
+  int cb_succ_sum = 0;
+  int cb_fail_sum = 0;
+  int after_succ_sum = 0;
+  int fail_before_succ = 0;
+  for (auto const& m : g_meas) {
+    if (m.kind == static_cast(
+                      temp_sensor::bench::DsPendingKind::kFull)) {
+      full_user.push_back(m.user_us);
+    }
+    if (m.kind == static_cast(
+                      temp_sensor::bench::DsPendingKind::kHot)) {
+      hot_user.push_back(m.user_us);
+      hot_wifi.push_back(m.wifi_us);
+      connect.push_back(m.connect_us);
+      txdone.push_back(m.txdone_us);
+      cb += m.cb_seen;
+      to += m.cb_timeout;
+      cb_total_sum += m.tx_cb_total;
+      cb_succ_sum += m.tx_cb_success;
+      cb_fail_sum += m.tx_cb_failed;
+      after_succ_sum += m.callbacks_after_success;
+      if (m.first_status == 1) {
+        ++first_ok;
+      } else if (m.first_status == 0) {
+        ++first_fail;
+      }
+      if (m.tx_cb_failed > 0 && m.tx_cb_success > 0) {
+        ++fail_before_succ;
+      }
+      if (m.first_cb_delta_us != 0xffffffffu) {
+        first_cb.push_back(m.first_cb_delta_us);
+      }
+      if (m.first_success_delta_us != 0xffffffffu) {
+        first_success.push_back(m.first_success_delta_us);
+      }
+      if (m.last_cb_delta_us != 0xffffffffu) {
+        last_cb.push_back(m.last_cb_delta_us);
+      }
+      rssi_pos.push_back(static_cast(
+          static_cast(m.rssi) + 200));
+    }
+  }
+  auto rssi_med = [&]() -> int {
+    if (rssi_pos.empty()) {
+      return 0;
+    }
+    return static_cast(PercentileUs(rssi_pos, 50)) - 200;
+  };
+  std::cout << "TEST_RESULT"
+            << " full_recv=" << g_full_recv << " hot_recv=" << g_hot_recv
+            << " final_recv=" << g_final_recv << " records=" << g_meas.size()
+            << " dup=" << g_dup_records << " ooo=" << g_ooo
+            << " full_med_ms=" << (PercentileUs(full_user, 50) / 1000)
+            << " hot_user_med_ms=" << (PercentileUs(hot_user, 50) / 1000)
+            << " hot_wifi_med_ms=" << (PercentileUs(hot_wifi, 50) / 1000)
+            << " connect_med_ms=" << (PercentileUs(connect, 50) / 1000)
+            << " txdone_med_us=" << PercentileUs(txdone, 50)
+            << " first_cb_med_us=" << PercentileUs(first_cb, 50)
+            << " first_success_med_us=" << PercentileUs(first_success, 50)
+            << " last_cb_med_us=" << PercentileUs(last_cb, 50)
+            << " rssi_med=" << rssi_med() << " cb_seen=" << cb
+            << " cb_timeout=" << to << " first_status_ok=" << first_ok
+            << " first_status_fail=" << first_fail
+            << " cb_total_sum=" << cb_total_sum
+            << " cb_succ_sum=" << cb_succ_sum << " cb_fail_sum=" << cb_fail_sum
+            << " after_succ_sum=" << after_succ_sum
+            << " fail_before_succ=" << fail_before_succ
+            << " brownout_boots=" << g_brownout_boots << "\n";
+  std::cout << "BENCH_DONE " << tag << "\n";
+  std::cout.flush();
+}
+
+void OnBootWifiOpt(temp_sensor::bench::BootWifiOptPayload const& p) {
+  auto const type = static_cast(p.type);
+  static int hot_by_var[16] = {};
+  if (type == temp_sensor::bench::BootWifiOptMsgType::kFull) {
+    ++g_full_recv;
+    std::cout << "BWO_FULL seq=" << p.sequence_global
+              << " variant=" << static_cast(p.variant_id)
+              << " name="
+              << temp_sensor::bench::BootWifiOptVariantName(p.variant_id)
+              << " prev_v=" << static_cast(p.prev_variant_id)
+              << " prev_sends=" << static_cast(p.prev_hot_send_count)
+              << "\n";
+  } else if (type == temp_sensor::bench::BootWifiOptMsgType::kHot) {
+    ++g_hot_recv;
+    auto vid = p.pending_kind == 2 ? p.pending_variant : p.variant_id;
+    if (vid < 16) {
+      ++hot_by_var[vid];
+    }
+    std::cout << "BWO V" << static_cast(vid) << " "
+              << (vid < 16 ? hot_by_var[vid] : 0)
+              << (vid == 0xff ? "/100" : "/30")
+              << " wake_ov=" << (p.sleep_to_app_overhead_us / 1000.0) << "ms"
+              << " init=" << (p.wifi_init_us / 1000.0) << "ms"
+              << " conn=" << (p.connect_us / 1000.0) << "ms"
+              << " txdone=" << (p.tx_done_wait_us / 1000.0) << "ms"
+              << " user=" << (p.pending_user_cycle_us / 1000.0) << "ms"
+              << " rssi=" << static_cast(p.rssi) << "\n";
+  } else if (type == temp_sensor::bench::BootWifiOptMsgType::kFinal) {
+    ++g_final_recv;
+    std::cout << "BWO_FINAL seq=" << p.sequence_global << "\n";
+  }
+
+  Meas m{};
+  m.record_id = p.record_id;
+  m.kind = p.pending_kind;
+  m.outer = p.pending_variant;
+  m.hot = p.pending_hot_index;
+  m.user_us = p.pending_user_cycle_us;
+  m.wifi_us = p.pending_wifi_cycle_us;
+  m.connect_us = p.connect_us;
+  m.txdone_us = p.tx_done_wait_us;
+  m.teardown_us = p.teardown_us;
+  m.sleep_elapsed_us = p.sleep_elapsed_to_app_us;
+  m.sleep_overhead_us = p.sleep_to_app_overhead_us;
+  m.app_entry_us = static_cast(
+      p.app_entry_esp_timer_us < 0
+          ? 0
+          : (p.app_entry_esp_timer_us > 0xffffffffll
+                 ? 0xffffffffu
+                 : static_cast(p.app_entry_esp_timer_us)));
+  m.cb_seen = (p.flags & 2) ? 1 : 0;
+  m.cb_timeout = p.cb_timeout;
+  m.brownout = (p.flags & 1) ? 1 : 0;
+  m.auth = p.authmode;
+  m.tx_cb_total = p.tx_cb_total;
+  m.tx_cb_success = p.tx_cb_success;
+  m.tx_cb_failed = p.tx_cb_failed;
+  m.first_status = p.first_status;
+  m.rssi = p.rssi;
+  m.disconnect_count = p.disconnect_count;
+  m.reconnect_count = p.reconnect_count;
+  m.actual_channel = p.actual_channel;
+  m.ap_primary = p.actual_channel;
+  m.seq = p.sequence_global;
+  m.variant = p.pending_kind == 2 ? p.pending_variant : p.variant_id;
+  m.encode_us = p.encode_send_us;
+  m.wifi_init_us = p.wifi_init_us;
+  m.heap_before = p.heap_before_wifi;
+  m.heap_after = p.heap_after_wifi;
+  NoteRecord(m);
+
+  if (type == temp_sensor::bench::BootWifiOptMsgType::kFinal) {
+    PrintFinalStats("boot_wifi_opt");
+  }
+  std::cout.flush();
+}
+
+void OnMacRetry(temp_sensor::bench::MacRetryPayload const& p) {
+  auto const type = static_cast(p.type);
+  static int hot_by_var[8] = {};
+  if (type == temp_sensor::bench::MacRetryMsgType::kFull) {
+    ++g_full_recv;
+    std::cout << "MAC_FULL seq=" << p.sequence_global
+              << " variant=" << static_cast(p.variant_id)
+              << " name=" << temp_sensor::bench::MacRetryVariantName(p.variant_id)
+              << " prev_v=" << static_cast(p.prev_variant_id)
+              << " prev_sends=" << static_cast(p.prev_hot_send_count)
+              << " prev_tx_ok=" << static_cast(p.prev_tx_success_count)
+              << " prev_tx_fail=" << static_cast(p.prev_tx_fail_count)
+              << "\n";
+  } else if (type == temp_sensor::bench::MacRetryMsgType::kHot) {
+    ++g_hot_recv;
+    auto vid = p.pending_kind == 2 ? p.pending_variant : p.variant_id;
+    if (vid < 8) {
+      ++hot_by_var[vid];
+    }
+    char const* tx = "NA";
+    if (p.first_status == 1) {
+      tx = "OK";
+    } else if (p.first_status == 0) {
+      tx = "FAIL";
+    }
+    char const* cb = "none";
+    if (p.cb_timeout) {
+      cb = "timeout";
+    } else if (p.tx_cb_success) {
+      cb = "success";
+    } else if (p.tx_cb_failed) {
+      cb = "fail";
+    }
+    std::cout << "RETRY V" << static_cast(vid) << " "
+              << (vid < 8 ? hot_by_var[vid] : 0) << "/50"
+              << " s/l=" << static_cast(p.short_retry) << "/"
+              << static_cast(p.long_retry)
+              << " tx=" << tx << " cb=" << cb
+              << " txdone=" << (p.tx_done_wait_us / 1000.0) << "ms"
+              << " wifi=" << (p.pending_wifi_cycle_us / 1000.0) << "ms"
+              << " rssi=" << static_cast(p.rssi)
+              << " rc=" << p.retry_set_rc
+              << " recv=yes\n";
+  } else if (type == temp_sensor::bench::MacRetryMsgType::kFinal) {
+    ++g_final_recv;
+    std::cout << "MAC_FINAL seq=" << p.sequence_global << "\n";
+  }
+
+  Meas m{};
+  m.record_id = p.record_id;
+  m.kind = p.pending_kind;
+  m.outer = p.pending_variant;
+  m.hot = p.pending_hot_index;
+  m.user_us = p.pending_user_cycle_us;
+  m.wifi_us = p.pending_wifi_cycle_us;
+  m.connect_us = p.connect_us;
+  m.txdone_us = p.tx_done_wait_us;
+  m.teardown_us = p.teardown_us;
+  m.encode_us = p.encode_send_us;
+  m.cb_seen = (p.flags & 2) ? 1 : 0;
+  m.cb_timeout = p.cb_timeout;
+  m.brownout = (p.flags & 1) ? 1 : 0;
+  m.auth = p.authmode;
+  m.tx_cb_total = p.tx_cb_total;
+  m.tx_cb_success = p.tx_cb_success;
+  m.tx_cb_failed = p.tx_cb_failed;
+  m.first_status = p.first_status;
+  m.first_cb_delta_us = p.first_cb_delta_us;
+  m.first_success_delta_us = p.first_success_delta_us;
+  m.first_failed_delta_us = p.first_failed_delta_us;
+  m.last_cb_delta_us = p.last_cb_delta_us;
+  m.rssi = p.rssi;
+  m.disconnect_count = p.disconnect_count;
+  m.reconnect_count = p.reconnect_count;
+  m.actual_channel = p.actual_channel;
+  m.ap_primary = p.actual_channel;
+  m.seq = p.sequence_global;
+  m.variant = p.pending_kind == 2 ? p.pending_variant : p.variant_id;
+  m.short_retry = p.short_retry;
+  m.long_retry = p.long_retry;
+  m.retry_called = p.retry_function_called;
+  m.retry_set_rc = p.retry_set_rc;
+  m.retry_cfg_us = p.retry_cfg_us;
+  NoteRecord(m);
+
+  if (type == temp_sensor::bench::MacRetryMsgType::kFinal) {
+    PrintFinalStats("mac_retry");
+  }
+  std::cout.flush();
+}
+
+void OnTxDiag(temp_sensor::bench::TxDiagPayload const& p) {
+  auto const type = static_cast(p.type);
+  if (type == temp_sensor::bench::TxDiagMsgType::kFull) {
+    ++g_full_recv;
+    std::cout << "FULL_DIAG seq=" << p.sequence_global
+              << " reason=" << temp_sensor::bench::FullReasonName(p.full_reason)
+              << " reset=" << static_cast(p.reset_reason)
+              << " wake=" << static_cast(p.wake_cause)
+              << " rtc_state={magic=" << p.rtc_state_magic
+              << ",ver=" << p.rtc_state_version
+              << ",crc=" << static_cast(p.rtc_state_crc_ok)
+              << ",valid=" << static_cast(p.rtc_state_valid) << "}"
+              << " phase=" << static_cast(p.phase)
+              << " outer=" << static_cast(p.outer_cycle)
+              << " hot=" << static_cast(p.hot_index)
+              << " prepared={valid="
+              << static_cast(p.prepared_block_valid)
+              << ",left=" << p.prepared_message_left << "}"
+              << " wifi={magic=" << p.rtc_wifi_magic
+              << ",ver=" << p.rtc_wifi_version
+              << ",crc=" << static_cast(p.rtc_wifi_crc_ok)
+              << ",valid=" << static_cast(p.rtc_wifi_valid) << "}"
+              << " pre_sleep={phase="
+              << static_cast(p.pre_sleep_phase)
+              << ",outer=" << static_cast(p.pre_sleep_outer)
+              << ",hot=" << static_cast(p.pre_sleep_hot)
+              << ",left="
+              << static_cast(p.pre_sleep_prepared_left)
+              << ",state_crc=" << p.pre_sleep_state_crc
+              << ",wifi_crc=" << p.pre_sleep_wifi_crc << "}\n";
+  } else if (type == temp_sensor::bench::TxDiagMsgType::kHot) {
+    ++g_hot_recv;
+    if (g_hot_recv <= 5 || g_hot_recv % 10 == 0) {
+      std::cout << ae::Format(
+          "RECV HOT outer={} idx={} seq={} record={} user_us={} "
+          "cb_t={} cb_s={} cb_f={} first_st={} rssi={}\n",
+          p.outer_cycle, p.hot_index, p.sequence_global, p.record_id,
+          p.pending_user_cycle_us, p.tx_cb_total, p.tx_cb_success,
+          p.tx_cb_failed, p.first_status, p.rssi);
+    }
+  } else if (type == temp_sensor::bench::TxDiagMsgType::kFinal) {
+    ++g_final_recv;
+    std::cout << ae::Format("RECV FINAL seq={} record={}\n", p.sequence_global,
+                            p.record_id);
+  } else {
+    std::cout << ae::Format("RECV OTHER type={} seq={}\n", p.type,
+                            p.sequence_global);
+  }
+
+  Meas m{};
+  m.record_id = p.record_id;
+  m.kind = p.pending_kind;
+  m.outer = p.pending_outer;
+  m.hot = p.pending_hot_index;
+  m.user_us = p.pending_user_cycle_us;
+  m.wifi_us = p.pending_wifi_cycle_us;
+  m.connect_us = p.connect_us;
+  m.txdone_us = p.tx_done_wait_us;
+  m.teardown_us = p.teardown_us;
+  m.sleep_elapsed_us = p.sleep_elapsed_to_app_us;
+  m.sleep_overhead_us = p.sleep_to_app_overhead_us;
+  m.app_entry_us = p.app_entry_esp_timer_us;
+  m.cb_seen = (p.flags & static_cast(
+                             temp_sensor::bench::TxDiagFlags::kCallbackSeen))
+                  ? 1
+                  : 0;
+  m.cb_timeout = p.cb_timeout;
+  m.brownout =
+      (p.flags & static_cast(temp_sensor::bench::TxDiagFlags::kBrownout))
+          ? 1
+          : 0;
+  m.auth = p.negotiated_auth;
+  m.diag_mode = p.diag_mode;
+  m.tx_cb_total = p.tx_cb_total;
+  m.tx_cb_success = p.tx_cb_success;
+  m.tx_cb_failed = p.tx_cb_failed;
+  m.first_status = p.first_status;
+  m.first_cb_delta_us = p.first_cb_delta_us;
+  m.first_success_delta_us = p.first_success_delta_us;
+  m.first_failed_delta_us = p.first_failed_delta_us;
+  m.last_cb_delta_us = p.last_cb_delta_us;
+  m.callbacks_after_success = p.callbacks_after_success;
+  m.rssi = p.rssi;
+  m.disconnect_count = p.disconnect_count;
+  m.last_disconnect_reason = p.last_disconnect_reason;
+  m.reconnect_count = p.reconnect_count;
+  m.ap_primary = p.ap_primary;
+  m.seq = p.sequence_global;
+  NoteRecord(m);
+
+  if (type == temp_sensor::bench::TxDiagMsgType::kFinal) {
+    PrintFinalStats("tx_done_diag");
+  }
+  std::cout.flush();
+}
+
+void OnDs(temp_sensor::bench::DsPayload const& p) {
+  auto const type = static_cast(p.type);
+  if (type == temp_sensor::bench::DsMsgType::kFull) {
+    ++g_full_recv;
+  } else if (type == temp_sensor::bench::DsMsgType::kHot) {
+    ++g_hot_recv;
+  } else if (type == temp_sensor::bench::DsMsgType::kFinal) {
+    ++g_final_recv;
+  }
+  Meas m{};
+  m.record_id = p.record_id;
+  m.kind = p.pending_kind;
+  m.outer = p.pending_outer;
+  m.hot = p.pending_hot_index;
+  m.user_us = p.pending_user_cycle_us;
+  m.wifi_us = p.pending_wifi_cycle_us;
+  m.connect_us = p.connect_us;
+  m.txdone_us = p.tx_done_wait_us;
+  m.teardown_us = p.teardown_us;
+  m.sleep_elapsed_us = p.sleep_elapsed_to_app_us;
+  m.sleep_overhead_us = p.sleep_to_app_overhead_us;
+  m.app_entry_us = p.app_entry_esp_timer_us;
+  m.cb_seen = (p.flags & static_cast(
+                             temp_sensor::bench::DsFlags::kCallbackSeen))
+                  ? 1
+                  : 0;
+  m.cb_timeout = (p.flags & static_cast(
+                                temp_sensor::bench::DsFlags::kCallbackTimeout))
+                     ? 1
+                     : 0;
+  m.brownout =
+      (p.flags & static_cast(temp_sensor::bench::DsFlags::kBrownout))
+          ? 1
+          : 0;
+  m.auth = p.negotiated_auth;
+  m.seq = p.sequence_global;
+  NoteRecord(m);
+  if (type == temp_sensor::bench::DsMsgType::kFinal) {
+    PrintFinalStats("deepsleep_5x50");
+  }
+}
+
+void OnMessage(ae::Uid, ae::DataBuffer const& data) {
+  std::lock_guard lock{g_mu};
+  temp_sensor::bench::BootWifiOptPayload bwo{};
+  if (temp_sensor::bench::DecodeBootWifiOpt(data, bwo)) {
+    OnBootWifiOpt(bwo);
+    return;
+  }
+  temp_sensor::bench::MacRetryPayload mr{};
+  if (temp_sensor::bench::DecodeMacRetry(data, mr)) {
+    OnMacRetry(mr);
+    return;
+  }
+  temp_sensor::bench::TxDiagPayload td{};
+  if (temp_sensor::bench::DecodeTxDiag(data, td)) {
+    OnTxDiag(td);
+    return;
+  }
+  temp_sensor::bench::DsPayload ds{};
+  if (temp_sensor::bench::DecodeDs(data, ds)) {
+    OnDs(ds);
+    return;
+  }
+  temp_sensor::bench::FastPayload fp{};
+  if (temp_sensor::bench::DecodeFast(data, fp)) {
+    std::cout << "RECV FAST (ignored) type=" << static_cast(fp.type)
+              << "\n";
+    std::cout.flush();
+    return;
+  }
+  std::cout << "RECV unknown size=" << data.size() << "\n";
+  std::cout.flush();
+}
+
+std::filesystem::path ResolveSessionRoot() {
+#if defined(_WIN32)
+  if (char const* env = std::getenv("AE_RECEIVER_SESSION_DIR")) {
+    return std::filesystem::path{env};
+  }
+#endif
+  return std::filesystem::current_path();
+}
+
+}  // namespace
+
+int main() {
+  std::cout.setf(std::ios::unitbuf);
+#if defined(_WIN32)
+  setvbuf(stdout, nullptr, _IONBF, 0);
+#endif
+  auto const session_root = ResolveSessionRoot();
+  std::filesystem::create_directories(session_root / "state");
+  std::filesystem::current_path(session_root);
+  std::cerr << ae::Format("receiver_session_dir={}\n", session_root.string());
+
+  auto aether_app = ae::AetherApp::Construct(ae::AetherAppContext{});
+  ae::Client::ptr client;
+  aether_app->aether()
+      ->SelectClient(kParentUid, kClientName)
+      .result_event()
+      .Subscribe([&](ae::Result const& res) {
+        if (!res) {
+          std::cerr << "SelectClient failed\n";
+          aether_app->Exit(1);
+          return;
+        }
+        client = res.value();
+        std::cout << ae::Format("RECEIVER_UID={}\n", client->uid());
+        std::cout.flush();
+        client->connectivity_policy()->ResetRxTimings();
+        client->connectivity_policy()
+            ->ConfigureRxTimings(ae::RequestPolicy::All{})
+            .ForAllPriorities(ae::RxTimingConf::Every(1s).WithWindow(1s));
+        client->message_stream_manager().new_port_event().Subscribe(
+            [&](ae::P2pPortHandle handle) {
+              auto sender = handle.destination();
+              auto stream = std::make_unique(
+                  *aether_app, client.Load(), sender, std::move(handle));
+              stream->out_data_event().Subscribe(
+                  [sender](auto const& d) { OnMessage(sender, d); });
+              g_streams.push_back(std::move(stream));
+            });
+      });
+
+  while (!aether_app->IsExited()) {
+    auto t = aether_app->Update(ae::Now());
+    aether_app->WaitUntil(t);
+  }
+  return aether_app->ExitCode();
+}
diff --git a/temperature_receiver/user_config.h b/temperature_receiver/user_config.h
new file mode 100644
index 0000000..da553dd
--- /dev/null
+++ b/temperature_receiver/user_config.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2026 Aethernet Inc.
+ */
+#ifndef USER_CONFIG_H_
+#define USER_CONFIG_H_
+
+#include "aether/config_consts.h"
+
+#define AE_CRYPTO_ASYNC AE_HYDRO_CRYPTO_PK
+#define AE_CRYPTO_SYNC AE_HYDRO_CRYPTO_SK
+#define AE_SIGNATURE AE_HYDRO_SIGNATURE
+#define AE_KDF AE_HYDRO_KDF
+
+#define AE_TELE_ENABLED 1
+#define AE_TELE_LOG_CONSOLE 1
+#if defined NDEBUG
+#  define AE_TELE_DEBUG_MODULES 0
+#else
+#  define AE_TELE_DEBUG_MODULES AE_ALL
+#endif
+
+#endif  // USER_CONFIG_H_
diff --git a/ulp/CMakeLists.txt b/ulp/CMakeLists.txt
index 1e63d3e..d3d6cbf 100644
--- a/ulp/CMakeLists.txt
+++ b/ulp/CMakeLists.txt
@@ -52,7 +52,7 @@ ulp_add_build_binary_targets(${ULP_APP_NAME})
 target_include_directories(${ULP_APP_NAME} PUBLIC "${CMAKE_CURRENT_LIST_DIR}/../main")
 
 include(../cmake/CPM.cmake)
-CPMAddPackage(URI "https://github.com/aethernetio/aether-client-cpp.git#main")
+CPMAddPackage(URI "https://github.com/aethernetio/aether-client-cpp.git#157aadbec8e7b852d0f89274307ff7cb8103e5f7")
 
 # not link but only setup include directory for aether/config_consts.h
 target_include_directories(${ULP_APP_NAME} PUBLIC "${aether-client-cpp_SOURCE_DIR}")