gabriel / musehub public
feat patch fix/release-prune-pep440-sort #3 / 4
AI Agent gabriel · 11 days ago · Jul 7, 2026 · Diff

feat: prune_releases.py -- PEP 440-aware release pruning (issue #128, Phase 1)

Replaces sort -V's lexical comparison with packaging.version.Version for deciding which release tarballs to keep during publish cleanup.

Found and corrected a real error in issue #128's own plan during TDD: the plan's stated exit gate expected 0.2.0.dev1 to survive pruning ahead of 0.2.0rc14-16, but PEP 440 correctly ranks dev as the lowest-precedence pre-release stage for a shared base version -- 0.2.0.dev1 < 0.2.0rc16 is right, not a bug. The actual root cause is that the channel pivot reused the base version 0.2.0 for the new nightly instead of bumping it. Added a docs/versioning.md rule: a channel pivot must bump the base version. stale_releases() itself needed no behavior change -- only the plan's narrative and its test expectations did.

PRUNE_01-07 all green; PRUNE_01b specifically confirms the corrected fix (bumped base version) produces the originally-intended outcome.

sha256:d21dd1eafdd88cdcde0f9d636e3dedff5ce7ac43a63bc74d5d336410e7cdc7de sha
+23 ~3 symbols
sha256:28457d98882aeaa2d940270b37a3af0a8b3c691d152fa5b1bedc62f6f7186d89 snapshot
+23
symbols added
~3
symbols modified
0
dead code introduced
Semantic Changes 26 symbols
~ deploy/prune_releases.py .py 9 symbols added
+ _FILENAME_RE variable variable _FILENAME_RE L24–24
+ InvalidVersion import import InvalidVersion L22–22
+ Version import import Version L22–22
+ annotations import import annotations L16–16
+ argparse import import argparse L18–18
+ re import import re L19–19
+ sys import import sys L20–20
+ main function function main L77–91
+ stale_releases function function stale_releases L27–74
~ tests/test_prune_releases.py .py 13 symbols added
+ TestStaleReleases class class TestStaleReleases L22–115
+ test_PRUNE_01_same_base_version_dev_is_lowest_precedence_not_newest method method test_PRUNE_01_same_base_version_dev_is_lowest_precedence_not_newest L23–45
+ test_PRUNE_01b_pivot_with_bumped_version_keeps_new_nightly method method test_PRUNE_01b_pivot_with_bumped_version_keeps_new_nightly L47–61
+ test_PRUNE_02_mixed_channels_full_precedence_coverage method method test_PRUNE_02_mixed_channels_full_precedence_coverage L63–77
+ test_PRUNE_03_keep_greater_than_len_prunes_nothing method method test_PRUNE_03_keep_greater_than_len_prunes_nothing L79–81
+ test_PRUNE_03b_keep_equal_to_len_prunes_nothing method method test_PRUNE_03b_keep_equal_to_len_prunes_nothing L83–85
+ test_PRUNE_04_unparseable_filename_raises method method test_PRUNE_04_unparseable_filename_raises L87–90
+ test_PRUNE_05_stable_sorts_after_all_prerelease_channels method method test_PRUNE_05_stable_sorts_after_all_prerelease_channels L92–100
+ test_PRUNE_06_empty_filename_list_returns_empty method method test_PRUNE_06_empty_filename_list_returns_empty L102–103
+ test_PRUNE_07_returns_oldest_first_stable_ordering method method test_PRUNE_07_returns_oldest_first_stable_ordering L105–115
+ annotations import import annotations L15–15
+ pytest import import pytest L17–17
+ stale_releases import import stale_releases L19–19
~ docs/versioning.md .md 1 symbol added, 3 symbols modified

0 comments

No comments yet. Be the first to start the discussion.

To add a comment, use the Muse CLI: muse hub commit comment sha256:d21dd1eafdd88cdcde0f9d636e3dedff5ce7ac43a63bc74d5d336410e7cdc7de --body "your comment"