-
Notifications
You must be signed in to change notification settings - Fork 0
fix: restore service detail fixtures and dashboard H1 copy #855
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,10 +44,9 @@ export default defineConfig({ | |
| screenshot: "only-on-failure", | ||
| // Disable CSS/web animations suite-wide so a click can't land mid-transition | ||
| // on a moving target (documented races in ui-stress/ui-smoke). The dedicated | ||
| // reduced-motion a11y spec emulates it per-test too, so it is unaffected. | ||
| contextOptions: { | ||
| reducedMotion: "reduce", | ||
| }, | ||
| // reduced-motion a11y spec emulates a per-test mode, so suite-wide settings | ||
| // remain stable across builds. | ||
| contextOptions: { reducedMotion: "reduce" }, | ||
| }, | ||
| projects: [ | ||
| { | ||
|
|
@@ -56,6 +55,7 @@ export default defineConfig({ | |
| grepInvert: mockupTag, | ||
| use: { | ||
| ...devices["Desktop Chrome"], | ||
| contextOptions: { reducedMotion: "no-preference" }, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This project-level Useful? React with 👍 / 👎. |
||
| ...(chromiumExecutablePath ? { launchOptions: { executablePath: chromiumExecutablePath } } : {}), | ||
| }, | ||
| }, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,6 +44,13 @@ import type { DocumentIndexUnitMatch, DocumentMemoryCard, SearchResult } from "@ | |
| // the floor, which is how the live schema drift (42702) went unnoticed. Log it structurally and, | ||
| // where telemetry is in scope, record the failing RPC + code so it shows up in rag_retrieval_logs. | ||
| export type SupabaseRpcError = { message?: string; code?: string; details?: string; hint?: string } | null; | ||
| type RpcResult<T> = Promise<{ data: T | null; error: SupabaseRpcError }>; | ||
| type AbortableRpc<T> = RpcResult<T> & { | ||
| abortSignal?: (signal: AbortSignal) => RpcResult<T>; | ||
| }; | ||
| type SupabaseRpcClient = { | ||
| rpc: (name: string, rpcArgs: Record<string, unknown>) => AbortableRpc<unknown[]> | PromiseLike<unknown>; | ||
| }; | ||
|
|
||
| function legacyRankFields(versionedName: string) { | ||
| if (versionedName === "match_document_chunks_v2") return ["similarity"]; | ||
|
|
@@ -81,15 +88,20 @@ export async function callVersionedRetrievalRpc<T extends unknown[] = unknown[]> | |
| versionedName: string, | ||
| legacyName: string, | ||
| args: Record<string, unknown>, | ||
| signal?: AbortSignal, | ||
| ): Promise<{ data: T | null; error: SupabaseRpcError }> { | ||
| const client = supabase as unknown as { | ||
| rpc: (name: string, rpcArgs: Record<string, unknown>) => Promise<{ data: T | null; error: SupabaseRpcError }>; | ||
| const client = supabase as unknown as SupabaseRpcClient; | ||
| const executeRpc = async (name: string, rpcArgs: Record<string, unknown>) => { | ||
| const pending = client.rpc(name, rpcArgs) as AbortableRpc<T>; | ||
| const pendingWithAbort = | ||
| signal && typeof pending.abortSignal === "function" ? pending.abortSignal(signal) : pending; | ||
|
Comment on lines
+96
to
+97
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This helper now knows how to attach an Useful? React with 👍 / 👎. |
||
| return await pendingWithAbort; | ||
| }; | ||
| const versioned = await client.rpc(versionedName, args); | ||
| const versioned = await executeRpc(versionedName, args); | ||
| if (versioned && !isMissingRetrievalRpcError(versioned.error)) return versioned; | ||
| const legacyArgs = { ...args }; | ||
| delete legacyArgs.include_public; | ||
| const ownerResult = await client.rpc(legacyName, legacyArgs); | ||
| const ownerResult = await executeRpc(legacyName, legacyArgs); | ||
| const ownerFilter = String(args.owner_filter ?? ""); | ||
| if ( | ||
| ownerResult.error || | ||
|
|
@@ -99,7 +111,7 @@ export async function callVersionedRetrievalRpc<T extends unknown[] = unknown[]> | |
| ) { | ||
| return ownerResult; | ||
| } | ||
| const publicResult = await client.rpc(legacyName, { | ||
| const publicResult = await executeRpc(legacyName, { | ||
| ...legacyArgs, | ||
| owner_filter: PUBLIC_OWNER_FILTER_SENTINEL, | ||
| }); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,7 @@ import { createAdminClient } from "@/lib/supabase/admin"; | |
| import { retrievalAccessScopeForArgs, retrievalRpcScopeArgs } from "@/lib/owner-scope"; | ||
| import { | ||
| callVersionedRetrievalRpc, | ||
| createChunkLoadCache, | ||
| memoryCardChunkScore, | ||
| mergeSearchResults, | ||
| recordHybridRpcError, | ||
|
|
@@ -11,7 +12,6 @@ import { | |
| searchTableFactCandidates, | ||
| searchTextChunkCandidates, | ||
| withMemoryBoostedCandidates, | ||
| createChunkLoadCache, | ||
| type MemoryCardCache, | ||
| } from "@/lib/rag-candidate-sources"; | ||
| export { | ||
|
|
@@ -120,6 +120,11 @@ export { | |
| retrievalPlanCacheQuery, | ||
| } from "@/lib/rag-cache"; | ||
| import { classifySearchCacheOutcome, recordCacheLookup } from "@/lib/observability/cache-metrics"; | ||
| import { | ||
| recordAnswerOrigination, | ||
| recordAnswerOriginationFinished, | ||
| recordCoalescedAnswerWaiter, | ||
| } from "@/lib/observability/answer-coalescing-metrics"; | ||
| import { buildRagSourceBlock, compactContextText, neutralizeIdentityField } from "@/lib/rag-source-block"; | ||
| export { buildRagSourceBlock, truncateForModel } from "@/lib/rag-source-block"; | ||
| import { | ||
|
|
@@ -423,6 +428,26 @@ function throwIfAborted(signal?: AbortSignal) { | |
| } | ||
| } | ||
|
|
||
| function awaitWithCallerSignal<T>(pending: Promise<T>, signal?: AbortSignal): Promise<T> { | ||
| if (!signal) return pending; | ||
| if (signal.aborted) throw signal.reason ?? new DOMException("The operation was aborted.", "AbortError"); | ||
|
|
||
| return new Promise<T>((resolve, reject) => { | ||
| const onAbort = () => reject(signal.reason ?? new DOMException("The operation was aborted.", "AbortError")); | ||
| signal.addEventListener("abort", onAbort, { once: true }); | ||
| pending.then( | ||
| (value) => { | ||
| signal.removeEventListener("abort", onAbort); | ||
| resolve(value); | ||
| }, | ||
| (error) => { | ||
| signal.removeEventListener("abort", onAbort); | ||
| reject(error); | ||
| }, | ||
| ); | ||
|
Comment on lines
+431
to
+447
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
node - <<'NODE'
const controller = new AbortController();
const reason = new Error("caller cancelled");
controller.abort(reason);
if (controller.signal.reason !== reason) process.exit(1);
NODERepository: BigSimmo/Database Length of output: 155 🏁 Script executed: #!/bin/bash
set -euo pipefail
file="src/lib/rag.ts"
wc -l "$file"
sed -n '410,470p' "$file" | cat -n
printf '\n---\n'
sed -n '1370,1415p' "$file" | cat -nRepository: BigSimmo/Database Length of output: 4351 🏁 Script executed: #!/bin/bash
set -euo pipefail
file="src/lib/rag.ts"
nl -ba "$file" | sed -n '428,450p'
printf '\n---\n'
nl -ba "$file" | sed -n '1388,1405p'Repository: BigSimmo/Database Length of output: 195 Preserve caller cancellations here. Any aborted signal should skip the classifier fallback; custom reasons like 🤖 Prompt for AI Agents |
||
| }); | ||
| } | ||
|
|
||
| export type AnswerProgressEvent = { | ||
| stage: | ||
| | "retrieved" | ||
|
|
@@ -1290,6 +1315,7 @@ export async function analyzeQueryWithClassifierFallback( | |
| // owner_filter retrieval will use so grounding can never see documents retrieval cannot. | ||
| corpusGrounding?: { supabase: ReturnType<typeof createAdminClient>; ownerFilter: string | null }; | ||
| ownerId?: string | null; | ||
| signal?: AbortSignal; | ||
| }, | ||
| ) { | ||
| if ( | ||
|
|
@@ -1361,10 +1387,16 @@ export async function analyzeQueryWithClassifierFallback( | |
| } | ||
|
|
||
| try { | ||
| const verdict = await pending; | ||
| const verdict = await awaitWithCallerSignal(pending, opts?.signal); | ||
| storeClassifierVerdictMemo(memoKey, verdict); | ||
| return applyClassifierVerdict(analysis, verdict); | ||
| } catch { | ||
| } catch (error) { | ||
| if ( | ||
| error && | ||
| (error instanceof DOMException || typeof error === "object") && | ||
| (error as { name?: string }).name === "AbortError" | ||
| ) | ||
| throw error; | ||
| // Transport/parse failures are deliberately NOT memoized: fall back to the deterministic | ||
| // analysis for this request only, and let the next request retry the classifier. | ||
| return analysis; | ||
|
|
@@ -2398,6 +2430,7 @@ export async function searchChunksWithTelemetry(args: SearchChunksArgs) { | |
| const queryAnalysis = await analyzeQueryWithClassifierFallback(retrievalQuery, analyzeClinicalQuery(retrievalQuery), { | ||
| corpusGrounding: corpusGroundingScope, | ||
| ownerId: args.ownerId, | ||
| signal: args.signal, | ||
| }); | ||
|
Comment on lines
2430
to
2434
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win Thread the caller signal into both retrieval RPC calls. Line 2433 cancels classifier waiting, but the hybrid and fallback calls to Proposed fix const { data, error } = await callVersionedRetrievalRpc(
supabase,
"match_document_chunks_hybrid_v2",
"match_document_chunks_hybrid",
{
// ...
},
+ args.signal,
);Apply the same fifth argument to the fallback call around Line 2945. 🤖 Prompt for AI Agents |
||
| throwIfAborted(args.signal); | ||
| if (modeQueryClass) queryAnalysis.queryClass = modeQueryClass; | ||
|
|
@@ -3123,6 +3156,7 @@ export async function answerQuestionWithScope(args: AnswerQuestionWithScopeArgs) | |
| let existing = inflightKey ? answerInflight.get(inflightKey) : undefined; | ||
|
|
||
| while (existing) { | ||
| recordCoalescedAnswerWaiter(); | ||
| await args.onProgress?.({ | ||
| stage: "cached", | ||
| message: "Waiting for an identical cited answer request already in progress.", | ||
|
|
@@ -3154,8 +3188,15 @@ export async function answerQuestionWithScope(args: AnswerQuestionWithScopeArgs) | |
| } | ||
| } | ||
|
|
||
| // Only coalescible requests belong in this process-local signal. Requests | ||
| // that intentionally bypass cache/coalescing must not make a replica look | ||
| // ineffective, and neither keys nor clinical content leave this function. | ||
| if (inflightKey) recordAnswerOrigination(); | ||
| const pending = answerQuestionWithScopeUncoalesced(args, startedAt).finally(() => { | ||
| if (inflightKey) answerInflight.delete(inflightKey); | ||
| if (inflightKey) { | ||
| answerInflight.delete(inflightKey); | ||
| recordAnswerOriginationFinished(); | ||
| } | ||
| }); | ||
| if (inflightKey) answerInflight.set(inflightKey, pending); | ||
| return pending; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the
chromiumproject runs the production specs, including theui-smokeandui-stressfiles selected byproductionSpecPattern, this project-levelcontextOptions: { reducedMotion: "no-preference" }overrides the suite default that was added to keep CSS transitions from moving click targets mid-test. That puts the main Chromium gate back under real animations and reintroduces the documented flake risk for every production Chromium spec just to support one transition assertion; keep the default reduced motion and opt that specific assertion into no-preference withpage.emulateMediaor a dedicated project.Useful? React with 👍 / 👎.