Compare commits

..
Author SHA1 Message Date
ClaudeandClaude Opus 5.5 f824489ec9 docs(tasks): brief for #224 reading-birth-window
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXozsiu43ob7B8UZCmDM
2026-11-13 00:00:54 +08:00
@@ -0,0 +1,83 @@
# TASK:出生时间没确认到分钟时,按用户填的误差范围(没填按 ±30 分钟)判断分盘边界(2026-11-13)
- Gitea:#224
- 分支:`codex/reading-birth-window-20261113`,基于 staging `b1bb5c53fd19307caf7e4f2fd519bd7809daffe6`
- Bug 编号:BUG-1864(开工时核对 `docs/BUG_HISTORY.md` 末尾;若已被占用就顺延,并在 PROGRESS 写明)
- 验收:Claude(jyotisha-e6)
不得自行写「产品决定/裁定」。任务书没写到的取舍,一律选「需拍板」。
不得修改或删除既有断言来让测试通过。确需修改的,在 PROGRESS 里逐条写明原值、新值和原因。
占星师的引擎和资料(`scripts/jyotish_engine.py`、`scripts/yoga_engine.py`、`references/` 下她仓库已有的文件、`SKILL.md`)一律不改。产品差异只能放进单独的产品文件,并在 `references/product_runtime_contract.md` 公告(项目规则 2026-11-07)。
占星师回复原文:`docs/tasks/ref-astrologer-acceptance-reply-20261112.md`,由本分支第一个提交带入。下文的「她 §N」都指这份文件。
## 背景
产品负责人 2026-11-13 导出了一份报告。出生时间填的是 05:00,没有确认到分钟。D2、D6、D8、D10 的上升离换座只有约 0.3 分钟,D9 约 8 分钟,D1 约 73 分钟。可是事业、财富、健康的结论照样用了这几张分盘,而且都给到 C。
原因在 `scripts/report_render/evidence_grade.py::_varga_boundary`:
- `minute_confirmed` 为假时,直接返回 `not_evaluated`;
- `not_evaluated` 不算缺失,所以上限仍是 C。
她 §2 P0-1 要求:会跨越边界的判断,必须分支,或者暂缓给确定结论。
**产品负责人 2026-11-13 的决定:**
- 出生时间没确认到分钟时,用用户在填写出生信息时给的范围(#144:最早、最晚)。
- 用户没给范围(选了「不清楚误差」,或者只是大概记得),默认按 **±30 分钟**。
- 只记得时辰、只知道时段的,用该时辰或时段本身的起止。
- 必需分盘的上升在这个范围内会换座的,记为 `boundary_sensitive`,依赖它的结论上限降为 D。
## 要做的
1. **找出误差数据的来源。** 从资料表字段一路追到报告生成请求,再到 Python 端的报告事实包,写进 PROGRESS。相关字段:`uncertainty_before_minutes`、`uncertainty_after_minutes`、`birth_time_uncertainty_known`、`birth_time_source`、`birth_time_period`、`birth_time_shichen`、`declared_window_start/end`。`frontend/src/lib/personal-report-longform-birth.ts` 里已有 `provenanceUncertaintyMinutes`,先看它是怎么传的。
- 现有请求已经带误差的,直接用。
- 没带的,在报告生成请求里补传前后两个分钟数和它的来源。改动尽量小,在 PROGRESS 列出改了哪些文件。
2. **报告事实包加字段。** `birth_precision` 新增 `window`,形如 `{"before_minutes": 前误差, "after_minutes": 后误差, "source": 来源}`。`source` 取以下之一:
- `user_stated`:用户给了最早、最晚;
- `default_unknown_30`:没给范围,按 ±30 分钟;
- `shichen`:只记得时辰,取该时辰的起止;
- `period`:只知道时段,取该时段的起止;
- `confirmed_minute`:已确认到分钟。
时辰和时段的起止,取产品现有的定义(`birth-time-intake-model.ts` 或后端的对应常量),不要自己另定。
3. **上限计算**(`evidence_grade.py::_varga_boundary`)
- 已确认到分钟:行为不变,仍按 `birth_record_minute_v1` 的 ±1 分钟。
- 没确认到分钟:用 `birth_precision.window` 检查,`policy` 为 `birth_record_window_v1`。
- 前误差与 `before_minutes` 边界比,后误差与 `after_minutes` 边界比,只要有一侧边界落在误差之内,就记为 `boundary_sensitive`;两侧都在误差之外,记为 `clear_at_tolerance`。
- `boundary_check.rows` 里记下前后两个误差值和来源。
- 事实包里没有 `window` 时,按 `default_unknown_30` 处理,不能退回 `not_evaluated`。
- `purpose_stability` 照旧取事实包的值,不受这一条影响(#215)。
4. **D30 等精度分盘**:`PRECISION_VARGA` 按现有规则不参与,保持不变。
## 不要碰
- `frontend/src/lib/personal-report-reading.ts`(#218 在改)
- `references/**`
- 冻结文件
- 聊天证据卡。聊天是否采用同一规则,在 PROGRESS 里列出影响,选需拍板,不要改。
## 验收标准(新测试)
1. 合成事实,未确认到分钟、没有 `window`:D1 边界 73 分钟记为 clear;D9 边界 8 分钟、D2/D6/D8/D10 边界 0.3 分钟都记为 `boundary_sensitive`。`wealth_*`、`health_pressure`、`career_promise`、`relationship_structure` 的上限都是 D;`character_structure`(必需依赖只有 D1)的上限是 C。
2. 同一份事实,`window` 为 `{"before_minutes": 5, "after_minutes": 5, "source": "user_stated"}`:D9 记为 clear,上限 C;D2 仍是 `boundary_sensitive`,上限 D。
3. 前后误差不对称(例如前 0、后 20)时,只检查对应那一侧。
4. 已确认到分钟的旧测试全部通过,上限不变。
5. 用一个只记得时辰的合成请求,确认 `window.source == "shichen"`,且前后误差与产品对该时辰的定义一致。
6. #215 和 #216 的测试,以及报告事实包的测试,全部通过。
## 自测命令
```
python3 -m pytest -q tests/test_report_evidence_grade_20261112.py tests/test_evidence_grade_purpose_stability_20261112.py tests/test_reading_facts_v3_20261112.py tests/test_report_reading_facts.py
python3 scripts/run_quality_gate.py --profile quick --skip-frontend-runtime
cd frontend && npx tsc --noEmit -p . && npx eslint . # 只有改了前端才跑;改了前端还要跑相关测试
```
## 何时停下来选「需拍板」
- 报告生成请求里拿不到误差,而且补传必须改数据库结构。
- 时辰或时段的起止,产品里有两套互相矛盾的定义。