Files
firmware/variants
James Rich 46b4fdc799 The ESP32 spike is inert again unless a variant opts in, and BLE ingress resets priority
Four findings from the 2026-09-06 feature review, verified against this branch.

The spike was not inert on ESP32. [ble_mesh_esp32] documents itself as opt-in and
the commit that introduced it is titled "Factor the ESP32 BLE mesh build settings
into one opt-in block", but it was referenced with no condition from
[esp32s3_base] and [esp32c3_base] - the sections every S3 and C3 variant extends.
So HAS_BLE_MESH, BLE_MESH_USE_EXT_ADV and HAS_BLE_GATT_MESH were set on every
S3/C3 build, against a NimBLE rebuilt with ext-adv and the observer role, and the
#if in NimbleBluetooth.cpp made the legacy advertising branch dead code - the
phone advertisement on a stock Heltec V3 was the spike's hand-rolled ext-adv path.
The base sections no longer reference it; heltec-v3_blemesh and
heltec-ht62-esp32c3-sx1262_blemesh do, the way rak4631_blemesh already did on
nRF52. Checked with `pio project config` across all 306 envs: no env carries the
flags now without opting in, and the two opt-in envs carry all of them.

clearCorruptBondStoreOnce() erased the NimBLE bond database once per device on the
first boot of any ESP32 build from this branch, unpairing every phone with no
notice. Its own comment says why it exists - NimBLE failing to come up "after
flipping between builds with different BLE configs" - which is this feature's
hazard and nobody else's. Gated on HAS_BLE_MESH.

The NO_PIN branch changed setAuthenticationMode(true, false, false) to
(false, false, false), so no ESP32 build from this branch offered to bond in
NO_PIN. The reason is the unauthenticated mesh-peer characteristic, so it is
gated on HAS_BLE_GATT_MESH and a build without it keeps develop's behaviour.

Both BLE ingress paths now reset priority. via_mqtt and tx_after were already
cleared as local-only, but priority was left as sent - and unlike want_ack,
next_hop and relay_node it is not a field the 16-byte LoRa header carries, so
fixPriority() always derives it locally for a LoRa arrival and this bearer is the
first that lets a sender choose it. Left alone, a crafted frame with priority MAX
outranks ACK, the ceiling fixPriority assigns, and once perhapsRebroadcast copies
it into the TX queue replaceLowerPriorityPacket evicts one of ours for it. No PSK
needed: the guards run before decryption.

Native suites green in Docker: test_ble_mesh 13, test_ble_gatt_mesh 26,
test_transport_registry 7. No ESP32 or nRF52 build was run - the ESP32 toolchain
rewrites a framework sdkconfig shared with every other checkout on this machine,
so that wants a deliberate sitting.
2026-09-06 08:31:34 -05:00
..