|
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
|
|
internalObservationsFromWindowScan,
|
|
|
|
|
parseWindowScan,
|
|
|
|
|
} from "../src/lib/rectification-agentic/v9/varga-observations.ts";
|
|
|
|
|
import { WINDOW_SCAN_DISPLAY_LAYER_ORDER } from "../src/lib/rectification-agentic/v9/refinement-packet.ts";
|
|
|
|
|
import { RECTIFICATION_SKILL_VERSION } from "../src/lib/rectification-agentic/v9/case-status.ts";
|
|
|
|
|
import { createRectificationV9Tools, latestResultToolProjection } from "../src/mastra/rectification-v9-tools.ts";
|
|
|
|
|
import { PUBLIC_RECTIFICATION_TOOLS } from "../src/lib/rectification-agentic/v9/public-receipt.ts";
|
|
|
|
@@ -33,6 +34,17 @@ const THIRD_CANDIDATE_ID = "88888888-8888-4888-8888-888888888883";
|
|
|
|
|
const EDUCATION_ID = "44444444-4444-4444-8444-444444444441";
|
|
|
|
|
const FORBIDDEN_LABELS = /白羊|金牛|双子|巨蟹|狮子|处女|天秤|天蝎|射手|摩羯|水瓶|双鱼|热情冲动|配偶类型|事业特质/;
|
|
|
|
|
|
|
|
|
|
const CLASSIC_COVERAGE = [
|
|
|
|
|
{ status: "confirmed", domain: "education", datePrecision: "year" as const, occurredFrom: "2016-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "relationship", datePrecision: "year" as const, occurredFrom: "2018-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "career", datePrecision: "year" as const, occurredFrom: "2019-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "family", datePrecision: "year" as const, occurredFrom: "2020-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "appearance", datePrecision: "unknown" as const, occurredFrom: null, occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "marks", datePrecision: "unknown" as const, occurredFrom: null, occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "occupation", datePrecision: "unknown" as const, occurredFrom: null, occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "horary", datePrecision: "day" as const, occurredFrom: "2024-01-01", occurredTo: null },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const ENGINE_SCORE = {
|
|
|
|
|
success: true,
|
|
|
|
|
endpoint: "rectification_v5_score",
|
|
|
|
@@ -164,7 +176,8 @@ test("user-stop action explains the window when follow-up remains but the user s
|
|
|
|
|
assert.match(action.on_user_stop.user_meaning, /12:00/);
|
|
|
|
|
assert.match(action.on_user_stop.user_meaning, /不要只说会话会保留/);
|
|
|
|
|
assert.equal(plan.methods.find((item) => item.method_id === "marks")?.status, "uncovered");
|
|
|
|
|
assert.equal(plan.methods.find((item) => item.method_id === "horary")?.status, "skipped_by_policy");
|
|
|
|
|
assert.equal(plan.methods.find((item) => item.method_id === "horary")?.status, "uncovered");
|
|
|
|
|
assert.equal(plan.methods.find((item) => item.method_id === "occupation")?.status, "uncovered");
|
|
|
|
|
assert.notEqual(plan.next_followup?.method_id, "appearance");
|
|
|
|
|
assert.doesNotMatch(JSON.stringify(plan), FORBIDDEN_LABELS);
|
|
|
|
|
});
|
|
|
|
@@ -209,7 +222,7 @@ test("adopt_representative defers method follow-up instead of asking this turn",
|
|
|
|
|
assert.equal(plan.session_outcome, "adopt_representative");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("declined relationship skips to career and still skips horary", () => {
|
|
|
|
|
test("declined relationship skips to career and leaves horary uncovered", () => {
|
|
|
|
|
const plan = buildMethodFollowupPlan({
|
|
|
|
|
evidence: [{
|
|
|
|
|
status: "confirmed",
|
|
|
|
@@ -222,7 +235,8 @@ test("declined relationship skips to career and still skips horary", () => {
|
|
|
|
|
});
|
|
|
|
|
assert.equal(plan.next_followup?.method_id, "d10_career");
|
|
|
|
|
assert.equal(plan.next_followup?.domain, "career");
|
|
|
|
|
assert.deepEqual([...plan.do_not_poll], ["horary"]);
|
|
|
|
|
assert.deepEqual([...plan.do_not_poll], []);
|
|
|
|
|
assert.equal(plan.methods.find((item) => item.method_id === "horary")?.status, "uncovered");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("D9 differ becomes an internal ask theme without sign labels", () => {
|
|
|
|
@@ -264,16 +278,7 @@ test("D9 differ becomes an internal ask theme without sign labels", () => {
|
|
|
|
|
]);
|
|
|
|
|
assert.doesNotMatch(JSON.stringify({ scan, observations }), FORBIDDEN_LABELS);
|
|
|
|
|
const plan = buildMethodFollowupPlan({
|
|
|
|
|
evidence: [
|
|
|
|
|
{ status: "confirmed", domain: "education", datePrecision: "year", occurredFrom: "2016-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "relationship", datePrecision: "year", occurredFrom: "2018-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "career", datePrecision: "year", occurredFrom: "2019-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "family", datePrecision: "year", occurredFrom: "2020-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "finance", datePrecision: "year", occurredFrom: "2021-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "health_pressure", datePrecision: "year", occurredFrom: "2022-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "appearance", datePrecision: "unknown", occurredFrom: null, occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "marks", datePrecision: "unknown", occurredFrom: null, occurredTo: null },
|
|
|
|
|
],
|
|
|
|
|
evidence: CLASSIC_COVERAGE,
|
|
|
|
|
observations,
|
|
|
|
|
});
|
|
|
|
|
assert.equal(plan.next_followup?.source, "varga_observation");
|
|
|
|
@@ -310,15 +315,7 @@ test("D24-only window change folds into education follow-up without a second lay
|
|
|
|
|
["d9", "d10", "d4", "d5", "d7", "d12", "d11", "d30"],
|
|
|
|
|
);
|
|
|
|
|
const plan = buildMethodFollowupPlan({
|
|
|
|
|
evidence: [
|
|
|
|
|
{ status: "confirmed", domain: "relationship", datePrecision: "year", occurredFrom: "2018-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "career", datePrecision: "year", occurredFrom: "2019-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "family", datePrecision: "year", occurredFrom: "2020-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "finance", datePrecision: "year", occurredFrom: "2021-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "health_pressure", datePrecision: "year", occurredFrom: "2022-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "appearance", datePrecision: "unknown", occurredFrom: null, occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "marks", datePrecision: "unknown", occurredFrom: null, occurredTo: null },
|
|
|
|
|
],
|
|
|
|
|
evidence: CLASSIC_COVERAGE,
|
|
|
|
|
observations,
|
|
|
|
|
});
|
|
|
|
|
assert.equal(plan.next_followup?.method_id, "d5_education");
|
|
|
|
@@ -362,13 +359,8 @@ test("D11-only window change folds into finance follow-up without delaying adopt
|
|
|
|
|
);
|
|
|
|
|
const plan = buildMethodFollowupPlan({
|
|
|
|
|
evidence: [
|
|
|
|
|
{ status: "confirmed", domain: "relationship", datePrecision: "year", occurredFrom: "2018-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "career", datePrecision: "year", occurredFrom: "2019-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "family", datePrecision: "year", occurredFrom: "2020-01-01", occurredTo: null },
|
|
|
|
|
...CLASSIC_COVERAGE,
|
|
|
|
|
{ status: "confirmed", domain: "finance", datePrecision: "year", occurredFrom: "2021-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "health_pressure", datePrecision: "year", occurredFrom: "2022-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "appearance", datePrecision: "unknown", occurredFrom: null, occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "marks", datePrecision: "unknown", occurredFrom: null, occurredTo: null },
|
|
|
|
|
],
|
|
|
|
|
observations,
|
|
|
|
|
});
|
|
|
|
@@ -376,6 +368,31 @@ test("D11-only window change folds into finance follow-up without delaying adopt
|
|
|
|
|
assert.equal(plan.next_followup?.source, "varga_observation");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("window scan displays KP sub-lord changes without opening confirmation", () => {
|
|
|
|
|
assert.deepEqual(
|
|
|
|
|
["kp1", "kp4", "kp7", "kp10"].every((layer) => WINDOW_SCAN_DISPLAY_LAYER_ORDER.includes(layer as typeof WINDOW_SCAN_DISPLAY_LAYER_ORDER[number])),
|
|
|
|
|
true,
|
|
|
|
|
);
|
|
|
|
|
const scan = parseWindowScan({
|
|
|
|
|
scanned: true,
|
|
|
|
|
confirmation_allowed: true,
|
|
|
|
|
unique_minute_claim: true,
|
|
|
|
|
d9_lagna_count: 1,
|
|
|
|
|
d10_lagna_count: 1,
|
|
|
|
|
transitions: [
|
|
|
|
|
{ layer: "kp1", at: "05:14" },
|
|
|
|
|
{ layer: "kp10", at: "05:15" },
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
assert.ok(scan);
|
|
|
|
|
assert.equal(scan.confirmation_allowed, false);
|
|
|
|
|
assert.equal(scan.unique_minute_claim, false);
|
|
|
|
|
assert.deepEqual(scan.transitions, [
|
|
|
|
|
{ layer: "kp1", at: "05:14", user_meaning: "KP 1宫子主 在 05:14 发生变化" },
|
|
|
|
|
{ layer: "kp10", at: "05:15", user_meaning: "KP 10宫子主 在 05:15 发生变化" },
|
|
|
|
|
]);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("read-case follows method plan and hides D9/D10 labels even when SQL missing categories rotate", async () => {
|
|
|
|
|
const accounting = fakeAccounting({
|
|
|
|
|
...receiptHandlers,
|
|
|
|
@@ -603,9 +620,9 @@ test("rescore failure does not fail the evidence write", async () => {
|
|
|
|
|
assert.ok(result.rescore.error_code);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("public tool surface stays at 13 and new cases bind 10.0.9", () => {
|
|
|
|
|
test("public tool surface stays at 13 and new cases bind 10.0.10", () => {
|
|
|
|
|
assert.equal(PUBLIC_RECTIFICATION_TOOLS.length, 13);
|
|
|
|
|
assert.equal(RECTIFICATION_SKILL_VERSION, "10.0.9");
|
|
|
|
|
assert.equal(RECTIFICATION_SKILL_VERSION, "10.0.10");
|
|
|
|
|
const deprecated = resolveExactSkillPackage(
|
|
|
|
|
"jyotish-birth-time-rectification",
|
|
|
|
|
"10.0.2",
|
|
|
|
@@ -630,11 +647,14 @@ test("public tool surface stays at 13 and new cases bind 10.0.9", () => {
|
|
|
|
|
assert.equal((plateau.session_outcome as { kind: string }).kind, "collect_evidence");
|
|
|
|
|
const skill = readFileSync(new URL("../../skills/jyotish-birth-time-rectification/SKILL.md", import.meta.url), "utf8");
|
|
|
|
|
assert.match(skill, /method_followup_plan/);
|
|
|
|
|
assert.match(skill, /感情 → 事业 → 家人 → 外貌 → 疤痕 → 职业 → 占问/);
|
|
|
|
|
assert.match(skill, /KP 观察不计分、不挡提出门/);
|
|
|
|
|
assert.match(skill, /不得给用户贴 D9\/D10 星座或类型标签/);
|
|
|
|
|
assert.doesNotMatch(skill, /±5 分钟确定性/);
|
|
|
|
|
assert.doesNotMatch(skill, /KP 政策跳过不挡提出门/);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("family then finance then health then appearance follow the method plan", () => {
|
|
|
|
|
test("family then appearance then marks then occupation then horary follow the method plan", () => {
|
|
|
|
|
const afterFamily = buildMethodFollowupPlan({
|
|
|
|
|
evidence: [
|
|
|
|
|
{ status: "confirmed", domain: "education", datePrecision: "year", occurredFrom: "2016-01-01", occurredTo: null },
|
|
|
|
@@ -643,45 +663,59 @@ test("family then finance then health then appearance follow the method plan", (
|
|
|
|
|
{ status: "confirmed", domain: "family", datePrecision: "year", occurredFrom: "2020-01-01", occurredTo: null },
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
assert.equal(afterFamily.next_followup?.method_id, "d2_finance");
|
|
|
|
|
assert.equal(afterFamily.next_followup?.domain, "finance");
|
|
|
|
|
const afterFinance = buildMethodFollowupPlan({
|
|
|
|
|
evidence: [
|
|
|
|
|
{ status: "confirmed", domain: "education", datePrecision: "year", occurredFrom: "2016-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "relationship", datePrecision: "year", occurredFrom: "2018-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "career", datePrecision: "year", occurredFrom: "2019-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "family", datePrecision: "year", occurredFrom: "2020-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "finance", datePrecision: "year", occurredFrom: "2021-01-01", occurredTo: null },
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
assert.equal(afterFinance.next_followup?.method_id, "d30_health");
|
|
|
|
|
assert.equal(afterFinance.next_followup?.domain, "health_pressure");
|
|
|
|
|
assert.match(afterFinance.next_followup?.user_prompt_hint ?? "", /不是医学判断/);
|
|
|
|
|
const afterHealth = buildMethodFollowupPlan({
|
|
|
|
|
evidence: [
|
|
|
|
|
{ status: "confirmed", domain: "education", datePrecision: "year", occurredFrom: "2016-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "relationship", datePrecision: "year", occurredFrom: "2018-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "career", datePrecision: "year", occurredFrom: "2019-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "family", datePrecision: "year", occurredFrom: "2020-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "finance", datePrecision: "year", occurredFrom: "2021-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "health_pressure", datePrecision: "year", occurredFrom: "2022-01-01", occurredTo: null },
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
assert.equal(afterHealth.next_followup?.method_id, "appearance");
|
|
|
|
|
assert.equal(afterHealth.next_followup?.domain, "appearance");
|
|
|
|
|
assert.equal(afterFamily.next_followup?.method_id, "appearance");
|
|
|
|
|
assert.equal(afterFamily.next_followup?.domain, "appearance");
|
|
|
|
|
assert.equal(conversationalSessionOutcome({
|
|
|
|
|
selectionAllowed: true,
|
|
|
|
|
proposeAllowed: true,
|
|
|
|
|
confirmationAllowed: false,
|
|
|
|
|
nextFollowup: afterFamily.next_followup,
|
|
|
|
|
methods: afterFamily.methods,
|
|
|
|
|
}), "collect_evidence");
|
|
|
|
|
const afterAppearance = buildMethodFollowupPlan({
|
|
|
|
|
evidence: [
|
|
|
|
|
{ status: "confirmed", domain: "education", datePrecision: "year", occurredFrom: "2016-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "relationship", datePrecision: "year", occurredFrom: "2018-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "career", datePrecision: "year", occurredFrom: "2019-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "family", datePrecision: "year", occurredFrom: "2020-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "finance", datePrecision: "year", occurredFrom: "2021-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "health_pressure", datePrecision: "year", occurredFrom: "2022-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "appearance", datePrecision: "unknown", occurredFrom: null, occurredTo: null },
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
assert.equal(afterAppearance.next_followup?.method_id, "marks");
|
|
|
|
|
assert.match(afterAppearance.next_followup?.user_prompt_hint ?? "", /辅助对照|一宫/);
|
|
|
|
|
const afterMarks = buildMethodFollowupPlan({
|
|
|
|
|
evidence: [
|
|
|
|
|
{ status: "confirmed", domain: "education", datePrecision: "year", occurredFrom: "2016-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "relationship", datePrecision: "year", occurredFrom: "2018-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "career", datePrecision: "year", occurredFrom: "2019-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "family", datePrecision: "year", occurredFrom: "2020-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "appearance", datePrecision: "unknown", occurredFrom: null, occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "marks", datePrecision: "unknown", occurredFrom: null, occurredTo: null },
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
assert.equal(afterMarks.next_followup?.method_id, "occupation");
|
|
|
|
|
assert.equal(afterMarks.next_followup?.domain, "occupation");
|
|
|
|
|
assert.match(afterMarks.next_followup?.user_prompt_hint ?? "", /第 10 宫|D10/);
|
|
|
|
|
assert.doesNotMatch(afterMarks.next_followup?.user_prompt_hint ?? "", FORBIDDEN_LABELS);
|
|
|
|
|
const afterOccupation = buildMethodFollowupPlan({
|
|
|
|
|
evidence: [
|
|
|
|
|
{ status: "confirmed", domain: "education", datePrecision: "year", occurredFrom: "2016-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "relationship", datePrecision: "year", occurredFrom: "2018-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "career", datePrecision: "year", occurredFrom: "2019-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "family", datePrecision: "year", occurredFrom: "2020-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "appearance", datePrecision: "unknown", occurredFrom: null, occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "marks", datePrecision: "unknown", occurredFrom: null, occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "occupation", datePrecision: "unknown", occurredFrom: null, occurredTo: null },
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
assert.equal(afterOccupation.next_followup?.method_id, "horary");
|
|
|
|
|
assert.equal(afterOccupation.next_followup?.domain, "horary");
|
|
|
|
|
assert.equal(conversationalSessionOutcome({
|
|
|
|
|
selectionAllowed: true,
|
|
|
|
|
proposeAllowed: true,
|
|
|
|
|
confirmationAllowed: false,
|
|
|
|
|
nextFollowup: afterOccupation.next_followup,
|
|
|
|
|
methods: afterOccupation.methods,
|
|
|
|
|
}), "adopt_representative");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("precision stage lagna_frame asks another dated event instead of rotating domains", () => {
|
|
|
|
@@ -698,14 +732,7 @@ test("precision stage lagna_frame asks another dated event instead of rotating d
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("precision stage d4 asks home change not family, and d5 asks education", () => {
|
|
|
|
|
const covered = [
|
|
|
|
|
{ status: "confirmed", domain: "education", datePrecision: "year", occurredFrom: "2016-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "relationship", datePrecision: "year", occurredFrom: "2018-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "career", datePrecision: "year", occurredFrom: "2019-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "family", datePrecision: "year", occurredFrom: "2020-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "finance", datePrecision: "year", occurredFrom: "2021-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "health_pressure", datePrecision: "year", occurredFrom: "2022-01-01", occurredTo: null },
|
|
|
|
|
] as const;
|
|
|
|
|
const covered = CLASSIC_COVERAGE;
|
|
|
|
|
const d4 = buildMethodFollowupPlan({
|
|
|
|
|
evidence: covered,
|
|
|
|
|
precisionStage: "d4_refine",
|
|
|
|
@@ -779,31 +806,75 @@ test("d9_refine after relationship still asks uncovered career first", () => {
|
|
|
|
|
proposeAllowed: false,
|
|
|
|
|
confirmationAllowed: false,
|
|
|
|
|
nextFollowup: plan.next_followup,
|
|
|
|
|
methods: plan.methods,
|
|
|
|
|
}), "collect_evidence");
|
|
|
|
|
assert.equal(conversationalSessionOutcome({
|
|
|
|
|
selectionAllowed: true,
|
|
|
|
|
proposeAllowed: true,
|
|
|
|
|
confirmationAllowed: false,
|
|
|
|
|
nextFollowup: plan.next_followup,
|
|
|
|
|
methods: plan.methods,
|
|
|
|
|
}), "collect_evidence");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("appearance follow-up does not block propose once coverage is complete", () => {
|
|
|
|
|
test("career evidence does not cover occupation; appearance still blocks until occupation is asked", () => {
|
|
|
|
|
const plan = buildMethodFollowupPlan({
|
|
|
|
|
evidence: [
|
|
|
|
|
{ status: "confirmed", domain: "education", datePrecision: "year", occurredFrom: "2016-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "relationship", datePrecision: "day", occurredFrom: "2024-05-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "career", datePrecision: "day", occurredFrom: "2019-09-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "family", datePrecision: "year", occurredFrom: "2020-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "finance", datePrecision: "year", occurredFrom: "2021-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "health_pressure", datePrecision: "year", occurredFrom: "2022-01-01", occurredTo: null },
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
assert.equal(plan.next_followup?.method_id, "appearance");
|
|
|
|
|
assert.equal(plan.methods.find((item) => item.method_id === "occupation")?.status, "uncovered");
|
|
|
|
|
assert.equal(conversationalSessionOutcome({
|
|
|
|
|
selectionAllowed: true,
|
|
|
|
|
proposeAllowed: true,
|
|
|
|
|
confirmationAllowed: false,
|
|
|
|
|
nextFollowup: plan.next_followup,
|
|
|
|
|
methods: plan.methods,
|
|
|
|
|
}), "collect_evidence");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("declining occupation covers the method; declining horary is skipped_by_policy", () => {
|
|
|
|
|
const plan = buildMethodFollowupPlan({
|
|
|
|
|
evidence: [
|
|
|
|
|
{ status: "confirmed", domain: "education", datePrecision: "year", occurredFrom: "2016-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "relationship", datePrecision: "year", occurredFrom: "2018-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "career", datePrecision: "year", occurredFrom: "2019-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "family", datePrecision: "year", occurredFrom: "2020-01-01", occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "appearance", datePrecision: "unknown", occurredFrom: null, occurredTo: null },
|
|
|
|
|
{ status: "confirmed", domain: "marks", datePrecision: "unknown", occurredFrom: null, occurredTo: null },
|
|
|
|
|
],
|
|
|
|
|
declinedTopics: [
|
|
|
|
|
{ target_domain: "occupation", status: "declined" },
|
|
|
|
|
{ target_domain: "horary", status: "declined" },
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
assert.equal(plan.methods.find((item) => item.method_id === "occupation")?.status, "covered");
|
|
|
|
|
assert.equal(plan.methods.find((item) => item.method_id === "horary")?.status, "skipped_by_policy");
|
|
|
|
|
assert.equal(plan.next_followup, null);
|
|
|
|
|
assert.equal(conversationalSessionOutcome({
|
|
|
|
|
selectionAllowed: true,
|
|
|
|
|
proposeAllowed: true,
|
|
|
|
|
confirmationAllowed: false,
|
|
|
|
|
nextFollowup: plan.next_followup,
|
|
|
|
|
methods: plan.methods,
|
|
|
|
|
}), "adopt_representative");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test("horary follow-up does not block propose once occupation is covered", () => {
|
|
|
|
|
const plan = buildMethodFollowupPlan({
|
|
|
|
|
evidence: CLASSIC_COVERAGE.filter((item) => item.domain !== "horary"),
|
|
|
|
|
});
|
|
|
|
|
assert.equal(plan.next_followup?.method_id, "horary");
|
|
|
|
|
assert.equal(conversationalSessionOutcome({
|
|
|
|
|
selectionAllowed: true,
|
|
|
|
|
proposeAllowed: true,
|
|
|
|
|
confirmationAllowed: false,
|
|
|
|
|
nextFollowup: plan.next_followup,
|
|
|
|
|
methods: plan.methods,
|
|
|
|
|
}), "adopt_representative");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|