fix(rectification): resolve typed focus answers deterministically
Independent Staging Quality Gate / validate (push) Successful in 19m52s
Independent Staging Quality Gate / publish (push) Successful in 53m47s

This commit is contained in:
Jesse_Chen
2026-08-27 20:31:05 +08:00
parent f3327235ea
commit 85db4591d3
24 changed files with 695 additions and 168 deletions
@@ -2,7 +2,12 @@ import assert from "node:assert/strict";
import test from "node:test";
import { buildInferenceState } from "../src/lib/rectification-agentic/core/build-state.ts";
import { persistServerOwnedFocus, shouldSkipDiscriminatorFollowup, stableFollowupQuestionId } from "../src/lib/rectification-agentic/v9/server-focus.ts";
import {
openQuestionFromPersistedFocus,
persistServerOwnedFocus,
shouldSkipDiscriminatorFollowup,
stableFollowupQuestionId,
} from "../src/lib/rectification-agentic/v9/server-focus.ts";
import { buildChoiceFrame, serverOwnedChoiceCopy } from "../src/lib/rectification-agentic/v9/choice-card.ts";
import type { MethodFollowup } from "../src/lib/rectification-agentic/v9/method-followup.ts";
import type { EventProbeStyleOption } from "../src/lib/rectification-agentic/v9/refinement-packet.ts";
@@ -107,10 +112,70 @@ async function assertInvalidChoiceSkipped(followup: MethodFollowup) {
decisionReceipt: null,
followup,
});
assert.equal(result.status, "skipped");
assert.equal(result.status, "invalid_choice_schema");
assert.equal(accounting.calls.length, 0);
}
function persistedFocus(questionId = "probe:education:2016") {
const copy = serverOwnedChoiceCopy(discriminatorFollowup().choice_frame!);
assert.ok(copy);
return {
id: FOCUS_ID,
caseId: CASE_ID,
questionId,
intent: "distinguish_candidates",
targetEvidenceId: null,
targetDomain: "education",
targetKind: null,
expectedAnswerSchema: {
choice: copy,
semantic_key: "education:2016",
candidate_split_hash: "education:2016",
},
status: "active" as const,
askedAt: "2026-08-27T00:00:00.000Z",
resolvedAt: null,
};
}
test("only a successfully persisted focus can expose its discriminator question", () => {
const focus = persistedFocus();
for (const status of ["created", "already_open"] as const) {
assert.deepEqual(openQuestionFromPersistedFocus({
status,
focus,
questionId: focus.questionId,
prompt: "2016 年前后 · 升学结果或学习环境出现明显变化",
}), {
question_id: focus.questionId,
prompt: "2016 年前后 · 升学结果或学习环境出现明显变化",
status,
});
}
});
test("an unpersisted, mismatched, or incomplete focus cannot expose a discriminator question", () => {
const focus = persistedFocus();
assert.equal(openQuestionFromPersistedFocus({
status: "duplicate_focus",
focus,
questionId: focus.questionId,
prompt: "不能展示",
}), null);
assert.equal(openQuestionFromPersistedFocus({
status: "created",
focus: { ...focus, questionId: "another-question" },
questionId: focus.questionId,
prompt: "不能展示",
}), null);
assert.equal(openQuestionFromPersistedFocus({
status: "created",
focus: { ...focus, expectedAnswerSchema: { choice: { prompt: "不完整" } } },
questionId: focus.questionId,
prompt: "不能展示",
}), null);
});
test("complete dynamic event options persist a server-owned focus", async () => {
const followup = discriminatorFollowup({ source: "precision_stage", information_gain: 0.2 });
const accounting = fakeAccounting({
@@ -145,6 +210,12 @@ test("complete dynamic event options persist a server-owned focus", async () =>
option_b: DYNAMIC_STYLE_OPTIONS[1].label,
option_c: DYNAMIC_STYLE_OPTIONS[2].label,
option_d: DYNAMIC_STYLE_OPTIONS[3].label,
options: [
{ key: "A", label: DYNAMIC_STYLE_OPTIONS[0].label, answer_class: "yes" },
{ key: "B", label: DYNAMIC_STYLE_OPTIONS[1].label, answer_class: "weak_yes" },
{ key: "C", label: DYNAMIC_STYLE_OPTIONS[2].label, answer_class: "no" },
{ key: "D", label: DYNAMIC_STYLE_OPTIONS[3].label, answer_class: "unsure" },
],
});
});
@@ -261,7 +332,7 @@ test("an unmatched scoring identity is skipped instead of being synthesized", as
},
followup,
});
assert.equal(result.status, "skipped");
assert.equal(result.status, "invalid_choice_schema");
assert.equal(accounting.calls.length, 0);
});