Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
{
Expand Down
7 changes: 1 addition & 6 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,7 @@ import { HomePageClient } from "@/app/home-page-client";
import { appModeHomeHref, isAppModeId, isAppModeVisible, type AppModeId } from "@/lib/app-modes";

type HomeProps = {
searchParams?: Promise<{
mode?: string | string[];
q?: string | string[];
focus?: string | string[];
run?: string | string[];
}>;
searchParams?: Promise<Record<string, string | string[] | undefined>>;
};

function firstSearchParam(value: string | string[] | undefined) {
Expand Down
8 changes: 4 additions & 4 deletions src/components/ClinicalDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3716,6 +3716,10 @@ export function ClinicalDashboard({
</div>
) : null)}

{showUniversalAlsoMatches && activeModeResultKind === "tools" ? (
<UniversalSearchAlsoMatches modeId={searchMode} query={universalAlsoMatchesQuery} />
) : null}

{activeModeResultKind === "differentials" ? (
<DifferentialsHome
query={query}
Expand Down Expand Up @@ -3876,10 +3880,6 @@ export function ClinicalDashboard({
/>
) : null}

{showUniversalAlsoMatches && activeModeResultKind !== "answer" ? (
<UniversalSearchAlsoMatches modeId={searchMode} query={universalAlsoMatchesQuery} />
) : null}

{showUniversalAlsoMatches && activeModeResultKind === "answer" ? (
<UniversalSearchAlsoMatches modeId={searchMode} query={universalAlsoMatchesQuery} />
) : null}
Expand Down
37 changes: 16 additions & 21 deletions src/components/forms/forms-search-results-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,7 @@ type FormsSearchResultsPageProps = {
query: string;
};

const sourceSnippetCount = 278;
const taskCount = 8;
const pathwayCount = 12;
const supportsPathwayClaims = false;
Comment thread
BigSimmo marked this conversation as resolved.
Comment thread
BigSimmo marked this conversation as resolved.

const refineFilters: {
icon: LucideIcon;
Expand All @@ -59,7 +57,9 @@ const refineFilters: {
}[] = [
{ icon: Shield, title: "High risk only", subtitle: "Show high risk forms", enabled: false, danger: true },
{ icon: FileText, title: "Official forms", subtitle: "Limit to official forms", enabled: true },
{ icon: Workflow, title: "Pathway linked", subtitle: "Show pathway-linked", enabled: true },
...(supportsPathwayClaims
? [{ icon: Workflow, title: "Pathway linked", subtitle: "Show pathway-linked", enabled: true }]
: []),
{ icon: Search, title: "Source matches", subtitle: "Require source match", enabled: false },
];

Expand All @@ -86,17 +86,14 @@ function compactMatchReason(match: FormSearchMatch, query: string) {
if (match.reasons.includes("title")) {
return trimmedQuery ? `Title or content match for "${trimmedQuery}"` : "Title or content match";
}
if (match.reasons.includes("record fields")) return "Content match in related pathway";
if (match.reasons.includes("record fields")) return "Content match in record details";
return "Content match in the forms catalogue";
}

function ResultTabs({ formsCount }: { formsCount: number }) {
const tabs = [
["Results", null],
["Forms", formsCount],
["Evidence", sourceSnippetCount],
["Pathways", pathwayCount],
["Tasks", taskCount],
] as const;

return (
Expand Down Expand Up @@ -669,14 +666,16 @@ function FormsSearchResultsPageContent({ query }: FormsSearchResultsPageProps) {
</div>
<div className="flex items-center gap-2 pb-1.5">
<ResultSortControl value={sortValue} onChange={setSortValue} className="md:hidden" />
<RefineBar
open={refineOpen}
onToggle={() => setRefineOpen((open) => !open)}
panelId={refinePanelId}
/>
{supportsPathwayClaims ? (
<RefineBar
open={refineOpen}
onToggle={() => setRefineOpen((open) => !open)}
panelId={refinePanelId}
/>
) : null}
</div>
</div>
<RefinePanel open={refineOpen} panelId={refinePanelId} />
{supportsPathwayClaims ? <RefinePanel open={refineOpen} panelId={refinePanelId} /> : null}
<div className="hidden md:block">
<ResultsTable matches={displayedMatches} query={query} sortValue={sortValue} />
</div>
Expand All @@ -688,13 +687,9 @@ function FormsSearchResultsPageContent({ query }: FormsSearchResultsPageProps) {
<UniversalSearchAlsoMatches modeId="forms" query={query} />
</>
) : null}
<div className="hidden lg:block">
<PathwayPanel />
</div>
<div className="lg:hidden">
<MobilePathway />
</div>
{registryReady ? <VerifiedFooter /> : null}
<div className="hidden lg:block">{supportsPathwayClaims ? <PathwayPanel /> : null}</div>
<div className="lg:hidden">{supportsPathwayClaims ? <MobilePathway /> : null}</div>
{registryReady && supportsPathwayClaims ? <VerifiedFooter /> : null}
</main>
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion src/components/route-error-boundary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export function RouteErrorBoundary({
<h1
ref={headingRef}
tabIndex={-1}
className="mt-4 text-lg font-semibold tracking-tight text-[color:var(--text-heading)] focus:outline focus:outline-2 focus:outline-offset-2 focus:outline-[color:var(--focus-ring,Highlight)]"
className="mt-4 text-lg font-semibold tracking-tight text-[color:var(--text-heading)] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[color:var(--focus-ring,Highlight)]"
>
{title}
</h1>
Expand Down
35 changes: 30 additions & 5 deletions src/lib/rag-candidate-sources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"];
Expand Down Expand Up @@ -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;
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);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
const ownerFilter = String(args.owner_filter ?? "");
if (
ownerResult.error ||
Expand All @@ -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,
});
Expand Down Expand Up @@ -179,6 +191,7 @@ export async function searchTextChunkCandidates(args: {
allowGlobalSearch?: boolean;
matchCount: number;
telemetry?: SearchTelemetry;
signal?: AbortSignal;
}) {
const runChunkText = async (queryText: string, matchCount: number) => {
const accessScope = retrievalAccessScopeForArgs(args);
Expand All @@ -192,6 +205,7 @@ export async function searchTextChunkCandidates(args: {
document_filters: args.documentIds ?? undefined,
...retrievalRpcScopeArgs(accessScope),
},
args.signal,
);
// Report the error before returning empty so a schema drift on this
// most-terminal lexical layer surfaces in hybrid_rpc_errors telemetry
Expand Down Expand Up @@ -376,6 +390,7 @@ async function fetchBestDocumentLookupChunks(args: {
ownerId?: string;
accessScope?: RetrievalAccessScope;
allowGlobalSearch?: boolean;
signal?: AbortSignal;
}) {
const terms = documentLookupChunkTerms(args.query);
const { data: rpcChunks, error: rpcError } = await callVersionedRetrievalRpc(
Expand All @@ -388,6 +403,7 @@ async function fetchBestDocumentLookupChunks(args: {
match_count: Math.max(args.limit * 3, 24),
...retrievalRpcScopeArgs(retrievalAccessScopeForArgs(args)),
},
args.signal,
);
if (!rpcError && rpcChunks?.length) {
const ranked = (rpcChunks as DocumentLookupChunkRow[])
Expand Down Expand Up @@ -499,6 +515,7 @@ export async function searchDocumentLookupFastPath(args: {
documentIds?: string[];
matchCount: number;
telemetry?: SearchTelemetry;
signal?: AbortSignal;
}): Promise<SearchResult[]> {
if (!args.ownerId) return [] as SearchResult[];
const variants = (args.queryVariants?.length ? args.queryVariants : [buildClinicalTextSearchQuery(args.query)]).slice(
Expand All @@ -515,6 +532,7 @@ export async function searchDocumentLookupFastPath(args: {
match_count: matchCount,
...retrievalRpcScopeArgs(retrievalAccessScopeForArgs(args)),
},
args.signal,
);
if (error) recordHybridRpcError(args.telemetry, "match_documents_for_query", error);
if (error || !data?.length) return [] as DocumentLookupRow[];
Expand Down Expand Up @@ -566,6 +584,7 @@ export async function searchDocumentLookupFastPath(args: {
limit: Math.max(args.matchCount, rankedDocuments.length * 4),
ownerId: args.ownerId,
accessScope: args.accessScope,
signal: args.signal,
});

if (!chunks.length) return [];
Expand Down Expand Up @@ -930,6 +949,7 @@ export async function searchTableFactCandidates(args: {
matchCount: number;
telemetry?: SearchTelemetry;
cache?: ChunkLoadCache;
signal?: AbortSignal;
}) {
const variants = (args.queryVariants?.length ? args.queryVariants : [buildClinicalTextSearchQuery(args.query)]).slice(
0,
Expand All @@ -946,6 +966,7 @@ export async function searchTableFactCandidates(args: {
document_filters: args.documentIds ?? undefined,
...retrievalRpcScopeArgs(retrievalAccessScopeForArgs(args)),
},
args.signal,
);
if (error) recordHybridRpcError(args.telemetry, "match_document_table_facts_text", error);
if (error || !data?.length) return [] as TableFactRpcRow[];
Expand Down Expand Up @@ -1002,6 +1023,7 @@ export async function searchEmbeddingFieldCandidates(args: {
matchCount: number;
telemetry?: SearchTelemetry;
cache?: ChunkLoadCache;
signal?: AbortSignal;
}) {
const { data, error } = await callVersionedRetrievalRpc(
args.supabase,
Expand All @@ -1015,6 +1037,7 @@ export async function searchEmbeddingFieldCandidates(args: {
document_filters: args.documentIds ?? undefined,
...retrievalRpcScopeArgs(retrievalAccessScopeForArgs(args)),
},
args.signal,
);
if (error) recordHybridRpcError(args.telemetry, "match_document_embedding_fields_hybrid", error);
if (error || !data?.length) return [] as SearchResult[];
Expand Down Expand Up @@ -1067,6 +1090,7 @@ export async function searchIndexUnitCandidates(args: {
matchCount: number;
telemetry?: SearchTelemetry;
cache?: ChunkLoadCache;
signal?: AbortSignal;
}) {
const { data, error } = await callVersionedRetrievalRpc(
args.supabase,
Expand All @@ -1080,6 +1104,7 @@ export async function searchIndexUnitCandidates(args: {
document_filters: args.documentIds ?? undefined,
...retrievalRpcScopeArgs(retrievalAccessScopeForArgs(args)),
},
args.signal,
);
if (error) recordHybridRpcError(args.telemetry, "match_document_index_units_hybrid", error);
if (error || !data?.length) return [] as SearchResult[];
Expand Down
Loading