From d228d01244be8b6ac34b8142fe845420bcdbd14a Mon Sep 17 00:00:00 2001 From: 134 Date: Tue, 20 Oct 2026 02:00:23 +0800 Subject: [PATCH] fix(canvas): retry uncertain text inspection without replaying image generation --- lib/canvas/layout-replace-text-lock.ts | 6 ++++++ tests/integration/layout-replace-validation.test.ts | 9 +++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/canvas/layout-replace-text-lock.ts b/lib/canvas/layout-replace-text-lock.ts index dc31c5af0..02ee04623 100644 --- a/lib/canvas/layout-replace-text-lock.ts +++ b/lib/canvas/layout-replace-text-lock.ts @@ -50,6 +50,12 @@ export function parseLayoutReplaceTextCheck(text: string) { if (normalize(d.original) === normalize(d.result)) return []; return [`原文「${d.original}」,结果「${d.result}」`]; }); + // An uncertain or unexplained verdict is a verifier failure, not evidence + // of a bad generated image. Let the read-only fallback inspect it; never + // trigger another paid image generation based on an empty accusation. + if (value.uncertain || (!value.identical && !differences.length)) { + throw new Error("模版文案检查没有给出可确认的具体结论"); + } return { passed: value.identical && !value.uncertain && !differences.length && value.confidence >= 0.8, confidence: value.confidence, differences: [...new Set(differences)].slice(0, 8).map(d => d.slice(0, 160)) }; } diff --git a/tests/integration/layout-replace-validation.test.ts b/tests/integration/layout-replace-validation.test.ts index 959970bab..96be4edac 100644 --- a/tests/integration/layout-replace-validation.test.ts +++ b/tests/integration/layout-replace-validation.test.ts @@ -123,8 +123,8 @@ test("text verification refuses discount/price changes, uncertain reading and in const good = { identical: true, uncertain: false, confidence: .95, differences: [] }; assert.equal(parseLayoutReplaceTextCheck(JSON.stringify(good)).passed, true); assert.equal(parseLayoutReplaceTextCheck(JSON.stringify({ ...good, passed: true, differences: ["8.7折变成6.7折"] })).passed, false); - assert.equal(parseLayoutReplaceTextCheck(JSON.stringify({ ...good, uncertain: true })).passed, false); - assert.equal(parseLayoutReplaceTextCheck(JSON.stringify({ ...good, identical: false })).passed, false); + assert.throws(() => parseLayoutReplaceTextCheck(JSON.stringify({ ...good, uncertain: true }))); + assert.throws(() => parseLayoutReplaceTextCheck(JSON.stringify({ ...good, identical: false }))); for (const value of ["null", "{}", JSON.stringify({ ...good, confidence: "0.95" }), JSON.stringify({ ...good, differences: [1] })]) { assert.throws(() => parseLayoutReplaceTextCheck(value)); } @@ -154,6 +154,11 @@ test("independently observed support types reject added legs without confusing t assert.throws(() => parseLayoutReplaceSupport('{"supportType":"maybe","confidence":0.95}')); }); +test("an unexplained or uncertain text verdict cannot trigger paid semantic regeneration", () => { + assert.throws(() => parseLayoutReplaceTextCheck(JSON.stringify({ identical: false, uncertain: false, confidence: .95, differences: [] }))); + assert.throws(() => parseLayoutReplaceTextCheck(JSON.stringify({ identical: true, uncertain: true, confidence: .95, differences: [] }))); +}); + test("quality rejection covers identity, background direction, copy loss, collage and low confidence", () => { assert.equal(quality().passed, true); for (const changes of [{ sourceProductPreserved: false }, { templateLayoutPreserved: false },