gabriel / muse public
feat BREAKING feat/216-branch-creation-provenance #1 / 1
AI Agent gabriel · 22 hours ago · Oct 22, 2026 · Diff

feat: persist real branch-creation provenance, separate from tip authorship (musehub#216)

muse branch --json's created_by field was never a creation record -- it was recomputed live from whichever commit currently happens to be the branch's tip (branch.py's old `rec.agent_id if rec and rec.agent_id else None`). Rewrite history, fast-forward the branch, or have someone else commit to it, and created_by silently changes to match, with no indication the value ever meant something different a moment ago.

BranchMeta never had any field for 'who ran muse switch -c / muse branch <name> and when' -- despite write_branch_meta()'s own docstring already (falsely) claiming creation-time fields were preserved.

Fix: - Add created_by_handle/created_by_kind/created_at to BranchMeta, written once at actual creation time by muse switch -c / muse checkout -b / muse branch <name> (never touched again). - resolve_actor_identity() resolves the invoking actor via MUSE_AGENT_HANDLE (agentception's injection mechanism) or user.handle config -- lightweight and local-only, no key material. - muse branch --json: created_by is now the immutable creation record ({handle, kind}), falling back to the legacy tip-authorship value for branches created before this shipped (no creation record exists). A new last_committer field reports current tip authorship separately -- the fact created_by used to conflate. - Fixed a pre-existing _load_config bug along the way: the TOML parser whitelisted only intent/resumable/remote/merge, silently dropping any other [branch.<name>] field -- would have made the new fields round-trip as empty regardless of what was written. - Batched the --json listing's per-branch config.toml reads into a single load up front. Every branch now gets a creation-provenance section (previously, branches with no --intent/--resumable had no section at all and the file stayed tiny), so the existing per-branch reload in _upstream_for/read_branch_meta became a real O(n^2) cost at scale -- caught by the existing 500-branch listing perf test timing out at ~4.8s against a 2s budget.

sha256:f8da4e8a3d3f70a3d5b8e754b5e775f9785f6021ac2411a7ef82e64e10917ee3 sha
+18 ~18 −5 symbols
4 changed · 1260 in snapshot files
sha256:8ae5fcb54bc18afa20cdc3cbf38ac317828cc62944d2b30b432c2b0d4330b476 snapshot
+18
symbols added
~18
symbols modified
−5
symbols removed
4
files changed
1260
files in snapshot
0
dead code introduced
Semantic Changes 41 symbols
~ muse/cli/commands/branch.py .py 3 symbols added, 8 symbols modified
+ _CreatedByJson class class _CreatedByJson L107–109
+ now_utc_iso import import now_utc_iso L73–73
+ resolve_actor_identity import import resolve_actor_identity L72–72
~ run
~ muse/cli/commands/checkout.py .py 1 symbol added, 2 symbols modified
+ resolve_actor_identity import import resolve_actor_identity L93–93
~ run
~ muse/cli/config.py .py 1 symbol added, 4 symbols modified
+ resolve_actor_identity function function resolve_actor_identity L1171–1191
~ tests/test_branch_intent_created_by.py .py 13 symbols added, 5 symbols removed, 4 symbols modified
− test_create_without_intent_no_config_entry method method test_create_without_intent_no_config_entry L259–263
− test_created_by_survives_new_branch_on_agent_repo method method test_created_by_survives_new_branch_on_agent_repo L421–429
− test_list_json_created_by_empty_for_empty_branch method method test_list_json_created_by_empty_for_empty_branch L339–346
− test_list_json_created_by_empty_for_human_commit method method test_list_json_created_by_empty_for_human_commit L330–337
− test_list_json_created_by_from_agent_commit method method test_list_json_created_by_from_agent_commit L322–328
+ test_create_without_intent_has_no_intent_resumable_entries method method test_create_without_intent_has_no_intent_resumable_entries L269–280
+ test_last_committer_reflects_tip_even_on_new_branch method method test_last_committer_reflects_tip_even_on_new_branch L527–539
+ test_created_by_handle_from_env_agent_handle method method test_created_by_handle_from_env_agent_handle L407–416
+ test_created_by_immutable_across_later_commits method method test_created_by_immutable_across_later_commits L418–439
+ test_created_by_independent_of_last_committer method method test_created_by_independent_of_last_committer L395–405
+ test_list_json_created_at_null_for_legacy_branch method method test_list_json_created_at_null_for_legacy_branch L381–385
+ test_list_json_created_by_legacy_fallback_for_agent_commit method method test_list_json_created_by_legacy_fallback_for_agent_commit L339–348
+ test_list_json_created_by_null_for_empty_branch method method test_list_json_created_by_null_for_empty_branch L360–367
+ test_list_json_created_by_null_for_human_commit method method test_list_json_created_by_null_for_human_commit L350–358
+ test_list_json_created_by_real_record_for_new_branch method method test_list_json_created_by_real_record_for_new_branch L369–379
+ test_list_json_has_last_committer_field method method test_list_json_has_last_committer_field L387–393
+ test_switch_create_writes_creation_record method method test_switch_create_writes_creation_record L441–451
+ _branch_json function function _branch_json L70–71
Files Changed
~4
1260 in snapshot
← Older Oldest on feat/216-branch-creation-provenance
All commits
Newer → Latest on feat/216-branch-creation-provenance

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