diff --git a/src/lib/domain/__tests__/validation.test.ts b/src/lib/domain/__tests__/validation.test.ts index c645177..cc069c4 100644 --- a/src/lib/domain/__tests__/validation.test.ts +++ b/src/lib/domain/__tests__/validation.test.ts @@ -122,6 +122,24 @@ describe("domain validation", () => { expect(parsed.ai_taste_checks[0]?.rule_id).toBe("promotion_tone"); }); + it("normalizes empty AI taste check evidence from LLM copy results", () => { + const parsed = copyOptimizationResultSchema.parse({ + optimized_text: "我把句子顺了一下。", + change_notes: [], + ai_taste_checks: [ + { + rule_id: "promotion_tone", + status: "pass", + evidence: "", + suggestion: "", + }, + ], + warnings: [], + }); + + expect(parsed.ai_taste_checks[0]?.evidence).toBe("未提供具体证据。"); + }); + it("accepts an unconfirmed optimization fact card with unresolved items", () => { const parsed = optimizationFactCardSchema.parse({ company_full_name: "", diff --git a/src/lib/domain/validation.ts b/src/lib/domain/validation.ts index c4198b1..8105c3a 100644 --- a/src/lib/domain/validation.ts +++ b/src/lib/domain/validation.ts @@ -217,6 +217,14 @@ const optionalLlmStringSchema = z.preprocess((value) => { return normalizeStringValue(value); }, z.string().trim().default("")); +const fallbackLlmEvidenceSchema = z.preprocess((value) => { + const normalized = normalizeStringValue(value); + if (typeof normalized === "string" && normalized.trim().length === 0) { + return "未提供具体证据。"; + } + return normalized; +}, z.string().trim().min(1)); + const stringListSchema = z.preprocess( normalizeStringList, z.array(z.string().trim().min(1)).default([]), @@ -480,7 +488,7 @@ const copyAiTasteCheckSchema = z.object({ "filler_hedging", ]), status: z.enum(["pass", "warn"]), - evidence: requiredLlmStringSchema, + evidence: fallbackLlmEvidenceSchema, suggestion: optionalLlmStringSchema, }) satisfies z.ZodType;