Skip to content

feat: publish drivers with the control path they were ported with#31

Merged
frahlg merged 1 commit into
mainfrom
30-publish-drivers-with-their-control-path
Jul 26, 2026
Merged

feat: publish drivers with the control path they were ported with#31
frahlg merged 1 commit into
mainfrom
30-publish-drivers-with-their-control-path

Conversation

@frahlg

@frahlg frahlg commented Jul 26, 2026

Copy link
Copy Markdown
Member

Closes #30.

Every artifact this channel published was write-inert. The generator replaced host.modbus_write, host.mqtt_pub and the rest with a function that raises, then overwrote driver_command and driver_default_mode after the source loaded. All 80 drivers went out read_only: true, control_enabled: false.

The bundled copy has none of that, and since FTW #673 it is a pinned snapshot of this repo. The same source file could drive a battery when it shipped with the build and could not when it was downloaded.

The manifests were not the answer either

Battery drivers with a working driver_command 18
…whose manifest still said control: false 16

The control logic was ported. The manifest never caught up. Deriving control from the manifest would have published pixii, alphaess, solaredge, sma and eleven others unable to do the one thing they were ported for.

So the code decides

  • A driver whose source defines driver_command is published with that path intact, and gets the write permission for its protocol (modbus.write, mqtt.publish, …).
  • A driver that declares read_only in its own DRIVER table keeps the write guards. That is a meter or a telemetry gateway stating what it is, and it outranks an entrypoint the driver may only have inherited from a shared source.

Today: 43 controlling, 37 read-only. sdm630, zap and the esphome meters stay read-only exactly as before.

Consistency is enforced, not assumed

read_only and control_enabled are two spellings of one fact, and verification now rejects them when they disagree — a driver that may control while claiming to be read-only reads as safe to anything checking only one of the two. A read-only driver carrying a write permission is rejected for the same reason.

The signed identity is still reasserted after the source loads, so no driver can rename itself into another driver's slot.

Paired change

FTW must stop refusing these: directManifestRuntimePolicy returned an error for any device-drivers artifact that was not read-only. That is srcfl/ftw — a controlling driver now gets no runtime policy, so it runs under the same terms as the bundled copy of the same source.

Merge order matters: the FTW change should land and reach the field first, or a gateway on an older build will refuse to load an updated driver from this channel.

1984 tests pass.

🤖 Generated with Claude Code

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 36ab10190b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tools/ftw_repository.py
# A driver that declares read_only in its own DRIVER table overrides
# this: a meter saying what it is outranks an entrypoint it may only
# have inherited from a shared source.
controls = has_driver_command and not declares_read_only

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Keep unapproved control paths disabled

When the full channel is built, deriving controls solely from the presence of driver_command enables drivers that have not passed the control gate: Pixii's package explicitly sets FTW control_enabled to false and says physical HIL is still pending, while AlphaESS's matching function only logs “control not yet implemented” and returns false. The resulting signed entries nevertheless advertise control and receive write permissions, so require explicit target approval/HIL rather than treating every legacy entrypoint as accepted control.

AGENTS.md reference: AGENTS.md:L15-L18

Useful? React with 👍 / 👎.

frahlg added a commit to srcfl/ftw that referenced this pull request Jul 26, 2026
directManifestRuntimePolicy refused any device-drivers artifact that was not
read-only, and the channel marked every one of them read-only. Meanwhile the
bundled copy -- a pinned snapshot of the same repository since #673 -- carries
no policy at all and drives batteries fine. One source file, two behaviours,
decided by where the file came from.

A driver the channel publishes with control_enabled now gets no runtime policy,
which is exactly what the bundled copy of that same source already gets. A
driver that declares itself read-only still gets a read-only policy bound to
its signed identity and permissions.

read_only and control_enabled are two spellings of one fact, so a manifest
where they agree with each other -- both true or both false -- is refused: a
driver that may control while claiming to be read-only reads as safe to
anything that checks only one of them.

Pairs with srcfl/device-drivers#31, which stops making artifacts write-inert.
This side has to reach the field first, or a gateway on an older build refuses
to load an updated driver from the channel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every artifact this channel published was write-inert. The generator replaced
host.modbus_write, host.mqtt_pub and the rest with a function that raises, then
overwrote driver_command and driver_default_mode after the source loaded. All
80 drivers went out as read_only, control_enabled false.

The bundled copy has none of that, and since FTW #673 it is a pinned snapshot
of this repo. So one source file could drive a battery when it shipped with the
build and could not when it was downloaded -- the same code, two behaviours,
decided by where the file came from.

The manifests could not be trusted to sort this out: 16 of 18 battery drivers
carry a working driver_command while their catalog manifest still says
control: false. The control logic was ported and the manifest never caught up.

So the code decides. A driver whose source defines driver_command is published
with that path intact and gets the write permission for its protocol.
A driver that declares read_only in its own DRIVER table keeps the guards --
that is a meter or a telemetry gateway stating what it is, and it outranks an
entrypoint the driver may only have inherited from a shared source. Today that
is 43 controlling and 37 read-only, with sdm630, zap and the esphome meters
staying read-only exactly as before.

The manifest now carries read_only and control_enabled as opposites of one
fact, and verification rejects them when they disagree: a driver that may
control while claiming to be read-only reads as safe to anything that checks
only one of the two. A read-only driver with a write permission is rejected for
the same reason.

The signed identity is still reasserted after the source loads, so no driver
can rename itself into another driver's slot.

Closes #30

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
@frahlg
frahlg force-pushed the 30-publish-drivers-with-their-control-path branch from 36ab101 to 3f0171d Compare July 26, 2026 15:14
frahlg added a commit to srcfl/ftw that referenced this pull request Jul 26, 2026
…rol (#676)

directManifestRuntimePolicy refused any device-drivers artifact that was not
read-only, and the channel marked every one of them read-only. Meanwhile the
bundled copy -- a pinned snapshot of the same repository since #673 -- carries
no policy at all and drives batteries fine. One source file, two behaviours,
decided by where the file came from.

A driver the channel publishes with control_enabled now gets no runtime policy,
which is exactly what the bundled copy of that same source already gets. A
driver that declares itself read-only still gets a read-only policy bound to
its signed identity and permissions.

read_only and control_enabled are two spellings of one fact, so a manifest
where they agree with each other -- both true or both false -- is refused: a
driver that may control while claiming to be read-only reads as safe to
anything that checks only one of them.

Pairs with srcfl/device-drivers#31, which stops making artifacts write-inert.
This side has to reach the field first, or a gateway on an older build refuses
to load an updated driver from the channel.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@frahlg
frahlg merged commit 3dfdfba into main Jul 26, 2026
5 checks passed
@frahlg
frahlg deleted the 30-publish-drivers-with-their-control-path branch July 26, 2026 15:42
frahlg added a commit that referenced this pull request Jul 26, 2026
The channel refuses to republish a driver whose artifact bytes moved without a
higher version, and #31 moved all eighty: the generated prefix changed for
every driver, and forty-three stopped carrying write guards.

Gaining a control path is a behaviour change, so those forty-three take a
minor. The rest only lost a comment line and take a patch. esphome-dsmr, pixii
and sungrow repeat their version inside their own DRIVER table, so those had to
move in step with the manifest.

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.

The signed channel publishes every driver unable to control anything

1 participant