perf(citation-verification): cache view + parallelize backend retrieval
The "אימות פסיקה" tab reloaded its data on every tab revisit and the first load took 1.5–3s. Two independent causes, two fixes: Frontend (web-ui/src/lib/api/citation-verification.ts): - staleTime 10s → 5min and refetchOnMount: false. Radix Tabs unmounts inactive TabsContent, so switching back used to trigger a full rebuild once the 10s window elapsed. Verify mutations still invalidate the query, so edits pull fresh data. Backend (mcp-server/.../case_citation_verification.py): - The per-argument loop ran a Voyage embed + vector search + batched authority query sequentially (N args × ~300ms waterfall). Extracted to _fetch() and fanned out with asyncio.gather — order preserved, n_verified counter and per-argument seen-sets unchanged. First load ~5× faster on multi-argument cases. Pure read/assembly — no new parallel path (G2), no silent error swallowing (search/radar still log warnings). Invariants: INV-DIG1/INV-AH unaffected (still read-only, never cites). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,7 @@ rows. Reuses the one corpus search + the one authority query + the one radar (G2
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from uuid import UUID
|
||||
|
||||
@@ -65,25 +66,37 @@ async def build_view(case_number: str) -> dict:
|
||||
except Exception as e: # noqa: BLE001 — radar is best-effort
|
||||
logger.warning("citation_verification radar failed for %s: %s", case_number, e)
|
||||
|
||||
out_args: list[dict] = []
|
||||
n_verified = 0
|
||||
for a in args:
|
||||
aid = str(a["id"])
|
||||
async def _fetch(a: dict) -> tuple[list[dict], dict]:
|
||||
"""Per-argument corpus search + batched authority — run concurrently.
|
||||
|
||||
Each call is one Voyage embed + one vector search (+ one batched authority
|
||||
query); independent across arguments, so they fan out rather than waterfall.
|
||||
"""
|
||||
title = (a.get("argument_title") or "").strip()
|
||||
topic = (a.get("legal_topic") or "").strip()
|
||||
query = f"{ctx} {title}. {topic}".strip()
|
||||
|
||||
hits = []
|
||||
hits: list[dict] = []
|
||||
try:
|
||||
hits = await precedent_library.search_library(
|
||||
query=query, limit=_SUGGEST_PER_ISSUE, include_halachot=True)
|
||||
except Exception as e: # noqa: BLE001
|
||||
logger.warning("citation_verification search failed (%s): %s", title[:30], e)
|
||||
|
||||
# Resolve the authority breakdown for the hit set in one batched query.
|
||||
clids = [UUID(str(h["case_law_id"])) for h in hits
|
||||
if h.get("case_law_id") and float(h.get("score", 0) or 0) >= _SUGGEST_FLOOR]
|
||||
authority = await db.citation_authority(clids) if clids else {}
|
||||
return hits, authority
|
||||
|
||||
# Fan out the expensive per-argument retrieval concurrently — was a sequential
|
||||
# waterfall (N args × Voyage embed + vector search each). gather preserves order.
|
||||
fetched = await asyncio.gather(*(_fetch(a) for a in args)) if args else []
|
||||
|
||||
out_args: list[dict] = []
|
||||
n_verified = 0
|
||||
for a, (hits, authority) in zip(args, fetched):
|
||||
aid = str(a["id"])
|
||||
title = (a.get("argument_title") or "").strip()
|
||||
topic = (a.get("legal_topic") or "").strip()
|
||||
|
||||
seen: set[str] = set()
|
||||
supporting: list[dict] = []
|
||||
|
||||
@@ -84,7 +84,13 @@ export function useCitationVerification(caseNumber: string | undefined) {
|
||||
{ signal },
|
||||
),
|
||||
enabled: Boolean(caseNumber),
|
||||
staleTime: 10_000,
|
||||
// The view is an expensive synthesized build (per-argument Voyage embed +
|
||||
// vector search on the backend). Keep it fresh for 5 min and do NOT refetch
|
||||
// on remount — Radix Tabs unmounts inactive TabsContent, so every tab switch
|
||||
// back used to trigger a full rebuild. Verify mutations invalidate the query,
|
||||
// so edits still pull fresh data.
|
||||
staleTime: 5 * 60_000,
|
||||
refetchOnMount: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user