fix: create_repo seeds invalid genesis commit; commit_files_to_repo's commit_id not client-verifiable (musehub#220)
Audit (Part 1, as reported): create_repo(initialize=True) hand-rolled a commit_id with no snapshot_id and no MusehubSnapshot row -- structurally invalid the moment any client tried to clone it ("apply_mpack: malformed commit -- snapshot_id must be a non-empty str"). Push's divergence check, comparing local history against this phantom remote tip, correctly reported a divergence and demanded --force -- every first push this season needed it because of this.
Investigation found a second, bigger bug while building the fix: reusing commit_files_to_repo (the natural way to create a correct empty commit) surfaced that its own commit_id computation -- a hand-rolled hash seeded from repo_id/branch/snapshot_id/message/timestamp -- does not match what a real client recomputes via hash_commit() on clone/fetch (muse/core/commits.py::_verify_commit_id, called on every write_commit, including clone/pull). Confirmed computationally: identical field values produce different hashes. commit_files_to_repo is shared by org creation, org membership changes, and identity-repo creation at registration -- every commit ever created through it would fail content-hash verification the moment any real client tried to store it locally.
Design decision (confirmed via AskUserQuestion): fix commit_files_to_repo's root cause rather than hand-rolling a separately-correct commit for create_repo only -- reusing the still-broken function would just inherit the bug, and the broader issue is real and already live on staging.
Fix: - commit_files_to_repo now computes commit_id via muse.core.ids.hash_commit (the canonical, client-verifiable formula), not a hand-rolled hash. - create_repo(initialize=True) now calls commit_files_to_repo with an empty files dict instead of hand-rolling a commit with no snapshot -- produces a correct, materializable empty commit with a real MusehubSnapshot row.
TDD: wrote tests/test_repo_init_commit_cloneable.py first (5 tests) -- non-empty snapshot_id, snapshot_id resolves to a real MusehubSnapshot row, commit_id matches what _verify_commit_id's real recomputation would produce (reproduces the actual client-side check), commit_files_to_repo's own commit_id passes the same check independent of create_repo, and initialize=False still creates zero commits. Confirmed genuine RED via muse-dev shelf save/pop isolation on both files.
Regression: 217 passed across repo-creation/identity/org/membership test files -- no regressions in any flow that uses commit_files_to_repo.
Verified live end-to-end against a local MuseHub instance, reproducing the ticket's exact repro steps: muse init + commit + `muse hub repo create` (no --initialize, new CLI default -- muse-side companion fix) + `muse push local main` succeeded with no --force needed and no divergence error; separately, `muse hub repo create --initialize` + `muse clone` on the empty seeded repo succeeded cleanly (1 commit, 0 blobs, no malformed-commit warnings).
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Semantic Changes
25 symbols
Files Changed
+1
~2
1108 in snapshot
0 comments
muse hub commit comment sha256:5dbc6b75b9add84f8812f9f390fbd5b47fcf9e22947b2cf86ae54146c99c9df8 --body "your comment"
No comments yet. Be the first to start the discussion.