feat(store): self-describing HEAD format with typed read/write API (#163)
Muse HEAD file format --------------------- Before: bare path, no type tag refs/heads/main
After: self-describing, explicit type prefix ref: refs/heads/<branch> — symbolic ref (on a branch) commit: <sha256> — detached HEAD (direct commit)
The `ref:` prefix is adopted from Git because a file that can hold two semantically different things should declare which one it holds. The `commit:` prefix for detached HEAD is a Muse extension — Git stores a bare SHA, which is ambiguous (SHA-1? SHA-256?). Muse makes the type explicit and leaves room for future algorithm prefixes without changing the parsing rule.
Changes ------- muse/core/store.py: - HeadState = SymbolicHead | DetachedHead (TypedDict union) - read_head(repo_root) → HeadState (typed parser, raises on malformed) - read_current_branch(repo_root) → str (raises ValueError in detached state) - write_head_branch(repo_root, branch) (writes "ref: refs/heads/<branch>") - write_head_commit(repo_root, commit_id) (writes "commit: <sha256>")
Write sites updated (4): muse/cli/commands/init.py, checkout.py, clone.py, tools/git2muse.py
Read sites updated (80+): Every muse/cli/commands/*.py that had the inline `(root / ".muse" / "HEAD").read_text().strip().removeprefix("refs/heads/")` pattern is replaced with `read_current_branch(root)`.
muse/plugins/bitcoin/_loader.py: dead local `read_current_branch` deleted. btc_*.py commands: import moved from _loader to muse.core.store.
Shell plugin (tools/omzsh-plugin/muse.plugin.zsh): _muse_parse_head updated — now matches "ref: refs/heads/" and "commit: " prefixes instead of heuristic shape checks.
Tests (20 fixture writes + all assertions): Every `write_text("refs/heads/…")` in tests/ updated to the new format.
Verification: mypy 0 errors · typing_audit 0 violations · 2504 tests green
Co-authored-by: Gabriel Cardona <gabriel@tellurstori.com>
No comments yet. Be the first to start the discussion.