Files
Jyotisha/docs/tasks/TASK-rectification-declared-uncertainty-20260907.md
T

84 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TASK · 出生时间"有多确定"只问一次:intake 三档、校正读档案里的偏移、吻合率低时一键放宽并写回(2026-09-07)
- 基线:`origin/staging` @ `5c644f92`(代码头 `517df002`,含 BUG-565570
- 分支:`codex/rectification-declared-uncertainty-20260907`
- 执行方:coding agent;验收:Claude
- 涉及文件:`frontend/src/lib/birth-time-intake-model.ts``frontend/src/components/birth-time-intake.tsx``frontend/src/lib/account-profile-patch.ts``frontend/src/lib/rectification-agentic/v9/case-service.ts``decision-from-dossier.ts``core/rectification-decision.ts``method-followup.ts``answer-choice.ts``block-scan-answer.ts`(重算函数泛化)、`tool-service.ts``frontend/supabase/migrations/`(新 RPC)、`frontend/src/lib/rectification-agentic/user-copy.ts`
- 不改:Python 引擎、探针契约 `contracts/probe-question-v1.json`、采用/确认门、`page.tsx``jyotish_api_server.py`
- BUG 编号起点:**BUG-571**(开工时 `grep -o "^## BUG-5[0-9][0-9]" docs/BUG_HISTORY.md | tail -1` 复核)
- 串行:在 `TASK-rectification-capability-fix-20260907.md`(已合入)之后;与其他校正单无并行
## 0. 为什么做这件事
产品负责人 2026-09-07 拍板:出生时间"有多确定"在初始化出生资料时问一次、存进档案,校正每次直接读,不再问;校正过程中只在证据说窗口选错时,由系统出一键卡提议放宽,并把新偏移写回档案。对照上游 yinduzhanxing:它保留用户给的区间,且方法 1 规定吻合率 <60% 要调 ±1~2 小时重验;我们现在两件都没做。
## 1. 现状实证
| # | 事实 | 位置 |
| --- | --- | --- |
| 1 | intake 只露出两个来源:"我知道准确出生时间"(`family_exact`,±0)和"我不确定准确时间"(`period_only` 自选起止 / `unknown`)。模型与校验里早有 `approximate`(±15/30/60)和 `hospital_record`(固定 ±2),但单选框 `birthTimeSourceOptions` 只有两项,用户选不到 | `birth-time-intake-model.ts` L9194、L96140`account-profile-patch.ts` L126145 |
| 2 | 校正开 Case:只要档案有钟点,一律 `reportedTime ± 15``FRESH_CASE_SEARCH_RADIUS_MINUTES`),注释写明"引擎执行边界,不是用户声明的不确定度";档案里的 `uncertainty_before/after` 被读进 baseline 但不参与窗口 | `case-service.ts` L131146 |
| 3 | 引擎每次重算都产出 `event_fit_rate`matched / total / percent / band:≥80 high、6080 medium、<60 low),TS 已解析,但只用在采用后的八法报告里;没有"吻合低 → 窗口可能错 → 放宽"的动作 | `refinement_packet.py::event_fit_rate``refinement-packet.ts` L761`skill-verification-report.ts` |
| 4 | 设置弹窗的星盘资料复用 `BirthTimeIntakeFields`,所以 intake 改了设置页自动同步 | `profile-fields.tsx` L3 |
| 5 | 改窗口的 RPC 只有 `advance_agentic_rectification_case_from_block_scan`,要求 `stage=block_scan`;分钟阶段没有放宽窗口的入口。`candidateRangeFingerprint` 含起止,窗口一变快照自动失配触发重算 | `20260906030000_rectification_block_scan_stage.sql` L132182`tool-service.ts` L619 |
| 6 | 既有测试把填报 05:00 → 04:4505:15 写死了三处 | `rectification-v9-case-service.test.ts` L83、L136、L428 |
## 2. 决策记录(产品负责人 2026-09-07 拍板)
1. **只在 intake 问一次**,用"你对这个时间有多确定"来问,不用"偏移 / 误差"字眼。三档:
- 「有出生证或医院记录,精确到分钟」→ `hospital_record`(校验仍固定 ±2 作无感检查)
- 「家人记得大概时间」→ `approximate` + 一排按钮「差不多准 / 前后半小时 / 前后一小时 / 前后两小时」= ±15 / 30 / 60 / 120(校验从 {15,30,60} 扩到 {15,30,60,120}
- 「只知道大概时段,或完全不知道」→ 现有 `period_only` / `unknown` 分支不动
`family_exact` 不再出现在新用户选项里,存量档案仍合法,语义等同"差不多准"(±15)。
2. **校正窗口读档案。** 有钟点时:`hospital_record` / `family_exact` → ±15(引擎边界,记录常按 5 或 15 分钟取整);`approximate` → ±max(15, 声明值),最大 ±120(241 分钟,引擎实测 4 小时 3 秒,仍走分钟阶段,不进时段扫描)。`period_only` / `unknown` 逻辑不变。
3. **校正中唯一碰这个值的时机是证据说窗口错了**:训练门已开、`event_fit_rate.band = low``total ≥ 3`、代表分钟落在窗口边缘 3 分钟内、`stage=minute`、未采用、有钟点、本证据指纹下没拒过。满足即出**服务端一键卡**(不是模型问句):"按你说的经历,出生时间可能比家人记的偏得更多。放宽后再比一次?" A「放宽到前后 {下一档}」 B「放宽到前后 {再下一档}」 C「不放宽,按现在的范围继续」 D「说不好」。A/B 改窗口、重算、并把新偏移写回档案(来源改为 `approximate`);C/D 记 `declined_at_fingerprint`,同一批证据不再问。已是 ±120 的不出卡。
4. 放宽卡优先级高于区分卡:窗口都可能错的时候,先别在错窗口里出题。
5. 放宽不写证据账本、不进推断层;已答探针按 `semantic_key` 在新候选集上重放(`buildInferenceState` 现有行为),测试锁定。
6. 不动采用门、确认门、`MIN_SEPARATION_LEAD``_relative_support`;不动 `adopted_credible_range`(那是采用后的产物)。
## 3. 硬红线
- `approximate` 校验扩到 120 只在 `account-profile-patch.ts``isBirthTimeDraftReady` 两处同改;`hospital_record` 固定 ±2 不改。
- 放宽只能扩大且必须包含旧窗口;新窗口 ≤ 241 分钟;只在 `stage=minute` 允许;RPC 内校验,不信客户端。
- 放宽后 `candidate_range` 改写是**合法的**(这是搜索窗口,不是采用产物);但 `adopted_credible_range` 不得被动。
- 既有 04:4505:15 断言只对 `family_exact` / `hospital_record` 保留;`approximate` 用例另写,三栏说明。
- 文案对照 `frontend/docs/VOICE.md`;不得出现"偏移 / 误差 / 置信度 / 概率";一键卡四选项契约与其他卡一致(TS 内部 `choice_kind: "widen_window"`,不进 Python 契约,比照 `block_choice`)。
- 迁移需 Docker `test:db`;无 Docker 写 `BLOCKED.md`
- 测试总数 ≥ 1521(口径同 BUG-569 验收);tsc 0 错;lint 0 error。
## 4. 任务分解
### D1 intake 三档
- `birthTimeSourceOptions` 改三项(决策 1),`approximate` 分支渲染四个按钮写 `uncertaintyBefore/After``hospital_record` 保留"无感检查前后 2 分钟"说明;`family_exact` 从选项移除、读档时映射为"差不多准"显示。
- 校验:`isBirthTimeDraftReady``account-profile-patch.ts` 的 approximate 集合 → {15,30,60,120};错误文案同步。
- 验收:`birth-time-intake.test.ts` 新增三档渲染与 120 校验;`account-profile-patch` 测试 120 合法、90 非法;设置页(`profile-fields`)源扫描仍复用 `BirthTimeIntakeFields`
### D2 校正窗口读档案(BUG-571:声明的不确定度被忽略)
- `case-service.ts::deriveRectificationOpenPlan` 增加 `uncertaintyBefore/After` 入参:`approximate``reportedTime max(15,before)` `reportedTime + max(15,after)`(各自独立,允许不对称),上限 120;其他钟点来源 ±15。
- 验收:`rectification-v9-case-service.test.ts` 新增 approximate ±60 → 04:0006:00、±120 → 03:0007:00;既有三处 04:4505:15 保留并注明来源为 `family_exact`(三栏)。
### D3 放宽窗口一键卡(BUG-572:吻合率低不提议放宽)
- 迁移:`widen_agentic_rectification_case_window(p_user_id, p_case_id, p_start_time, p_end_time)`:校验 `stage='minute'`、新窗口包含旧窗口、宽度 ≤ 241、`status ∉ terminal`、未采用;写 `candidate_range`,返回新范围;同一迁移给 `agentic_rectification_cases``widen_declined_at_fingerprint text null`
- 决策层:`decideRectification` 新入参 `windowWidenSuggested`(由 `decision-from-dossier` 按决策 3 条件计算,边缘判定用 `separation.representativeTime``case.candidateRange`),为真时返回 `nextAction="ask_window_widen"`,排在 `ask_candidate_discriminator` 之前;`sessionOutcome="widen_window"``can_adopt=false`
- 计划层:`method-followup.ts` 比照 `blockChoiceFollowup` 生成 `widen_window` 卡(选项文案服务端生成,档位从当前半径推:15→30/60、30→60/120、60→120/—(B 隐藏为 C 的同义?不行——四选项契约要求四项,则 B 写「放宽到前后两小时」与 A 相同档时 B 改为「先补一件带月份的经历再说」,answer_class `no`)。
- 应用:`answer-choice.ts` 比照 `mutateCaseForBlockChoice`:A/B → RPC 改窗口 → 泛化 `rescoreMinuteAfterBlockAdvance``rescoreMinuteAfterWindowChange` 重算 → 调用现有账户资料 patch 路径把 `uncertainty_before/after` 写为新半径、`birth_time_source``approximate``hospital_record` 例外:档案不改,只改窗口,因为其校验固定 ±2);C/D → 写 `widen_declined_at_fingerprint`
- 验收:新文件 `rectification-window-widen-20260907.test.ts`——(1) fit low + 代表分钟在边缘 → `nextAction=ask_window_widen`,卡四项齐;(2) fit low 但代表分钟在中间 → 不出卡;(3) 答 A → RPC 收到包含旧窗口的新范围、重算被触发、profile patch 收到新半径、已答探针数不变;(4) 答 C → 记指纹,同指纹下再评估不出卡,新证据到来后可再出;(5) 已 ±120 不出卡;(6) `hospital_record` 答 A 不改档案来源。`rectification-v9-database.test.ts` 加 RPC 用例(Docker)。
### D4 记录
- `docs/BUG_HISTORY.md` BUG-571、BUG-572`CHANGELOG.md``PROGRESS-rectification-declared-uncertainty-20260907.md``docs/testing/rectification-declared-uncertainty-20260907.md`(真实环境:intake 选"家人记得大概时间 · 前后一小时"→ 进校正后顶部范围是 2 小时;说 3 件与该窗口明显不合的经历 → 出放宽卡 → 点 A 后范围变宽且设置页里的选项跟着变);`frontend/DESIGN.md``frontend/docs/VOICE.md`
## 5. 让步顺序
D1 + D2 不可拆,先做;D3 其次(若一天内做不完,先落 RPC + 决策层 + 卡,写回档案可后置到同分支第二次提交并写明);D4 不可省。
## 6. 开工前置命令
```bash
git fetch origin --prune
git worktree add -b codex/rectification-declared-uncertainty-20260907 .worktrees/rectification-declared-uncertainty-20260907 origin/staging
cd .worktrees/rectification-declared-uncertainty-20260907
ln -s /workspace/Jyotisha/frontend/node_modules frontend/node_modules
cd frontend && ls tests/rectification-*.test.ts tests/consultation-*.test.ts tests/report-*.test.ts tests/personal-report-*.test.ts tests/birth-time-*.test.ts tests/account-profile*.test.ts tests/agent-voice-copy-contract.test.ts 2>/dev/null | grep -v database | xargs npx tsx --test 2>&1 | grep -E "^# (tests|pass|fail)"
grep -o "^## BUG-5[0-9][0-9]" ../docs/BUG_HISTORY.md | tail -1
```