Files
Jyotisha/frontend/tests/rectification-spoken-prompt.test.ts
T
Jesse_Chen 35e5781e66
Independent Staging Quality Gate / validate (push) Successful in 9m50s
Independent Staging Quality Gate / publish (push) Successful in 1m53s
fix(rectification): gate collect-phase adopt cards and keep post-adopt verify answerable
Public can_adopt follows session_outcome; reverse_verify reuses the persisted question id; offer cards settle on the owning message with a status-bar handoff.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-03 09:29:34 +08:00

145 lines
5.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import assert from "node:assert/strict";
import test from "node:test";
import { parseAgentChoiceCopy } from "../src/lib/rectification-agentic/v9/choice-card.ts";
import { validateSpokenPrompt, withSpokenPrompt } from "../src/lib/rectification-agentic/v9/spoken-prompt.ts";
import { MACHINE_VOICE_LEXICON } from "../src/lib/rectification-agentic/v9/agent-voice-lexicon.ts";
import type { MethodFollowup } from "../src/lib/rectification-agentic/v9/method-followup.ts";
function followup(overrides: Partial<MethodFollowup> = {}): MethodFollowup {
return {
method_id: "d9_relationship",
intent: "distinguish_candidates",
ask_theme: "relationship_style",
domain: "relationship",
kind_hint: "relationship_change",
user_prompt_hint: "probe",
must_not_label: false,
choice_frame: {
question_id: "d9:relationship:2023",
method_id: "d9_relationship",
period: "2023 年前后",
prompt: "2023 年前后,你有没有一段认真开始或结束的关系?",
varga: "D9",
why: "区分",
option_a_hint: "明确发生且时间吻合",
option_b_hint: "发生过但时间偏了",
neither_label: "没有这回事",
unsure_label: "记不清",
option_a_answer_class: "yes",
option_b_answer_class: "weak_yes",
option_c_answer_class: "no",
option_d_answer_class: "unsure",
choice_mode: "A/B/C/D",
stop_label: "先这样,先看当前范围",
stop_message: "先这样",
scoring: true,
},
source: "event_probe",
probe_year: 2023,
...overrides,
};
}
test("spokenPrompt rejects length, option literals, unique-minute claims, and machine voice", () => {
assert.equal(validateSpokenPrompt({ spokenPrompt: "太短了" }).ok, false);
const optionLiteral = validateSpokenPrompt({
spokenPrompt: "2023 年这段感情,选项怎么选你还记得吗?",
});
assert.equal(optionLiteral.ok, false);
assert.equal(optionLiteral.ok ? null : optionLiteral.reason, "option_literal");
const uniqueMinute = validateSpokenPrompt({
spokenPrompt: "这能定下唯一的出生分钟吗,你还记得医院的钟点?",
});
assert.equal(uniqueMinute.ok, false);
assert.equal(uniqueMinute.ok ? null : uniqueMinute.reason, "unique_minute");
assert.equal(validateSpokenPrompt({
spokenPrompt: MACHINE_VOICE_LEXICON[3],
}).ok, false);
});
test("spokenPrompt rejects a different year or domain than the server probe", () => {
const probe = followup();
const yearMismatch = validateSpokenPrompt({
spokenPrompt: "2018 年前后,你有没有一段认真开始或结束的关系?",
followup: probe,
targetDomain: "relationship",
questionId: "d9_relationship:relationship:2023",
});
assert.equal(yearMismatch.ok ? null : yearMismatch.reason, "year_mismatch");
const yearMissing = validateSpokenPrompt({
spokenPrompt: "你有没有一段认真开始或结束的关系?",
followup: probe,
targetDomain: "relationship",
questionId: "d9_relationship:relationship:2023",
});
assert.equal(yearMissing.ok ? null : yearMissing.reason, "year_missing");
const domainMismatch = validateSpokenPrompt({
spokenPrompt: "2023 年前后,你有没有换过工作?",
followup: probe,
targetDomain: "career",
questionId: "d9_relationship:relationship:2023",
});
assert.equal(domainMismatch.ok ? null : domainMismatch.reason, "domain_mismatch");
assert.equal(validateSpokenPrompt({
spokenPrompt: "工作记下了。2023 年前后,有没有一段认真开始或结束的关系?",
followup: probe,
targetDomain: "relationship",
questionId: "d9_relationship:relationship:2023",
}).ok, true);
});
test("spokenPrompt requires each year in a period when probe_year is empty", () => {
const ranged = followup({
probe_year: undefined,
choice_frame: {
...followup().choice_frame!,
period: "20142016 年前后",
},
});
const questionId = "d9:relationship:2023";
const missing = validateSpokenPrompt({
spokenPrompt: "你有没有升学或换过学习环境?",
followup: ranged,
questionId,
});
assert.equal(missing.ok ? null : missing.reason, "year_missing");
assert.equal(validateSpokenPrompt({
spokenPrompt: "2014 到 2016 年前后,有没有升学或换过学习环境?",
followup: ranged,
questionId,
}).ok, true);
const collect = followup({ choice_frame: null, probe_year: 2023 });
assert.equal(validateSpokenPrompt({
spokenPrompt: "你还记得哪年入的职吗?",
followup: collect,
targetDomain: "relationship",
}).ok, true);
});
test("withSpokenPrompt keeps a parseable choice prompt when spoken copy includes a clock time", () => {
const schema = {
choice: {
prompt: "2016 年前后,升学结果或学习环境有没有明显变化?",
option_a: "明确发生且时间吻合",
option_b: "发生过但程度较弱",
option_c: "明确没有发生",
option_d: "这段记不清楚",
options: [
{ key: "A", label: "明确发生且时间吻合", answer_class: "yes" },
{ key: "B", label: "发生过但程度较弱", answer_class: "weak_yes" },
{ key: "C", label: "明确没有发生", answer_class: "no" },
{ key: "D", label: "这段记不清楚", answer_class: "unsure" },
],
},
};
const next = withSpokenPrompt(
schema,
"已按 05:06 采用。现在核对:2016 年前后升学或学习环境有没有明显变化?",
);
const copy = parseAgentChoiceCopy(next);
assert.equal(copy?.options.length, 4);
assert.equal(copy?.prompt, "2016 年前后,升学结果或学习环境有没有明显变化?");
assert.equal(next.prompt, "已按 05:06 采用。现在核对:2016 年前后升学或学习环境有没有明显变化?");
});