From dfec2865f7b40d060f7055d3d129b771c8de7c08 Mon Sep 17 00:00:00 2001 From: BigSimmo <87357024+BigSimmo@users.noreply.github.com> Date: Fri, 24 Jul 2026 12:56:16 +0800 Subject: [PATCH 1/3] docs: record next patch review --- docs/branch-review-ledger.md | 1 + package-lock.json | 166 +++++++++------------------- package.json | 8 +- src/app/api/search/route.ts | 6 +- src/components/ui/sheet.tsx | 1 + src/lib/search-scope.ts | 45 ++++++-- tests/pdf-extraction-budget.test.ts | 9 +- tests/private-access-routes.test.ts | 41 ++++++- tests/search-scope.test.ts | 161 ++++++++++++++++++++++++++- 9 files changed, 309 insertions(+), 129 deletions(-) diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index f9e9f3b56..2ce0825c9 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -697,3 +697,4 @@ Use this ledger to prevent repeated branch and PR reviews when the reviewed HEAD | 2026-07-21 | claude/clinical-kb-pwa-review-asi3wb (Option A wave verdict — no code change; #1040 merged as cde6c5c) | canary run 29827012719 (#61, main cde6c5c) vs banked #60 (29800029819) | OPTION A WAVE ADOPTED — FIRST FULLY-GREEN 44-CASE CANARY IN PROGRAM HISTORY (Blocking failures: None). (1) Option A payoff EXCEEDED: citation_failure_rate 0.0227→0; the neuroleptic-side-effect-escalation case flipped from wrong-doc→failed-generation→1-citation-fallback to **strong route, successful gpt-5.6-sol generation, passed in 15.4s with no fallback marker** — the rescued S3 retrieval fixed generation itself, not just the citation count; expected_source_hit 0.6364→0.6591. (2) Golden held exactly as the blast-radius analysis promised: 36/36 PASS, content_recall 1.0, mrr@10 0.8921 BYTE-IDENTICAL to the pre-wave baseline (zero ordering movement — no golden case fires the predicate), irrelevant@10 0.1083→0.0917 (slightly better). (3) Parity payoff PARTIAL: monitoring targeting 1/5→2/5 (olanzapine-lai flipped — previously called a retrieval-depth residual; quetiapine-dose also flipped on the dose side); lithium-range (232ch) + metabolic (73ch, byte-identical answer to #60) did NOT flip despite offline-proven fixes — their live chunk sets evidently contain no admissible schedule sentence even under the widened gate → reclassified as retrieval-depth/live-content residuals joining adhd; below the ≥3/5 target but strictly improved, no regression anywhere. Dose 2/5 vs 2/4: same passing count, applicable set grew (new quality-metformin-renal-dosing miss = eval-set churn, not regression). (4) No-worse EXCEEDED: relevance 0.5333→0.6 (the two-step watch-item slide FULLY REVERSED to the #58 level), targeting_rate 0.6667→0.6957, fail_closed 0.9 held, readability/artifact_leaks 1.0, route ceilings 0, grounded 1.0, unsupported_correct 1.0, numeric 0, p95 22.8s, red_result 3/3. Adoption per the measured-gain rule: primary goal achieved, three case flips, relevance recovered, zero regressions. Residual queue: monitoring retrieval-depth trio (lithium-range/metabolic/adhd), E-3d H2 discards, weekly ANSWER_CASE_LIMIT 8→44 raise now unblocked (gate would be green), comparison-class coverage. Wave spend +~$2-4 → Phase E + Option A total ~$12-20 of ≤$20. | Evidence: run #61 job log read (Threshold Status: None; Answer Metrics; neuroleptic diagnostics row; targeting metric_rates + 6-miss list; golden 36 PASS lines + summary). Revert drill NOT triggered. | | 2026-07-21 | claude/clinical-kb-pwa-review-asi3wb (PR: I9 weekly coverage raise) | see PR head | ADDENDUM 5 post-green item I9 (plan-authorized "after reds fixed"): weekly scheduled canary ANSWER_CASE_LIMIT default 8→44 — the Sunday 18:00 UTC cron now guards the FULL answer-quality case set instead of the first 8 (both #57 blocking reds historically lived OUTSIDE the first 8, leaving the weekly gate blind to them). Unblocked by run #61 proving the citation gate green on the full 44. Cost: est +$1-2/week (user-authorized in the plan). Contract test pin updated in lockstep (eval-canary-workflow.test.ts). Dispatch shapes unchanged (input override still wins); operational-risk diff, plain-revert rollback. | check:github-actions PASS; check:ci-scope PASS; check:gate-manifest PASS (20/20); eval-canary-workflow contract 4/4; prettier clean; no provider calls | | 2026-07-21 | claude/database-governance-audit-10b6ed (PR #1051: source-governance audit — safe subset) | cee396730 | Governance-metadata observability + UI display + provenance flow test; no ranking/retrieval/generation surface touched. | IMPLEMENTED + handed off (not a review of prior work). Resolved audit #1 (logger.warn on unrecognized enum values; return value unchanged), #2 (review_due_source added to frontendVisibleWarningCodes → answer-level badge; warning-severity, no refusal impact), #9 (source_metadata retained on safety-finding citations + governance pill in SafetyFindingsListContent), #13 (new tests/provenance-flow.test.ts: DB-normalize→governance→client payload sources+safety citations→render policy). Deferred #4/5/6/8/10 (RAG-protected ranking/selection/LLM-context/cache — need live eval-canary+approval), #11/#5 flag debt (D5/D4), #3 (is_public schema/RLS), #7 (conflict-detection scope), #12 (canary automation). Rebased onto origin/main (was 18 behind; conflict-free — none of the 18 commits touched the 8 files). PR-policy CI green (confirmed no ragRankingPatterns match). | verify:pr-local exit 0 (351 files/3129 tests, production build, client-bundle secret scan, offline RAG fixtures 36/36); typecheck + lint + prettier green. verify:ui NOT run locally: pre-existing globals.css Tailwind/Turbopack dev-compile error (git-clean, unrelated; prod build passed) — CI Production UI job covers it. check:production-readiness deferred (offline env/config validator; PR changes no env/secret/config inputs; secretless worktree). No provider calls. | +| 2026-07-24 | work (latest commit review: Next security patch + merge-readiness stabilizers) | e6bdd3478a94fd535b7fffe1d0e330ae1263f735 | Scoped local review requested by user for remaining ASAP issues after latest PR commit. | No high-confidence code defect found in the current latest-commit diff. Recommended remaining ASAP work is process/environmental rather than another code patch: run the merge-readiness gate on Node 24.x, fetch/provide `main` or a remote so a true checkout-against-main check can run, and keep provider-backed/live gates approval-gated. Evidence: Next packages are updated to 16.2.11 in package.json/package-lock; sheet teardown guard prevents `document` access after DOM teardown; PDF deadline test now avoids scheduler-start race and zombie false-positive. Search-scope files were not changed by the latest commit. | Local inspection: git status/HEAD/branch/remotes, latest commit diff, docs/codex-review-protocol.md. Prior checks from the commit: focused search/private-access tests passed, PDF/sheet focused tests passed, typecheck passed, npm audit high found 0 vulnerabilities. `npm run verify:cheap` remains blocked in this container by Node v20.20.2 vs repo Node 24.x engine / `node:module.registerHooks`; no hosted CI, GitHub, Supabase, OpenAI, or live provider calls. | diff --git a/package-lock.json b/package-lock.json index 60d0f777a..c79d9c007 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,14 +10,14 @@ "hasInstallScript": true, "license": "UNLICENSED", "dependencies": { - "@next/env": "16.2.10", + "@next/env": "16.2.11", "@supabase/ssr": "^0.12.3", "@supabase/supabase-js": "^2.110.7", "exceljs": "^4.4.0", "jszip": "^3.10.1", "lucide-react": "^1.25.0", "mammoth": "^1.12.0", - "next": "^16.2.10", + "next": "^16.2.11", "openai": "^6.48.0", "pdf-parse": "^2.4.5", "pdfjs-dist": "^6.1.200", @@ -31,7 +31,7 @@ "devDependencies": { "@axe-core/playwright": "^4.12.1", "@babel/parser": "^8.0.4", - "@next/bundle-analyzer": "^16.2.10", + "@next/bundle-analyzer": "^16.2.11", "@tailwindcss/postcss": "^4.3.3", "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "^7.0.0", @@ -45,7 +45,7 @@ "@vitest/coverage-v8": "^4.1.10", "esbuild": "0.28.1", "eslint": "^9.39.5", - "eslint-config-next": "16.2.10", + "eslint-config-next": "16.2.11", "fast-check": "^4.8.0", "jsdom": "^29.1.1", "knip": "^6.27.0", @@ -1523,9 +1523,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1542,9 +1539,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1561,9 +1555,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1580,9 +1571,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1599,9 +1587,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1618,9 +1603,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1637,9 +1619,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1656,9 +1635,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -1675,9 +1651,6 @@ "cpu": [ "arm" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1700,9 +1673,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1725,9 +1695,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1750,9 +1717,6 @@ "cpu": [ "riscv64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1775,9 +1739,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1800,9 +1761,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1825,9 +1783,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1850,9 +1805,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "Apache-2.0", "optional": true, "os": [ @@ -2234,9 +2186,9 @@ } }, "node_modules/@next/bundle-analyzer": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/bundle-analyzer/-/bundle-analyzer-16.2.10.tgz", - "integrity": "sha512-KcepWhb3IVniZgm00GSSCQDEUQqZXuXtuXRh8J6e3Un342TcQ77iK4DedeEkct+fcx7yFEDL2J6z4Jeho5JDAw==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/bundle-analyzer/-/bundle-analyzer-16.2.11.tgz", + "integrity": "sha512-C5228wy1RC0g7uOSvmQhrZXCuEeLIPureKkqramAkySmqY2Y0yw6K+TyAxXXvtrYe4uehnZs3YMFfJcorBRwpg==", "dev": true, "license": "MIT", "dependencies": { @@ -2244,15 +2196,15 @@ } }, "node_modules/@next/env": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.10.tgz", - "integrity": "sha512-zLPxg9M0MEHmygpj5OuxjQ+vHMiy/K7cSp74G8ecYolmgUWw0RwN02tF56npup/+qaI8JB97hQgS/r2Hb6QwVA==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.11.tgz", + "integrity": "sha512-0do5A3BJ2gxWr0ZCMcD6BhW+e595jyxdTl3rXTS6lOtD8ektMiW6CO+EPwt1Eca1DBnm90r/7GdiKWBKxH++DA==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.2.10.tgz", - "integrity": "sha512-Gs8D2m21VnJeFo9qvYIIqJH94frWerWYu41BprU1pLtRVF7PCQNLiFZZ3fG+iPuj3K83Cwv/rt+msLOy8Qgu3Q==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.2.11.tgz", + "integrity": "sha512-vMEf/aXOpzFFdtIvFYOnIDPKb0xBbrXONsz83CcKdRrekfxNdL8PNkq5qHqAHSXVlIifnX68LOMaxr3z5PkeLQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2260,9 +2212,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.10.tgz", - "integrity": "sha512-v9IdJCa0H0mbo+8z5zwUpOk1Vj7RjkcI5uNYf5Ws1y6szf/p3Mzl9hLaST8SCt6L9h8NGnruZcd2+o0NTNwDhA==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.11.tgz", + "integrity": "sha512-wryL4pjKmDwGv2ox6+GZDFxvmtSRLqApBR8kL1j4+vhB7Z5vJC/zAnXpiR9Xkfzl0AS8WLMnsuGV/UKI67/rrw==", "cpu": [ "arm64" ], @@ -2276,9 +2228,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.10.tgz", - "integrity": "sha512-17IS0jJRViROGmA9uGdNR8VPJpfbnaVG7E9qhso5jDLkmyd0lSDORWxbcKINzcFqzZqGwGtMSnrFRxBpuUYjLQ==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.11.tgz", + "integrity": "sha512-aZl2j4f/fLyjQvOhv0Oe9UaMAQHolYpKhctsoYzplSumKJKPUmgjcf6545aBtysLTcu994TREd0+pSgNE4ohmg==", "cpu": [ "x64" ], @@ -2292,9 +2244,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.10.tgz", - "integrity": "sha512-GRQRsRtuciNJvB54AvvuQTiq0oZtFwa1owQqtZD8wwnGpM2L39MV22kpI72YSXLKIyY40LC66EiLFv4PiicXxg==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.11.tgz", + "integrity": "sha512-5jEriyEnH/LWFy27L2ZG0XaLlyEJIjhsImEsiS9P563PKEVp2BVups/xfOucIrsvVntp11oNcZwjHvaDPYVB5g==", "cpu": [ "arm64" ], @@ -2308,9 +2260,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.10.tgz", - "integrity": "sha512-zkN9MQYS7UQBro+FnISUq1itaQjXI9xqISzuQ+2bc921NcJ1x4yPCqrn77tVN6/dOOXaaWVX3k6/bR07pPwK+A==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.11.tgz", + "integrity": "sha512-eIjcpx2fnnFSSkZDbTxy74KnokUXDjfoLClpWelfgHLf621aTqswhwXQ7GkD5K5rplrS6LZ/Bj+mVuvzluBOEg==", "cpu": [ "arm64" ], @@ -2324,9 +2276,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.10.tgz", - "integrity": "sha512-iCVJnwvrPYECvA6WM/7+oo+OiTvedIKLxtCLAZP4xZR3nXa1zmzZyLPbYCmWvpd4CvMYF1EMTafd0ii3DygLvA==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.11.tgz", + "integrity": "sha512-8WgzpaWMs46qJT9kiV47cje86L0x/Mu9t8/Gwj+pnbgW3rETVfCnaScPjlYUwNScpOozdcIMHWmAvuZJUonR2w==", "cpu": [ "x64" ], @@ -2340,9 +2292,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.10.tgz", - "integrity": "sha512-ov2g4H0dHY9bPoOU83m91hWT7Iq5qy13bUnyyshLU3HGR1Ownn0X9QpmDPc5iIUaahTp7f7LeGAhV4DSFtackw==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.11.tgz", + "integrity": "sha512-I3UgPds7G4ZYnTb/H+5GBGuUT2DhAk6j0mL6A4s63RjFs74wB2hOWP0vaxsK+3NJraExt3eYEPQ/UtT0x/64Nw==", "cpu": [ "x64" ], @@ -2356,9 +2308,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.10.tgz", - "integrity": "sha512-DwAnhLX76HQiFFQNgWlcK+JzlnD1rZ+UK/WY0ZMI/deXpvgnesjNYrqcfo1JzBuz4Kf7o3brIBL0glI1junatA==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.11.tgz", + "integrity": "sha512-n89CjtcThnjrwgJMAiI5xbqwLY51zvwC9tSlArmVndAJLYVl9T9UAdlkXTmZvE++idoXe8KdglQlhNRdUp1c6g==", "cpu": [ "arm64" ], @@ -2372,9 +2324,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.10.tgz", - "integrity": "sha512-0JXq3b85Jk9Jg4ntLUbXSPvoDw3gpZou7twuKdoFG2jOw635v7+IiXfTaa0TxVMyx78pUjnrVYwLgjKfX4e6/A==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.11.tgz", + "integrity": "sha512-md8CLNggS1Dx9pUgApzps5uAf+N8GN9xywzmNx9vHAWo94HtBwCCqkSnhIrdfQe83Dhz8Lfo/20Nb1Zxal092w==", "cpu": [ "x64" ], @@ -3674,9 +3626,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3694,9 +3643,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3714,9 +3660,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -3734,9 +3677,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -6205,13 +6145,13 @@ } }, "node_modules/eslint-config-next": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.2.10.tgz", - "integrity": "sha512-HSybLOY0QKf39i4FWUqPN0xWiNDi6A6UqJmZtgDkS3zMqjXTqULvj/sueXx3cdCG0mVG+qH6k5/qdegklH1d1w==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.2.11.tgz", + "integrity": "sha512-FIpbK/dUyxUExchDB7eBg3k+VU8R2iR/Cx9/kqTBUTFv2bOIR9aRrpno4rvAQ9VhiPQAyFKNA2NlZwouGWtclA==", "dev": true, "license": "MIT", "dependencies": { - "@next/eslint-plugin-next": "16.2.10", + "@next/eslint-plugin-next": "16.2.11", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", @@ -9159,12 +9099,12 @@ "license": "MIT" }, "node_modules/next": { - "version": "16.2.10", - "resolved": "https://registry.npmjs.org/next/-/next-16.2.10.tgz", - "integrity": "sha512-2som5AVXb3kE6Yjine3/mNbBayYF58eguBWIVVUdr1y/L426xyVEgYxgBG+1QC34P2x5E+tcDup6XkuOAX3dCA==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/next/-/next-16.2.11.tgz", + "integrity": "sha512-B339zaqbyK8cmxhoAvLrcwoabwCP1wz21zSzfqxqXAemTu2BXnH7tQnfcglKv1vnMUIDBc+Hth7XODQriTZiRQ==", "license": "MIT", "dependencies": { - "@next/env": "16.2.10", + "@next/env": "16.2.11", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", @@ -9178,14 +9118,14 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.2.10", - "@next/swc-darwin-x64": "16.2.10", - "@next/swc-linux-arm64-gnu": "16.2.10", - "@next/swc-linux-arm64-musl": "16.2.10", - "@next/swc-linux-x64-gnu": "16.2.10", - "@next/swc-linux-x64-musl": "16.2.10", - "@next/swc-win32-arm64-msvc": "16.2.10", - "@next/swc-win32-x64-msvc": "16.2.10", + "@next/swc-darwin-arm64": "16.2.11", + "@next/swc-darwin-x64": "16.2.11", + "@next/swc-linux-arm64-gnu": "16.2.11", + "@next/swc-linux-arm64-musl": "16.2.11", + "@next/swc-linux-x64-gnu": "16.2.11", + "@next/swc-linux-x64-musl": "16.2.11", + "@next/swc-win32-arm64-msvc": "16.2.11", + "@next/swc-win32-x64-msvc": "16.2.11", "sharp": "^0.34.5" }, "peerDependencies": { diff --git a/package.json b/package.json index 08f1e74a0..a98eeb0bb 100644 --- a/package.json +++ b/package.json @@ -181,14 +181,14 @@ "drift:manifest": "node scripts/run-tsx.mjs scripts/generate-drift-manifest.ts" }, "dependencies": { - "@next/env": "16.2.10", + "@next/env": "16.2.11", "@supabase/ssr": "^0.12.3", "@supabase/supabase-js": "^2.110.7", "exceljs": "^4.4.0", "jszip": "^3.10.1", "lucide-react": "^1.25.0", "mammoth": "^1.12.0", - "next": "^16.2.10", + "next": "^16.2.11", "openai": "^6.48.0", "pdf-parse": "^2.4.5", "pdfjs-dist": "^6.1.200", @@ -211,7 +211,7 @@ "devDependencies": { "@axe-core/playwright": "^4.12.1", "@babel/parser": "^8.0.4", - "@next/bundle-analyzer": "^16.2.10", + "@next/bundle-analyzer": "^16.2.11", "@tailwindcss/postcss": "^4.3.3", "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "^7.0.0", @@ -225,7 +225,7 @@ "@vitest/coverage-v8": "^4.1.10", "esbuild": "0.28.1", "eslint": "^9.39.5", - "eslint-config-next": "16.2.10", + "eslint-config-next": "16.2.11", "fast-check": "^4.8.0", "jsdom": "^29.1.1", "knip": "^6.27.0", diff --git a/src/app/api/search/route.ts b/src/app/api/search/route.ts index c3c3515b3..bfc8de55e 100644 --- a/src/app/api/search/route.ts +++ b/src/app/api/search/route.ts @@ -1022,7 +1022,9 @@ export async function POST(request: Request) { const failurePayload = { results: [], telemetry: { - query_class: classifyRagQuery(error.message).queryClass, + query_class: fallbackBody + ? classifyRagQuery(fallbackBody.query).queryClass + : classifyRagQuery(error.message).queryClass, retrieval_strategy: null, failure_code: code, }, @@ -1031,7 +1033,7 @@ export async function POST(request: Request) { logSearchObservation({ supabase, ownerId, - query: "unknown", + query: fallbackBody?.query ?? "unknown", results: [], payload: failurePayload, failure: { diff --git a/src/components/ui/sheet.tsx b/src/components/ui/sheet.tsx index f0b9eba2b..685ae1310 100644 --- a/src/components/ui/sheet.tsx +++ b/src/components/ui/sheet.tsx @@ -222,6 +222,7 @@ export function Sheet({ window.setTimeout(() => { if ( restoreTarget.isConnected && + typeof document !== "undefined" && document.activeElement !== restoreTarget && document.activeElement === document.body ) { diff --git a/src/lib/search-scope.ts b/src/lib/search-scope.ts index 9e468bd34..fdb7330fb 100644 --- a/src/lib/search-scope.ts +++ b/src/lib/search-scope.ts @@ -22,6 +22,8 @@ const labelTypes = [ const sourceStatusValues = ["current", "review_due", "outdated", "unknown"] as const; const validationStatusValues = ["unverified", "locally_reviewed", "approved"] as const; const documentScopeQueryPageSize = 1000; +const labelScopeDocumentBatchSize = 200; +const labelScopeQueryPageSize = 1000; export const searchScopeFiltersSchema = z .object({ @@ -78,6 +80,7 @@ type ScopeDocumentRow = { }; type ScopeLabelRow = { + id?: string; document_id: string; label: string; label_type: DocumentLabelType; @@ -163,6 +166,39 @@ function labelMatches(labels: ScopeLabelRow[], type: DocumentLabelType, requeste return labels.some((label) => label.label_type === type && wanted.has(normalizeFilterText(label.label))); } +async function loadScopeLabels(args: { + supabase: SupabaseClient; + candidateIds: string[]; + signal?: AbortSignal; +}): Promise { + const rows: ScopeLabelRow[] = []; + + for (let start = 0; start < args.candidateIds.length; start += labelScopeDocumentBatchSize) { + const documentIdBatch = args.candidateIds.slice(start, start + labelScopeDocumentBatchSize); + for (let offset = 0; ; offset += labelScopeQueryPageSize) { + let labelQuery = args.supabase + .from("document_labels") + .select("id,document_id,label,label_type") + .in("document_id", documentIdBatch) + .in("label_type", [...labelTypes]) + .order("document_id", { ascending: true }) + .order("label_type", { ascending: true }) + .order("label", { ascending: true }) + .order("id", { ascending: true }) + .range(offset, offset + labelScopeQueryPageSize - 1); + if (args.signal) labelQuery = labelQuery.abortSignal(args.signal); + + const { data, error } = await labelQuery; + if (error) throw new Error(error.message); + const page = (data ?? []) as ScopeLabelRow[]; + rows.push(...page); + if (page.length < labelScopeQueryPageSize) break; + } + } + + return rows; +} + function isLocalSource(metadata: ClinicalSourceMetadata) { const jurisdiction = `${metadata.jurisdiction ?? ""} ${metadata.publisher ?? ""}`.toLowerCase(); return /\b(?:wa|western australia|north metropolitan|east metropolitan|south metropolitan|perth|health service)\b/.test( @@ -326,14 +362,9 @@ export async function resolveSearchScope(args: { hasValues(filters.labelTypesAny); let labelsByDocument = new Map(); if (needsLabels) { - const { data: labelRows, error: labelError } = await args.supabase - .from("document_labels") - .select("document_id,label,label_type") - .in("document_id", candidateIds) - .in("label_type", [...labelTypes]); - if (labelError) throw new Error(labelError.message); + const labelRows = await loadScopeLabels({ supabase: args.supabase, candidateIds, signal: args.signal }); labelsByDocument = new Map(); - for (const label of (labelRows ?? []) as ScopeLabelRow[]) { + for (const label of labelRows) { labelsByDocument.set(label.document_id, [...(labelsByDocument.get(label.document_id) ?? []), label]); } } diff --git a/tests/pdf-extraction-budget.test.ts b/tests/pdf-extraction-budget.test.ts index f802a8f79..ff7f978cd 100644 --- a/tests/pdf-extraction-budget.test.ts +++ b/tests/pdf-extraction-budget.test.ts @@ -121,7 +121,7 @@ describe("PDF extraction budgets", () => { ); await expect( - runPythonPdfExtractor(inputPath, outputDir, { ...PDF_EXTRACTION_BUDGET, totalTimeoutMs: 1_000 }, fakeExtractor), + runPythonPdfExtractor(inputPath, outputDir, { ...PDF_EXTRACTION_BUDGET, totalTimeoutMs: 3_000 }, fakeExtractor), ).rejects.toMatchObject({ code: "PDF_EXTRACTION_DEADLINE_EXCEEDED" }); const childPid = Number(await readFile(childPidPath, "utf8")); @@ -131,6 +131,13 @@ describe("PDF extraction budgets", () => { while (Date.now() < deadline) { try { process.kill(childPid, 0); + if (process.platform === "linux") { + const stat = await readFile(`/proc/${childPid}/stat`, "utf8").catch(() => ""); + if (stat.split(" ")[2] === "Z") { + childIsAlive = false; + break; + } + } await new Promise((resolve) => setTimeout(resolve, 25)); } catch { childIsAlive = false; diff --git a/tests/private-access-routes.test.ts b/tests/private-access-routes.test.ts index 837b09944..a470d9391 100644 --- a/tests/private-access-routes.test.ts +++ b/tests/private-access-routes.test.ts @@ -1,4 +1,4 @@ -import { createHash } from "node:crypto"; +import { createHash, createHmac } from "node:crypto"; import { afterEach, describe, expect, it, vi } from "vitest"; const userId = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"; @@ -3921,6 +3921,45 @@ describe("private document API access", () => { expect(searchChunksWithTelemetry).not.toHaveBeenCalled(); }); + it("logs failed search telemetry against the parsed query instead of an unknown placeholder", async () => { + vi.stubEnv("NODE_ENV", "production"); + const searchChunksWithTelemetry = vi.fn(async () => ({ + results: [], + telemetry: { retrieval_strategy: "text_fast_path" }, + })); + const client = createSupabaseMock((call) => + call.table === "documents" && call.operation === "select" ? fail("Unregistered API key") : ok([]), + ); + mockRuntime(client, { searchChunksWithTelemetry }); + const { POST } = await import("../src/app/api/search/route"); + + const response = await POST( + authenticatedRequest("/api/search", { + method: "POST", + body: JSON.stringify({ + query: "Clozapine monitoring", + includeRelatedDocuments: false, + filters: { sourceStatuses: ["current"] }, + }), + }), + ); + + expect(response.status).toBe(500); + await vi.waitFor(() => { + const insert = client.calls.find((call) => call.table === "rag_queries" && call.operation === "insert"); + expect(insert).toBeTruthy(); + const payload = insert?.insertPayload as Record; + const expectedHash = createHmac("sha256", "test-query-hash-secret-at-least-16-chars") + .update("clozapine monitoring") + .digest("hex"); + const unknownHash = createHmac("sha256", "test-query-hash-secret-at-least-16-chars") + .update("unknown") + .digest("hex"); + expect(payload.query).toBe(`redacted-query:${expectedHash}`); + expect(payload.query).not.toBe(`redacted-query:${unknownHash}`); + }); + }); + it("falls back to visible demo answers only outside production when Supabase rejects the API key", async () => { const answerQuestionWithScope = vi.fn(async () => ({ answer: "Live answer", diff --git a/tests/search-scope.test.ts b/tests/search-scope.test.ts index 49f2fb6aa..e2a8f16a4 100644 --- a/tests/search-scope.test.ts +++ b/tests/search-scope.test.ts @@ -1,6 +1,84 @@ -import { describe, expect, it } from "vitest"; +import { describe, expect, it, vi } from "vitest"; import { activeScopeFilterCount, resolveSearchScope, searchScopeFiltersSchema } from "@/lib/search-scope"; +type QueryCall = { + table: string; + selected?: string; + range?: { from: number; to: number }; + filters: Array<{ column: string; value: unknown }>; + inFilters: Array<{ column: string; values: unknown[] }>; + orders: string[]; + abortSignals: AbortSignal[]; +}; + +type QueryResult = { data: unknown[]; error: { message: string } | null }; +type QueryResolver = (call: QueryCall) => QueryResult; + +class QueryBuilder implements PromiseLike { + constructor( + private readonly call: QueryCall, + private readonly resolver: QueryResolver, + ) {} + + select(selected: string) { + this.call.selected = selected; + return this; + } + + eq(column: string, value: unknown) { + this.call.filters.push({ column, value }); + return this; + } + + is(column: string, value: unknown) { + this.call.filters.push({ column, value }); + return this; + } + + or() { + return this; + } + + in(column: string, values: unknown[]) { + this.call.inFilters.push({ column, values }); + return this; + } + + order(column: string) { + this.call.orders.push(column); + return this; + } + + range(from: number, to: number) { + this.call.range = { from, to }; + return this; + } + + abortSignal(signal: AbortSignal) { + this.call.abortSignals.push(signal); + return this; + } + + then( + onfulfilled?: ((value: QueryResult) => TResult1 | PromiseLike) | null, + onrejected?: ((reason: unknown) => TResult2 | PromiseLike) | null, + ): PromiseLike { + return Promise.resolve(this.resolver(this.call)).then(onfulfilled, onrejected); + } +} + +function supabaseMock(resolver: QueryResolver) { + const calls: QueryCall[] = []; + return { + calls, + from: vi.fn((table: string) => { + const call: QueryCall = { table, filters: [], inFilters: [], orders: [], abortSignals: [] }; + calls.push(call); + return new QueryBuilder(call, resolver); + }), + }; +} + describe("search scope filters", () => { it("accepts smart document label filter groups", () => { const filters = searchScopeFiltersSchema.parse({ @@ -55,4 +133,85 @@ describe("search scope filters", () => { summary: "All public documents", }); }); + + it("paginates label rows so later-page label matches are not silently dropped", async () => { + const wantedDocumentId = "22222222-2222-4222-8222-222222222222"; + const supabase = supabaseMock((call) => { + if (call.table === "documents") { + return { + data: [ + { id: "11111111-1111-4111-8111-111111111111", metadata: {}, import_batch_id: null }, + { id: wantedDocumentId, metadata: {}, import_batch_id: null }, + ], + error: null, + }; + } + if (call.table === "document_labels") { + if (call.range?.from === 0) { + return { + data: Array.from({ length: 1000 }, (_, index) => ({ + id: `label-${index.toString().padStart(4, "0")}`, + document_id: "11111111-1111-4111-8111-111111111111", + label: "other topic", + label_type: "topic", + })), + error: null, + }; + } + return { + data: [ + { + id: "label-wanted", + document_id: wantedDocumentId, + label: "clozapine", + label_type: "topic", + }, + ], + error: null, + }; + } + return { data: [], error: null }; + }); + + await expect( + resolveSearchScope({ + supabase: supabase as never, + accessScope: { ownerId: "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", includePublic: false }, + filters: { topics: ["clozapine"] }, + }), + ).resolves.toMatchObject({ + documentIds: [wantedDocumentId], + matchedDocumentCount: 1, + }); + + const labelCalls = supabase.calls.filter((call) => call.table === "document_labels"); + expect(labelCalls.map((call) => call.range)).toEqual([ + { from: 0, to: 999 }, + { from: 1000, to: 1999 }, + ]); + expect(labelCalls.every((call) => call.orders.includes("id"))).toBe(true); + }); + + it("propagates caller cancellation to label scope queries", async () => { + const controller = new AbortController(); + const supabase = supabaseMock((call) => { + if (call.table === "documents") { + return { + data: [{ id: "11111111-1111-4111-8111-111111111111", metadata: {}, import_batch_id: null }], + error: null, + }; + } + return { data: [], error: null }; + }); + + await resolveSearchScope({ + supabase: supabase as never, + accessScope: { ownerId: "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa", includePublic: false }, + filters: { labelTypesAny: ["topic"] }, + signal: controller.signal, + }); + + const labelCall = supabase.calls.find((call) => call.table === "document_labels"); + expect(labelCall?.abortSignals).toContain(controller.signal); + }); }); From ed07a614f502a5053431e416110388d9b88f412a Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 24 Jul 2026 06:19:16 +0000 Subject: [PATCH 2/3] docs: correct PR 1132 review ledger head Co-authored-by: BigSimmo --- docs/branch-review-ledger.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index edc2e1999..28196fe88 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -707,4 +707,4 @@ Use this ledger to prevent repeated branch and PR reviews when the reviewed HEAD | 2026-07-21 | claude/clinical-kb-pwa-review-asi3wb (Option A wave verdict — no code change; #1040 merged as cde6c5c) | canary run 29827012719 (#61, main cde6c5c) vs banked #60 (29800029819) | OPTION A WAVE ADOPTED — FIRST FULLY-GREEN 44-CASE CANARY IN PROGRAM HISTORY (Blocking failures: None). (1) Option A payoff EXCEEDED: citation_failure_rate 0.0227→0; the neuroleptic-side-effect-escalation case flipped from wrong-doc→failed-generation→1-citation-fallback to **strong route, successful gpt-5.6-sol generation, passed in 15.4s with no fallback marker** — the rescued S3 retrieval fixed generation itself, not just the citation count; expected_source_hit 0.6364→0.6591. (2) Golden held exactly as the blast-radius analysis promised: 36/36 PASS, content_recall 1.0, mrr@10 0.8921 BYTE-IDENTICAL to the pre-wave baseline (zero ordering movement — no golden case fires the predicate), irrelevant@10 0.1083→0.0917 (slightly better). (3) Parity payoff PARTIAL: monitoring targeting 1/5→2/5 (olanzapine-lai flipped — previously called a retrieval-depth residual; quetiapine-dose also flipped on the dose side); lithium-range (232ch) + metabolic (73ch, byte-identical answer to #60) did NOT flip despite offline-proven fixes — their live chunk sets evidently contain no admissible schedule sentence even under the widened gate → reclassified as retrieval-depth/live-content residuals joining adhd; below the ≥3/5 target but strictly improved, no regression anywhere. Dose 2/5 vs 2/4: same passing count, applicable set grew (new quality-metformin-renal-dosing miss = eval-set churn, not regression). (4) No-worse EXCEEDED: relevance 0.5333→0.6 (the two-step watch-item slide FULLY REVERSED to the #58 level), targeting_rate 0.6667→0.6957, fail_closed 0.9 held, readability/artifact_leaks 1.0, route ceilings 0, grounded 1.0, unsupported_correct 1.0, numeric 0, p95 22.8s, red_result 3/3. Adoption per the measured-gain rule: primary goal achieved, three case flips, relevance recovered, zero regressions. Residual queue: monitoring retrieval-depth trio (lithium-range/metabolic/adhd), E-3d H2 discards, weekly ANSWER_CASE_LIMIT 8→44 raise now unblocked (gate would be green), comparison-class coverage. Wave spend +~$2-4 → Phase E + Option A total ~$12-20 of ≤$20. | Evidence: run #61 job log read (Threshold Status: None; Answer Metrics; neuroleptic diagnostics row; targeting metric_rates + 6-miss list; golden 36 PASS lines + summary). Revert drill NOT triggered. | | 2026-07-21 | claude/clinical-kb-pwa-review-asi3wb (PR: I9 weekly coverage raise) | see PR head | ADDENDUM 5 post-green item I9 (plan-authorized "after reds fixed"): weekly scheduled canary ANSWER_CASE_LIMIT default 8→44 — the Sunday 18:00 UTC cron now guards the FULL answer-quality case set instead of the first 8 (both #57 blocking reds historically lived OUTSIDE the first 8, leaving the weekly gate blind to them). Unblocked by run #61 proving the citation gate green on the full 44. Cost: est +$1-2/week (user-authorized in the plan). Contract test pin updated in lockstep (eval-canary-workflow.test.ts). Dispatch shapes unchanged (input override still wins); operational-risk diff, plain-revert rollback. | check:github-actions PASS; check:ci-scope PASS; check:gate-manifest PASS (20/20); eval-canary-workflow contract 4/4; prettier clean; no provider calls | | 2026-07-21 | claude/database-governance-audit-10b6ed (PR #1051: source-governance audit — safe subset) | cee396730 | Governance-metadata observability + UI display + provenance flow test; no ranking/retrieval/generation surface touched. | IMPLEMENTED + handed off (not a review of prior work). Resolved audit #1 (logger.warn on unrecognized enum values; return value unchanged), #2 (review_due_source added to frontendVisibleWarningCodes → answer-level badge; warning-severity, no refusal impact), #9 (source_metadata retained on safety-finding citations + governance pill in SafetyFindingsListContent), #13 (new tests/provenance-flow.test.ts: DB-normalize→governance→client payload sources+safety citations→render policy). Deferred #4/5/6/8/10 (RAG-protected ranking/selection/LLM-context/cache — need live eval-canary+approval), #11/#5 flag debt (D5/D4), #3 (is_public schema/RLS), #7 (conflict-detection scope), #12 (canary automation). Rebased onto origin/main (was 18 behind; conflict-free — none of the 18 commits touched the 8 files). PR-policy CI green (confirmed no ragRankingPatterns match). | verify:pr-local exit 0 (351 files/3129 tests, production build, client-bundle secret scan, offline RAG fixtures 36/36); typecheck + lint + prettier green. verify:ui NOT run locally: pre-existing globals.css Tailwind/Turbopack dev-compile error (git-clean, unrelated; prod build passed) — CI Production UI job covers it. check:production-readiness deferred (offline env/config validator; PR changes no env/secret/config inputs; secretless worktree). No provider calls. | -| 2026-07-24 | work (latest commit review: Next security patch + merge-readiness stabilizers) | e6bdd3478a94fd535b7fffe1d0e330ae1263f735 | Scoped local review requested by user for remaining ASAP issues after latest PR commit. | No high-confidence code defect found in the current latest-commit diff. Recommended remaining ASAP work is process/environmental rather than another code patch: run the merge-readiness gate on Node 24.x, fetch/provide `main` or a remote so a true checkout-against-main check can run, and keep provider-backed/live gates approval-gated. Evidence: Next packages are updated to 16.2.11 in package.json/package-lock; sheet teardown guard prevents `document` access after DOM teardown; PDF deadline test now avoids scheduler-start race and zombie false-positive. Search-scope files were not changed by the latest commit. | Local inspection: git status/HEAD/branch/remotes, latest commit diff, docs/codex-review-protocol.md. Prior checks from the commit: focused search/private-access tests passed, PDF/sheet focused tests passed, typecheck passed, npm audit high found 0 vulnerabilities. `npm run verify:cheap` remains blocked in this container by Node v20.20.2 vs repo Node 24.x engine / `node:module.registerHooks`; no hosted CI, GitHub, Supabase, OpenAI, or live provider calls. | +| 2026-07-24 | PR #1132 / `codex/review-code-for-bugs-and-issues` (latest commit review: Next security patch + merge-readiness stabilizers) | 444972627e829775510638295665db09422f2812 | Scoped local review requested by user for remaining ASAP issues after latest PR commit. | No high-confidence code defect found in the current latest-commit diff. Recommended remaining ASAP work is process/environmental rather than another code patch: run the merge-readiness gate on Node 24.x, fetch/provide `main` or a remote so a true checkout-against-main check can run, and keep provider-backed/live gates approval-gated. Evidence: Next packages are updated to 16.2.11 in package.json/package-lock; sheet teardown guard prevents `document` access after DOM teardown; PDF deadline test now avoids scheduler-start race and zombie false-positive. Search-scope files were not changed by the latest commit. | Local inspection: git status/HEAD/branch/remotes, latest commit diff, docs/codex-review-protocol.md. Prior checks from the commit: focused search/private-access tests passed, PDF/sheet focused tests passed, typecheck passed, npm audit high found 0 vulnerabilities. `npm run verify:cheap` remains blocked in this container by Node v20.20.2 vs repo Node 24.x engine / `node:module.registerHooks`; no hosted CI, GitHub, Supabase, OpenAI, or live provider calls. | From 31fd421b608d385f0f0623b177f2e8997b870446 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 24 Jul 2026 06:22:41 +0000 Subject: [PATCH 3/3] docs: clarify PR 1132 review scope Co-authored-by: BigSimmo --- docs/branch-review-ledger.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/branch-review-ledger.md b/docs/branch-review-ledger.md index 28196fe88..567feffac 100644 --- a/docs/branch-review-ledger.md +++ b/docs/branch-review-ledger.md @@ -707,4 +707,4 @@ Use this ledger to prevent repeated branch and PR reviews when the reviewed HEAD | 2026-07-21 | claude/clinical-kb-pwa-review-asi3wb (Option A wave verdict — no code change; #1040 merged as cde6c5c) | canary run 29827012719 (#61, main cde6c5c) vs banked #60 (29800029819) | OPTION A WAVE ADOPTED — FIRST FULLY-GREEN 44-CASE CANARY IN PROGRAM HISTORY (Blocking failures: None). (1) Option A payoff EXCEEDED: citation_failure_rate 0.0227→0; the neuroleptic-side-effect-escalation case flipped from wrong-doc→failed-generation→1-citation-fallback to **strong route, successful gpt-5.6-sol generation, passed in 15.4s with no fallback marker** — the rescued S3 retrieval fixed generation itself, not just the citation count; expected_source_hit 0.6364→0.6591. (2) Golden held exactly as the blast-radius analysis promised: 36/36 PASS, content_recall 1.0, mrr@10 0.8921 BYTE-IDENTICAL to the pre-wave baseline (zero ordering movement — no golden case fires the predicate), irrelevant@10 0.1083→0.0917 (slightly better). (3) Parity payoff PARTIAL: monitoring targeting 1/5→2/5 (olanzapine-lai flipped — previously called a retrieval-depth residual; quetiapine-dose also flipped on the dose side); lithium-range (232ch) + metabolic (73ch, byte-identical answer to #60) did NOT flip despite offline-proven fixes — their live chunk sets evidently contain no admissible schedule sentence even under the widened gate → reclassified as retrieval-depth/live-content residuals joining adhd; below the ≥3/5 target but strictly improved, no regression anywhere. Dose 2/5 vs 2/4: same passing count, applicable set grew (new quality-metformin-renal-dosing miss = eval-set churn, not regression). (4) No-worse EXCEEDED: relevance 0.5333→0.6 (the two-step watch-item slide FULLY REVERSED to the #58 level), targeting_rate 0.6667→0.6957, fail_closed 0.9 held, readability/artifact_leaks 1.0, route ceilings 0, grounded 1.0, unsupported_correct 1.0, numeric 0, p95 22.8s, red_result 3/3. Adoption per the measured-gain rule: primary goal achieved, three case flips, relevance recovered, zero regressions. Residual queue: monitoring retrieval-depth trio (lithium-range/metabolic/adhd), E-3d H2 discards, weekly ANSWER_CASE_LIMIT 8→44 raise now unblocked (gate would be green), comparison-class coverage. Wave spend +~$2-4 → Phase E + Option A total ~$12-20 of ≤$20. | Evidence: run #61 job log read (Threshold Status: None; Answer Metrics; neuroleptic diagnostics row; targeting metric_rates + 6-miss list; golden 36 PASS lines + summary). Revert drill NOT triggered. | | 2026-07-21 | claude/clinical-kb-pwa-review-asi3wb (PR: I9 weekly coverage raise) | see PR head | ADDENDUM 5 post-green item I9 (plan-authorized "after reds fixed"): weekly scheduled canary ANSWER_CASE_LIMIT default 8→44 — the Sunday 18:00 UTC cron now guards the FULL answer-quality case set instead of the first 8 (both #57 blocking reds historically lived OUTSIDE the first 8, leaving the weekly gate blind to them). Unblocked by run #61 proving the citation gate green on the full 44. Cost: est +$1-2/week (user-authorized in the plan). Contract test pin updated in lockstep (eval-canary-workflow.test.ts). Dispatch shapes unchanged (input override still wins); operational-risk diff, plain-revert rollback. | check:github-actions PASS; check:ci-scope PASS; check:gate-manifest PASS (20/20); eval-canary-workflow contract 4/4; prettier clean; no provider calls | | 2026-07-21 | claude/database-governance-audit-10b6ed (PR #1051: source-governance audit — safe subset) | cee396730 | Governance-metadata observability + UI display + provenance flow test; no ranking/retrieval/generation surface touched. | IMPLEMENTED + handed off (not a review of prior work). Resolved audit #1 (logger.warn on unrecognized enum values; return value unchanged), #2 (review_due_source added to frontendVisibleWarningCodes → answer-level badge; warning-severity, no refusal impact), #9 (source_metadata retained on safety-finding citations + governance pill in SafetyFindingsListContent), #13 (new tests/provenance-flow.test.ts: DB-normalize→governance→client payload sources+safety citations→render policy). Deferred #4/5/6/8/10 (RAG-protected ranking/selection/LLM-context/cache — need live eval-canary+approval), #11/#5 flag debt (D5/D4), #3 (is_public schema/RLS), #7 (conflict-detection scope), #12 (canary automation). Rebased onto origin/main (was 18 behind; conflict-free — none of the 18 commits touched the 8 files). PR-policy CI green (confirmed no ragRankingPatterns match). | verify:pr-local exit 0 (351 files/3129 tests, production build, client-bundle secret scan, offline RAG fixtures 36/36); typecheck + lint + prettier green. verify:ui NOT run locally: pre-existing globals.css Tailwind/Turbopack dev-compile error (git-clean, unrelated; prod build passed) — CI Production UI job covers it. check:production-readiness deferred (offline env/config validator; PR changes no env/secret/config inputs; secretless worktree). No provider calls. | -| 2026-07-24 | PR #1132 / `codex/review-code-for-bugs-and-issues` (latest commit review: Next security patch + merge-readiness stabilizers) | 444972627e829775510638295665db09422f2812 | Scoped local review requested by user for remaining ASAP issues after latest PR commit. | No high-confidence code defect found in the current latest-commit diff. Recommended remaining ASAP work is process/environmental rather than another code patch: run the merge-readiness gate on Node 24.x, fetch/provide `main` or a remote so a true checkout-against-main check can run, and keep provider-backed/live gates approval-gated. Evidence: Next packages are updated to 16.2.11 in package.json/package-lock; sheet teardown guard prevents `document` access after DOM teardown; PDF deadline test now avoids scheduler-start race and zombie false-positive. Search-scope files were not changed by the latest commit. | Local inspection: git status/HEAD/branch/remotes, latest commit diff, docs/codex-review-protocol.md. Prior checks from the commit: focused search/private-access tests passed, PDF/sheet focused tests passed, typecheck passed, npm audit high found 0 vulnerabilities. `npm run verify:cheap` remains blocked in this container by Node v20.20.2 vs repo Node 24.x engine / `node:module.registerHooks`; no hosted CI, GitHub, Supabase, OpenAI, or live provider calls. | +| 2026-07-24 | PR #1132 / `codex/review-code-for-bugs-and-issues` (latest commit review: Next security patch + merge-readiness stabilizers) | 444972627e829775510638295665db09422f2812 | Scoped local review requested by user for remaining ASAP issues after latest PR commit. | No high-confidence code defect found in the current latest-commit diff. Recommended remaining ASAP work is process/environmental rather than another code patch: run the merge-readiness gate on Node 24.x, fetch/provide `main` or a remote so a true checkout-against-main check can run, and keep provider-backed/live gates approval-gated. Evidence: Next packages are updated to 16.2.11 in package.json/package-lock; `src/lib/search-scope.ts` adds batched label loading and abort propagation; sheet teardown guard prevents `document` access after DOM teardown; PDF deadline test now avoids scheduler-start race and zombie false-positive. | Local inspection: git status/HEAD/branch/remotes, latest commit diff, docs/codex-review-protocol.md. Prior checks from the commit: focused search/private-access tests passed, PDF/sheet focused tests passed, typecheck passed, npm audit high found 0 vulnerabilities. `npm run verify:cheap` remains blocked in this container by Node v20.20.2 vs repo Node 24.x engine / `node:module.registerHooks`; no hosted CI, GitHub, Supabase, OpenAI, or live provider calls. |