Audit re-triage (all 21 closed), line-level H2 sanitizer fix, fast-check property suite#338
Conversation
…l markers
H2 line-level residue, found by the new fast-check property suite: extraction
glues control markers ('Document owner:', 'review date') onto body text, and
stripInternalImageDataBlocks compacts excerpts to a single line before
stripLowYieldLines runs — so the control-line filter deleted whole clinical
lines when they carried threshold values but no clinical keyword. Shrunken
counterexample: 'The Glasgow Coma Scale ranges from 3 to 15 with 1 or below
indicating severe head injury. Document owner: Pharmacy Department.'
sanitized to an empty string.
The line-level heuristics now get the same clinicalThresholdSignalPattern
rescue the fragment-level heuristics received in the original H2 fix: a line
carrying unit-bearing figures, ranges, or comparatives is never dropped by the
control-line/source-marker rules. Pure control lines without clinical values
are still removed (pinned by test).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds fast-check (dev dependency) and three property-test files wired into the existing vitest suite: - property-numeric-token-preservation: no unit-bearing numeric token (doses, ranges, percentages, comparatives) ever disappears through clinicalProseUsefulness, sourceTextForDisplay, sourceTextForModel, or sourceTextForVerbatimQuote, across generated clinical prose with injected provenance/control/banner noise. This suite caught the line-level H2 residue fixed in the previous commit. - property-chunking: chunkTextWithOverlap terminates for any size/overlap combination including overlap >= chunkSize (audit M17 region), loses no characters (order-preserving subsequence check tolerant of overlap duplication), and invents nothing (every chunk is a contiguous run of the input). Generators respect removePageNoise's documented line contracts so the assertions target the chunker, not the noise filter. - property-accessible-table: normalizeAccessibleTable always yields a rectangular grid, never invents or loses numeric values, preserves row counts for first-cell-anchored rows, flags ambiguous clinical tables low-confidence with the raw grid preserved 1:1, and the low-confidence caveat survives both formatAnswerForClipboard and formatWardNote (audit H4/M8/M16 invariants), with a non-vacuity canary. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
All 21 findings (H1-H4, M1-M17) from the 2026-07-01 audit verified closed on current main; H3 closed by PR #118 supersession. Documents the eval debt for the sanitizer fix (eval:quality --rag-only needs live keys) per the standing gates. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ract comment Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…operty-tests # Conflicts: # docs/process-hardening.md
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
CI status note: all three checks (verify, Gitleaks, ui-smoke) failed at job start, before any step ran — GitHub reports "The job was not started because recent account payments have failed or your spending limit needs to be increased" (Actions billing). Not a code failure. Local 🤖 Generated with Claude Code |
Co-authored-by: BigSimmo <BigSimmo@users.noreply.github.com>
…operty-tests # Conflicts: # docs/process-hardening.md
…s' into claude/audit-sweep-property-tests
Summary
docs/audit/repo-audit-2026-07-01.md(H1–H4, M1–M17) was verified against current main, code-level, not comment-level. All 21 are closed (table below), so the planned Phase 2 fix list was a no-op.fast-check(dev dependency) and three property suites wired into vitest, pinning the text-processing core's clinical invariants over generated inputs.stripLowYieldLines(src/lib/source-text-sanitizer.ts) — extraction glues document-control markers ("Document owner:", "review date") onto body text, and several callers compact excerpts to a single line before the filter runs, so a line carrying threshold values but no clinical keyword was deleted wholesale. Shrunken counterexample:"The Glasgow Coma Scale ranges from 3 to 15 with 1 or below indicating severe head injury. Document owner: Pharmacy Department."sanitized to an empty string. The line-level heuristics now get the sameclinicalThresholdSignalPatternrescue the fragment-level heuristics received in the original H2 fix.Triage table (all 21 findings vs current main)
sourceTextForResultincludesretrieval_synopsis, image text, and table-fact metadata (answer-verification.ts:112–132, incl. the R4 completion)clinicalThresholdSignalPatternrescue inclinicalProseUsefulness(source-text-sanitizer.ts);stripLowYieldLineslacked the same rescue → commit 1 hereretrieval-selection.ts:329–336. The residualMath.maxfloor only affects intent-based boosts, and un-flooring it was already tried and withdrawn (audit R1: penalties compounded across the 2–3 selection passes). Re-opening it requires the live golden eval, which this environment cannot run — deliberately untouched.clinicalTableToTextRowsroutes throughnormalizeAccessibleTable(conservativeClinical) and emits the caveat line (ward-output.ts:604–636); now also property-testedderiveConfidencescoped to cited chunks (rag.ts:744–753)containsAny(clinical-search.ts:605–615)explicitDoseTermssurvive escalation cancellation (clinical-search.ts:796–813)structuralTableguard before the bare yes/no flowchart branch (document-index-units.ts:290–296)confirmedCandidates(document-organization.ts:1668–1689)evidenceText, bracket-stripped (document-organization.ts:1566–1588)\bbmj\btoken (document-organization.ts:270–275)ward-output.ts:612–622); property-testedpending+processing, plus the PR #278 TOCTOU re-check (documents/[id]/route.ts:504–558)searchRequestSeqRefrequest-token guard incl. progress messages (ClinicalDashboard.tsx:2646+)deep-memory.ts:646–650)image-filtering.ts:343–385)20260702000000_commit_generation_preserve_legacy_artifacts.sqlin-tree; live-apply verification (npm run check:m13-migration) needs live keys unavailable herechunking.ts:20–25)RAG_QUERY_HASH_SECRETset (query-privacy.ts)normalizeAccessibleTable(ward-output.ts); property-testedchunkTextBySentence(chunking.ts:363–369); property-tested incl.overlap >= chunkSizeProperty suite (Phase 3)
tests/property-numeric-token-preservation.test.ts— no unit-bearing numeric token (doses, ranges, percentages, comparatives) ever disappears throughclinicalProseUsefulness,sourceTextForDisplay,sourceTextForModel, orsourceTextForVerbatimQuote, across generated clinical prose with injected provenance/control/banner noise. This suite found the line-level H2 residue.tests/property-chunking.test.ts—chunkTextWithOverlapterminates for any size/overlap combination includingoverlap >= chunkSize(the M17 region), loses no characters (order-preserving subsequence check tolerant of overlap duplication), and invents nothing (every chunk is a contiguous run of the input).tests/property-accessible-table.test.ts—normalizeAccessibleTablealways yields a rectangular grid, never invents or loses numeric values, preserves row counts for first-cell-anchored rows, flags ambiguous clinical tables low-confidence with the raw grid preserved 1:1, and the low-confidence caveat survives bothformatAnswerForClipboardandformatWardNote(H4), with a non-vacuity canary.Side observation (no change made here):
removePageNoisedeliberately drops whole lines of ≤ 2 chars as extraction debris, which would delete a wrapped unit-only line ("12.5\nmg" → "mg" line lost). The property generators respect that documented contract. A spun-off session is fixing this onclaude/chunking-unit-lines(rejoinWrappedDoseUnits); commit8bd318670on this branch (authored by that session) updates the generator comment to forward-reference it — the function lands via that branch, not this one.Verification
npm run verify:cheap— see eval/verification status belownpm run verify:ui— N/A (no UI/routing/styling change)npm run verify:release— N/Anpm run format:check— clean on all changed filesnpm run eval:retrieval:quality— N/A for this branch: no retrieval/selection/ranking/chunking behavior changed (H3 deliberately untouched; chunking changes are tests-only)npm run eval:rag -- --limit 15+npm run eval:quality -- --rag-only— REQUIRED before merge, could not run: this machine has no live Supabase/OpenAI keys (npm run check:supabase-projectreports env unset; no.env.localexists). The sanitizer fix is answer-path post-processing, so per the standing gate these must be run before merging. Debt recorded indocs/process-hardening.md("Audit re-triage & property-test suite (2026-07-06)"). The change is strictly keep-more-text (a line is rescued if it carries threshold values; nothing new is dropped), so grounded-supported should not drop — but the gate still needs to be run.npm run check:production-readiness— not run (no env/privacy/governance behavior change; sanitizer change is covered by the eval gate above)npm run check:deployment-readiness— N/ATest/verify status detail:
verify:cheapon the merged tree (postorigin/mainmerge): exit 0 — 132 files / 1194 tests, all passing, pluscheck:runtime,sitemap:check, lint, and typecheck.tests/universal-search.test.ts(untouched by this branch) hit its 15s per-test timeout under parallel load; it passes 8/8 in isolation and in the final gate — load-induced flake, noting for visibility.Clinical Governance Preflight
Clinical KB Database(sjrfecxgysukkwxsowpy) — no Supabase config touchedNotes
origin/main(56 commits, including the tools-catalog and cross-mode-links merges) was merged into this branch before opening the PR; the only conflict was the appendeddocs/process-hardening.mdsection (both entries kept).verify:cheapwas re-run on the merged tree.935e9d6ab). Of the 56 new main commits, the only audited file touched isClinicalDashboard.tsx, and its M10 request-token guard (searchRequestSeqRef) is untouched and still present post-merge (re-verified). All other audited functions are unchanged by the new commits.npm run check:supabase-project→NEXT_PUBLIC_SUPABASE_URL/SUPABASE_PROJECT_REF/SUPABASE_PROJECT_NAMEall unset, and no.env.localexists on this machine. This is why the eval gates above are recorded as pre-merge debt rather than run.🤖 Generated with Claude Code