diff --git a/frontend/src/components/birth-time-rectification.tsx b/frontend/src/components/birth-time-rectification.tsx index c7a07940..b608f12c 100644 --- a/frontend/src/components/birth-time-rectification.tsx +++ b/frontend/src/components/birth-time-rectification.tsx @@ -69,6 +69,8 @@ export function BirthTimeRectification(props: BirthTimeRectificationProps) { const heading = dynamicHeading(action); const error = props.controller.error || props.externalError; const showsProgress = action.kind !== "ask_dynamic_choice" && action.kind !== "clarify_unmatched_answer"; + const childOwnsError = action.kind === "ask_dynamic_choice" + || action.kind === "clarify_unmatched_answer"; const showsCandidate = action.kind === "present_low_result" || action.kind === "present_medium_result" || action.kind === "request_candidate_confirmation" @@ -122,7 +124,7 @@ export function BirthTimeRectification(props: BirthTimeRectificationProps) { journey={props.journey} /> ) : null} - {error && !showsCandidate ?

{error}

: null} + {error && !showsCandidate && !childOwnsError ?

{error}

: null} ); } diff --git a/frontend/src/lib/birth-time-guided-preview.ts b/frontend/src/lib/birth-time-guided-preview.ts index 66e22dca..cdfd4897 100644 --- a/frontend/src/lib/birth-time-guided-preview.ts +++ b/frontend/src/lib/birth-time-guided-preview.ts @@ -141,15 +141,6 @@ export function guidedBirthTimePreview(mode: string): JourneyClientResponse { progress: { ...response().progress, phase: "adaptive", baselineDomainCount: 3, confirmedEvidenceCount: 3, adaptiveRound: 1 }, }); } - if (mode === "birth-time-rectification-low") { - return response({ - snapshot: { ...response().snapshot, state: "candidate", input: "candidate_actions", confidence: "low", assistantIntent: "explain_event_evidence_insufficient" }, - candidateResult: { ...candidate, confidence: "low", canApply: false }, - turnVersion: 6, - nextAction: { kind: "present_low_result", resultId }, - progress: { ...response().progress, phase: "result", baselineDomainCount: 3, confirmedEvidenceCount: 4, adaptiveRound: 3 }, - }); - } const candidateSnapshot = { ...response().snapshot, state: "candidate", diff --git a/frontend/tests/birth-time-guided-review-fixes.test.ts b/frontend/tests/birth-time-guided-review-fixes.test.ts index 84b4f4e8..3c950bc6 100644 --- a/frontend/tests/birth-time-guided-review-fixes.test.ts +++ b/frontend/tests/birth-time-guided-review-fixes.test.ts @@ -34,6 +34,7 @@ test("draft revision publishes its new version before confirmation can fail", as }); test("low without a result and saved medium both return to declared-time editing safely", () => { + const dynamicLow = dynamicBirthTimePreview("low"); const low = guidedBirthTimePreview("birth-time-rectification-low"); const nullResultLow = parseJourneyResponse({ ...low, @@ -42,6 +43,7 @@ test("low without a result and saved medium both return to declared-time editing }); const saved = guidedBirthTimePreview("birth-time-rectification-saved"); + assert.equal(dynamicLow.candidateResult, null); assert.deepEqual(guidedTerminalPath(nullResultLow), { kind: "edit_birth_time_details", preservesCase: true, @@ -121,6 +123,7 @@ test("ready completion is explicit and terminal low has no finish mutation", () test("terminal candidate owns one explicit next step and its completion error", () => { const candidateResultSource = readFileSync(new URL("../src/components/birth-time-candidate-result.tsx", import.meta.url), "utf8"); + const choiceQuestionSource = readFileSync(new URL("../src/components/birth-time-choice-question.tsx", import.meta.url), "utf8"); const rectificationSource = readFileSync(new URL("../src/components/birth-time-rectification.tsx", import.meta.url), "utf8"); const legacyRectificationSource = readFileSync(new URL("../src/components/birth-time-legacy-rectification.tsx", import.meta.url), "utf8"); const globalCssSource = readFileSync(new URL("../src/app/globals.css", import.meta.url), "utf8"); @@ -130,7 +133,9 @@ test("terminal candidate owns one explicit next step and its completion error", assert.match(candidateResultSource, /正在采用 \$\{path\.time\}…/); assert.match(candidateResultSource, /birth-time-next-step/); assert.match(rectificationSource, /error=\{error\}/); - assert.match(rectificationSource, /error && !showsCandidate/); + assert.match(rectificationSource, /const childOwnsError = action\.kind === "ask_dynamic_choice"\s*\|\| action\.kind === "clarify_unmatched_answer"/); + assert.match(rectificationSource, /error && !showsCandidate && !childOwnsError/); + assert.equal(choiceQuestionSource.match(/role="alert"/g)?.length, 1); assert.match(legacyRectificationSource, /error=\{error\}/); assert.match(legacyRectificationSource, /error && !showsCandidate/); assert.match(globalCssSource, /\.birth-time-next-step/); diff --git a/frontend/tests/birth-time-rectification-contract.test.ts b/frontend/tests/birth-time-rectification-contract.test.ts index 05fecfed..e1a3bab0 100644 --- a/frontend/tests/birth-time-rectification-contract.test.ts +++ b/frontend/tests/birth-time-rectification-contract.test.ts @@ -33,6 +33,7 @@ test("low-confidence preview mirrors the persisted dynamic terminal state", () = assert.equal(low.snapshot.state, "rectifying"); assert.equal(low.nextAction.kind, "present_low_result"); assert.ok(low.candidateResult); + assert.equal(low.candidateResult.winningSegment?.representativeTime, "05:21"); assert.equal(low.nextAction.resultId, low.candidateResult.resultId); assert.deepEqual(guidedTerminalPath(low), { kind: "complete_with_candidate",