fix(rectification): ask a ready discriminator before dated collect
Family coverage still continues dated collection when nothing can split leftover minutes, but an already-built choice card must not be displaced by spoken finance collect. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1974,8 +1974,98 @@ export function buildMethodFollowupPlan(input: {
|
||||
const candidate = followupFromRanked(ranked);
|
||||
return candidate.choice_frame ? candidate : null;
|
||||
};
|
||||
const firstRenderableYearlessFollowup = (): MethodFollowup | null => {
|
||||
for (const ranked of yearlessDiscriminators) {
|
||||
const domain = contrastFollowupDomain(
|
||||
ranked.eventProbe?.domain ?? ranked.contrastProbe?.domain ?? null,
|
||||
);
|
||||
if (declined.has(domain)) continue;
|
||||
const key = rankedDiscriminatorKey(ranked);
|
||||
if (key && askedKeys.has(key)) continue;
|
||||
const candidate = followupFromRanked(ranked);
|
||||
if (candidate.choice_frame) return candidate;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
const precisionStageFollowup = (): MethodFollowup | null => {
|
||||
if (stage === "lagna_frame") {
|
||||
return makeFollowup({
|
||||
method_id: "dasha_events",
|
||||
intent: "distinguish_candidates",
|
||||
ask_theme: "dated_event",
|
||||
domain: null,
|
||||
kind_hint: null,
|
||||
user_prompt_hint: ask(
|
||||
"窗口里本命上升还可能落在两段。按 choice_frame.period 与探针问一件前事是否发生,用来筛这两段。不要问两套盘哪个更像。",
|
||||
"本命上升 / Dasha",
|
||||
),
|
||||
source: "precision_stage",
|
||||
});
|
||||
}
|
||||
if (stage === "d9_refine" && !relationshipCovered && !declined.has("relationship")) {
|
||||
return makeFollowup({
|
||||
method_id: "d9_relationship",
|
||||
intent: "distinguish_candidates",
|
||||
ask_theme: "relationship_style",
|
||||
domain: "relationship",
|
||||
kind_hint: "relationship_change",
|
||||
user_prompt_hint: ask(
|
||||
"关系盘仍会换升。按探针年份问感情这条线的前事是否发生,用来筛窗。不要问两套盘哪个更像。",
|
||||
"D9",
|
||||
"对照 D9 上升类型表只作校时方法。",
|
||||
),
|
||||
source: "precision_stage",
|
||||
});
|
||||
}
|
||||
if (stage === "d10_refine" && !declined.has("career")) {
|
||||
return makeFollowup({
|
||||
method_id: "d10_career",
|
||||
intent: "distinguish_candidates",
|
||||
ask_theme: "career_style",
|
||||
domain: "career",
|
||||
kind_hint: "career_change",
|
||||
user_prompt_hint: ask(
|
||||
"事业盘仍会换升。按探针年份问事业这条线的前事是否发生,用来筛窗。不要问两套盘哪个更像。",
|
||||
"D10",
|
||||
"可用 D10 事业类型表作校时对照。",
|
||||
),
|
||||
source: "precision_stage",
|
||||
});
|
||||
}
|
||||
if ((stage === "d4_refine" || stage === "theme_refine") && !declined.has("relocation")) {
|
||||
return makeFollowup({
|
||||
method_id: "d4_home",
|
||||
intent: "distinguish_candidates",
|
||||
ask_theme: "home_change",
|
||||
domain: "relocation",
|
||||
kind_hint: "home_change",
|
||||
user_prompt_hint: ask(
|
||||
"居所盘仍会换升。按探针年份问搬家或住处变化是否发生,用来筛窗。不要问两套盘哪个更像。",
|
||||
"D4",
|
||||
),
|
||||
source: "precision_stage",
|
||||
});
|
||||
}
|
||||
if (stage === "d5_refine" && !declined.has("education")) {
|
||||
return makeFollowup({
|
||||
method_id: "d5_education",
|
||||
intent: "distinguish_candidates",
|
||||
ask_theme: "education_style",
|
||||
domain: "education",
|
||||
kind_hint: "education_milestone",
|
||||
user_prompt_hint: ask(
|
||||
"成就盘或学业盘仍会换升。按探针年份问学业或考试变化是否发生,用来筛窗。不要问两套盘哪个更像。",
|
||||
"D5 / D24",
|
||||
),
|
||||
source: "precision_stage",
|
||||
});
|
||||
}
|
||||
return null;
|
||||
};
|
||||
let datedCollect: MethodFollowup | null = null;
|
||||
let renderableYearless: MethodFollowup | null = null;
|
||||
if (!next) {
|
||||
const precisionCard = precisionStageFollowup();
|
||||
if (!relationshipCovered && !declined.has("relationship")) {
|
||||
next = sameDomainYearlessCard("relationship") ?? makeFollowup({
|
||||
method_id: "d9_relationship",
|
||||
@@ -2020,6 +2110,16 @@ export function buildMethodFollowupPlan(input: {
|
||||
source: "method_coverage",
|
||||
...collectionYearFields(familyCollect),
|
||||
});
|
||||
} else if ((renderableYearless = firstRenderableYearlessFollowup())) {
|
||||
next = renderableYearless;
|
||||
} else if (
|
||||
// BUG-547: a renderable precision card beats dated collect, but only
|
||||
// after the training gate is open. lagna_frame can borrow an unrelated
|
||||
// probe into choice_frame while holdout is still short.
|
||||
meetsAcceptanceEventQuality(input.evidence)
|
||||
&& precisionCard?.choice_frame
|
||||
) {
|
||||
next = precisionCard;
|
||||
} else if ((datedCollect = nextDatedCollectFollowup(input.evidence, declined))) {
|
||||
next = makeFollowup(datedCollect);
|
||||
} else if (!occupationCovered) {
|
||||
@@ -2063,73 +2163,8 @@ export function buildMethodFollowupPlan(input: {
|
||||
&& !declined.has("relocation"))
|
||||
) {
|
||||
next = makeFollowup(otherCollectFollowup(input.evidence));
|
||||
} else if (stage === "lagna_frame") {
|
||||
next = makeFollowup({
|
||||
method_id: "dasha_events",
|
||||
intent: "distinguish_candidates",
|
||||
ask_theme: "dated_event",
|
||||
domain: null,
|
||||
kind_hint: null,
|
||||
user_prompt_hint: ask(
|
||||
"窗口里本命上升还可能落在两段。按 choice_frame.period 与探针问一件前事是否发生,用来筛这两段。不要问两套盘哪个更像。",
|
||||
"本命上升 / Dasha",
|
||||
),
|
||||
source: "precision_stage",
|
||||
});
|
||||
} else if (stage === "d9_refine" && !relationshipCovered && !declined.has("relationship")) {
|
||||
next = makeFollowup({
|
||||
method_id: "d9_relationship",
|
||||
intent: "distinguish_candidates",
|
||||
ask_theme: "relationship_style",
|
||||
domain: "relationship",
|
||||
kind_hint: "relationship_change",
|
||||
user_prompt_hint: ask(
|
||||
"关系盘仍会换升。按探针年份问感情这条线的前事是否发生,用来筛窗。不要问两套盘哪个更像。",
|
||||
"D9",
|
||||
"对照 D9 上升类型表只作校时方法。",
|
||||
),
|
||||
source: "precision_stage",
|
||||
});
|
||||
} else if (stage === "d10_refine" && !declined.has("career")) {
|
||||
next = makeFollowup({
|
||||
method_id: "d10_career",
|
||||
intent: "distinguish_candidates",
|
||||
ask_theme: "career_style",
|
||||
domain: "career",
|
||||
kind_hint: "career_change",
|
||||
user_prompt_hint: ask(
|
||||
"事业盘仍会换升。按探针年份问事业这条线的前事是否发生,用来筛窗。不要问两套盘哪个更像。",
|
||||
"D10",
|
||||
"可用 D10 事业类型表作校时对照。",
|
||||
),
|
||||
source: "precision_stage",
|
||||
});
|
||||
} else if ((stage === "d4_refine" || stage === "theme_refine") && !declined.has("relocation")) {
|
||||
next = makeFollowup({
|
||||
method_id: "d4_home",
|
||||
intent: "distinguish_candidates",
|
||||
ask_theme: "home_change",
|
||||
domain: "relocation",
|
||||
kind_hint: "home_change",
|
||||
user_prompt_hint: ask(
|
||||
"居所盘仍会换升。按探针年份问搬家或住处变化是否发生,用来筛窗。不要问两套盘哪个更像。",
|
||||
"D4",
|
||||
),
|
||||
source: "precision_stage",
|
||||
});
|
||||
} else if (stage === "d5_refine" && !declined.has("education")) {
|
||||
next = makeFollowup({
|
||||
method_id: "d5_education",
|
||||
intent: "distinguish_candidates",
|
||||
ask_theme: "education_style",
|
||||
domain: "education",
|
||||
kind_hint: "education_milestone",
|
||||
user_prompt_hint: ask(
|
||||
"成就盘或学业盘仍会换升。按探针年份问学业或考试变化是否发生,用来筛窗。不要问两套盘哪个更像。",
|
||||
"D5 / D24",
|
||||
),
|
||||
source: "precision_stage",
|
||||
});
|
||||
} else if (precisionCard) {
|
||||
next = precisionCard;
|
||||
} else {
|
||||
const d9 = input.observations?.find((item) => item.layer === "d9");
|
||||
const d10 = input.observations?.find((item) => item.layer === "d10");
|
||||
|
||||
@@ -751,6 +751,54 @@ test("distinguish follow-up copy forbids competing-chart ranking", () => {
|
||||
assert.match(plan.next_followup?.user_prompt_hint ?? "", /不得发明年份/);
|
||||
});
|
||||
|
||||
test("family coverage without a renderable discriminator still collects the next dated domain", () => {
|
||||
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: "occupation",
|
||||
datePrecision: "unknown",
|
||||
occurredFrom: null,
|
||||
occurredTo: null,
|
||||
}, {
|
||||
status: "confirmed",
|
||||
domain: "horary",
|
||||
datePrecision: "day",
|
||||
occurredFrom: "2024-01-01",
|
||||
occurredTo: null,
|
||||
}],
|
||||
precisionStage: "d4_refine",
|
||||
birthDate: "1997-08-08",
|
||||
});
|
||||
assert.equal(plan.next_followup?.method_id, "d2_finance");
|
||||
assert.equal(plan.next_followup?.intent, "collect_method_evidence");
|
||||
assert.equal(plan.next_followup?.choice_frame, null);
|
||||
assert.equal(plan.deferred_followup, null);
|
||||
});
|
||||
|
||||
test("GET A/B card stays visible after coverage when candidates remain tied", () => {
|
||||
const card = projectRectificationChoiceCard({
|
||||
evidence: [{
|
||||
|
||||
@@ -248,7 +248,10 @@ test("career evidence alone still does not cover occupation", () => {
|
||||
contrastPacket: { candidateSetVersion: "04:47-05:15", vargaDifferences: [], probes: [] },
|
||||
});
|
||||
assert.equal(plan.methods.find((item) => item.method_id === "occupation")?.status, "uncovered");
|
||||
assert.equal(plan.next_followup?.method_id, "occupation");
|
||||
// 原值: occupation
|
||||
// 新值: d2_finance
|
||||
// 原因: 家人已覆盖且无区分卡时,BUG-546 继续收未用带年份域;职业仍未覆盖,只是还没轮到
|
||||
assert.equal(plan.next_followup?.method_id, "d2_finance");
|
||||
});
|
||||
|
||||
test("training gate open does not mint yearless existence or quality varga cards", () => {
|
||||
@@ -256,7 +259,10 @@ test("training gate open does not mint yearless existence or quality varga cards
|
||||
assert.equal(plan.methods.find((item) => item.method_id === "occupation")?.status, "uncovered");
|
||||
assert.doesNotMatch(plan.next_followup?.semantic_key ?? "", /^varga\.d(24|7|4|5)\./);
|
||||
assert.equal(plan.dropped_probes.some((item) => item.reason === "yearless_ungrounded_contrast"), true);
|
||||
assert.equal(plan.next_followup?.method_id, "occupation");
|
||||
// 原值: occupation
|
||||
// 新值: d2_finance
|
||||
// 原因: yearless 存在/质量卡被丢掉后没有可渲染区分卡,BUG-546 先收财务采集
|
||||
assert.equal(plan.next_followup?.method_id, "d2_finance");
|
||||
assert.equal(plan.next_followup?.intent, "collect_method_evidence");
|
||||
assert.equal(plan.next_followup?.choice_frame, null);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user