PKG-09: refuse a deploy that would be a no-op, or that the add-on would reject
checks / unit (pull_request) Successful in 6m16s
checks / unit (pull_request) Successful in 6m16s
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 six 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. ⚠️ IT CAUGHT A LIVE ONE ON ITS OWN PULL REQUEST. Run against release/1.0 while this branch was in review: version 0.8.0 on both sides with UX-02's and OPT-09's runtime commits already merged behind it. The class this exists to catch had recurred, the same day, unnoticed - which is the argument for PKG-10, a non-required post-merge check, since this script only helps someone who remembers to run it. ⚠️ THE FIRST VERSION WAS BROKEN ON EVERY REAL REPOSITORY AND ITS TESTS COULD NOT SEE IT. The "when did the version last change" lookup was `git log -S`, the pickaxe, which finds commits that change the COUNT of a literal string. A bump edits the line IN PLACE, so the count never moves and it returned only the commit that first INTRODUCED the line. Measured here: -S ->0a1e61d2026-08-23 Packaged as a Home Assistant add-on -G ->06661c52026-09-06 PKG-07: bump 0.7.0 -> 0.8.0 so a correctly bumped tree was reported as 87 COMMITS BEHIND AN UNBUMPED VERSION, PKG-06's and PKG-07's own bump commits among the offenders. A tool whose whole purpose is to be trusted cried wolf on every run. ⚠️ AND `-G` IS NOT THE FIX EITHER, ONLY A BETTER FILTER - it matches a reformat, a quote change, a comment moved onto the line. `-G` narrows the candidates and the VALUE is then compared against the parent's. ⚠️ THREE DISTINCT SHAPES OF HABIT 4 IN ONE FILE, each found by a different means, which is the honest record of how this landed: 1. Fixtures built fresh repositories whose version line is introduced once and never edited - the one shape in which `-S` looks correct. Found by review. Answered with a three-state history; the old lookup goes red on 4 checks. 2. That three-state history still could not tell "value-compared" from "filtered-only": review swapped in `-G`'s newest raw hit and THE WHOLE SUITE STAYED GREEN, so the docstring's central claim was pinned by nothing. Answered with a cosmetic touch of the version line - `-G` matches it, the value comparison does not. That mutant now goes red on 3 checks. 3. The counts below were claimed fixed and two of them had not landed at all. Two git shapes it still gets wrong are recorded in the docstring rather than fixed - a bump resolved inside a merge commit (false refusal) and a bump reverted while the work is kept (false clearance, the dangerous direction). Neither has ever occurred here; both were constructed in review. Card PKG-11. ⚠️ AND THE PROSE COUNTS, WHICH I REPORTED AS FIXED WHEN THEY WERE NOT. Round 1 found "PKG-06 ... four merges" (its own commit message says six) and "recorded eleven times" (MUTATION.md:550 says TWELFTH). I replaced them without asserting the replacement matched, said "all applied", and round 2 found both still in the tree - one fixed in DOCS.md but not in the script, one not fixed anywhere. A claim that a correction landed is itself a claim that needs checking, and this is PROC-01's tenth instance. WHAT IT DOES NOT DO. It does not read the live box: the options blob needs the Supervisor API. Without --options the validator half SKIPS - loudly, exit 2 - and never pretends. On a bare host `app/validate.py` needs aiohttp, so that half skips too and names the container to re-run in. A missing or malformed --options file is a REFUSAL with a sentence, not a traceback. EXIT CODES: 0 cleared, 1 REFUSED, 2 NOT CLEARED. ⚠️ 2 IS NOT A PASS. Suite: 26 files, all pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BwRLw7eKYj2byVdwB6kbjU
This commit is contained in:
co-authored by
Claude Opus 5
parent
fdb3b69397
commit
04b3330def
@@ -1572,3 +1572,46 @@ If an MQTT broker is available the add-on publishes setpoint, grid power,
|
||||
battery power, circulating power, state of charge, maintenance phase and
|
||||
controller status by MQTT discovery. This is observability only — the controller works fine without a
|
||||
broker, and MQTT problems can never affect control.
|
||||
|
||||
## Before you deploy: `tools/predeploy_check.py` (PKG-09)
|
||||
|
||||
Two ways a deploy has gone wrong on this system, both of which the Supervisor
|
||||
reports as success:
|
||||
|
||||
**The silent no-op.** The Supervisor keys the built image by `version:` in
|
||||
`config.yaml`. `ha apps update` against an unchanged version installs nothing
|
||||
and says it worked. This happened twice: PKG-06 (six merges behind an unbumped
|
||||
version) and PKG-07 (six again). Both times a human noticed. Nothing else would have.
|
||||
|
||||
**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.
|
||||
|
||||
Run it inside the container, so the validator half actually runs:
|
||||
|
||||
docker run --rm -v <repo>:/w:ro goodwe-addon-checks:1 \
|
||||
python3 /w/goodwe_controller/tools/predeploy_check.py \
|
||||
--deployed-version 0.7.0 --options /w/live-options.json
|
||||
|
||||
Export `live-options.json` from the Supervisor first — the options blob is not
|
||||
reachable through the Home Assistant REST API, and no entity carries it.
|
||||
|
||||
**Exit codes.** `0` cleared · `1` REFUSED, do not deploy · `2` NOT CLEARED,
|
||||
meaning a check did not run. ⚠️ **2 is not a pass.** On a bare host without the
|
||||
add-on's dependencies the validator half skips and returns 2 rather than
|
||||
pretending; `test_version_gate.py` pins that a skipped check can never exit 0,
|
||||
because the first draft of that test reported four silent skips as passes.
|
||||
|
||||
⚠️ **Why this is not a CI check.** The obvious gate — "a pull request touching
|
||||
runtime code must bump the version" — is the wrong shape here. This project
|
||||
deliberately batches many merges into one deploy, so a per-PR bump would put
|
||||
every branch in conflict over one line and still not prevent the failure, which
|
||||
happens at deploy and not at merge. The check belongs where the mistake is made.
|
||||
|
||||
⚠️ This file's own change does **not** need a version bump, and the gate agrees:
|
||||
`tools/` and `test_*.py` are not in its runtime set, because demanding a bump
|
||||
for a typo fix trains people to bump without reading — the habit the check
|
||||
exists to prevent.
|
||||
|
||||
Reference in New Issue
Block a user