Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions data/outstanding-issues-snapshot.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,15 +2,15 @@
"version": "outstanding-issues-snapshot-v1",
"ledger_revision": {
"sha": "2327bd9624d788a7b9ecb61eee494f1acd9a1997",
"committed_at": "2026-08-22T06:11:46Z"
"committed_at": "2026-08-22T06:11:46+00:00"
},
"counts": {
"open": 78,
"p1": 2,
"p2": 43,
"p3": 33,
"queued": 11,
"pending": 41,
"pending": 43,
"resolved": 359
},
"queue": [
Expand DownExpand Up@@ -985,6 +985,12 @@
"summary": "Cancel request 54bbb5e0-a573-47e5-9daa-f7eedc4e6b73: Reissued as a single closure that also carries the evidence from cancelled request 993f7ca7, which had independently re-proven the defect in another session. Requests are immutable, so folding that evidence into the outcome means replacing this one rather than editing it.",
"created_at": "2026-08-22"
},
{
"request_id": "98fb14c8-7362-4b4b-934a-e4d8de3d35d3",
"action": "update",
"summary": "#NPQJKP: detail → PACKET 2 IMPLEMENTED 2026-08-22, PR pending. Step 1 falsification CONFIRMED the premise before any production change: generatedAnswerQualityFailureReason returned null for BOTH captured answers at their real eval query classes (medication_dose_risk, document_lookup), run against unmodified source. TWO CORRECTIONS TO THE ROW'S OWN FRAMING, both from reading the code. (1) The gate is NOT unreachable on the grounded first-choice extractive path. rag.ts:3113 is only the review-fallback reason labeller; the ENFORCING call is unconditional inside finalizeRagAnswerQualityCore and the grounded path reaches it via finalizeAnswer -> finalizeRagAnswerQuality. No reachability change was needed or made. The only remaining bypass is the preformatted-and-grounded early return, now named and pinned by a test rather than assumed closed. (2) The wrapper is NOT purely a laundering step. The first predicate version — reject any \"The guidance is that X\" whose continuation lacks a verb from openingSentenceActionPattern — broke tests/rag-extractive-procedural-artifact.test.ts, which pins \"the ECT Coordinator places the patient onto BASE\" as a grounded answer; \"places\" is a real finite verb and rightly absent from a clinical-directive list. SHIPPED: isLaunderedGuidanceWrapperAnswer rejects only two shapes no verb list could rescue — a \">\" breadcrumb pointing at a word rather than a figure, and a bare coordinated noun list with no determiner, auxiliary or directive verb — returning reason guidance_wrapper_fragment. Placed after the other prose gates so nothing already-rejected is relabelled; not in the shouldPreserveSourceBackedGeneratedAnswer rescue allowlist, so a flagged answer cannot be recovered to grounded. clippedClinicalFragmentPattern's four-continuation enumeration is left in place and its cases are still rejected. EVAL IMPACT: eval:rag:offline 627/627 and eval:rag:adversarial:offline 25/25, identical before and after (baseline re-run with GATE_RECEIPTS=refresh). source_backed_review_fallback_count cannot be measured offline; threshold is ragSourceBackedReviewFallbackCount 0 in scripts/eval-quality.ts and PREDICTED to rise by +2 per 30-case capture. Threshold NOT adjusted and should not be. OWNER DECISION LEFT OPEN: quality-antipsychotic-metabolic-monitoring lacks acceptSourceOnly, so once it degrades it fails the live answer-quality eval with \"expected grounded answer\" (its mustContainAny is still satisfied — the source-only text echoes the query). That case asserts a grounded answer for a query whose grounded answer is one of the two incoherent outputs this change rejects; whether it should gain acceptSourceOnly like its discharge sibling is a clinical call and was deliberately not made here. STILL OPEN: the live eval-canary pair, which needs owner approval and is the only thing that can confirm the change.; source → PR #2285; commit 957b76a; docs/rag-improvement/231-diagnosis-2026-08-22.md §3.1-§3.2; src/lib/rag/rag-extractive-answer.ts isLaunderedGuidanceWrapperAnswer",
"created_at": "2026-08-22"
},
{
"request_id": "993f7ca7-5277-4399-82fc-19ff981823e4",
"action": "update",
Expand DownExpand Up@@ -1081,6 +1087,12 @@
"summary": "Cancel request afaa753b-41ae-4bee-8c63-89c649cdcfd5: Duplicate done request created by overlapping command completion; retain 5201bfa7-4966-4583-abff-02305de82219.",
"created_at": "2026-08-21"
},
{
"request_id": "fa499354-66e6-42d3-b880-f5f712a38ae3",
"action": "add",
"summary": "A caring-contacts mockup timer fires after jsdom teardown, so the full unit suite can exit 1 with 8359/8359 passing",
"created_at": "2026-08-22"
},
{
"request_id": "fac29c48-c558-4249-97ed-c86e61b61b97",
"action": "update",
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
| 2026-08-22 | claude/rag-quality-predicate-gap-uw320a | 957b76afa20c4b4667f41cbb0725d71482171228 | Packet 2 (#NPQJKP): answer-quality predicate gap — src/lib/rag/rag-extractive-answer.ts, tests/rag-guidance-wrapper-quality-gate.test.ts, docs/rag-improvement/HANDOVER.md pointer line | SHIPPED as PR #2285 (draft). Falsification confirmed the premise first: generatedAnswerQualityFailureReason returned null for both captured incoherent answers at their real query classes (medication_dose_risk, document_lookup) against unmodified source. Two corrections to the recorded diagnosis: (1) the gate is NOT unreachable on the grounded extractive path — the enforcing call is unconditional inside finalizeRagAnswerQualityCore, reached via finalizeAnswer, so NO reachability change was made; only the preformatted-and-grounded early return remains as a bypass and is now pinned by test. (2) the wrapper is not purely laundering — a first predicate keyed on openingSentenceActionPattern broke the ECT 'places the patient onto BASE' answer pinned by rag-extractive-procedural-artifact, so the shipped predicate rejects only a '>' breadcrumb aimed at a word and a bare coordinated noun list. Placed after the other prose gates so nothing is relabelled; outside the shouldPreserveSourceBackedGeneratedAnswer rescue allowlist. NO ranking, selection, retrieval, prompt or budget change; answerRouteBudgetMs untouched. Live eval-canary pair still owed under owner approval. | verify:pr-local exit 0, all 19 gates completed / none failed (lint, typecheck, test, build, eval:rag:offline, eval:rag:adversarial:offline); a concurrent second invocation exited 75 DATABASE_HEAVY_RUN_ADMISSION_BUSY on self-inflicted lease contention, and a later confirmation re-run hit a PRE-EXISTING unrelated flake (ReferenceError: document is not defined from a 250ms setTimeout in src/components/caring-contacts/mockups/caring-contact-shell-frame.tsx:104 firing after jsdom teardown; 714 files / 8359 tests still passed). typecheck:internal exit 0 on the committed tree. Focused 300/300 across the seven suites exercising this predicate. eval:rag:offline 627/627 and eval:rag:adversarial:offline 25/25, identical before and after with the baseline re-run under GATE_RECEIPTS=refresh. No provider-backed command run; no canary dispatched. |
1 change: 1 addition & 0 deletions docs/design-system/adoption-manifest.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -427,6 +427,7 @@
"tests/probe-generation-quality.test.ts",
"tests/rag-claim-support.test.ts",
"tests/rag-eval-source-governance.test.ts",
"tests/rag-guidance-wrapper-quality-gate.test.ts",
"tests/source-backed-recovery-cross-reference.test.ts",
"tests/ui-smoke.spec.ts",
"tests/ui-v2-components.dom.test.tsx"
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
{
"version": 2,
"id": "98fb14c8-7362-4b4b-934a-e4d8de3d35d3",
"createdOn": "2026-08-22",
"action": "update",
"payload": {
"id": "#NPQJKP",
"detail": "PACKET 2 IMPLEMENTED 2026-08-22, PR pending. Step 1 falsification CONFIRMED the premise before any production change: generatedAnswerQualityFailureReason returned null for BOTH captured answers at their real eval query classes (medication_dose_risk, document_lookup), run against unmodified source. TWO CORRECTIONS TO THE ROW'S OWN FRAMING, both from reading the code. (1) The gate is NOT unreachable on the grounded first-choice extractive path. rag.ts:3113 is only the review-fallback reason labeller; the ENFORCING call is unconditional inside finalizeRagAnswerQualityCore and the grounded path reaches it via finalizeAnswer -> finalizeRagAnswerQuality. No reachability change was needed or made. The only remaining bypass is the preformatted-and-grounded early return, now named and pinned by a test rather than assumed closed. (2) The wrapper is NOT purely a laundering step. The first predicate version — reject any \"The guidance is that X\" whose continuation lacks a verb from openingSentenceActionPattern — broke tests/rag-extractive-procedural-artifact.test.ts, which pins \"the ECT Coordinator places the patient onto BASE\" as a grounded answer; \"places\" is a real finite verb and rightly absent from a clinical-directive list. SHIPPED: isLaunderedGuidanceWrapperAnswer rejects only two shapes no verb list could rescue — a \">\" breadcrumb pointing at a word rather than a figure, and a bare coordinated noun list with no determiner, auxiliary or directive verb — returning reason guidance_wrapper_fragment. Placed after the other prose gates so nothing already-rejected is relabelled; not in the shouldPreserveSourceBackedGeneratedAnswer rescue allowlist, so a flagged answer cannot be recovered to grounded. clippedClinicalFragmentPattern's four-continuation enumeration is left in place and its cases are still rejected. EVAL IMPACT: eval:rag:offline 627/627 and eval:rag:adversarial:offline 25/25, identical before and after (baseline re-run with GATE_RECEIPTS=refresh). source_backed_review_fallback_count cannot be measured offline; threshold is ragSourceBackedReviewFallbackCount 0 in scripts/eval-quality.ts and PREDICTED to rise by +2 per 30-case capture. Threshold NOT adjusted and should not be. OWNER DECISION LEFT OPEN: quality-antipsychotic-metabolic-monitoring lacks acceptSourceOnly, so once it degrades it fails the live answer-quality eval with \"expected grounded answer\" (its mustContainAny is still satisfied — the source-only text echoes the query). That case asserts a grounded answer for a query whose grounded answer is one of the two incoherent outputs this change rejects; whether it should gain acceptSourceOnly like its discharge sibling is a clinical call and was deliberately not made here. STILL OPEN: the live eval-canary pair, which needs owner approval and is the only thing that can confirm the change.",
"source": "PR #2285; commit 957b76a; docs/rag-improvement/231-diagnosis-2026-08-22.md §3.1-§3.2; src/lib/rag/rag-extractive-answer.ts isLaunderedGuidanceWrapperAnswer",
"baseRowFingerprint": "0984e27d9fe481f1ce6b3be42b7d99fd9ae9e08a6749f9156c83e4a5234acd18"
}
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
{
"version": 2,
"id": "fa499354-66e6-42d3-b880-f5f712a38ae3",
"createdOn": "2026-08-22",
"action": "add",
"payload": {
"pri": "P3",
"type": "issue",
"summary": "A caring-contacts mockup timer fires after jsdom teardown, so the full unit suite can exit 1 with 8359/8359 passing",
"detail": "FOUND 2026-08-22 during PR #2285's verification, unrelated to that change. npm run test can exit 1 while reporting 'Test Files 714 passed (714) / Tests 8359 passed | 1 skipped (8360)' plus 'Errors 1 error'. The error is 'ReferenceError: document is not defined' thrown from Timeout._onTimeout at src/components/caring-contacts/mockups/caring-contact-shell-frame.tsx:104, inside the 250ms window.setTimeout that selectDestination schedules when returning from the More sheet; the callback calls document.querySelector after the jsdom environment for tests/caring-contact-product-redesign.dom.test.tsx has been torn down. Timing-dependent: two runs of verify:pr-local on byte-identical content in the same container disagreed — the first completed all 19 gates at exit 0, the second failed at 'test (exit 1)' on this error and never reached build or the eval gates. IMPACT: an unhandled post-teardown error is indistinguishable at the summary line from a real failure, and it can fail a PR whose diff cannot reach the component. The component is design scratch under mockups/, so no production surface is affected. LIKELY FIX: the component already holds focusTimerRef; the gap is that nothing clears it on unmount. A cleanup effect that calls window.clearTimeout(focusTimerRef.current) on teardown, and/or a guard on document existence inside the callback, should close it. STOP: do not respond by skipping, disabling or quarantining tests/caring-contact-product-redesign.dom.test.tsx — the test is not what is broken, the uncancelled timer is.",
"source": "verify:pr-local run 2026-08-22 during PR #2285; src/components/caring-contacts/mockups/caring-contact-shell-frame.tsx:104; tests/caring-contact-product-redesign.dom.test.tsx",
"issueUlid": "01M0MPB6D80YK2S3PCVRBKZ9RN"
}
}
2 changes: 2 additions & 0 deletions docs/rag-improvement/HANDOVER.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -83,6 +83,8 @@ generation-quality verdict on fallback`), merged 2026-08-13 — structured
rejected — generation completed inside the deadline and still failed the quality gate.
Never "fix" A1 by raising `answerRouteBudgetMs` without new evidence that directly rebuts
that recorded result. S1's evidence (2026-08-17) re-confirmed it.
Full evidence and the re-scope of the row itself:
[`231-diagnosis-2026-08-22.md`](231-diagnosis-2026-08-22.md).

## 2. Status table — update in every programme PR

Expand Down
52 changes: 52 additions & 0 deletions src/lib/rag/rag-extractive-answer.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -3243,6 +3243,57 @@ function hasCompleteOpeningSentence(value: string) {
return openingSentenceActionPattern.test(opening);
}

// The extractive completer's last-resort branch (completeExtractiveSentence, above) wraps a
// fragment it could not complete as "The guidance is that <fragment>.", and sentenceFromFact may
// then splice the query entity in as "The guidance for <entity> is that …". The wrapper supplies
// both a terminator and the finite verb "is", so the wrapped result passes
// hasCompleteOpeningSentence even though the text inside it did not.
//
// That wrapper is NOT purely laundering — it legitimately rescues well-formed clauses whose only
// flaw is that openingSentenceActionPattern is a narrow list of clinical directives rather than a
// general finite-verb test ("… the ECT Coordinator places the patient onto BASE" is a real
// sentence built on "places", which is not and should not be on that list). So this gate does not
// ask "does the continuation carry a clinical action". It rejects only two shapes that no verb
// list could rescue, both observed live in the 2026-08-21 capture
// (docs/rag-improvement/231-diagnosis-2026-08-22.md §3.1):
//
// 1. Layout debris: a ">" breadcrumb pointing at a word rather than a number, which is a
// flattened heading trail, not a clinical comparator ("QTc > 500" is untouched).
// 2. A bare coordinated noun list with no determiner, auxiliary or directive verb anywhere —
// "compliance, monitoring and evaluation" — which states nothing that can be checked
// against a source.
//
// Runs after the other prose gates so anything they already reject keeps its existing reason;
// this only catches what nothing else does. clippedClinicalFragmentPattern (rag-answer-text.ts)
// covers the same wrapper for four continuations enumerated one incident at a time, and is
// deliberately left in place rather than replaced.
const launderedGuidanceWrapperPattern = /^the\s+guidance(?:\s+for\s+[^.!?]{1,60}?)?\s+is\s+that\s+(.+?)\.?$/i;
// A ">" aimed at a word, not a figure: "aim > To effectively identify…" is a heading trail left
// by PDF flattening. Numeric comparators ("ANC > 2.0", "eGFR > 30 mL/min") never match.
const guidanceWrapperLayoutDebrisPattern = />\s*[A-Za-z]/;
// A coordinated list of bare nouns: letters, spaces, commas, apostrophes and hyphens only (so a
// clause carrying parentheses, digits, slashes or other punctuation is never judged here), joined
// by a comma or "and"/"or".
const guidanceWrapperNounListShapePattern = /^[A-Za-z][A-Za-z\s,'-]*(?:,|\band\b|\bor\b)[A-Za-z\s,'-]*[A-Za-z]$/;
const guidanceWrapperDeterminerPattern =
/\b(?:the|a|an|this|that|these|those|their|its|his|her|our|your|any|each|every|all|both|no)\b/i;
const guidanceWrapperAuxiliaryPattern =
/\b(?:is|are|was|were|be|been|being|has|have|had|do|does|did|can|could|may|might|must|shall|should|will|would)\b/i;

/** Is laundered guidance wrapper answer. */
export function isLaunderedGuidanceWrapperAnswer(text: string) {
const opening = firstSentence(normalizeSectionText(text)).replace(/\*\*/g, "").trim();
const continuation = opening.match(launderedGuidanceWrapperPattern)?.[1]?.trim();
if (!continuation) return false;
if (guidanceWrapperLayoutDebrisPattern.test(continuation)) return true;
return (
guidanceWrapperNounListShapePattern.test(continuation) &&
!guidanceWrapperDeterminerPattern.test(continuation) &&
!guidanceWrapperAuxiliaryPattern.test(continuation) &&
!openingSentenceActionPattern.test(continuation)
);
}

/** Has invalid model evidence ids. */
export function hasInvalidModelEvidenceIds(answer: Pick<RagAnswer, "routingReason">) {
return /\binvalid_model_citation_ids\b/.test(answer.routingReason ?? "");
Expand All@@ -3261,6 +3312,7 @@ export function generatedAnswerQualityFailureReason(answer: RagAnswer, query: st
if (hasClinicalAnswerQualityIssue(cleanedAnswer)) return "clinical_answer_quality_issue";
if (isLowYieldClinicalText(cleanedAnswer)) return "low_yield_answer";
if (isFragmentLikeClinicalAnswer(cleanedAnswer, query)) return "fragment_like_answer";
if (isLaunderedGuidanceWrapperAnswer(cleanedAnswer)) return "guidance_wrapper_fragment";
if (isMissingCriticalQueryIntent(query, cleanedAnswer)) return "missing_query_intent";
// Core-term (entity/intent) overlap responsiveness check. For extractive/low-confidence answers
// it always applies. For synthesized model answers it is only safe on narrow simple direct
Expand Down
Loading
Loading