Files
Jyotisha/docs/tasks/TASK-rectification-range-reading-20260906.md
T

99 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 · 生时校正:可信区间成为一等公民,报告与对话按"稳定层 / 分钟敏感层"读盘(2026-09-06
- 基线:`origin/staging` @ `b938c76a`(文档头 `211f9bb2`
- 分支:`codex/rectification-range-reading-20260906`
- 执行方:coding agent;验收:Claude
- 串行:排在 `TASK-rectification-convergence-exit-fix-20260906.md`BUG-565567)与 `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**(开工时复核;565567 已被修复单预留)
## 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` L5068`personal-report-route-core.ts::resolveReportBirthTimeSensitivityInput` |
| 2 | 采用(acceptRPC 只写 `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` L2223 |
| 5 | 校正采用轮只交付代表分钟 + 八法报告;没有"这段区间里哪些主题稳定"的话 | `adopt-narration.ts`、SKILL.md §9 |
| 6 | `declared_birth_window` 聊天模式已存在(未校正的时段用户),只做输出守卫降级,不做稳定/敏感分层 | `consultation-birth-time-mode.ts` L8495 |
## 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` 的 231 上限不改。
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
```
## 验收(Claude2026-09-07`origin/staging` @ `814c924e`
| 项 | 结论 |
| --- | --- |
| A1 落库 + RPC | 通过(代码审阅)。迁移 `20260906020000_adopted_credible_range.sql`:加列、六参采用函数、`read_report_candidate_range` 优先 `adopted_credible_range`;不改 `candidate_range`。Docker `test:db` 由执行方在有 Docker 的机器跑 37/0,本机无 Docker,按环境缺口记,不重复宣称 |
| A2 引擎采样 | 通过。≤31 逐分钟;>31 等距 31 点;`approximate` 且 >31 才 3 采样(决策 5);`flexible_birth_time_profile` 上限 15→31(任务书按 31 写,仓库原值 15,执行方如实记录) |
| A3 聊天 | 通过。`verified_chart(accepted)` 加载最近一个 `candidate_accepted` Case 的区间(不带 case idSQL 取 `updated_at desc limit 1`,可接受),`birth_time_accuracy=provisional` + `candidate_range` 进 workflow`minute_sensitive_themes` 进 answer_policy 并触发输出守卫 |
| A4 采用旁白 | 通过。稳定/敏感两句由 `theme_sensitivity` 生成,带边界句,引擎不可用静默省略 |
| A5 declared_birth_window | 通过(「这只是粗看」) |
| A6 记录 | 通过 |
部署提醒:staging 当前 `b938c76a`,本轮两条新迁移(`20260906020000``20260906030000`)未应用,部署前先跑 Migrate Staging Database。