feat: muse#53 item 4 — remote symlog sharing via push/pull/bundle
Symlogs were 100% local-only until now: a fresh clone started with zero per-symbol change history. Mirrors muse#54 item 4's reflog remote-sharing precedent (same wire-conversion / idempotent-merge / transport-method / server-table shape), with one structural difference: symlog is per-symbol, not per-branch, so there is no "local vs remote-tracking namespace" split — reflog needs that split to avoid conflating a remote's ref-movement history with purely local activity, but a symbol's commit history is identical for every clone, so entries merge directly into the same local journal a muse commit would write to.
Muse CLI: - `muse push --symlog` (or `push.symlog=true` config, new [push] key alongside tags/reflog) batches every local symbol's journal entries into one POST request (unlike reflog's per-branch push, since symlog has no branch scope). - `muse pull` always best-effort fetches every symlog entry and merges directly into local journals via the new merge_remote_symlog_entries(). - `muse bundle create`/`unbundle` now also carry every local symlog entry unconditionally (bundles are a comprehensive offline transfer, so no --symlog-style opt-in needed there) — found and fixed a bug while live-verifying: `_load_bundle()` does defensive field-by-field reconstruction of the parsed msgpack dict (same as the pre-existing branch_heads field), so a "symlogs" key needed the same explicit extraction or it would be silently dropped on unbundle even though bundle create wrote it correctly. - muse/core/symlog.py: symlog_entries_to_wire() (content IDs/commit IDs pass through unchanged — unlike reflog, symlog already stores them in canonical sha256:<hex> form on disk, no stripping/normalization needed) and merge_remote_symlog_entries() (idempotent exact-raw-line comparison, appending directly into the local journal). - muse/core/transport.py: push_symlog()/fetch_symlog() on both the Protocol and HttpTransport — push batches {"symbols": {addr: [entries]}} in one request; fetch returns every symbol's entries grouped the same way. - _PushJson gained always-present symlog_pushed/symlog_skipped fields, same always-present-with-0/0-default rationale as reflog_pushed/ reflog_skipped.
MuseHub server (~/ecosystem/musehub, shipped as a companion commit): - New musehub_symlog_entries table (migration 0081), keyed by a content-hash entry_id (includes symbol_addr in the hash, unlike reflog's per-branch hash) for ON CONFLICT DO NOTHING append-only semantics. - musehub/services/musehub_symlog.py: store_symlog_entries() (batched across any number of symbols in one call, unlike reflog's single-branch call) / list_symlog_entries() (grouped by symbol addr). - wire_push_symlog/wire_get_symlog routes on the existing bare-path wire.py router.
Covered by tests/test_symlog_remote_sharing.py (11 cases: wire pass-through (no ID normalization needed, unlike reflog), core merge idempotency/per-symbol-isolation/no-collision, CLI --symlog flag + config flag + transport-not-called when disabled, pull merge + non-fatal fetch-failure handling, and a real bundle create→unbundle round trip asserting symlog_entries_merged >= 1 — this last test is what caught the _load_bundle() field-stripping bug above) plus tests/test_musehub_symlog_service.py (7 cases, musehub repo: round-trip, dedup-skip, batched multi-symbol push, per-symbol isolation, ordering, empty-batch, missing-commit_id).
Confirmed genuine RED by reverting all six touched muse-side files and re-running (ImportError: merge_remote_symlog_entries doesn't exist), then GREEN with the fix restored plus the full targeted regression suite (177 muse-side symlog/reflog/version-tag tests, zero regressions; 644 more across push/pull/config/bundle areas, zero regressions; 87 musehub-side tests including migrations + ORM/schema-match checks). Live-verified end-to-end against the real local MuseHub hub (containers restarted, migration 0081 auto-applied, schema check passed at 75 tables): created a scratch repo, pushed a symbol's journal with --symlog (confirmed idempotent on retry), pulled from a fresh clone, and confirmed the local journal received the exact original entry. Scratch repo deleted after verification.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Semantic Changes
75 symbols
Files Changed
+1
~7
1242 in snapshot
0 comments
muse hub commit comment sha256:b570925a487b44187c0441977d252906b6bf2719253bc53f96412d520cd24d9e --body "your comment"
No comments yet. Be the first to start the discussion.