The 6 multi-record ProgType values (WHEN/AT/EVERY/AND/OR/THEN) now have
typed accessors on the Program dataclass:
is_multi_record() - classifier for ProgTypes 5-10
event_id - WHEN trigger event-id (same property as EVENT, no
Mon/Day swap, BE wire form)
and_family - AND record byte-1 family + operand bits (mirrors
compact-form cond's high byte: ZONE=0x04, CTRL+ON=0x0A,
OTHER=0x00, etc.)
and_instance - AND record bytes 3-4 BE u16 (zone#, unit#,
MiscConditional value, ...)
every_interval - EVERY record bytes 3-4 BE u16 (recurrence interval)
AT records reuse the existing month/day/days/hour/minute fields (same
byte layout as compact-form TIMED, just with cmd/par/pr2 zero).
OR records carry no payload — only the ProgType byte distinguishes
them. THEN records reuse cmd/par/pr2 (same layout and LE byte order
as compact-form action fields).
10 new tests cover the empirical captures from pca-re/clausal-re:
- is_multi_record() classifier
- WHEN event_id for Zone 5 Secure and Zone 1 Secure
- EVERY 5 SECONDS interval decoding
- AND IF UNIT 1 ON, AND IF ZONE 5 SECURE, AND IF NEVER family+instance
- AT record month/day/days/hour/minute
- OR record all-zero invariants
- THEN record cmd/par/pr2 (UNIT 1 ON)
All byte vectors in the tests come from real PC Access captures in
pca-re/clausal-re/06-10.pca with firmware override at 3.0+.
The and_family and and_instance properties derive from the existing
cond and cond2 fields via byte-swap — disk bytes 1-4 of AND records
use BE u16 order, but Program's cond/cond2 fields are LE-decoded
(per compact-form convention). The byte-swap formula
((cond2 & 0xFF) << 8) | ((cond2 >> 8) & 0xFF) yields the BE
interpretation without re-reading raw bytes.
473 tests passing (up from 463).