gabriel / muse public
shelf-created-by-identity.md markdown
84 lines 4.2 KB
Raw
sha256:18b983389ee1b55900fcd799bfbb496552d2e3ecded9d18cefbfef188947a12e chore: remove blob-debug test marker file Sonnet 4.6 20 hours ago

muse shelf: resolve created_by from user identity instead of hardcoding "human"

Background

muse shelf save recorded created_by: "human" (a plain string) for every human-initiated shelf entry. This lost the caller's username and made it impossible to distinguish gabriel's entries from any other user's. The commit command already solved this correctly: it calls get_config_value("user.handle", root) and uses the result as the author field.

We went further than the original plan: created_by is now a structured object {"handle": "<name>", "kind": "human|agent"} instead of a plain string. This makes the identity richer (you can filter by kind, not just by name) and brings shelf entries in line with how commit records carry agent provenance.

Breaking change: created_by in all shelf JSON output is now {"handle": "...", "kind": "..."} instead of a plain string. Old entries stored as a string are normalised on load — the deserialization in _load_shelf handles both formats gracefully.

Goal

  • muse shelf save (and muse shelf bare) emit created_by: {"handle": "gabriel", "kind": "human"} when user.handle is configured.
  • When no handle is configured (CI, fresh machine, anonymous), falls back to {"handle": "human", "kind": "human"} — same observable behaviour as before.
  • The --by flag still overrides everything and produces {"handle": "<id>", "kind": "agent"}.
  • _shelf_push_programmatic (autoshelf) routes through the same helper; created_by="muse"{"handle": "muse", "kind": "agent"}.
  • Old shelf entries stored with a plain string created_by are normalised on read — no migration needed.

Phases

Phase 1 — Extract a helper

  • [x] CB_01 — Add _resolve_created_by(root, explicit_by) helper in muse/cli/commands/shelf.py. Returns {"handle": explicit_by, "kind": "agent"} when explicit_by != "human"; otherwise calls get_config_value("user.handle", root) and returns {"handle": handle, "kind": "human"}, falling back to "human" when unconfigured. Also introduced _CreatedBy TypedDict.
  • [x] CB_02 — Test: helper returns explicit --by value as kind=agent unchanged
  • [x] CB_03 — Test: helper returns handle from config when --by is "human" and config is populated
  • [x] CB_04 — Test: helper falls back to {"handle": "human", "kind": "human"} when config has no handle

Phase 2 — Wire into run_save

  • [x] CB_05run_save and _shelf_push_programmatic: replace bare created_by string with _resolve_created_by(root, created_by) call. Updated all TypedDicts (_ShelfSaveJson, _ShelfListEntryJson, _ShelfReadJson, ShelfEntry) and _load_shelf backward-compat normalisation.
  • [x] CB_06 — Test: muse shelf save --json with a configured handle produces created_by: {"handle": "<handle>", "kind": "human"}
  • [x] CB_07 — Test: muse shelf save --by my-agent --json produces created_by: {"handle": "my-agent", "kind": "agent"}
  • [x] CB_08 — Test: muse shelf save --json with no configured handle produces created_by: {"handle": "human", "kind": "human"}

Phase 3 — Wire into autoshelf call sites

  • [x] CB_09_shelf_push_programmatic now calls _resolve_created_by; callers in checkout.py and merge.py pass created_by="muse" → resolves to {"handle": "muse", "kind": "agent"}
  • [x] CB_10 — Test: _shelf_push_programmatic(root, created_by="muse") records {"handle": "muse", "kind": "agent"}

Acceptance criteria

  • muse shelf save --json | jq '.created_by' returns {"handle":"gabriel","kind":"human"} on a machine where user.handle = gabriel is configured ✅
  • muse shelf save --by my-agent --json | jq '.created_by' returns {"handle":"my-agent","kind":"agent"}
  • muse shelf list --json | jq '.[].created_by.handle' shows the handle on all new entries ✅
  • All CB_0x tests pass (9/9) ✅
  • No regression on machines without a configured handle ✅
  • 166 shelf tests pass ✅

Out of scope

  • Backfilling created_by on existing shelf entries — old entries are normalised on read
  • Reading identity from ~/.muse/identity.toml directly — get_config_value is the correct single source of truth; no new I/O path needed
File History 1 commit
sha256:18b983389ee1b55900fcd799bfbb496552d2e3ecded9d18cefbfef188947a12e chore: remove blob-debug test marker file Sonnet 4.6 20 hours ago