fix: complete dynamic choice preview flow
This commit is contained in:
@@ -183,6 +183,11 @@ export function useBirthTimeGuidedJourney(input: GuidedJourneyInput): BirthTimeG
|
||||
};
|
||||
const retryScoring = () => {
|
||||
const turn = journey;
|
||||
if (preview && turn?.journeyProtocol === "dynamic-choice-v2"
|
||||
&& (turn.nextAction.kind === "score_pending" || turn.nextAction.kind === "retry_scoring")) {
|
||||
operate((current) => Promise.resolve(previewAction(current, { kind: "retry_scoring" })));
|
||||
return;
|
||||
}
|
||||
if (turn?.nextAction.kind === "score_pending") {
|
||||
setError("");
|
||||
setPollRun((value) => value + 1);
|
||||
|
||||
@@ -147,14 +147,72 @@ export function advanceDynamicBirthTimePreview(
|
||||
if (action.kind !== "ask_dynamic_choice") return turn;
|
||||
const option = action.question.options.find((item) => item.optionId === command.optionId);
|
||||
if (!option) return turn;
|
||||
const answeredCount = turn.progress.answeredCount + 1;
|
||||
const effectiveAnswerCount = turn.progress.effectiveAnswerCount + (option.kind === "primary" ? 1 : 0);
|
||||
switch (option.kind) {
|
||||
case "unmatched": return dynamicBirthTimePreview("clarification");
|
||||
case "primary": return dynamicBirthTimePreview("scoring");
|
||||
case "unknown": return response({ nextAction: { kind: "ask_dynamic_choice", question: questions[1] }, phase: "question", answeredCount: 1, turnVersion: 2 });
|
||||
case "unmatched": return response({
|
||||
nextAction: { kind: "clarify_unmatched_answer", questionId: action.question.questionId },
|
||||
phase: "clarification",
|
||||
answeredCount,
|
||||
effectiveAnswerCount,
|
||||
turnVersion: turn.turnVersion + 1,
|
||||
});
|
||||
case "primary": {
|
||||
if (action.question.questionId === questions[0].questionId) {
|
||||
return response({
|
||||
nextAction: { kind: "ask_dynamic_choice", question: questions[1] },
|
||||
phase: "question",
|
||||
answeredCount,
|
||||
effectiveAnswerCount,
|
||||
turnVersion: turn.turnVersion + 1,
|
||||
});
|
||||
}
|
||||
return response({
|
||||
nextAction: { kind: "present_medium_result", resultId },
|
||||
phase: "result",
|
||||
answeredCount,
|
||||
effectiveAnswerCount,
|
||||
candidateResult: candidate,
|
||||
snapshotState: "candidate",
|
||||
turnVersion: turn.turnVersion + 1,
|
||||
});
|
||||
}
|
||||
case "unknown": {
|
||||
if (action.question.questionId === questions[0].questionId) {
|
||||
return response({
|
||||
nextAction: { kind: "ask_dynamic_choice", question: questions[1] },
|
||||
phase: "question",
|
||||
answeredCount,
|
||||
effectiveAnswerCount,
|
||||
turnVersion: turn.turnVersion + 1,
|
||||
});
|
||||
}
|
||||
return response({
|
||||
nextAction: { kind: "present_low_result", resultId: null },
|
||||
phase: "result",
|
||||
answeredCount,
|
||||
effectiveAnswerCount,
|
||||
snapshotState: "candidate",
|
||||
turnVersion: turn.turnVersion + 1,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
case "reframe": return response({ nextAction: { kind: "ask_dynamic_choice", question: questions[1] }, phase: "question", answeredCount: 1, turnVersion: 3 });
|
||||
case "finish": return dynamicBirthTimePreview("low");
|
||||
case "reframe": return response({
|
||||
nextAction: { kind: "ask_dynamic_choice", question: questions[1] },
|
||||
phase: "question",
|
||||
answeredCount: turn.progress.answeredCount,
|
||||
effectiveAnswerCount: turn.progress.effectiveAnswerCount,
|
||||
turnVersion: turn.turnVersion + 1,
|
||||
});
|
||||
case "finish": return response({
|
||||
nextAction: { kind: "present_low_result", resultId: null },
|
||||
phase: "result",
|
||||
answeredCount: turn.progress.answeredCount,
|
||||
effectiveAnswerCount: turn.progress.effectiveAnswerCount,
|
||||
snapshotState: "candidate",
|
||||
turnVersion: turn.turnVersion + 1,
|
||||
});
|
||||
case "pause": return dynamicBirthTimePreview("paused");
|
||||
case "resume": return dynamicBirthTimePreview("question");
|
||||
case "retry_scoring": return dynamicBirthTimePreview("medium");
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import test from "node:test";
|
||||
import {
|
||||
choiceQuestionGroups,
|
||||
@@ -45,33 +44,32 @@ test("unmatched requests clarification without creating scoring evidence", () =>
|
||||
assert.equal(normalizeUnmatchedNote("甲".repeat(260)).length, 240);
|
||||
});
|
||||
|
||||
test("the rendered component keeps one-click and optional-note semantics", () => {
|
||||
const source = readFileSync(
|
||||
new URL("../src/components/birth-time-choice-question.tsx", import.meta.url),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
assert.match(source, /<fieldset/);
|
||||
assert.match(source, /<legend/);
|
||||
assert.match(source, /onSelect\(intent\.optionId\)/);
|
||||
assert.match(source, /maxLength=\{240\}/);
|
||||
assert.doesNotMatch(source, /整理为经历草稿|记得的精度|发生时间|第.*\/.*轮/);
|
||||
assert.doesNotMatch(source, /required/);
|
||||
});
|
||||
|
||||
test("preview choices expose real local interaction states without authentication", () => {
|
||||
const start = dynamicBirthTimePreview();
|
||||
const scoring = advanceDynamicBirthTimePreview(start, { kind: "select", optionId: "earlier" });
|
||||
const nextQuestion = advanceDynamicBirthTimePreview(start, { kind: "select", optionId: "earlier" });
|
||||
const result = advanceDynamicBirthTimePreview(nextQuestion, { kind: "select", optionId: "school" });
|
||||
const clarification = advanceDynamicBirthTimePreview(start, { kind: "select", optionId: "unmatched" });
|
||||
const reframed = advanceDynamicBirthTimePreview(clarification, { kind: "reframe" });
|
||||
const terminal = advanceDynamicBirthTimePreview(reframed, { kind: "finish" });
|
||||
|
||||
assert.equal(scoring.nextAction.kind, "score_pending");
|
||||
assert.equal(nextQuestion.nextAction.kind, "ask_dynamic_choice");
|
||||
assert.equal(nextQuestion.progress.effectiveAnswerCount, 1);
|
||||
assert.equal(result.nextAction.kind, "present_medium_result");
|
||||
assert.equal(clarification.nextAction.kind, "clarify_unmatched_answer");
|
||||
assert.equal(reframed.nextAction.kind, "ask_dynamic_choice");
|
||||
assert.equal(terminal.nextAction.kind, "present_low_result");
|
||||
});
|
||||
|
||||
test("preview unknown answers terminate instead of repeating the same question", () => {
|
||||
const start = dynamicBirthTimePreview();
|
||||
const secondQuestion = advanceDynamicBirthTimePreview(start, { kind: "select", optionId: "unknown" });
|
||||
const terminal = advanceDynamicBirthTimePreview(secondQuestion, { kind: "select", optionId: "unknown-2" });
|
||||
|
||||
assert.equal(secondQuestion.nextAction.kind, "ask_dynamic_choice");
|
||||
assert.equal(terminal.nextAction.kind, "present_low_result");
|
||||
assert.equal(terminal.progress.answeredCount, 2);
|
||||
});
|
||||
|
||||
test("dynamic previews cover every visible result and recovery state", () => {
|
||||
const expected = new Map([
|
||||
["generating", "generate_dynamic_question"],
|
||||
|
||||
Reference in New Issue
Block a user