gabriel / muse public
feat patch task/prune #1 / 1
gabriel · 166 days ago · Apr 14, 2026 · Diff

feat: implement muse prune — surgical removal of unreachable objects

- _collect_all_reachable_ids: delegates to gc._collect_reachable_objects (conservative walk: all snapshot manifests on disk + stash.json entries) - _find_prune_candidates: scandir-based walk of .muse/objects/; excludes reachable IDs; filters by mtime when --expire SECONDS is given - run: refuses mid-merge; computes reachable set; finds candidates; --dry-run reports without deleting; live run uses os.unlink with missing_ok semantics for concurrent-prune safety - JSON schema: pruned, bytes_freed, dry_run; candidates list in dry-run - Safety: only deletes under .muse/objects/; never touches working tree, commits, snapshots, or stash; merge-in-progress guard - 18 tests: unit (reachable collection, candidate finding, expire filter for recent and old objects), integration (dry-run idempotent, JSON schema, pruned count, keeps reachable, empty repo, no orphans), security (commits and snapshots untouched), stress (200 objects with 50% orphaned)

sha256:21acafd51794b3181aa9489e0b5c015ba9c9294309f09b65ed5054ed2b339504 sha
+62 ~111 symbols
sha256:9816791cd09c73ae886aa1a2bfe5f90f153b51b34e3bb03b3e714034804aed7d snapshot
+62
symbols added
~111
symbols modified
0
dead code introduced
Semantic Changes 173 symbols
~ muse/cli/commands/prune.py .py 17 symbols added
+ _collect_all_reachable_ids function function _collect_all_reachable_ids L81–94
+ _find_prune_candidates function function _find_prune_candidates L97–152
+ ExitCode import import ExitCode L68–68
+ _collect_reachable_objects import import _collect_reachable_objects L69–69
+ _json import import _json L61–61
+ annotations import import annotations L58–58
+ argparse import import argparse L60–60
+ logging import import logging L62–62
+ objects_dir import import objects_dir L70–70
+ os import import os L63–63
+ pathlib import import pathlib L64–64
+ require_repo import import require_repo L71–71
+ sys import import sys L65–65
+ time import import time L66–66
+ logger variable variable logger L73–73
+ register function function register L160–196
+ run function function run L204–288
~ tests/test_cmd_prune.py .py 44 symbols added
+ _REPO_ID variable variable _REPO_ID L32–32
+ _commit_files function function _commit_files L60–97
+ _counter variable variable _counter L33–33
+ _env function function _env L56–57
+ _init_repo function function _init_repo L45–53
+ _invoke function function _invoke L100–102
+ _object_count function function _object_count L105–114
+ _sha function function _sha L41–42
+ CliRunner import import CliRunner L24–24
+ CommitRecord import import CommitRecord L27–27
+ Manifest import import Manifest L28–28
+ SnapshotRecord import import SnapshotRecord L27–27
+ annotations import import annotations L14–14
+ compute_commit_id import import compute_commit_id L26–26
+ compute_snapshot_id import import compute_snapshot_id L26–26
+ datetime import import datetime L16–16
+ has_object import import has_object L25–25
+ hashlib import import hashlib L17–17
+ json import import json L18–18
+ pathlib import import pathlib L19–19
+ pytest import import pytest L22–22
+ time import import time L20–20
+ write_commit import import write_commit L27–27
+ write_object import import write_object L25–25
+ write_snapshot import import write_snapshot L27–27
+ runner variable variable runner L30–30
+ test_collect_all_reachable_ids_after_commit function function test_collect_all_reachable_ids_after_commit L129–135
+ test_collect_all_reachable_ids_empty_repo function function test_collect_all_reachable_ids_empty_repo L122–126
+ test_collect_all_reachable_ids_excludes_orphan function function test_collect_all_reachable_ids_excludes_orphan L138–146
+ test_find_prune_candidates_excludes_reachable function function test_find_prune_candidates_excludes_reachable L167–174
+ test_find_prune_candidates_expire_before_filters_recent function function test_find_prune_candidates_expire_before_filters_recent L177–188
+ test_find_prune_candidates_expire_old_objects function function test_find_prune_candidates_expire_old_objects L191–209
+ test_find_prune_candidates_returns_orphan function function test_find_prune_candidates_returns_orphan L154–164
+ test_prune_50_percent_unreachable function function test_prune_50_percent_unreachable L344–357
+ test_prune_does_not_touch_commits_or_snapshots function function test_prune_does_not_touch_commits_or_snapshots L326–336
+ test_prune_dry_run_does_not_delete_objects function function test_prune_dry_run_does_not_delete_objects L217–227
+ test_prune_dry_run_json_lists_candidates function function test_prune_dry_run_json_lists_candidates L230–242
+ test_prune_dry_run_text_mentions_candidates function function test_prune_dry_run_text_mentions_candidates L245–251
+ test_prune_empty_repo_exits_zero function function test_prune_empty_repo_exits_zero L304–309
+ test_prune_json_pruned_count function function test_prune_json_pruned_count L294–301
+ test_prune_json_schema function function test_prune_json_schema L281–291
+ test_prune_keeps_reachable_objects function function test_prune_keeps_reachable_objects L271–278
+ test_prune_no_orphans_exits_zero function function test_prune_no_orphans_exits_zero L312–318
+ test_prune_removes_unreachable_objects function function test_prune_removes_unreachable_objects L259–268
← Older Oldest on task/prune
All commits
Newer → Latest on task/prune

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:21acafd51794b3181aa9489e0b5c015ba9c9294309f09b65ed5054ed2b339504 --body "your comment"