fix(ai-moderation): skip caching error results to prevent false positives from transient failures
This commit is contained in:
@@ -1685,24 +1685,38 @@ export async function runModerationAnalysis(
|
|||||||
try {
|
try {
|
||||||
const cached = await getCachedUserModeration(cacheKey);
|
const cached = await getCachedUserModeration(cacheKey);
|
||||||
if (cached) {
|
if (cached) {
|
||||||
cacheHits.push({
|
// Safety: skip cache entries that are artifacts of API/parse errors.
|
||||||
messageId: target.id,
|
// A previous bug cached error results as "flagged", causing 24h false positives.
|
||||||
status: cached.status,
|
// This guards against both legacy corrupt entries and any future write-path bugs.
|
||||||
flags: cached.flags,
|
if (
|
||||||
score: cached.score,
|
cached.flags.some((f) =>
|
||||||
analysis: cached.analysis,
|
["analysis_api_failed", "analysis_parse_failed", "analysis_incomplete"].includes(f),
|
||||||
categories: cached.categories,
|
)
|
||||||
severity: cached.severity as AnalysisResult["severity"],
|
) {
|
||||||
confidence: cached.confidence,
|
log.warn(
|
||||||
recommendedAction: cached.recommendedAction as AnalysisResult["recommendedAction"],
|
{ messageId: target.id, cacheKey },
|
||||||
policyVersion: "cached-user-moderation-2026-06",
|
"Cache entry contains error artifact — treating as miss",
|
||||||
evidence: [],
|
);
|
||||||
});
|
} else {
|
||||||
log.debug(
|
cacheHits.push({
|
||||||
{ messageId: target.id, userId: target.user_id, cacheKey },
|
messageId: target.id,
|
||||||
"User moderation cache HIT — reusing previous result",
|
status: cached.status,
|
||||||
);
|
flags: cached.flags,
|
||||||
continue;
|
score: cached.score,
|
||||||
|
analysis: cached.analysis,
|
||||||
|
categories: cached.categories,
|
||||||
|
severity: cached.severity as AnalysisResult["severity"],
|
||||||
|
confidence: cached.confidence,
|
||||||
|
recommendedAction: cached.recommendedAction as AnalysisResult["recommendedAction"],
|
||||||
|
policyVersion: "cached-user-moderation-2026-06",
|
||||||
|
evidence: [],
|
||||||
|
});
|
||||||
|
log.debug(
|
||||||
|
{ messageId: target.id, userId: target.user_id, cacheKey },
|
||||||
|
"User moderation cache HIT — reusing previous result",
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
// Cache lookup failed — proceed with uncached path
|
// Cache lookup failed — proceed with uncached path
|
||||||
@@ -1767,6 +1781,10 @@ export async function runModerationAnalysis(
|
|||||||
const rawContent = target.edited_content ?? target.content;
|
const rawContent = target.edited_content ?? target.content;
|
||||||
if (!rawContent.trim()) continue;
|
if (!rawContent.trim()) continue;
|
||||||
|
|
||||||
|
// Do NOT cache error results (API failures, parse failures, incomplete).
|
||||||
|
// Caching a transient error would turn it into a 24h false positive.
|
||||||
|
if (result.status === "error") continue;
|
||||||
|
|
||||||
const cacheKey = makeUserModerationCacheKey(target.user_id, rawContent);
|
const cacheKey = makeUserModerationCacheKey(target.user_id, rawContent);
|
||||||
setCachedUserModeration(cacheKey, {
|
setCachedUserModeration(cacheKey, {
|
||||||
flags: result.flags ?? [],
|
flags: result.flags ?? [],
|
||||||
@@ -1776,7 +1794,7 @@ export async function runModerationAnalysis(
|
|||||||
severity: result.severity ?? "none",
|
severity: result.severity ?? "none",
|
||||||
confidence: result.confidence ?? result.score ?? 0,
|
confidence: result.confidence ?? result.score ?? 0,
|
||||||
recommendedAction: result.recommendedAction ?? "none",
|
recommendedAction: result.recommendedAction ?? "none",
|
||||||
status: result.status === "error" ? "flagged" : result.status,
|
status: result.status,
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user