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

feat: implement muse range-diff — compare two versions of a commit series

- Walk both commit ranges (base..old, base..new) using exclude-set BFS - Compute patch-ids in parallel via ThreadPoolExecutor (reuses patch-id algorithm from patch_id.py) - Pair series: exact patch-id match → equivalent; positional fallback → changed; leftovers → dropped/added - --creation-factor controls fuzzy pairing aggressiveness (0.0 = exact only, 1.0 = all positional) - --stable strips trailing whitespace before hashing - JSON output: {pairs, trivially_equivalent, old_range, new_range}; each pair has {old, new, status} - Text output: =equiv !changed <dropped >added sigils - Exit 0 iff trivially_equivalent; exit 1 on any diff; exit 2 on bad refs/ANSI - 24 tests: range parsing, pairing logic, JSON schema, text output, creation-factor, error cases, ANSI rejection, 50-commit stress

sha256:3901a2aacd1ddbab847e38d54e4439a3e1b5acf2949e4de1b7c3d4eadcf445a0 sha
+84 ~112 symbols
sha256:402ffccce16dbe4ab1096eb6d6627227a14094fd6e68938f13a60c497244b719 snapshot
+84
symbols added
~112
symbols modified
0
dead code introduced
Semantic Changes 196 symbols
~ muse/cli/commands/range_diff.py .py 35 symbols added
+ _SAFE_RANGE_RE variable variable _SAFE_RANGE_RE L94–94
+ _SAFE_REF_RE variable variable _SAFE_REF_RE L92–92
+ _commit_info function function _commit_info L274–283
+ _compute_patch_id function function _compute_patch_id L205–251
+ _exclude_set function function _exclude_set L149–167
+ _pair_series function function _pair_series L291–379
+ _parse_range function function _parse_range L102–111
+ _patch_id_for_commit function function _patch_id_for_commit L254–271
+ _print_text function function _print_text L531–554
+ _resolve_ref function function _resolve_ref L119–141
+ _walk_range function function _walk_range L170–197
+ Any import import Any L75–75
+ ExitCode import import ExitCode L77–77
+ Manifest import import Manifest L86–86
+ ThreadPoolExecutor import import ThreadPoolExecutor L74–74
+ _json import import _json L68–68
+ annotations import import annotations L64–64
+ argparse import import argparse L66–66
+ as_completed import import as_completed L74–74
+ deque import import deque L73–73
+ get_head_commit_id import import get_head_commit_id L80–80
+ hashlib import import hashlib L67–67
+ logging import import logging L69–69
+ pathlib import import pathlib L70–70
+ re import import re L71–71
+ read_commit import import read_commit L80–80
+ read_current_branch import import read_current_branch L80–80
+ read_object import import read_object L78–78
+ read_snapshot import import read_snapshot L80–80
+ require_repo import import require_repo L79–79
+ sanitize_display import import sanitize_display L87–87
+ sys import import sys L72–72
+ logger variable variable logger L89–89
+ register function function register L387–429
+ run function function run L437–528
~ tests/test_cmd_range_diff.py .py 48 symbols added
+ _REPO_ID variable variable _REPO_ID L32–32
+ _commit function function _commit L72–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
+ _sha function function _sha L41–42
+ _write_files function function _write_files L60–69
+ 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 L15–15
+ compute_commit_id import import compute_commit_id L26–26
+ compute_snapshot_id import import compute_snapshot_id L26–26
+ datetime import import datetime L17–17
+ hashlib import import hashlib L18–18
+ json import import json L19–19
+ pathlib import import pathlib L20–20
+ pytest import import pytest L22–22
+ 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_ansi_in_new_range_rejected function function test_ansi_in_new_range_rejected L370–373
+ test_ansi_in_old_range_rejected function function test_ansi_in_old_range_rejected L364–367
+ test_both_empty_trivially_equivalent function function test_both_empty_trivially_equivalent L219–226
+ test_commit_added function function test_commit_ L184–196
+ test_commit_dropped function function test_commit_dropped L169–181
+ test_creation_factor_one_all_positionally_paired function function test_creation_factor_one_all_positionally_paired L311–319
+ test_creation_factor_zero_no_fuzzy_pairing function function test_creation_factor_zero_no_fuzzy_pairing L297–308
+ test_empty_new_series_all_dropped function function test_empty_new_series_all_dropped L209–216
+ test_empty_old_series_all_added function function test_empty_old_series_all_ L199–206
+ test_exit_nonzero_on_differences function function test_exit_nonzero_on_differences L350–356
+ test_exit_zero_on_trivially_equivalent function function test_exit_zero_on_trivially_equivalent L341–347
+ test_identical_series_all_equivalent function function test_identical_series_all_equivalent L136–151
+ test_json_pair_commit_info function function test_json_pair_commit_info L252–264
+ test_json_schema_all_fields function function test_json_schema_all_fields L234–249
+ test_nonexistent_new_ref_exits_nonzero function function test_nonexistent_new_ref_exits_nonzero L334–338
+ test_nonexistent_old_ref_exits_nonzero function function test_nonexistent_old_ref_exits_nonzero L327–331
+ test_parse_range_no_dotdot function function test_parse_range_no_dotdot L117–121
+ test_parse_range_preserves_whitespace_stripped function function test_parse_range_preserves_whitespace_stripped L124–128
+ test_parse_range_with_dotdot function function test_parse_range_with_dotdot L110–114
+ test_single_commit_changed function function test_single_commit_changed L154–166
+ test_stress_50_commits_mixed function function test_stress_50_commits_mixed L398–422
+ test_stress_50_commits_trivially_equivalent function function test_stress_50_commits_trivially_equivalent L381–395
+ test_text_output_shows_changed function function test_text_output_shows_changed L282–289
+ test_text_output_shows_equivalent function function test_text_output_shows_equivalent L272–279
← Older Oldest on task/range-diff
All commits
Newer → Latest on task/range-diff

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:3901a2aacd1ddbab847e38d54e4439a3e1b5acf2949e4de1b7c3d4eadcf445a0 --body "your comment"