Cluster
Files: project.conf (variables.release-version), Justfile (fsdk_version, version recipes), elements/freedesktop-sdk.bst (pinned junction ref), .github/workflows/build.yml (release tag + asset upload steps).
Consumers: elements/oci/bluefin-server-ddi.bst (ddi-version), elements/oci/bluefin-server-installer.bst (installer-version), elements/oci/k3s-sysext.bst (FNAME), files/os/sysupdate.d/50-root.transfer, 60-uki.transfer, 70-k3s.transfer.
Problem
The asset version axis is declared in two places that are computed independently and never compared.
project.conf hardcodes release-version: "25.08.13" with the comment "Single source of truth for asset versioning; must match the FSDK point release." This value produces every published asset filename: bluefin-server-ddi-<v>.raw.zst, bluefin-server-installer-<v>.raw.zst, bluefin-server-<v>.efi, k3s-<v>.raw.zst.
Justfile computes fsdk_version by grepping the point release out of the pinned junction ref in elements/freedesktop-sdk.bst. .github/workflows/build.yml uses just version to build the release tag: TAG="installer-v${V}".
elements/freedesktop-sdk.bst is currently pinned to freedesktop-sdk-25.08.15-0-gda39a00..., and build.yml auto-tracks and auto-commits that ref on Renovate PRs. So the derived value moves on its own; the hardcoded value does not.
The drift is already live: project.conf says 25.08.13, the junction says 25.08.15.
Structural consequence
The next main build publishes tag installer-v25.08.15 whose assets are still named ...-25.08.13.... The upload steps in build.yml copy by glob (bluefin-server-ddi-*.raw.zst, k3s-*.raw.zst), so nothing notices.
files/os/sysupdate.d/*.transfer match on @v inside the filename and track releases/latest/download/. systemd-sysupdate therefore reads version 25.08.13 — the version already installed — and concludes there is nothing to update. A/B OS updates, UKI updates, and k3s sysext updates all silently stop for the whole fleet, with a green CI and a fresh GitHub Release as evidence that everything shipped. There is no error surface anywhere in the pipeline.
Why it was not caught
just validate only runs bst show --deps all on the three OCI elements; it does not compare the two version axes.
- The invariant is written down but not enforced:
docs/skills/avoid-over-engineering.md lists "The same version string in more than one .bst file" as a red flag and asserts "release-version in project.conf is the single source of truth." The Justfile is a second source of truth that the checklist does not cover.
gh release upload --clobber plus gh release create ... || true makes releases mutable, so a re-run overwrites assets in place without changing the version — the same silent-no-op failure mode from a different direction.
Proposed fix
Fail closed on the drift: a small checker that parses release-version from project.conf and the point release from the pinned junction ref, and errors when they disagree. Wire it into CI and pre-commit so a Renovate FSDK bump that does not carry a matching release-version bump cannot reach main.
Filed by architect agent (ACMM L5 — hold-gated mode).
🐝 Hive Agent: architect | Instance: hosted-projectbluefin-knuckle-gjvq | SHA: 5e263a0
— hive: agent=architect backend=copilot model=claude-opus-5
Cluster
Files:
project.conf(variables.release-version),Justfile(fsdk_version,versionrecipes),elements/freedesktop-sdk.bst(pinned junction ref),.github/workflows/build.yml(release tag + asset upload steps).Consumers:
elements/oci/bluefin-server-ddi.bst(ddi-version),elements/oci/bluefin-server-installer.bst(installer-version),elements/oci/k3s-sysext.bst(FNAME),files/os/sysupdate.d/50-root.transfer,60-uki.transfer,70-k3s.transfer.Problem
The asset version axis is declared in two places that are computed independently and never compared.
project.confhardcodesrelease-version: "25.08.13"with the comment "Single source of truth for asset versioning; must match the FSDK point release." This value produces every published asset filename:bluefin-server-ddi-<v>.raw.zst,bluefin-server-installer-<v>.raw.zst,bluefin-server-<v>.efi,k3s-<v>.raw.zst.Justfilecomputesfsdk_versionby grepping the point release out of the pinned junction ref inelements/freedesktop-sdk.bst..github/workflows/build.ymlusesjust versionto build the release tag:TAG="installer-v${V}".elements/freedesktop-sdk.bstis currently pinned tofreedesktop-sdk-25.08.15-0-gda39a00..., andbuild.ymlauto-tracks and auto-commits that ref on Renovate PRs. So the derived value moves on its own; the hardcoded value does not.The drift is already live:
project.confsays25.08.13, the junction says25.08.15.Structural consequence
The next
mainbuild publishes taginstaller-v25.08.15whose assets are still named...-25.08.13.... The upload steps inbuild.ymlcopy by glob (bluefin-server-ddi-*.raw.zst,k3s-*.raw.zst), so nothing notices.files/os/sysupdate.d/*.transfermatch on@vinside the filename and trackreleases/latest/download/. systemd-sysupdate therefore reads version25.08.13— the version already installed — and concludes there is nothing to update. A/B OS updates, UKI updates, and k3s sysext updates all silently stop for the whole fleet, with a green CI and a fresh GitHub Release as evidence that everything shipped. There is no error surface anywhere in the pipeline.Why it was not caught
just validateonly runsbst show --deps allon the three OCI elements; it does not compare the two version axes.docs/skills/avoid-over-engineering.mdlists "The same version string in more than one.bstfile" as a red flag and asserts "release-versioninproject.confis the single source of truth." The Justfile is a second source of truth that the checklist does not cover.gh release upload --clobberplusgh release create ... || truemakes releases mutable, so a re-run overwrites assets in place without changing the version — the same silent-no-op failure mode from a different direction.Proposed fix
Fail closed on the drift: a small checker that parses
release-versionfromproject.confand the point release from the pinned junction ref, and errors when they disagree. Wire it into CI and pre-commit so a Renovate FSDK bump that does not carry a matchingrelease-versionbump cannot reachmain.Filed by architect agent (ACMM L5 — hold-gated mode).
🐝 Hive Agent:
architect| Instance:hosted-projectbluefin-knuckle-gjvq| SHA:5e263a0— hive: agent=architect backend=copilot model=claude-opus-5