Skip to content

Cache rationale cards in SQLite#12

Open
cvetty wants to merge 1 commit into
mainfrom
feature/rationale-cache
Open

Cache rationale cards in SQLite#12
cvetty wants to merge 1 commit into
mainfrom
feature/rationale-cache

Conversation

@cvetty
Copy link
Copy Markdown
Contributor

@cvetty cvetty commented May 23, 2026

Summary

whygraph_rationale_brief used to call the LLM on every invocation. This PR adds a SQLite-backed cache keyed by (path, line_start, line_end, provider, model) and invalidated by a sha256 fingerprint of the sorted commit SHAs returned by collect_evidence. New commits landing on the blamed lines change the fingerprint and force a regeneration; the stale row is overwritten by the next store.

The cache PK uses the configured provider/model so the lookup is deterministic before the LLM call returns. config.model = None is translated to the literal "default" token; the LLM-reported identity persists separately in actual_provider / actual_model so rows keyed under "default" keep their provenance. The MCP response now carries a cached_at ISO-8601 UTC timestamp on both fresh and cached returns so agents can surface staleness.

Changes

  • New RationaleCache SQLModel (db/models/rationale_cache.py), registered in db/models/__init__.py.
  • Alembic migration b4de974b9f54_add_rationale_cache.py, hand-written to mirror the initial-schema migration's shape.
  • Cache helpers in mcp/rationale_cache.pylookup_cached, store_cached, evidence fingerprint, session.merge() upsert.
  • mcp/rationale.py consults the cache before generating and stores on miss; response shape extracted into _format_response.
  • Tests in test_mcp_rationale_cache.py cover second-call-cached, new-commit-invalidates, stale-fingerprint miss, and fingerprint order-independence.

`whygraph_rationale_brief` used to call the LLM on every invocation.
Add a SQLite-backed cache keyed by
`(path, line_start, line_end, provider, model)` and invalidated by the
sha256 fingerprint of the sorted commit SHAs from `collect_evidence`.
New commits landing on the blamed lines change the fingerprint and
force a regeneration; the stale row is overwritten by the next store.

The cache PK uses the *configured* provider/model so the lookup is
deterministic before the LLM call. `config.model = None` is translated
to the literal `"default"` token; the LLM-reported provider/model
identity persists separately in `actual_provider` / `actual_model` so
rows keyed under `"default"` keep their provenance.

The MCP response now carries a `cached_at` ISO-8601 UTC timestamp on
both fresh and cached returns so agents can surface staleness.

- New SQLModel `RationaleCache` (`db/models/rationale_cache.py`),
  registered in `db/models/__init__.py`.
- Alembic migration `b4de974b9f54_add_rationale_cache.py`
  (hand-written; mirrors the initial-schema migration's shape).
- Cache helpers (`mcp/rationale_cache.py`): `lookup_cached`,
  `store_cached`, evidence fingerprint, `session.merge()` upsert.
- Tests: `test_mcp_rationale_cache.py` covers second-call-cached,
  new-commit-invalidates, stale-fingerprint miss, and fingerprint
  order-independence.
- `test_db_plumbing.py` table-set updated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant