Calendar Day
Wednesday, June 17, 2026 (PR 1 of 2)
Planned Effort
5 story points — sprint item #4 (Medium)
Blocks: Wednesday PR 2 (benchmark gate #6) — baselines must be captured after the cache lands.
Problem
Every session-touching request calls parse_session(filepath) from disk. get_session() and get_session_stats() parse the same file twice; search() re-parses the entire corpus per query (500+ sessions in the power-user scenario). No in-memory cache, no mtime invalidation, no reuse across requests.
Goal
One merged PR that adds an mtime-invalidated, LRU-bounded session cache and routes all parse-backed API modules through it, with identical JSON responses and a repeated-access benchmark.
Scope
New module: utils/session_cache.py
- Key: absolute file path; value:
(mtime, SessionDict)
- Invalidate on
os.path.getmtime() change
- LRU eviction (default max 200 entries)
threading.Lock for --debug reloader safety
- Public API:
get_cached_session(path) -> SessionDict, clear_cache() for tests
Wire routes
api/sessions.py — get_session + get_session_stats share one cached parse
api/search.py, api/projects.py, api/export_api.py — replace direct parse_session calls
Benchmark
- New repeated-access bench in
tests/benchmarks/ (cold vs warm hit)
tests/benchmarks/test_parse_memory.py still passes
Acceptance Criteria
Verification
cd C:\Users\Jasen\CppAliance\claude-code-chat-browser
.\.venv\Scripts\Activate.ps1
pytest -q
pytest tests/benchmarks/test_parse_memory.py -q
mypy -p api -p utils -p models
Out of Scope
Calendar Day
Wednesday, June 17, 2026 (PR 1 of 2)
Planned Effort
5 story points — sprint item #4 (Medium)
Blocks: Wednesday PR 2 (benchmark gate #6) — baselines must be captured after the cache lands.
Problem
Every session-touching request calls
parse_session(filepath)from disk.get_session()andget_session_stats()parse the same file twice;search()re-parses the entire corpus per query (500+ sessions in the power-user scenario). No in-memory cache, no mtime invalidation, no reuse across requests.Goal
One merged PR that adds an mtime-invalidated, LRU-bounded session cache and routes all parse-backed API modules through it, with identical JSON responses and a repeated-access benchmark.
Scope
New module:
utils/session_cache.py(mtime, SessionDict)os.path.getmtime()changethreading.Lockfor--debugreloader safetyget_cached_session(path) -> SessionDict,clear_cache()for testsWire routes
api/sessions.py—get_session+get_session_statsshare one cached parseapi/search.py,api/projects.py,api/export_api.py— replace directparse_sessioncallsBenchmark
tests/benchmarks/(cold vs warm hit)tests/benchmarks/test_parse_memory.pystill passesAcceptance Criteria
utils/session_cache.pystores parsedSessionDictobjects keyed by absolute file pathos.path.getmtime()changes — edits picked up without restartOrderedDictorfunctools.lru_cache)api/sessions.pyroutes use the cache —get_session()andget_session_stats()share one cached parseapi/search.pyuses the cache, reducing disk I/O for repeated searchesapi/projects.pyandapi/export_api.pyuse the cachetests/benchmarks/measures repeated-access latency (cold parse vs. cached hit)test_parse_memory.pypassesVerification
Out of Scope
quick_session_infolightweight cache (optional; keep simple if time is tight)