Skip to content

fix(resolver): exclude unintended prereleases from stable version ranges #6

Closed

Description

@showxu

Summary

Version-range resolution in 0.2.1 can select a prerelease at the next major or minor boundary even when the requested range uses only stable versions.

For example, --from 1.0.0 can select 2.0.0-alpha.1 instead of an available 1.x stable release.

Code evidence at b742a99:

  • Sources/Core/ProcessRunner.swift:213–229 constructs the major, minor, and explicit range bounds.
  • Sources/Core/ProcessRunner.swift:251–268 filters only by >= lowerBound and < upperBound.
  • Sources/Core/SourceRequirement.swift:127–152 correctly orders a prerelease before the corresponding stable release, but range eligibility has no separate prerelease policy.

git diff v0.2.0 v0.2.1 shows that PR #2, merged as e0ea185, introduced prerelease-aware ordering without changing the range filter. Previously, 2.0.0-alpha.1 was compared as 2.0.0 and excluded at the upper bound.

Related PR: #2

Impact: an existing stable-range request can begin installing a next-major or next-minor prerelease after upgrading the CLI.

Reproduction

Proposed steps; not executed for this report.

  1. In a fresh temporary directory, create a Git repository containing SKILL.md with valid frontmatter:

    ---
    name: demo
    description: Version range fixture
    ---
  2. Commit the file and create tags 1.0.0, 1.5.0, and 2.0.0-alpha.1. They may all reference the same commit: the selected version alone demonstrates the defect.

  3. Create a separate empty project directory and run:

    skill add <absolute-temporary-source-path> \
      --from 1.0.0 --scope project --agent codex --mode copy
    cat .agent/skills.resolved
  4. Inspect pins[].state.version.

Additional boundary cases:

  • Tags 1.0.0, 1.0.5, 1.1.0-alpha.1 with --up-to-next-minor-from 1.0.0.
  • The same tags with --from 1.0.0 --to 1.1.0.

Use fresh project directories for independent cases.

Expected Behavior

A stable-only range excludes prerelease candidates and selects the highest eligible stable release: 1.5.0 in the major-range example and 1.0.5 in the minor-range examples.

If no eligible stable tag exists, report no matching version rather than silently opting into prereleases.

Keep SemVer comparison correct and preserve exact prerelease selection. Define range membership separately from ordering. Explicit prerelease-range behavior should remain covered and documented.

Completion checks:

  • Cover stable-only major, minor, and explicit ranges with boundary prereleases.
  • Preserve --exact prerelease/build-specific selection and existing explicit prerelease tests.
  • Run swift test.

Actual Behavior

The current comparisons admit 2.0.0-alpha.1 because it is greater than 1.5.0 and less than 2.0.0. The resolver selects it and records it in state.version.

This is a range eligibility regression, not an incorrect SemVer sort order.

Tests/CoreTests/InstallWorkflowTests.swift:374–378 covers an explicitly prerelease range; lines 381–441 cover stable tags. Neither fixture covers stable-only ranges with prerelease candidates.

No duplicate issue was found. PR #2 is related history, not a fix for this regression; issue #4 is unrelated.

Environment

  • skill version: 0.2.1; regression identified by comparison with v0.2.0.
  • Source inspected: b742a99.
  • Swift version: not obtained in the read-only sandbox.
  • OS: macOS 27.0.1 (26A434).
  • Architecture: arm64.
  • Validation: static inspection and Git history comparison; reproduction not executed.

Decision needed

Define the prerelease policy for stable ranges. Proposed: stable ranges exclude prereleases by default; an explicit prerelease request is defined separately. Apply the rule in candidate admission, keeping correct SemVer ordering and exact-version support.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions