Skip to content

fix(bundles): reject non-positive preset and extension priorities in validation - #5012

Merged
mnriem merged 1 commit into
github:mainfrom
yxshee:fix/bundle-reject-nonpositive-priority
Oct 19, 2026
Merged

mnriem merged 1 commit into
github:mainfrom
yxshee:fix/bundle-reject-nonpositive-priority

Conversation

@yxshee

@yxshee yxshee commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

Description

specify bundle validate accepts a bundle whose preset or extension declares priority: 0 (or a negative priority), and specify bundle build packages it. Every specify bundle install of that bundle then fails, because the preset and extension managers refuse a priority below 1 and the bundle primitives pass the manifest priority through unchanged.

# bundle.yml: provides.presets: [{id: lean, version: 1.0.0, priority: 0, strategy: replace}]
$ specify bundle validate --path team-zero --offline
✓ team-zero is well-formed and valid.
exit=0
$ specify bundle install team-zero --offline
Error: Failed to install bundle 'team-zero': Priority must be a positive integer (1 or higher). No changes were recorded.
exit=1

Components install in manifest order, so the error only surfaces after earlier components have been installed and rolled back. With an extension listed before the preset (extensions: [{id: git, version: 1.0.1}]), the failed install on main leaves these behind, despite the "No changes were recorded." message:

.specify/extensions.yml
.specify/extensions/.backup/git/git-config.yml
.specify/extensions/.registry

Root cause: BundleManifest.structural_errors() in bundles/manifest.py only checks that a preset priority is present, not its range.

The fix adds one check there: an extension or preset reference with a priority below 1 is a structural error. validate, build and install therefore refuse the manifest before any component is touched:

$ specify bundle validate --path team-zero --offline
Manifest is invalid:
  - preset 'lean' priority must be 1 or higher, got 0.
exit=1
$ specify bundle install team-zero --offline
... contains an invalid bundle manifest:
  - preset 'lean' priority must be 1 or higher, got 0.
exit=1

A valid bundle still validates. The leftover files from a mid-install rollback are a separate issue that this PR doesn't change; it only stops this manifest from getting that far.

Testing

  • Tested locally with uv run specify --help
  • Ran existing tests with uv sync && uv run pytest
  • Tested with a sample project (if applicable): the transcripts above, on main and on this branch

New tests:

  • tests/contract/test_manifest_schema.py: test_non_positive_priority_is_rejected, for preset 0, preset -3 and extension 0
  • tests/contract/test_manifest_schema.py: test_priority_of_one_is_accepted, for presets and extensions
  • tests/specify_cli/bundles/test_command_validate.py: test_validate_rejects_non_positive_preset_priority
  • tests/specify_cli/bundles/test_command_install.py: test_local_bundle_with_non_positive_priority_is_rejected_before_any_install

On main, the 5 rejection cases fail and the 2 acceptance cases pass. All pass with the change; the three files give 109 passed.

  • tests/contract, tests/specify_cli/bundles, tests/integration, tests/unit: 1440 passed.
  • Full suite (macOS, Python 3.13): 12337 passed, 376 skipped. 11 failures in the tests/test_*_python_parity.py files occur identically on unmodified main on this machine under full-suite load; those files pass when run on their own (257 passed, 112 skipped).
  • uvx ruff@0.15.0 check src tests: clean

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (fill in the disclosure below)

AI disclosure: Claude Code (model: Claude Opus 5.5, max reasoning effort, autonomous agent mode) opened this PR on behalf of @yxshee. A Claude Code subagent (same model, autonomous) found the bug and wrote the fix and tests. The lead agent independently re-ran the new tests against main and the branch, reproduced the transcripts above with the real CLI, reviewed the diff, and wrote this description. No human reviewed the change line by line before it was opened.

🤖 Generated with Claude Code

…validation

`specify bundle validate` reported a manifest whose preset (or extension)
reference declared `priority: 0` or a negative priority as well-formed and
valid, and `specify bundle build` packaged it, yet every install of that
bundle failed: the preset and extension managers refuse a priority below 1,
and the bundle primitives pass the manifest priority through unchanged.
Because components install in manifest order, the error only surfaced after
earlier components (such as extensions) had been installed and rolled back,
which left files like .specify/extensions/.registry behind while the command
reported "No changes were recorded."

BundleManifest.structural_errors() only checked that a preset priority was
present. Also reject a priority below 1 on preset and extension references,
so validate, build and install refuse the manifest before any component is
touched.

Assisted-by: Claude Code (model: Claude Opus 5.5, autonomous)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@yxshee
yxshee requested a review from mnriem as a code owner October 17, 2026 19:14
@mnriem mnriem added the triage-must-have Verdict: high-value, important work for Spec Kit — do first label Oct 18, 2026
@mnriem
mnriem requested a max review from Copilot October 19, 2026 13:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

The focused validation guard matches installer constraints and has appropriate regression coverage, with no unresolved issues identified.

No open issues 🎉

What changed in this PR

Rejects non-positive preset and extension priorities during bundle validation, before component installation begins.

Changes:

  • Adds a shared structural validation check for priorities below 1.
  • Adds rejection, boundary-value, and early-install rejection tests.

Regression evidence is reported in the PR; tests were not rerun here.

File Description
tests/​specify_cli/​bundles/​test_command_validate.py Tests validation failure for priority zero.
tests/​specify_cli/​bundles/​test_command_install.py Checks rejection before installing extensions.
tests/​contract/​test_manifest_schema.py Tests invalid priorities and acceptance of priority one.
src/​specify_cli/​bundles/​manifest.py Rejects preset and extension priorities below one.

Review effort: Max

@mnriem
mnriem merged commit 42247a9 into github:main Oct 19, 2026
16 checks passed
@mnriem

mnriem commented Oct 19, 2026

Copy link
Copy Markdown
Collaborator

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triage-must-have Verdict: high-value, important work for Spec Kit — do first

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants