Problem
addCredentials(force=true) and clearCredentials() call saveConfig() directly from async_tcp body handlers (addNetwork at WebHandler.cpp:732, handleClearWifi at WebHandler.cpp:365). Settings::write() opens Preferences, serializes JSON, and writes to NVS — blocking the calling task for typically 30–200 ms, up to 500+ ms during flash sector garbage collection.
Root Cause
The B39 fix introduced wlanSaveConfigPending (already used in update() at Wlan.cpp:258–262) but the pattern was not applied to addCredentials (force path) and clearCredentials. Both still call saveConfig() synchronously from the async_tcp task.
Fix
Replace direct saveConfig() calls with wlanSaveConfigPending = true in both functions. The flag is already processed in Wlan::update() (ConnectTask context), which is the correct async-safe execution path — identical to the B39 fix pattern.
Review-Finding: CR-003-001
Severity: CRITICAL
Problem
addCredentials(force=true)andclearCredentials()callsaveConfig()directly from async_tcp body handlers (addNetworkat WebHandler.cpp:732,handleClearWifiat WebHandler.cpp:365).Settings::write()opens Preferences, serializes JSON, and writes to NVS — blocking the calling task for typically 30–200 ms, up to 500+ ms during flash sector garbage collection.Root Cause
The B39 fix introduced
wlanSaveConfigPending(already used inupdate()at Wlan.cpp:258–262) but the pattern was not applied toaddCredentials(force path) andclearCredentials. Both still callsaveConfig()synchronously from the async_tcp task.Fix
Replace direct
saveConfig()calls withwlanSaveConfigPending = truein both functions. The flag is already processed inWlan::update()(ConnectTask context), which is the correct async-safe execution path — identical to the B39 fix pattern.Review-Finding: CR-003-001
Severity: CRITICAL