Screen the whole comprehensive-insight prose surface before it persists

The briefing gate grades numbers only, and only the paragraph, signals and
key-findings blocks -- so a digit-free risk assertion with a dose suggestion
attached passed it untouched, and recommendations and summary were not graded
at all. Screen every readable prose field against the insights contracts.

A safety violation cannot be surgically stripped the way an ungrounded number
can: the offending sentence may sit in any field, and deleting one would leave
the rest referring to it. So the background generator fails the whole run and
persists nothing, leaving the previous cached payload in place, while the
user-initiated route returns an explicit error for the same reason.
This commit is contained in:
Marc-André Bombeck committed 2026-07-19 03:47:23 +02:00
1 parent 70e6e5e374
commit 0becc2a56d
3 files changed
+115

No files matched your search

+21
View File
@@ -58,6 +58,7 @@ import {
runRawCompletionWithFallback,
} from "@/lib/ai/provider-runner";
import { assertConsentForChain } from "@/lib/ai/consent-guard";
import { screenInsightPayloadProse } from "@/lib/ai/safety/insight-payload-screen";
import {
findUngroundedBriefingNumbers,
readBriefingBlock,
@@ -895,6 +896,26 @@ export const POST = apiHandler((request: NextRequest) =>
}
}
// Outbound safety screen over the whole prose surface, before the persist.
//
// This route is user-initiated but writes the SAME cached payload the
// background generator writes, so a violation must not be persisted here
// either. The user is waiting, so unlike the background path they get an
// explicit error rather than silence -- and because nothing was written,
// the previous cached insight is still what the app renders.
const screened = screenInsightPayloadProse(insights, locale);
if (screened) {
annotate({
action: { name: "insights.generate.outbound_blocked" },
meta: { locale, reason: screened },
});
return apiError(
"The generated insight did not pass the safety check and was discarded. Try regenerating.",
502,
{ errorCode: "insights.generate.outboundScreened" },
);
}
await prisma.user.update({
where: { id: userId },
data: {