fix: compare_version handles pre-release suffixes (closes #98)#113
Merged
Conversation
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
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>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Fixes the cosmetic correctness bug in
meld-core/src/merger.rs::compare_versionreported 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 resultcompare_version("0.2.99-rc1", "0.2.0")returnedOrdering::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):
+...) is stripped before comparison.MAJOR.MINOR.PATCHtriple is compared numerically; missing trailing segments default to0("0.2"=="0.2.0").0.2.0-rc1 < 0.2.0).The function signature
(a: &str, b: &str) -> std::cmp::Orderingis 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 issuetest_compare_version_prerelease_below_release—0.2.0-rc1 < 0.2.0test_compare_version_prerelease_ordering— alpha < beta, rc1 < rc2, numeric < alphanumeric, longer pre-release winstest_compare_version_build_metadata_ignored—+metadoes 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 droppedtest_compare_version_large_numbers—0.0.10 > 0.0.9(numeric, not lexical)Verified locally:
cargo fmt --checkcleancargo clippy --package meld-core --all-targetscleancargo test --releasepasses (incl. the 73-testwit_bindgen_runtimesuite, 30 merger unit tests)Closes #98.
🤖 Generated with Claude Code