gabriel / muse public
Closed #53 Enhancement
filed by gabriel human · 117 days ago

symlog follow-up: analytics, remote sharing, and ergonomic extensions

0 Anchors
— Blast radius
— Churn 30d
0 Proposals

muse symlog — Follow-up Items

Background

Issue #51 delivered the full symlog foundation: per-symbol journaling at commit time, muse symlog read CLI with filters, lifecycle management (expire/delete/GC), and @{N} ref resolution for muse code cat, muse symlog resolve, and muse symlog diff. All 55 test IDs (SL_01–SL_55) are green.

This issue captures the items explicitly deferred from #51 plus useful extensions that emerged during implementation.


Deferred from #51

1. Analytics commands — muse symlog coupling and muse symlog hotspots

The live symlog journal is a rich, already-written dataset. Two analytics commands can read it in O(1) per symbol without touching commit history:

muse symlog hotspots [--top N] [--file path] [--json] — ranks symbols by churn (number of symbol-modified entries in the journal). Complements muse code hotspots (which reads commit history) with a zero-scan alternative that is always up to date.

muse symlog coupling [--file path] [--json] — finds symbol pairs that share commit IDs across their logs (i.e. they always change together). Surfaced purely from symlog data, no AST traversal needed.

2. muse blame integration

muse blame "file.py::Symbol" currently reconstructs authorship by scanning commit history. With symlogs in place, the per-symbol change record already contains author and commit ID at each index. blame should prefer the symlog when available — O(1) per symbol instead of O(commits).

3. muse code narrative rewrite

muse code narrative "file.py::Symbol" generates a plain-English description of a symbol's lifecycle. It currently works from AST diffs across commits. The symlog journal is the canonical source of that history now — narrative should read from symlog entries, gaining richer metadata (operation, author, born-from chains).

4. Remote symlog sharing

Symlogs are currently local-only — they are not pushed or pulled. For teams sharing a MuseHub remote, symlogs are silently missing on clones. The correct design:

  • muse push bundles .muse/symlogs/ alongside commits.
  • muse pull merges incoming symlog entries (append-only, no conflicts).
  • muse bundle create includes symlogs in the msgpack payload.

5. Symlog entries for non-code domains

The extractor returns {} for non-parseable files, so MIDI tracks, binary assets, and schema files produce no symlog entries. For music repos this is the wrong trade-off: a MIDI symbol (track::chorus) should produce a symlog entry when the Harmony domain plugin identifies a change. Deferred until the domain plugin API supports content-ID extraction for non-code artifacts.

6. Relative time syntax (@{1.day.ago}, @{yesterday})

@{N} addresses work by index. Git's reflog also supports relative time syntax (HEAD@{1.hour.ago}). Symlog --since/--until cover the filtering use case, but @{1.day.ago} as a direct ref specifier is more ergonomic in agent prompts.


New items from implementation

7. muse checkout-symbol "file.py::Symbol@{N}"

Restore a prior version of a single symbol to disk without touching any other file. The natural extension of muse code cat "addr@{N}" — cat reads, checkout restores. Critically useful for surgical recovery: "undo the change to this one function without reverting the whole commit."

8. muse symlog grep PATTERN [--file path] [--json]

Search symbol bodies across their full symlog history. Answers: "when did this symbol last contain the string deprecated?" or "which version of this function called session.add?" Reads object store bodies via resolve_symbol_body for each entry.

9. muse symlog show "file.py::Symbol@{N}"

Convenience alias for muse code cat "file.py::Symbol@{N}" with human-focused output: operation, author, timestamp header, then the full symbol body. Useful for interactive exploration ("show me what this function looked like two changes ago").

10. muse symlog stat [--file path] [--json]

Summary statistics for a symbol or file: total entries, operation breakdown (created/modified/deleted/renamed), most active author, first and last commit IDs, date range. Useful for code review context and agent decision-making.

11. Symlog entries for muse revert

muse revert records a reflog entry for the branch ref move, but writes no symlog entries for the symbols it touches. A revert of a commit that modified compute_total should produce a symbol-modified: revert <commit_id> entry in that symbol's log.

12. muse symlog prune-orphans [--dry-run] [--json]

Find symlog files whose symbol address no longer exists in the current snapshot and remove them. Analogous to muse gc for unreachable objects — keeps the .muse/symlogs/ tree clean after large-scale renames or file deletions.

◎ Activity1
●
gabriel opened this issue 117 days ago
○
gabriel 2 days ago

All 12 items from this follow-up are now resolved — 11 implemented and shipped on main (both ~/ecosystem/muse and ~/ecosystem/musehub, pushed to local/staging/production), plus item 5 confirmed still genuinely blocked with a documented decision.

Deferred from #51

  1. Analytics commands — muse symlog hotspots [--top N] [--file path] (ranks symbols by symbol-modified churn) and muse symlog coupling [--file path] [--min N] [--top N] (finds symbol pairs that share commit IDs), both reading purely from the already-written journal — zero commit-history scan.
  2. muse code blame integration — now prefers the symlog journal (O(1) per symbol) over the full BFS commit-DAG walk, falling back only when no journal exists, --from REF is given, or --kind moved/signature is requested (categories the journal can't produce).
  3. muse code narrative rewrite — uses the journal as an index narrowing down which commits to examine, rather than a literal data-source swap (the journal's classification is coarser than narrative's impl-vs-signature distinction). Incidentally fixed a real latent bug: the original fixed-address BFS walk silently stopped at rename boundaries; the journal's born_from chain now crosses them correctly.
  4. Remote symlog sharing — muse push --symlog / push.symlog=true config, muse pull always best-effort merges, muse bundle create/unbundle carry symlogs too (caught and fixed a real bug here: _load_bundle()'s defensive field reconstruction was silently dropping the new symlogs key). Server side: new musehub_symlog_entries table (migration 0081) + wire_push_symlog/wire_get_symlog routes, mirroring the reflog remote-sharing precedent from #54.
  5. Symlog for non-code domains — ⏸️ re-verified still genuinely blocked: extract_symbols() imports the code AST parser directly with no domain-plugin dispatch hook. Documented as a confirmed decision rather than silently left alone.
  6. Relative time syntax (@{1.hour.ago}, @{yesterday}) — mirrors #54 item 1's reflog equivalent.

New items from implementation

  1. muse code checkout-symbol + symlog ref — ADDRESS can now embed @{N} directly instead of requiring --commit REF.
  2. muse symlog grep PATTERN [--file path] — searches reconstructed symbol bodies across full history for a case-insensitive substring match.
  3. muse symlog show "file.py::Symbol@{N}" — human-focused header + full body view.
  4. muse symlog stat — summary statistics (operation breakdown, most active author, first/last commit).
  5. Symlog entries for muse revert — reverts now write symlog entries for the symbols they touch, matching normal commits.
  6. muse symlog prune-orphans [--dry-run] — removes journals for symbols that no longer exist at HEAD.

Every item shipped with full TDD — and this ticket surfaced a real process lesson along the way: two early test drafts (for blame and narrative's symlog fast paths) initially asserted only on final output, which the pre-existing code already produced correctly on its own — reverting the fix left those tests passing, a false-negative RED. Both were rewritten to prove the actual mechanism (monkeypatching the old code path to raise, confirming the new path is what runs) before being accepted. Every item also got a targeted regression suite and live verification via muse-dev against disposable /tmp sandboxes; item 4 was additionally verified end-to-end against the real local MuseHub hub.

Closing.

✓
closed this issue 2 days ago