fix(rectification): ask relationship and career before dated collect
Move nextDatedCollectFollowup after family coverage so a new case still asks D9 then D10. Dated third-event collect stays education → finance → relocation → health. Admin input padding contract follows --space-3. BUG-531 and BUG-532. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
# 印度占星 Skill 更新日志
|
||||
|
||||
## 2026-09-04 — 新案例前两问恢复感情与事业
|
||||
|
||||
训练门未开时,新案例仍先问感情、再问事业、再问家人;缺第三件带年份的事,才按学业 → 财务 → 搬家 → 健康补采集。原生输入框间距合同测试跟上 `var(--space-3)`。Skill 版本仍是 10.0.14。
|
||||
|
||||
## 2026-09-04 — 采集阶段第三件事必须指向领域,盘外核对不得抢跑
|
||||
|
||||
可评分事件还不到 3 条时,不再进入盘外核对,也不再先问没有日期的职业或「随便哪件事」。下一问按家人 → 学业 → 财务 → 搬家 → 健康 → 事业 → 感情补带年份的事;采集题干必须写出领域。进度句只能用服务端给出的还差几件,没有数字就不说。Skill 版本仍是 10.0.14;采用门与确认门未改。
|
||||
|
||||
+33
-1
@@ -8161,7 +8161,7 @@
|
||||
- 修复:`DATED_COLLECT_ORDER`(家人 → 学业 → 财务 → 搬家 → 健康 → 事业 → 感情)由主流程与 `exhaustionSpokenCollectFollowup` 共用。训练门未开时,在方法轮转之前取下一件带年份采集题;职业与 `other` 泛问排在最后。`datedCollectFollowup` 的 `source` 为 `method_coverage`(采集,不是盘外核对)。
|
||||
- 验证:新文件锁 education → finance → occupation → other;拒答路径落下 `USER_COLLECT_QUESTION.education`。`rectification-eight-method` 中训练门未开的下一问从感情改为家人(或财务),每条改断言附原值/新值/原因。4 条可评分事件时本分支不触发(`rectification-collect-stall`、`rectification-yearless-ungrounded` 的 OOS 结论不变)。
|
||||
- 防复发:训练门未开时不得先问职业或无领域泛问。顺序只许有一处定义。
|
||||
- 相关记录:BUG-426、BUG-442、BUG-472、BUG-527
|
||||
- 相关记录:BUG-426、BUG-442、BUG-472、BUG-527、BUG-531
|
||||
- 复发自:无
|
||||
- 修复版本:待发布
|
||||
|
||||
@@ -8196,3 +8196,35 @@
|
||||
- 相关记录:BUG-527
|
||||
- 复发自:无
|
||||
- 修复版本:待发布
|
||||
|
||||
## BUG-531 | 新案例第二问被家人抢占感情 / 事业
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-09-04
|
||||
- 最近更新:2026-09-04
|
||||
- 影响面:`buildMethodFollowupPlan` 里 `nextDatedCollectFollowup` 的插入位置
|
||||
- 用户现象:新案例已有 1 件事业(或 1 件感情)时,第二问变成家人,而不是感情 / 事业。
|
||||
- 触发条件:训练门未开(前 3 件事几乎总是如此);`3847e9c9` 把 dated 补采集插在方法覆盖轮转之前。
|
||||
- 根因:上游任务书把「缺第三件带年份的事」的顺序写成了训练门未开阶段的总顺序。执行方按字面把 `nextDatedCollectFollowup` 放在 `!dashaCovered` 之后、感情 / 事业 / 家人轮转之前。这是任务书顺序错位,不是执行方偏离。
|
||||
- 修复:删掉轮转前分支。轮转里 `!familyCovered` 之后、`!occupationCovered` 之前,训练门未开且 `nextDatedCollectFollowup` 有结果时取它。此时感情 / 事业 / 家人已 covered 或 declined,补采集只会给出学业 → 财务 → 搬家 → 健康。`DATED_COLLECT_ORDER` 与 `exhaustionSpokenCollectFollowup` 不动。
|
||||
- 验证:`rectification-collect-direction-20260904` 锁 1 事业 → `d9_relationship`、1 感情 → `d10_career`、事业+感情 → `relatives`、再拒答家人 → `d5_education`、再拒答学业 → `d2_finance`。家人答「没有」后焦点仍是学业。`3847e9c9` 改写的感情 / 事业断言回到 `45bdb63e`。
|
||||
- 防复发:dated 补采集不得插在感情 / 事业轮转之前。训练门未开时新案例前两问仍是 D9 / D10。
|
||||
- 相关记录:BUG-528、BUG-463
|
||||
- 复发自:BUG-528
|
||||
- 修复版本:待发布
|
||||
|
||||
## BUG-532 | 原生 input 间距合同测试仍锁 12px
|
||||
|
||||
- 状态:resolved
|
||||
- 首次发现:2026-09-04
|
||||
- 最近更新:2026-09-04
|
||||
- 影响面:`frontend/tests/admin-model-management-ui-contract.test.ts`;挡住 `backend-quality-gate` 的 `npm test --prefix frontend`
|
||||
- 用户现象:无直接用户可见故障。`7ee7f825` 之后门禁因这一条失败,staging 部署停在更早的 SHA。
|
||||
- 触发条件:`globals.css` 原生 input 为 `padding: 0 var(--space-3)`,合同测试仍匹配 `padding: 0 12px;`。
|
||||
- 根因:`7ee7f825`(`fix(ui): collapse product weights and radii onto the shared Button`)把间距收敛到 token,未改合同测试。本单开工时 `origin/staging` 上这条仍红,别处未修。
|
||||
- 修复:测试接受 `padding: 0 var(--space-3);`。不改 CSS。
|
||||
- 验证:`admin-model-management-ui-contract` 全过;全量失败清单只剩 Docker 并发争用,隔离重跑通过。
|
||||
- 防复发:改 `globals.css` 原生控件尺寸时同步合同测试。不得为迁就测试把 token 改回裸像素。
|
||||
- 相关记录:无
|
||||
- 复发自:无
|
||||
- 修复版本:待发布
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
# PROGRESS · 采集方向修复单(2026-09-04)
|
||||
|
||||
工作树:`.worktrees/rectification-collect-direction-fix-20260904`
|
||||
分支:`codex/rectification-collect-direction-fix-20260904`
|
||||
基线:任务书写 `origin/staging` `3847e9c9`;开工时 tip 是纯文档 `cce919fe`。交付前再 `git fetch`,快进合入 `846b6064`(BUG-526 任务书,未占用 BUG-531)。
|
||||
任务书:`docs/tasks/TASK-rectification-collect-direction-fix-20260904.md`
|
||||
未改 Python、未 bump Skill(仍 10.0.14)、未改 `holdoutFollowupFor` / `validateSpokenPrompt` / `collectionProgressFromReceipt` / `declinedDomains` / 采用确认门。推 `origin/staging`。
|
||||
|
||||
| 任务 | 状态 | BUG |
|
||||
| --- | --- | --- |
|
||||
| 5.1 dated 分支移到轮转内(家人后、职业前) | 完成 | BUG-531 |
|
||||
| 5.2 回退 17 条感情/事业断言 | 完成 | 随 BUG-531 |
|
||||
| 5.3 门禁 CSS 合同测试 | 完成 | BUG-532 |
|
||||
| 5.4 记录 | 完成 | — |
|
||||
|
||||
## 编号
|
||||
|
||||
开工时 `docs/BUG_HISTORY.md` 最大号 BUG-530。本单 **BUG-531~532**。`846b6064` 未占用。
|
||||
|
||||
## 实现要点
|
||||
|
||||
- 删掉 `buildMethodFollowupPlan` 里轮转前的 `if (!next && !meetsAcceptanceEventQuality) nextDatedCollectFollowup`。
|
||||
- 轮转内 `!familyCovered` 之后、`!occupationCovered` 之前:训练门未开且 `nextDatedCollectFollowup` 有结果则取它。`source` 仍是 `method_coverage`。
|
||||
- `DATED_COLLECT_ORDER` 与 `exhaustionSpokenCollectFollowup` 不动;`rectification-range-offer-deadend` 搬家在职业前保留。
|
||||
- `3847e9c9` 把新案例第二问改成家人的断言回到 `45bdb63e`(感情 / 事业)。三栏:原值 = `3847e9c9`,新值 = `45bdb63e`,原因 = dated 分支移到家人之后。
|
||||
- CSS 合同测试接受 `padding: 0 var(--space-3)`。这条是 `7ee7f825` 引入的,开工时 staging 仍红,别处未修。
|
||||
|
||||
## 偏离
|
||||
|
||||
- `rectification-question-ownership` / `rectification-v10-conversation-focus` 不能把 spokenPrompt 恢复成「哪年上的大学」:服务端下一问仍是采集,BUG-529 要求题干命中领域词。默认 1 件事业现在下一问是感情,改用 `USER_COLLECT_QUESTION.relationship`。
|
||||
- `three dated events with one holdout` 仍锁 `domain: finance`(家人拒答后 dated 补采集,不是轮转抢跑)。`45bdb63e` 未锁 domain;本单不删这条,因为行为与 `3847e9c9` 补第三件事一致。
|
||||
- `collect_retry: true` 与 `USER_COLLECT_QUESTION_RETRY.relationship` 实际在 `rectification-walkthrough-polish`,已恢复。v10 文件里没有这两条断言。
|
||||
|
||||
## 测试
|
||||
|
||||
`tsc --noEmit`:exit=0。
|
||||
|
||||
聚焦套件 `tsx --test tests/rectification-*.test.ts tests/admin-model-management-ui-contract.test.ts`:
|
||||
|
||||
```
|
||||
# tests 875
|
||||
# pass 875
|
||||
# fail 0
|
||||
# cancelled 0
|
||||
# skipped 0
|
||||
# todo 0
|
||||
exit=0
|
||||
```
|
||||
|
||||
新断言在 `rectification-collect-direction-20260904.test.ts`:9/9。
|
||||
|
||||
全量 `npm test`(本机有 Docker):
|
||||
|
||||
```
|
||||
# tests 2656
|
||||
# pass 2654
|
||||
# fail 2
|
||||
# cancelled 0
|
||||
# skipped 0
|
||||
# todo 0
|
||||
exit=1
|
||||
```
|
||||
|
||||
2 条失败均为 Docker 迁移争用(`database migration failed`):`database-personal-report-sections`、`rectification-v9-database` 里 `v9 agent api migration…`。`--test-concurrency=1` 隔离重跑:
|
||||
|
||||
```
|
||||
# tests 8
|
||||
# pass 8
|
||||
# fail 0
|
||||
# cancelled 0
|
||||
# skipped 0
|
||||
# todo 0
|
||||
exit=0
|
||||
```
|
||||
|
||||
`eslint` 本单文件 0 error;`choice-card` / `walkthrough-polish` 各 1 条既有 unused 警告,未触碰。
|
||||
|
||||
未改 Python;未声称系统 `python3` 预检通过。
|
||||
|
||||
## 改动文件
|
||||
|
||||
- 计划:`frontend/src/lib/rectification-agentic/v9/method-followup.ts`
|
||||
- 新断言:`frontend/tests/rectification-collect-direction-20260904.test.ts`
|
||||
- 回退:eight-method、walkthrough-polish、question-ownership、choice-card、v10-conversation-focus
|
||||
- 门禁:`frontend/tests/admin-model-management-ui-contract.test.ts`
|
||||
- 文档:`docs/BUG_HISTORY.md`、`docs/tasks/README.md`、`CHANGELOG.md`、本文件
|
||||
@@ -48,7 +48,7 @@
|
||||
| `TASK-rectification-adopt-narration-fix-20260904.md` | `PROGRESS-rectification-adopt-narration-fix-20260904.md` | 采用旁白 Agent 在点选入口从不运行(早退分支重算过期决策)+ 校验器/可观测/超时 | 已验收(5.1/5.2 实现通过;超时测试挂死事件循环,见修复单 2) | `13dded9f`(BUG-521/522) |
|
||||
| `TASK-rectification-adopt-narration-fix2-20260904.md` | `PROGRESS-rectification-adopt-narration-fix2-20260904.md` | 采用旁白超时用了 unref 的 `AbortSignal.timeout`,测试挂死取消同文件后三条用例,门禁 `npm test` 退出码 1 | 已验收(门禁通过,staging 已部署) | `45bdb63e`(BUG-523) |
|
||||
| `TASK-rectification-collect-direction-20260904.md` | `PROGRESS-rectification-collect-direction-20260904.md` | 可评分事件 2 条时盘外核对抢跑到刚拒答的家人领域,Agent 只能改写成不指向任何领域的泛问;缺第三件带年份的事却先问职业 | 已验收:5.1/5.3/5.4 通过;5.2 顺序错位(任务书责任)见修复单 | `codex/rectification-collect-direction-20260904`(BUG-527~530) |
|
||||
| `TASK-rectification-collect-direction-fix-20260904.md` | `PROGRESS-rectification-collect-direction-fix-20260904.md` | dated 补采集分支插在方法轮转之前,新案例第二问被家人抢占感情/事业;`7ee7f825` CSS 与合同测试脱节挡住门禁 | 待执行 | `codex/rectification-collect-direction-fix-20260904`(BUG-531~532) |
|
||||
| `TASK-rectification-collect-direction-fix-20260904.md` | `PROGRESS-rectification-collect-direction-fix-20260904.md` | dated 补采集分支插在方法轮转之前,新案例第二问被家人抢占感情/事业;`7ee7f825` CSS 与合同测试脱节挡住门禁 | 待验收 | `codex/rectification-collect-direction-fix-20260904`(BUG-531~532) |
|
||||
| `TASK-rectification-ux-20260902.md` | `PROGRESS-rectification-ux-20260903.md` | 会话面空白假死与交互摩擦 | 已验收 | `d159f08e`(09-03 在新基线重做后合入,BUG-505~509) |
|
||||
|
||||
### 聊天主链路与首页
|
||||
|
||||
@@ -1843,10 +1843,6 @@ export function buildMethodFollowupPlan(input: {
|
||||
source: "method_coverage",
|
||||
});
|
||||
}
|
||||
if (!next && !meetsAcceptanceEventQuality(input.evidence)) {
|
||||
const dated = nextDatedCollectFollowup(input.evidence, declined);
|
||||
if (dated) next = makeFollowup(dated);
|
||||
}
|
||||
if (!next && dashaCovered && coverageComplete && occupationCovered) {
|
||||
const allowLowGainDiscriminator = !coverageComplete || !candidatesSeparated;
|
||||
const yearless = yearlessDiscriminators[0];
|
||||
@@ -1911,6 +1907,7 @@ export function buildMethodFollowupPlan(input: {
|
||||
const candidate = followupFromRanked(ranked);
|
||||
return candidate.choice_frame ? candidate : null;
|
||||
};
|
||||
let datedCollect: MethodFollowup | null = null;
|
||||
if (!next) {
|
||||
if (!relationshipCovered && !declined.has("relationship")) {
|
||||
next = sameDomainYearlessCard("relationship") ?? makeFollowup({
|
||||
@@ -1956,6 +1953,11 @@ export function buildMethodFollowupPlan(input: {
|
||||
source: "method_coverage",
|
||||
...collectionYearFields(familyCollect),
|
||||
});
|
||||
} else if (
|
||||
!meetsAcceptanceEventQuality(input.evidence)
|
||||
&& (datedCollect = nextDatedCollectFollowup(input.evidence, declined))
|
||||
) {
|
||||
next = makeFollowup(datedCollect);
|
||||
} else if (!occupationCovered) {
|
||||
if (meetsAcceptanceEventQuality(input.evidence)) {
|
||||
for (const ranked of yearlessDiscriminators) {
|
||||
|
||||
@@ -115,9 +115,12 @@ test("model management renders localized labels without changing stored enum val
|
||||
});
|
||||
|
||||
test("global native input sizing excludes Ant Design picker internals", () => {
|
||||
// 原值: padding: 0 12px
|
||||
// 新值: padding: 0 var(--space-3)
|
||||
// 原因: 7ee7f825 把间距收敛到 token;合同测试跟随 CSS,不改业务代码。
|
||||
assert.match(
|
||||
globals,
|
||||
/input:not\(\[type="radio"\]\):not\(\[type="checkbox"\]\):not\(\[class\^="ant-"\]\):not\(\[class\*=" ant-"\]\):not\(\.ant-picker input\), select[^\{]+\{ width: 100%; min-height: 44px; padding: 0 12px;/,
|
||||
/input:not\(\[type="radio"\]\):not\(\[type="checkbox"\]\):not\(\[class\^="ant-"\]\):not\(\[class\*=" ant-"\]\):not\(\.ant-picker input\), select[^\{]+\{ width: 100%; min-height: 44px; padding: 0 var\(--space-3\);/,
|
||||
);
|
||||
assert.match(
|
||||
globals,
|
||||
|
||||
@@ -605,10 +605,10 @@ test("GET hides a legacy known-event quality focus and resumes evidence collecti
|
||||
expectedAnswerSchema: { choice: SAMPLE_COPY },
|
||||
},
|
||||
});
|
||||
// 原值: d9_relationship
|
||||
// 新值: relatives
|
||||
// 原因: 丢弃遗留质量焦点后继续采集;一件学业未开训练门,下一问是家人。
|
||||
assert.equal(plan.next_followup?.method_id, "relatives");
|
||||
// 原值: relatives
|
||||
// 新值: d9_relationship
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情 / 事业
|
||||
assert.equal(plan.next_followup?.method_id, "d9_relationship");
|
||||
assert.equal(plan.next_followup?.choice_frame, null);
|
||||
});
|
||||
|
||||
|
||||
@@ -100,6 +100,43 @@ function collectPlan(
|
||||
});
|
||||
}
|
||||
|
||||
test("method rotation asks relationship and career before dated collect", () => {
|
||||
const careerOnly = buildMethodFollowupPlan({
|
||||
evidence: [dated("career", "2011", { eventKind: "career_entry" })],
|
||||
holdoutValidation: "not_started",
|
||||
});
|
||||
assert.equal(careerOnly.next_followup?.method_id, "d9_relationship");
|
||||
assert.equal(careerOnly.next_followup?.domain, "relationship");
|
||||
|
||||
const relationshipOnly = buildMethodFollowupPlan({
|
||||
evidence: [dated("relationship", "2014", { eventKind: "relationship_start" })],
|
||||
holdoutValidation: "not_started",
|
||||
});
|
||||
assert.equal(relationshipOnly.next_followup?.method_id, "d10_career");
|
||||
assert.equal(relationshipOnly.next_followup?.domain, "career");
|
||||
|
||||
const both = buildMethodFollowupPlan({
|
||||
evidence: TWO_SCOREABLE,
|
||||
holdoutValidation: "not_started",
|
||||
});
|
||||
assert.equal(both.next_followup?.method_id, "relatives");
|
||||
assert.equal(both.next_followup?.domain, "family");
|
||||
|
||||
const familyDeclined = collectPlan(TWO_SCOREABLE);
|
||||
assert.equal(familyDeclined.next_followup?.method_id, "d5_education");
|
||||
assert.equal(familyDeclined.next_followup?.domain, "education");
|
||||
assert.notEqual(familyDeclined.next_followup?.domain, "occupation");
|
||||
|
||||
const educationDeclined = collectPlan(TWO_SCOREABLE, {
|
||||
declinedTopics: [
|
||||
...FAMILY_DECLINED,
|
||||
{ target_domain: "education", status: "declined", intent: "collect_method_evidence" },
|
||||
],
|
||||
});
|
||||
assert.equal(educationDeclined.next_followup?.method_id, "d2_finance");
|
||||
assert.equal(educationDeclined.next_followup?.domain, "finance");
|
||||
});
|
||||
|
||||
test("two scoreable events do not open OOS even when holdout prompts exist", () => {
|
||||
assert.equal(meetsAcceptanceEventQuality(TWO_SCOREABLE), false);
|
||||
const declined = new Set(["family"]);
|
||||
|
||||
@@ -54,6 +54,8 @@ const FAMILY_ID = "44444444-4444-4444-8444-444444444443";
|
||||
const CAREER_ID = "44444444-4444-4444-8444-444444444444";
|
||||
const UNIQUE_MINUTE_COPY = /±5 分钟确定性/;
|
||||
|
||||
// 本单回退 3847e9c9 把训练门未开的下一问改成家人的断言。见各断言旁三栏。
|
||||
|
||||
function collectDecision(candidates: readonly { time: string; relativeSupport?: number }[]) {
|
||||
return decideRectification({
|
||||
engineCeiling: OPEN_ENGINE_CAPABILITY_CEILING,
|
||||
@@ -365,7 +367,7 @@ function stubEngine(response: unknown) {
|
||||
};
|
||||
}
|
||||
|
||||
test("eight-method routing asks family after dated education, not relocation", () => {
|
||||
test("eight-method routing asks relationship after dated education, not relocation", () => {
|
||||
const plan = buildMethodFollowupPlan({
|
||||
evidence: [{
|
||||
status: "confirmed",
|
||||
@@ -375,11 +377,11 @@ test("eight-method routing asks family after dated education, not relocation", (
|
||||
occurredTo: null,
|
||||
}],
|
||||
});
|
||||
// 原值: d9_relationship / relationship
|
||||
// 新值: relatives / family
|
||||
// 原因: 训练门未开时主流程走 datedCollectOrder,家人在感情之前;SQL missing 的 relocation 仍不进轮转。
|
||||
assert.equal(plan.next_followup?.method_id, "relatives");
|
||||
assert.equal(plan.next_followup?.domain, "family");
|
||||
// 原值: relatives / family
|
||||
// 新值: d9_relationship / relationship
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情 / 事业
|
||||
assert.equal(plan.next_followup?.method_id, "d9_relationship");
|
||||
assert.equal(plan.next_followup?.domain, "relationship");
|
||||
assert.equal(plan.stop_domain_rotation, true);
|
||||
assert.deepEqual([...plan.not_in_rotation], ["relocation"]);
|
||||
assert.equal(plan.methods.find((item) => item.method_id === "appearance")?.status, "skipped_by_policy");
|
||||
@@ -390,11 +392,11 @@ test("dasha conflict probe does not jump ahead of method rotation before accepta
|
||||
evidence: [datedEvidence("education", "2016")],
|
||||
eventProbes: [CAREER_CONFLICT_PROBE],
|
||||
});
|
||||
// 原值: method_coverage / d9_relationship
|
||||
// 新值: method_coverage / relatives
|
||||
// 原因: 训练门未开时先补家人采集,冲突探针仍不得抢跑。
|
||||
// 原值: method_coverage / relatives
|
||||
// 新值: method_coverage / d9_relationship
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情 / 事业
|
||||
assert.equal(plan.next_followup?.source, "method_coverage");
|
||||
assert.equal(plan.next_followup?.method_id, "relatives");
|
||||
assert.equal(plan.next_followup?.method_id, "d9_relationship");
|
||||
assert.equal(plan.next_followup?.choice_frame, null);
|
||||
assert.notEqual(plan.next_followup?.source, "event_probe");
|
||||
});
|
||||
@@ -404,11 +406,11 @@ test("known exam quality does not create a scoring card after one recorded event
|
||||
evidence: [datedEvidence("education", "2016")],
|
||||
eventProbes: [EDUCATION_QUALITY_PROBE, CAREER_CONFLICT_PROBE],
|
||||
});
|
||||
// 原值: method_coverage / d9_relationship
|
||||
// 新值: method_coverage / relatives
|
||||
// 原因: 一条学业记录未开训练门,先问家人而不是质量卡。
|
||||
// 原值: method_coverage / relatives
|
||||
// 新值: method_coverage / d9_relationship
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情 / 事业
|
||||
assert.equal(plan.next_followup?.source, "method_coverage");
|
||||
assert.equal(plan.next_followup?.method_id, "relatives");
|
||||
assert.equal(plan.next_followup?.method_id, "d9_relationship");
|
||||
assert.equal(plan.next_followup?.choice_frame, null);
|
||||
assert.notEqual(plan.next_followup?.choice_kind, "event_quality");
|
||||
});
|
||||
@@ -421,11 +423,11 @@ test("career known-event quality does not jump the adoption gate", () => {
|
||||
],
|
||||
eventProbes: [CAREER_QUALITY_PROBE, CAREER_CONFLICT_PROBE],
|
||||
});
|
||||
// 原值: method_coverage / d9_relationship
|
||||
// 新值: method_coverage / relatives
|
||||
// 原因: 两条事业记录仍不足训练门(领域数不够),先补家人。
|
||||
// 原值: method_coverage / relatives
|
||||
// 新值: method_coverage / d9_relationship
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情 / 事业
|
||||
assert.equal(plan.next_followup?.source, "method_coverage");
|
||||
assert.equal(plan.next_followup?.method_id, "relatives");
|
||||
assert.equal(plan.next_followup?.method_id, "d9_relationship");
|
||||
assert.equal(plan.next_followup?.choice_frame, null);
|
||||
assert.notEqual(plan.next_followup?.source, "event_probe");
|
||||
assert.notEqual(plan.next_followup?.choice_kind, "event_quality");
|
||||
@@ -436,11 +438,11 @@ test("encoded exam quality does not stamp another card and keeps method rotation
|
||||
evidence: [datedEvidence("education", "2016", { summary: "2016年高考发挥异常" })],
|
||||
eventProbes: [EDUCATION_QUALITY_PROBE, CAREER_CONFLICT_PROBE],
|
||||
});
|
||||
// 原值: method_coverage / d9_relationship
|
||||
// 新值: method_coverage / relatives
|
||||
// 原因: 编码质量探针仍不得在训练门前出卡;下一问是家人采集。
|
||||
// 原值: method_coverage / relatives
|
||||
// 新值: method_coverage / d9_relationship
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情 / 事业
|
||||
assert.equal(plan.next_followup?.source, "method_coverage");
|
||||
assert.equal(plan.next_followup?.method_id, "relatives");
|
||||
assert.equal(plan.next_followup?.method_id, "d9_relationship");
|
||||
assert.equal(plan.next_followup?.choice_frame, null);
|
||||
});
|
||||
|
||||
@@ -504,11 +506,11 @@ test("three scoreable events in one domain still rotate methods instead of rever
|
||||
],
|
||||
eventProbes: [CAREER_CONFLICT_PROBE],
|
||||
});
|
||||
// 原值: method_coverage / d9_relationship
|
||||
// 新值: method_coverage / relatives
|
||||
// 原因: 三件都在学业,领域数不足训练门,先补家人而不是反推。
|
||||
// 原值: method_coverage / relatives
|
||||
// 新值: method_coverage / d9_relationship
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情 / 事业
|
||||
assert.equal(plan.next_followup?.source, "method_coverage");
|
||||
assert.equal(plan.next_followup?.method_id, "relatives");
|
||||
assert.equal(plan.next_followup?.method_id, "d9_relationship");
|
||||
assert.equal(plan.next_followup?.choice_frame, null);
|
||||
});
|
||||
|
||||
@@ -528,11 +530,11 @@ test("occupation_note does not count toward reverse-inference event quality", ()
|
||||
],
|
||||
eventProbes: [CAREER_CONFLICT_PROBE],
|
||||
});
|
||||
// 原值: method_coverage / d9_relationship
|
||||
// 新值: method_coverage / relatives
|
||||
// 原因: occupation_note 不计训练门,下一问仍是家人采集。
|
||||
// 原值: method_coverage / relatives
|
||||
// 新值: method_coverage / d9_relationship
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情 / 事业
|
||||
assert.equal(plan.next_followup?.source, "method_coverage");
|
||||
assert.equal(plan.next_followup?.method_id, "relatives");
|
||||
assert.equal(plan.next_followup?.method_id, "d9_relationship");
|
||||
assert.equal(plan.next_followup?.choice_frame, null);
|
||||
});
|
||||
|
||||
@@ -558,10 +560,10 @@ test("age-band probe does not jump ahead of uncovered relationship", () => {
|
||||
role: "reverse_verify",
|
||||
}],
|
||||
});
|
||||
// 原值: d9_relationship
|
||||
// 新值: relatives
|
||||
// 原因: 年龄带探针不得抢跑;训练门未开时先问家人,不是感情。
|
||||
assert.equal(plan.next_followup?.method_id, "relatives");
|
||||
// 原值: relatives
|
||||
// 新值: d9_relationship
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情 / 事业
|
||||
assert.equal(plan.next_followup?.method_id, "d9_relationship");
|
||||
assert.equal(plan.next_followup?.source, "method_coverage");
|
||||
assert.equal(plan.next_followup?.choice_frame, null);
|
||||
});
|
||||
@@ -618,10 +620,10 @@ test("user-stop action offers a range when candidates already exist", () => {
|
||||
assert.equal(plan.methods.find((item) => item.method_id === "marks")?.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");
|
||||
// 原值: d9_relationship
|
||||
// 新值: relatives
|
||||
// 原因: 一件学业未开训练门,用户停下时仍在采集家人。
|
||||
assert.equal(plan.next_followup?.method_id, "relatives");
|
||||
// 原值: relatives
|
||||
// 新值: d9_relationship
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情 / 事业
|
||||
assert.equal(plan.next_followup?.method_id, "d9_relationship");
|
||||
assert.match(plan.next_followup?.user_prompt_hint ?? "", /自然语言/);
|
||||
assert.doesNotMatch(plan.next_followup?.user_prompt_hint ?? "", /A\/B\/C\/D/);
|
||||
assert.equal(plan.next_followup?.choice_frame, null);
|
||||
@@ -647,10 +649,10 @@ test("selectionAllowed with remaining method follow-up keeps collecting and offe
|
||||
nextFollowup: plan.next_followup,
|
||||
workingTime: "05:07",
|
||||
});
|
||||
// 原值: d9_relationship
|
||||
// 新值: relatives
|
||||
// 原因: 训练门未开时继续采集家人,停下才给区间。
|
||||
assert.equal(plan.next_followup?.method_id, "relatives");
|
||||
// 原值: relatives
|
||||
// 新值: d9_relationship
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情 / 事业
|
||||
assert.equal(plan.next_followup?.method_id, "d9_relationship");
|
||||
assert.equal(action.id, "ask_method_followup");
|
||||
assert.equal(action.on_user_stop.id, "offer_provisional_range");
|
||||
});
|
||||
@@ -667,10 +669,10 @@ test("adopt_representative defers method follow-up instead of asking this turn",
|
||||
sessionOutcome: "adopt_representative",
|
||||
});
|
||||
assert.equal(plan.next_followup, null);
|
||||
// 原值: d9_relationship
|
||||
// 新值: relatives
|
||||
// 原因: 采用轮仍 stash 下一采集题;训练门未开时那题是家人。
|
||||
assert.equal(plan.deferred_followup?.method_id, "relatives");
|
||||
// 原值: relatives
|
||||
// 新值: d9_relationship
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情 / 事业
|
||||
assert.equal(plan.deferred_followup?.method_id, "d9_relationship");
|
||||
assert.equal(plan.session_outcome, "adopt_representative");
|
||||
});
|
||||
|
||||
@@ -699,11 +701,11 @@ test("declined relationship skips to career and leaves horary uncovered", () =>
|
||||
}],
|
||||
declinedTopics: [{ target_domain: "relationship", status: "declined" }],
|
||||
});
|
||||
// 原值: d10_career / career
|
||||
// 新值: relatives / family
|
||||
// 原因: 感情拒答只跳过感情;训练门未开时下一件带年份的是家人,不是事业。
|
||||
assert.equal(plan.next_followup?.method_id, "relatives");
|
||||
assert.equal(plan.next_followup?.domain, "family");
|
||||
// 原值: relatives / family
|
||||
// 新值: d10_career / career
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情 / 事业
|
||||
assert.equal(plan.next_followup?.method_id, "d10_career");
|
||||
assert.equal(plan.next_followup?.domain, "career");
|
||||
assert.deepEqual([...plan.do_not_poll], []);
|
||||
assert.equal(plan.methods.find((item) => item.method_id === "horary")?.status, "uncovered");
|
||||
});
|
||||
@@ -938,11 +940,11 @@ test("read-case follows method plan and keeps D9/D10 type tables when SQL missin
|
||||
}>;
|
||||
}).execute({ caseId: CASE_ID, projection: "full_diagnostics" });
|
||||
assert.deepEqual(projection.conversation_summary.missing_evidence_categories, ["relocation", "health", "finance"]);
|
||||
// 原值: d9_relationship / relationship
|
||||
// 新值: d2_finance / finance
|
||||
// 原因: 学业+家人+事业三条里 1 条 holdout,训练门未开;datedCollectOrder 里家人/学业已有记录,下一问是财务。仍不按 SQL missing 先问搬家。
|
||||
assert.equal(projection.method_followup_plan.next_followup?.method_id, "d2_finance");
|
||||
assert.equal(projection.method_followup_plan.next_followup?.domain, "finance");
|
||||
// 原值: d2_finance / finance
|
||||
// 新值: d9_relationship / relationship
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情 / 事业
|
||||
assert.equal(projection.method_followup_plan.next_followup?.method_id, "d9_relationship");
|
||||
assert.equal(projection.method_followup_plan.next_followup?.domain, "relationship");
|
||||
assert.equal(projection.method_followup_plan.deferred_followup, null);
|
||||
assert.equal(projection.method_followup_plan.session_outcome, "collect_evidence");
|
||||
assert.equal(
|
||||
@@ -1626,10 +1628,10 @@ test("precision stage lagna_frame waits for uncovered career before asking anoth
|
||||
],
|
||||
precisionStage: "lagna_frame",
|
||||
});
|
||||
// 原值: d10_career
|
||||
// 新值: relatives
|
||||
// 原因: 学业+感情仍不足训练门,lagna_frame 不得先问另一件泛问;先补家人。
|
||||
assert.equal(plan.next_followup?.method_id, "relatives");
|
||||
// 原值: relatives
|
||||
// 新值: d10_career
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情 / 事业
|
||||
assert.equal(plan.next_followup?.method_id, "d10_career");
|
||||
assert.equal(plan.next_followup?.source, "method_coverage");
|
||||
assert.equal(isOfferBlockingFollowup(plan.next_followup, plan.methods), true);
|
||||
assert.doesNotMatch(JSON.stringify(plan), UNIQUE_MINUTE_COPY);
|
||||
@@ -2726,9 +2728,9 @@ test("three dated events with one holdout keep collecting instead of discriminat
|
||||
precisionStage: "lagna_frame",
|
||||
eventProbes: [CAREER_CONFLICT_PROBE],
|
||||
});
|
||||
// 原值: method_coverage(方法轮转)
|
||||
// 原值: method_coverage / finance(3847e9c9 新增 domain 锁)
|
||||
// 新值: method_coverage / finance
|
||||
// 原因: 家人已拒答,学业/事业/感情已有记录,holdout 占用 1 条,训练门未开,补财务而不是区分。
|
||||
// 原因: dated 分支在家人之后;家人已拒答,下一件带年份仍是财务,不是轮转抢跑。
|
||||
assert.equal(plan.next_followup?.source, "method_coverage");
|
||||
assert.equal(plan.next_followup?.intent, "collect_method_evidence");
|
||||
assert.equal(plan.next_followup?.domain, "finance");
|
||||
@@ -2800,10 +2802,10 @@ test("adjacent education year does not re-ask enrollment after a recorded start"
|
||||
});
|
||||
assert.notEqual(plan.next_followup?.domain, "education");
|
||||
assert.notEqual(plan.next_followup?.source, "event_probe");
|
||||
// 原值: d10_career
|
||||
// 新值: relatives
|
||||
// 原因: 邻近年不得再问入学;训练门未开时下一问是家人,不是事业。
|
||||
assert.equal(plan.next_followup?.method_id, "relatives");
|
||||
// 原值: relatives
|
||||
// 新值: d10_career
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情 / 事业
|
||||
assert.equal(plan.next_followup?.method_id, "d10_career");
|
||||
assert.match(plan.next_followup?.user_prompt_hint ?? "", /2016 年入学/);
|
||||
assert.match(plan.next_followup?.user_prompt_hint ?? "", /2024 年感情结束/);
|
||||
assert.match(plan.next_followup?.user_prompt_hint ?? "", /不要再问这些事发生在哪一年/);
|
||||
|
||||
@@ -402,10 +402,10 @@ test("collect set-focus writes collect:true even if Agent sends choice", async (
|
||||
caseId: CASE_ID,
|
||||
questionId: followup ? stableFollowupQuestionId(followup) : "collect:relationship:collect_method_evidence",
|
||||
intent: "collect_method_evidence",
|
||||
// 原值: 「你还记得哪年上的大学吗?」
|
||||
// 新值: USER_COLLECT_QUESTION[domain](默认 dossier 一件事业 → 家人)
|
||||
// 原因: 采集题干必须命中服务端领域关键词,大学不命中家人。
|
||||
spokenPrompt: USER_COLLECT_QUESTION[followup?.domain ?? "family"] ?? USER_COLLECT_QUESTION.family,
|
||||
// 原值: USER_COLLECT_QUESTION.family(3847e9c9;45bdb63e 为「哪年上的大学」)
|
||||
// 新值: USER_COLLECT_QUESTION[followup.domain](默认 dossier 一件事业 → 感情)
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情;BUG-529 仍要求题干命中领域词,大学不命中感情。
|
||||
spokenPrompt: USER_COLLECT_QUESTION[followup?.domain ?? "relationship"] ?? USER_COLLECT_QUESTION.relationship,
|
||||
expectedAnswerSchema: {
|
||||
choice: {
|
||||
prompt: "伪造采集",
|
||||
|
||||
@@ -140,10 +140,10 @@ test("set/resolve focus tools return safe projections and never infer the active
|
||||
caseId: CASE_ID,
|
||||
questionId: "career-month-question",
|
||||
intent: "clarify_event_date",
|
||||
// 原值: 「你还记得哪年上的大学吗?」
|
||||
// 新值: USER_COLLECT_QUESTION.family
|
||||
// 原因: 默认 dossier 一件事业,训练门未开时下一问是家人采集;大学不命中家人关键词。
|
||||
spokenPrompt: USER_COLLECT_QUESTION.family,
|
||||
// 原值: USER_COLLECT_QUESTION.family(3847e9c9;45bdb63e 为「哪年上的大学」)
|
||||
// 新值: USER_COLLECT_QUESTION.relationship
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情;服务端下一问仍是采集,BUG-529 要求题干命中感情词。
|
||||
spokenPrompt: USER_COLLECT_QUESTION.relationship,
|
||||
}) as Record<string, unknown>;
|
||||
assert.equal(setResult.ok, undefined);
|
||||
assert.equal(setResult.focus_id, FOCUS_ID);
|
||||
|
||||
@@ -459,11 +459,12 @@ test("same-domain collect retry uses structured closed-focus state, not body mat
|
||||
}],
|
||||
sessionOutcome: "collect_evidence",
|
||||
});
|
||||
// 原值: relationship / collect_retry true
|
||||
// 新值: family
|
||||
// 原因: 一件事业未开训练门,datedCollectOrder 先问家人;已关闭的感情采集不挡家人。retry 文案仍由上面的 constructed followup 覆盖。
|
||||
assert.equal(plan.next_followup?.domain, "family");
|
||||
assert.equal(spokenFollowupForUser(plan.next_followup), USER_COLLECT_QUESTION.family);
|
||||
// 原值: family
|
||||
// 新值: relationship / collect_retry true / USER_COLLECT_QUESTION_RETRY.relationship
|
||||
// 原因: dated 分支移到家人之后,前两问恢复感情 / 事业
|
||||
assert.equal(plan.next_followup?.domain, "relationship");
|
||||
assert.equal(plan.next_followup?.collect_retry, true);
|
||||
assert.equal(spokenFollowupForUser(plan.next_followup), USER_COLLECT_QUESTION_RETRY.relationship);
|
||||
const declined = buildMethodFollowupPlan({
|
||||
evidence: [{
|
||||
status: "confirmed",
|
||||
|
||||
Reference in New Issue
Block a user