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

feat: cursor-based pagination for symbol detail provenance and coupling

- 10 entries/page for provenance history (keyset cursor = committed_at ISO string) - 15 entries/page for coupling partners (integer offset cursor) - Both cursors independent and cross-preserved in Load More links - Enrich all entries first, then paginate to keep version_num/gap_hours correct - TDD: 47 passing tests covering unit, integration, HTML, edge cases, perf, security

sha256:be7d9f0c983bbbea418ae8edc91aaa091643fab43e32299539488ba8bff1f8f2 sha
+79 ~2 symbols
sha256:410234fa1e36a62a0ea484180266222e128e9bc3f05d6b917fed924f5bbb371c snapshot
+79
symbols added
~2
symbols modified
0
dead code introduced
Semantic Changes 81 symbols
+ COUPLING_PAGE variable variable COUPLING_PAGE L36–36
+ HISTORY_PAGE variable variable HISTORY_PAGE L35–35
+ TestCouplingCursorParsing class class TestCouplingCursorParsing L75–103
+ _decode method method _decode L81–83
+ _encode method method _encode L78–79
+ test_P105_roundtrip method method test_P105_roundtrip L85–90
+ test_P106_address_with_colons_preserved method method test_P106_address_with_colons_preserved L92–97
+ test_P107_zero_shared_valid method method test_P107_zero_shared_valid L99–103
+ TestCouplingPagination class class TestCouplingPagination L264–360
+ test_P211_first_page_returns_15_partners method async_method test_P211_first_page_returns_15_partners L267–274
+ test_P212_first_page_has_coupling_next_link method async_method test_P212_first_page_has_coupling_next_link L276–282
+ test_P213_second_page_returns_remaining method async_method test_P213_second_page_returns_remaining L284–296
+ test_P214_last_coupling_page_no_next_link method async_method test_P214_last_coupling_page_no_next_link L298–314
+ test_P215_fewer_than_15_partners_no_pagination method async_method test_P215_fewer_than_15_partners_no_pagination L316–322
+ test_P216_both_cursors_independent method async_method test_P216_both_cursors_independent L324–340
+ test_P217_invalid_coupling_cursor_returns_200_first_page method async_method test_P217_invalid_coupling_cursor_returns_200_first_page L342–351
+ test_P218_coupling_ordered_by_shared_commits_desc method async_method test_P218_coupling_ordered_by_shared_commits_desc L353–360
+ TestHistoryCursorParsing class class TestHistoryCursorParsing L43–72
+ _decode method method _decode L50–51
+ _encode method method _encode L46–48
+ test_P101_roundtrip_utc method method test_P101_roundtrip_utc L53–56
+ test_P102_cursor_is_comparable method method test_P102_cursor_is_comparable L58–64
+ test_P103_page_size_constant_is_10 method method test_P103_page_size_constant_is_10 L66–68
+ test_P104_coupling_page_size_constant_is_15 method method test_P104_coupling_page_size_constant_is_15 L70–72
+ TestPageSlicing class class TestPageSlicing L106–153
+ _slice method method _slice L110–117
+ test_P108_first_page_returns_page_items method method test_P108_first_page_returns_page_items L119–125
+ test_P109_last_page_has_no_next method method test_P109_last_page_has_no_next L127–132
+ test_P110_exact_fit_no_next method method test_P110_exact_fit_no_next L134–139
+ test_P111_empty_set_returns_empty method method test_P111_empty_set_returns_empty L141–146
+ test_P112_coupling_page_size_15 method method test_P112_coupling_page_size_15 L148–153
+ TestPaginationEdgeCases class class TestPaginationEdgeCases L445–516
+ test_P401_exactly_10_history_no_next method async_method test_P401_exactly_10_history_no_next L448–454
+ test_P402_exactly_11_history_has_next method async_method test_P402_exactly_11_history_has_next L456–461
+ test_P403_exactly_15_coupling_no_next method async_method test_P403_exactly_15_coupling_no_next L463–468
+ test_P404_exactly_16_coupling_has_next method async_method test_P404_exactly_16_coupling_has_next L470–475
+ test_P405_past_cursor_returns_empty_page method async_method test_P405_past_cursor_returns_empty_page L477–490
+ test_P406_both_cursors_on_last_pages_no_links method async_method test_P406_both_cursors_on_last_pages_no_links L492–516
+ TestPaginationHTML class class TestPaginationHTML L369–436
+ test_P301_next_history_link_is_anchor method async_method test_P301_next_history_link_is_anchor L372–379
+ test_P302_next_coupling_link_is_anchor method async_method test_P302_next_coupling_link_is_anchor L381–388
+ test_P303_page_indicator_present method async_method test_P303_page_indicator_present L390–397
+ test_P304_no_controls_when_single_page method async_method test_P304_no_controls_when_single_page L399–404
+ test_P305_cursor_preserved_in_coupling_next_link method async_method test_P305_cursor_preserved_in_coupling_next_link L406–421
+ test_P306_history_next_link_preserves_coupling_cursor method async_method test_P306_history_next_link_preserves_coupling_cursor L423–436
+ TestPaginationPerformance class class TestPaginationPerformance L525–588
+ test_P501_history_page2_same_query_count_as_page1 method async_method test_P501_history_page2_same_query_count_as_page1 L528–555
+ test_P502_coupling_page_uses_offset_not_python_scan method async_method test_P502_coupling_page_uses_offset_not_python_scan L557–574
+ test_P503_render_time_under_300ms method async_method test_P503_render_time_under_300ms L576–588
+ TestPaginationSecurity class class TestPaginationSecurity L597–642
+ test_P601_sql_injection_in_history_cursor method async_method test_P601_sql_injection_in_history_cursor L600–609
+ test_P602_sql_injection_in_coupling_cursor method async_method test_P602_sql_injection_in_coupling_cursor L611–620
+ test_P603_xss_in_history_cursor_escaped method async_method test_P603_xss_in_history_cursor_escaped L622–631
+ test_P604_very_long_cursor_no_500 method async_method test_P604_very_long_cursor_no_500 L633–642
+ TestProvenancePagination class class TestProvenancePagination L162–260
+ test_P201_first_page_returns_10_entries method async_method test_P201_first_page_returns_10_entries L165–173
+ test_P202_first_page_has_next_link method async_method test_P202_first_page_has_next_link L175–181
+ test_P203_last_page_no_next_link method async_method test_P203_last_page_no_next_link L183–206
+ test_P204_no_cursor_shows_newest_first method async_method test_P204_no_cursor_shows_newest_first L208–216
+ test_P205_cursor_page_does_not_overlap_previous method async_method test_P205_cursor_page_does_not_overlap_previous L218–230
+ test_P206_10_or_fewer_entries_no_pagination method async_method test_P206_10_or_fewer_entries_no_pagination L232–239
+ test_P207_history_total_count_in_context method async_method test_P207_history_total_count_in_context L241–248
+ test_P208_invalid_history_cursor_returns_200_first_page method async_method test_P208_invalid_history_cursor_returns_200_first_page L250–260
+ _dt import import _dt L27–27
+ annotations import import annotations L25–25
+ blob_id import import blob_id L29–29
+ pytest import import pytest L28–28
~ musehub/api/routes/musehub/ui_symbols.py .py 3 symbols added, 1 symbol modified
+ _COUPLING_PAGE variable variable _COUPLING_PAGE L204–204
+ _HISTORY_PAGE variable variable _HISTORY_PAGE L203–203
+ _quote import import _quote L206–206
~ tests/conftest.py .py 9 symbols added, 1 symbol modified
+ _seed_coupling_partners function async_function _seed_coupling_partners L730–778
+ _seed_history_entries function async_function _seed_history_entries L699–727
+ seed_symbol_high_coupling_40 function async_function seed_symbol_high_coupling_40 L797–798
+ seed_symbol_with_11_history function async_function seed_symbol_with_11_history L792–793
+ seed_symbol_with_16_coupling function async_function seed_symbol_with_16_coupling L807–808
+ seed_symbol_with_26_history function async_function seed_symbol_with_26_history L782–783
+ seed_symbol_with_26_history_and_40_coupling function async_function seed_symbol_with_26_history_and_40_coupling L812–855
+ seed_symbol_with_exactly_10_history function async_function seed_symbol_with_exactly_10_history L787–788
+ seed_symbol_with_exactly_15_coupling function async_function seed_symbol_with_exactly_15_coupling L802–803
← 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:be7d9f0c983bbbea418ae8edc91aaa091643fab43e32299539488ba8bff1f8f2 --body "your comment"