fix(rectification): stop discriminator followup from dropping user evidence
Decision and question ranking now share contrast option completion, so a missing style card cannot deadlock the interview with a dead-end reply. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -644,11 +644,24 @@ test("answering a discriminator persists the next dated card so GET still has a
|
||||
assert.doesNotMatch(card.prompt, /2015/);
|
||||
});
|
||||
|
||||
test("answering the last discriminator persists a year-locked family collect, not a yearless D24 card", async () => {
|
||||
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: () => {
|
||||
throw new Error("yearless D24 must not persist a scoring focus");
|
||||
},
|
||||
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,
|
||||
@@ -662,11 +675,14 @@ test("answering the last discriminator persists a year-locked family collect, no
|
||||
optionId: "C",
|
||||
expectedRevision: familyCollectInference().revision,
|
||||
});
|
||||
assert.equal(
|
||||
accounting.calls.some((call) => call.fn === "set_agentic_rectification_conversation_focus"),
|
||||
false,
|
||||
JSON.stringify(accounting.calls.map((call) => call.fn)),
|
||||
);
|
||||
const setFocus = accounting.calls.find((call) => call.fn === "set_agentic_rectification_conversation_focus");
|
||||
assert.ok(setFocus, JSON.stringify(accounting.calls.map((call) => call.fn)));
|
||||
assert.equal(setFocus.args.p_intent, "collect_method_evidence");
|
||||
const schema = setFocus.args.p_expected_answer_schema as { choice?: unknown; prompt?: string; collect?: boolean };
|
||||
assert.equal(schema.choice, undefined);
|
||||
assert.equal(schema.collect, true);
|
||||
assert.match(schema.prompt ?? "", /2021/);
|
||||
assert.match(schema.prompt ?? "", /家人|结婚|添丁|住院/);
|
||||
assert.equal(applied.nextInterviewPersisted, true);
|
||||
assert.equal(applied.nextChoiceReady, false);
|
||||
assert.equal(shouldContinueAfterStructuredChoice(applied.nextAction, applied), false);
|
||||
@@ -801,6 +817,39 @@ test("collection focus without choice copy is not an unrenderable current_questi
|
||||
assert.equal(projection.current_question, null);
|
||||
});
|
||||
|
||||
test("failed card persist still leaves a spoken collect next step", () => {
|
||||
const source = readFileSync(new URL("../src/lib/rectification-agentic/v9/answer-choice.ts", import.meta.url), "utf8");
|
||||
assert.match(source, /if \(followup\?\.choice_frame\)/);
|
||||
assert.match(source, /intent: "collect_method_evidence"/);
|
||||
assert.match(source, /choice_frame: null/);
|
||||
assert.match(source, /请再说一件记得大概时间的经历/);
|
||||
assert.match(source, /当前几个候选已经构成可信区间/);
|
||||
});
|
||||
|
||||
test("spoken collect focus keeps current_question after refresh", () => {
|
||||
const snapshot = candidateSnapshotFixture();
|
||||
Object.assign(snapshot.decision_receipt, { inference_state: inferenceState() });
|
||||
const dossier = parseV9CaseDossier(dossierFixture({
|
||||
latestResult: snapshot,
|
||||
conversationSummary: conversationSummaryFixture({
|
||||
activeFocus: activeFocusFixture({
|
||||
intent: "collect_method_evidence",
|
||||
targetDomain: "family",
|
||||
expectedAnswerSchema: {
|
||||
prompt: "2021 年前后,家里有没有结婚、添丁或住院这类记得住时间的事?不记得具体日子也可以先说有没有。",
|
||||
collect: true,
|
||||
},
|
||||
}),
|
||||
}),
|
||||
}));
|
||||
assert.ok(dossier);
|
||||
const projection = projectTurnDecision(dossier);
|
||||
const currentQuestion = projection.current_question as { prompt?: string; unrenderable?: boolean } | null;
|
||||
assert.equal(currentQuestion?.unrenderable, undefined);
|
||||
assert.match(currentQuestion?.prompt ?? "", /2021/);
|
||||
assert.equal(projection.current_question && typeof projection.current_question === "object", true);
|
||||
});
|
||||
|
||||
test("turn_decision hides current_probe unless a valid current_question exists", () => {
|
||||
const withFocus = projectTurnDecision(parseV9CaseDossier(choiceDossier())!);
|
||||
assert.ok(withFocus.current_question);
|
||||
|
||||
Reference in New Issue
Block a user