gabriel / muse public
feat muse#83 feat/snapshot-content-id-migration #3 / 4
AI Agent gabriel · 10 days ago · Jul 7, 2026 · Diff

feat(muse#83): Phase 2 -- migrate_commit_ids_cascade with mandatory resign

Cascades a Phase 1 snapshot-ID correction through the commit DAG: any commit whose own snapshot_id changed, or whose parent's commit_id changed (transitively, in topological order), gets a new commit_id and is re-signed with the current signing identity. Everything outside that blast radius is left byte-identical.

This closes the one real gap found in reusing muse.core.migrate's existing migrate_commit_ids as-is: that function recomputes commit_id but never touches signature/signer_public_key, which would leave every rewritten commit's authenticity silently broken (signature covering a superseded commit_id).

6 tests, all green, against the A -> B(bad snapshot) -> C -> D fixture chain from the plan doc: cascade correctly rewrites B/C/D and spares A (CC_01), new parent pointers actually thread through rather than being independently rewritten in isolation (CC_02), every rewritten commit's new signature verifies against its new commit_id (CC_03), an unrelated sibling commit is provably byte-identical (CC_04), dry-run writes nothing (CC_05), running twice is deterministic given the non-destructive invariant (CC_06).

sha256:7e75b3b116bea8aed979cdcde23ebeb677b11aff24d2986e654ec0e51ec914af sha
+30 symbols
sha256:1bc44ba5d9be0fe21d5171a65b6d236ca1807b9f3b634e43aa9075de21618e66 snapshot
+30
symbols added
0
dead code introduced
Semantic Changes 30 symbols
+ _AT_ISO variable variable _AT_ISO L35–35
+ _build_chain function function _build_chain L107–141
+ _make_identity function function _make_identity L49–50
+ _read_unified_commit function function _read_unified_commit L95–99
+ _sign function function _sign L53–55
+ _write_unified_commit function function _write_unified_commit L58–92
+ Ed25519PrivateKey import import Ed25519PrivateKey L20–20
+ SigningIdentity import import SigningIdentity L32–32
+ annotations import import annotations L13–13
+ datetime import import datetime L15–15
+ decode_pubkey import import decode_pubkey L33–33
+ encode_public_key import import encode_public_key L25–25
+ hash_commit import import hash_commit L22–22
+ hash_snapshot import import hash_snapshot L22–22
+ json import import json L16–16
+ migrate_commit_ids_cascade import import migrate_commit_ids_cascade L31–31
+ object_path import import object_path L23–23
+ objects_dir import import objects_dir L24–24
+ pathlib import import pathlib L17–17
+ provenance_payload import import provenance_payload L25–25
+ pytest import import pytest L19–19
+ sign_commit_ed25519 import import sign_commit_ed25519 L25–25
+ verify_commit_ed25519 import import verify_commit_ed25519 L25–25
+ repo function function repo L44–46
+ test_cc_01_cascade_rewrites_descendants_and_spares_ancestor function function test_cc_01_cascade_rewrites_descendants_and_spares_ancestor L149–165
+ test_cc_02_cascade_threads_new_parent_ids_through function function test_cc_02_cascade_threads_new_parent_ids_through L175–194
+ test_cc_03_rewritten_commits_are_resigned_and_verify function function test_cc_03_rewritten_commits_are_resigned_and_verify L203–229
+ test_cc_04_unrelated_sibling_commit_is_byte_identical function function test_cc_04_unrelated_sibling_commit_is_byte_identical L237–254
+ test_cc_05_dry_run_writes_nothing function function test_cc_05_dry_run_writes_nothing L262–271
+ test_cc_06_running_twice_is_deterministic function function test_cc_06_running_twice_is_deterministic L285–295

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