gabriel / muse public
feat patch task/patch-id #1 / 1
gabriel · 167 days ago · Apr 14, 2026 · Diff

feat: implement muse patch-id — content-based commit identity

- _compute_patch_id: SHA-256 of sorted-file unified diff content lines (+/- only, no @@ or file headers); --stable strips trailing whitespace so cosmetic differences don't produce new patch-ids - _resolve_commit: resolves HEAD, branch names, and commit IDs to CommitRecord - run: resolves commit → loads parent manifest → computes patch-id → text output '<patch_id> <commit_id>' or JSON with subject line - ANSI/control-char rejection in ref argument - 16 tests: unit (same diff = same id, different = different, whitespace normalization, deterministic empty diff), integration (JSON schema, text format, specific commit, branch ref, error cases), security (ANSI rejected), stress (10 distinct diffs produce 10 distinct patch-ids)

sha256:df9844bc6776600449ef2e14666547d4c1ff1f8fcf0e2d4b2543a6bf13fafae3 sha
+64 ~28 symbols
sha256:5e3e3fa66b1e16a6e86b9ac88be71e30ab2ac739ff0945537d8adcf26bf4742a snapshot
+64
symbols added
~28
symbols modified
0
dead code introduced
Semantic Changes 92 symbols
~ muse/cli/commands/patch_id.py .py 24 symbols added
+ _compute_patch_id function function _compute_patch_id L81–144
+ _resolve_commit function function _resolve_commit L147–191
+ ExitCode import import ExitCode L60–60
+ Manifest import import Manifest L71–71
+ _json import import _json L55–55
+ annotations import import annotations L50–50
+ argparse import import argparse L52–52
+ difflib import import difflib L53–53
+ get_head_commit_id import import get_head_commit_id L63–63
+ hashlib import import hashlib L54–54
+ logging import import logging L56–56
+ pathlib import import pathlib L57–57
+ read_commit import import read_commit L63–63
+ read_current_branch import import read_current_branch L63–63
+ read_object import import read_object L61–61
+ read_repo_id import import read_repo_id L62–62
+ read_snapshot import import read_snapshot L63–63
+ require_repo import import require_repo L62–62
+ resolve_commit_ref import import resolve_commit_ref L63–63
+ sanitize_display import import sanitize_display L70–70
+ sys import import sys L58–58
+ logger variable variable logger L73–73
+ register function function register L199–231
+ run function function run L239–289
~ tests/test_cmd_patch_id.py .py 39 symbols added
+ _REPO_ID variable variable _REPO_ID L31–31
+ _commit_files function function _commit_files L59–96
+ _counter variable variable _counter L32–32
+ _env function function _env L55–56
+ _init_repo function function _init_repo L44–52
+ _invoke function function _invoke L99–101
+ _sha function function _sha L40–41
+ CliRunner import import CliRunner L23–23
+ CommitRecord import import CommitRecord L26–26
+ Manifest import import Manifest L27–27
+ SnapshotRecord import import SnapshotRecord L26–26
+ annotations import import annotations L14–14
+ compute_commit_id import import compute_commit_id L25–25
+ compute_snapshot_id import import compute_snapshot_id L25–25
+ datetime import import datetime L16–16
+ hashlib import import hashlib L17–17
+ json import import json L18–18
+ pathlib import import pathlib L19–19
+ pytest import import pytest L21–21
+ write_commit import import write_commit L26–26
+ write_object import import write_object L24–24
+ write_snapshot import import write_snapshot L26–26
+ runner variable variable runner L29–29
+ test_compute_patch_id_different_diff_different_id function function test_compute_patch_id_different_diff_different_id L120–131
+ test_compute_patch_id_empty_diff_is_deterministic function function test_compute_patch_id_empty_diff_is_deterministic L134–142
+ test_compute_patch_id_same_diff_same_id function function test_compute_patch_id_same_diff_same_id L109–117
+ test_compute_patch_id_stable_normalizes_whitespace function function test_compute_patch_id_stable_normalizes_whitespace L145–160
+ test_compute_patch_id_without_stable_is_sensitive_to_whitespace function function test_compute_patch_id_without_stable_is_sensitive_to_whitespace L163–177
+ test_patch_id_ansi_in_ref_rejected function function test_patch_id_ansi_in_ref_rejected L303–307
+ test_patch_id_branch_name_ref function function test_patch_id_branch_name_ref L271–277
+ test_patch_id_different_commits_have_different_ids function function test_patch_id_different_commits_have_different_ids L315–330
+ test_patch_id_empty_repo_exits_nonzero function function test_patch_id_empty_repo_exits_nonzero L292–295
+ test_patch_id_json_commit_id_matches_head function function test_patch_id_json_commit_id_matches_head L207–214
+ test_patch_id_json_schema_keys function function test_patch_id_json_schema_keys L185–195
+ test_patch_id_json_subject_is_commit_message function function test_patch_id_json_subject_is_commit_message L198–204
+ test_patch_id_nonexistent_ref_exits_nonzero function function test_patch_id_nonexistent_ref_exits_nonzero L285–289
+ test_patch_id_same_diff_same_id_across_commits function function test_patch_id_same_diff_same_id_across_commits L241–253
+ test_patch_id_specific_commit_id function function test_patch_id_specific_commit_id L261–268
+ test_patch_id_text_output_has_two_parts function function test_patch_id_text_output_has_two_parts L222–233
← Older Oldest on task/patch-id
All commits
Newer → Latest on task/patch-id

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