gabriel / musehub public
feat BREAKING feat/muse54-reflog-remote-sharing-server #1 / 1
AI Agent gabriel · 7 hours ago · Oct 22, 2026 · Diff

feat: muse#54 item 4 server side — musehub_reflog_entries

Server-side companion to the muse-repo commit implementing remote reflog sharing. Mirrors the existing version-tags precedent (musehub side of muse#57 item 4) rather than the content-addressed mpack format, since reflog entries are per-ref metadata, not content-addressed objects.

- New musehub_reflog_entries table (migration 0080): entry_id is a content hash of every field (repo_id, branch, old_id, new_id, timestamp, author, operation) rather than a mutable (repo_id, branch) pointer like version tags — reflog entries are immutable history, so storage is pure ON CONFLICT DO NOTHING append-only, never DO UPDATE. ix_musehub_reflog_entries_repo_branch composite index since every read is scoped to one branch's log. - musehub/services/musehub_reflog.py: store_reflog_entries()/ list_reflog_entries(), sole owner of the table, same boundary rules as musehub_version_tags.py (no state stores/SSE/LLM imports). - wire_push_reflog (POST /{owner}/{slug}/reflog) / wire_get_reflog (GET, same path) on the existing bare-path wire.py router. No force flag on push — there's nothing to conflict, unlike version tags' force-to-overwrite semantics. - New BranchQueryParam validator in api/validation.py: the existing BranchParam uses fastapi.Path(), which requires {branch} in the URL template; these routes carry branch as a query param instead (the route path has no {branch} segment), so a Query()-based twin with the same regex/length constraints was needed. - wire_get_reflog calls _assert_readable (the version-tags read route doesn't check this today — a gap noted while researching the precedent, deliberately not copied here since reflog entries can reveal private branch activity that repo visibility should still gate). - test_migrations.py: _ALL_REVISIONS/_HEAD bumped to include 0080.

Covered by tests/test_musehub_reflog_service.py (6 cases: round-trip, re-push dedup via content-hash entry_id, per-branch isolation, oldest-first ordering, empty-batch no-op, missing-new_id skipped silently). Full suite run: 80 tests (service + version-tags service + migrations + schema-check) all passing, confirming migration 0080 applies cleanly on top of 0079 and the ORM model matches the DB schema exactly (assert_schema_matches_orm). Containers restarted and verified clean boot (schema check passed, 74 tables; alembic current = 0080 head) before live end-to-end verification from the muse-repo side: pushed reflog entries with --reflog to a scratch repo on the real local hub, confirmed idempotent re-push, pulled into a fresh clone and confirmed the remote-tracking reflog received the correct entries.

Co-Authored-By: Claude Sonnet 5 <[email protected]>

sha256:80674069cfe8fe062c526a103e1cd0f855009d1cd06662ca3ae8393e1545a400 sha
+42 ~5 −1 symbols
7 changed · 1094 in snapshot files
sha256:b21108bfaf663dd347cda81439d941a246c681e495e0addca404cc73f0e9081c snapshot
+42
symbols added
~5
symbols modified
−1
symbol removed
7
files changed
1094
files in snapshot
0
dead code introduced
Semantic Changes 48 symbols
+ branch_labels variable variable branch_labels L22–22
+ depends_on variable variable depends_on L23–23
+ down_revision variable variable down_revision L21–21
+ downgrade function function downgrade L44–47
+ Sequence import import Sequence L13–13
+ Union import import Union L13–13
+ annotations import import annotations L11–11
+ op import import op L15–15
+ sa import import sa L16–16
+ revision variable variable revision L20–20
+ upgrade function function upgrade L26–41
~ musehub/services/musehub_reflog.py .py 12 symbols added
+ compute_reflog_entry_id function function compute_reflog_entry_id L30–46
+ AsyncSession import import AsyncSession L23–23
+ MusehubReflogEntry import import MusehubReflogEntry L25–25
+ datetime import import datetime L19–19
+ hashlib import import hashlib L17–17
+ logging import import logging L18–18
+ pg_insert import import pg_insert L22–22
+ select import import select L21–21
+ timezone import import timezone L19–19
+ list_reflog_entries function async_function list_reflog_entries L128–161
+ logger variable variable logger L27–27
+ store_reflog_entries function async_function store_reflog_entries L49–125
~ tests/test_musehub_reflog_service.py .py 13 symbols added
+ _entry_dict function function _entry_dict L17–26
+ AsyncSession import import AsyncSession L11–11
+ annotations import import annotations L7–7
+ create_repo import import create_repo L14–14
+ datetime import import datetime L9–9
+ reflog_svc import import reflog_svc L13–13
+ timezone import import timezone L9–9
+ test_empty_entries_list_is_noop function async_function test_empty_entries_list_is_noop L101–106
+ test_entries_isolated_per_branch function async_function test_entries_isolated_per_branch L66–81
+ test_entry_missing_new_id_is_skipped_silently function async_function test_entry_missing_new_id_is_skipped_silently L109–119
+ test_list_ordered_oldest_first function async_function test_list_ordered_oldest_first L84–98
+ test_repush_same_entry_is_skipped function async_function test_repush_same_entry_is_skipped L46–63
+ test_store_and_list_round_trip function async_function test_store_and_list_round_trip L29–43
~ musehub/api/routes/wire.py .py 3 symbols added, 1 symbol removed, 1 symbol modified
− BranchParam import import BranchParam L39–39
+ BranchQueryParam import import BranchQueryParam L39–39
+ wire_get_reflog function async_function wire_get_reflog L1154–1177
+ wire_push_reflog function async_function wire_push_reflog L1095–1145
~ musehub/api/validation.py .py 2 symbols added, 1 symbol modified
+ BranchQueryParam variable variable BranchQueryParam L55–58
+ Query import import Query L18–18
~ Path
~ musehub/db/musehub_repo_models.py .py 1 symbol added, 1 symbol modified
+ MusehubReflogEntry class class MusehubReflogEntry L567–600
~ tests/test_migrations.py .py 2 symbols modified
Files Changed
+3 ~4
1094 in snapshot
← Older Oldest on feat/muse54-reflog-remote-sharing-server
All commits
Newer → Latest on feat/muse54-reflog-remote-sharing-server

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