fix(rectification): require three answers before uncertainty stop
One "一时说不好" no longer ends the interview. Plateau streaks use the same sample floor. Delivery copy states why the range stopped. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -805,6 +805,48 @@ test("deferFollowup scores the choice without persisting the next interview or t
|
||||
assert.equal(applied.narrationPersisted, false);
|
||||
});
|
||||
|
||||
test("one unsure discriminator answer does not adopt and persists the next question", async () => {
|
||||
const accounting = persistChoiceAccounting(twoProbeDossier(), {
|
||||
set_agentic_rectification_conversation_focus: (_fn, args) => ({
|
||||
focus: {
|
||||
id: NEXT_FOCUS_ID,
|
||||
case_id: CASE_ID,
|
||||
question_id: args.p_question_id,
|
||||
intent: args.p_intent,
|
||||
target_evidence_id: args.p_target_evidence_id,
|
||||
target_domain: args.p_target_domain,
|
||||
target_kind: args.p_target_kind,
|
||||
expected_answer_schema: args.p_expected_answer_schema,
|
||||
status: "active",
|
||||
asked_at: "2026-08-28T07:37:50.000Z",
|
||||
resolved_at: null,
|
||||
},
|
||||
idempotent: false,
|
||||
}),
|
||||
});
|
||||
const applied = await applyRectificationChoice(accounting.client, {
|
||||
userId: USER_ID,
|
||||
caseId: CASE_ID,
|
||||
sessionId: SESSION_ID,
|
||||
actionId: ACTION_ID,
|
||||
action: CHOICE_ACTION,
|
||||
focusId: FOCUS_ID,
|
||||
questionId: QUESTION_ID,
|
||||
probeId: RELOCATION_2015_PROBE.id,
|
||||
optionId: "D",
|
||||
expectedRevision: twoProbeInference().revision,
|
||||
});
|
||||
assert.equal(applied.answerClass, "unsure");
|
||||
assert.equal(applied.narration, "已记录。这题先不计分,换一件事问。");
|
||||
assert.notEqual(applied.nextAction.session_outcome, "adopt_representative");
|
||||
assert.equal(applied.nextAction.type, "ask_candidate_discriminator");
|
||||
assert.equal(applied.nextInterviewPersisted, true);
|
||||
const persist = accounting.calls.find((call) => call.fn === "apply_agentic_rectification_choice_action");
|
||||
assert.ok(persist?.args.p_inference);
|
||||
const setFocus = accounting.calls.find((call) => call.fn === "set_agentic_rectification_conversation_focus");
|
||||
assert.ok(setFocus);
|
||||
});
|
||||
|
||||
test("answering the last discriminator persists a year-locked family collect focus, not a yearless D24 card", async () => {
|
||||
const accounting = persistChoiceAccounting(familyCollectDossier(), {
|
||||
set_agentic_rectification_conversation_focus: (_fn, args) => ({
|
||||
@@ -1116,11 +1158,29 @@ test("structured choice narration never persists a fake loading state", () => {
|
||||
composeChoiceNarration({ optionId: "A", scoring: true, appliedInference: true }),
|
||||
composeChoiceNarration({ optionId: "A", scoring: true, appliedInference: false }),
|
||||
composeChoiceNarration({ optionId: "A", scoring: false, appliedInference: false }),
|
||||
composeChoiceNarration({
|
||||
optionId: "D",
|
||||
scoring: true,
|
||||
appliedInference: true,
|
||||
answerClass: "unsure",
|
||||
}),
|
||||
]) {
|
||||
assert.doesNotMatch(narration, /正在准备下一步/);
|
||||
}
|
||||
});
|
||||
|
||||
test("an unsure choice keeps applied inference and does not claim scores changed", () => {
|
||||
const narration = composeChoiceNarration({
|
||||
optionId: "D",
|
||||
scoring: true,
|
||||
appliedInference: true,
|
||||
answerClass: "unsure",
|
||||
});
|
||||
// 旧:appliedInference 仍说「更新了候选比较」→ 新:unsure 不计分旁白 → 保留 inference 行仍持久化
|
||||
assert.equal(narration, "已记录。这题先不计分,换一件事问。");
|
||||
assert.doesNotMatch(narration, /更新了候选比较/);
|
||||
});
|
||||
|
||||
test("the public agent route treats structured choice as a non-model command", () => {
|
||||
const route = readFileSync(new URL("../src/app/api/rectification/agent/route.ts", import.meta.url), "utf8");
|
||||
const start = route.indexOf("if (isStructuredChoice)");
|
||||
|
||||
Reference in New Issue
Block a user