fix(catalog): stop badging five drivers Control when they refuse every command - #64
Open
HuggeK wants to merge 1 commit into
Open
fix(catalog): stop badging five drivers Control when they refuse every command#64HuggeK wants to merge 1 commit into
HuggeK wants to merge 1 commit into
Conversation
…y command myuplink, nibe_local, pixii_pv, solis_string and tibber declared control: true. All five have a driver_command that refuses unconditionally, and four say so in a comment on the line above the return false -- "Read-only: no actuation", "Tibber Pulse is a read-only meter; no control surface". The Control badge is the first thing an owner reads when deciding whether a driver can run their heat pump or their battery, and for these five it promised something the code refuses. They are now control: false, which is what their sources have said all along. No Lua changed and no artifact bytes moved: control is not among the fields the channel copies into the signed artifact, so no version had to move. Verified by rebuilding the channel from main and comparing all 80 digests. tests/test_control_claims.py compares the claim against the code, which nothing did before. A driver_command that calls nothing cannot reach a write however it is invoked. Reverting any of the five fails it by name. It also asserts at least 20 drivers still read as controlling, because a guard that stops recognising anything passes exactly as loudly as one that works -- which its own unit test caught while it was being written, when the call regex counted `function driver_command(` and so found every driver busy. Signed-off-by: HuggeK <48095810+HuggeK@users.noreply.github.com> Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com>
This was referenced Jul 31, 2026
HuggeK
marked this pull request as ready for review
July 31, 2026 12:25
Collaborator
Author
|
Update — the "deeper issue" section above says the artifact half was prototyped and backed out. It has since become two PRs, so here is the current picture:
Merge order: ftw#743 must land and ship before #65. A read-only This PR is not part of that ordering. It changes no Lua and moves no artifact bytes — verified by rebuilding the channel and comparing all 80 digests — so it can merge independently of both. |
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.
No — myuplink cannot control anything, and the catalog said it could.
Its
driver_commandrefuses every command it is handed:Its header opens with
READ-ONLY telemetry, itsDRIVER.descriptionends withObserve-only — no control, and its onlyhttp_postis the OAuth tokenrefresh. Yet
manifests/myuplink.yamlsaidcontrol: true, so the page badgedit Control — the first thing an owner reads when deciding whether a driver
can run their heat pump.
Checking the rest of the catalog found four more in exactly the same state:
driver_commandsaysmyuplink-- Read-only: no actuation in Step 1.nibe_local-- Read-only: no actuation. The pump stays in aidMode=off.pixii_pv-- Read-only driver, nothing to control.solis_stringreturn falsetibber-- Tibber Pulse is a read-only meter; no control surface.All five are now
control: false. Each was confirmed by reading its source,not by pattern-matching — an earlier heuristic pass wrongly flagged
sungrow,solisandsolaredge_*, which dispatch to helpers and genuinely do write.Why no driver version had to move
controlis not among the fields the channel copies into the signedartifact, so unlike
ders(#53) this costs no version. Verified rather thanassumed: I rebuilt the channel from
4b5b474and compared all 80 artifactdigests against this tree — none moved.
The deeper issue this uncovered, which is NOT fixed here
The signed artifact does not use the manifest's
controlfield at all:It infers control from the mere presence of a
driver_commandentrypoint, soa stub that always refuses reads to it as a control path. All five are still
published with
control_enabled: true,read_only: false, and a writepermission.
The repo's own sanctioned fix is
read_only = truein the driver'sDRIVERtable. I prototyped it and backed it out, because for
myuplinkit breaks thedriver: the read-only guard replaces
host.http_postwith a function thatraises, and
myuplinkPOSTs to/oauth/tokenfor the token it reads with.Exempting it would need a write permission on a read-only driver, which
ftw_repositoryexplicitly forbids:That invariant is sound and deliberate. Splitting "may POST to authenticate"
from "may write to the device" is a real design decision, so it belongs in its
own change with a maintainer's call — not slipped into a labelling fix.
How the guard was tested, including a bug in the guard itself
tests/test_control_claims.pycompares the claim against the code, whichnothing did before. Reverting any of the five to
control: truefails it byname, with both ways out stated — verified by actually reverting
myuplinkandwatching it go red.
It also asserts at least 20 drivers still read as controlling, because a guard
that quietly stops recognising anything passes exactly as loudly as one that
works. That is not hypothetical: the guard's own unit test caught it while it
was being written, when the call regex counted
function driver_command(as acall and so found every driver busy — which would have made both main
assertions vacuous.
🤖 Generated with Claude Code