fix(rectification): narrate exhausted-probe adopt instead of keep-collecting
Independent Staging Quality Gate / validate (push) Successful in 10m33s
Independent Staging Quality Gate / publish (push) Successful in 1m55s

When leftover probes cannot split adjacent minutes, skip frameless follow-ups and let a no-tool agent explain the stop. Distinguish-card "no" no longer closes a whole evidence domain.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-09-04 14:22:13 +08:00
parent cfa824994e
commit 0aaa0d702e
18 changed files with 1757 additions and 51 deletions
@@ -722,7 +722,11 @@ test("collect persist maps occupation to other and health_pressure to health", a
assert.equal(persistableFocusDomain("occupation"), "other");
assert.equal(persistableFocusDomain("health_pressure"), "health");
assert.equal(persistableFocusDomain("education"), "education");
assert.equal(persistableFocusDomain("horary"), "horary");
// Was: persistableFocusDomain("horary") === "horary".
// Now: null. DB check excludes horary; the old assertion locked a write that always failed.
assert.equal(persistableFocusDomain("horary"), null);
assert.equal(persistableFocusDomain("appearance"), null);
assert.equal(persistableFocusDomain("nakshatra"), null);
assert.equal(persistableFocusDomain(null), null);
assert.equal(persistableFocusDomain("unknown"), null);
// 旧 collect:education → 新 collect:other → 保留 unknown/null 不得写入 unknown
@@ -808,3 +812,35 @@ test("collect focus unique conflict retries with a :next question id", async ()
`collect:relationship:collect_method_evidence:${COLLECT_FOCUS_RETRY_SUFFIX}`,
);
});
test("appearance distinguish without a frame is skipped with zero RPC", async () => {
const followup: MethodFollowup = {
method_id: "nakshatra_boundary",
intent: "distinguish_candidates",
ask_theme: "nakshatra_trait",
domain: "appearance",
kind_hint: null,
user_prompt_hint: "外表或体质更接近哪一种?",
must_not_label: false,
choice_frame: null,
source: "nakshatra_boundary",
};
const accounting = fakeAccounting({
set_agentic_rectification_conversation_focus: () => {
throw new Error("appearance collect must not be written");
},
});
const persisted = await persistServerOwnedFocus({
accounting: accounting.client,
userId: USER_ID,
caseId: CASE_ID,
activeFocus: null,
decisionReceipt: null,
followup,
});
assert.equal(persisted.status, "skipped");
assert.equal(
accounting.calls.some((item) => item.fn === "set_agentic_rectification_conversation_focus"),
false,
);
});