Skip to content

feat(core,observability): Cache SPI split + async telemetry (Step 1.1e)#51

Merged
officialCodeWork merged 1 commit into
mainfrom
build/phase-1/step-1.1e-cache-split-perf-telemetry
May 24, 2026
Merged

feat(core,observability): Cache SPI split + async telemetry (Step 1.1e)#51
officialCodeWork merged 1 commit into
mainfrom
build/phase-1/step-1.1e-cache-split-perf-telemetry

Conversation

@officialCodeWork

Copy link
Copy Markdown
Owner

Summary

  • Adds three distinct cache SPIs (rag_core.spi.{embedding,retrieval,answer}_cache), each with a different cache key and a different invalidation contract per caching.md:
    • EmbeddingCache(tenant, model_id, model_version, text_hash); invalidate_model(...).
    • RetrievalCache(tenant, plan_hash, corpus_version); invalidate_corpus(...).
    • AnswerCache(tenant, plan_hash, corpus_version, policy_version); invalidate_policy(...).
  • Adds AsyncTelemetrySink in rag-observability — bounded buffer (default 10 000), non-blocking submit(), per-kind drop + exporter-error counters, idempotent start/stop, drain-timeout cancel.
  • Extends tests/contract/spi_signature.py to enforce ctx-first on the three new caches.
  • Expands performance.md hot-path discipline with a concrete hot/cold call-site table and rewrites the async-telemetry section around AsyncTelemetrySink (counters, alerting).
  • rag-core 0.6.0 → 0.7.0.

Step 1.1e of the Phase 1 refactor window (1.1a–1.1f). Last remaining step in the window is 1.1f (ADRs 0005–0009 finalized + reviewer checklist).

Tests

  • 27 new tests: 18 cache conformance tests (hit/miss, version partitioning, invalidate semantics, tenant isolation across all three SPIs) + 9 AsyncTelemetrySink tests (drain ordering, drops under simulated back-pressure, exporter-exception swallowing, idempotent lifecycle, drain-timeout cancellation).
  • Full repo: 576 passed, 1 skipped (up from 549).
  • mypy --strict clean across the workspace (67 source files).
  • ruff check . clean.
  • Schema regen — no drift.

Documentation

Per the per-PR docs requirement (CLAUDE.md):

  • Updated: caching.md (SPI signatures now ctx-first; extension-point block lists canonical shapes incl. invalidate_*).
  • Updated: performance.md (hot/cold call-site table + AsyncTelemetrySink section).
  • Updated: rag-core.md (Cache SPIs section).
  • New: rag-observability.md — package reference, including AsyncTelemetrySink usage and alerting guidance.
  • Updated: docs/README.md (reference index).

Tracker

Test plan

  • uv run pytest tests/contract/test_embedding_cache.py tests/contract/test_retrieval_cache.py tests/contract/test_answer_cache.py -x
  • uv run pytest tests/observability/test_async_sink.py -x
  • uv run pytest tests/ packages/ -k "not integration" — 576 passed
  • uv run ruff check . clean
  • uv run mypy packages/core/ packages/observability/ apps/gateway/ clean
  • PYTHONPATH=... uv run python -m rag_core.gen_schemas dist/schemas/ — no drift
  • SPI signature linter passes (cache SPIs registered)

🤖 Generated with Claude Code

…p 1.1e)

Adds the three distinct cache SPIs the platform needs (each with a
different key and invalidation contract) plus the bounded, drop-on-
overflow telemetry path that decouples the request path from any
exporter back-pressure.

Cache SPIs (rag_core.spi)
-------------------------
- ``EmbeddingCache`` — key ``(tenant_id, model_id, model_version,
  text_hash)``; ``invalidate_model(ctx, model_id, model_version)`` for
  model rotation. Survives re-chunking; target hit rate ≥ 99% on
  identical re-ingest.
- ``RetrievalCache`` — key ``(tenant_id, plan_hash, corpus_version)``;
  ``invalidate_corpus(ctx, corpus_id)`` called by the write path on
  any successful upsert/delete. Stores ``list[ChunkRef]``; target hit
  rate ≥ 30%.
- ``AnswerCache`` — key ``(tenant_id, plan_hash, corpus_version,
  policy_version)``; ``invalidate_policy(ctx, policy_version)`` called
  by the control plane on policy rotation. Stores opaque bytes; target
  hit rate ≥ 15%.

All three are ``ctx``-first; ``tests/contract/spi_signature.py``
extended to cover them. Noop in-memory reference impls live in
``rag_core.spi.noop``. The base ``Cache`` SPI is retained for generic
byte-level caching needs.

Async telemetry sink (rag_observability)
----------------------------------------
- ``AsyncTelemetrySink(export_fn, *, max_buffer=10_000,
  drain_timeout_s=5.0)`` — bounded ``asyncio.Queue`` fronting any async
  exporter. ``submit(record, kind=...)`` is non-blocking and returns
  ``False`` on a full queue. Per-kind drop and exporter-error counters
  are surfaceable as ``telemetry.dropped_total{kind}`` and
  ``telemetry.export_errors_total{kind}``.
- Idempotent ``start()`` / ``stop()``; cooperative drain with timeout.
- Records submitted before ``start()`` are queued; the drainer flushes
  them once started.

Tests
-----
- 18 new conformance tests across the three caches (hit/miss, version
  partition, invalidate semantics, tenant isolation).
- 9 new sink tests covering drain ordering, drops under simulated
  back-pressure, exporter-exception swallowing, idempotent lifecycle,
  drain-timeout cancellation.
- Full suite: **576 passed**, 1 skipped (was 549 before this step).
- ``mypy --strict`` clean across the workspace (67 source files).

Documentation
-------------
- Updated [caching.md](../architecture/caching.md): SPI signatures now
  show ``ctx`` as first arg; extension-point block lists the canonical
  shapes including ``invalidate_*`` methods.
- Updated [performance.md](../architecture/performance.md): hot-path
  discipline section gains a concrete hot/cold call-site table; async
  telemetry section rewritten around ``AsyncTelemetrySink`` with
  counter / alerting guidance.
- Updated [rag-core.md](../reference/rag-core.md): new Cache SPIs
  section.
- New [rag-observability.md](../reference/rag-observability.md):
  package reference covering logger, event registry, and the new
  ``AsyncTelemetrySink``.

``rag-core`` 0.6.0 → 0.7.0.

Step 1.1e of the Phase 1 refactor window. Last remaining step in the
window is 1.1f (ADRs 0005–0009 finalized + reviewer checklist).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@officialCodeWork
officialCodeWork merged commit 8af5e90 into main May 24, 2026
11 checks passed
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