gabriel / muse public
utility-reference.md markdown
399 lines 22.1 KB
Raw
sha256:b636f72dcba9e190afb980bece906fa5b717fbde014b76ef023df8cb96e01eb9 docs: expand cache plan with all seven testing tiers and do… Sonnet 4.6 132 days ago

Muse Utility Reference & Anti-Pattern Inventory

Every canonical ID, path, hash, and display operation has a utility function. Never inline these patterns. Use the function. This document is both a reference and a checkable inventory — every known violation is listed so they can be tracked to zero.


Utility Functions

muse.core._types

Function Signature Purpose Replaces
blob_id (data: bytes) → str sha256: ID from raw bytes "sha256:" + hashlib.sha256(data).hexdigest()
content_hash (obj: JsonValue) → str sha256: ID from JSON-serialisable object manual json.dumps + hashlib.sha256
hash_file (path: Path, *, chunk_size=65536) → str sha256: ID from file (streaming) blob_id(path.read_bytes()) for large files
long_id (hex_digest: str, algo="sha256", *, strip=False) → str Add or strip algo: prefix (idempotent) f"sha256:{hex}" · "sha256:" + hex · .removeprefix("sha256:")
short_id (full_id: str, algo="sha256", *, strip=False) → str Canonical 12-char abbreviated ID full_id[:12] · full_id[7:19] · manual slicing
split_id (object_id: str) → tuple[str, str] Parse (algo, hex) from prefixed or bare ID partition(":") inline · .removeprefix("sha256:") at storage boundary
fake_id (seed: str) → str Deterministic sha256: ID for tests hashlib.sha256(seed.encode()).hexdigest() in tests
now_utc_iso () → str Current UTC time as ISO 8601 datetime.datetime.now(datetime.timezone.utc).isoformat()
load_json_file (path: Path) → Any \| None Read + parse JSON file, None on error json.loads(path.read_text(...)) in try/except
encode_sig (algorithm: str, raw: bytes) → str Encode signature bytes as algo:base64url manual base64.urlsafe_b64encode + f-string
encode_pubkey (algorithm: str, raw: bytes) → str Encode public key bytes as algo:base64url same as above
decode_sig (value: str) → tuple[str, bytes] Decode prefixed signature string manual partition(":") + b64decode
decode_pubkey (value: str) → tuple[str, bytes] Decode prefixed public key string same as above
sig_algo (value: str) → str Extract algorithm prefix from crypto value value.partition(":")[0] inline
split_sig (value: str) → tuple[str, str] Parse (algo, b64_str) from prefixed signature string sig.removeprefix("ed25519:") · manual partition(":")
split_pubkey (value: str) → tuple[str, str] Parse (algo, b64_str) from prefixed public key string key.removeprefix("ed25519:") · manual partition(":")

muse.core._types — Object store layout constants

Constant Value Purpose Replaces
OBJECTS_DIR "objects" Objects subdirectory name inside .muse/ hardcoded "objects" string
DEFAULT_ALGO "sha256" Default hash algorithm subdirectory hardcoded "sha256" string in path construction

Import these instead of hardcoding the strings. object_store.py imports them here — no other module should redefine them.

muse.core.object_store — Object path utilities

Function Purpose Replaces
object_path(root, object_id) .muse/objects/sha256/<shard>/<rest> root / ".muse" / "objects" / "sha256" / hex[:2] / hex[2:]
objects_algo_dir(root) .muse/objects/sha256/ directory root / ".muse" / "objects" / "sha256" · root / ".muse" / "objects" / DEFAULT_ALGO

object_path accepts a full sha256:<64hex> ID and handles shard-prefix length from config. Never construct these paths by hand.

muse.core.store — Path constructors

Function Purpose Replaces
commit_path(root, commit_id) .muse/commits/sha256/<hex>.msgpack _commits_dir(root) / f"{id.removeprefix('sha256:')}.msgpack"
snapshot_path(root, snapshot_id) .muse/snapshots/sha256/<hex>.msgpack inline path construction
tag_path(root, repo_id, tag_id) .muse/tags/sha256/<r-hex>/sha256/<t-hex>.msgpack inline construction
release_path(root, repo_id, release_id) .muse/releases/sha256/<r-hex>/sha256/<re-hex>.msgpack inline construction

muse.core.validation — Input guards

Function Purpose
validate_object_id(s) Assert sha256:<64-hex>; raise ValueError
sanitize_display(s) Strip control chars for terminal output
sanitize_provenance(s) Strip unsafe chars from agent/model IDs
contain_path(base, rel) Resolve and assert stays inside base
assert_write_inside_repo(root, path) Raise if path escapes repo root

ID Format Rules

Entity Format Notes
Object, Commit, Snapshot, Tag, Release sha256:<64-hex> Always prefixed
Repo genesis ID sha256:<64-hex> content_hash({"created_at":…,"domain":…,"path":…})
Signature ed25519:<base64url> No padding
Public key ed25519:<base64url> No padding
Coordination IDs (reservation, intent) UUID string Ephemeral advisory — legitimately UUID
Task queue task IDs UUID string Ephemeral — legitimately UUID
Test hub repo slugs arbitrary string External names — not Muse object IDs

UUIDs are not used for any content-addressed system entity. uuid.uuid4() for repo_id, commit_id, snapshot_id, object_id, tag_id, release_id is a bug.


The Storage-Boundary Rule

In-memory, content-addressed IDs are always prefixed (sha256:<64hex>). Always.

The prefix is stripped only at the storage boundary — when constructing a filesystem path that uses bare hex as a directory/filename component. It is added back only when reading an ID back from disk. Nowhere else.

in memory:   sha256:abcdef...   ← always full prefixed form
               ↓ write path
  on disk:   .muse/objects/sha256/ab/cdef...   ← algo dir, then bare hex sharded
               ↓ read path
in memory:   sha256:abcdef...   ← reconstitute prefix immediately on read

Legitimate uses of split_id() / long_id(strip=True):

  • Inside object_path(), commit_path(), snapshot_path(), tag_path(), release_path() — path construction only
  • GC traversal that walks raw filesystem paths and needs to reconstruct IDs
  • Prefix-scan globs where the filesystem requires bare hex

Not legitimate:

  • Stripping prefix to pass an ID between in-memory functions
  • Stripping to do string comparison (compare full prefixed IDs)
  • Stripping to shorten for display (use short_id() instead — it handles the prefix)

UUID truncation is exempt from short_id(). Coordination IDs (reservation_id, intent_id), task queue IDs, hub proposal IDs, and other UUIDs are not content-addressed entities. [:8] or [:12] on a UUID for a debug log is fine — do not apply short_id() to UUIDs. short_id() is only for sha256:-prefixed IDs.


Anti-Pattern Inventory

Pattern 1 — Manual sha256: prefix construction

Fix: long_id(hex) · blob_id(data) · content_hash(obj)

File Notes
muse/core/gc.py Fixed — long_id()
tests/test_implicit_edge_cache.py Fixed — blob_id()
tests/test_guard_supercharge.py Fixed — fake_id()
tests/test_symbol_log_supercharge.py Fixed — fake_id()
tests/test_symbols_supercharge.py Fixed — fake_id()
tests/test_algo_prefix_globs.py Fixed — fake_id()
tests/test_verify_tag_supercharge.py Fixed — fake_id()
tests/test_predict_supercharge.py Fixed — fake_id()
tests/test_cmd_cherry_pick_hardening.py Fixed — fake_id()
tests/test_cmd_cat_object.py Fixed — fake_id()
tests/test_cmd_verify_object.py Fixed — fake_id()
tests/test_merge_base_supercharge.py Fixed — fake_id()
tests/test_cmd_merge_base.py Fixed — fake_id()
tests/test_cmd_read_snapshot.py Fixed — fake_id()
tests/test_read_snapshot_supercharge.py Fixed — fake_id()
tests/test_cmd_read_commit.py Fixed — fake_id()
tests/test_read_commit_supercharge.py Fixed — fake_id()
tests/test_cmd_commit_tree.py Fixed — fake_id()
tests/test_harmony_cli.py Fixed — fake_id()
tests/test_harmony_phase1.py Fixed — fake_id()
tests/test_update_ref_supercharge.py:472 Assertion string, not construction — intentional
tests/test_verify_supercharge.py:400,401 Expected-value assertions for long_id — intentional
tests/test_core_types.py Unit tests for long_id itself — intentional
muse/core/snapshot.py docstring Example strings in module docstring — intentional

All actionable Pattern 1 violations are resolved.


Pattern 2 — Manual prefix stripping outside the storage boundary

Rule: IDs in memory are always prefixed. Strip only inside path-construction functions. Fix: split_id(x)(algo, hex) · or long_id(x, strip=True) for bare hex. Any removeprefix("sha256:") or [7:] outside of object_path()/commit_path()/snapshot_path()/tag_path()/release_path() or a GC filesystem walk is a violation.

Production code

File Notes
muse/core/gc.py Fixed — long_id(id_str, strip=True)
muse/core/object_store.py Fixed — split_id(object_id) (×2)
muse/core/store.py Fixed — long_id(safe_ref, strip=True)
muse/cli/commands/read.py Fixed — long_id(ref, strip=True)
muse/cli/commands/log.py Fixed — long_id(ref, strip=True) (×2)
muse/cli/commands/rev_parse.py Fixed — long_id(ref, strip=True)
muse/cli/commands/read_commit.py Fixed — long_id(commit_id, strip=True)
muse/cli/commands/code_check.py Fixed — long_id(ref, strip=True)
muse/cli/commands/snapshot_cmd.py Fixed — long_id(snapshot_id, strip=True)
muse/cli/commands/snapshot_diff.py Fixed — long_id(prefix, strip=True)
muse/cli/commands/name_rev.py Fixed — long_id(s, strip=True)

Test code

File Notes
tests/test_apply_pack_oserror_integrity.py Fixed — commit_path()
tests/test_cmd_code_add.py Fixed — split_id() / startswith assertion
tests/test_directories_feature.py Fixed — split_id()
tests/test_cmd_reset_hardening.py Fixed — split_id() / snapshot_path()
tests/test_cmd_snapshot_hardening.py Fixed — split_id()
tests/test_harmony_phase4.py Fixed — split_id()
tests/test_integrity_I5_commit_integrity.py Fixed — long_id(strip=True)
tests/test_algo_prefix_globs.py Fixed — long_id(strip=True)
tests/test_ls_tree_supercharge.py Fixed — split_id()
tests/test_cmd_ls_files.py Fixed — split_id(f["object_id"])
tests/test_cmd_revert_hardening.py Fixed — short_id(cid, strip=True)

Note: muse/core/snapshot.py lines 474–475 strip before hashing — the hash computation intentionally uses bare hex as input. Leave as-is.


Pattern 3 — Manual hashlib.sha256 for object IDs

Fix: blob_id(data) · content_hash(obj) · hash_file(path) Only flagged where result is used as a stored/returned ID, not streaming verification.

File Notes
tests/test_implicit_edge_cache.py Already fixed — blob_id(raw)
muse/plugins/code/manifest.py Fixed — blob_id(…) (×2); also storage-boundary fix with long_id(strip=True)
muse/plugins/midi/manifest.py Fixed — blob_id(file_path.encode())
muse/plugins/midi/entity.py Fixed — split_id(blob_id(track_path.encode()))[1][:8]

Pattern 4 — Manual short ID truncation

Fix: short_id(full_id) (returns sha256:abcdef123456) · short_id(full_id, strip=True) (returns abcdef123456)

Production code

Only applies to sha256:-prefixed content-addressed IDs. UUID-based IDs (reservation_id, intent_id, task_id, proposal_id) are exempt — [:8] on a UUID is fine.

File Notes
muse/cli/commands/migrate.py Fixed — short_id(sha, strip=True) (×2)
muse/plugins/midi/plugin.py Fixed — short_id(cid, strip=True)
muse/cli/commands/tension.py Fixed — short_id(commit.commit_id, strip=True)
muse/cli/commands/scale_detect.py Fixed — short_id(commit.commit_id, strip=True)
muse/cli/commands/rhythm.py Fixed — short_id(commit.commit_id, strip=True)
muse/cli/commands/velocity_profile.py Fixed — short_id(commit.commit_id, strip=True)
muse/cli/commands/release.py Fixed — short_id(release_id, strip=True) (×2)

muse/core/dag.py:594, muse/core/task_queue.py:578,660,1068, muse/core/coordination.py:362,568,797,944, muse/cli/commands/hub/proposals.py:600,642 — UUID truncations, not violations.

Test code (representative — use short_id consistently)

