gabriel / muse public
feat BREAKING code-test feat/49-code-test-cache-audit #1 / 1
AI Agent gabriel · 2 hours ago · Oct 22, 2026 · Diff

feat(code-test): audit cache internals, add cache_hit/--cache-status, close 5 invalidation test gaps (muse#49)

Phase 1-5 of muse#49: - Audit SymbolCache/CallGraphCache: content-addressed per-file memoization, not snapshot-keyed — documented in docs/code-test-internals.md, including a deliberate departure from the ticket's imagined cache_snapshot_id/ head_snapshot_id staleness schema (the data model doesn't support it without a cache redesign, out of scope). - build_forward_graph/symbols_for_snapshot gain an optional stats= dict to observe per-file hit/miss counts without touching their return types or ~30 existing call sites. - SelectionResult gains cache_hit/cache_misses; select_tests emits a warning on the cold-rebuild path. CLI --json surfaces cache_hit. - 5 new regression tests close real cache-invalidation gaps (new-commit invalidation, unchanged-snapshot reuse via read_object/parse_symbols call-count spying, new-import call-graph rebuild, new-test-file not busting unrelated cache, index-rebuild non-interference). - New `muse code test --cache-status [--json]` reports per-file warmth for HEAD without ever parsing anything. - Found and fixed a real pre-existing bug while building --cache-status: `muse code test`'s CLI path never persisted SymbolCache to disk (only CallGraphCache was ever saved), so every real invocation silently re-parsed every file's symbol tree from scratch. - docs/code-test.md: new user-facing reference; select_tests docstring cross-references both docs.

All new/changed behavior TDD-verified with genuine RED/GREEN cycles (mechanism-level assertions, not output-only) and confirmed live via muse-dev against a disposable /tmp repo.

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

sha256:ce542c4d0f6dacc9520c02d0e3378bf96bc377d118a7402f2bbc8af1749b08e0 sha
+99 ~14 symbols
10 changed · 1247 in snapshot files
sha256:ff779c253f2afc03315211a761ae6be075dd0662bd07d93ce4272f19d11ca2ac snapshot
+99
symbols added
~14
symbols modified
10
files changed
1247
files in snapshot
0
dead code introduced
Semantic Changes 113 symbols
~ docs/code-test-internals.md .md 9 symbols added
+ muse code test — Caching Internals (muse#49 audit) section muse code test — Caching Internals (muse#49 audit) L1–164
+ Cache key — content-addressed, not snapshot-addressed section Cache key — content-addressed, not snapshot-addressed L9–30
+ Decision: --cache-status schema departs from the ticket's imagined shape section Decision: --cache-status schema departs from the ticket's imagined shape L118–158
+ Files read, and when section Files read, and when L31–44
+ Invalidation triggers section Invalidation triggers L45–63
+ Out of scope (per ticket, respected) section Out of scope (per ticket, respected) L159–164
+ Real bug found during this audit (not originally in scope, fixed anyway) section Real bug found during this audit (not originally in scope, fixed anyway) L100–117
+ Test-coverage gap map (CT_02) — before this ticket section Test-coverage gap map (CT_02) — before this ticket L79–99
+ Warm/cold performance envelope section Warm/cold performance envelope L64–78
~ docs/code-test.md .md 9 symbols added
+ muse code test — symbol-graph–driven test selection section muse code test — symbol-graph–driven test selection L1–144
+ Caching — why it's fast, and how to tell section Caching — why it's fast, and how to tell L37–111
+ cache_hit in --json output section cache_hit in --json output L52–71
+ muse code test --cache-status section muse code test --cache-status L72–111
+ Flags reference section Flags reference L112–130
+ How it works section How it works L8–21
+ See also section See also L141–144
+ Usage section Usage L22–36
+ Why call-graph selection beats file-name heuristics section Why call-graph selection beats file-name heuristics L131–140
~ tests/test_cache_invalidation_gaps.py .py 27 symbols added
+ PROD_V1 variable variable PROD_V1 L48–51
+ PROD_V2 variable variable PROD_V2 L52–55
+ TEST_V1 variable variable TEST_V1 L56–61
+ TestIndexRebuildDoesNotAffectTestSelectionCache class class TestIndexRebuildDoesNotAffectTestSelectionCache L277–336
+ test_cache_still_warm_after_index_rebuild method method test_cache_still_warm_after_index_rebuild L278–336
+ TestNewCommitInvalidatesChangedFile class class TestNewCommitInvalidatesChangedFile L71–94
+ test_changed_file_is_reparsed_unchanged_file_is_not method method test_changed_file_is_reparsed_unchanged_file_is_not L72–94
+ TestNewImportRebuildsCallGraphAndIncludesNewlyReachableTest class class TestNewImportRebuildsCallGraphAndIncludesNewlyReachableTest L140–205
+ test_newly_reachable_test_appears_after_call_graph_rebuild method method test_newly_reachable_test_appears_after_call_graph_rebuild L141–205
+ TestNewTestFileDoesNotBustUnrelatedCache class class TestNewTestFileDoesNotBustUnrelatedCache L214–263
+ test_adding_test_file_does_not_reparse_unrelated_prod_file method method test_adding_test_file_does_not_reparse_unrelated_prod_file L215–263
+ TestUnchangedSnapshotReusesCache class class TestUnchangedSnapshotReusesCache L103–130
+ test_second_identical_run_reads_no_objects_and_parses_nothing method method test_second_identical_run_reads_no_objects_and_parses_nothing L104–130
+ _base_repo function function _base_repo L43–45
+ _write_file function function _write_file L33–40
+ CallGraphCache import import CallGraphCache L25–25
+ ChangedSymbol import import ChangedSymbol L29–29
+ Manifest import import Manifest L30–30
+ SymbolCache import import SymbolCache L28–28
+ annotations import import annotations L18–18
+ blob_id import import blob_id L30–30
+ muse_dir import import muse_dir L27–27
+ patch import import patch L21–21
+ pathlib import import pathlib L20–20
+ pytest import import pytest L23–23
+ select_tests import import select_tests L29–29
+ write_object import import write_object L26–26
~ tests/test_cache_status.py .py 20 symbols added
+ TestColdAfterCommitBeforeAnyRun class class TestColdAfterCommitBeforeAnyRun L58–74
+ test_committed_file_reported_cold method method test_committed_file_reported_cold L59–74
+ TestFreshRepoGraceful class class TestFreshRepoGraceful L34–55
+ test_no_commits_no_exception_zero_counts method method test_no_commits_no_exception_zero_counts L35–49
+ test_no_muse_repo_at_all_no_exception method method test_no_muse_repo_at_all_no_exception L51–55
+ TestWarmAfterRealRun class class TestWarmAfterRealRun L77–132
+ test_cache_status_reflects_warm_run method method test_cache_status_reflects_warm_run L78–109
+ test_status_never_triggers_a_parse method method test_status_never_triggers_a_parse L111–132
+ CallGraphCache import import CallGraphCache L16–16
+ ChangedSymbol import import ChangedSymbol L20–20
+ CliRunner import import CliRunner L21–21
+ SymbolCache import import SymbolCache L19–19
+ annotations import import annotations L10–10
+ get_cache_status import import get_cache_status L20–20
+ get_head_snapshot_id import import get_head_snapshot_id L17–17
+ pathlib import import pathlib L12–12
+ pytest import import pytest L14–14
+ read_snapshot import import read_snapshot L18–18
+ select_tests import import select_tests L20–20
+ repo function function repo L25–31
~ tests/test_cache_status_fields.py .py 21 symbols added
+ TestColdCacheReportsMiss class class TestColdCacheReportsMiss L62–97
+ test_cold_run_emits_warning method method test_cold_run_emits_warning L80–97
+ test_first_run_cache_hit_false_with_misses method method test_first_run_cache_hit_false_with_misses L63–78
+ TestEmptyChangedAddressesShortCircuit class class TestEmptyChangedAddressesShortCircuit L136–146
+ test_no_changed_symbols_reports_hit_true method method test_no_changed_symbols_reports_hit_true L137–146
+ TestWarmCacheReportsHit class class TestWarmCacheReportsHit L100–133
+ test_second_run_cache_hit_true_zero_misses method method test_second_run_cache_hit_true_zero_misses L101–117
+ test_warm_run_emits_no_cold_warning method method test_warm_run_emits_no_cold_warning L119–133
+ _make_repo function function _make_repo L31–59
+ CallGraphCache import import CallGraphCache L23–23
+ ChangedSymbol import import ChangedSymbol L27–27
+ Manifest import import Manifest L28–28
+ SymbolCache import import SymbolCache L26–26
+ annotations import import annotations L16–16
+ blob_id import import blob_id L28–28
+ logging import import logging L18–18
+ muse_dir import import muse_dir L25–25
+ pathlib import import pathlib L19–19
+ pytest import import pytest L21–21
+ select_tests import import select_tests L27–27
+ write_object import import write_object L24–24
~ muse/cli/commands/test_cmd.py .py 3 symbols added, 10 symbols modified
+ _print_cache_status function function _print_cache_status L443–460
+ CacheStatusResult import import CacheStatusResult L137–137
+ get_cache_status import import get_cache_status L137–137
~ run
~ muse/core/test_selection.py .py 2 symbols added, 2 symbols modified
+ CacheStatusResult class class CacheStatusResult L129–184
+ get_cache_status function function get_cache_status L186–245
~ tests/test_cmd_test.py .py 8 symbols added
+ TestCacheStatusCommand class class TestCacheStatusCommand L318–368
+ test_cache_status_after_run_reports_warm method method test_cache_status_after_run_reports_warm L354–368
+ test_cache_status_before_any_run_reports_cold method method test_cache_status_before_any_run_reports_cold L343–352
+ test_cache_status_json method method test_cache_status_json L326–341
+ test_cache_status_text method method test_cache_status_text L319–324
+ TestSymbolCachePersistedAfterRealRun class class TestSymbolCachePersistedAfterRealRun L371–407
+ test_symbol_cache_file_exists_after_default_diff_run method method test_symbol_cache_file_exists_after_default_diff_run L395–407
+ test_symbol_cache_file_exists_after_forced_symbol_run method method test_symbol_cache_file_exists_after_forced_symbol_run L380–393
Files Changed
+5 ~5
1247 in snapshot
← Older Oldest on feat/49-code-test-cache-audit
All commits
Newer → Latest on feat/49-code-test-cache-audit

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