Skip to content

build: ask the SemVer gate about the pins, not about git history - #709

Merged
frahlg merged 1 commit into
masterfrom
check-driver-versions-across-pins
Jul 28, 2026
Merged

build: ask the SemVer gate about the pins, not about git history#709
frahlg merged 1 commit into
masterfrom
check-driver-versions-across-pins

Conversation

@frahlg

@frahlg frahlg commented Jul 28, 2026

Copy link
Copy Markdown
Member

Second step toward FTW holding no driver source. Stacked on #708 — merge that first; this targets its branch so the diff stays readable.

The problem

check-versions diffs changed .lua files between two Git revisions of this repository. That works only while the drivers are committed here. Once they are fetched instead, there is nothing in the history to diff and the gate silently has no subject.

It was never quite the right question either. What reaches a gateway is decided by where drivers/BUNDLED_SOURCE.json points, not by what this repository's history happens to show.

The change

check-versions gains -old-dir / -new-dir, comparing two materialised snapshots instead of two revisions. ValidateDriverVersionChange is untouched — it always took bytes rather than revisions, so the rule being enforced is identical. Only where the bytes come from changed.

scripts/check-driver-versions.sh reads the pin at a base revision and the pin now:

  • pins match → nothing to check, and it says so. A pull request that does not move the pin cannot have moved any driver's bytes.
  • pins differ → fetch both snapshots, compare every bundled driver.

The Git-based mode stays for now. It still works while the files are committed, and removing it belongs with the deletion.

Tested where it counts

Six cases in main_test.go, and the first is the one the gate exists for:

Case Expected
bytes changed, version stood still fails, and names the driver
bytes changed with a bump passes
nothing changed passes
driver newly added to the bundle list passes — nothing to compare
driver dropped from the list ignored — a coverage decision, not a version one
three drivers all missed a bump all three reported, not just the first

Also run against the real pin move in #704 (1f670783f62a00), where pixii, solaredge_legacy and sungrow all changed with bumps:

$ bash scripts/check-driver-versions.sh master
comparing srcfl/device-drivers 1f67078a54c4 -> 3f62a0050aea
driver version changes verified across 37 bundled drivers

And with the pin left alone:

pin unchanged at 1f67078a54c4; no driver bytes can have moved

Where this leaves the cutover

