checks / unit (pull_request) Successful in 6m11s
Two ways a deploy of this add-on has gone wrong, and the Supervisor reports both as success. THE SILENT NO-OP. The Supervisor keys the built image by `version:`, so `ha apps update` against an unchanged version installs nothing and says it worked. PKG-06 recorded this on 2026-09-05 with four merges behind an unbumped version. PKG-07 recorded it again on 2026-09-06 with six. Both times a human noticed. Nothing else was going to. THE REFUSED CONFIG. A config the shipped validator rejects is SystemExit(78) - the add-on does not start. ⚠️ AND THE INGRESS PANEL GOES WITH IT, because the add-on serving it is not running, so recovery means the Supervisor UI. SAFETY-39's rule 10 made this reachable from a config that started fine on the previous version: 0.7.0's own default `slew_w: 1000` exceeds the 555.6 W ceiling on a 5000 W rail. ⚠️ WHY THIS IS NOT A CI CHECK, WHICH IS THE OBVIOUS IMPLEMENTATION. "A pull request that touches runtime code must bump the version" is the wrong shape for this project. It deliberately batches many merges into one deploy, so a per-PR bump would put every open branch in conflict over one line of config.yaml, and it still would not prevent the actual failure - which happens at DEPLOY, not at merge. The check belongs where the mistake is made, so it is a script the operator runs, not a gate on a pull request. WHAT IT DOES NOT DO. It does not read the live box: the options blob needs the Supervisor API and a supervisor token, and neither the HA REST API nor any entity exposes it. The operator exports the options and passes --options. Without that flag the validator half SKIPS - loudly, exit 2 - and never pretends. `app/validate.py` imports its siblings and those need aiohttp, so on a bare host that half skips too and says which container to re-run it in. EXIT CODES: 0 cleared, 1 REFUSED, 2 NOT CLEARED. ⚠️ 2 IS NOT A PASS. ⚠️ THE TEST'S FIRST DRAFT REPORTED FOUR SILENT SKIPS AS PASSES. It copied the gate into each throwaway fixture, so the script's sibling `app/` was the stub the fixture had built and the validator import failed - every validator assertion skipped, and four of them were written to expect a clearance. Fixed by invoking the gate WHERE IT SHIPS and pointing --tree/--repo at the fixture, which is also the behaviour that matters: the gate must check a config against the validator it ships beside. That is MUTATION.md habit 4 again - a check whose data cannot reach the failure it names - caught this time by the harness positive control rather than in review. Every refusal in test_version_gate.py is DRIVEN: a repository is built in which the failure is really present and the check is required to say so. There is a positive control that the no-op detector does NOT fire on a docs-only change, and a pin that omitting --options can never exit 0. This change needs no version bump, and the gate agrees: `tools/` and `test_*.py` are outside its runtime set, because demanding a bump for a typo fix trains people to bump without reading - the habit it exists to prevent. Suite: 24 files, all pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU