fix(rectification): keep same-sentence dated events after structured answers
Independent Staging Quality Gate / validate (push) Successful in 13m7s
Independent Staging Quality Gate / publish (push) Successful in 29m19s

The choice and collect fast paths applied the answer then returned,
so a dated event in the same utterance never reached the evidence
ledger. Idle persist also prechecked follow-up with a hardcoded
collect_evidence outcome instead of the dossier decision.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-29 23:18:07 +08:00
co-authored by Cursor
parent 078c1cdc0d
commit 3a0319694e
8 changed files with 306 additions and 17 deletions
@@ -5,6 +5,8 @@ import test from "node:test";
import {
optionIdForAnswerClass,
parseRectificationTurnIntent,
shouldContinueAgentForDatedEvent,
shouldDeclineCollectFocus,
} from "../src/lib/rectification-agentic/v9/turn-intent-classifier.ts";
import type { ConversationFocus } from "../src/lib/rectification-agentic/v9/tool-service.ts";
import { CASE_ID, FOCUS_ID } from "./rectification-v9-test-support.ts";
@@ -71,6 +73,36 @@ test("turn intent parser enforces answer_class only for current-focus answers",
}), null);
});
test("missing has_new_dated_event is treated as false and true is fail-closed optional", () => {
const legacy = parseRectificationTurnIntent({
intent: "answer_current_focus",
answer_class: "no",
});
assert.equal(legacy?.intent, "answer_current_focus");
assert.equal(legacy?.answer_class, "no");
assert.equal(legacy?.has_new_dated_event, undefined);
assert.equal(shouldContinueAgentForDatedEvent(legacy), false);
assert.equal(shouldContinueAgentForDatedEvent(null), false);
assert.equal(shouldContinueAgentForDatedEvent({
intent: "answer_current_focus",
answer_class: "no",
has_new_dated_event: false,
}), false);
const withEvent = parseRectificationTurnIntent({
intent: "answer_current_focus",
answer_class: "no",
has_new_dated_event: true,
});
assert.equal(withEvent?.has_new_dated_event, true);
assert.equal(shouldContinueAgentForDatedEvent(withEvent), true);
assert.equal(shouldDeclineCollectFocus(withEvent), true);
assert.equal(parseRectificationTurnIntent({
intent: "answer_current_focus",
answer_class: "no",
has_new_dated_event: "yes",
}), null);
});
test("answer classes resolve through each dynamic option instead of A/B/C/D position", () => {
const focus = focusWithOptions(SHUFFLED_CHOICE);
assert.equal(optionIdForAnswerClass(focus, "no"), "A");