Step State
Fetch is a build step, proven sufficient #708
SemVer gate asks the pins this PR
Delete drivers/*.lua, gitignore them, keep the pin next, and now small
Replace the drift check with "no .lua may be committed here" with the deletion

The remaining step is genuinely small now: both things that needed the files in git — the build and this gate — no longer do.

go vet ./... clean, go test ./cmd/ftw-driver-repository/ ./internal/driverrepo/ green.

🤖 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: 2b34d73615

ℹ️ 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 on lines +32 to +36
OLD_PIN_JSON="$(git -C "$ROOT" show "${BASE}:${PIN}" 2>/dev/null || echo '')"

if [ -z "$OLD_PIN_JSON" ]; then
echo "no ${PIN} at ${BASE}; nothing to compare"
exit 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Fail when the base revision cannot be read

When BASE is misspelled, unavailable in a shallow clone, or otherwise unreadable, this command converts every git show failure into an empty value and exits successfully as though the pin were being introduced for the first time. Consequently, the advertised make driver-versions-across-pin gate can silently skip all validation; only a confirmed missing BUNDLED_SOURCE.json should be treated as the first-pin case, while revision and Git errors should propagate.

Useful? React with 👍 / 👎.

Comment on lines +39 to +42
REPOSITORY="$(printf '%s' "$NEW_PIN_JSON" | jq -r .repository)"
SOURCE_DIR="$(printf '%s' "$NEW_PIN_JSON" | jq -r .source_dir)"
NEW_COMMIT="$(printf '%s' "$NEW_PIN_JSON" | jq -r .commit)"
OLD_COMMIT="$(printf '%s' "$OLD_PIN_JSON" | jq -r .commit)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Read each snapshot location from its own pin

If a pin update also changes repository or source_dir, both the old and new commits are fetched from the new pin's repository and read through its source path because only OLD_COMMIT is extracted from the old JSON. Such a valid repository/layout migration therefore either fails to materialize the old snapshot or compares unrelated bytes; extract the old repository and source directory too and materialize each commit using its corresponding pin.

Useful? React with 👍 / 👎.

Comment on lines +256 to +257
- name: Require version bumps across the pin
run: bash scripts/check-driver-versions.sh "${{ needs.changes.outputs.base_sha }}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Classify gate-script edits as driver changes

In .github/workflows/test.yml, the drivers job is selected only for Lua files, BUNDLED_SOURCE.json, sync-bundled-drivers.sh, Makefile, or workflow changes; the newly added scripts/check-driver-versions.sh is absent from that classifier. A later PR changing only this gate will therefore skip this step and all of its related checks while the final required job still succeeds with skipped suites, so this script path should select the drivers job.

Useful? React with 👍 / 👎.

@frahlg
frahlg changed the base branch from fetch-bundled-drivers-at-build-time to master July 28, 2026 18:36
@frahlg

frahlg commented Jul 28, 2026

Copy link
Copy Markdown
Member Author

Retargeted to master so CI runs. test.yml triggers only on pull requests against master, so while this pointed at #708's branch it got no checks at all.

That means this PR currently carries two commits: #708's and this one. The dependency is unchanged — #708 should still merge first, and when it does this diff shrinks to the SemVer commit on its own with no action needed.

Review the second commit, build: ask the SemVer gate about the pins, for this change.

@frahlg frahlg closed this Jul 28, 2026
@frahlg frahlg reopened this Jul 28, 2026
The gate diffs changed .lua files between two Git revisions of this
repository. That works only while the drivers are committed here, and
it was never quite the right question: what reaches a gateway is decided
by where drivers/BUNDLED_SOURCE.json points, not by what this history
shows.

check-versions gains -old-dir/-new-dir, comparing two materialised
snapshots instead of two revisions. ValidateDriverVersionChange is
untouched -- it always took bytes rather than revisions, so the rule
being enforced is identical.

scripts/check-driver-versions.sh reads the pin at a base revision and
the pin now, and stays quiet when they match: a pull request that does
not move the pin cannot have moved any driver's bytes. When it has
moved, both snapshots are fetched and every bundled driver compared.

The Git-based mode stays for now. It still works while the files are
committed, and removing it belongs with the deletion.

Tested where it counts -- the failure case. Six table-driven cases in
main_test.go: changed bytes under an unchanged version fail and name
the driver, a bump passes, untouched files pass, a newly bundled driver
has nothing to compare, a dropped one is a coverage decision rather than
a version one, and every offender is reported rather than just the
first.

Also run against the real pin move in #704 (1f67078 -> 3f62a00), where
pixii, solaredge_legacy and sungrow all changed with bumps: verified
across 37 bundled drivers.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
@frahlg
frahlg force-pushed the check-driver-versions-across-pins branch from 2b34d73 to e6d0789 Compare July 28, 2026 18:57
@frahlg
frahlg merged commit 4827627 into master Jul 28, 2026
13 checks passed
@frahlg
frahlg deleted the check-driver-versions-across-pins branch July 28, 2026 18:59
frahlg added a commit that referenced this pull request Jul 28, 2026
Brings the whole absent-register campaign into the recovery snapshot:
every bundled driver now gives up on a register the device does not
answer instead of paying a failed read for it on every poll.

Generated by scripts/sync-bundled-drivers.sh. The SemVer gate added in
#709 verified the move across all 37 bundled drivers.

HELD: go test ./internal/drivers/ fails on this snapshot.
TestSungrowZeroBatteryCommandForcesIdle expects a battery command
issued straight after load to write idle; device-drivers #40 made the
driver refuse a battery command unless the model named itself a hybrid
or a battery register has answered, and neither is true before the
first poll. That disagreement is a control-path decision and is not
mine to settle -- see the pull request for both positions.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
frahlg added a commit that referenced this pull request Jul 29, 2026
Brings the whole absent-register campaign into the recovery snapshot:
every bundled driver now gives up on a register the device does not
answer instead of paying a failed read for it on every poll. 497
addresses across 49 drivers, plus the control-path fixes that landed
alongside.

Pin moves 1f67078 -> edb32ff. Generated by
scripts/sync-bundled-drivers.sh; nothing edited by hand.

The SemVer gate added in #709 verified the move across all 37 bundled
drivers. go test ./... passes, including the Sungrow zero-power case
that held this back, and the full-stack e2e is green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
frahlg added a commit that referenced this pull request Jul 29, 2026
Brings the whole absent-register campaign into the recovery snapshot:
every bundled driver now gives up on a register the device does not
answer instead of paying a failed read for it on every poll. 497
addresses across 49 drivers, plus the control-path fixes that landed
alongside.

Pin moves 1f67078 -> edb32ff. Generated by
scripts/sync-bundled-drivers.sh; nothing edited by hand.

The SemVer gate added in #709 verified the move across all 37 bundled
drivers. go test ./... passes, including the Sungrow zero-power case
that held this back, and the full-stack e2e is green.

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
frahlg added a commit that referenced this pull request Jul 29, 2026
drivers/*.lua leaves git and is gitignored. The files still ship --
offline recovery needs them in the image, the release tarballs carry
them, the tests read them -- but they are fetched from the commit
pinned in drivers/BUNDLED_SOURCE.json rather than committed here.

The point is not the bytes. It is that there is no file to open a pull
request against. Two contributors spent real effort, including thirty
minutes on an SE17K and register-by-register probing on a Pixii,
writing fixes against files that regenerate. A guard that fails the
pull request recovers the codebase but not the afternoon. Absence
teaches faster than a red check does.

Everything that needed the files in git already stopped needing them:
#708 made the fetch a build step and proved a build works from the pin
alone, #709 moved the SemVer gate onto the pins. This is the small
change those two were for.

--check changes its question. It used to compare committed bytes
against the pin; there are no committed bytes now, so it asks whether
any driver is committed at all. Cheaper than a content diff, a stricter
rule, and it needs no network.

Every workflow that reads drivers/ fetches first: core, drivers and
e2e in test.yml, the image build in beta.yml, and both the tarball and
image jobs in release-assets.yml. e2e, release and
driver-repository-validate depend on drivers-present locally, so a
missing fetch fails with the remedy rather than a confusing
file-not-found.

Verified: rm -rf the drivers, make drivers restores 37 of 37, go test
./... passes uncached, and the full-stack e2e is green. The guard is
proven to fire -- git add -f on one driver and --check reports it.

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.

1 participant