Gap {index + 1}
-{warning}
-From 3f38a33f47eeb80c4a9b5b7500852b7cd7a55644 Mon Sep 17 00:00:00 2001
From: BigSimmo <87357024+BigSimmo@users.noreply.github.com>
Date: Sun, 5 Jul 2026 20:12:10 +0800
Subject: [PATCH 1/3] Reconcile search_schema_health index drift on live
Supabase
Create missing retrieval-support indexes (trgm, composite btree, partial
miss log) that were absent or only present under legacy names on live.
Update search_schema_health() to accept verified functional equivalents
during rollout. Set search_path for pg_trgm gin_trgm_ops in extensions.
Verified on linked project: search_schema_health() ok=true, missing=[].
---
...180000_reconcile_search_health_indexes.sql | 202 ++++++++++++++++++
supabase/schema.sql | 22 ++
tests/supabase-schema.test.ts | 15 ++
3 files changed, 239 insertions(+)
create mode 100644 supabase/migrations/20260705180000_reconcile_search_health_indexes.sql
diff --git a/supabase/migrations/20260705180000_reconcile_search_health_indexes.sql b/supabase/migrations/20260705180000_reconcile_search_health_indexes.sql
new file mode 100644
index 000000000..21e0c281d
--- /dev/null
+++ b/supabase/migrations/20260705180000_reconcile_search_health_indexes.sql
@@ -0,0 +1,202 @@
+-- Reconcile live index drift reported by search_schema_health() on 2026-07-05.
+-- Creates canonical retrieval-support indexes that are missing on live (or only
+-- present under legacy names) and teaches search_schema_health() to accept
+-- verified functional equivalents so replays do not false-fail mid-rollout.
+
+set search_path = public, extensions, pg_catalog;
+
+create index if not exists documents_title_trgm_idx
+ on public.documents using gin (lower(coalesce(title, '') || ' ' || coalesce(file_name, '')) gin_trgm_ops);
+
+create index if not exists document_chunks_content_trgm_idx
+ on public.document_chunks using gin (lower(coalesce(section_heading, '') || ' ' || coalesce(content, '')) gin_trgm_ops);
+
+create index if not exists document_labels_label_trgm_idx
+ on public.document_labels using gin (lower(label) gin_trgm_ops);
+
+create index if not exists document_summaries_summary_trgm_idx
+ on public.document_summaries using gin (lower(summary) gin_trgm_ops);
+
+create index if not exists document_table_facts_owner_document_page_idx
+ on public.document_table_facts(owner_id, document_id, page_number);
+
+create index if not exists document_index_units_owner_chunk_type_idx
+ on public.document_index_units(owner_id, source_chunk_id, unit_type)
+ where source_chunk_id is not null;
+
+create index if not exists document_pages_document_idx
+ on public.document_pages(document_id, page_number);
+
+create index if not exists document_sections_document_idx
+ on public.document_sections(document_id, section_index);
+
+create index if not exists rag_retrieval_logs_owner_created_idx
+ on public.rag_retrieval_logs(owner_id, created_at desc);
+
+create index if not exists rag_retrieval_logs_miss_idx
+ on public.rag_retrieval_logs(is_miss, created_at desc)
+ where is_miss = true;
+
+create or replace function public.search_schema_health()
+returns jsonb
+language plpgsql
+stable
+security definer
+set search_path = public, extensions, pg_catalog, pg_temp
+as $$
+declare
+ missing text[] := array[]::text[];
+ vector_type_oid oid;
+ vector_schema text;
+ index_name text;
+ legacy_ivfflat_indexes text[];
+ zero_vec extensions.vector(1536);
+ probe_text text := 'schema health probe zzznomatch';
+ hybrid_rpcs text[] := array[
+ 'match_document_chunks_hybrid',
+ 'match_document_index_units_hybrid',
+ 'match_document_embedding_fields_hybrid',
+ 'match_document_memory_cards_hybrid'
+ ];
+ rpc_name text;
+ required_indexes constant text[] := array[
+ 'documents_title_trgm_idx',
+ 'document_chunks_content_trgm_idx',
+ 'document_labels_label_trgm_idx',
+ 'document_summaries_summary_trgm_idx',
+ 'document_chunks_embedding_hnsw_idx',
+ 'document_embedding_fields_embedding_hnsw_idx',
+ 'document_memory_cards_embedding_hnsw_idx',
+ 'documents_indexed_owner_title_idx',
+ 'document_table_facts_owner_document_page_idx',
+ 'document_embedding_fields_owner_chunk_idx',
+ 'document_index_units_owner_chunk_type_idx',
+ 'document_table_facts_source_image_idx',
+ 'document_pages_document_idx',
+ 'document_sections_document_idx',
+ 'document_chunks_document_idx',
+ 'document_memory_cards_document_idx',
+ 'document_embedding_fields_document_idx',
+ 'document_table_facts_document_idx',
+ 'document_index_units_document_idx',
+ 'rag_retrieval_logs_owner_created_idx',
+ 'rag_retrieval_logs_miss_idx',
+ 'rag_retrieval_logs_strategy_idx'
+ ];
+ -- Verified live equivalents: same table/column intent, different migration-era name.
+ index_aliases constant jsonb := jsonb_build_object(
+ 'documents_title_trgm_idx', jsonb_build_array('documents_title_search_tsv_idx', 'documents_title_search_idx'),
+ 'document_chunks_content_trgm_idx', jsonb_build_array('document_chunks_search_tsv_idx', 'document_chunks_search_idx'),
+ 'document_table_facts_owner_document_page_idx', jsonb_build_array('document_table_facts_owner_idx'),
+ 'document_pages_document_idx', jsonb_build_array('document_pages_document_id_page_number_key'),
+ 'document_sections_document_idx', jsonb_build_array('document_sections_document_id_idx'),
+ 'rag_retrieval_logs_owner_created_idx', jsonb_build_array('rag_retrieval_logs_owner_id_idx')
+ );
+begin
+ select t.oid, n.nspname
+ into vector_type_oid, vector_schema
+ from pg_type t
+ join pg_namespace n on n.oid = t.typnamespace
+ where t.typname = 'vector'
+ and n.nspname = 'extensions'
+ limit 1;
+
+ if vector_type_oid is null then
+ missing := array_append(missing, 'extensions.vector_type');
+ end if;
+
+ if to_regprocedure('public.match_document_chunks(extensions.vector, integer, double precision, uuid, uuid)') is null then
+ missing := array_append(missing, 'match_document_chunks.extensions_vector_signature');
+ end if;
+ if to_regprocedure('public.match_document_chunks_hybrid(extensions.vector, text, integer, double precision, uuid[], uuid)') is null then
+ missing := array_append(missing, 'match_document_chunks_hybrid.extensions_vector_signature');
+ end if;
+ if to_regprocedure('public.match_document_chunks_text(text, integer, uuid[], uuid)') is null then
+ missing := array_append(missing, 'match_document_chunks_text.signature');
+ end if;
+ if to_regprocedure('public.match_document_lookup_chunks_text(text, uuid[], integer, uuid)') is null then
+ missing := array_append(missing, 'match_document_lookup_chunks_text.signature');
+ end if;
+ if to_regprocedure('public.match_document_memory_cards_hybrid(extensions.vector, text, integer, double precision, uuid[], uuid)') is null then
+ missing := array_append(missing, 'match_document_memory_cards_hybrid.extensions_vector_signature');
+ end if;
+ if to_regprocedure('public.match_document_memory_cards_hybrid_v2(extensions.vector, text, integer, double precision, uuid[], uuid)') is null then
+ missing := array_append(missing, 'match_document_memory_cards_hybrid_v2.extensions_vector_signature');
+ end if;
+ if to_regprocedure('public.match_document_index_units_hybrid(extensions.vector, text, integer, double precision, uuid[], uuid)') is null then
+ missing := array_append(missing, 'match_document_index_units_hybrid.extensions_vector_signature');
+ end if;
+ if to_regprocedure('public.match_document_embedding_fields_hybrid(extensions.vector, text, integer, double precision, uuid[], uuid)') is null then
+ missing := array_append(missing, 'match_document_embedding_fields_hybrid.extensions_vector_signature');
+ end if;
+ if to_regprocedure('public.match_documents_for_query(text, integer, uuid)') is null then
+ missing := array_append(missing, 'match_documents_for_query.signature');
+ end if;
+ if to_regprocedure('public.match_document_table_facts_text(text, integer, uuid[], uuid)') is null then
+ missing := array_append(missing, 'match_document_table_facts_text.signature');
+ end if;
+ if to_regprocedure('public.explain_retrieval_rpc(text, text, integer, uuid, uuid[], boolean)') is null then
+ missing := array_append(missing, 'explain_retrieval_rpc.signature');
+ end if;
+ if to_regclass('public.rag_retrieval_logs') is null then
+ missing := array_append(missing, 'rag_retrieval_logs.table');
+ end if;
+
+ foreach index_name in array required_indexes loop
+ if not exists (
+ select 1
+ from pg_class c
+ join pg_namespace ns on ns.oid = c.relnamespace
+ where ns.nspname = 'public'
+ and c.relname = index_name
+ and c.relkind = 'i'
+ )
+ and not (
+ index_aliases ? index_name
+ and exists (
+ select 1
+ from pg_class c
+ join pg_namespace ns on ns.oid = c.relnamespace
+ where ns.nspname = 'public'
+ and c.relkind = 'i'
+ and c.relname in (
+ select jsonb_array_elements_text(index_aliases -> index_name)
+ )
+ )
+ ) then
+ missing := array_append(missing, index_name);
+ end if;
+ end loop;
+
+ if vector_type_oid is not null then
+ zero_vec := (select ('[' || string_agg('0', ',') || ']') from generate_series(1, 1536))::extensions.vector(1536);
+ foreach rpc_name in array hybrid_rpcs loop
+ begin
+ execute format(
+ 'select 1 from public.%I($1, $2, 1, 0.1, null::uuid[], null::uuid) limit 1',
+ rpc_name
+ ) using zero_vec, probe_text;
+ exception
+ when undefined_function then
+ missing := array_append(missing, rpc_name || '.execution_signature');
+ when others then
+ missing := array_append(missing, rpc_name || '.execution:' || SQLSTATE);
+ end;
+ end loop;
+ end if;
+
+ select public.detect_legacy_ivfflat_indexes() into legacy_ivfflat_indexes;
+
+ return jsonb_build_object(
+ 'ok', cardinality(missing) = 0,
+ 'missing', missing,
+ 'vector_extension_schema', vector_schema,
+ 'legacy_ivfflat_indexes', coalesce(legacy_ivfflat_indexes, array[]::text[]),
+ 'deferred_hnsw_indexes', array[]::text[],
+ 'checked_at', now()
+ );
+end;
+$$;
+
+revoke execute on function public.search_schema_health() from public, anon, authenticated;
+grant execute on function public.search_schema_health() to service_role;
diff --git a/supabase/schema.sql b/supabase/schema.sql
index 63657b132..16ce2230c 100644
--- a/supabase/schema.sql
+++ b/supabase/schema.sql
@@ -2396,6 +2396,15 @@ declare
'rag_retrieval_logs_miss_idx',
'rag_retrieval_logs_strategy_idx'
];
+ -- Verified live equivalents: same table/column intent, different migration-era name.
+ index_aliases constant jsonb := jsonb_build_object(
+ 'documents_title_trgm_idx', jsonb_build_array('documents_title_search_tsv_idx', 'documents_title_search_idx'),
+ 'document_chunks_content_trgm_idx', jsonb_build_array('document_chunks_search_tsv_idx', 'document_chunks_search_idx'),
+ 'document_table_facts_owner_document_page_idx', jsonb_build_array('document_table_facts_owner_idx'),
+ 'document_pages_document_idx', jsonb_build_array('document_pages_document_id_page_number_key'),
+ 'document_sections_document_idx', jsonb_build_array('document_sections_document_id_idx'),
+ 'rag_retrieval_logs_owner_created_idx', jsonb_build_array('rag_retrieval_logs_owner_id_idx')
+ );
begin
select t.oid, n.nspname
into vector_type_oid, vector_schema
@@ -2454,6 +2463,19 @@ begin
where ns.nspname = 'public'
and c.relname = index_name
and c.relkind = 'i'
+ )
+ and not (
+ index_aliases ? index_name
+ and exists (
+ select 1
+ from pg_class c
+ join pg_namespace ns on ns.oid = c.relnamespace
+ where ns.nspname = 'public'
+ and c.relkind = 'i'
+ and c.relname in (
+ select jsonb_array_elements_text(index_aliases -> index_name)
+ )
+ )
) then
missing := array_append(missing, index_name);
end if;
diff --git a/tests/supabase-schema.test.ts b/tests/supabase-schema.test.ts
index 68cd98773..6dd16d6c9 100644
--- a/tests/supabase-schema.test.ts
+++ b/tests/supabase-schema.test.ts
@@ -80,6 +80,10 @@ const registryCatalogPayloadMigration = readFileSync(
new URL("../supabase/migrations/20260705030000_registry_catalog_payload.sql", import.meta.url),
"utf8",
).replace(/\s+/g, " ");
+const searchHealthIndexesMigration = readFileSync(
+ new URL("../supabase/migrations/20260705180000_reconcile_search_health_indexes.sql", import.meta.url),
+ "utf8",
+).replace(/\s+/g, " ");
const ragQueriesRetentionMigration = readFileSync(
new URL("../supabase/migrations/20260629060603_rag_queries_retention.sql", import.meta.url),
"utf8",
@@ -739,6 +743,17 @@ describe("Supabase schema Data API grants", () => {
"add column if not exists catalog_payload jsonb not null default '{}'::jsonb",
);
});
+
+ it("reconciles search_schema_health index drift with canonical creates and live aliases", () => {
+ expect(searchHealthIndexesMigration).toContain("create index if not exists documents_title_trgm_idx");
+ expect(searchHealthIndexesMigration).toContain("create index if not exists document_labels_label_trgm_idx");
+ expect(searchHealthIndexesMigration).toContain("create index if not exists rag_retrieval_logs_miss_idx");
+ expect(searchHealthIndexesMigration).toContain("index_aliases constant jsonb := jsonb_build_object(");
+ expect(searchHealthIndexesMigration).toContain("'documents_title_search_tsv_idx'");
+ expect(searchHealthIndexesMigration).toContain("'document_pages_document_id_page_number_key'");
+ expect(schema).toContain("index_aliases constant jsonb := jsonb_build_object(");
+ expect(schema).toContain("jsonb_array_elements_text(index_aliases -> index_name)");
+ });
});
describe("RC9 — lexical text path must not fabricate a cosine similarity", () => {
From 940084176946fe0e1544f5ec0939df0dd58ecdf4 Mon Sep 17 00:00:00 2001
From: BigSimmo <87357024+BigSimmo@users.noreply.github.com>
Date: Sun, 5 Jul 2026 20:19:45 +0800
Subject: [PATCH 2/3] test: add deep public access and production scope checks
---
tests/public-access-deep.test.ts | 225 +++++++++++++++++++++++++++++++
1 file changed, 225 insertions(+)
create mode 100644 tests/public-access-deep.test.ts
diff --git a/tests/public-access-deep.test.ts b/tests/public-access-deep.test.ts
new file mode 100644
index 000000000..0801c4bd9
--- /dev/null
+++ b/tests/public-access-deep.test.ts
@@ -0,0 +1,225 @@
+import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
+
+const publicDocumentId = "11111111-1111-4111-8111-111111111111";
+
+beforeEach(() => {
+ vi.resetModules();
+});
+
+afterEach(() => {
+ vi.restoreAllMocks();
+ vi.resetModules();
+ vi.unstubAllEnvs();
+});
+
+describe("public access deep checks", () => {
+ it("rejects unauthenticated access to operator-only routes", async () => {
+ vi.doMock("@/lib/env", () => ({ isDemoMode: () => false, env: {} }));
+ const auth = {
+ AuthenticationError: class AuthenticationError extends Error {},
+ requireAuthenticatedUser: vi.fn(async () => {
+ throw new auth.AuthenticationError();
+ }),
+ unauthorizedResponse: () => Response.json({ error: "Authentication required." }, { status: 401 }),
+ };
+ vi.doMock("@/lib/supabase/admin", () => ({
+ createAdminClient: vi.fn(() => ({ auth: { getUser: vi.fn() } })),
+ }));
+ vi.doMock("@/lib/supabase/auth", () => auth);
+
+ const cases = [
+ {
+ routePath: "../src/app/api/jobs/route",
+ handler: "GET" as const,
+ request: new Request("http://localhost/api/jobs"),
+ },
+ {
+ routePath: "../src/app/api/ingestion/jobs/route",
+ handler: "GET" as const,
+ request: new Request("http://localhost/api/ingestion/jobs"),
+ },
+ {
+ routePath: "../src/app/api/ingestion/batches/route",
+ handler: "GET" as const,
+ request: new Request("http://localhost/api/ingestion/batches"),
+ },
+ {
+ routePath: "../src/app/api/documents/bulk/route",
+ handler: "POST" as const,
+ request: new Request("http://localhost/api/documents/bulk", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ action: "delete", documentIds: [publicDocumentId] }),
+ }),
+ },
+ {
+ routePath: "../src/app/api/documents/[id]/summarize/route",
+ handler: "POST" as const,
+ request: new Request(`http://localhost/api/documents/${publicDocumentId}/summarize`, { method: "POST" }),
+ params: { id: publicDocumentId },
+ },
+ {
+ routePath: "../src/app/api/eval-cases/route",
+ handler: "POST" as const,
+ request: new Request("http://localhost/api/eval-cases", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ query: "What monitoring is needed?",
+ rating: "good",
+ answer: "Monitor FBC.",
+ queryMode: "auto",
+ queryClass: "table_threshold",
+ }),
+ }),
+ },
+ ] as const;
+
+ for (const testCase of cases) {
+ vi.resetModules();
+ vi.doMock("@/lib/env", () => ({ isDemoMode: () => false, env: {} }));
+ vi.doMock("@/lib/supabase/admin", () => ({
+ createAdminClient: vi.fn(() => ({ auth: { getUser: vi.fn() } })),
+ }));
+ vi.doMock("@/lib/supabase/auth", () => auth);
+ const mod = await import(testCase.routePath);
+ const handler = mod[testCase.handler];
+ const response = await handler(
+ testCase.request,
+ "params" in testCase ? { params: Promise.resolve(testCase.params) } : undefined,
+ );
+ expect(response.status, testCase.routePath).toBe(401);
+ }
+ });
+
+ it("does not expose secret values from the health endpoint", async () => {
+ vi.doMock("@/lib/env", () => ({
+ env: {
+ NEXT_PUBLIC_SUPABASE_URL: "https://sjrfecxgysukkwxsowpy.supabase.co",
+ SUPABASE_SERVICE_ROLE_KEY: "super-secret-service-role-key",
+ OPENAI_API_KEY: "sk-super-secret-openai-key",
+ },
+ isDemoMode: () => false,
+ }));
+ const { GET } = await import("../src/app/api/health/route");
+ const response = await GET(new Request("https://clinical.example/api/health?deep=1"));
+ const body = await response.json();
+ const serialized = JSON.stringify(body);
+
+ expect(serialized).not.toContain("super-secret-service-role-key");
+ expect(serialized).not.toContain("sk-super-secret-openai-key");
+ expect(body.checks.supabaseConfig).toBe("ok");
+ expect(body.checks.openaiConfig).toBe("ok");
+ });
+
+});
+
+describe("production anonymous retrieval scope", () => {
+ beforeEach(() => {
+ vi.resetModules();
+ });
+
+ afterEach(() => {
+ vi.restoreAllMocks();
+ vi.resetModules();
+ vi.unstubAllEnvs();
+ });
+
+ it("fails closed in production when anonymous global retrieval omits owner scope", async () => {
+ vi.doUnmock("@/lib/rag");
+ vi.stubEnv("NODE_ENV", "production");
+ vi.doMock("@/lib/env", () => ({
+ env: {
+ OPENAI_API_KEY: "sk-test",
+ RAG_PROVIDER_MODE: "offline",
+ RAG_SEARCH_CACHE_TTL_MS: 0,
+ RAG_ANSWER_CACHE_TTL_MS: 0,
+ },
+ isDemoMode: () => false,
+ isLocalNoAuthMode: () => false,
+ requestedOpenAIAnswerModels: () => ({ fast: "gpt-test", strong: "gpt-test" }),
+ }));
+ vi.doMock("@/lib/supabase/admin", () => ({
+ createAdminClient: vi.fn(() => ({
+ from: vi.fn(() => ({
+ select: vi.fn(() => ({
+ eq: vi.fn(() => ({
+ is: vi.fn(() => ({
+ order: vi.fn(() => ({
+ limit: vi.fn(async () => ({ data: [], error: null })),
+ })),
+ })),
+ })),
+ })),
+ })),
+ rpc: vi.fn(async () => ({ data: [], error: null })),
+ })),
+ }));
+
+ const { searchChunksWithTelemetry } = await import("../src/lib/rag");
+
+ await expect(
+ searchChunksWithTelemetry({
+ query: "clozapine monitoring",
+ allowGlobalSearch: true,
+ }),
+ ).rejects.toThrow(/ownerId|tenant/i);
+ });
+});
+
+describe("test-runtime anonymous retrieval scope", () => {
+ beforeEach(() => {
+ vi.resetModules();
+ });
+
+ afterEach(() => {
+ vi.restoreAllMocks();
+ vi.resetModules();
+ vi.unstubAllEnvs();
+ });
+
+ it("allows anonymous global retrieval in test runtime where owner scope stays permissive", async () => {
+ vi.doUnmock("@/lib/rag");
+ vi.doMock("@/lib/env", () => ({
+ env: {
+ OPENAI_API_KEY: undefined,
+ RAG_PROVIDER_MODE: "offline",
+ RAG_SEARCH_CACHE_TTL_MS: 0,
+ RAG_ANSWER_CACHE_TTL_MS: 0,
+ },
+ isDemoMode: () => false,
+ isLocalNoAuthMode: () => false,
+ requestedOpenAIAnswerModels: () => ({ fast: "gpt-test", strong: "gpt-test" }),
+ }));
+ vi.doMock("@/lib/supabase/admin", () => ({
+ createAdminClient: vi.fn(() => ({
+ from: vi.fn(() => ({
+ select: vi.fn(() => ({
+ eq: vi.fn(() => ({
+ is: vi.fn(() => ({
+ order: vi.fn(() => ({
+ limit: vi.fn(async () => ({ data: [], error: null })),
+ })),
+ in: vi.fn(() => ({
+ order: vi.fn(() => ({
+ limit: vi.fn(async () => ({ data: [], error: null })),
+ })),
+ })),
+ })),
+ })),
+ })),
+ })),
+ rpc: vi.fn(async () => ({ data: [], error: null })),
+ })),
+ }));
+
+ const { searchChunksWithTelemetry } = await import("../src/lib/rag");
+ const result = await searchChunksWithTelemetry({
+ query: "clozapine monitoring",
+ allowGlobalSearch: true,
+ });
+
+ expect(result.results).toEqual([]);
+ expect(result.telemetry).toBeDefined();
+ });
+});
From a382754cce30010e187558412a4d54e7cd706328 Mon Sep 17 00:00:00 2001
From: BigSimmo <87357024+BigSimmo@users.noreply.github.com>
Date: Sun, 5 Jul 2026 20:26:19 +0800
Subject: [PATCH 3/3] refactor(ui): remove duplicate visual-evidence code from
ClinicalDashboard
Delete post-extraction dead code left in the monolith and trim unused imports. Also fix minor lint issues in favourites-hub, visual-evidence, and services-navigator.
---
src/components/ClinicalDashboard.tsx | 433 +-----------------
.../clinical-dashboard/favourites-hub.tsx | 1 -
.../clinical-dashboard/visual-evidence.tsx | 1 -
.../services/services-navigator-page.tsx | 6 +-
4 files changed, 9 insertions(+), 432 deletions(-)
diff --git a/src/components/ClinicalDashboard.tsx b/src/components/ClinicalDashboard.tsx
index 2545d2b24..647d6e1a8 100644
--- a/src/components/ClinicalDashboard.tsx
+++ b/src/components/ClinicalDashboard.tsx
@@ -1,18 +1,15 @@
"use client";
-import Link from "next/link";
import { useRouter, useSearchParams } from "next/navigation";
import dynamic from "next/dynamic";
import {
AlertCircle,
Bell,
BookOpen,
- CheckCircle2,
ChevronDown,
ChevronRight,
CircleUserRound,
Clock3,
- Copy,
ExternalLink,
FileImage,
FileText,
@@ -21,7 +18,6 @@ import {
HelpCircle,
Heart,
Keyboard,
- Layers,
ListChecks,
Loader2,
LogOut,
@@ -29,7 +25,6 @@ import {
LockKeyhole,
Palette,
PanelTop,
- Plus,
Quote,
RefreshCw,
Search,
@@ -48,66 +43,37 @@ import {
import {
type CSSProperties,
type FormEvent,
- type RefObject,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from "react";
-import { AccessibleTable } from "@/components/AccessibleTable";
-import {
- DocumentOrganizationBadges,
- documentDisplayTitle,
- documentOrganizationProfile,
-} from "@/components/DocumentOrganizationBadges";
-import { DocumentTagCloud } from "@/components/DocumentTagCloud";
-import { DocumentManagementActions, type DocumentDeleteResult } from "@/components/DocumentManagementActions";
+import { type DocumentDeleteResult } from "@/components/DocumentManagementActions";
import { useDismissableLayer } from "@/components/use-dismissable-layer";
-import { formatCompactCitationLabel } from "@/lib/citations";
import { extractSafetyFindings } from "@/lib/clinical-safety";
import { readLocalProjectIdentity, unsafeLocalProjectMessage } from "@/lib/local-project-identity";
import { isLocalNoAuthMode } from "@/lib/env";
import {
appBackdrop,
answerSurface,
- chatMicroAction,
- clinicalDivider,
cn,
- EmptyState,
- fieldControlPlain,
fieldControlWithIcon,
fieldIcon,
floatingControl,
- iconTilePremium,
- metadataPill,
- panelSubtle,
primaryControl,
- SourceProvenance,
- SourceStatusBadge,
- sourceCard,
- subtleStatusPill,
- tableCard,
- tableCardHeader,
- tableMicroActionRow,
textMuted,
- toneDanger,
- toneInfo,
- toneNeutral,
toneSuccess,
toneWarning,
} from "@/components/ui-primitives";
import { useAuthSession } from "@/lib/supabase/client";
-import { SafeBoldText } from "@/components/SafeBoldText";
import { Sheet } from "@/components/ui/sheet";
import { AccountSetupDialog } from "@/components/clinical-dashboard/account-setup-dialog";
import { StagedAnswerResultSurface } from "@/components/clinical-dashboard/answer-result-surface";
import { RelatedDocumentsPanel } from "@/components/clinical-dashboard/document-results";
-import { AnswerFollowUpSuggestions } from "@/components/clinical-dashboard/answer-follow-up-suggestions";
import { AuthPanel } from "@/components/clinical-dashboard/auth-panel";
import { useSidebarCollapsed } from "@/components/clinical-dashboard/use-sidebar-collapsed";
import { useTheme } from "@/components/clinical-dashboard/use-theme";
-import { StatusBadge } from "@/components/clinical-dashboard/badges";
import {
type SidebarIdentity,
deriveSidebarIdentity,
@@ -129,42 +95,22 @@ import {
import {
GuideDialog,
GuideTrigger,
- SectionHeading,
UtilityDrawer,
} from "@/components/clinical-dashboard/dashboard-shell";
import {
- cleanDisplayTitle,
sanitizeAnswerDisplayText,
sanitizeDisplayText,
} from "@/components/clinical-dashboard/display-text";
import {
NaturalLanguageAnswer,
ScopeAndGovernanceNotice,
- SourceImage,
UserQuestionBubble,
} from "@/components/clinical-dashboard/answer-content";
import { AnswerEmptyState, AnswerSkeleton } from "@/components/clinical-dashboard/answer-status";
-import {
- AnswerFeedbackPanel,
- AnswerSafetyNotice,
- AnswerSupportSummaryCard,
- answerHasCentralTable,
- answerSupportPriority,
- ClinicalNotesChecklistPanel,
- clinicalNotesCount,
- clinicalNotesDisplayCountForAnswer,
- compactEvidenceSummary,
- type EvidenceTabName,
- simpleClinicalTableProps,
- evidenceMapRowsFromRenderModel,
- evidenceTabCount,
- evidenceTabOrder,
- QuoteCards,
- SafetyFindingsListContent,
-} from "@/components/clinical-dashboard/evidence-panels";
+import { evidenceMapRowsFromRenderModel } from "@/components/clinical-dashboard/evidence-panels";
import { MasterSearchHeader } from "@/components/clinical-dashboard/master-search-header";
import { SearchCommandProvider } from "@/components/clinical-dashboard/search-command-context";
-import { emptyStates, errorCopy } from "@/lib/ui-copy";
+import { errorCopy } from "@/lib/ui-copy";
import { applicationsLauncherItemCount } from "@/components/applications-launcher-page";
import {
DrawerGroupLabel,
@@ -198,7 +144,7 @@ const DocumentDrawer = dynamic(
);
import { DocumentSearchResultsPanel, type SearchFacets } from "@/components/clinical-dashboard/document-search-results";
-import { isWeakRelevance, QueryCoverageChips } from "@/components/clinical-dashboard/relevance";
+import { isWeakRelevance } from "@/components/clinical-dashboard/relevance";
import {
answerPayloadIsUsable,
isRetryableError,
@@ -236,20 +182,15 @@ import {
maxStoredAnswerTurns,
savePersistedAnswerThread,
} from "@/lib/answer-thread-storage";
-import { buildAnswerRenderModel, type AnswerRenderModel } from "@/lib/answer-render-policy";
-import { sourceTextForCompactDisplay } from "@/lib/source-text-sanitizer";
+import { buildAnswerRenderModel } from "@/lib/answer-render-policy";
import {
frontendSourceGovernanceWarnings,
groupSourceGovernanceWarnings,
type SourceGovernanceWarning,
} from "@/lib/source-governance";
-import { smartEvidenceTags } from "@/lib/evidence-tags";
import {
- tagSearchText,
type SmartDocumentTag,
type SmartDocumentTagFacet,
- type SmartDocumentTagTier,
- type SmartDocumentTagQualityIssueKind,
} from "@/lib/document-tags";
import type {
ClinicalDocument,
@@ -263,16 +204,13 @@ import type {
RelatedDocument,
SearchResult,
SearchScopeSummary,
- VisualEvidenceCard,
ClinicalQueryMode,
DocumentLabel,
- DocumentLabelType,
} from "@/lib/types";
import type { SearchScopeFilters } from "@/lib/search-scope";
import { differentialsMobileCompareAddonSlotId, modeHomeDesktopComposerSlotId } from "@/lib/mode-home-composer";
import {
createQuoteFollowUp,
- type AnswerEvidenceMapRow,
type AnswerViewMode,
shouldPollForUpdates,
} from "@/lib/ward-output";
@@ -487,367 +425,6 @@ async function readAnswerStream(response: Response, onProgress: (message: string
function normalizeNavigationHash(hash: string) {
return navigationHashes.includes(hash as (typeof navigationHashes)[number]) ? hash : "#search";
}
-
-function compactClinicalTableCaption(item: VisualEvidenceCard) {
- const raw = item.tableTitle || item.tableLabel || item.caption || "Clinical table";
- const cleaned = sourceTextForCompactDisplay(raw)
- .replace(/\btable\s+\d+\s*[:.-]?\s*/i, "")
- .replace(/\b(?:page|p\.)\s*\d+\b/gi, "")
- .replace(/\s{2,}/g, " ")
- .trim();
- const caption = cleaned || "Clinical table";
- return caption.length <= 72 ? caption : `${caption.slice(0, 69).trim()}...`;
-}
-
-function visualEvidenceHeader(item: VisualEvidenceCard) {
- const titleSource = [item.tableLabel, item.tableTitle].filter(Boolean).join(" · ");
- const titleText = sourceTextForCompactDisplay(titleSource).trim();
- const captionText = sourceTextForCompactDisplay(item.caption ?? "").trim();
- const normalizedTitle = titleText.toLowerCase();
- const normalizedCaption = captionText.toLowerCase();
- const isDuplicateCaption =
- Boolean(normalizedCaption) &&
- (normalizedCaption.startsWith(normalizedTitle) || normalizedCaption === normalizedTitle);
- return {
- title: titleText || captionText || "Visual evidence",
- caption: isDuplicateCaption ? null : captionText,
- };
-}
-
-function VisualEvidenceStrip({
- evidence,
- collapsed = false,
- embedded = false,
-}: {
- evidence: VisualEvidenceCard[];
- collapsed?: boolean;
- embedded?: boolean;
-}) {
- function looksLikeTableText(value?: string | null) {
- return Boolean(value?.includes("|") && value.split("|").filter((cell) => cell.trim()).length >= 3);
- }
-
- if (collapsed) {
- return (
-
{sourceHeader.title}
: null} - {!hasStructuredTable && sourceHeader.caption ?{sourceHeader.caption}
: null} -- {sourceTextForCompactDisplay(item.tableTextSnippet)} -
- ) : null} - {displayLabels.length ? ( -Claims checked
-- {directCount} direct · {partialCount} partial -
-Gap {index + 1}
-{warning}
-- {compactClinicalTableCaption(item)} -
-- Table {index + 1} · p.{item.page_number ?? "n/a"} -
-