From 1bdb79e7346d9075fb8694baa114eaf392400ae9 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Tue, 13 Oct 2026 12:42:13 +0800 Subject: [PATCH 01/53] feat(audit): comprehensive repository audit remediation across phases 1, 2, and 3 --- .../audit/full-repository-audit-2026-10-11.md | 215 ++++++++++++++ docs/codebase-index.md | 1 + .../2026-10-11-parallel-repository-audit.md | 274 ++++++++++++++++++ .../2026-10-12-phase-1-critical-hotfixes.md | 125 ++++++++ .../plans/2026-10-13-phase-2-hardening.md | 122 ++++++++ .../plans/2026-10-13-phase-3-refinement.md | 36 +++ src/lib/bounded-ttl-cache.ts | 21 ++ src/lib/calculators/clinical-math/index.ts | 4 + src/lib/calculators/clinical-math/lithium.ts | 111 +++++++ src/lib/calculators/clinical-math/qtc.ts | 100 +++++++ src/lib/calculators/clinical-math/renal.ts | 120 ++++++++ src/lib/calculators/clinical-math/types.ts | 94 ++++++ src/lib/chunking.ts | 38 ++- src/lib/medications/tall-man.ts | 70 +++++ src/lib/openai.ts | 19 +- src/lib/query-privacy.ts | 26 +- src/lib/rag/rag-cache.ts | 12 +- src/lib/rag/rag-versioning.ts | 2 + src/lib/rag/rag.ts | 15 +- src/lib/signed-url-cache.ts | 11 +- tests/bounded-ttl-cache.test.ts | 34 ++- tests/chunking-negation.test.ts | 41 +++ tests/clinical-math-calculators.test.ts | 247 ++++++++++++++++ tests/privacy.test.ts | 36 +++ tests/rag-generation-fingerprint.test.ts | 7 + tests/rag-prompt-injection.test.ts | 33 +++ tests/setup-node.test.ts | 22 ++ tests/setup/node.setup.ts | 8 + tests/tall-man-lettering.test.ts | 43 +++ tests/ui-chrome-scroll.spec.ts | 30 +- worker/python/extract_pdf_assets.py | 7 + 31 files changed, 1893 insertions(+), 31 deletions(-) create mode 100644 docs/audit/full-repository-audit-2026-10-11.md create mode 100644 docs/superpowers/plans/2026-10-11-parallel-repository-audit.md create mode 100644 docs/superpowers/plans/2026-10-12-phase-1-critical-hotfixes.md create mode 100644 docs/superpowers/plans/2026-10-13-phase-2-hardening.md create mode 100644 docs/superpowers/plans/2026-10-13-phase-3-refinement.md create mode 100644 src/lib/calculators/clinical-math/index.ts create mode 100644 src/lib/calculators/clinical-math/lithium.ts create mode 100644 src/lib/calculators/clinical-math/qtc.ts create mode 100644 src/lib/calculators/clinical-math/renal.ts create mode 100644 src/lib/calculators/clinical-math/types.ts create mode 100644 src/lib/medications/tall-man.ts create mode 100644 tests/chunking-negation.test.ts create mode 100644 tests/clinical-math-calculators.test.ts create mode 100644 tests/rag-prompt-injection.test.ts create mode 100644 tests/setup-node.test.ts create mode 100644 tests/setup/node.setup.ts create mode 100644 tests/tall-man-lettering.test.ts diff --git a/docs/audit/full-repository-audit-2026-10-11.md b/docs/audit/full-repository-audit-2026-10-11.md new file mode 100644 index 0000000000..973d06ec1f --- /dev/null +++ b/docs/audit/full-repository-audit-2026-10-11.md @@ -0,0 +1,215 @@ +# Comprehensive Full-Repository Forensic Audit Report: PsychSift + +**Repository:** `BigSimmo/PsychSift` +**Date:** October 11, 2026 +**Auditor:** Antigravity AI Review Swarm (7 Parallel Autonomous Domain Agents) +**Execution Mode:** Pure Forensic Read-Only (Zero Code Mutations, Zero Live External API Calls) +**Git Baseline:** `feat/scoped-resilience-and-ui-hardening` (Commit: `adcc101ab2`, Base: `origin/main` at `73d08a5a78`) + +--- + +## 1. Executive Summary & Clinical Overview + +This report delivers the findings of an exhaustive, parallel multi-agent forensic audit across the entire PsychSift codebase. Seven specialized autonomous auditors simultaneously evaluated the repository across distinct clinical, architectural, security, accessibility, and quality domains. + +### Overall System Health + +PsychSift displays **exceptional engineering maturity** in several foundational areas: + +- **Client-Side Ergonomics & Accessibility:** A centralized `LiveAnnouncer` screen-reader singleton, two-phase focus restoration in sheets/drawers, strict suppression of misleading "0 matches" on failed network searches (`ErrorState`), and WCAG 2.1 AA tokenized color contrast. +- **API Boundary Discipline:** 100% of API route payloads are validated with strict Zod schemas with centralized error envelope wrapping (`jsonError`). +- **Postgres Row-Level Security:** 100% of database tables have Row-Level Security enabled (`ENABLE ROW LEVEL SECURITY`) with `auth.uid()` tenant confinement. +- **Offline Evaluation Culture:** Robust golden datasets and deterministic offline retrieval scoring pipelines. + +### Primary Risks & Critical Vulnerabilities + +Despite these strengths, the audit identified **3 Critical Blockers (P0)** and **9 High-Severity Issues (P1)** that warrant immediate attention: + +1. **Unbounded Serverless Memory Leak (P0 / MEM-01):** Module-level in-memory `Map` caches (`answerCache`, `queryEmbeddingCache`, `signedUrlCache`) accumulate entries indefinitely across requests in warm serverless instances, leading to heap exhaustion (OOM crashes) and cross-tenant memory leakage. +2. **Total Absence of Medical Math / Clinical Calculators (P0 / CS-001):** While psychometric rating scales (PHQ-9, GAD-7, K10) are implemented, all clinical dosing calculators (renal clearance / Cockcroft-Gault, eGFR, QTc interval correction formulas, and lithium/clozapine titration helpers) are completely absent from `src/lib/calculators/`. +3. **Vitest Mock Leakage & State Bleed (P0 / TS-01):** The Vitest Node test suite configuration omits setup files that restore mocks (`vi.restoreAllMocks()`), leaving global stubs (`Date`, `fetch`, timers) leaking across suites and causing non-deterministic CI failures. +4. **Clinical Drug Selection Hazards (P1 / CS-002):** Flat lowercase medication entity names without ISMP Tall Man lettering for look-alike/sound-alike drugs (e.g., `clozapine` vs `clonidine`, `hydroxyzine` vs `hydralazine`). +5. **Prompt Injection in Clinical RAG (P1 / INJ-01):** Direct interpolation of unescaped user query strings into LLM prompts without delimiter sanitization, allowing prompt jailbreaks and overriding clinical guardrails. +6. **React Hydration Mismatches (P1 / FE-HYD-01 to 04):** Direct evaluation of browser globals (`window.location.search`, `BarcodeDetector`) during initial component render causes layout flicker and console errors. +7. **Severe Cumulative Layout Shift (P1 / FE-CLS-01):** Global search shell hard reloads snap from a full-height hero to a compact bottom dock after hydration. +8. **Mobile Search Chrome Contract Breach (P1 / A11Y-01):** `DocumentViewer.tsx` retains a `0.75rem` pad on scroll-hide, violating the repository's core invariant ("Hidden means zero reserve: exactly 0rem"). + +--- + +## 2. Severity Classification Matrix + +| Severity Level | Definition | Impact on PsychSift | +| :------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------- | +| **P0 (Critical Blocker)** | Immediate patient safety risk, production crash / memory leak, or broken test harness preventing reliable verification. | Must be remediated before production deployment or clinical user exposure. | +| **P1 (High Priority)** | Substantial functional, clinical, or architectural flaw (prompt injection, hydration mismatch, chunk negation severing, mobile contract breach). | Remediation required in the current release cycle. | +| **P2 (Medium Priority)** | Moderate flaw, performance bottleneck, test flakiness, or maintenance burden (unclosed PDF handles, missing test timeouts, large client bundles). | Scheduled remediation in upcoming sprints. | +| **P3 (Advisory / Low)** | Cosmetic inconsistency, minor hygiene gap, or defense-in-depth recommendation (cookie flags, stale type casts, minor accessibility attributes). | Addressed during routine maintenance. | + +--- + +## 3. Master Findings Matrix + +| Ref ID | Sev | Domain | File & Line | Summary Description | Clinical / Technical Consequence | +| :------------ | :----: | :-------------------- | :------------------------------------------------------------------------------------------------------------------ | :----------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------- | +| **MEM-01** | **P0** | TypeScript / API | `src/lib/rag/rag-cache.ts:36-44`
`src/lib/openai.ts:65, 72`
`src/lib/signed-url-cache.ts:29` | Unbounded module-level `Map` caches in serverless environment. | Memory leaks / OOM crashes in warm containers; potential cross-tenant memory leakage. | +| **CS-001** | **P0** | Clinical Safety | `src/lib/calculators/` | Total absence of clinical dosing & medical math calculators (renal clearance, QTc, lithium titration). | Clinicians using PsychSift have psychometric scales but no safety calculators for high-risk psychiatric prescribing. | +| **TS-01** | **P0** | Test Suite | `vitest.config.mts:118` | Vitest Node environment omits `setupFiles` with `vi.restoreAllMocks()`. | Leaked mocks (`Date`, `fetch`, timers) cause non-deterministic CI flakes across test suites. | +| **CS-002** | **P1** | Clinical Safety | `src/lib/medication-entities.ts:69, 72, 344` | Flat lowercase medication names lacking ISMP Tall Man lettering. | Increased cognitive error and selection hazard for look-alike/sound-alike drugs (e.g. clozapine vs clonidine). | +| **CS-003** | **P1** | Clinical Safety | `src/lib/medication-interaction-lexicon.ts:108-138` | Non-stocked external contraindicated interactants excluded from active alerts. | Critical contraindications (e.g., St John's Wort with SSRIs/SNRIs) do not trigger automated interaction warnings. | +| **CHK-01** | **P1** | AI / RAG | `src/lib/chunking.ts:405-407` | Semantic chunker falls back to arbitrary string slice on short prefixes. | Splits critical clinical sentences across chunk boundaries, severing negations ("DO NOT administer"). | +| **INJ-01** | **P1** | AI / RAG | `src/app/api/answer/route.ts`
`src/lib/rag/rag.ts` | Direct interpolation of unsanitized user query into LLM prompt template. | Prompt injection allowing user search queries to override clinical guidelines and safety guardrails. | +| **FE-HYD-01** | **P1** | Frontend Architecture | `src/components/roster/manage/roster-manage-page.tsx:172`
`src/components/roster/swaps/roster-swaps-page.tsx:88` | Browser `window.location.search` evaluated during initial React component render. | Severe React hydration mismatch, breaking SSR tree reconciliation and causing UI flash. | +| **FE-HYD-02** | **P1** | Frontend Architecture | `src/components/clinical-dashboard/differentials-home.tsx:990-1010` | Checkbox state initialized from URL query parameters without two-pass hydration guard. | Hydration mismatch on direct-linked or refreshed differential search queries. | +| **FE-HYD-03** | **P1** | Frontend Architecture | `src/components/teaching-attendance/teaching-qr-checkin-sheet.tsx:32` | `"BarcodeDetector" in window` checked directly in component render body. | Hydration error on client render when server SSR renders fallback state. | +| **FE-CLS-01** | **P1** | Frontend Architecture | `src/components/clinical-dashboard/global-search-shell.tsx:352-357` | Hard reload on submitted search URL (`?q=...&run=1`) renders full hero, snapping to bottom dock. | Severe Cumulative Layout Shift (CLS), jarring user experience and layout jump on mobile/desktop. | +| **MEM-02** | **P1** | TypeScript / API | `src/app/api/search/route.ts:79`
`src/lib/shared-get.ts:19` | In-flight promise tracking `Map` lacks timeout and cleanup guarantees on aborted requests. | Stalled or aborted client connections permanently pin promise references in memory. | +| **TS-02** | **P1** | Test Suite | `tests/ui-chrome-scroll.spec.ts:226`
`tests/ui-smoke.spec.ts:3404` | >20 instances of hardcoded `page.waitForTimeout(1000)` arbitrary sleeps in Playwright. | Fragile, slow test runs susceptible to machine load and race conditions. | +| **A11Y-01** | **P1** | Accessibility / UX | `src/components/DocumentViewer.tsx:1377-1391` | Declares `data-phone-composer-reserve="0.75rem"` on hidden search composer. | Directly violates repository design invariant: "Hidden means zero reserve: exactly 0rem". | +| **SEC-01** | **P2** | Security / Privacy | `src/lib/privacy.ts:6`
`src/app/api/answer/stream/route.ts:113` | `safeErrorLogDetails` redacts structured keys but passes raw error strings to logger. | Incidental PHI leakage: patient names or identifiable text in query error messages flushed to server logs. | +| **CS-004** | **P2** | Clinical Safety | `src/lib/medications/` | Absence of centralized zero-dosing formatter utility across medication displays. | Risk of trailing zeros (`5.0 mg` misread as 50 mg) or missing leading zeros (`.5 mg` misread as 5 mg). | +| **CS-005** | **P2** | Clinical Safety | `src/lib/medications/` | QTc risk evaluated per-drug rather than cumulative polypharmacy set calculation. | Underestimates arrhythmia risk when multiple moderately-prolonging psychotropics are combined. | +| **PY-01** | **P2** | AI / RAG | `worker/python/extract_pdf_assets.py:234, 386` | PyMuPDF `Document` and `Pixmap` instances lack explicit `.close()` calls in processing loop. | Python worker OOM crash and file descriptor leaks during bulk extraction of large clinical guidelines. | +| **RAG-01** | **P2** | AI / RAG | `src/lib/rag/rag.ts:716-735` | `safeFallbackAnswer` returns unparsed plain text bypassing structured citation checks. | Degraded trust: user receives answer without explicit provenance links or citation audit trails. | +| **FE-CLS-02** | **P2** | Frontend Architecture | `src/components/on-call/on-call-home.tsx:321-370` | `TodayShell` relies on `empty:hidden` containers populating asynchronously. | Above-the-fold content shifts downward as widgets load, degrading Core Web Vitals. | +| **FE-ARC-01** | **P2** | Frontend Architecture | `src/app/(search-app)/layout.tsx` | Root shell layout bundles `GlobalSearchShell` and `MasterSearchHeader` across all routes. | 5.60 MB gzip bundle overhead imposed on lightweight work pages (`/my-day`, `/roster`, `/teaching`). | +| **FE-INP-01** | **P2** | Frontend Architecture | `src/components/dsm/dsm-search-page.tsx`
`src/components/differentials/` | Client-side filtering and matrix calculation executed synchronously on the main thread. | Long tasks (>50ms) causing typing stutter and poor Interaction to Next Paint (INP) responsiveness. | +| **TS-03** | **P2** | Test Suite | `tests/ui-smoke.spec.ts` | Dynamic `test.skip(({ browserName }) => browserName !== "chromium")` silently bypasses WebKit/Firefox. | Tests pass on CI but leave Safari and Firefox rendering engines unverified. | +| **TS-04** | **P2** | Test Suite | `tests/ui-smoke.spec.ts` | Synthetic `setTimeout` promises inside `route.fulfill()` network mocks. | Delays test execution artificially without testing true network latency characteristics. | +| **A11Y-02** | **P2** | Accessibility / UX | `src/components/phone-focus-clearance.tsx:54` | Focus clearance bails out on elements outside `.phone-scroll-surface`. | Inputs inside bottom `Sheet` overlays risk being occluded by mobile virtual software keyboards. | +| **A11Y-03** | **P2** | Accessibility / UX | `src/components/compare/compare-empty-state.tsx:30-49` | Primary action button and starter chips lack explicit `focusRing` / focus-visible utilities. | Ambiguous keyboard focus indicator under custom themes or high-contrast settings. | +| **SEC-02** | **P3** | Security / Privacy | `src/app/auth/callback/route.ts:121` | `PASSWORD_RECOVERY_COOKIE` lacks `httpOnly: true` flag. | Advisory: cookie accessible via client JavaScript; should be strictly `httpOnly`. | +| **WRK-01** | **P3** | AI / RAG | `worker/main.ts:177-194` | Read-modify-write on `documents.metadata` executed via client update if RPC is missing. | Potential data race if multiple workers update metadata concurrently without optimistic locking. | +| **A11Y-04** | **P3** | Accessibility / UX | `src/components/clinical-dashboard/search-pins-menu.tsx:351` | Search pin text input relies on parent `