File Notes
tests/test_cmd_gc.py Fixed — short_id(orphan_id, strip=True)
tests/test_cmd_check.py Fixed — short_id(cids[-1], strip=True)
tests/test_cmd_tag.py Fixed — short_id(commit_id)
tests/test_harmony_cli.py Fixed — short_id(pid) (×4)
tests/test_cmd_show.py Fixed — short_id(cid)
tests/test_cmd_read_snapshot.py Fixed — short_id(sid)
tests/test_cmd_read_commit.py Fixed — short_id(cid)
tests/test_cmd_cherry_pick_hardening.py Fixed — short_id(cid) (×2)
tests/test_cmd_revert_hardening.py Fixed — short_id(cid) (×2)
tests/test_cmd_bisect_hardening.py Fixed — short_id(mid) (×3)
tests/test_cmd_snapshot_hardening.py Fixed — short_id(snap_id) (×7)
tests/test_cmd_branch.py Fixed — short_id(first_sha) (×2)
tests/test_cmd_archive_hardening.py Fixed — short_id(commit_id) (×2)
tests/test_algo_prefix_globs.py bare_hex[:12] — bare hex variable, not prefixed, exempt
tests/test_cmd_reflog_hardening.py _SHA_B[:12] — bare hex constant, not prefixed, exempt

Pattern 5 — Manual UTC timestamp

Fix: now_utc_iso()

File Notes
muse/core/bisect.py Fixed — now_utc_iso()
tools/demo.py Fixed — now_utc_iso() (×3 including line 490)
tests/test_directories_feature.py Fixed — now_utc_iso() (×3)
tests/test_workdir_integrity.py Fixed — now_utc_iso()
tests/test_cmd_coord_gc.py Fixed — now_utc_iso() (×2)
tests/test_cmd_watch_coord.py Fixed — now_utc_iso() (×5)
tests/test_release_analysis.py Fixed — now_utc_iso()
tests/test_security_object_store_poisoning.py Fixed — now_utc_iso() (×2)

Pattern 6 — Manual JSON file loading

Fix: load_json_file(path) — returns None on any error

Production code

File Notes
muse/cli/commands/status.py Fixed — load_json_file(cfg_path)
muse/plugins/code/stage.py Uses msgpack, not JSON file — not applicable
tools/render_html.py Fixed — load_json_file(json_path)
tools/demo.py Fixed — load_json_file(f) (×2)

Note: verify_tag.py:182 and verify_commit.py:121 use _json.loads(resp.read().decode()) on HTTP response bodies — not file paths, leave as-is.

Test code (representative sample)

File Notes
tests/test_cli_workflow.py Fixed — load_json_file(...)
tests/test_cmd_reserve.py Fixed — load_json_file(...) (×3)
tests/test_cmd_sparse_checkout.py Fixed — load_json_file(...) (×6)

Pattern 7 — uuid.uuid4() for content-addressed entity IDs

Fix: content_hash({…}) for genesis IDs · fake_id(seed) for deterministic test IDs

Legitimate UUIDs: coordination reservation_id/intent_id, task_queue task IDs, test hub slugs, CRDT tokens. Everything below is a bugrepo_id, tag_id, release_id, commit_id must not be UUIDs.

File Notes
tests/test_cmd_gc.py Fixed — fake_id("repo")
tests/test_rebase_missing_snapshot_guard.py Fixed — fake_id(...)
tests/test_security_ast_dos.py Fixed — fake_id(...)
tests/test_merge_data_integrity.py Fixed — fake_id(...)
tests/test_merge_supercharge.py Fixed — fake_id(...)
tests/test_cmd_merge_dry_run.py Fixed — fake_id(...)
tests/test_cmd_check.py Fixed — fake_id(...)
tests/test_cmd_shelf.py Fixed — fake_id(...)
tests/test_workdir_integrity.py Fixed — fake_id(...)
tests/test_gc_full.py Fixed — fake_id(...)
tests/test_cmd_merge.py Fixed — fake_id(...)
tests/test_cmd_tag.py Fixed — fake_id(...) (×5)
tests/test_pull_missing_snapshot_guard.py Fixed — fake_id(...)
tests/test_cmd_reset_revert.py Fixed — fake_id(...)
tests/test_cmd_config.py Fixed — fake_id(...)
tests/test_cmd_bisect.py Fixed — fake_id(...)
tests/test_cmd_archive_hardening.py Fixed — fake_id(...)
tests/test_gc_supercharge.py Fixed — fake_id(...)
tests/test_cmd_bisect_hardening.py Fixed — fake_id(...) (×2)
tests/test_cmd_gc_hardening.py Fixed — fake_id(...)
tests/test_security_code_porcelain.py Fixed — fake_id(...)
tests/test_cmd_reflog.py Fixed — fake_id(...)
tests/test_cmd_plan_merge.py Fixed — fake_id(...) (×2)
tests/test_cmd_release_hardening.py Fixed — fake_id(...); stale import uuid removed

