gabriel / musehub public
feat BREAKING dev
AI Agent gabriel · 130 days ago · May 9, 2026 · Diff

feat: blame page revamp + blob/blame perf fixes

- Blame page full redesign: new .blm-* CSS, symbol cards with colored borders, expandable history panels, file-level blame with line-annotated code view - ui_blame.py: fast path via symbol history index (O(1) vs O(N) snapshot scan), 50-commit cap on fallback scan, file content loading for file-level blame - ui_blob.py: load_symbol_history called once; _fetch_file_history uses index fast path with dedup; _fetch_file_symbols/intel accept pre-loaded history - musehub_repository.get_last_commit_for_file: index fast path - TDD: test_blame_page_perf, test_blob_page_perf, test_last_commit_index_lookup - blame.ts: replace MIDI tooltip with code blame hash navigation - SCSS: _blame.scss component + page partials, app.scss imports both

sha256:3232d72dcec2a511e1cf003a83fb340c1204a29bd79e6fe78d205f2fe94b96ef sha
+259 ~11 −5 symbols
sha256:762bca7dc21f63efda2e816fb95ae1b58a0780d4ba07fa20a2cf456034aced7c snapshot
+259
symbols added
~11
symbols modified
−5
symbols removed
0
dead code introduced
Semantic Changes 275 symbols
~ src/scss/components/_blame.scss .scss 113 symbols added
+ blm-author-icon rule .blm-author-icon L442–460
+ blm-author-icon--agent rule .blm-author-icon--agent L452–455
+ blm-author-icon--human rule .blm-author-icon--human L456–459
+ blm-breadcrumb rule .blm-breadcrumb L79–97
+ blm-breadcrumb-link rule .blm-breadcrumb-link L99–103
+ blm-breadcrumb-link:hover rule .blm-breadcrumb-link:hover L102–102
+ blm-card rule .blm-card L306–316
+ blm-card-author rule .blm-card-author L432–440
+ blm-card-bottom rule .blm-card-bottom L394–399
+ blm-card-commit rule .blm-card-commit L466–478
+ blm-card-commit:hover rule .blm-card-commit:hover L477–477
+ blm-card-dot rule .blm-card-dot L462–462
+ blm-card-main rule .blm-card-main L331–331
+ blm-card-summary rule .blm-card-summary L318–329
+ -webkit-details-marker rule .blm-card-summary::-webkit-details-marker L327–327
+ blm-card-summary:hover rule .blm-card-summary:hover L328–328
+ blm-card-time rule .blm-card-time L464–464
+ blm-card-top rule .blm-card-top L333–339
+ blm-card:hover rule .blm-card:hover L314–314
+ blm-card[open] rule .blm-card[open] L315–315
+ blm-code-cell rule .blm-code-cell L662–668
+ blm-code-row rule .blm-code-row L634–640
+ blm-code-cell rule .blm-code-row:target .blm-code-cell, .blm-code-row:hover .blm-code-cell L637–638
+ blm-gutter rule .blm-code-row:target .blm-gutter L639–639
+ blm-code-table rule .blm-code-table L625–632
+ blm-code-truncated rule .blm-code-truncated L670–677
+ blm-commit-body rule .blm-commit-body L221–221
+ blm-commit-card rule .blm-commit-card L199–211
+ blm-commit-card:hover rule .blm-commit-card:hover L210–210
+ blm-commit-card:last-child rule .blm-commit-card:last-child L209–209
+ blm-commit-count rule .blm-commit-count L261–269
+ blm-commit-dot rule .blm-commit-dot L213–219
+ blm-commit-meta rule .blm-commit-meta L280–287
+ blm-commit-model rule .blm-commit-model L289–296
+ blm-commit-msg rule .blm-commit-msg L271–278
+ blm-commit-prov rule .blm-commit-prov L242–259
+ blm-commit-prov--agent rule .blm-commit-prov--agent L251–254
+ blm-commit-prov--human rule .blm-commit-prov--human L255–258
+ blm-commit-sha rule .blm-commit-sha L230–240
+ blm-commit-top rule .blm-commit-top L223–228
+ blm-empty rule .blm-empty L139–159
+ blm-empty-hint rule .blm-empty-hint L161–164
+ blm-expand-chevron rule .blm-expand-chevron L480–486
+ blm-file-commit-author rule .blm-file-commit-author L604–608
+ blm-file-commit-bar rule .blm-file-commit-bar L568–577
+ blm-file-commit-msg rule .blm-file-commit-msg L592–600
+ blm-file-commit-sep rule .blm-file-commit-sep L602–602
+ blm-file-commit-sha rule .blm-file-commit-sha L579–590
+ blm-file-commit-sha:hover rule .blm-file-commit-sha:hover L589–589
+ blm-file-commit-time rule .blm-file-commit-time L610–614
+ blm-file-empty rule .blm-file-empty L616–621
+ blm-file-view rule .blm-file-view L561–566
+ blm-filename rule .blm-filename L41–55
+ blm-gutter rule .blm-gutter L642–651
+ blm-header-left rule .blm-header-left L18–24
+ blm-heat rule .blm-heat L401–406
+ blm-heat-bar rule .blm-heat-bar L408–415
+ blm-heat-count rule .blm-heat-count L425–430
+ blm-heat-fill rule .blm-heat-fill L417–423
+ blm-hist-age rule .blm-hist-age L537–537
+ blm-hist-author rule .blm-hist-author L536–536
+ blm-hist-msg rule .blm-hist-msg L535–535
+ blm-hist-num rule .blm-hist-num L523–523
+ blm-hist-sha a rule .blm-hist-sha a L524–534
+ blm-hist-sha a:hover rule .blm-hist-sha a:hover L533–533
+ blm-history-empty rule .blm-history-empty L551–557
+ blm-history-footer rule .blm-history-footer L539–549
+ blm-history-panel rule .blm-history-panel L490–493
+ blm-history-table rule .blm-history-table L495–521
+ blm-legend rule .blm-legend L168–173
+ blm-legend-hdr rule .blm-legend-hdr L175–187
+ blm-legend-prov-key rule .blm-legend-prov-key L189–197
+ blm-lnlink rule .blm-lnlink L653–660
+ blm-lnlink:hover rule .blm-lnlink:hover L659–659
+ blm-op rule .blm-op L359–376
+ blm-op--add rule .blm-op--add L369–369
+ blm-op--remove rule .blm-op--delete, .blm-op--remove L372–373
+ blm-op--replace rule .blm-op--modify, .blm-op--replace L370–371
+ blm-op--patch rule .blm-op--patch L375–375
+ blm-op--rename rule .blm-op--rename L374–374
+ blm-page-header rule .blm-page-header L11–16
+ blm-path-icon rule .blm-path-icon L26–37
+ blm-path-info rule .blm-path-info L39–39
+ blm-prov-key rule .blm-prov-key L681–687
+ blm-signal rule .blm-signal L378–392
+ blm-signal--blast rule .blm-signal--blast L391–391
+ blm-signal--dead rule .blm-signal--dead L390–390
+ blm-signal--hotspot rule .blm-signal--hotspot L389–389
+ blm-stat rule .blm-stat L115–125
+ blm-stat--blast rule .blm-stat--blast L135–135
+ blm-stat--active rule .blm-stat--blast.blm-stat--active L135–135
+ blm-stat--dead rule .blm-stat--dead L134–134
+ blm-stat--active rule .blm-stat--dead.blm-stat--active L134–134
+ blm-stat--hotspot rule .blm-stat--hotspot L133–133
+ blm-stat--active rule .blm-stat--hotspot.blm-stat--active L133–133
+ blm-stat-val rule .blm-stat-val L135–135
+ blm-stats rule .blm-stats L107–113
+ blm-symbol-link rule .blm-symbol-link L353–357
+ blm-symbol-link:hover rule .blm-symbol-link:hover L356–356
+ blm-symbol-list rule .blm-symbol-list L300–304
+ blm-symbol-name rule .blm-symbol-name L341–351
+ blm-type-badge rule .blm-type-badge L57–77
+ blm-type-badge--file rule .blm-type-badge--file L72–76
+ blm-type-badge--symbol rule .blm-type-badge--symbol L67–71
+ a rule a L543–548
+ a:hover rule a:hover L547–547
+ code rule code L150–158
+ blm-expand-chevron rule details[open] > summary .blm-expand-chevron L485–485
+ p rule p L149–149
+ td rule td L512–517
+ th rule th L500–510
+ tr:hover td rule tr:hover td L520–520
+ tr:last-child td rule tr:last-child td L519–519
~ src/scss/pages/_blame.scss .scss 19 symbols added
+ (max-width: 900px) rule (max-width: 900px) L17–19
+ blm-card-bottom rule .blm-card-bottom L68–73
+ blm-card-main rule .blm-card-main L58–58
+ blm-card-summary rule .blm-card-summary L52–56
+ blm-card-top rule .blm-card-top L60–66
+ blm-code-cell rule .blm-code-cell L82–82
+ blm-code-table rule .blm-code-table L77–79
+ blm-content rule .blm-content L35–40
+ blm-gutter rule .blm-gutter L81–81
+ blm-history-table rule .blm-history-table L86–93
+ blm-layout rule .blm-layout L11–20
+ blm-legend rule .blm-legend L24–31
+ blm-symbol-list rule .blm-symbol-list L44–48
+ th:nth-child(1) rule th:nth-child(1) L87–87
+ th:nth-child(2) rule th:nth-child(2) L88–88
+ th:nth-child(3) rule th:nth-child(3) L89–89
+ th:nth-child(4) rule th:nth-child(4) L90–90
+ th:nth-child(5) rule th:nth-child(5) L91–91
+ th:nth-child(6) rule th:nth-child(6) L92–92
~ tests/test_blame_page_perf.py .py 36 symbols added
+ _FILE variable variable _FILE L47–47
+ _OTHER variable variable _OTHER L48–48
+ _OWNER_ID variable variable _OWNER_ID L46–46
+ _blob function function _blob L71–72
+ _commit function async_function _commit L97–113
+ _fresh_session function async_function _fresh_session L139–141
+ _history_entry function async_function _history_entry L116–135
+ _make_repo function async_function _make_repo L75–84
+ _obj function function _obj L67–68
+ _repo_id function function _repo_id L57–60
+ _snap function async_function _snap L87–94
+ _snap_id function function _snap_id L63–64
+ _uid function function _uid L53–54
+ AsyncGenerator import import AsyncGenerator L31–31
+ AsyncSession import import AsyncSession L36–36
+ JSONObject import import JSONObject L41–41
+ StrDict import import StrDict L41–41
+ _database import import _database L40–40
+ annotations import import annotations L26–26
+ asynccontextmanager import import asynccontextmanager L29–29
+ compute_identity_id import import compute_identity_id L38–38
+ compute_repo_id import import compute_repo_id L38–38
+ datetime import import datetime L30–30
+ db import import db L39–39
+ long_id import import long_id L42–42
+ msgpack import import msgpack L34–34
+ now_utc_iso import import now_utc_iso L42–42
+ patch import import patch L32–32
+ pytest import import pytest L35–35
+ secrets import import secrets L28–28
+ timedelta import import timedelta L30–30
+ timezone import import timezone L30–30
+ test_snapshot_diff_blame_caps_fallback_scan function async_function test_snapshot_diff_blame_caps_fallback_scan L232–265
+ test_snapshot_diff_blame_falls_back_when_no_history function async_function test_snapshot_diff_blame_falls_back_when_no_history L212–228
+ test_snapshot_diff_blame_returns_entry_from_history_index function async_function test_snapshot_diff_blame_returns_entry_from_history_index L182–208
+ test_snapshot_diff_blame_skips_manifest_scan_when_history_exists function async_function test_snapshot_diff_blame_skips_manifest_scan_when_history_exists L148–178
~ tests/test_blob_page_perf.py .py 39 symbols added
+ _FILE variable variable _FILE L50–50
+ _OTHER variable variable _OTHER L51–51
+ _OWNER_ID variable variable _OWNER_ID L49–49
+ _blob function function _blob L74–75
+ _commit function async_function _commit L100–117
+ _fresh_session function async_function _fresh_session L143–145
+ _history_entry function async_function _history_entry L120–139
+ _make_repo function async_function _make_repo L78–87
+ _obj function function _obj L70–71
+ _repo_id function function _repo_id L60–63
+ _snap function async_function _snap L90–97
+ _snap_id function function _snap_id L66–67
+ _uid function function _uid L56–57
+ AsyncGenerator import import AsyncGenerator L34–34
+ AsyncMock import import AsyncMock L35–35
+ AsyncSession import import AsyncSession L39–39
+ JSONObject import import JSONObject L44–44
+ StrDict import import StrDict L44–44
+ _database import import _database L43–43
+ annotations import import annotations L29–29
+ asynccontextmanager import import asynccontextmanager L32–32
+ call import import call L35–35
+ compute_identity_id import import compute_identity_id L41–41
+ compute_repo_id import import compute_repo_id L41–41
+ datetime import import datetime L33–33
+ db import import db L42–42
+ long_id import import long_id L45–45
+ msgpack import import msgpack L37–37
+ now_utc_iso import import now_utc_iso L45–45
+ patch import import patch L35–35
+ pytest import import pytest L38–38
+ secrets import import secrets L31–31
+ timedelta import import timedelta L33–33
+ timezone import import timezone L33–33
+ test_blob_page_calls_load_symbol_history_once function async_function test_blob_page_calls_load_symbol_history_once L269–301
+ test_fetch_file_history_deduplicates_commits function async_function test_fetch_file_history_deduplicates_commits L238–262
+ test_fetch_file_history_falls_back_when_no_history_entries function async_function test_fetch_file_history_falls_back_when_no_history_entries L216–234
+ test_fetch_file_history_returns_commits_from_history_index function async_function test_fetch_file_history_returns_commits_from_history_index L188–212
+ test_fetch_file_history_skips_snapshot_scan_when_history_exists function async_function test_fetch_file_history_skips_snapshot_scan_when_history_exists L152–184
+ _FILE variable variable _FILE L54–54
+ _OTHER variable variable _OTHER L55–55
+ _OWNER_ID variable variable _OWNER_ID L53–53
+ _blob function function _blob L78–79
+ _commit function async_function _commit L104–120
+ _fresh_session function async_function _fresh_session L147–149
+ _history_entry function async_function _history_entry L123–143
+ _make_repo function async_function _make_repo L82–91
+ _obj function function _obj L74–75
+ _repo_id function function _repo_id L64–67
+ _snap function async_function _snap L94–101
+ _snap_id function function _snap_id L70–71
+ _uid function function _uid L60–61
+ AsyncGenerator import import AsyncGenerator L37–37
+ AsyncMock import import AsyncMock L38–38
+ AsyncSession import import AsyncSession L42–42
+ StrDict import import StrDict L48–48
+ _database import import _database L46–46
+ annotations import import annotations L32–32
+ asynccontextmanager import import asynccontextmanager L35–35
+ compute_identity_id import import compute_identity_id L44–44
+ compute_repo_id import import compute_repo_id L44–44
+ datetime import import datetime L36–36
+ db import import db L45–45
+ get_last_commit_for_file import import get_last_commit_for_file L47–47
+ long_id import import long_id L49–49
+ msgpack import import msgpack L40–40
+ now_utc_iso import import now_utc_iso L49–49
+ patch import import patch L38–38
+ pytest import import pytest L41–41
+ secrets import import secrets L34–34
+ timedelta import import timedelta L36–36
+ timezone import import timezone L36–36
+ test_get_last_commit_falls_back_to_snapshot_scan_when_no_history function async_function test_get_last_commit_falls_back_to_snapshot_scan_when_no_history L216–230
+ test_get_last_commit_ignores_entries_for_other_files function async_function test_get_last_commit_ignores_entries_for_other_files L267–289
+ test_get_last_commit_matches_symbol_entries_for_file function async_function test_get_last_commit_matches_symbol_entries_for_file L234–263
+ test_get_last_commit_returns_most_recent_history_entry function async_function test_get_last_commit_returns_most_recent_history_entry L186–212
+ test_get_last_commit_skips_snapshot_scan_when_history_exists function async_function test_get_last_commit_skips_snapshot_scan_when_history_exists L156–182
~ musehub/api/routes/musehub/ui_blame.py .py 2 symbols added, 2 symbols modified
+ _get_storage_backend import import _get_storage_backend L49–49
+ get_snapshot_manifests_batch import import get_snapshot_manifests_batch L48–48
~ musehub/api/routes/musehub/ui_blob.py .py 6 symbols added, 4 symbols modified
+ _INTEL_EMPTY variable variable _INTEL_EMPTY L309–314
+ _compute_intel_from_history function function _compute_intel_from_history L317–375
+ _fetch_file_intel_from_history function async_function _fetch_file_intel_from_history L389–393
+ _fetch_file_symbols_from_history function async_function _fetch_file_symbols_from_history L91–95
+ _symbol_history_to_outline function function _symbol_history_to_outline L61–78
+ load_symbol_history import import load_symbol_history L30–30
~ musehub/templates/musehub/pages/blame.html .html 4 symbols added, 4 symbols removed, 1 symbol modified
aside@109 section aside@109 L109–151
details@172 section details@172 L172–280
details@175 section details@175 L175–277
h2: h2 section h2: h2 L24–32
+ aside@96 section aside@96 L96–133
+ details@145 section details@145 L145–253
+ h1: h1 section h1: h1 L24–31
+ index }} section tr#L{{ loop.index }} L283–288
~ src/scss/components/_diff.scss .scss 1 symbol added
+ df3-meta-time rule .df3-meta-time L47–51
~ src/ts/pages/blame.ts .ts 1 symbol added, 1 symbol removed, 1 symbol modified
initMidiTooltip function function initMidiTooltip L10–38
+ highlightTargetLine function function highlightTargetLine L9–20
← Older Oldest on dev
All commits
Newer → Latest on dev

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:3232d72dcec2a511e1cf003a83fb340c1204a29bd79e6fe78d205f2fe94b96ef --body "your comment"