Two boundary flaws found reviewing v3.20.0:
- /api/send-ota decoded the PoR with the request's `cntr`, not the counter
the packet was actually built with. With the new seeding an omitted
counter is the normal case, so a warning ENVELOPE's verdict - notably the
live card's cntr_low PoR - could fail its RC/CC check and be lost (the
success and the failure path are both fixed). Tests pin the decode counter
on both paths; the failure path also echoes the effective `cntr`.
- the PWA's effective counter (preview / verify / the older-server fallback)
fell back to the preset's first keyset and then 1, while the server's empty
seed builds counter 0 (no preset / kvn 0 / an unknown keyset). A manual
form or a keyless packet then produced a spurious "Verify vs pySim"
MISMATCH and a preview that differed from the delivered packet.
spPresetCounterValue()/spCntrEffective() now mirror _preset_counter_seed()
exactly: the packet's matched keyset, else 0.
- the `OTA SEND: counter not tracked` line reflects the effective counter (a
seeded value is logged too); docs/api.md records that the seed uses the
packet's keyset whatever SPI1.b5b4 says.
Tests: 823 frontend + 737 Python; sw cache simple-v394.