You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(bundles): keep user-set priorities when a bundle is refreshed - #5319
specify bundle install --refresh and specify bundle update put each bundle component back to the priority the bundle declares, so a priority set with preset set-priority or extension set-priority was lost (#5318). docs/bundles/cli.md says a refresh preserves "primitive-level overrides such as preset priority". The refresh is a forced reinstall, and the preset and extension install paths in bundles/primitives.py passed the declared priority (or the default, 10) to it without looking at the registry.
On a refresh, both paths now pass the priority already recorded for the component, through a small _installed_priority() helper, so a refresh keeps it the way extension update keeps the stored priority of an extension it reinstalls. A fresh install still uses the bundle's declaration, and a missing or malformed stored value falls back to the declaration (normalize_priority with the declared priority as its default). The bundle record keeps the declared priority, as before.
One behavior to weigh: a bundle version that changes a component's declared priority no longer changes it on an existing install, because the refresh can't tell a priority the user chose from one an earlier version of the bundle set. bundle info still shows the declared value, and set-priority applies it. Earlier commits on this branch tried to tell the two apart, from the bundle records and then from a mark in the registry, but each way got a case wrong (a failed refresh retried, an extension shared by two bundles, an extension update in between), so this PR keeps the rule the docs state.
Repro with the real CLI, steps in #5318 (bundle team requires extension bug and preset lean, both at priority 10):
no set-priority; bundle.yml now declares priority 5 for both
lean 5, bug 5
lean 10, bug 10
the same set-priority calls; bundle.yml now declares 5 for both
lean 5, bug 5
lean 3, bug 4
Projects whose priority was already reset need one set-priority call to set it again; the old value isn't recorded anywhere the fix could restore it from. After that, refreshes keep it.
A bundled_component fixture in tests/specify_cli/bundles/conftest.py installs a bundle with one extension or one preset at priority 10, and priority_bundle then sets that priority to 3 through the CLI.
test_command_install.py::test_refresh_preserves_primitive_priority: bundle install --refresh keeps priority 3, and the bundle record still lists the declared 10.
test_command_update.py::test_update_preserves_primitive_priority: the same through bundle update from a local catalog.
test_command_install.py::test_refresh_keeps_a_user_priority_when_the_bundle_priority_changes: with priority 3 set by the user, the same refresh keeps 3.
test_command_install.py::test_refresh_keeps_a_user_priority_after_the_bundle_declares_the_same_value: with priority 3 set by the user, a refresh with the bundle declaring 3 and then one declaring 5 both keep 3.
test_primitives.py::test_primitive_priority_on_install_and_refresh: both kinds, bundled and catalog sources, install and refresh, with no stored priority, a stored 3, and a malformed stored value.
With primitives.py reverted to main, 12 of the 32 new cases fail: the eight CLI cases and the refresh cases with a stored priority.
Full suite on Linux, Python 3.13: 13985 passed, 449 skipped, 1 failed (pytest -n 2, 7 min). The failure, test_version_execution.py::TestWindowsUvToolEnvironment::test_non_windows_uv_tool_dry_run_still_previews_installer, fails the same way on main here, as noted on #5308: Rich wraps the dry-run output, and my checkout's venv path is long enough to be split mid-path. Ruff 0.15.0 (ruff check src tests) passes. I haven't run it on Windows.
AI Disclosure
I did not use AI assistance for this contribution
I did use AI assistance (fill in the disclosure below)
AI disclosure: Codex CLI (model: gpt-6.1-sol, reasoning effort xhigh, autonomous, offline sandbox) found the priority reset while comparing bundle commands with the docs, and wrote the first fix and tests. Claude Code (model: claude-opus-5-5, autonomous) moved the fix into a shared helper, made a malformed stored priority fall back to the declared one, tried two ways to let a bundle's new priority through while keeping the user's, then went back to always keeping the stored priority after Copilot found cases both got wrong; it reran the repro with the real CLI on main and the branch, ran the full suite and lint, and drafted this description. The commits carry Assisted-by: trailers.
`bundle install --refresh` and `bundle update` reinstall each component
with the priority the bundle declares, so a priority the user had set
with `preset set-priority` or `extension set-priority` went back to the
bundle's value. docs/bundles/cli.md says a refresh keeps primitive-level
overrides such as preset priority.
On a refresh, read the priority already recorded for the component and
pass that to the reinstall. A fresh install still uses the bundle's
declaration, and a missing or malformed stored value falls back to it.
Assisted-by: Codex CLI (model: gpt-6.1-sol, autonomous)
Assisted-by: Claude Code (model: claude-opus-5-5, autonomous)
The refresh kept every stored priority, including the one the bundle
itself set at install. A bundle update that changes its own priority
(say from 10 to 5) then kept 10.
Keep the stored priority only when it differs from every priority the
installed bundle records declared for the component, which means the
user changed it. Otherwise the bundle's new declaration applies.
Assisted-by: Claude Code (model: claude-opus-5-5, autonomous)
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Explicit user priority overrides can be lost across consecutive bundle refreshes when a declaration temporarily matches the override, affecting both presets and extensions.
A refresh treated the stored priority as the user's only while it
differed from every priority the bundle records declared. After a
bundle version declared the user's value, the record held that value,
and the next version's priority replaced the user's.
When a refresh keeps a user priority, mark the registry entry with
"user_priority". The reinstall rewrites the entry, so the refresh writes
the mark again afterwards, and later refreshes keep a marked priority.
Assisted-by: Claude Code (model: claude-opus-5-5, autonomous)
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
Priority tracking still loses explicit user overrides during shared-extension refreshes and extension updates, while failed refresh retries can incorrectly treat bundle-applied priorities as user choices.
set-priority fails to mark shared-extension overrides
src/specify_cli/bundles/primitives.py:67
Shared extensions can still lose explicit user priorities: install bundle A declaring 10 and bundle B declaring 5 for the same extension/version, then run extension set-priority <id> 5 and refresh A. Because 5 matches B's recorded declaration and set-priority does not write user_priority, this returns None and resets the priority to 10. Mark explicit overrides when set-priority runs, reserve declaration-based inference for legacy entries, and add a shared-extension regression.
AI-generated by GitHub Copilot for the review requester (model: unknown; autonomous review; analysis and comment drafting).
Extension update drops the user-priority marker
src/specify_cli/bundles/primitives.py:460
Ordinary extension update drops user_priority: extensions/_command_update_transaction.py:588–604 restores the priority after reinstalling, but not this marker. If a user-set 3 survives a bundle refresh declaring 3, an intervening extension update removes the marker, and the next bundle refresh declaring 5 resets the override. Preserve the marker in the extension update's metadata restoration and add a regression interleaving primitive and bundle updates.
AI-generated by GitHub Copilot for the review requester (model: unknown; autonomous review; analysis and comment drafting).
The last two commits guessed whether the user had set a component's
priority, from the bundle records and then from a registry mark. Each
guess had cases it got wrong: a failed refresh retried, an extension
shared by two bundles, an `extension update` in between.
Go back to the rule the docs state: a refresh reapplies components
through their primitive update paths and preserves primitive-level
overrides such as preset priority. A refresh always keeps the stored
priority, as `extension update` does, and the declared priority is used
only when nothing valid is stored. A bundle version that changes its
declared priority therefore doesn't change an existing install.
Assisted-by: Claude Code (model: claude-opus-5-5, autonomous)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
specify bundle install --refreshandspecify bundle updateput each bundle component back to the priority the bundle declares, so a priority set withpreset set-priorityorextension set-prioritywas lost (#5318).docs/bundles/cli.mdsays a refresh preserves "primitive-level overrides such as preset priority". The refresh is a forced reinstall, and the preset and extension install paths inbundles/primitives.pypassed the declared priority (or the default, 10) to it without looking at the registry.On a refresh, both paths now pass the priority already recorded for the component, through a small
_installed_priority()helper, so a refresh keeps it the wayextension updatekeeps the stored priority of an extension it reinstalls. A fresh install still uses the bundle's declaration, and a missing or malformed stored value falls back to the declaration (normalize_prioritywith the declared priority as its default). The bundle record keeps the declared priority, as before.One behavior to weigh: a bundle version that changes a component's declared priority no longer changes it on an existing install, because the refresh can't tell a priority the user chose from one an earlier version of the bundle set.
bundle infostill shows the declared value, andset-priorityapplies it. Earlier commits on this branch tried to tell the two apart, from the bundle records and then from a mark in the registry, but each way got a case wrong (a failed refresh retried, an extension shared by two bundles, anextension updatein between), so this PR keeps the rule the docs state.Repro with the real CLI, steps in #5318 (bundle
teamrequires extensionbugand presetlean, both at priority 10):bundle install ../team --offline --refreshmain(c438494)preset set-priority lean 3,extension set-priority bug 4lean10,bug10lean3,bug4set-priority;bundle.ymlnow declares priority 5 for bothlean5,bug5lean10,bug10set-prioritycalls;bundle.ymlnow declares 5 for bothlean5,bug5lean3,bug4Projects whose priority was already reset need one
set-prioritycall to set it again; the old value isn't recorded anywhere the fix could restore it from. After that, refreshes keep it.Fixes #5318
Testing
uv run specify --helpuv sync && uv run pytestA
bundled_componentfixture intests/specify_cli/bundles/conftest.pyinstalls a bundle with one extension or one preset at priority 10, andpriority_bundlethen sets that priority to 3 through the CLI.test_command_install.py::test_refresh_preserves_primitive_priority:bundle install --refreshkeeps priority 3, and the bundle record still lists the declared 10.test_command_update.py::test_update_preserves_primitive_priority: the same throughbundle updatefrom a local catalog.test_command_install.py::test_refresh_keeps_a_user_priority_when_the_bundle_priority_changes: with priority 3 set by the user, the same refresh keeps 3.test_command_install.py::test_refresh_keeps_a_user_priority_after_the_bundle_declares_the_same_value: with priority 3 set by the user, a refresh with the bundle declaring 3 and then one declaring 5 both keep 3.test_primitives.py::test_primitive_priority_on_install_and_refresh: both kinds, bundled and catalog sources, install and refresh, with no stored priority, a stored 3, and a malformed stored value.With
primitives.pyreverted tomain, 12 of the 32 new cases fail: the eight CLI cases and the refresh cases with a stored priority.Full suite on Linux, Python 3.13: 13985 passed, 449 skipped, 1 failed (
pytest -n 2, 7 min). The failure,test_version_execution.py::TestWindowsUvToolEnvironment::test_non_windows_uv_tool_dry_run_still_previews_installer, fails the same way onmainhere, as noted on #5308: Rich wraps the dry-run output, and my checkout's venv path is long enough to be split mid-path. Ruff 0.15.0 (ruff check src tests) passes. I haven't run it on Windows.AI Disclosure
AI disclosure: Codex CLI (model: gpt-6.1-sol, reasoning effort xhigh, autonomous, offline sandbox) found the priority reset while comparing bundle commands with the docs, and wrote the first fix and tests. Claude Code (model: claude-opus-5-5, autonomous) moved the fix into a shared helper, made a malformed stored priority fall back to the declared one, tried two ways to let a bundle's new priority through while keeping the user's, then went back to always keeping the stored priority after Copilot found cases both got wrong; it reran the repro with the real CLI on
mainand the branch, ran the full suite and lint, and drafted this description. The commits carryAssisted-by:trailers.