diff --git a/docs/archive/operator-decisions-2026-07-06.md b/docs/archive/operator-decisions-2026-07-06.md new file mode 100644 index 0000000000..46572cec40 --- /dev/null +++ b/docs/archive/operator-decisions-2026-07-06.md @@ -0,0 +1,27 @@ +# Operator decisions — 2026-07-06 + +Approvals granted during the repository-review follow-up session. **No live actions were taken from this checklist** — the authoring environment had no authenticated Supabase connection. Any live-connected session (or the operator) can execute these without re-asking. + +## Pending live migrations — APPROVED to apply + +**Decision:** The operator explicitly approved applying both pending migrations to the live `Clinical KB Database` project (`sjrfecxgysukkwxsowpy`). + +1. **M13** `supabase/migrations/20260702000000_commit_generation_preserve_legacy_artifacts.sql` — prerequisite for reindex commits safely purging legacy NULL-generation rows. +2. `supabase/migrations/20260703030000_reconcile_storage_cleanup_jobs_indexes.sql` — drops the legacy auto-named indexes and (re)creates the intended named/partial indexes to match `supabase/schema.sql`. (This is the migration the debt log marked "apply to live only with explicit approval" — that approval is now recorded here.) + +**Post-apply verification (required):** + +```bash +npm run check:m13-migration +npm run reindex:health +npm run check:indexing +npm run check:supabase-project +``` + +## Edge function deploy — APPROVED + +**Decision:** Deploy `supabase/functions/indexing-v3-agent` so the JSONB status-RPC parsing is live (follow-up noted in `docs/process-hardening.md` "Live database drift reconciliation (2026-07-05)"). + +## Context + +Approval came alongside the operator green-lighting the two structural efforts (finish the ClinicalDashboard admin cutover; decompose `src/lib/rag.ts`) tracked in `docs/process-hardening.md`. diff --git a/docs/process-hardening.md b/docs/process-hardening.md index 053ed64a45..40f3f4c0a9 100644 --- a/docs/process-hardening.md +++ b/docs/process-hardening.md @@ -47,7 +47,7 @@ This document turns the current process review into phased, durable repo practic All approved render-surface modules are extracted. `ClinicalDashboard.tsx` went from ~8.8k → ~4.7k lines and now holds the main `ClinicalDashboard` orchestrator, its data/state hooks, and the deferred admin surfaces only. The 6 extracted modules live in `src/components/clinical-dashboard/`: `auth-panel`, `answer-content`, `evidence-panels`, `output-panel`, `visual-evidence`, `document-results` (+ the shared `use-mobile-preview-sheet` hook and `display-text` helpers). The barrel `index.ts` was intentionally not extended. -**Out of scope (deferred admin surfaces, optional later pass):** `DocumentDrawer`, `SettingsDialog`, `ToolsHub`, `MobileSectionFab`, `DocumentLabelReviewPanel`/`DocumentTagQualityPanel`/`DocumentIndexRepairPanel` and their label helpers (`tagQualityTone`, `labelTierTone`, `documentLabelTypeOptions`) all remain in `ClinicalDashboard.tsx`. +**Deferred admin surfaces: DONE (2026-07-06).** `DocumentDrawer` + the label panels/helpers had already landed via #250/#251 (`document-admin.tsx`, wired). The remaining half-wired state was finished on `claude/dashboard-decomp-final`: `ToolsHub` + `MobileSectionFab` cut over to `dashboard-nav.tsx` and `SettingsDialog` (+ its 7 `Settings*` helpers) to `settings-dialog.tsx`. **Both #250 sibling files had drifted from the live monolith** (settings-dialog.tsx predated the auth-email sign-in flow; dashboard-nav.tsx had stale colour tokens and prop lists) and were regenerated verbatim from the current monolith blocks before wiring — reusable lesson: an orphaned prepared module is stale the moment the monolith copy keeps evolving; always re-diff before cutover. `global-mockup-search-shell.tsx` now imports `SettingsDialog` from the module. The dead `document-admin/` **directory** (shadowed by the live `document-admin.tsx` file in module resolution, imported by nothing) was deleted. Monolith: 4,373 → ~3,450 lines (orchestrator + data/state hooks + small render/stream helpers). Live-surface `data-testid`/`aria-label` corpus verified byte-identical across both moves. ## Phase 4 - Release maturity diff --git a/src/components/ClinicalDashboard.tsx b/src/components/ClinicalDashboard.tsx index 868b63df5e..af65e0f6cb 100644 --- a/src/components/ClinicalDashboard.tsx +++ b/src/components/ClinicalDashboard.tsx @@ -4,72 +4,43 @@ import { useRouter, useSearchParams } from "next/navigation"; import dynamic from "next/dynamic"; import { AlertCircle, - Bell, BookOpen, ChevronDown, - ChevronRight, - CircleUserRound, Clock3, ExternalLink, FileImage, FileText, FolderOpen, - Globe2, - HelpCircle, Heart, - Keyboard, ListChecks, Loader2, - LogOut, - Mail, - LockKeyhole, - Palette, - PanelTop, Quote, RefreshCw, Search, - Settings as SettingsIcon, ShieldAlert, - ShieldCheck, - SlidersHorizontal, - Sparkles, - Stethoscope, UploadCloud, - UserRound, WifiOff, Wrench, X, } from "lucide-react"; -import { type CSSProperties, type FormEvent, useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { type CSSProperties, useCallback, useEffect, useMemo, useRef, useState } from "react"; import { type DocumentDeleteResult } from "@/components/DocumentManagementActions"; -import { useDismissableLayer } from "@/components/use-dismissable-layer"; import { extractSafetyFindings } from "@/lib/clinical-safety"; import { readLocalProjectIdentity, unsafeLocalProjectMessage } from "@/lib/local-project-identity"; import { isDeployedClinicalKb } from "@/lib/deployed-app"; import { isLocalNoAuthMode, publicUploadsEnabled } from "@/lib/env"; -import { - appBackdrop, - answerSurface, - cn, - fieldControlWithIcon, - fieldIcon, - floatingControl, - primaryControl, - textMuted, - toneSuccess, - toneWarning, -} from "@/components/ui-primitives"; +import { appBackdrop, answerSurface, cn, textMuted, toneSuccess, toneWarning } from "@/components/ui-primitives"; import { useAuthSession } from "@/lib/supabase/client"; -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 { CrossModeLinksSection } from "@/components/clinical-dashboard/cross-mode-links"; import { RelatedDocumentsPanel } from "@/components/clinical-dashboard/document-results"; import { AuthPanel } from "@/components/clinical-dashboard/auth-panel"; +import { buildMobileSectionFabState, MobileSectionFab, ToolsHub } from "@/components/clinical-dashboard/dashboard-nav"; +import { SettingsDialog } from "@/components/clinical-dashboard/settings-dialog"; import { useSidebarCollapsed } from "@/components/clinical-dashboard/use-sidebar-collapsed"; import { useTheme } from "@/components/clinical-dashboard/use-theme"; import { - type SidebarIdentity, deriveSidebarIdentity, ClinicalDesktopSidebar, ClinicalMobileSidebar, @@ -516,923 +487,6 @@ type LibraryHealthTarget = "documents" | "setup" | "indexing" | "failures"; type IndexingMonitorFilter = "all" | "active" | "failed"; type UploadIndexingTab = "setup" | "upload" | "jobs" | "quality"; -export function SettingsDialog({ - open, - onClose, - identity, - theme, - onToggleTheme, - onSignOut, - onOpenGuide, -}: { - open: boolean; - onClose: () => void; - identity: SidebarIdentity; - theme: "light" | "dark"; - onToggleTheme: () => void; - onSignOut: () => void; - onOpenGuide: () => void; -}) { - const closeButtonRef = useRef(null); - const settingsEmailInputRef = useRef(null); - const currentThemeLabel = theme === "dark" ? "Dark" : "Light"; - const auth = useAuthSession(); - const [settingsEmail, setSettingsEmail] = useState(""); - const [emailEntryOpen, setEmailEntryOpen] = useState(false); - const [settingsEmailAttempted, setSettingsEmailAttempted] = useState(false); - const [accountNotice, setAccountNotice] = useState(null); - const settingsAuthBusy = auth.status === "loading"; - const signedOutAccount = !identity.signedIn; - - async function submitSettingsEmail(event: FormEvent) { - event.preventDefault(); - if (!settingsEmail.trim()) return; - setAccountNotice(null); - setSettingsEmailAttempted(true); - await auth.signInWithEmail(settingsEmail.trim()); - } - - function openSettingsEmailEntry() { - setEmailEntryOpen(true); - setAccountNotice(null); - } - - function chooseSettingsProvider(provider: string) { - setAccountNotice(`${provider} sign-in is a placeholder for now. Continue with email to use this workspace.`); - } - - useEffect(() => { - if (!emailEntryOpen) return; - const focusFrame = window.requestAnimationFrame(() => { - settingsEmailInputRef.current?.focus({ preventScroll: true }); - }); - return () => window.cancelAnimationFrame(focusFrame); - }, [emailEntryOpen]); - - const settingSections = [ - { - title: "Account", - rows: [ - { icon: UserRound, label: "Profile", value: identity.displayName }, - { icon: Stethoscope, label: "Clinical role", value: "Consultant psychiatrist" }, - ], - }, - { - title: "Clinical defaults", - rows: [ - { icon: Globe2, label: "Jurisdiction", value: "Western Australia", active: true }, - { icon: CircleUserRound, label: "Default population", value: "Adults" }, - { icon: SlidersHorizontal, label: "Answer style", value: "Conservative" }, - ], - }, - { - title: "App preferences", - rows: [ - { - icon: Palette, - label: "Appearance", - value: currentThemeLabel, - onClick: onToggleTheme, - actionLabel: `Switch to ${theme === "dark" ? "light" : "dark"} mode`, - }, - { icon: SettingsIcon, label: "Interface density", value: "Comfortable" }, - ], - }, - ]; - const navItems = [ - { icon: SettingsIcon, label: "General" }, - { icon: Stethoscope, label: "Clinical defaults" }, - { icon: Sparkles, label: "Personalisation" }, - { icon: Bell, label: "Notifications" }, - { icon: LockKeyhole, label: "Security" }, - { icon: CircleUserRound, label: "Account", active: true }, - { icon: Keyboard, label: "Keyboard" }, - { - icon: HelpCircle, - label: "Help & About", - onClick: () => { - onClose(); - onOpenGuide(); - }, - }, - ]; - - const closeButton = ( - - ); - - return ( - -
- {closeButton} - - -
-
-
-

