# TASK · 生时校正:可信区间成为一等公民,报告与对话按"稳定层 / 分钟敏感层"读盘(2026-09-06) - 基线:`origin/staging` @ `b938c76a`(文档头 `211f9bb2`) - 分支:`codex/rectification-range-reading-20260906` - 执行方:coding agent;验收:Claude - 串行:排在 `TASK-rectification-convergence-exit-fix-20260906.md`(BUG-565~567)与 `TASK-rectification-explain-layer-20260906.md` 之后,三者都改 `adopt-narration.ts` / `rectification-agentic-chat.tsx` - 涉及文件:`frontend/supabase/migrations/`(新迁移)、`frontend/src/lib/report-candidate-range.ts`、`frontend/src/lib/personal-report-route-core.ts`、`frontend/src/lib/consultation-route-service.ts`、`frontend/src/lib/consultation-birth-time-mode.ts`、`frontend/src/mastra/consultation-workflow.ts`、`frontend/src/lib/rectification-agentic/v9/tool-service.ts`、`adopt-narration.ts`、`scripts/jyotish_engine.py::_candidate_minutes`、`scripts/rectification/api_service.py`(新函数) - 不改:`scripts/jyotish_api_server.py` 主体(只允许一行薄注册)、`frontend/src/app/page.tsx`、任何采用/确认门 - BUG 编号起点:**BUG-568**(开工时复核;565~567 已被修复单预留) ## 0. 为什么做这件事 昨天的 20 例公开 holdout 校准说明引擎原始分在分钟级几乎没有区分力(见父单 `TASK-rectification-convergence-exit-20260906.md` 验收段与 BUG-560)。既然大多数校正最后都停在一个 10~30 分钟的可信区间,产品最诚实、也最有价值的交付就是:**告诉用户这段区间里哪些结论稳定、哪些结论随分钟变**,而不是把代表分钟当成精确时间去排盘。上游 yinduzhanxing 的 `FlexibleBirthTimeProfile` 合同(稳定证据 / 分钟敏感证据分开、多分钟区间不建单分钟盘)就是这个思路;它的四个脚本 9-03 已经同步进本仓,引擎 `_build_birth_time_sensitivity` 也已经在报告链上跑,但接的是错的窗口。 ## 1. 现状实证(代码定位,非猜测) | # | 事实 | 位置 | | --- | --- | --- | | 1 | 报告的 `birth_time_sensitivity` 窗口来自 RPC `read_report_candidate_range`,它返回 `agentic_rectification_cases.candidate_range`——即校正**开工时**的搜索窗口(填报时间 ±15 分钟,或时段 4~6 小时),不是 `latest_result.credible_range` | `frontend/supabase/migrations/20260904010000_read_report_candidate_range.sql` L50–68;`personal-report-route-core.ts::resolveReportBirthTimeSensitivityInput` | | 2 | 采用(accept)RPC 只写 `p_result_id / p_candidate_id`,可信区间不落库;profile 上只有 `active_birth_time` + `birth_time_status=accepted`,`uncertainty_before/after` 仍是填报值 | `tool-service.ts` L1726 `accept_agentic_rectification_candidate_for_case_v2` | | 3 | 引擎窗口 >15 分钟时只取 3 个样本(起点 / 代表 / 终点)做稳定-敏感分类,27 分钟区间等于只看 3 个分钟 | `jyotish_engine.py::_candidate_minutes` L2191 | | 4 | 聊天:`birth_time_status=accepted` → `verified_chart` 模式,按 `active_birth_time` 当精确分钟排盘;`birth_time_accuracy` / `candidate_range` 只在报告路径传,聊天不传 | `consultation-route-service.ts` L254、L515;`consultation-workflow.ts` L22–23 | | 5 | 校正采用轮只交付代表分钟 + 八法报告;没有"这段区间里哪些主题稳定"的话 | `adopt-narration.ts`、SKILL.md §9 | | 6 | `declared_birth_window` 聊天模式已存在(未校正的时段用户),只做输出守卫降级,不做稳定/敏感分层 | `consultation-birth-time-mode.ts` L84–95 | ## 2. 决策记录(PM 代为落地,可否决) 1. **采用即落库可信区间。** `accept_agentic_rectification_candidate_for_case_v2` 同时写入 `adopted_credible_range jsonb`(`{start_time,end_time,representative_time,width_minutes,source:"inference_credible_range"}`),来源 = 采用那一刻决策层的 `credibleRange`(与 UI 上"目前范围"同源)。用户改选候选时重写。 2. **报告与聊天优先读它。** `read_report_candidate_range` 先返回 `adopted_credible_range`,没有再退回 `candidate_range`;聊天 `verified_chart` 且 `status=accepted` 时把 `birth_time_accuracy="provisional"` + `candidate_range` 传进 workflow,与报告同一份 `birth_time_sensitivity`。`status=confirmed` 仍是 `confirmed`,不变。 3. **采样规则。** 窗口 ≤ 31 分钟逐分钟;> 31 分钟等距取 31 个样本(含起点、代表、终点),并在 `window` 里标 `sampled: true`。`flexible_birth_time_profile` 的 2~31 上限不改。 4. **校正采用轮多一段话。** 采用旁白在八法报告之后加"稳定 / 随分钟变"两句(服务端从 `theme_sensitivity` 生成,模型不得自编),例:"这 27 分钟里,事业方向、性格底色的判断是稳定的;婚恋(D9)和学业(D24)会随分钟变,看盘时按范围读。" 5. **`declared_birth_window` 模式也用同一分层**:时段用户没做校正也能拿到"这个时段里稳定的是什么",但窗口 > 31 分钟按 3 采样,措辞里必须写明"只是粗看"。 6. 不动任何门:采用门、确认门、`MIN_SEPARATION_LEAD`、报告的 `birthTimePolicy` 枚举都不改。 ## 3. 硬红线 - 迁移只加列 + 改一个 RPC;必须真跑 `npm run test:db --prefix frontend`(无 Docker 时写 `BLOCKED.md`,不得标通过)。 - `adopted_credible_range` 不得反向改写 `candidate_range`(那是开工基线,重算指纹依赖它)。 - 稳定 / 敏感句只允许来自 `theme_sensitivity`,不得由模型补写;文案对照 `frontend/docs/VOICE.md`,保留"不是已确认的唯一出生分钟"边界句。 - `scripts/jyotish_api_server.py` 只允许薄注册一行;新逻辑进 `scripts/rectification/api_service.py`。 - 测试总数 ≥ 开工实测;`tsc` 0 错;lint 0 error;`run_quality_gate.py --profile quick`。 ## 4. 任务分解 ### A1 落库(BUG-568:报告敏感度窗口用的是开工窗口) - 迁移 `agentic_rectification_cases.adopted_credible_range jsonb null`;`accept_agentic_rectification_candidate_for_case_v2` 新增可选参数 `p_credible_range jsonb`;`tool-service.ts` 采用时从 `decision.credibleRange` + `representativeTime` 组装传入;改选时覆盖。 - `read_report_candidate_range`:优先 `adopted_credible_range`,否则原逻辑。 - 验收:`rectification-v9-database.test.ts` 新增采用后读回区间用例(Docker);无 Docker 时 SQL 单元断言写进 `BLOCKED.md` 并附手工 psql 验证步骤。 ### A2 引擎采样 - `_candidate_minutes(start, representative, end)`:≤31 全取;>31 等距 31 点;返回值不变(`list[str]`)。 - 验收:`tests/test_jyotish_engine_birth_time_sensitivity*.py`(若无则新建)——27 分钟窗口返回 27 个样本;60 分钟返回 31 个且含起点/代表/终点。 ### A3 聊天接同一份敏感度 - `consultation-route-service.ts`:`verified_chart` 且 `birth_time_status=accepted` 时加载 `adopted_credible_range`(复用 `loadReportCandidateRange`),把 `birth_time_accuracy="provisional"` 与 `candidate_range` 放进 workflow 输入;`consultation-workflow.ts` 把 `birth_time_sensitivity.theme_sensitivity` 映射到 `consumer_context.answer_policy.minute_sensitive_themes: string[]`;系统提示块加一句固定说明(服务端文案),敏感主题的应期结论走 `guardPreciseTimingOutput` 同级降级。 - 验收:`consultation-*.test.ts` 新增——accepted + 有区间 → workflow 输入含 `candidate_range`,`answer_policy.minute_sensitive_themes` 非空;confirmed → 不含。 ### A4 校正采用轮的"范围读盘" - `scripts/rectification/api_service.py` 新增 `range_reading(request)`:输入出生资料 + 区间 + 代表分钟,内部调 `_build_birth_time_sensitivity`,返回 `{window, stable_themes[], sensitive_themes[], claim_boundary}`;`jyotish_api_server.py` 只加一行注册 `/api/rectification/v5/range_reading`。 - `engine-client.ts` 新增 `runV9RangeReading`;`adopt-narration.ts` 在采用旁白追加两句(决策 4);`rectification-offer-candidates` 工具返回里带 `range_reading`,SKILL 不改(措辞由服务端旁白承载)。 - 验收:`rectification-adopt-narration*.test.ts` 新增——给定 theme_sensitivity fixture,旁白含"稳定"与"随分钟变"两句且含边界句;引擎不可用时旁白不带这两句、不报错。 ### A5 `declared_birth_window` 复用(决策 5) - 同 A3 路径,`birth_time_accuracy="approximate"`,`candidate_range` = 声明时段;措辞加"只是粗看"。 - 验收:一条 consultation 测试。 ### A6 记录 - `docs/BUG_HISTORY.md` BUG-568;`CHANGELOG.md`;`docs/tasks/PROGRESS-rectification-range-reading-20260906.md`;`docs/testing/rectification-range-reading-20260906.md`(真实环境:采用后新建对话,回答里对婚恋/学业类问题出现范围口径;报告出生时间敏感度节的窗口等于采用时的"目前范围");`frontend/DESIGN.md` 若采用旁白布局有变。 ## 5. 让步顺序 A1 + A2 + A4 是核心,不可拆;A3 必做;A5 可后置到同分支第二次提交;A6 不可省。 ## 6. 开工前置命令 ```bash git fetch origin --prune git worktree add -b codex/rectification-range-reading-20260906 .worktrees/rectification-range-reading-20260906 origin/staging cd .worktrees/rectification-range-reading-20260906 ln -s /workspace/Jyotisha/frontend/node_modules frontend/node_modules ln -s /workspace/Jyotisha/.venv .venv 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)"; cd .. .venv/bin/python -m pytest tests/test_rectification_v5_services.py -q grep -o "^## BUG-5[0-9][0-9]" docs/BUG_HISTORY.md | tail -1 ```