test(micromate): real 11.0BD fixtures replace the synthesised ones

UM20147 captured over USB with mm_client_check.py --capture, read out with
scratch/mm_frame_parse.py: 11 frames each direction, 0 bad checksums.  The two
BD-specific response data sections are now verbatim fixtures; only the frame
wrapper is rebuilt, which is sound because the framing is verified 251/251
elsewhere in the same file, and the reconstruction is pinned against the
payload length the parser reported.

Every field lands where the forward-offset model says it should:

  data[0]        = 0x30 = 48 = 59 - 11   (CB declares 0x2C = 44; the +4 holds)
  content[1]     = 0x0e   monitoring
  content[2:10]  = 30 Sep 2026 14:00:49  matches the wall clock
  content[34:36] = 3.50 V
  content[36:44] = 15,000,000 total / 14,848,448 free

AND THE WARNING IS NOW DEMONSTRATED ON THE UNIT IT PREDICTED.  Series III reads
battery from data[-10:-8], which on this block is e1 c0 -> 577.92 V.  That is
the exact figure the A/B section named, and there is now a test asserting it,
so the reason the offsets are forward cannot be quietly refactored away.

Two corrections to the reference:

1. The four extra BD bytes are `0f a0 00 04`, not `0f a0 00 00`.  Only the
   first two look fixed.  Nothing reads them, but the last is not padding.

2. POLL content[3] VARIES BETWEEN UNITS -- 0x50 on UM12947, 0x56 on UM20147.
   It is printable in both cases ("P" and "V"), which is a second, independent
   reason the POLL block cannot be parsed by scanning for printable runs: a
   scan returns "PInstantel" on one unit and "VInstantel" on the other.  The
   fixed offset content[4] was the right call for a reason I had not seen.

The model string sits at content[26] on both firmware lines; only its tail
differs, so anchoring on "MM/" remains correct.

98 micromate tests pass.  Full suite unchanged at 16 pre-existing failures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ru8Lg9HkkYvX9VWWo65SmL
This commit is contained in:
2026-09-30 14:08:27 -04:00
co-authored by Claude Opus 5
parent ea229ed19d
commit 080fb92ba2
3 changed files with 161 additions and 16 deletions
+45 -4
View File
@@ -919,16 +919,57 @@ know about?" answers *no* on this unit. Worth fixing before it is a field bug
Thor's own UI couples the scheduler to a setup name, so name matching is on the
path for anything that replaces it.
### ✅ Real BD bytes, and the exact numbers (2026-09-30)
Captured with `mm_client_check.py --capture` and read out with
`scratch/mm_frame_parse.py`: 11 frames each direction, 0 bad checksums. Both
BD-specific responses are now real fixtures in `tests/`, replacing synthesised
ones.
**`SUB 0x1C`, BD, 59 B data — the block the from-the-end offsets break on:**
```
content[ 1] 0x0e monitoring
content[ 2:6] 1e 09 07ea 30 Sep 2026
content[ 6] 0x60 = 96 ⚠ still unidentified (32/100/116 on CB)
content[ 7:10] 0e 00 31 14:00:49 ✓ matches the wall clock
content[34:36] 01 5e 3.50 V
content[36:40] 00 e4 e1 c0 15,000,000
content[40:44] 00 e2 91 c0 14,848,448
content[44:48] 0f a0 00 04 ⚠ the four extra bytes
```
`data[0] = 0x30` = 48 = 59 − 11, against CB's `0x2C` = 44. The low-byte length
rule and the +4 both hold.
⚠ **The extra four bytes are `0f a0 00 04`, not `0f a0 00 00`** as recorded
earlier. Only the first two look fixed. Nothing reads them, but do not treat
the last as padding.
**And the warning is now demonstrated on the unit it predicted:**
`data[-10:-8]` on this block is `e1 c0` → **577.92 V**. Exactly the figure in
the A/B section. Forward offsets give 3.50 V.
**`SUB 0x5B` POLL, BD:**
```
content[ 3] 0x56 ⚠ 0x50 on UM12947 — THIS BYTE VARIES BETWEEN UNITS
content[ 4] "Instantel\0"
content[26] "MM/ISEE/S\0" (CB: "MM/ISEE/S/IO\0", same offset)
```
⚠ **content[3] is not a constant.** It is printable on both units — `P` and `V`
— which is the second reason a printable-run scan is the wrong way to read this
block: it would return `PInstantel` on one unit and `VInstantel` on the other.
Read the vendor at the fixed offset content[4]; the model is at content[26] on
both lines, but anchor on `MM/` since only its tail varies.
### Still not covered
- **A download from a BD unit.** UM20147 had no events stored, so the chunk
walk is verified on `11.0CB` only. Nothing suggests it differs — the `0x5A`
prefix and the offset arithmetic are not firmware-line dependent in anything
observed — but it is untested.
- **Raw BD bytes are still not in the repo.** The behaviour is confirmed; the
test fixtures for the Thor line remain synthesised. `mm_client_check.py
--capture DIR` now writes a `raw_bw_*`/`raw_s3_*` pair in the layout
`scratch/mm_frame_parse.py` reads, so one more run on UM20147 would close it.
- **A unit that is monitoring**, and a unit with a nearly-full event buffer.
- **The inbound call-home session** — still the one protocol unknown.