Audit P-2 and P-3 (2026-05-02): GUI radar_protocol.py was still on the
pre-PR-G wire format. Production frames were rejected 100% before they
reached the dashboard.
Bulk frame (P-2):
- BULK_FRAME_HEADER_SIZE 8 -> 9 (FPGA emits byte[1] = RP_USB_PROTOCOL_VERSION
= 0x02). All field offsets shift by 1 (frame_num at +3,+4; n_range at
+5,+6; n_doppler at +7,+8). Parser now validates the version byte.
- Detect packing: 1 bit/cell (np.unpackbits) -> 2 bits/cell, 4 cells per
byte MSB-first per PR-F. BULK_DETECT_DENSE_BYTES 3072 -> 6144 (= 512 *
ceil(48*2/8)). New _unpack_detect_2bit returns uint8 codes 0..3
(NONE/CAND/CONFIRM/RSVD) instead of a 0/1 bitmap.
- Reserved-bit mask 0xC0 -> 0xF8 (only low 3 stream-enable bits valid;
bits 3-7 reserved). Drop dead BULK_FLAG_MAG_ONLY/SPARSE_DET constants
and the rejection logic gated on them — the FPGA emit path always emits
mag-only / dense, so flag-driven variants were never on the wire.
- find_bulk_frame_boundaries: 9-byte minimum, validate version, bin
counts at +5,+6 and +7,+8.
- _mock_read updated to emit v2 frames so FT2232HConnection(mock=True)
produces parseable data for tests and replay.
Status (P-3):
- STATUS_PACKET_SIZE 26 -> 30 (PR-G adds status_words[6] for 2-tier CFAR
telemetry: detect_count_cand[31:16] + detect_threshold_soft[15:0]).
StatusResponse gains detect_count_cand, detect_threshold_soft, and
frame_drop_count fields.
Bonus: m-3 fixed in passing — Opcode docstring line refs were stale
(902-944 -> current ranges), now also documents 0x17/0x18/0x2D/0x32 as
"M-2/M-3 — no enum yet" so a reader knows what's wired but unreachable.
RadarFrame docstring "(64 range x 32 Doppler)" -> production dims.
Tests:
- TestBulkFrameV2RoundTrip (5 cases) — synthetic v2 frame round-trip,
version-byte rejection, reserved-bit rejection, 2-bit code decode,
back-to-back boundary scan.
- TestStatusPacketV2RoundTrip (4 cases) — 30-byte size, word[6] decode,
short-packet rejection, legacy-26B packet rejection.
- test_GUI_V65_Tk: _make_status_packet emits 30 B w/ word[6];
_build_bulk_frame emits v2 w/ version byte + 2-bit detect packing.
Pre-PR-G assertions on MAG_ONLY/SPARSE_DET dropped; new
test_reject_wrong_version_byte + test_parse_status_word6_2tier_cfar.
Test result: test_v7 111/111 + test_GUI_V65_Tk 117/117 = 228/228 PASS in
radar_venv. Ruff clean.