Skip to content

fix: compare_version handles pre-release suffixes (closes #98)#113

Merged
avrabe merged 1 commit into
mainfrom
fix/issue-98-compare-version
Apr 28, 2026
Merged

fix: compare_version handles pre-release suffixes (closes #98)#113
avrabe merged 1 commit into
mainfrom
fix/issue-98-compare-version

Conversation

@avrabe
Copy link
Copy Markdown
Contributor

@avrabe avrabe commented Apr 28, 2026

Summary

Fixes the cosmetic correctness bug in meld-core/src/merger.rs::compare_version reported in #98.

The previous implementation parsed each dot segment with filter_map(parse::<u32>), which silently dropped any segment containing non-numeric characters. As a result compare_version("0.2.99-rc1", "0.2.0") returned Ordering::Less — the "99-rc1" segment was discarded, leaving [0, 2] vs [0, 2, 0].

This PR replaces the body with a small inline implementation of the relevant subset of semver 2.0.0 precedence rules (no new dependency, ~70 LOC):

  • Build metadata (+...) is stripped before comparison.
  • The MAJOR.MINOR.PATCH triple is compared numerically; missing trailing segments default to 0 ("0.2" == "0.2.0").
  • A version with a pre-release suffix sorts below the same version without one (0.2.0-rc1 < 0.2.0).
  • Pre-release identifiers are compared dot-segment-wise: numeric ids numerically, alphanumerics lexically, numeric ids below alphanumerics (semver §11.4.3).
  • Non-numeric main segments fall back to a lexical compare of that segment instead of being silently dropped.

The function signature (a: &str, b: &str) -> std::cmp::Ordering is unchanged.

Test plan

Eight new unit tests in meld-core/src/merger.rs:

  • test_compare_version — pure numeric triples (existing coverage)
  • test_compare_version_prerelease_regression_issue_98 — the exact reproducer from the issue
  • test_compare_version_prerelease_below_release0.2.0-rc1 < 0.2.0
  • test_compare_version_prerelease_ordering — alpha < beta, rc1 < rc2, numeric < alphanumeric, longer pre-release wins
  • test_compare_version_build_metadata_ignored+meta does not affect precedence (with or without pre-release)
  • test_compare_version_missing_segments"0.2" == "0.2.0", "1" == "1.0.0"
  • test_compare_version_mixed_alphanumeric — non-numeric main segments are no longer silently dropped
  • test_compare_version_large_numbers0.0.10 > 0.0.9 (numeric, not lexical)

Verified locally:

  • cargo fmt --check clean
  • cargo clippy --package meld-core --all-targets clean
  • cargo test --release passes (incl. the 73-test wit_bindgen_runtime suite, 30 merger unit tests)
  • Pre-commit hook chain (fmt + clippy + test) passes

Closes #98.

🤖 Generated with Claude Code

Previously `compare_version` parsed each dot segment with
`filter_map(parse::<u32>)`, which silently dropped any segment containing
non-numeric characters. As a result `compare_version("0.2.99-rc1", "0.2.0")`
returned `Ordering::Less` because the "99-rc1" segment was discarded,
leaving `[0, 2]` to compare against `[0, 2, 0]`.

Replace with a small inline implementation of the relevant subset of
semver 2.0.0 precedence rules (no new dependency):

* Build metadata (`+...`) is stripped before comparison.
* The MAJOR.MINOR.PATCH triple is compared numerically; missing trailing
  segments default to 0 so `"0.2"` == `"0.2.0"`.
* A version with a pre-release suffix sorts below the same version
  without one (`0.2.0-rc1 < 0.2.0`).
* Pre-release identifiers are compared dot-segment-wise: numeric
  identifiers numerically, alphanumerics lexically, and numeric ids sort
  below alphanumeric ones (semver §11.4.3).
* Non-numeric main segments fall back to a lexical compare of that
  segment instead of being silently dropped.

Eight test cases cover the issue-98 regression, pre-release ordering
both vs release and vs other pre-releases, build metadata, missing
segments, mixed alphanumeric, and large numeric segments that would
mis-order under a naive lexical comparison.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@avrabe avrabe marked this pull request as ready for review April 28, 2026 17:47
@avrabe avrabe merged commit c895a7b into main Apr 28, 2026
4 checks passed
@avrabe avrabe deleted the fix/issue-98-compare-version branch April 28, 2026 17:48
avrabe added a commit that referenced this pull request Apr 29, 2026
V&V-hardening minor release. Closes 5 issues:

- #98 — semver-correct compare_version (PR #113)
- #99 — resource-import fallback name-keyed, sentinel eliminated (PR #115)
- #102 — Kani + proptest harnesses for parser/merger/resolver (PR #116)
- #104 — cargo-fuzz scaffolding with 4 targets (PR #114)
- #112 — Mythos v0.4 follow-up: items 4, 5, 6 confirmed and fixed (PR #117)

New approved STPA loss scenarios: LS-R-10, LS-CP-3.

Pre-release Mythos delta pass (tier-5 + tier-4 changed since v0.3.0):
merger.rs and resolver.rs scanned; **no confirmed findings**.

The cargo-fuzz scaffolding immediately surfaced a real parser panic on
truncated component-section input — tracked as #118 for v0.4.1 / v0.5.

Co-authored-by: Claude Opus 4.7 (1M context) <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.

Cosmetic: compare_version drops pre-release suffixes

1 participant