gabriel / musehub public
feat BREAKING dev
AI Agent gabriel · 144 days ago · May 1, 2026 · Diff

feat: Phase 5 — pack file support + GC for per-repo object store

- musehub/storage/pack.py: new module with pack_loose_objects, read_packed_object, and gc_packs - pack format: msgpack dict (.pack) + sorted list index (.idx), content- addressed by SHA-256 of sorted object IDs (idempotent) - LocalBackend.get/exists fall through to read_packed_object when loose path is absent; loose takes precedence on hot path - 21 new tests in 7 tiers: creation, read, backend fallthrough, idempotency, GC, result counts, full round-trip

sha256:1d60649537848875b1d90134650925620fe4b15d2e6fa482f136e2c93f9481e9 sha
+52 ~3 symbols
sha256:4364fd501c7a96c85e57b83cbb9c55ee071a998c5ec4f1fbb77ee3add725bf73 snapshot
+52
symbols added
~3
symbols modified
0
dead code introduced
Semantic Changes 55 symbols
~ musehub/storage/pack.py .py 13 symbols added
+ GCPackResult class class GCPackResult L34–35
+ PackResult class class PackResult L28–30
+ _loose_objects function function _loose_objects L42–56
+ _pack_dir function function _pack_dir L38–39
+ _pack_hash function function _pack_hash L59–63
+ gc_packs function function gc_packs L123–155
+ Path import import Path L22–22
+ annotations import import annotations L18–18
+ dataclass class import dataclass L21–21
+ hashlib import import hashlib L20–20
+ msgpack import import msgpack L24–24
+ pack_loose_objects function function pack_loose_objects L66–104
+ read_packed_object function function read_packed_object L107–120
~ tests/test_pack_files.py .py 39 symbols added
+ TestGCPacks class class TestGCPacks L300–354
+ test_gc_keeps_pack_with_unique_objects method method test_gc_keeps_pack_with_unique_objects L323–343
+ test_gc_noop_with_single_pack method method test_gc_noop_with_single_pack L345–354
+ test_gc_removes_pack_superseded_by_newer_pack method method test_gc_removes_pack_superseded_by_newer_pack L301–321
+ TestLocalBackendPackFallthrough class class TestLocalBackendPackFallthrough L186–256
+ test_exists_returns_true_for_packed_object method async_method test_exists_returns_true_for_packed_object L207–222
+ test_get_finds_object_in_pack_after_loose_removed method async_method test_get_finds_object_in_pack_after_loose_ L188–204
+ test_get_returns_none_when_not_loose_or_packed method async_method test_get_returns_none_when_not_loose_or_packed L225–232
+ test_loose_object_takes_precedence_over_pack method async_method test_loose_object_takes_precedence_over_pack L235–256
+ TestPackCreatesFiles class class TestPackCreatesFiles L62–112
+ test_creates_pack_and_index_files method method test_creates_pack_and_index_files L75–89
+ test_creates_pack_dir method method test_creates_pack_dir L63–73
+ test_noop_when_no_loose_objects method method test_noop_when_no_loose_objects L91–98
+ test_packs_all_loose_objects method method test_packs_all_loose_objects L100–112
+ TestPackIdempotent class class TestPackIdempotent L261–295
+ test_packing_already_packed_objects_skips_them method method test_packing_already_packed_objects_skips_them L281–295
+ test_same_objects_produce_same_pack_name method method test_same_objects_produce_same_pack_name L262–279
+ TestPackResult class class TestPackResult L359–382
+ test_bytes_packed_sums_object_sizes method method test_bytes_packed_sums_object_sizes L372–382
+ test_packed_count_matches_loose_objects method method test_packed_count_matches_loose_objects L360–370
+ TestPackRoundTrip class class TestPackRoundTrip L387–446
+ test_new_loose_objects_after_pack_are_readable method async_method test_new_loose_objects_after_pack_are_readable L423–446
+ test_write_pack_remove_loose_still_readable method async_method test_write_pack_remove_loose_still_readable L389–420
+ TestReadPackedObject class class TestReadPackedObject L117–181
+ test_reads_all_objects_from_pack method method test_reads_all_objects_from_pack L141–155
+ test_reads_from_correct_pack_when_multiple_exist method method test_reads_from_correct_pack_when_multiple_exist L157–181
+ test_reads_object_from_pack method method test_reads_object_from_pack L118–128
+ test_returns_none_for_unknown_object method method test_returns_none_for_unknown_object L130–139
+ _count_loose function function _count_loose L48–53
+ _oid function function _oid L25–28
+ _pack_dir function function _pack_dir L56–57
+ _repo_root function function _repo_root L31–35
+ _write_loose function function _write_loose L38–45
+ Path import import Path L15–15
+ annotations import import annotations L12–12
+ blob_id import import blob_id L20–20
+ msgpack import import msgpack L18–18
+ pytest import import pytest L17–17
+ uuid import import uuid L14–14
~ musehub/storage/backends.py .py 3 symbols modified
← Older Oldest on dev
All commits
Newer → Latest on dev

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