Skip to content

fix(drivers): never lose a driver selection to a Core update - #1428

Merged
frahlg merged 2 commits into
masterfrom
fix/driver-review-followups
Sep 25, 2026
Merged

frahlg merged 2 commits into
masterfrom
fix/driver-review-followups

Conversation

@frahlg

@frahlg frahlg commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Follow-up to #1422 and #1426, from a Codex review and an independent review of today's merged driver work.

Defects found

  1. Retirement was destructive (independent review). RetireSupersededByBundled deactivated the owner's managed selection when a release bundled a version at least as new. An update trial that fell back, or ftw rollback, then ran the older release's older copy. The version installed early, for example to fix a bug, was lost.
  2. A choice counted only against the bundled copy (independent review). Scenario: under a release with 1.3.0, the owner installs 1.3.3 early and goes back to 1.3.2. The choice was not kept, and the next release ran the rejected 1.3.3.
  3. A failed retirement was never retried on that release (Codex). The release marker was saved anyway. The derived model below makes this moot.
  4. used_by matched configured drivers by file name (Codex). An operator's own file elsewhere with the same name was credited to the catalog entry.

Change

  • Selections are never changed at start.
    • driver-repository/active records what the owner selected.
    • driver-repository/effective is derived from it and the release's drivers at every start and after every change. Paths resolve through it: config, catalog, API and driver inventory.
  • A selection runs when it is at least as new as the release's copy, or when the owner went back to it from a newer version that was running.
  • When a release brings a newer copy, that copy runs, and the selection is kept. An older release runs it again.
  • A rollback restores the choice it replaced, so recovering from a failed install leaves no mark.
  • The release marker is gone.
  • used_by compares the configured resolved path with the entry's file in its source directory.
  • Backups: the new symlinks live in the data directory and are archived like the existing ones.

Evidence

  • New or rewritten tests in go/internal/driverrepo/bundled_supersedes_test.go:
    • a newer release driver runs, the selection is kept, and a rollback runs it again;
    • the same version keeps the selection running;
    • an older choice stays across releases;
    • going back below the running version is a choice;
    • a rollback restores the undone choice;
    • "use bundled" forgets the choice;
    • a newer or unbundled selection stays.
  • TestDriverCatalogCreditsOnlyTheFileThatRuns fails on the old basename matching.
  • go test passes for internal/driverrepo, internal/api, cmd/ftw, internal/driverinventory, internal/ftwcli and internal/backup.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MuerPFZFG88kgu8sWVHeq7

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-25T07:28:15.041026Z 88b6a6e PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@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: 88b6a6e6ee

ℹ️ 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 go/internal/api/api.go
continue
}
rel := filepath.FromSlash(strings.TrimPrefix(entries[i].Path, "drivers/"))
entries[i].UsedBy = usedBy[filepath.Clean(filepath.Join(root, rel))]

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 Canonicalize both sides before matching driver paths

When the catalog root is relative but the configured Lua path is absolute—e.g. FTW starts in /opt/ftw with -drivers=drivers while the config names /opt/ftw/drivers/demo.lua—both paths identify the same file, but filepath.Clean leaves one relative and one absolute, so this lookup produces no used_by entry. Absolute driver paths and relative -drivers values are both supported, and with this configuration ftw status can omit its Drivers line even though the cataloged driver is running; normalize both keys with filepath.Abs before comparing them.

Useful? React with 👍 / 👎.

@frahlg frahlg changed the title fix(drivers): retry failed retirements and credit only the file that runs fix(drivers): never lose a driver selection to a Core update Sep 25, 2026
frahlg added a commit that referenced this pull request Sep 25, 2026
Matches #1428: a newer release driver runs over an early selection
without discarding it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MuerPFZFG88kgu8sWVHeq7
frahlg added a commit that referenced this pull request Sep 25, 2026
…#1429)

* fix(drivers): one id per driver, from the bundled copy to the channel

Moves the pin to srcfl/device-drivers#132, where every driver's DRIVER
table states the catalog id and version. FTW's identity rule for the
old spellings (IdentifiesSameDriver) goes: a bundled copy and a channel
artifact are the same driver when their ids are equal.

- Catalog tests look drivers up by the catalog ids.
- The recovery-snapshot provenance test for esphome_dsmr is gone: the
  bundled file is now the driver's source, and sync-bundled-drivers.sh
  --check already binds every bundled file to the pinned commit.
- setup.js recognises the Zap driver by its id `zap`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MuerPFZFG88kgu8sWVHeq7

* docs(release): promote the driver channel as the last stable step

drivers-stable only serves installs that read the channel (1.x-3.x) and
the stable rows of the Versions list; 0.x runs the drivers its release
bundles. Promoting it is one existing command after a stable Core
release, not new automation. The proposal to promote it with Core goes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MuerPFZFG88kgu8sWVHeq7

* fix(drivers): pin the merged one-id device-drivers commit

Moves the pin to bcf4683, srcfl/device-drivers#132 as merged on main,
instead of the branch commit it was tested against before its rebase.
The changeset no longer says esphome-dsmr is gone: #132 keeps that
catalog entry for sites that installed it. The stable promotion step
says what to do when main has moved past drivers-beta.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MuerPFZFG88kgu8sWVHeq7

* docs(agents): a driver selection survives updates and rollbacks

Matches #1428: a newer release driver runs over an early selection
without discarding it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MuerPFZFG88kgu8sWVHeq7

* fix(drivers): pin device-drivers 43710c8 (esphome_dsmr 1.0.5)

srcfl/device-drivers#134 puts esphome_dsmr's host API fields on their
own lines; FTW reads DRIVER fields line by line and its publication
check refused the 1.0.4 file. The bundled set now publishes cleanly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MuerPFZFG88kgu8sWVHeq7

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
frahlg and others added 2 commits September 25, 2026 10:00
…runs

Codex review of #1422 found two defects:

- RetireSupersededByBundled recorded the release as reconciled even
  when a Deactivate failed, so a retirement blocked once (for example by
  an unwritable active directory) was never tried again on that
  release. The release marker is now saved only when every retirement
  succeeded.
- The catalog's used_by matched configured drivers by file name. An
  operator's own file elsewhere with the same name was credited to the
  catalog entry, and `ftw status` reported a version that was not
  running. It now compares the configured resolved path with the
  entry's file in its source directory.

Both new tests fail on the previous code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MuerPFZFG88kgu8sWVHeq7
Independent review of #1422 and #1426:

- RetireSupersededByBundled deactivated the managed selection when a
  release bundled a version at least as new. A failed update trial that
  fell back, or `ftw rollback`, then ran the older release's older copy
  and lost the version the owner had installed early.
- A choice counted only when it was older than the bundled copy at that
  moment, so going back from an early 1.3.3 to 1.3.2 under a release
  with 1.3.0 was not kept, and the next release ran the rejected 1.3.3.

The selection is no longer changed at start. driver-repository/active
records what the owner selected; driver-repository/effective, which
paths now resolve through (config, catalog, API, driver inventory), is
derived from it and the release's drivers at every start and after
every change. A selection runs while it is at least as new as the
release's copy, or when the owner went back to it from a newer version
that was running. A rollback of an activation restores the choice it
replaced, so recovering from a failed install leaves no mark. The
release marker is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MuerPFZFG88kgu8sWVHeq7
@frahlg
frahlg force-pushed the fix/driver-review-followups branch from c651ce6 to fd74e18 Compare September 25, 2026 08:01
@frahlg
frahlg merged commit 2487c90 into master Sep 25, 2026
16 checks passed
@frahlg
frahlg deleted the fix/driver-review-followups branch September 25, 2026 08:05
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