Skip to content

perf: remove serial dead weight from the answer hot path (round 2, phase 3)#480

Merged
BigSimmo merged 1 commit into
claude/perf-r2-network-cachingfrom
claude/perf-r2-hot-path
Jul 11, 2026
Merged

perf: remove serial dead weight from the answer hot path (round 2, phase 3)#480
BigSimmo merged 1 commit into
claude/perf-r2-network-cachingfrom
claude/perf-r2-hot-path

Conversation

@BigSimmo

Copy link
Copy Markdown
Owner

Summary

Phase 3 of the round-2 performance initiative (stacked on #479). Results-identical orchestration changes on the answer hot path — no retrieval behavior, ranking, or scoring is touched, so no eval gate applies (per docs/capacity-review.md this PR deliberately stays on the orchestration side of that line).

  1. Cache miss probe off the hot path. Every generic shared-cache miss ran a second rag_response_cache query purely to classify the miss reason before retrieval could start. The probe now runs detached and patches telemetry when it lands (pending_probe placeholder; query logging happens after generation so the classified reason still wins in practice). Saves one serial DB round trip on every cold answer.
  2. Rate-limit ∥ scope resolution. Both depend only on the access context; they now overlap in /api/answer and /api/answer/stream. The rate limit still rejects before any retrieval or generation.
  3. AbortSignal on the retrieval RPC fan-out. All 9 match_*/correction RPC sites are now bounded by the caller's signal via a withAbort helper — a client disconnect cancels in-flight Postgres work and frees the pooled connection (previously throwIfAborted only checked between stages, so up to 10–14 RPCs ran to completion for a caller that had already gone). Aborted RPCs resolve through the existing error branches; the pipeline unwinds at the next stage check. Addresses the reliability finding that the fan-out had no server-side time-bounding tied to the request.
  4. Anonymous scope cache (60s). Anonymous public-scope resolution enumerated every public indexed document (paginated, up to the 5000-doc ceiling) on each request. The zero-filter default scope is now cached per client instance (WeakMap: the prod admin singleton shares one entry; test mocks stay isolated), with defensive clones on both sides. Authenticated scope resolution is untouched (it already early-returns without a query).

Verification

  • tsc, eslint, prettier clean
  • Targeted vitest: search-scope, rag-cache-utils, rag-cache-invalidation, owner-scope, api-validation-contract, private-access-routes, rag-answer-fallback, answer-telemetry — all green
  • Retrieval results are bit-identical by construction: no query, ranking, or selection logic changed; only when independent I/O runs and whether doomed I/O is cancelled

🤖 Generated with Claude Code

Round-2 phase 3 (results-identical orchestration; no retrieval behavior
change).

- Shared-cache miss classification no longer blocks retrieval: the probe that
  cost a full extra rag_response_cache round trip on every generic miss now
  runs off-path and patches telemetry when it resolves (reason starts as
  "pending_probe"; query logging happens after generation, so the classified
  value wins in practice). Lookup-derived reasons stay synchronous.
- /api/answer runs the rate-limit consume and the read-only scope resolution
  concurrently instead of serially; the limit still rejects before retrieval
  or generation starts. /api/answer/stream kicks scope resolution off next to
  the rate-limit consume and awaits it inside the stream (detached catch marks
  a pre-await rejection handled; the stream's own await reports the error).
- Every retrieval match_* RPC (9 sites: chunk text, trigram correction,
  document lookup, documents-for-query, table facts, embedding-field hybrid,
  index-unit hybrid, chunk hybrid, vector fallback) is now bounded by the
  caller's AbortSignal via a withAbort helper, so a client disconnect cancels
  in-flight Postgres work and frees the pooled connection. throwIfAborted only
  checked between stages; aborted RPCs resolve through the existing error
  branches and the pipeline unwinds at the next stage check.
- Anonymous public-scope resolution (a paginated enumeration of every public
  indexed document per request) is cached for 60s, keyed by client instance
  (WeakMap) so the production admin singleton shares one entry while tests
  stay isolated. Only the zero-filter default scope is cached; the resolved
  object is defensively cloned on read and write.

Verified: tsc, eslint, prettier; targeted vitest (search-scope, rag-cache,
owner-scope, api-validation-contract, private-access-routes,
rag-answer-fallback, answer-telemetry) all green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@supabase

supabase Bot commented Jul 11, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 46920988-e704-4c06-ac76-95a918c27d77

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/perf-r2-hot-path
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch claude/perf-r2-hot-path

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 848fa9248a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// Independent given `access`: the rate-limit consume and the read-only
// scope resolution overlap instead of running serially. The limit still
// rejects before any retrieval or generation starts.
const [rateLimit, scope] = await Promise.all([

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep scope resolution behind the rate-limit gate

When a subject is already over the answer limit, this Promise.all still starts and waits for resolveSearchScope before the 429 branch can run. For uncached anonymous scopes, filters, or explicit document IDs, scope resolution can page through documents/labels; if that read is slow or fails, a request that should be a cheap 429 is delayed or becomes a 500, and the stream route now starts the same scope work before its rate-limit check as well. A focused regression test would make the limiter return limited: true and the documents query throw, and assert the route returns 429 without touching scope queries.

Useful? React with 👍 / 👎.

@BigSimmo
BigSimmo merged commit 424ae6b into claude/perf-r2-network-caching Jul 11, 2026
4 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