Closed
#58
Unify commits, snapshots, and blobs into a single object store
0
Anchors
—
Blast radius
—
Churn 30d
0
Proposals
Problem
.muse has three separate content-addressed stores:
.muse/commits/sha256/<id>.msgpack
.muse/snapshots/sha256/<id>.msgpack
.muse/objects/sha256/<prefix>/<id>
This is a historical accident. Commits and snapshots are already sha256 content-addressed, just like blobs. There is no principled reason they live in separate directories with a separate format.
Git does it right: one objects/ store, everything in it, type encoded in the object itself, 2-hex-char path prefix.
Target state
.muse/objects/sha256/
01/c8de44... ← blob
4d/8b40ce... ← snapshot
6a/9cf0e8... ← blob
6f/a10416... ← blob
8d/bb26b7... ← commit
One store. Same lookup path for everything. Type is encoded in the object data, not the directory.
Approach
TDD. Write the tests first:
- Write a commit object → read it back by ID from the unified store
- Write a snapshot object → read it back by ID from the unified store
- Write a blob → read it back by ID (unchanged behavior)
- Mixed read: given only an ID, resolve the correct object regardless of type
- Migration: existing repo with separate commits/ and snapshots/ dirs → migrated to unified store, all IDs resolve correctly
Tests must pass before any implementation changes to the store layout.
Notes
- The format question (msgpack vs custom binary vs JSON) is separate and can be decided during implementation
- The wire format is unaffected — this is on-disk layout only
.muse/commits/and.muse/snapshots/directories should be removed once migration is complete
Activity4
gabriel
25 days ago
Progress update
Done
muse.core.idscreated as the canonical home for all ID derivationhash_blob,hash_snapshot,hash_commitimplemented inids.pywith canonicalhash_*naming conventionDEFAULT_HASH_ALGOandlong_idmoved intoids.py(self-contained, no imports fromtypes.py)- Deprecation comments added to
blob_idintypes.pyandcompute_commit_id/compute_snapshot_idinsnapshot.py tests/test_unified_object_store.pycreated with 3 passing tests:test_write_read_blob— raw bytes stored and retrieved correctlytest_write_read_snapshot— snapshot JSON stored with type+version header, read back correctlytest_write_read_commit— fullCommitRecordfield shape stored as JSON, read back correctly
- All tests use
object_pathandobjects_dirfrommuse.core.object_store— no hardcoded path strings - Fixture chain:
blob_id→snapshot_id→commit_id,snapshot_data,commit_data
Remaining
store.py: updatewrite_commitandwrite_snapshotto write toobjects/sha256/with type+version headerstore.py: updateread_commitandread_snapshotto read fromobjects/sha256/with legacy fallbackgc.py: update reachability walks to scanobjects/sha256/for commits and snapshots- Remove
.muse/commits/and.muse/snapshots/once all repos have migrated
gabriel
25 days ago
Update — Test 4 complete
All 4 tests passing:
test_write_read_blob✅test_write_read_snapshot✅test_write_read_commit✅test_mixed_read_resolves_type✅ — all three objects written to the same store; given only an ID, the type byte correctly identifies each one without any prior knowledge of what was stored
Remaining tests (per issue spec)
- Test 5: migration — existing repo with separate
commits/andsnapshots/dirs resolves all IDs correctly after migration - Test 6: missing object raises
FileNotFoundError - Test 7: on-disk path layout
Remaining implementation
store.py:write_commit/write_snapshotwrite toobjects/sha256/with type+version headerstore.py:read_commit/read_snapshotread fromobjects/sha256/with legacy fallbackgc.py: reachability walks scanobjects/sha256/for commits and snapshots- Remove
.muse/commits/and.muse/snapshots/once all repos migrated
gabriel
20 days ago
All deliverables complete and verified:
- Unified object store implemented in
muse/core/object_store.py— one store, Git-style<type> <len>\0<payload>format commits.py::write_commitandsnapshots.py::write_snapshotboth write to.muse/objects/sha256/commit_pathandsnapshot_pathboth route to the unified store viaobject_path()gc.pyreachability walk covers all three types (blob, commit, snapshot) in the unified store- Migration tooling in
muse/core/migrate.pyhandles repos with legacy.muse/commits/and.muse/snapshots/dirs - 23 tests passing:
test_unified_object_store.py(13) +test_migrate_object_store.py(10) - Dead imports of
snapshots_dir/commits_dirremoved from gc.py, snapshot_cmd.py, snapshot_diff.py, verify.py - All docstrings, CLI help text, and docs updated to reference
.muse/objects/sha256/ - Stale test names renamed to reflect unified store
Closing.
Unified object format
Every object in
.muse/objects/sha256/<prefix>/<id>uses this layout:Type registry
Rules