gabriel / muse public
shelf-created-by-identity.md markdown
84 lines 4.2 KB
Raw
sha256:c0eba5ad689cec79f4a3fcdc4f5da78556cb4b8cb7b330f944634356c10379ed chore: pivot to nightly channel — bump version to 0.2.0.dev… Sonnet 5 patch 12 days 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 4 commits
sha256:c287f599c5429903a139eadf3c5db5d930520e57cb0c3c575d9570e953c3b2d6 chore: bump version to 0.2.0.dev2 — nightly.2 Sonnet 4.6 patch 11 days ago
sha256:8de4334a98c945aace420969d389ad678aa926d4ab4e886b2ac4c4241cb3bf2b revert: keep pyproject.toml in canonical PEP 440 form Sonnet 4.6 patch 14 days ago
sha256:50bb615c573aa4b928fca75b60f82ba2a659910066507cec6a95c412ae22ccb9 docs: add issue docs for push have-negotiation bug (#55) an… Sonnet 4.6 18 days ago
sha256:d90d175cded68aae1d4ffcf4858917854195d0cd8ce1fe73cee4dbc02541cb74 chore: trigger push to surface null-OID paths Sonnet 4.6 23 days ago