Repository navigation
fix(heating): refuse WHO 4 DIMENSION 22 only without an actuator token in WHERE (oracle thermo-dim22) - #151
Draft
gdluck wants to merge 1 commit into
Conversation
…n in WHERE The firmware oracle's thermo-dim22 suite (12 emulated gateways, two byte-identical runs) crashes bt_termo only on the forms whose WHERE has no actuator token: *michnovka#4*Z*22##, *michnovka#4*0*22##, *michnovka#4*#0*22## and the zone write. The published split forms *michnovka#4*3#Z#N*22## / *michnovka#4*3#Z#N*OpenWebNet-HA#22*...## and the actuator form *michnovka#4*Z#N*22## crashed none of the twelve gateways; ten forward them to the bus as a telegram to zone Z, actuator N. is_who4_dimension_22() keeps recognising every DIMENSION 22 spelling; the send paths now refuse is_who4_dimension_22_crash_form(), which lets through only the canonical actuator-addressed spellings the oracle replayed (Z 0..99, N 1..9) and keeps every untested spelling refused. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This was referenced Oct 28, 2026
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by A
Summary
Before: since #136 every WHO 4 DIMENSION 22 frame is refused by every send path, in any spelling, the published split-unit forms
*#4*3#Z#N*22##/*#4*3#Z#N*#22*MOD*SP*VEL*SWING##included. The evidence behind it was two F461020011crash frames of the same shape (*#4*2*22##,*#4*#0*22##) and the live F461 reboot, and the CHANGELOG / docstrings generalised that to "in any spelling".After: the send paths refuse
is_who4_dimension_22_crash_form(): every DIMENSION 22 spelling whose WHERE carries no actuator token, plus every spelling the oracle did not replay. The canonical split forms and the actuator form*#4*Z#N*22##(Z0..99,N1..9, request*22or write*#22*...) are sent.is_who4_dimension_22()keeps its "every spelling" meaning for callers that want the detector.Context and how it was found. A questioned whether all DIMENSION 22 forms crash the daemon or only the zone / central one, and asked for the oracle to settle it. New suite
thermo-dim22(OpenWebNet-HA/own-firmware-oracle#68, findingfindings/thermo-dim22.md): 11 forms on the twelve emulated gateways, two byte-identical runs. On the nine gateways that crash at all (F450, F453, F453AV, F454, F459, F460, F461, MH200N, MyHomeServer1) the crash set is exactly the four forms without an actuator token (*#4*2*22##,*#4*2*#22*1*0215*2*0##,*#4*#0*22##,*#4*0*22##;bt_termoSIGSEGV where attributed). No form with an actuator token crashed anywhere:*#4*3#2#1*22##and its write go out on ten of twelve gateways (F461 included) as aD1telegram to zone 2, actuator 1, dimension 22;*#4*2#1*22##and the touchscreen's*#4*45#1*#22*3**1*1##arenack, silenton all but MH202 (which forwards them). Emulation only: no DIMENSION 22 frame was sent to a physical gateway, and the live F461 supervisor's reboot is not modelled, so this PR narrows the refusal to the evidence and nothing more.Follows up #136 and #148 (the "in any spelling ... Linux IP gateways" wording).
Changes
OWNd/message/heating.py:_WHO4_DIMENSION_22_REGEXunchanged (every spelling, atoi-tolerant, anchored per##chunk); new_WHO4_DIMENSION_22_SENDABLE_REGEX = ^\*#4\*(?:3#)?(?:0|[1-9][0-9]?)#[1-9](?:\*22\Z|\*#22\*)andis_who4_dimension_22_crash_form(frame): a chunk the detector matches that the sendable pattern does not. Refused therefore:Z,0,0ZZ,#0,#Z,#0#C,Z#4#IF,Z#0,0#0, two-digit or zero-paddedN, a parameter after the request (*22*1,*22#1), a bare*#22, and any whitespace,+, leading-zero or trailing-newline spelling (\Z, not$, which matches before a final newline). Allowed: the canonical forms above. The oracle replayedZ2 and 45 withN1; the published ranges are allowed on the grammar, and the comment says so.OWNd/connection/command_session.py,OWNd/transport/serial.py,OWNd/transport/base.py: the three send paths call the crash-form detector;DESTRUCTIVE_FRAME_REASONnames the WHERE condition. Contract,reason="destructive_frame", logging andsend_to_gateway's refusal beforeconnect()unchanged.OWNd/message/__init__.py: exportsis_who4_dimension_22_crash_form.tests/test_who4_dimension22_guard.py:DIMENSION_22_FRAMESis now the refused set (41 spellings, the four oracle crash forms and the untested ones); newSPLIT_UNIT_FRAMES(11 canonical forms) asserted detectorTrue/ crash formFalse, written unchanged byOWNCommandSession.send,send_to_gateway(connects) andAsyncSerialTransport.send; the parsed / built refusal fixtures use crash forms.CHANGELOG.md: the[Unreleased]/Fixedbullet rewritten to what is refused and what is sent.State Diagram
stateDiagram-v2 direction TB state "send paths: OWNCommandSession.send / send_to_gateway, AsyncSerialTransport.send" as Guard { [*] --> Chunk Chunk --> NotDim22 : _WHO4_DIMENSION_22_REGEX no match\n*#4*22##, *#13**22##, *#2*#4*#11#001*22## Chunk --> Sendable : canonical *#4*(3#)?Z#N*22## or *#4*(3#)?Z#N*#22*...##\nZ 0..99, N 1..9 Chunk --> Refused : every other DIMENSION 22 spelling\n*#4*2*22##, *#4*0*22##, *#4*#0*22##, *#4*2*#22*...##, *#4*#2*22##, *#4*2#0*22##, *#04*2#1*022## Refused --> [*] : OWNProtocolError reason destructive_frame, never written Sendable --> Validate : OWNMessage.parse / is_valid as any frame NotDim22 --> Validate } state "oracle thermo-dim22, 12 gateways x 2 runs" as Oracle { [*] --> NoToken NoToken --> Crash : *#4*2*22##, *#4*2*#22*1*0215*2*0##, *#4*#0*22##, *#4*0*22##\nbt_termo SIGSEGV on 9 of 12 (F461, MyHomeServer1 included) [*] --> Token Token --> Out : *#4*3#2#1*22##, *#4*3#2#1*#22*...## out on 10 of 12\n*#4*2#1*22##, *#4*45#1*#22*3**1*1## silent on 11, out on MH202 }Where are the traces
results/<P>/<V>/oracle/full/thermo-dim22.tsv(OpenWebNet-HA/own-firmware-oracle#68), emulated, two runs*#4*2*22##What does the Oracle say
crashoutsilent*#4*2*22##,*#4*2*#22*1*0215*2*0##,*#4*#0*22##,*#4*0*22##*#4*3#2#1*22##,*#4*3#2#1*#22*1*0215*2*0##*#4*2#1*22##,*#4*2#1*#22*1*0215*2*0##,*#4*45#1*#22*3**1*1##,*#4*45#1*#22*4**1*1##*#4*45#1*#22*0***##tools/expected_divergences.yamlgains the zone write and the general read for F461 in the oracle PR. Not settled by the rows, and so still refused here:0ZZ,#Z,#0#C,Z#4#IF,N0, other payloads' effect on a real split unit.Testing
pytest testsagainst this head: 2198 passed (-o asyncio_default_fixture_loop_scope=functionlocally, as CI sets since ci(pytest): set asyncio_default_fixture_loop_scope so pytest-asyncio 1.4.1 does not abort the suite #150).ruff check OWNd testsclean;mypy OWNdclean.*#4*2#1*22\n##,*#4*2#1*22*1##,*#4*2#1*#22##, found by a second-opinion review and added to the refused set)._WHO4_DIMENSION_22regex inservices.py/websocket.py, which still blocks every form from the service and the websocket; it does not call OWNd's detector, so the conformance suite is unaffected. Narrowing it is MyHOME's call once this lands.Companion
🤖 Generated with Claude Code