# TASK · 生时校正结尾重设计:一张区间交付卡 + 只列未问分歧的对比面板,不再让用户在分钟里挑(2026-09-07) - 基线:`origin/staging` @ `0219f63b`(代码头 `4e0db55f`) - 分支:`codex/rectification-range-delivery-card-20260907` - 执行方:coding agent;验收:Claude - **串行**:必须排在 `TASK-rectification-stop-rescore-fix-20260907.md`(BUG-581~582,P0)合入并部署之后;两者都改 `answer-choice.ts` / `rectification-agentic-chat.tsx` / 采用路由 - 涉及文件:`frontend/src/components/rectification-agentic-chat.tsx`(`RectificationCandidateCards` 替换)、新组件 `frontend/src/components/rectification-range-delivery.tsx`、`frontend/src/lib/rectification-candidate-result.ts`、`frontend/src/lib/rectification-agentic/v9/adopt-narration.ts`、`v9/answer-choice.ts`(`withProspectiveWindows`)、新模块 `v9/divergence-panel.ts`、`frontend/src/app/api/rectification/cases/[caseId]/candidates/accept/route.ts`、`v9/case-service.ts`(快照投影)、`skills/jyotish-birth-time-rectification/SKILL.md`(§9 一处口径,bump 10.0.15)、`frontend/DESIGN.md`、`frontend/docs/VOICE.md` - 不改:采用门、确认门、`MIN_SEPARATION_LEAD`、`_relative_support`、引擎、采用 RPC 的校验 - BUG 编号:能力重设计,不预留;执行中发现缺陷再按当时最大号续 ## 0. 为什么做这件事 产品负责人 2026-09-07 拍板。三条依据:(1) 20 例公开 holdout 校准已证明引擎在分钟级近乎随机(BUG-560),四张分钟卡上的"相对支持度 16/13/12/8"对用户没有可判断性;(2) 答题已经把范围收到几分钟,交付对象应当是这段范围,代表分钟只是排盘用的计算点,报告与对话读的也是区间(BUG-568);(3) 产品负责人提出"并排几个时间让用户选"的体验,评审结论是:并排的对象只能是**剩余候选之间真正不同、且还没问过**的分盘分歧,不能是三篇完整解读(本命宫位表在这几分钟里完全相同,全文对比九成雷同且会把自我认同当成真相)。 ## 1. 现状 | # | 事实 | 位置 | | --- | --- | --- | | 1 | 交付轮渲染 `RectificationCandidateCards`:每个公开候选一张卡,显示"相对支持度 N"、"当前推荐"徽章、"采用此时间"按钮 | `rectification-agentic-chat.tsx` L180–215、L1699 | | 2 | 采用接口只接 `resultId + candidateId`,采用时已落库 `adopted_credible_range`(BUG-568) | `candidates/accept/route.ts` L14–18 | | 3 | 交付旁白 = 停止原因句 + 范围句 + 边界句 + `adoptCue` + 稳定/敏感两句(BUG-568)+ **三行"候选 A/B/C 预测下一次事业变动…"**(`withProspectiveWindows`) | `answer-choice.ts` L135–143;`adopt-narration.ts` | | 4 | 可供对比面板用的数据都已在回执里:`inference_state.probes[].style_options[].sign`(D9/D10 类型卡的选项对应星座)与 `candidate_ids` / `expected_outcomes`;`answered_probes`(已问过哪些);`window_scan.d9_sign_names / d10_sign_names / transitions`;`house_tables_by_time`;nakshatra 边界 `options[].traits` | 最近一次实测 Case JSON | | 5 | 类型表只有 D9、D10 两张(`D9_TYPE_TABLE` / `D10_TYPE_TABLE`);D24 等没有类型表 | `varga-type-tables.ts` L21、L96 | | 6 | Skill §9 写着"候选卡仍作 adopt 控件;正文要写候选窗、代表分钟、相对支持与方法层理由" | `SKILL.md` L119 | ## 2. 决策记录(产品负责人 2026-09-07 拍板;评审细节见本单 §0) 1. **交付轮只有一张卡**:`RectificationRangeDelivery`,上半"区间交付"、下半"分歧面板(可选)"。四张分钟卡、"相对支持度 N"、"当前推荐"徽章、"采用此时间"从用户界面删除(专业数字留在看盘板)。 2. **上半内容**(全部服务端投影,模型不写):范围(如 04:48–04:59)、代表分钟、共对照几件带年月经历、这段里稳定的主题与随分钟变的主题(复用 `range_reading`)、边界句"这只是代表性候选,不是已确认的唯一出生分钟"。 3. **分歧面板只在满足全部条件时出现**:剩余活跃候选簇 2~3 个;它们之间至少有一层 D9 或 D10 星座不同、且该层**没有被问过**(`answered_probes` 里没有对应 `varga.d9.*` / `varga.d10.*`);或 nakshatra 边界探针未问且 `near_boundary=true`。每列 = 一个候选簇,列头是簇的时间段("04:48–04:53 这段"),列内 1~3 行,每行"关系盘落在 X,通常表现为 …"(文案来自 `D9_TYPE_TABLE` / `D10_TYPE_TABLE` / nakshatra `traits`,不得由模型补写),末尾一列外的两个按钮"都不像 / 说不好"。**不列已经问过的层,也不列没有类型表的层(D24 等)。** 4. **动作只有两个**:"按这个范围用"(采用代表分钟,落库区间;面板里若选了某一列,则以该簇的代表分钟作为采用分钟)与"再补一件经历"(回到采集,不改任何状态)。选列不写证据账本、不进推断层、不改可信区间——它只决定排盘代表点。 5. 旁白:删除三行"候选 A/B/C 预测下一次事业变动…",改为一句"下一次事业变动的预测窗口留在采用后的核对阶段";或整段移到采用后 `postAdoptVerify` 的第一轮。停止原因句、范围句、稳定/敏感句、边界句保留。 6. Skill §9 那句改为"交付轮出一张区间交付卡;正文写候选窗、代表分钟、稳定/敏感主题与方法层理由,不写相对支持度",版本 bump 到 **10.0.15**,CHANGELOG 写明。 7. 采用接口新增 `mode: "range"` 语义:客户端传 `candidateId`(代表分钟或所选簇代表)+ `resultId`,服务端行为不变;不新造 RPC。 8. 看盘板(`rectification-board`)保留候选簇与支持度作为专业视图,不动。 ## 3. 硬红线 - 面板文案只能来自 `varga-type-tables.ts` 与 nakshatra `traits`,不得让模型生成"这个时间的解读"。 - 不得出现"概率 / 置信度 / 确定 / 相对支持度"字样(`agent-voice-copy-contract` 守卫)。 - 采用 RPC 校验不放宽;`adopted_credible_range` 落库逻辑不变。 - 已答过的层不得在面板里再问;面板条件不满足时必须只出上半卡。 - BUG-503/544/546/547/549/550/558/565~582 的用例原样通过;改断言写三栏。 - `page.tsx` 不增长;tsc 0 错;lint 0 error;测试总数 ≥ 开工实测。 ## 4. 任务分解 ### 4.1 服务端投影 `range_delivery` - 新模块 `v9/divergence-panel.ts`:输入 `inference_state`(活跃候选与簇范围)、`probes`、`answered_probes`、`window_scan`、`nakshatra_boundary`;输出 `{ columns: [{cluster_range, representative_candidate_id, rows: [{layer, sign, label}]}], eligible: boolean, reason }`。规则见决策 3。 - `case-service.ts` 快照与采用轮的 `latest_result` 投影加 `range_delivery = { range, representative_time, event_count, stable_themes, sensitive_themes, boundary, divergence }`;`rectification-candidate-result.ts` 解析。 - 验收:单测——(a) 两簇 D9 不同且未问 → 两列各一行 D9;(b) D9 已问、D10 未问 → 只列 D10;(c) 都问过 → `eligible=false`;(d) 四簇以上 → `eligible=false`;(e) 文案全部命中类型表。 ### 4.2 客户端 - 新组件 `rectification-range-delivery.tsx` 替换 `RectificationCandidateCards` 的渲染位;两个动作按钮;面板列可选中(单选),"都不像 / 说不好"清空选中;`acceptCandidate` 用所选簇代表或默认代表。移动端列改为纵向堆叠。 - 删除 `isRecommendedRectificationCandidate` 的 UI 使用(保留函数给看盘板);`DESIGN.md` 记录布局与等待态;`VOICE.md` 加文案。 - 验收:组件源扫描——不再渲染"相对支持度";`canShowRectificationSelectionCards` 语义不变(仍由 `ADOPT_OUTCOMES` 控制显示);`rectification-adopt-*.test.ts` 三栏。 ### 4.3 旁白与 Skill - `withProspectiveWindows` 从交付旁白移除(决策 5);`adopt-narration.ts` 旁白顺序:停止原因 → 范围 → 稳定/敏感 → 边界 → `adoptCue`。 - `SKILL.md` §9 改口径,版本 10.0.15;`skill-package-registry.json` 与 `docs/…` 同步;`agent-voice-copy-contract` 对新文案过守卫。 - 验收:`rectification-adopt-narration*.test.ts`——交付旁白不含"候选 A 预测";Skill 版本测试同步。 ### 4.4 记录 - `CHANGELOG.md`(用户可感知:交付改一张区间卡;Skill 10.0.15);`PROGRESS-rectification-range-delivery-card-20260907.md`;`docs/testing/rectification-scenarios-20260907.md` 加第 5 条"交付轮只见一张卡:范围、代表分钟、稳定/敏感主题;若有分歧面板,每列只有 1~3 行且都是没问过的层;点『按这个范围用』成功,设置页出生时间状态变为已采用"。 ## 5. 让步顺序 4.1 + 4.2 的上半卡 + 4.3 是底线(哪怕分歧面板先不做,也要先把四张分钟卡换掉);分歧面板其次;4.4 不可省。 ## 6. 开工前置命令 ```bash git fetch origin --prune git worktree add -b codex/rectification-range-delivery-card-20260907 .worktrees/rectification-range-delivery-card-20260907 origin/staging cd .worktrees/rectification-range-delivery-card-20260907 ln -s /workspace/Jyotisha/frontend/node_modules frontend/node_modules cd frontend && ls tests/rectification-*.test.ts tests/consultation-*.test.ts tests/agent-voice-copy-contract.test.ts | grep -v database | xargs npx tsx --test 2>&1 | grep -E "^# (tests|pass|fail)" grep -n "^version" ../skills/jyotish-birth-time-rectification/SKILL.md ``` ## 验收(Claude,2026-09-07,`origin/staging` @ `ab57d03f`) **未通过(P1 阻断)**:`frontend/src/components/rectification-agentic-chat.tsx` L1655 把 `dismissedRangeResultId !== candidateResult.resultId` 放在 `candidateResult &&` 判空之前,`tsc --noEmit` 报 `TS18047: 'candidateResult' is possibly 'null'`。硬红线 tsc 0 错不满足,`next build` 会失败,staging 门禁过不去。修法一行:把判空提到最前面。执行方进度记录写 tsc 0,不符。 其余各项(在修掉这一行之后可视为通过): | 项 | 结论 | | --- | --- | | 4.1 投影 `range_delivery` | 通过。`divergence-panel.ts`:活跃簇 2~3、只列未问的 D9/D10/月宿层,星座先从探针选项取、再从换升表推,文案只取 `D9_TYPE_TABLE` / `D10_TYPE_TABLE` 的 `userChoice` 与 nakshatra `traits`;代表 id 用公开 UUID | | 4.2 组件 | 通过。四张分钟卡、相对支持度、当前推荐徽章全部删除;两个动作;列单选,"都不像 / 说不好"清空 | | 4.3 旁白与 Skill | 通过。三行预测窗口删除;Skill §9 改口径、10.0.15 快照与 live 一致、五份 references 与 10.0.14 逐字相同(没有新写方法学);注册表新条目 `sourceCommit: null` 与历史条目一致 | | 4.4 记录 | 通过;手测场景第 5 条已加 | | P2 | 旁白改成"下一次事业变动的预测窗口留在采用后的核对阶段",但采用后没有任何地方再展示预测窗口(`prospectiveWindowsNarration` 已无调用点)——这是一句兑现不了的承诺,与之前"说一声我来汇总"同类。要么在采用后核对首轮真的接上,要么把这句删掉 | | P3 | "再补一件经历"只在本地隐藏卡片,不给用户任何提示该说什么;建议隐藏后由步骤条/旁白给一句采集提示 | | P3 | lint warning 从 84 涨到 103 | 修复单:`TASK-rectification-range-delivery-fix-20260907.md`。