core: Saturate IR/calibration logic with property and stress tests
A targeted testing pass over the pure logic added across the IR-capture
and calibration work, plus one latent bug it surfaced.
# Bug fix: strobe period truncation
`classify_ir_mode` computed the strobe period as `(w[1] - w[0]) as u8`,
which *truncates* (wraps mod 256) when bright frames are more than 255
indices apart — a long, sparse burst could classify as a bogus tiny
period. Now uses a saturating `u8::try_from(...).unwrap_or(u8::MAX)`. A
regression test pins it (gap of 300 → 255, not 44), and was confirmed to
fail against the old code.
# Property tests
- `select_brightest`: result is an in-bounds true argmax; `Some` iff
the input is non-empty.
- `classify_ir_mode`: total (never panics) over arbitrary `&[f32]`
including NaN/inf/empty; a synthesized period-`p` strobe round-trips
to `Strobed { period: p }`; a sub-contrast stream is always
`Constant`; the result's `min_burst()` is always >= 1 and any strobed
period >= 2.
- Calibration store: `save_all`→`load` round-trips an arbitrary record
set (mirrors the enrollment store's headline property); `upsert`
leaves exactly one record per identity carrying the new mode.
- `resolve_calibration`: total; `Exact` implies an identical full
identity; any non-`None` match implies a same-card+kind record exists;
deterministic.
- `resolve_ir_camera` / `resolve_rgb_camera`: explicit path always wins;
total; an adopted camera is always of the matching kind; RGB adoption
happens exactly when there's a single path-bearing RGB camera.
# Stress test
Calibration store: 16 threads racing `upsert` on one file. The
read-modify-write isn't serialized (last-writer-wins on the record set,
as documented), so the test asserts only *integrity* — atomic
temp+rename means every post-race `load` succeeds on a structurally
valid, non-torn file and two consecutive loads agree.