Skip to content

chore(profiles): derive the discovery rows from the OWNd profile (prep for OWNd #142) - #808

Merged
GreenGrassBlueOcean merged 7 commits into
OpenWebNet-HA:v2-phase1-architecturefrom
gdluck:chore/profiles-companion-ownd-142
Oct 26, 2026
Merged

GreenGrassBlueOcean merged 7 commits into
OpenWebNet-HA:v2-phase1-architecturefrom
gdluck:chore/profiles-companion-ownd-142

Conversation

@gdluck

@gdluck gdluck commented Oct 24, 2026 •

Copy link
Copy Markdown

Requested by A

The MyHOME companion of OpenWebNet-HA/OWNd#142 (fix(profiles): drop WHO 16 from the F461 and MyHomeServer1 profiles). Sequencing: merge this → merge OpenWebNet-HA/OWNd#142 → OWNd release → bump the OWNd pin here, and scripts/sync_documentation.py --update regenerates the two docs rows together with the pinned_whos fallback below (one edit in scripts/update_gateway_profiles.py).

Rebase after #794 (2026-10-26)

Rebased on v2-phase1-architecture at a27b32f6 (after #794, #793, #797, #798, #801 and #804); the two commits of the first push are kept and reconciled with #794 in place, three follow-up commits on top. Base SHA a27b32f6, branch head bfc1c270.

What #794 and this PR each bring, and how they are reconciled (the three conflicts: .github/release-notes/2.0.0b16.md, scripts/update_gateway_profiles.py, tests/test_gateway_profiles.py):

Suite against both OWNd checkouts (venv with HA 2026.10.2, Python 3.14, pytest -n 4; the OWNd checkout on PYTHONPATH):

OWNd on PYTHONPATH Result Notes
master 87cafc3 (#136 merged; the behaviour of the 2.0.0b11 pin) 4965 passed, 1 skipped, verify_ownd_coverage.py 100 % (16,770 / 16,770 statements, 0 missing) committed tree
fix/profiles-f461-mhs1-no-who16 95dc8a5 (OpenWebNet-HA/OWNd#142, on f04d8aa) 4964 passed, 1 failed, 1 skipped committed tree: the one failure is tests/test_sync_documentation.py::test_check_all_documentation_real_tree, "Gateway Discovery table out of sync" (the F461 / MyHomeServer1 rows the pin bump regenerates); sync_documentation.py --check reports the same two rows and nothing else (no oracle violation)
fix/profiles-f461-mhs1-no-who16 95dc8a5, pin-bump rehearsal 4965 passed, 1 skipped pinned_whos of the two rows set to [1, 2, 4, 18], *#16*0*5## removed from their sweep_omits, sync_documentation.py --update: only the F461 and MyHomeServer1 rows change (docs/getting-started/hardware-compatibility.md: 2 lines, `WHO 1, 2, 4, 18

Checks on the final head with OWNd master: ruff check ., scripts/typing_ratchet.py (0 errors, baseline 0), scripts/verify_ha_standards.py (with OWNd and without), scripts/sync_documentation.py --check (with OWNd and without), scripts/manage_translations.py check. tests/test_gateway_profiles.py now has 25 tests; test_discovery_table_with_ownd_matches_the_committed_docs compares row by row and lets only the rows whose profile differs from pinned_whos differ (and requires them to), so it is right before and after the pin bump while --check keeps reporting the drift until --update is run.

Independent review (focus: the validator still rejects a wrong sweep_omits; the derivation cannot silently drop a WHO the sweep sends; the no-OWNd fallback): agreed on all three for the shown rows; found that pinned_whos itself was not checked against any profile (a mistyped pin would have passed), that a malformed pin raised instead of being flagged, that a repeated or reordered pin passed as a set, and that an empty row rendered an unfinished sent cell with the WHO 22 wording. All four are fixed in the two follow-up commits and pinned by tests. Accepted residual, by design: on the two rows that declare notes_without_who16 the validator cannot tell "pin with WHO 16 against OWNd #142" from "pin without WHO 16 against the pinned release" (both OWNds report __version__ 2.0.0b11); the WHO 16 cell of those rows is pinned by test_discovery_table_without_ownd_matches_the_committed_docs (pin equals the committed docs) and by the sweep_omits rule (*#16*0*5## requires WHO 16 in the pin), not by the profile comparison.


Review follow-up (review 5651153472)

  • fd20792: negative test test_oracle_check_rejects_a_row_that_resolves_to_the_generic_profile for the GenericGatewayProfile guard of verify_profiles_against_oracle(): a row whose profile_name is Generic or an unknown model string reports resolves to the generic profile for that row and for no other; it fails with the previous is None check. Full suite 4991 passed / 1 skipped at 100 % coverage. Marked ready for review as asked.

Review follow-up (CI red on the first push)

  • Cause: the quality-scale, test-coverage and docs jobs run scripts/verify_ha_standards.py / scripts/sync_documentation.py --check without OWNd installed ([OWND] Client library verification skipped (OWNd not in path: No module named 'OWNd') in the same log). The first push removed the static queried_whos and printed unknown (OWNd profile not available) for every row when OWNd is not importable, so the regenerated table differed from the committed one: [RULE_DOCS_ANTI_DRIFT] Gateway Discovery table out of sync in docs/getting-started/hardware-compatibility.md. Locally the check had only been run with OWNd on PYTHONPATH.
  • Fix: each discovery row carries pinned_whos, the row the pinned OWNd (OWNd==2.0.0b11 in manifest.json) yields; it is used only when OWNd is not importable, so the generated table is byte-identical with and without OWNd. With OWNd importable the row is still derived from the installed profile. Reproduced and fixed locally: sync_documentation.py --check now passes both in a venv without OWNd (pyyaml + ruff only, as in the CI jobs) and with OWNd master on PYTHONPATH; tests/test_gateway_profiles.py::test_discovery_table_without_ownd_matches_the_committed_docs pins the fallback to the committed table and ::test_discovery_table_with_ownd_matches_the_committed_docs pins the derived table to it, so installed profile == committed table == pinned_whos is asserted explicitly.
  • Oracle double-check (the maintainer refreshed own-firmware-oracle main to 72759e8, fix(oracle): write a past date in who13-clock so the DIM 1 verdict does not depend on the day own-firmware-oracle#61 and fix(results): refresh 7 stale sound-who22 TSVs and MCP index (#58) own-firmware-oracle#62): the WHO 16 verdicts for the F461 020011 and the MyHomeServer1 028206 are unchanged, see "What does the Firmware Oracle / Encyclopedia say" below.
  • Also: verify_profiles_against_oracle() now flags a discovery row whose profile_name resolves to OWNd's generic profile (get_gateway_profile() never returns None, so the earlier is None check could not fire).

What is the problem

scripts/update_gateway_profiles.py keeps a static queried_whos list per startup discovery row next to the list it derives from the installed OWNd profile, and verify_profiles_against_oracle() compares the two. The derived list is what the generated docs/getting-started/hardware-compatibility.md table shows and what the runtime sends (the startup gate in gateway.py asks profile.supports_who(who) for every discovery WHO; #794 reads the same flag for the refused requests). When an OWNd profile changes, the static copy goes stale: with OpenWebNet-HA/OWNd#142 the F461 and MyHomeServer1 rows become [1, 2, 4, 18], the oracle check reports Discovery row **F461** queried_whos=[1, 2, 4, 16, 18] disagrees with F461 profile [1, 2, 4, 18], sync_documentation.py --check fails and tests/test_gateway_profiles.py asserts the old literal row. Hard-coding the new rows instead would be red against the pinned OWNd 2.0.0b11 today.

Refs OpenWebNet-HA/OWNd#142; #794 (the runtime gate); #424 / #459 (the F461 / MyHomeServer1 plants that speak WHO 22 only, and the MyHomeServer1 "firmware discards 5, 16, 22" note). The combined test build (combined/all-prs-2026-10-24, commit 4a79e8cb) showed which files and tests are involved; its hard-coded rows are not used here.


What is the solution

  1. scripts/update_gateway_profiles.py:
    • GATEWAY_DISCOVERY_METADATA rows carry model, profile_name, pinned_whos (the no-OWNd fallback, see below) and notes; no queried_whos.
    • New discovery_whos_for(profile): [w for w in STARTUP_DISCOVERY_WHOS if profile.supports_who(w)], the rule MyHOMEGatewayHandler._profile_supports_who applies at startup; [] for anything without supports_who.
    • calibrate_discovery_with_ownd() fills queried_whos from the installed profile for every row and keeps only the sweep_omits of advertised WHOs (a request of a WHO that is not advertised is no omission: nothing is sent for it); the F461 and MyHomeServer1 rows carry a notes_without_who16 text that replaces notes when the row does not carry WHO 16 ("Sound is WHO 22 only (no bt_difson; every WHO 16 frame refused ...)", with fix(gateway): skip the startup requests the firmware refuses, poll each zone's temperature on SCS-only gateways #794's *#4*0## facts), so the wording follows the profile too.
    • Without an importable OWNd (the quality-scale, test-coverage and docs CI jobs) every row falls back to pinned_whos, the row the pinned OWNd 2.0.0b11 yields, so the generated table is the same either way; nothing else is guessed. At a pin bump that changes a profile, pinned_whos is edited together with sync_documentation.py --update (the tests below fail until both are done).
    • verify_profiles_against_oracle() no longer compares a static list with the profile; it checks that every discovery row names a real OWNd profile (not the generic fallback), that pinned_whos is a sweep-ordered list of startup WHOs equal to the installed profile except by WHO 16 where the row declares notes_without_who16, and (fix(gateway): skip the startup requests the firmware refuses, poll each zone's temperature on SCS-only gateways #794's rule, against the pin) that every sweep_omits entry is *#4*0## / *#16*0*5## of a WHO in pinned_whos; the per-gateway supports_who / audio_measured / auth_measured checks against firmware_oracle.json are unchanged.
  2. tests/test_gateway_profiles.py: the F461 and MyHomeServer1 cells (advertised and sent) are asserted against the installed profile (right before and after fix(profiles): drop WHO 16 from the F461 and MyHomeServer1 profiles OWNd#142), the other rows stay literal; discovery_whos_for mirrors the runtime gate for six profiles; a profile double without WHO 16 yields [1, 2, 4, 18], the reduced sweep_omits and the WHO 22 wording for both rows while the F454 / MH202 rows are unchanged; without OWNd every row carries exactly its pinned_whos and the generated block equals the committed one; with OWNd the derived block equals the committed one row by row (only rows whose profile differs from the pin may differ); pinned_whos is ignored when OWNd is importable; the validator rejects a stale *#16*0*5## at the pin bump, a pin that disagrees with the installed profile (other than by WHO 16 where declared), a malformed, repeated or reordered pin; the no-OWNd fallback yields the WHO 22 row once the pin drops WHO 16.
  3. docs/getting-started/hardware-compatibility.md: unchanged in this PR (against the pinned OWNd the generated table is byte-identical). After the pin bump the F461 and MyHomeServer1 rows regenerate to WHO 1, 2, 4, 18 with the WHO 22 note.
  4. .github/release-notes/2.0.0b16.md: one line under "Other changes".

Not changed here, named as follow-ups: the per-zone *#16*ZONE*5## media-player poll (media_player.py) on a gateway whose profile lacks WHO 16 (one refused frame per configured WHO 16 zone; those entities cannot work on these gateways anyway, and the planned WHO 22 backend is the right gate); and the topology side effect of OpenWebNet-HA/OWNd#142 itself (topology.py delegation: an F461 primary lets a WHO-16-capable follower own WHO 16 and 22, and a same-tier F454 / F461 pair is now ordered by WHO count rather than by MAC), which is OpenWebNet-HA/OWNd#142's to document and which this PR does not alter.


Companion PR: OpenWebNet-HA/OWNd#142 (fix(profiles): drop WHO 16 from the F461 and MyHomeServer1 profiles, draft). MyHOME #794 is the runtime half (startup requests gated on profile.supports_who, with a MyHOME fallback table until the OWNd release).


State Diagram

stateDiagram-v2
    direction LR
    state "Is OWNd importable" as Check
    state "Installed OWNd profile" as Profile {
        [*] --> Pinned : 2.0.0b11 - F461 and MyHomeServer1 supported_who includes 16
        [*] --> AfterPinBump : OWNd release with 142 - no 16
    }
    state "Discovery row - docs table, same rule as the startup gate" as Row {
        Pinned --> Row16 : discovery_whos_for gives 1 2 4 16 18 - notes sound unmeasured class default
        AfterPinBump --> Row18 : discovery_whos_for gives 1 2 4 18 - notes_without_who16 Sound is WHO 22 only
    }
    state "No OWNd - quality-scale, test-coverage and docs CI jobs" as Fallback {
        [*] --> PinnedRows : pinned_whos per row - the pinned OWNd rows, edited at the pin bump with update
        PinnedRows --> Row16 : today, identical to the committed table
    }
    [*] --> Check
    Check --> Profile : yes
    Check --> Fallback : no
Loading

Hardware Verification


How is it tested

  • tests/test_gateway_profiles.py::test_generate_gateway_discovery_table_and_verify_oracle (updated), ::test_discovery_whos_follow_the_runtime_gate, ::test_discovery_row_drops_who16_when_the_profile_does, ::test_discovery_table_without_ownd_uses_the_pinned_rows, ::test_discovery_table_without_ownd_matches_the_committed_docs, ::test_discovery_table_with_ownd_matches_the_committed_docs, ::test_pinned_rows_are_ignored_when_ownd_is_importable, ::test_oracle_check_rejects_a_stale_sweep_omission_at_the_pin_bump, ::test_discovery_table_without_ownd_follows_the_pinned_rows_at_the_pin_bump, ::test_oracle_check_rejects_a_pin_that_disagrees_with_the_installed_profile, ::test_discovery_row_with_an_unreadable_pin_and_no_ownd_is_empty (new); fix(gateway): skip the startup requests the firmware refuses, poll each zone's temperature on SCS-only gateways #794's ::test_oracle_check_rejects_a_sweep_omission_the_profile_does_not_advertise kept; 25 tests in the file.
  • Fail-before / pass-after: on the base script 4 of the first-push tests fail (no discovery_whos_for, rows hard-code their WHOs); on the first-push script (CI red) 3 fail: the table test (rows carry no pinned_whos), the no-OWNd rows test and the no-OWNd-equals-committed-docs test (unknown (OWNd profile not available) cells). All 18 pass after.
  • scripts/sync_documentation.py --check and scripts/verify_ha_standards.py: pass without OWNd (OWNd made unimportable, the CI jobs' shape: [OWND] Client library verification skipped; before the fix: Gateway Discovery table out of sync) and with OWNd master (87cafc3) on PYTHONPATH.
  • Full suite against OWNd master (87cafc3, the behaviour of the 2.0.0b11 pin), rebased on v2-phase1-architecture a27b32f: 4965 passed, 1 skipped; scripts/verify_ownd_coverage.py 100 % (16,770 / 16,770 statements, 0 missing) (before the rebase, on 31ea9fd with OWNd f04d8aa: 4514 passed, 1 skipped; first push on ddc6d60: 4421 passed, 1 skipped).
  • Against the fix(profiles): drop WHO 16 from the F461 and MyHomeServer1 profiles OWNd#142 branch (gdluck/OWNd fix/profiles-f461-mhs1-no-who16, 95dc8a5) on PYTHONPATH, full suite: 4964 passed, 1 failed, 1 skipped on the committed tree (the failure is tests/test_sync_documentation.py::test_check_all_documentation_real_tree, the docs drift the pin bump resolves) and 4965 passed, 1 skipped with the pin bump rehearsed (see "Rebase after fix(gateway): skip the startup requests the firmware refuses, poll each zone's temperature on SCS-only gateways #794"); verify_profiles_against_oracle() returns no violation, and the generator yields | **F461** | WHO 1, 2, 4, 18 | WHO 1, 2, 18 (firmware drops the shutters does not work in homekit #40##) | Lighting, cover, and energy meter 51 queries. Sound is WHO 22 only (no bt_difson; every WHO 16 frame refused, own-firmware-oracle 020011, confirmed live on 2.0.11). The firmware also drops the shutters does not work in homekit #40##, so the sweep leaves it out; zones are polled with the shutters does not work in homekit #4##. Alarm query omitted. | and the same shape for the MyHomeServer1.
  • scripts/typing_ratchet.py 0 errors (baseline 0), ruff check ., scripts/verify_ha_standards.py, scripts/manage_translations.py check pass.
  • Note for the sequencing: pypi_standards.yml installs OWNd from git (OWND_REF, the branch named like the MyHOME branch, else master), so once fix(profiles): drop WHO 16 from the F461 and MyHomeServer1 profiles OWNd#142 is on OWNd master that job reports the same docs drift on v2-phase1-architecture until the pin bump lands; this was already the case before this PR (the generator derived the rows from the installed profile when importable).

Live retest (2026-10-24)

Not exercised live: docs generator and tests only, no bus effect of its own (the gate it documents was confirmed for this startup configuration, above).


Where are the traces

Subsystem Capture Plant Frames verified by this PR
Docs generator No physical trace applies: this change touches no bus frame (configuration / diagnostics / validation only) — none
WHO 16 refused by the gateway (the fact OpenWebNet-HA/OWNd#142 encodes and this table will show) tests/fixtures/traces/f461_live_2026-10-23/ run run1_oracle_replay_readonly step oracle_who16; tests/fixtures/traces/myhomeserver1_live_2026-10-24/ run run2_reads_thermo_sound_alarm_lights step read_who16 (trace PR: #799, merged); upstream tests/fixtures/traces/issue_466/ F461 2.0.11; MyHomeServer1 3.87.13; MyHomeServer1 (#466) *#16*0*5## NACK 5 ms / 3 ms, *#16*101*5## NACK 6 ms / 3 ms (note: who16_refused_locally)

What does the Firmware Oracle / Encyclopedia say

Re-checked against the refreshed results/mcp_index.json at own-firmware-oracle main 72759e8 (schema 1.2.0, 529 inputs; after OpenWebNet-HA/own-firmware-oracle#61 and OpenWebNet-HA/own-firmware-oracle#62): the F461 020011 and the MyHomeServer1 028206 answer nack / silent to all 86 WHO 16 inputs (77 in sound-who16-source, 9 in trace-corpus), *#16*0*5## at sound-who16-source.tsv line 16 and *#16*101*5## at line 28 on both, no bus frame, no emitted frame; identical to the 53f9514 rows mirrored in tests/golden/firmware_oracle.json (schema 1.1.0, 509 inputs). The refresh added the 20 who13-clock inputs and four sound-who22 rows per gateway and changed nine MH202 lights-area0 / interface-routing / trace-corpus replies (nack → ack); nothing about WHO 16 changed. The golden mirror is left as is: it is refreshed by hand in its own commit together with tests/test_firmware_oracle_conformance.py (which pins schema_version to 1.0.0 / 1.1.0) and tests/test_trace_oracle_validation.py (which cites 53f9514), not something this PR should fold in.

Published rows (results/<P>/<V>/oracle/full/sound-who16-source.tsv, index 53f9514 and 72759e8 alike), *#16*0*5##: nack / silent on F450 020010, F459 020105, F460 020012, F461 020011, MH202 010024, MyHomeServer1 028206; ack / out (bus 24 30 34 42 35 30 30 38 30 38 46 0d) on F453 010100, F453AV 030014, F454 020051, H4684 020054, MH200 020102, MH200N 010108. OpenWebNet-HA/OWNd#142 drops WHO 16 from the F461 and MyHomeServer1 profiles on the strength of all 86 WHO 16 inputs being refused there; it keeps the MH202 (a live MH202 relays WHO 16 state frames from an F441M matrix, MyHOME #669), so the generated MH202 row does not change either. This PR adds no verdict of its own: verify_profiles_against_oracle() keeps checking audio_measured against this row and supports_who against the WHO 1 / 2 / 3 / 4 / 25 probe rows, unchanged.


Checklist

🤖 Generated with Claude Code

@GreenGrassBlueOcean

Copy link
Copy Markdown
Contributor

@gdluck i double check the firmware oracle and made a fix for the stale who16 please double check with the oracle and fix failing ci

@gdluck
gdluck force-pushed the chore/profiles-companion-ownd-142 branch from b06248b to 09dd4b5 Compare October 24, 2026 21:10
@gdluck

gdluck commented Oct 24, 2026

Copy link
Copy Markdown
Author

Checked with the refreshed oracle and fixed the CI (head 88ed3fa, rebased on the current base, still draft).

CI cause and fix. The quality-scale, test-coverage and docs jobs run the docs check without OWNd installed; this PR's first push derived the discovery rows from the installed profile and, with no OWNd, printed "unknown" rows, so the regenerated table no longer matched docs/getting-started/hardware-compatibility.md. Each discovery row now carries pinned_whos (the rows the pinned OWNd 2.0.0b11 yields: F461 / MyHomeServer1 still WHO 1, 2, 4, 16, 18), used only when OWNd is not importable; with OWNd the row is still derived from profile.supports_who. Tests pin installed-profile table == committed table == pinned_whos, and verify_profiles_against_oracle() now flags a profile name that resolves to the Generic profile (the previous is None check was vacuous). Both shapes pass sync_documentation.py --check locally (with and without OWNd).

Oracle re-check (main 72759e8, after #62). F461 020011 and MyHomeServer1 028206 still answer nack / silent to all 86 WHO 16 inputs (77 in sound-who16-source, 9 in trace-corpus; *#16*0*5## line 16, *#16*101*5## line 28), no bus frames: nothing changed for WHO 16, so OpenWebNet-HA/OWNd#142 stands. The refresh added the who13-clock inputs, 4 sound-who22 rows per gateway and flipped 9 MH202 replies in other suites. tests/golden/firmware_oracle.json (1.1.0 / 509) was not synced here: it is refreshed by hand in its own commit together with the conformance test (which pins the schema version), so that belongs in a separate PR if you want 72759e8 in.

Suite 4514 passed at 100 % coverage against the pinned OWNd; against the OWNd #142 branch the profile, conformance and trace-oracle tests pass (711) and only the docs-equality checks report the expected pin-bump drift, resolved by --update at that time. CI on 88ed3fa was still queued when I wrote this.

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@GreenGrassBlueOcean

Copy link
Copy Markdown
Contributor

@gdluck please rebase

@gdluck
gdluck force-pushed the chore/profiles-companion-ownd-142 branch from 88ed3fa to bfc1c27 Compare October 26, 2026 04:37
@gdluck

gdluck commented Oct 26, 2026

Copy link
Copy Markdown
Author

Rebased onto v2-phase1-architecture a27b32f (head bfc1c27, still draft) and reconciled with #794, which had reworked the same table generator:

Suite with OWNd master 87cafc3: 4965 passed / 1 skipped at 100 % coverage; with the OpenWebNet-HA/OWNd#142 checkout: 4964 passed and the single expected docs-drift failure on the committed tree (the two rows a pin bump regenerates), 4965 passed / 1 skipped with the pin bump rehearsed (pinned_whos, sweep_omits, sync_documentation.py --update: only those two docs rows change). ruff, typing ratchet, HA standards, docs sync with and without OWNd, and translations clean; hardware-compatibility.md is byte-identical on this base. Details under "Rebase after #794 (2026-10-26)" in the description.

gdluck and others added 6 commits October 26, 2026 10:47
…p for OWNd OpenWebNet-HA#142)

scripts/update_gateway_profiles.py carried a static `queried_whos` list per
discovery row next to the derived one, and the oracle check compared the two,
so an OWNd profile change (OWNd OpenWebNet-HA#142 drops WHO 16 from the F461 and the
MyHomeServer1) turned the check and the docs test red until the list was edited
by hand. The rows now come only from the installed OWNd profile over
STARTUP_DISCOVERY_WHOS, the rule the startup gate in gateway.py applies, and
the sound wording of a row follows `supports_who(16)`. Green against the pinned
OWNd today; after OWNd OpenWebNet-HA#142 lands and the pin is bumped,
`sync_documentation.py --update` regenerates the two rows and nothing else
needs an edit. Tests pin both shapes with a profile double.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tical with and without OWNd (CI follow-up)

The quality-scale, test-coverage and docs CI jobs run scripts/verify_ha_standards.py and
scripts/sync_documentation.py --check without OWNd installed ("[OWND] Client library
verification skipped (OWNd not in path: No module named 'OWNd')"). The first push derived
the startup discovery rows from the installed OWNd profile only and printed
"unknown (OWNd profile not available)" otherwise, so those jobs regenerated a table that
differed from the committed docs/getting-started/hardware-compatibility.md:
"[RULE_DOCS_ANTI_DRIFT] Gateway Discovery table out of sync".

Each discovery row now carries pinned_whos, the row the pinned OWNd 2.0.0b11 yields; it is
used only when OWNd is not importable, so the generated table is byte-identical with and
without OWNd. With OWNd importable the row is still derived from profile.supports_who over
STARTUP_DISCOVERY_WHOS, as the startup gate does, and notes_without_who16 applies whenever
the row does not carry WHO 16. verify_profiles_against_oracle() flags a row whose
profile_name resolves to the generic profile (get_gateway_profile() never returns None).

Tests: without OWNd every row carries exactly its pinned_whos and the generated block equals
the committed one; with OWNd the derived block equals the committed one (installed profile ==
committed table == pinned_whos); pinned_whos is ignored when OWNd is importable. Fail-before
on the first-push script: 3 of 18 fail; all pass after. sync_documentation.py --check passes
in a venv without OWNd and with OWNd master (f04d8aa) on PYTHONPATH. Against the OWNd OpenWebNet-HA#142
branch (95dc8a5) the two docs-equality tests report the drift that the pin bump resolves
with --update together with pinned_whos.

Oracle re-check at own-firmware-oracle main 72759e8 (results/mcp_index.json, schema 1.2.0,
529 inputs): F461 020011 and MyHomeServer1 028206 still answer nack/silent to all 86 WHO 16
inputs (*OpenWebNet-HA#16*0*5## sound-who16-source.tsv line 16, *OpenWebNet-HA#16*101*5## line 28), unchanged from
53f9514.

Refs OpenWebNet-HA/OWNd#142.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… bump (rebase on OpenWebNet-HA#794)

After the rebase the discovery rows carry both OpenWebNet-HA#794's `sweep_omits` (the general requests
the firmware drops) and this branch's `pinned_whos` (the no-OWNd fallback), while the
advertised column is derived from the installed OWNd profile. Two tests pin the interplay
at the OWNd OpenWebNet-HA#142 pin bump:

- `verify_profiles_against_oracle()` checks `sweep_omits` against `pinned_whos`, so once the
  F461 / MyHomeServer1 rows drop WHO 16 a leftover `*OpenWebNet-HA#16*0*5##` is flagged (and a
  `pinned_whos` entry the startup sweep never asks for is flagged too); the F455 /
  unknown-frame cases of OpenWebNet-HA#794 are unchanged.
- Without an importable OWNd, `pinned_whos` without WHO 16 yields the `WHO 1, 2, 4, 18`
  row, the reduced `(firmware drops `*michnovka#4*0##`)` sent column and the WHO 22 wording, so the
  CI jobs that run the docs check without OWNd regenerate the same table as the pinned OWNd.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…O 16 where the row declares it (review follow-up)

`verify_profiles_against_oracle()` checked `sweep_omits` against `pinned_whos` but never
`pinned_whos` against a profile, so a mistyped pin (an F455 row given WHO 16 and a matching
`*OpenWebNet-HA#16*0*5##` omission, or a row that lost WHO 4) passed the check and the no-OWNd table
would have followed it. Now a pin that differs from the installed profile is flagged, except
by WHO 16 on a row that carries `notes_without_who16` (the F461 / MyHomeServer1 switch of
OWNd OpenWebNet-HA#142, the one change the fallback is meant to absorb between the pinned release and the
next), so the check is green with the pinned OWNd and with the OWNd OpenWebNet-HA#142 checkout alike and
catches a stale pin at the pin bump together with the stale omission.

Hardening from the same review: `pinned_whos` that is not a list of WHO numbers is a
violation instead of a `ValueError` / `TypeError`, and such a row (or a profile lookup that
yields nothing) generates `none` cells with no omissions and the plain notes rather than an
unfinished sent cell and an unjustified WHO 22 wording.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…back in sweep order (review follow-up)

A `pinned_whos` such as `[1, 1, 2, 4, 18]` or `[2, 1, 4, 18]` compared equal to the profile
as a set and, without OWNd, was rendered as written. The oracle check now requires the pin in
STARTUP_DISCOVERY_WHOS order without repeats (the order the sweep sends, the order
`discovery_whos_for` yields), and the no-OWNd fallback renders the pin in that order.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A pin-bump rehearsal (pinned_whos of the F461 / MyHomeServer1 rows set to [1, 2, 4, 18],
`*OpenWebNet-HA#16*0*5##` removed from their sweep_omits, `sync_documentation.py --update`) left two tests
red for no reason of the code: one asserted the pre-bump WHO 16 literal of the two rows (the
committed-docs equality test pins that already), the other assumed the pre-bump sweep_omits
of the MyHomeServer1 row. Both now state their own precondition, so the pin bump edits the
rows, the docs and nothing in this file.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@gdluck
gdluck force-pushed the chore/profiles-companion-ownd-142 branch from bfc1c27 to 1e346c3 Compare October 26, 2026 08:56
@gdluck

gdluck commented Oct 26, 2026

Copy link
Copy Markdown
Author

Rebased once more onto v2-phase1-architecture e649bc8 (after #818): only the H4684 / H/L4684 row name in the table test changed; 4989 passed / 1 skipped at 100 % coverage against OWNd master, and against the OpenWebNet-HA/OWNd#142 checkout the single expected docs-drift row remains. Head 1e346c3, mergeable, still draft.

@GreenGrassBlueOcean GreenGrassBlueOcean left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gdluck Clean rebase and reconciliation with #794 and #818 — verified the discovery_whos_for derivation, the pinned_whos no-OWNd CI fallback, the sweep_omits / notes_without_who16 transition rules, and the refreshed own-firmware-oracle (72759e8) WHO 16 verdicts on F461 (020011) and MyHomeServer1 (028206). All 17 CI checks are green.

One final item before merge (inline below):

  • Add a negative unit test in tests/test_gateway_profiles.py for the new GenericGatewayProfile guard in verify_profiles_against_oracle() (scripts/update_gateway_profiles.py:642-646), asserting that a discovery row whose profile_name is "Generic" or an unknown model string (resolving to GenericGatewayProfile) emits the "resolves to the generic profile" violation.

Once that test is added (and you mark the PR Ready for review), I will merge right away.

Comment on lines +642 to +646
if isinstance(prof, GenericGatewayProfile):
violations.append(
f"Discovery row {row.get('model')} names an OWNd profile that does not exist: "
f"{prof_name} (resolves to the generic profile)."
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new isinstance(prof, GenericGatewayProfile) guard fixes the earlier vacuous is None check, but none of the negative tests in tests/test_gateway_profiles.py exercise it yet. Please add a quick negative test case (e.g. inside test_oracle_check_rejects_a_pin_that_disagrees_with_the_installed_profile or a dedicated test) setting a row's profile_name to "Generic" or a nonexistent model name and asserting "resolves to the generic profile" is reported in violations.

…is flagged (review follow-up)

Negative test for the GenericGatewayProfile guard of verify_profiles_against_oracle(): a row
whose profile_name is "Generic" or an unknown model string reports "resolves to the generic
profile" for that row and for no other. Fails with the previous `is None` check, passes with
the guard.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@gdluck
gdluck marked this pull request as ready for review October 26, 2026 11:22
@gdluck

gdluck commented Oct 26, 2026

Copy link
Copy Markdown
Author

Added in fd20792: test_oracle_check_rejects_a_row_that_resolves_to_the_generic_profile, parametrised over Generic and an unknown model string, asserts the resolves to the generic profile violation for that row and for no other; it fails with the previous is None check and passes with the GenericGatewayProfile guard. Full suite 4991 passed / 1 skipped at 100 % coverage, ruff and typing ratchet clean. Marked ready for review.

@GreenGrassBlueOcean
GreenGrassBlueOcean merged commit f4a5a90 into OpenWebNet-HA:v2-phase1-architecture Oct 26, 2026
17 checks passed
gdluck pushed a commit to gdluck/HomeAssistant-MyHOME that referenced this pull request Oct 26, 2026
…s mirror at the edges (OpenWebNet-HA#808 follow-up)

The docstring said the script "mirrors MyHOMEGatewayHandler._profile_supports_who";
the runtime gate fails open (every WHO when supports_who is missing or raises),
the script fails closed ([] when missing) and propagates when supports_who
raises, and test_discovery_whos_follow_the_runtime_gate pins the divergent
discovery_whos_for(object()) == []. Real OWNd profiles agree. The docstring
and the test's say so.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
GreenGrassBlueOcean added a commit that referenced this pull request Oct 26, 2026
…e-arg-and-log

fix(config_flow,legacy_yaml): drop an inert profile argument, say what moved, no unreachable MAC fallback (#804 / #798 / #801 / #808 follow-up)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants