diff --git a/docs/tasks/README.md b/docs/tasks/README.md index 4653890b..d9f43ee6 100644 --- a/docs/tasks/README.md +++ b/docs/tasks/README.md @@ -67,6 +67,7 @@ | `TASK-rectification-range-reading-20260906.md` | `PROGRESS-rectification-range-reading-20260906.md` | 可信区间成为一等公民:采用时落库 `adopted_credible_range`,报告 `read_report_candidate_range` 与聊天 `verified_chart(accepted)` 都改读它并接同一份 `birth_time_sensitivity`(现在报告读的是开工窗口,BUG-568);引擎 >15 分钟只取 3 样本改为 ≤31 逐分钟;采用旁白加「稳定 / 随分钟变」两句;`declared_birth_window` 复用 | 已验收通过(test:db 37/0 为执行方数字,本机无 Docker) | `814c924e`(BUG-568);两条迁移待应用 | | `TASK-rectification-unknown-time-20260906.md` | `PROGRESS-rectification-unknown-time-20260906.md` | 完全不知道出生时间的两段式路线:`stage=block_scan` 以 10 分钟步长扫 24 小时只做事件计分、出五时段四选卡(不写账本不采用),选定后进现有分钟流程;引擎加 `minute_step`;开场读 `birth_time_clue`;删 intake 劝退文案 | 已验收(带修复单:时段支持度按段长偏置,下午段先天 25%,P1) | `814c924e`;修复单 `TASK-rectification-capability-fix-20260907.md`(BUG-570) | | `TASK-rectification-capability-fix-20260907.md` | `PROGRESS-rectification-capability-fix-20260907.md` | 能力补齐修复单:答后旁白把 `range_start/range_end`(搜索窗口)当范围比较,每题都说「范围没变」;`block_scan` 五段支持度按段内原始分求和,长时段先天占优(24/24/36/30/30 个候选);`TRACK_LABEL` 音译与产品 Vimshottari/Narayana 口径不一;BLK-001 写到 `docs/BLOCKED.md` 应回根目录 | 已验收通过(P2:block_scan 15 s 壁钟断言在门禁里可能间歇红) | `517df002`(BUG-569~570);staging 未部署,需先 Migrate Staging Database | +| `TASK-rectification-declared-uncertainty-20260907.md` | `PROGRESS-rectification-declared-uncertainty-20260907.md` | 出生时间「有多确定」只在 intake 问一次:三档(医院记录 / 家人大概 ±15·30·60·120 / 时段或未知),校正窗口读档案(现在有钟点一律 ±15,声明值被忽略,BUG-571);吻合率 <60% 且代表分钟贴窗口边缘时出服务端一键放宽卡,放宽后重算并写回档案(BUG-572) | 待领取 | `codex/rectification-declared-uncertainty-20260907` | | `TASK-api-not-configured-mislabel-20260904.md` | `PROGRESS-api-not-configured-mislabel-20260904.md` | 16 处路由把数据库瞬断(部署切换窗口)兜底翻译成 503「服务尚未配置」;改为仅配置错误用该文案,其余 `service_unavailable`,收敛为共享 helper | 已验收 | `5483649b`(BUG-542);2 条子进程测试留 CI Node 22 复核 | | `TASK-rectification-ux-20260902.md` | `PROGRESS-rectification-ux-20260903.md` | 会话面空白假死与交互摩擦 | 已验收 | `d159f08e`(09-03 在新基线重做后合入,BUG-505~509) | diff --git a/docs/tasks/TASK-rectification-declared-uncertainty-20260907.md b/docs/tasks/TASK-rectification-declared-uncertainty-20260907.md new file mode 100644 index 00000000..d27bd2cf --- /dev/null +++ b/docs/tasks/TASK-rectification-declared-uncertainty-20260907.md @@ -0,0 +1,83 @@ +# TASK · 出生时间"有多确定"只问一次:intake 三档、校正读档案里的偏移、吻合率低时一键放宽并写回(2026-09-07) + +- 基线:`origin/staging` @ `5c644f92`(代码头 `517df002`,含 BUG-565~570) +- 分支:`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` L91–94、L96–140;`account-profile-patch.ts` L126–145 | +| 2 | 校正开 Case:只要档案有钟点,一律 `reportedTime ± 15`(`FRESH_CASE_SEARCH_RADIUS_MINUTES`),注释写明"引擎执行边界,不是用户声明的不确定度";档案里的 `uncertainty_before/after` 被读进 baseline 但不参与窗口 | `case-service.ts` L131–146 | +| 3 | 引擎每次重算都产出 `event_fit_rate`(matched / total / percent / band:≥80 high、60–80 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` L132–182;`tool-service.ts` L619 | +| 6 | 既有测试把填报 05:00 → 04:45–05: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:45–05: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:00–06:00、±120 → 03:00–07:00;既有三处 04:45–05: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 +```