fix(report): name final-parse guards and scrub blocked wording
Independent Staging Quality Gate / validate (push) Successful in 12m11s
Independent Staging Quality Gate / publish (push) Successful in 1m57s

Five-theme assemble cleared the chart and actionNotes caps, then failed
three anonymous guards. Log field path plus kind only, and strip
deterministic phrases from sections the producer already marked blocked.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-04 23:09:21 +08:00
parent a68fd01f68
commit 4ef4c4064f
7 changed files with 142 additions and 8 deletions
@@ -12,6 +12,7 @@ import {
findChartSetViolations,
findDanglingEvidenceRefs,
findDuplicateEvidenceIds,
classifyReportDocumentGuardError,
CURRENT_REPORT_DOCUMENT_SCHEMA_VERSION,
LEGACY_REPORT_DOCUMENT_SCHEMA_VERSION,
REPORT_DOCUMENT_SCHEMA_VERSION,
@@ -404,3 +405,28 @@ test("v2 guard rejects HTML and CSS while allowing ordinary Chinese prose", () =
assert.equal(findForbiddenContent(ordinary.actionNotes[0].note).length, 0);
assert.equal(safeParseReportDocument(ordinary).ok, true);
});
test("guard parse errors expose field path and kind without the offending value", () => {
const missing = cloneV2();
missing.blockedConflictDisclosure = missing.blockedConflictDisclosure.filter(
(section) => section.theme !== "career",
);
const coverage = safeParseReportDocument(missing);
assert.equal(coverage.ok, false);
assert.ok(coverage.errors.some((error) => (
error.path === "requestedThemes" && error.code === "theme_coverage"
)));
const medical = cloneV2();
medical.actionNotes[0].note = "你已经患有糖尿病。";
const forbidden = safeParseReportDocument(medical);
assert.equal(forbidden.ok, false);
assert.ok(forbidden.errors.some((error) => (
error.path === "actionNotes[0].note" && error.code === "forbidden_medical_diagnosis"
)));
assert.ok(forbidden.errors.every((error) => !error.path.includes("糖尿病")));
assert.equal(
classifyReportDocumentGuardError("thematicNarrative[1]: blocked section contains deterministic prediction").code,
"blocked_deterministic",
);
});
@@ -572,7 +572,7 @@ test("guard redacts precise timing and downgrades the section when timing is blo
id: "career",
theme: "career",
title: "事业",
narrative: "方向稳定。2027年3月将迎来事业转折,届时务必把握机会。",
narrative: "方向稳定。2027年3月将迎来事业转折,届时务必把握机会。命主一定会升职。",
actions: ["2027年3月跳槽"],
caveats: [],
claimStatus: "single_system_inference",
@@ -587,6 +587,7 @@ test("guard redacts precise timing and downgrades the section when timing is blo
const section = (guarded.document as unknown as { thematicNarrative: { narrative: string; claimStatus: string; caveats: string[] }[] })
.thematicNarrative[0];
assert.doesNotMatch(section.narrative, /2027年3月/);
assert.doesNotMatch(section.narrative, /一定会/);
assert.equal(section.claimStatus, "blocked");
assert.ok(section.caveats.some((caveat) => caveat.includes("确定性边界")));
});