fix(rectification): stop occupation coverage from locking questions and the range exit
Independent Staging Quality Gate / validate (push) Successful in 11m40s
Independent Staging Quality Gate / publish (push) Successful in 9m36s

Occupation answers were stored as career, so coverage never closed, yearless
cards never fired, and the decision layer suppressed an engine-allowed range.
Normalize occupation-collect writes, allow yearless cards once training is
open, offer a range when no distinguish card remains, and align the public
house table to the representative minute.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-30 03:05:28 +08:00
co-authored by Cursor
parent f5c02924c9
commit 02d4c91626
16 changed files with 815 additions and 69 deletions
+16
View File
@@ -6767,3 +6767,19 @@
- 复发自:BUG-432(无选择卡的问题曾要求由 Agent 正文问出,前端仍不渲染 `current_question`
- 修复版本:待发布
## BUG-442 | 职业采集关不上、无年份卡出不来、覆盖门压掉区间出口
- 状态:resolved
- 首次发现:2026-08-30
- 最近更新:2026-08-30
- 影响面:`applyOccupationCollectLedgerNorm` / `occupationCovered``buildMethodFollowupPlan` 无年份分盘卡、`decideRectification` 覆盖门、POST `/api/rectification/agent` 区间出口、`houseTableAlignedToMinute` / `publicChartForMinute`
- 用户现象:账本已有足够可计分事件和多个领域,助手仍反复追问职业口述题;候选几乎均匀,`margin_percent` 停在门槛以下,entropy 不降;`can_offer_range` / `can_adopt` / `propose_allowed` / `selection_allowed` 全为 false,用户从头到尾没被告知可以按当前区间收口。对外代表分钟与宫位表也可能不是同一时刻。
- 触发条件:职业采集焦点下用户给出职业性质描述,模型把证据记成 `domain=career` 的入职/换工作;训练事件已达标,剩余高信息量探针全是无年份分盘题;引擎回执已 `accept_allowed` / `propose_allowed`,决策层仍因 occupation 覆盖 flag 落 `collect()`
- 根因:四段同时成立。(1) 覆盖判定 `isOccupationNote` 要求 `domain=occupation`,职业口述回答被记成 career 域,occupation 方法层永不关闭,`next_followup` 恒为职业口述采集题。(2) 无年份分盘卡的出题条件绑在 `coverageComplete` 上,覆盖不齐则 d24/d7/d4/d5 一道都出不来,margin 无法被这些探针拉开。(3) `decideRectification` 撞上 `coverageBlocks` 直接 `collect()`,把 `canOfferRange` 压成 false;同一份引擎回执已经放行 accept/propose,决策层因覆盖 flag 单方面压掉区间出口。(4) 对外投影的 `representative_time` 取推理层代表分钟,`house_table` / `natal_recast` 却可能是另一分钟算出的盘面。
- 修复:P0occupation 采集焦点下,服务端把该轮职业性质描述归一成 `domain=occupation` / `eventKind=occupation_note`(无日期允许,occupation_note 不参与计分)。覆盖端:已有确认 career 证据且 occupation 采集焦点已按 questionId / target_domain 关闭时也算覆盖,不读正文、不用关键词。P1:训练门开时允许出无年份分盘卡,不再要求覆盖齐;训练门未开仍不出,避免回到 BUG-405/407。同领域可渲染计分卡仍优先于不计分口述题(BUG-440)。P2:训练门已开且出题层给不出带 choice_frame 的可渲染区分卡时,允许 `canOfferRange` 并播报「可以先按当前区间看盘,也可以再补一件记得时间的经历」;引擎 accept/propose 已放行而覆盖 flag 要压掉时至少放行 `canOfferRange``canAdopt` 与 confirmation gate 维持 fail-closed。P3:对外 `representative_time``house_table``natal_recast` 必须是同一分钟;对不上则取 `house_tables_by_time` 对应表,否则标成不可用。Skill 保持 10.0.13。未引入语义正则、关键词表、A/B/C/D 位置推断或轮次状态机。
- 验证:`frontend/tests/rectification-occupation-coverage-exit.test.ts` 用本例 15 件可计分、4 域账本锁:occupation 采集回答落 occupation_notecareer 证据 + 已关闭 occupation 焦点覆盖成立;career 单独仍不覆盖;训练门开且覆盖未齐能出无年份分盘卡,训练门关仍不出;训练门开且无可渲染区分卡时 `canOfferRange` 为真、`canAdopt` / `canConfirmExactMinute` 为假;路由播报二选一;代表分钟与 `house_table` / `natal_recast` 同源,构造不一致回执不得直接发出。collect focus 仍不是选择卡。BUG-440 collect-stall、BUG-437 hash、D12 同领域卡优先保持绿。
- 防复发:覆盖判定不得依赖模型选对 domain。同一个覆盖 flag 不得同时锁死出题与出口。训练门已开且无可渲染区分卡时必须给用户出路。对外代表分钟与盘面必须同源。不得用正文文本判断覆盖或意图。
- 相关记录:BUG-404、BUG-407、BUG-410、BUG-432、BUG-437、BUG-440、BUG-441
- 复发自:BUG-440(覆盖未齐时的收口分支存在,但 occupation 记账域错误导致永远走不到;无年份卡仍被同一覆盖门锁死)
- 修复版本:待发布