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
20 changes: 19 additions & 1 deletion src/lib/answer-render-policy.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -493,6 +493,23 @@ function blockDecisions(args: {
} satisfies Record<AnswerRenderBlock, AnswerRenderDecision>;
}

// P4b: the copy/paste block previously emitted the bare enum ("strong"/"moderate"/"limited"/"none"
// support) — which reads oddly ("none support") and gives no plain-English cue about how well the
// source matched. Gloss it into a clinician-readable phrase so pasted drafts carry interpretable
// source strength.
export function describeSourceStrengthForCopy(strength: SourceStrength | "none"): string {
switch (strength) {
case "strong":
return "strong match";
case "moderate":
return "moderate match";
case "limited":
return "limited match";
default:
return "match strength not rated";
}
}

export function formatAnswerRenderCopyText(args: {
answerText: string;
trust: AnswerRenderTrust;
Expand All@@ -501,7 +518,8 @@ export function formatAnswerRenderCopyText(args: {
}) {
const sourceLines = args.primarySources.length
? args.primarySources.map(
(source, index) => `${index + 1}. ${source.label} | ${source.sourceStrength} support | ${source.href}`,
(source, index) =>
`${index + 1}. ${source.label} | ${describeSourceStrengthForCopy(source.sourceStrength)} | ${source.href}`,
)
: ["No policy-approved sources were attached."];
const warningLines = args.warnings.length ? args.warnings.map((warning) => `- ${warning}`) : ["- None"];
Expand Down
42 changes: 41 additions & 1 deletion tests/answer-render-policy.test.ts
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
import { describe, expect, it } from "vitest";
import { buildAnswerRenderModel } from "../src/lib/answer-render-policy";
import {
buildAnswerRenderModel,
describeSourceStrengthForCopy,
formatAnswerRenderCopyText,
} from "../src/lib/answer-render-policy";
import type {
BestSourceRecommendation,
Citation,
Expand DownExpand Up@@ -262,4 +266,40 @@ describe("answer render policy", () => {
expect(model.quoteCards).toHaveLength(0);
expect(model.allowedBlocks).not.toContain("quoteCards");
});

describe("copy-text source-strength gloss (P4b)", () => {
it("glosses each strength into a clinician-readable phrase and avoids the odd 'none support'", () => {
expect(describeSourceStrengthForCopy("strong")).toBe("strong match");
expect(describeSourceStrengthForCopy("moderate")).toBe("moderate match");
expect(describeSourceStrengthForCopy("limited")).toBe("limited match");
expect(describeSourceStrengthForCopy("none")).toBe("match strength not rated");
});

it("renders the glossed strength in the copy block, not the bare enum", () => {
const link = (
overrides: Partial<Parameters<typeof formatAnswerRenderCopyText>[0]["primarySources"][number]>,
) => ({
id: "s1",
chunk_id: "c1",
document_id: "d1",
title: "T",
file_name: "f.pdf",
page_number: 4,
href: "/documents/doc-1?page=4",
label: "Clozapine Monitoring (AKG)",
sourceStrength: "strong" as const,
reason: "selected",
...overrides,
});
const text = formatAnswerRenderCopyText({
answerText: "Withhold clozapine for a red-range result.",
trust: "high",
primarySources: [link({}), link({ label: "Legacy Note", href: "/documents/doc-2", sourceStrength: "none" })],
warnings: [],
});
expect(text).toContain("Clozapine Monitoring (AKG) | strong match | /documents/doc-1?page=4");
expect(text).toContain("Legacy Note | match strength not rated | /documents/doc-2");
expect(text).not.toContain("none support");
});
});
});
Loading