docs(tasks): 校正出卡加精度门槛 + 引导式补经历任务书

产品 2026-09-16 拍板:宽度 ≤10 分钟且不并列才出卡;用户说没有了仍按现行规则出卡;
门槛未达改为系统点名逐题问 + 年/月选择器录入,删自由文本邀请;跳过的线换问法再问一次;
时间点题答没发生不关领域、存在性题问整个领域、七条线一张表不按领域写死。

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JUei7K13cYxLHE3Axe4A45
This commit is contained in:
Jesse_Chen
2026-09-16 08:50:35 +00:00
co-authored by Claude Fable 5.1
parent 071317f7ee
commit 20435a1916
2 changed files with 178 additions and 0 deletions
+1
View File
@@ -251,6 +251,7 @@
| `TASK-home-state-lowering-batch2-20260916.md` | — | **状态下沉第二批(纯前端,与另两单可并行)**:第一批 `f8e607c2` 已验收(useState 66→52、useRef 41→39、散装 `rectification*` 归零、全量套件两侧完全相同)。本单照同一套做法搬剩下三簇:`session*` **10** 个(`useSessionManagement` 仍要解构约 40 个参数)、`profile*` **6** 个、`synastry*` **4** 个(无 hook,散在 `Home()`),目标 useState 52 → **≤36**。另修第一批留下的尾巴:`createRectificationShellSetters` 在 render 体里无记忆化 → 每帧新身份 → 多一条 `exhaustive-deps` warning119→**120**),**正解是稳住 setter 身份、不是塞进 deps**(塞进去会每帧重拉入口摘要),本单要把 warning 降回 119。零行为变化;先分类再动手。不占 BUG 号 | 待领取 | — |
| `TASK-api-server-backdoor-close-20260916.md` | — | **取代 decomposition 单的阶段 1** · **第二版(2026-09-16 改写)**:第一版的「8 方法 / 314 行」**错了一个数量级**——闭包只跟了 `self._x()`,漏掉 `_compute_consultation_workflow` 那 6 行委托转给模块级 `execute_consultation_workflow(self, ...)` 的一跳。执行方重算实测 **115 方法 / 4,104 行(占全类 51% 方法),但碰 HTTP 上下文的仍是 0 个**。产品在 A/B/C 中**选定 B(mixin 抽取)**:方法体原样搬进 `ConsultationComputeMixin``JyotishAPIHandler(BaseHTTPRequestHandler, Mixin)` 靠 MRO 解析,离线调用方直接实例化 mixin——四个伪造点全关。**产品同时授权:§4 那条「不得搬 ≥150 行业务方法」按本意解释(本意是防逐行改写的 C 案),mixin 放行。** 必须先过 **spike 闸门**:搬完后 `test_api_server_security.py` 一字不改直接跑,绿则继续、红则退回 A(只搬 7 方法/300 行、关 2 个伪造点)。真风险是循环 import——闭包引用同文件 44 个模块级函数 + 21 个常量。`__new__` 归零只针对 scripts 侧 4→0tests 侧 29 处含不许改的 security 测试,保持不增长)。阶段 3 仍不做。不占 BUG 号 | **已执行(spike 红 → 退回 A** | spike 实测:整体 mixin 化后 `test_api_server_security.py` **1 failed / 128 passed**——`test_chart_async_job_executes_in_background` 挂在 `monkeypatch.setattr(jyotish_api_server, '_write_async_job_record', ...)`:调用方法随 mixin 搬走后从新模块 globals 解析,补丁落在旧模块上不生效(已证明把同一 fake 打到 mixin 模块即恢复原行为,非搬坏)。循环 import 不是障碍(移动集不引用 `JyotishAPIHandler`)。按 §6.3 退回 A`scripts/offline_compute_mixins.py` 收 7 方法 / 300 行 + 3 助手 + `BadRequest`,关掉 `consultation_workflow_service:27` 与 `local_accuracy_report:141` 两处伪造,scripts 侧 `__new__` **4 → 2**;类方法 225 → 218、行数 11,291 → 10,924security 测试一字未改 **129 passed**。剩余 2 处伪造都在咨询工作流链上,需另案解决 monkeypatch 落点问题 |
| `RECONCILE-20260916.md` | — | **对账清单(不是任务书)**:状态板与现实脱节(09-15~16 那 10 份早已合入却仍写「待领取/待验收」,本轮已修正),所以另外 7 份 09-10~14 的单**不能拿 README 当证据**——它们没有 `PROGRESS-*.md`,但引用的 BUG 号都是 `resolved`。要么被别的单顺带修了没留记录,要么压根没做。每行回一个「做了/没做」即可。另附三条我已查到确定没做的证据、两条状态未闭环的、以及 BLK-001 仍红(2026-09-16 在 `4f643aa0` 复跑确认) | 待产品负责人 / 执行方回填 | — |
| `TASK-rectification-precision-gate-guided-collect-20260916.md` | — | **出卡加精度门槛 + 引导式补经历**:真机 30 分钟窗给 5 件事 / 3 领域就出卡,区间 20 分钟、5 候选并列 26/26/20%,卡下只有自由文本邀请。产品拍板 D1 出卡门槛「宽度 ≤10 分钟且前两名差 >3 个百分点且不并列」;D2 用户说没有了仍按现行规则出卡(保留永远给结果);D3 门槛未达改为系统点名逐题问 + 类型芯片 + 年/月选择器录入,删自由文本邀请;D4 跳过的线换问法再问一次(拒绝不重问,改 BUG-687 口径);D5 时间点题答「没发生」不关领域、存在性题问整个领域、七条线一张表不许按领域写死。引擎新增 `guided_collect_windows`(边界不设 45 天闸门、含小运),不改打分与 lead。Skill 10.0.27。附 T6 两条核实:B/C/D 回执文案对调、性格题后范围回弹 8 分钟。BUG 段 740 起 | 待领取 | 与 BUG-661663 / 626~634 诸单同文件,本单优先;开工先核对它们是否已合入 |
## 命名与归档
@@ -0,0 +1,177 @@
# 任务书 · 出卡加精度门槛 + 引导式补经历(2026-09-16
## 0. 基线
- 基线:`origin/staging` @ `071317f7`staging 部署 `7061d0d1`(含 BUG-689 邀请语)。
- 分支:`codex/rectification-precision-gate-guided-collect-20260916`worktree `.worktrees/rectification-precision-gate-guided-collect-20260916`
- 校正 Skill 当前 `10.0.26``skills/jyotish-birth-time-rectification/SKILL.md`)。本单要 bump 到 `10.0.27`
- 与本单同文件的待执行单:`TASK-rectification-collection-redesign-v2`BUG-661663`da048676`)、BUG-626/627/628、631/632、633/634。**若那些单仍未领取,本单优先;执行方开工前 `git log origin/staging` 核对它们是否已合入,已合入的以 staging 为准 rebase,不得回退它们。**
## 1. 事故实证(2026-09-16 真机,脱敏)
30 分钟搜索窗,用户给了 5 件带年月的事、3 个领域(学业、事业、居所),其中 3 件落在同一年 6 个月内(同一段大运,等于 1 件证据)。家人、婚恋、收入三条线全部关闭。6 道带年月点选题 + 1 道性格题答完后,流程直接出交付卡:
| 项目 | 数值 |
| --- | ---: |
| 交付区间宽度 | 20 分钟 |
| 区间内候选 | 5 |
| 前三名相对可能性 | 26% / 26% / 20% |
| 5 件经历对每个候选的吻合 | 5/5(零区分) |
卡下是 BUG-689 的自由文本邀请:「你要是还记得确切哪一天的事,不限领域,说出来我接着算」。产品负责人反馈:**精度没达到要求就出卡了;之后也不该让用户随便打字,要引导用户填。**
代码定位(行号按符号):
1. `frontend/src/lib/rectification-agentic/core/rectification-decision.ts` `decideRectification`:分支 `stopClass.kind === "exhausted" && stopClass.reason === "tied_first" && !probe && input.targetedCollectExhausted !== false` 直接 `deliverRange(..., "exhausted")`。**没有任何宽度或领先度条件**。`classifyStop``tied_first` 来自 `candidate-separation.ts``tiedForFirst = top.score === runnerUp.score``stillNeedNarrowing` 只看 `refreshExhausted` / `targetedCollectExhausted`
2. `core/credible-range.ts` `unionStillValidRange`:区间 = 落后头名不足 `MIN_SEPARATION_LEAD = 8` 分的簇并集。区间宽度从未参与出卡判断。
3. `v9/collection-question-pool.ts` `targetedDomainClosed` / `remainingTargetedDomains``declined``skipped` 同样永久关闭该线;`targetedCollectExhausted` 只看这个池是否为空。池空 → `rangeNarrowHint` 落到 `user-copy.ts` `rangeDeliveryCollectClosed`(自由文本邀请)。
4. `v9/answer-choice.ts` `isTargetedCollectExistenceSchema` 分支:B「没有发生过」→ `declined`;C「记不太清楚」/ D「这条先跳过」→ `skipped``choice-card.ts` 给 D 的 answer class 是 `weak_yes`)。`targetedCollectExistenceAck``declined` 回「记下了,这方面先跳过」,`skipped` 回「记下了,这题先放着」。**文案与语义对调**:答「没有发生过」的用户看到的是「先跳过」。这次真机三条线的回执都是「这方面先跳过」,按代码等于用户点的是 B;若用户点的其实是 D,则是落库错位,执行方按 T6 核实。
5. `scripts/rectification/event_probes.py` `_boundary_windows` / `_union_boundary_dates`:候选间大运边界差 `< MIN_BOUNDARY_DAYS = 45` 天不出题。窗口收到 20 分钟时边界位移约 22 天,**自动点选题池必然为空**,这是「问完了」的算术原因(`docs/tasks/PROGRESS-rectification-precision-gate-research-20260914.md` 已量过:放宽这个闸门对自动是非题无收益,本单不动它)。
6. 未定性观察:性格题(只做 ±1 排序微调、不淘汰)答完后,范围从 20 分钟弹到 28 分钟,下一题又缩回。疑似某簇卡在 `lead = 8` 边界,被 ±1 推过线。见 T6。
7. **时间点题答「没发生」之后整个领域被关掉**(产品负责人补充的实证):先问「某年某月前后,有没有开始一段认真关系、分手或结婚」,用户答「明确没有发生」(那个时间点确实没有);随后定向线问的是 `TARGETED_EXISTENCE_PROMPT.relationship = "结过婚或订过婚吗?"`,用户如实答「没有发生过」→ `declined` → 该领域永久关闭。用户在**别的时间**有过认真关系,从头到尾没被问到。同一张表里其余六条线同样是「领域名 + 两个例子」缩成一句是非题:`family` 只问「添丁或长辈住院」、`finance` 只问「收入变过或大笔进出」,答「没有」就等于整个领域没有。另外 `remainingTargetedDomains(layers, …)` 只从 `remainingLayers`(分盘上还能切开候选的层)映射领域,某层切不开候选时,那条线根本不问;但事件按大运时点计分与分盘层无关,这条限制没有依据。
## 2. 根因
- 出口条件里没有精度项:七条线关闭 + 自动题池空 + 头名并列 = 出卡,宽度多少都出。
- 自动题池空之后没有第二个**有方向**的题源;剩下的只有一句让用户自由发挥的邀请。
- 「跳过」和「没有发生过」在数据层同义,用户想先放一放的线再也回不来。
- 定向线的是非题只覆盖领域里的一两个例子,却按整个领域记「没有」;时间点题的「没发生」也没有接一句「那别的时间有没有」。领域被关掉的不是用户的经历,是题干。
研究定论(`docs/research/rectification_minute_resolution_closure_2026_09_14.md`):调打分拉不开区间内并列,**唯一被证明有效的信息源是新的带年月经历**。所以本单只改出口条件和采集方式,不改打分。
## 3. 决策记录(产品负责人 2026-09-16 拍板)
| # | 决策 | 推翻 / 修改的既有口径 |
| --- | --- | --- |
| D1 | **出卡门槛**:交付区间宽度 ≤ 10 分钟,且头名比第二名的相对可能性至少多 3 个百分点(`RANGE_DELIVERY_TIE_PERCENT`)、`tiedForFirst = false`。三项同时满足才出交付卡。 | 现行「七条线关 + 题池空即出卡」 |
| D2 | **用户确实补不出来时**(明确说「没有了 / 就这些」,或引导题源也空了):**按现在的规则出卡**,卡片、采用按钮、三句正文都不变。不加「未达门槛」标注。 | 保留 09-10「永远给结果」 |
| D3 | **引导式补经历**:门槛未达时,系统点名逐题问,一次只问一件,题目指定「哪几年几月之间、哪一类事」。用户用**类型选项 + 年 / 月选择器(日可选)**录入,不再出现自由文本邀请句。输入框不禁用(BUG-551),用户打字仍然照记,但系统不再主动邀请打字。 | BUG-689 的自由文本邀请(卡上那句删除) |
| D4 | **跳过的线再问一次**:答「记不太清楚」或「这条先跳过」的线,在引导阶段换一种更具体的问法再问一次;再次跳过才永久关闭。答「没有发生过」的线不再问。 | Skill §流程「用户已拒绝或跳过的目标不得换词重问」改为只限「拒绝 / 没有发生过」;BUG-687 防复发条改为「不得再列已答没有发生过的线」 |
| D5 | **时间点的「没发生」不等于领域没有**(产品负责人会话中补充):某年某月的是非题答「明确没有发生」只关闭那个时间点,领域保持开放;领域的存在性问题必须问整个领域(任何时间、该领域全部事件类型),「没有发生过」的选项文案要写成「这类事都没有过」。**规则对七条线用同一张表驱动,不得因为这次是感情线就只改感情线,也不得给任何单个领域写死特殊流程。** | 现行「时间点题 + 窄题干答没有 = 领域关闭」;`remainingTargetedDomains` 只问分盘层还能切开候选的领域 |
不改的:打分尺度、`MIN_SEPARATION_LEAD = 8`、自动是非题的 45 天闸门、`MIN_ACCEPTANCE_DOMAINS = 2`、记录优先(BUG-691)、性格题 ±1 只排序不淘汰、「不用生日推年份」。
## 4. 硬红线
1. 不得为了让门槛更容易达到而改打分、改 lead、改簇合并;门槛只是出口条件。
2. 引导题的年份、月份区间必须来自引擎的候选边界,不得由模型或前端发明;不得用生日推年份(BUG-648)。
3. 引导问法不得列已答「没有发生过」的线(BUG-687 改后的口径);跳过的线最多再问一次。
4. 引导录入的证据必须走现有带年月证据路径(同 `batch` / `set-focus` 落库、改账本指纹、快照过期重算),不得另开一条评分旁路。
5. 用户说「没有了 / 就这些」立即出卡,不得追问第二遍(D2)。
6. 不得在同一回复里一边要引导题一边给采用按钮(Skill 既有红线)。
7. `page.tsx` 不增长;新组件进 `frontend/src/components/`,新逻辑进 `lib/rectification-agentic/`
8. Skill bump 后必须验证历史校正会话仍能打开(BUG-621 教训)。
9. 不得把研究里的离线命中率写成线上承诺;用户文案不得承诺「再补几件就能定到分钟」。
10. **七条线一张表**:题干、例子、重问句、录入芯片都从 `CollectKind` 的表里取;决策逻辑里不得出现 `if (domain === "relationship")` 这类按领域分叉。时间点题的负答案对任何领域都不关闭领域。
## 5. 任务分解
### T1 出卡门槛(前端决策层 + 策略常量)
- `references/rectification_policy.v1.json``deliveryMaxWidthMinutes: 10``scripts/rectification_policy.py` 与 TS 侧各读一次,常量只定义在这一个文件里。
- `decideFromDossier` 计算 `precisionGateMet``credible_range` 宽度 ≤ 10 且交付列前两名 `probability_percent` 差 > 3 且 `!separation.tiedForFirst`
- `decideRectification``tied_first` 耗尽分支、`!separation.sufficient` 的耗尽 / offer 分支、`stopClass.kind === "exhausted"` 分支,都加同一条判断:`precisionGateMet || input.userStopped || input.guidedCollectExhausted``deliverRange`;否则 `collect(...)` 并带上 T3 的引导题。`user_uncertainty_too_high` 分支保持原样(那是用户不配合的止损)。
- `withholdAdoptOnUnnarrowedRange``waitToNarrowCapability` 不动。
- 验收:
- 单测:20 分钟 / 5 候选并列 → `collect` + 引导题,`canOfferRange = false`8 分钟 / 前两名差 5 → `deliverRange`8 分钟并列 → `collect`;门槛未达但 `guidedCollectExhausted = true` → 现行交付卡(含采用);`userStopped` → 现行交付卡。
- 既有测试改断言的,写「原值 / 新值 / 原因」三栏。
### T2 引导题源(后端,`scripts/rectification/event_probes.py`,新函数不改旧函数)
- 新增 `guided_collect_windows(request, built, *, candidate_times, today)`:复用 `_representative_pairs` + `_union_boundary_dates`,参数 `min_boundary_days = 0``include_pratyantar = True``varga_narayana = True`,得到剩余候选之间大运 / 中运 / 小运边界不一致的日期。每个窗口输出 `{year, month_lo, month_hi, domain, split: {left: n, right: n}}`
- `month_lo` / `month_hi` 为该边界在所有剩余候选上的最早与最晚月份(跨年拆两条);
- `domain``_probe_domains` 的层序取该层对应领域,且剔除用户已答「没有发生过」的领域(请求里带 `declined_domains`);
- `split` 是把剩余候选按边界前 / 后分成两组的人数,**按两组越接近一半越靠前**排序,其次按年份靠近今天;上限 6 条。
- 挂进 `refinement_packet.py` / `decision_policy.py` / `api_service.py` 的 packet,键名 `guided_collect_windows`,与 `discriminating_event_probes` 并列;自动题池非空时该列表可以为空(自动题优先)。
- 不改 `MIN_BOUNDARY_DAYS`、不改 `_discriminating_event_probe_lists`
- 验收:
- `tests/test_event_probes_guided_windows.py`(新):golden 用真实引擎输出(不得手造);20 分钟窗至少产出 1 条窗口;`declined_domains` 被剔除;排序按 split 均衡;跨年拆分正确。
-`references/real_case_calibration/minute_rectification_holdout_v4.json` 离线回放:每例在六题后按 `guided_collect_windows` 顺序注入真值方向的带年月事件,记录**达到 D1 门槛所需件数**的中位数与 20 例中达标数(三档半径)。这组数字进进度记录,**不是合入门槛**,但必须报出来,产品据此决定门槛是否要调。
- `.venv/bin/python -m pytest tests/test_event_probes*.py tests/test_candidate_discriminator_contract.py tests/test_rectification_refresh_r3_r4.py` 全绿;快速门 quick 与基线逐条一致。
### T3 引导问法与选择器录入(前端)
- `collection-question-pool.ts` 新题型 `guided`,排在自动题之后、定向七条线之前:
1. **边界窗口题**(来自 T2):题干「YYYY 年 M 到 M 月之间,有没有<领域口语>?」,领域口语沿用 `USER_COLLECT_QUESTION` 的短语,不得复述服务器标签。选项:A「有,我来填时间」/ B「这段没有」/ C「记不清」。B、C 只关闭这一条窗口,不关闭领域。
2. **跳过线重问**T4)。
3. **未覆盖领域的开放时间题**(含时间点题答「没发生」后的领域,T4b):七条线里尚无带年月证据、也没答过「这类事都没有过」的领域,问「<领域全称问法>,哪一年都算」,选项同上。
- A 之后出**录入卡**:类型芯片(沿用七条线的 `CollectKind`,默认选中题目的领域,可改)+ 年 / 月选择器(日可选)。新组件 `frontend/src/components/event-date-picker.tsx`,复用 `birth-date-picker.tsx``Calendar` / `Popover`,但以月为粒度、日可留空;年份范围出生年到今年。提交 → 走现有带年月证据落库路径(与 `TARGETED_YEAR_PROMPT` 答案落库同一条:`collect_kind` + 年月)→ 改账本指纹 → 快照过期 → 重算。
- `rangeNarrowHint`:门槛未达时**不再拼** `rangeDeliveryCollectClosed`;卡下提示改为「现在还剩 HH:MM–HH:MM 里 N 个候选,再对照几件经历会更准」。门槛已达或 D2 出卡时,卡片与现在完全一样(`rangeDeliveryShowsOpenCollectInvite` 那条自由文本邀请一并删除,`RANGE_DELIVERY_OPEN_COLLECT_*` 常量删掉,不留死代码)。
- 用户说「没有了 / 就这些 / 想不起来了」:由现有分类器判为 `userStopped`(不靠正则,BUG-641~643 口径)→ D2 出卡。
- 常驻区间条(`ca020498` 加的代表分钟与已答题数)加一段「已对照 N 件」即可,不加进度条、不写「还差几件」(`COLLECT_FLOW_BANNED_PHRASES` 照旧)。
- 验收:
- `tsc --noEmit` 0 错;`npm run lint` 0 error`npm test` fail 数与基线逐条一致(无 Docker 的 27 条照旧)。
- 新测试:引导题排序(自动题 > 边界窗口 > 跳过重问 > 未覆盖领域);A 后出录入卡;录入卡提交后证据落库、指纹变化、`snapshotCurrent = false`;B / C 只关窗口不关领域;门槛未达时 hint 不含邀请句、不含 `RANGE_DELIVERY_OPEN_COLLECT_*` 任何例子。
- 合同测试 fixture 来自真实引擎响应(golden)。
- `next build``/` 仍 Static;首屏 gzip ±2%(选择器组件按需加载,不进首屏)。
- `frontend/DESIGN.md` 增录入卡与选择器条目;文案对照 `frontend/docs/VOICE.md`
### T4 跳过的线再问一次
- `targetedDomainClosed``declined` 永久关闭;`skipped` 且尚无 `retry` 标记的线**不算关闭**,进 T3 第 2 类题源,题干用 `TARGETED_EXISTENCE_PROMPT_RETRY[domain]`(新表,每条比第一次更具体,例如家人线改问「父母或祖辈有没有住过院、做过手术,或者家里添过小孩」);重问后再答 C / D → 写 `retry: true` 并永久关闭。
- 修文案:B「没有发生过」回「记下了,这条按没有发生过记」;C / D 回「记下了,这题先放着,后面换个问法再问一次」。两句先过 VOICE。
### T4b 领域存在性问题问整个领域(D5,七条线同一张表)
- `TARGETED_EXISTENCE_PROMPT` 重写为「领域 + 全部事件类型 + 任何时间」的问法,例如感情线「感情上有没有过开始一段认真关系、分手、订婚或结婚,哪一年都算?」;七条线都按这个格式改,表驱动,不许某条线特殊。B 选项文案改为「这类事都没有过」,`TARGETED_COLLECT_OPTION_B` 一处改全局生效。
- **时间点题(`source = event_probe` 的年月是非题)答「明确没有发生」不得写入任何会让 `targetedDomainClosed` / `declinedKinds` / `coveredCollectKinds` 判定领域关闭的状态**;它只是那一个探针的答案。若该领域尚无带年月证据,引导阶段紧接着出该领域的开放时间题(T3 第 3 类),最多一次。
- `remainingTargetedDomains` 不再以 `remainingLayers` 过滤:七个 `CollectKind``COLLECT_KIND_ORDER` 全部轮到,只剔除 `declined` 与已覆盖的。`remainingLayers` 仍可用于排序(能切开候选的层先问),不能用于剔除。
- 验收:单测「时间点题答 C → 领域仍在引导池」「窄题干旧文案不再出现(`agent-voice-copy-contract` 断言七条新题干)」「某层切不开候选时该领域仍被问到」;测试用表遍历七个领域,不许只测感情线。
- Skill 与 BUG-687 防复发条按 §3 D4 改写。
- 验收:单测覆盖「skipped 一次 → 重问 → 再 skipped → 关闭」「declined → 不重问」;`agent-voice-copy-contract` 跟上;`docs/BUG_HISTORY.md` BUG-687 条目补「2026-09-16 产品修改防复发口径」并链接本单。
### T5 Skill 10.0.27
- `skills/jyotish-birth-time-rectification/SKILL.md`
- §流程那段(「带年月池空时先按剩余候选刷新一批…所有线问完或用户说没有了后才交付」)改为:自动题池空 → 按 `guided_collect_windows` 逐条问 → 跳过线重问 → 未覆盖领域;**出卡须 `precision_gate_met = true` 或用户说没有了**;引导题用选项 + 选择器录入,不得邀请自由打字。
- 「已拒绝或跳过的目标不得换词重问」改为「已拒绝(没有发生过)的不得重问;跳过的按服务器计划最多重问一次」。
- 出牌三句正文不变。
- bump `version: 10.0.27`,复制到 `versions/10.0.27/`,更新 `skills/skill-package-registry.json``CHANGELOG.md` 写明 bump。
- 验收:Skill 合同测试绿;**历史校正会话能打开**(`open` RPC 与版本绑定的既有测试 + 手工清单一条)。
### T6 顺带核实(不阻塞 T1~T5 合入)
- **回执文案对调**(§1 第 4 条):确认 B / C / D 三个选项各自落什么状态、回什么话;若 D 落成 `declined`,是 BUG;若只是文案对调,随 T4 修并记 BUG。
- **性格题后范围回弹**(§1 第 6 条):查 `varga_style` 的 ±1 是否写进 `posterior_score` 并进入 `unionStillValidRange`。若是,区间并集改用不含风格微调的分数(风格题只影响排序,本就不该改范围)。能复现写 `resolved` 并附回归测试;不能复现写 `investigating`,附已排除的路径。
- 两条各占一个 BUG 号。
### T7 记录
- `docs/BUG_HISTORY.md`:出卡无精度门槛(1 条)、自由文本邀请无方向(可并入前一条)、跳过与拒绝同义(1 条)、T6 两条。编号从 **BUG-740** 起,开工时核对最大号。
- `CHANGELOG.md``frontend/DESIGN.md``frontend/docs/VOICE.md`(新句)、`docs/testing/rectification-guided-collect-20260916.md`(真机清单:门槛未达不出卡、引导题带年月区间、选择器录入后范围变化、说「没有了」出卡、跳过线重问一次、历史会话可开)。
- `docs/tasks/README.md` 状态板那一行随合入一起改。
## 6. 让步顺序
1. T2 的 `include_pratyantar = True` 若单次重算超过 `JYOTISH_HEAVY_COMPUTE` 现有预算(进度记录里给毫秒数),先只用大运 + 中运边界,小运留 BLOCKED。
2. T3 选择器若让首屏 gzip 超 ±2% 且按需加载解决不了,退成「系统点名的题 + 年月文本框(只收 YYYY-MM)」,仍然不出自由文本邀请。
3. T2 的离线回放若超过 3 小时,只跑 ±10 与 ±30 两档,±60 写未测。
4. T6 可留 `investigating`,不得为了收口编根因。
5. 不得让步的:D1 三个条件、D2 立即出卡、D4 跳过只重问一次、Skill bump。
## 7. 开工前置命令
```bash
git fetch origin --prune
git status -sb # 确认不在别人的分支上
git worktree add -b codex/rectification-precision-gate-guided-collect-20260916 \
.worktrees/rectification-precision-gate-guided-collect-20260916 origin/staging
grep -o "^## BUG-[0-9]*" docs/BUG_HISTORY.md | sort -t- -k2 -n | tail -1 # 应为 BUG-739
grep -n "分不开\|跳过" skills/jyotish-birth-time-rectification/SKILL.md | head
cd frontend && ./node_modules/.bin/tsc --noEmit && npm run lint && npm test 2>&1 | tail -5 # 记基线失败清单
cd .. && .venv/bin/python -m pytest tests/test_event_probes*.py tests/test_candidate_discriminator_contract.py -q
```
Bug 检索(§5 硬约束):`BUG-687``BUG-689``BUG-646``648``BUG-651``BUG-653``BUG-654``BUG-621``BUG-641``643``BUG-594``BUG-623`,全部读完再动手。
## 8. 验收口径(Claude 事后逐条)
- T1~T5 每条验收标准通过 / 未通过 / 环境缺口三选一。
- 前端:tsc 0 错、lint 0 error、测试失败清单与基线逐条一致、`/` Static、gzip ±2%。
- Python:定向测试全绿、quick 门与基线一致。
- 部署:`/api/health``deployment.gitCommit` = 本单最后一次含门禁路径的 staging 提交;staging 若需迁移先 Migrate。
- 真机清单交产品负责人。
## 9. BUG 编号起点
**BUG-740**(基线最大 BUG-739)。开工时重新核对。