Pattern 8 — Manual fake_id equivalent in tests

Fix: fake_id(seed) — deterministic, prefixed, well-formed

File Notes
tests/test_security_agent_impersonation.py Fixed — fake_id(cid)
tests/test_msign_dual_sig.py Nonces, not IDs — legitimate, leave as-is
tests/test_core_msign.py Signing verification hashes — legitimate, leave as-is

Pattern 9 — Manual object path construction

Fix: object_path(root, object_id) from muse.core.object_store Never inline root / ".muse" / "objects" / "sha256" / hex[:2] / hex[2:].

File Notes
tests/test_cmd_invariants.py Already using object_path()
tests/test_cmd_gc_hardening.py Fixed — object_path(root, "sha256:" + sha) (×2)
tests/test_gc_supercharge.py Already using object_path()
tests/test_porcelain_security.py Already using object_path()
tests/test_core_gc.py Already using object_path()
tests/test_cmd_code_add.py Already using object_path()
tests/test_code_manifest.py Already using object_path()
tests/test_merge_data_integrity.py Already using object_path()

Pattern 10 — Manual cryptographic prefix stripping / construction

Fix: split_sig(value)(algo, b64_str) · split_pubkey(value)(algo, b64_str) · encode_sig(algo, raw) · encode_pubkey(algo, raw) Never use removeprefix("ed25519:"), "ed25519:" + b64, or partition(":") inline on signature/pubkey strings.

File Notes
tests/test_core_provenance.py Fixed — split_sig() · encode_sig() / decode_sig()

Pattern 11 — --format flag instead of --json

Universal rule: Every muse CLI command follows the same output convention:

  • Default (no flag): plain text, human-readable
  • --json / -j: machine-readable JSON for agents and scripts

There is no --format flag on any muse command. --format text, --format json, and --format xml do not exist. Code or tests using --format are wrong.

In tests: never pass --format <value> to any muse CLI invocation. In production code: never add a --format argument to a command's parser. JSON parsing: cmd --json output is always an envelope dict — for list-style commands the entries are under the "entries" key, never at the top level as a bare array.

Known violations

| | File | Location | Fix | |--|------|----------|-----| | ✅ | tests/test_cmd_rev_parse.py | TestDefaultFormat, TestBranchResolution, TestAbbrevRef, TestEdgeCases, TestErrorJson | Removed --format text/xml; rewrote to use plain-text default | | ✅ | tests/test_cmd_shelf.py | TestSecurity::test_invalid_format_exits_1 | assert r.exit_code != 0 (no --format flag exists) | | ✅ | tests/test_cmd_shelf.py | TestListJsonSchema, TestReadJsonSchema, TestApplyJsonSchema, TestPopJsonSchema, TestDropJsonSchema, TestRoundTrips, TestStress | json.loads(r.output)json.loads(r.output)["entries"] | | ✅ | muse/cli/commands/intent.py | Fixed — replaced --format/-f with --json/-j bool flag; updated test_cmd_intent.py |

Legitimate --format uses (not violations)

File What --format controls
snapshot_cmd.py Archive encoding: tar.gz or zip — file container format, not output mode
archive.py Same
narrative.py Narrative style: timeline or prose — content structure, not output mode
docs_cmd.py Documentation output type: html, md, text, json — multi-format docs renderer; json choice is a violation but html/md have no --json equivalent

Grep target: "--format" in test files (no legitimate uses); add_argument.*"--format".*choices.*text.*json in command files.

File History 1 commit
sha256:b636f72dcba9e190afb980bece906fa5b717fbde014b76ef023df8cb96e01eb9 docs: expand cache plan with all seven testing tiers and do… Sonnet 4.6 132 days ago