Skip to content

refactor(eccc): harden language matching for bare primary subtags - #60

Merged
seevee merged 1 commit into
seevee:mainfrom
rkfshakti:fix/bcp47-language-matching-59
Jul 30, 2026
Merged

refactor(eccc): harden language matching for bare primary subtags#60
seevee merged 1 commit into
seevee:mainfrom
rkfshakti:fix/bcp47-language-matching-59

Conversation

@rkfshakti

@rkfshakti rkfshakti commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Thanks for the detailed review — really appreciate you digging into #59 and tracing the full path from config_flow through coordinator to the feed itself. You're right that the zh-CN scenario in the original framing can't occur, and I've reframed this accordingly.

What this actually does

The ECCC feed carries en-CA and fr-CA, config_flow restricts to those two, and auto resolves to one of them. Exact-match selection works today. But if a CAP body ever declared a bare en instead of en-CA, the existing == check would miss it and fall through to doc.infos[0], which can be the French block. This PR hardens against that by falling back to primary-subtag comparison when the exact match fails.

This is hardening, not a fix for an observed defect. I haven't seen NAAD do this either, but prefix matching makes the selection safe if it ever does.

Changes from review feedback

  1. Reframed title and description around the bare en case, dropping the zh-CN framing. Using refactor(eccc): since there's no observed defect.

  2. Added tests for _language_matches — five cases:

    • Exact match (en-CA == en-CA)
    • Bare primary against region-tag (en vs en-CA, both directions)
    • Negative case (en-CA vs fr-CA)
    • Empty-string guards
    • Case insensitivity
  3. Re-ran in the pinned venv (Python 3.14, requirements_test.txt): 123 passed, 0 failed in test_eccc_provider.py. The earlier "54 passed, 1 pre-existing failure" was from a different environment — in the pinned venv it's 118 on main and 123 with the new tests. Ruff check and format both clean.

  4. Added Assisted-by: trailer per CONTRIBUTING.md — used Assisted-by: GitHub Copilot:glm-5.2 instead of Co-authored-by:.

Fixes #59

@rkfshakti

Copy link
Copy Markdown
Contributor Author

Hi maintainers — gentle bump on this fix for #59. Adds BCP 47 prefix fallback for language matching in ECC alert parsing so that region-specific language tags (e.g. zh-CN) match their base language. CI is passing. Would appreciate a review when time allows. Thanks!

@seevee seevee left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Thanks for picking this up, and sorry for the slow review.

I dug into #59 before reviewing this and I don't think its premise holds. The full explanation is in my comment there, but the short version for this PR:

  • config_flow.py restricts the ECCC language option to vol.In(["auto", "en-CA", "fr-CA"]), so zh-Hans cannot be configured.
  • auto resolves in coordinator.py to "fr-CA" if hass.config.language.startswith("fr") else "en-CA".
  • NAAD CAP documents carry exactly one en-CA and one fr-CA <info> block per area group.

So preferred_lang reaching eccc.py is always en-CA or fr-CA, and one of the two blocks always matches it exactly. The zh-Hans against zh-CN case in the description cannot occur, and on real ECCC data the new prefix branch is unreachable: the exact-match check above it always wins. This is a no-op rather than a fix. It is harmless, since en and fr primary subtags never collide, but it is not doing what the PR says it does.

Worth saying that your version is better than the sketch in #59. That sketch guarded the fallback with "-" in preferred and "-" in info_lang, which would have excluded en against en-CA. You dropped it, and that happens to be the one comparison here with real value.

Which is why I would rather reframe this than close it. There is a latent gap: if a CAP body ever declared bare en instead of en-CA, today's == misses it and falls through to doc.infos[0], which can be the French block. I have not seen NAAD do that, but prefix matching would make it safe. I would merge this as that hardening, with two changes:

  1. Retitle and rewrite the description around the bare en case, dropping the zh-CN framing. refactor(eccc): fits, since there is no observed defect being fixed.
  2. Add tests for _language_matches. It is a new helper with no coverage in a suite of 478 tests, and the bare en against en-CA case is exactly the behavior worth pinning down so a future refactor does not quietly drop it. en-CA against fr-CA as a negative case, plus the empty-string guards, would round it out.

One process note. The test plan says tests/test_eccc_provider.py gives "54 passed, 1 pre-existing failure (unrelated asyncio fixture issue)". On main that file is 118 passed with no failures, and the full suite is green. That gap usually means the suite ran somewhere other than the pinned environment. Setup is in AGENTS.md under "Build & Test Commands": a venv seeded from requirements_test.txt, which is what CI uses. Could you re-run there and update the numbers?

If an assistant helped draft this, that is welcome. CONTRIBUTING.md just asks that it be disclosed as a tool with an Assisted-by: trailer on the commit rather than a Co-authored-by:.

Happy to merge once it is reframed and tested. If you would rather not carry it further, no problem at all, and I will close it alongside #59.

The ECCC feed consistently carries en-CA and fr-CA info blocks, and
config_flow restricts the language option to those two values, so
exact-match selection works today. However, if a CAP body ever declared
a bare 'en' instead of 'en-CA', the existing == check would miss it and
fall through to doc.infos[0], which can be the French block.

_language_matches now falls back to comparing the primary subtag (the
part before the first '-') when the exact match fails, so 'en' matches
'en-CA' and vice-versa. This is hardening, not a fix for an observed
defect — the ECCC feed has not been seen to do this, but prefix matching
makes the selection safe if it ever does.

Adds five tests covering exact match, bare-primary against region-tag,
en-CA/fr-CA negative case, empty-string guards, and case insensitivity.

Re-run in the pinned venv (requirements_test.txt): 123 passed, 0 failed
in test_eccc_provider.py. Ruff check and format clean.

Assisted-by: GitHub Copilot:glm-5.2
@rkfshakti
rkfshakti force-pushed the fix/bcp47-language-matching-59 branch from 731ee8c to 79a5339 Compare July 30, 2026 06:06
@rkfshakti rkfshakti changed the title fix: add BCP 47 prefix fallback for language matching in ECCC provider refactor(eccc): harden language matching for bare primary subtags Jul 30, 2026
@rkfshakti

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review — really appreciate you tracing the full path from config_flow through coordinator to the actual feed data. You're right that the zh-CN scenario can't occur, and I've reframed the PR accordingly.

Changes made:

  1. Reframed to refactor(eccc): around the bare en hardening case, dropping the zh-CN framing.

  2. Added five tests for _language_matches: exact match, bare en vs en-CA (both directions), en-CA vs fr-CA negative, empty-string guards, and case insensitivity.

  3. Re-ran in the pinned venv (Python 3.14, requirements_test.txt): 123 passed, 0 failed in test_eccc_provider.py. The earlier "54 passed, 1 failure" was from a different environment — on main in the pinned venv it's 118 passed with no failures, matching what you see. With the five new tests it's 123.

  4. Added Assisted-by: GitHub Copilot:glm-5.2 trailer per CONTRIBUTING.md, replacing the Co-authored-by: approach.

Squashed into a single commit. Happy to make any further adjustments.

@seevee seevee left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Looks good! Thanks for the tweaks and the fast turnaround!

@seevee
seevee merged commit e248db1 into seevee:main Jul 30, 2026
6 checks passed
@rkfshakti

Copy link
Copy Markdown
Contributor Author

Looks good! Thanks for the tweaks and the fast turnaround!

Please let me know or assign if if you need help on anything for fixes or issues; happy to contribute.

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.

WMO: multilingual CAP bodies fall through to infos[0] — no language selection

2 participants