From a830146636664c8e223f849e79a744b4697636cd Mon Sep 17 00:00:00 2001 From: Claude Opus 5 Date: Fri, 31 Jul 2026 10:56:59 +0200 Subject: [PATCH] fix(nibe_local): version the DER correction so the channel can publish it The driver release failed on main with error: nibe_local: changed artifact needs a higher version than 1.1.0 #53 corrected the manifest from ders: [meter] to ders: [heatpump] and read that as catalog-only metadata, so it left the version at 1.1.0. It is not catalog-only. _load_channel copies ders into the artifact's capabilities and the channel signs source and metadata as one file, so the correction moved the published bytes under a version that has already shipped. The channel refused, and it was right to: that immutability is what lets an operator name the bytes a site is running. So nibe_local takes a patch. Patch rather than minor because no register, field or emitted metric changed -- only the DER the catalog states. The Lua source is untouched and its sha256 with it, and bump_driver leaves the DRIVER table alone because the file is byte-identical to its FTW baseline, so the provenance guarantee #29 established is spent on nothing. Verified against the currently published beta manifest: of 80 drivers exactly one differs from what is published, and after the bump nothing is blocked. CONTRIBUTING said to raise the version whenever the Lua source changes, which is what #53 followed. It now also names the manifest fields that reach the signed artifact -- ders, protocol, and a tested_devices manufacturer and model_family -- and warns that this check runs on main after the merge rather than in the pull request, because only the release can read the channel. Co-authored-by: HuggeK <48095810+HuggeK@users.noreply.github.com> --- CHANGELOG.md | 3 ++- CONTRIBUTING.md | 9 +++++++++ SUPPORT_STATUS.md | 4 ++-- devices.yaml | 2 +- index.yaml | 2 +- manifests/nibe_local.yaml | 2 +- support-status.json | 2 +- 7 files changed, 17 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a268533..0362f80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,8 @@ Driver versions follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html ## [Unreleased] ### Fixed -- **`nibe_local` was filed as a meter.** Its manifest declared `ders: [meter]`; it reads a NIBE S-series heat pump. The driver emits nothing but metrics — `hp_power_w`, `hp_used_power_w`, the temperatures and the lifetime energy counters, all through `host.emit_metric` and never through `host.emit("meter", …)` — which its header states is deliberate, so that a pump's electrical draw cannot double-count against the site's real grid meter. The catalog was advertising a DER the driver does not provide, and the published page (#51) badges and filters on exactly that field: the pump sat under **Meter** and was absent from **Heat pump**, where an owner looking for it would start. Now `ders: [heatpump]`, matching `heishamon` — the other metric-only heat pump, which has been filed that way since it landed. Manifest metadata only: the Lua source, its version and its `sha256` are untouched, so no host sees a new driver build +- **`nibe_local` was filed as a meter.** Its manifest declared `ders: [meter]`; it reads a NIBE S-series heat pump. The driver emits nothing but metrics — `hp_power_w`, `hp_used_power_w`, the temperatures and the lifetime energy counters, all through `host.emit_metric` and never through `host.emit("meter", …)` — which its header states is deliberate, so that a pump's electrical draw cannot double-count against the site's real grid meter. The catalog was advertising a DER the driver does not provide, and the published page (#51) badges and filters on exactly that field: the pump sat under **Meter** and was absent from **Heat pump**, where an owner looking for it would start. Now `ders: [heatpump]`, matching `heishamon` — the other metric-only heat pump, which has been filed that way since it landed. The Lua source and its `sha256` are untouched, so the driver a host runs is byte-for-byte the one it ran before +- **`nibe_local`** 1.1.0 → 1.1.1 — **the version has to move anyway, because the signed artifact carries this metadata.** `ders` is not catalog-only decoration: `_load_channel` copies it into the artifact's `capabilities` and the channel publishes source and metadata as one signed file, so correcting the field changed the published bytes. The channel then refused the release — `error: nibe_local: changed artifact needs a higher version than 1.1.0` — and it was right to, since that immutability is what lets an operator name the bytes a site is running. A patch rather than a minor: no register, field or emitted metric changed, only the DER the catalog states. The `DRIVER` table is deliberately left alone, keeping the driver byte-identical to its FTW baseline the way #29 established ### Added - **A published driver catalog at [srcfl.github.io/device-drivers](https://srcfl.github.io/device-drivers/)** — all 80 drivers, searchable by manufacturer or model number and filterable by device type, protocol, tier and control. `tools/generate_site.py` builds it from the manifests and the Lua sources on every push to `main`, so no copy of this data is checked in and the page cannot fall behind what a host installs. It reports hardware evidence the way the repository does rather than the way a catalog usually does: 5 drivers state they have been confirmed against physical hardware and 28 state that they have not, and `tests/test_site.py` fails the build if a driver's `verification_status` is ever rendered as a stronger claim than the driver makes diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 55c3088..fe2e298 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,6 +49,15 @@ Raise the version whenever the Lua source changes. A version names a set of bytes that runs on hardware, so shipping two different drivers under one version leaves a site with no way to say which one it has. +Raise it too when a manifest field the signed channel publishes changes, even +though no Lua moved. The channel signs source and metadata as one artifact, so +`ders`, `protocol` and the `manufacturer` and `model_family` of a +`tested_devices` entry all reach the published bytes. Changing one under a +version already released fails the release with `changed artifact needs a +higher version`, and it fails on `main` after the merge, not in the pull +request — the check compares against the channel, which only the release can +read. + ```bash make bump-driver ID=example LEVEL=patch ``` diff --git a/SUPPORT_STATUS.md b/SUPPORT_STATUS.md index 99ba5bc..c7e2421 100644 --- a/SUPPORT_STATUS.md +++ b/SUPPORT_STATUS.md @@ -86,8 +86,8 @@ Catalog source is not proof that a target can install or run a driver. | mennekes | 1.0.3 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no | | myuplink | 1.1.0 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no | | myuplink | 1.1.0 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no | -| nibe_local | 1.1.0 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no | -| nibe_local | 1.1.0 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no | +| nibe_local | 1.1.1 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no | +| nibe_local | 1.1.1 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no | | opendtu | 1.0.2 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no | | opendtu | 1.0.2 | blixt-l1 | not_assessed | — | — | not_recorded | — | not_assessed | no | | opendtu_mqtt | 1.0.3 | ftw-core | not_assessed | — | — | not_recorded | — | not_assessed | no | diff --git a/devices.yaml b/devices.yaml index a53d4a1..f0028ff 100644 --- a/devices.yaml +++ b/devices.yaml @@ -989,7 +989,7 @@ manufacturers: protocols: - protocol: http driver: "nibe_local" - version: "1.1.0" + version: "1.1.1" ders: [heatpump] control: true firmware_versions: "" diff --git a/index.yaml b/index.yaml index 99acc46..088dea7 100644 --- a/index.yaml +++ b/index.yaml @@ -329,7 +329,7 @@ drivers: size_bytes: 15278 sha256: "d754fd4af96c2047f9d9e458a776ad8f10510569836618f4631dd70e2510f404" - name: "nibe_local" - version: "1.1.0" + version: "1.1.1" tier: core protocol: http ders: [heatpump] diff --git a/manifests/nibe_local.yaml b/manifests/nibe_local.yaml index 4a7d59e..5e9d478 100644 --- a/manifests/nibe_local.yaml +++ b/manifests/nibe_local.yaml @@ -1,5 +1,5 @@ name: "nibe_local" -version: "1.1.0" +version: "1.1.1" tier: core author: "Sourceful Labs AB" protocol: http diff --git a/support-status.json b/support-status.json index 1dc75ef..d124f51 100644 --- a/support-status.json +++ b/support-status.json @@ -1150,7 +1150,7 @@ }, { "catalog_source": true, - "catalog_version": "1.1.0", + "catalog_version": "1.1.1", "driver_id": "nibe_local", "package_id": null, "targets": {