- Account & app -

-
- - Clinician account - -
- -
-

- Clinical Guide account -

-
- - {signedOutAccount ? : identity.initials} - {identity.signedIn ? ( - - ) : null} - -
-

- {identity.displayName} -

-

- {signedOutAccount ? "Sign in or create an account" : "Consultant psychiatrist, Western Australia"} -

-
- {signedOutAccount ? ( -
- - -
- ) : ( -
- - -
- )} -
- - {signedOutAccount ? ( -
-
- - -
- - {emailEntryOpen ? ( -
- - -
- ) : null} - -
- - or continue with - -
- -
- chooseSettingsProvider("Apple")} /> - chooseSettingsProvider("Google")} /> - chooseSettingsProvider("Microsoft")} /> - -
- -

- - Accounts save preferences and search history. Do not enter PHI. -

- - {(accountNotice || !auth.isConfigured || (settingsEmailAttempted && auth.error)) && ( -

- {accountNotice ?? - (settingsEmailAttempted ? auth.error : null) ?? - "Supabase browser authentication is not configured for account sign-in."} -

- )} -
- ) : ( - - )} -
- -
- - - -
- -
-
- {settingSections.map((section) => ( -
-

- {section.title} -

-
- {section.rows.map((row) => ( - - ))} - {section.title === "Account" && identity.signedIn ? ( - { - onSignOut(); - onClose(); - }} - actionLabel="Sign out" - /> - ) : null} -
-
- ))} -
- { - onClose(); - onOpenGuide(); - }} - /> -
-
-
-
- ); -} - -function SettingsChip({ label }: { label: string }) { - return ( - - {label} - - ); -} - -function SettingsProviderRow({ - provider, - onClick, -}: { - provider: "Apple" | "Google" | "Microsoft" | "email"; - onClick: () => void; -}) { - const label = provider === "email" ? "Use email instead" : provider; - - return ( - - ); -} - -function SettingsProviderMark({ provider }: { provider: "Apple" | "Google" | "Microsoft" }) { - if (provider === "Microsoft") { - return ( -