docs(report): add blocked-repairs task brief — varga shape, transit receipt, karakas layer
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016P5RoqzmUQEbeC2qjAkeGr
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
# 任务书 · 个人报告全主题 blocked 修复(2026-09-02)
|
||||
|
||||
基线:`origin/staging` @ `24a1cf37`。
|
||||
|
||||
## 事故实证
|
||||
|
||||
2026-09-02 15:45 staging 真实生成的 personal_full 报告(请求主题 career/marriage/timing/wealth)四个主题**全部 blocked**,摘要退化为"报告主题尚未生成"。blocked 理由:
|
||||
|
||||
- career:缺少最低证据组 AmK、Transit
|
||||
- marriage:缺少最低证据组 DK
|
||||
- timing:缺少最低证据组 Transit
|
||||
- wealth:缺少结构化分盘 D2、D11
|
||||
|
||||
已在本地用 `origin/staging @ 24a1cf37` 的前端提取层 + 同版本 Python 引擎(`scripts/jyotish_api_server.py`,虚构 smoke 出生数据,按 worker 的方式每主题一次 `/api/consultation_workflow`)**完整复现**:blocked 主题与理由逐字一致。这是确定性缺陷,不是线上环境问题。
|
||||
|
||||
## 根因(已逐项定位,不需要重新猜)
|
||||
|
||||
**根因 1(wealth):分盘值形状不匹配,所有分盘图提取失败。**
|
||||
引擎 `chart.modules.varga_full` 的值形状是:
|
||||
|
||||
```json
|
||||
{ "ascendant": { "sign": "Gemini", "sign_index": 2, "degree": 21.027 },
|
||||
"planets": { "Sun": { "sign": "Libra", "sign_index": 6, "degree": 15.23, "house": 5 }, ... },
|
||||
"house_chart": [["Ketu"], [], ...], "division": ..., "name": ..., "meaning": ... }
|
||||
```
|
||||
|
||||
而 `frontend/src/lib/personal-report-generation.ts` 的 `deriveVargaHousesFromEngine`(约 :336)读的是**大写 `Ascendant` + `sign_idx` + 顶层行星键** → 每张分盘都返回 null → bundle `charts` 只剩 D1。昨日 `45f190a1` 修了键名别名(`D2_Hora`→`D2`)并新增"claim card 主题缺结构化分盘图则降 blocked"的兜底(`demoteThemesMissingRequiredCharts`),但没修值形状——于是 wealth 从"write 后文档校验失败"变成"bundle 层 blocked"。`643f6f7a` 的 fixture 是按**旧形状手造**的,所以测试全绿、线上照挂。(2026-08-30 观察到的 `final_parse_rejected` 大概率同源。)
|
||||
|
||||
**根因 2(timing、career 之一半):Transit 回执从不生成。**
|
||||
引擎响应 `chart.modules.transits` 存在且 `status: "executed"`(含 sade_sati、triggers、search_period、boundary),但 `consumer_context.available_layers` 与 machine packet sections 里都没有 transit 名目,前端提取层从不为它 upsert 执行回执 → 要求 Transit 的 timing/career 自这套 claim gate 上线起从未通过。存量问题。
|
||||
|
||||
**根因 3(career:AmK、marriage:DK):consultation 响应没有 Chara Karaka 数据。**
|
||||
整个响应中无 Amatyakaraka/Darakaraka 数值层:`chart.modules.jaimini` 只有 `arudha_padas`;guided topics 里 DK 的值是空占位符 `- H-`。引擎的 full-reading 路径有现成 karaka 计算(`scripts/jaimini.py`),但 `scripts/jyotish_api_server.py` 的 `_attach_local_consultation_layers` 没有把这层挂进 consultation 响应。**前端修不了,必须引擎响应新增字段。**
|
||||
|
||||
## 决策记录
|
||||
|
||||
产品负责人 2026-09-02 确认修复方向并授权:
|
||||
|
||||
- **(a)** 引擎侧允许在 consultation 响应中**新增** Chara Karaka 字段(这是 `TASK-report-skill-parity-20260901.md` 任务 0 预留的"响应新增字段"止损分支,正式启用)。仍然只许新增、不许改动既有字段的键名、形状或语义。
|
||||
- **(b)** `643f6f7a` / 既有测试中按旧分盘形状手造的 fixture 与断言,属于"锁住本轮要修的缺陷本身",允许按红线 9 的程序修改(注明原值与原因)。
|
||||
- **(c)** 主题最低证据组(`report-theme-evidence-plan.ts`)**不在授权范围内**:不得为了让主题通过而删除或放宽 AmK/DK/Transit/D2/D11 要求。修法只能是把证据真实供给上。
|
||||
|
||||
## 硬红线
|
||||
|
||||
1. **最低证据组一条不得放宽**(见决策记录 c)。`demoteThemesMissingRequiredCharts` 兜底保留,不得删除——修好值形状后它自然不触发。
|
||||
2. **引擎改动只许响应新增字段**:不改既有字段、不改排盘算法、不改 full-reading 路径;新增层必须复用 `scripts/jaimini.py` 既有实现,不得重写 karaka 算法。
|
||||
3. **fixture 必须来自真实引擎响应**(golden),不得再手造形状。任务 0 是门控:先落 golden fixture 与形状契约测试,任务 1–3 的实现测试必须建立在它之上。
|
||||
4. 上一轮任务书(`TASK-report-skill-parity-20260901.md`)的红线继续有效:输入隔离不放松、writer 输出 schema 只可收紧、`assertionLevel` 推导与 consensus ≥2 verified 防升级校验一字不改、本轮不改数据库结构、章节串行、telemetry 只记指标名与数值。
|
||||
5. 隐私红线:fixture 与测试只用虚构 smoke 出生数据;golden fixture 入库前确认不含任何真实用户资料。
|
||||
6. 推 staging 前 `./node_modules/.bin/tsc --noEmit` 必须通过(**不要用 `npx tsc`**,会装到空包 `tsc@2.0.4`)。不得改 `.gitea/workflows/**`,不得自行提升 main。
|
||||
7. Python 侧改动必须带单元测试(`.venv` + unittest/pytest,按仓内既有测试形式),并真实跑过。
|
||||
|
||||
让步顺序:数据不损坏 > 证据纪律不回退 > 功能与测试不回归 > 可验证的修复 > 成本 > 代码整洁。
|
||||
|
||||
## 开工前置
|
||||
|
||||
```bash
|
||||
git fetch origin --prune
|
||||
git worktree add -b codex/report-blocked-repairs-20260902 \
|
||||
../.worktrees/report-blocked-repairs-20260902 origin/staging
|
||||
```
|
||||
|
||||
读 `pre_work_error_ledger.md`,跑 `scripts/pre_work_check.py`,读 `frontend/AGENTS.md`,在 `docs/BUG_HISTORY.md` 检索(BUG-486 及相邻条目与本轮直接相关)。
|
||||
|
||||
**先读这几处再动手**:
|
||||
|
||||
- `frontend/src/lib/personal-report-generation.ts` —— `deriveVargaHousesFromEngine`(:336 附近)、`readAllVargaCharts` / `readVargaHouses`(`VARGA_KEY_ALIASES` 已存在)、`demoteThemesMissingRequiredCharts`、receipt upsert 逻辑
|
||||
- `frontend/src/lib/report-theme-evidence-plan.ts` —— 各主题 `requiredTechniqueGroups`(只读,不改)
|
||||
- `scripts/jyotish_api_server.py` —— `_attach_local_consultation_layers`、`execute_consultation_workflow`
|
||||
- `scripts/jaimini.py` —— 既有 Chara Karaka 实现
|
||||
- `git show 45f190a1` 与 `git show 643f6f7a` —— 昨日两次治标修复的全部内容
|
||||
|
||||
## 复现方法(验收也用它)
|
||||
|
||||
起本地引擎:`.venv/bin/python scripts/jyotish_api_server.py --port 5200`。用虚构出生数据(如 1993-06-15 10:30,lat 36.42 / lon 114.21 / tz 8)按 worker 的调用方式(`entryMode: "direct_chart"`,question `请为个人报告计算 <theme> 主题证据`)对 career/marriage/timing/wealth 各调一次 `runConsultationWorkflow`,把 4 个响应喂给 `buildReportEvidenceBundleV2`,检查 `claimCards` / `blockedSections` / `executionLedger` / `charts`。修复前的预期输出(用于确认复现成功):claimCards 为空、四主题全在 blockedSections、charts 只有 D1。
|
||||
|
||||
---
|
||||
|
||||
## 任务 0(P0,门控)· Golden fixture 与形状契约
|
||||
|
||||
### 做法
|
||||
|
||||
- 用上述复现方法捕获 4 个主题的真实响应,裁剪成 fixture(保留 `chart.modules.varga_full`(至少 D2/D9/D10/D11/D24 各一张完整值)、`modules.transits`、`modules.jaimini`、`consumer_context`、machine packet sections;删除与提取无关的大块字段以控制体积),入库为测试资产。
|
||||
- 新增形状契约测试:断言 varga_full 值的真实形状(小写 `ascendant`、`sign_index`、`planets` 字典、`house_chart`),并断言 `modules.transits.status` 字段存在。**这个测试在修复前就应该通过**(它锁的是引擎真实形状,不是前端行为)。
|
||||
- 将 `643f6f7a` 手造的旧形状 fixture 替换为 golden 派生数据;按红线 9 在改动处注明原值与原因。
|
||||
|
||||
### 验收
|
||||
|
||||
- 形状契约测试直接对 golden fixture 通过;PROGRESS 记录 fixture 的捕获命令与裁剪规则。
|
||||
|
||||
---
|
||||
|
||||
## 任务 1(P0)· 修分盘值形状,复活结构化分盘图
|
||||
|
||||
### 做法
|
||||
|
||||
`deriveVargaHousesFromEngine` 兼容真实形状,规则:
|
||||
|
||||
- 上升:`varga.ascendant ?? varga.Ascendant`;星座索引 `sign_index ?? sign_idx ?? signIndex(sign)`;度数 `degree ?? degree_in_sign`。
|
||||
- 行星:优先读 `varga.planets` 字典(每行星有 `sign_index` 与 `house`,宫位可直接用 `house`,无 `house` 时按整星座宫从上升推导);`planets` 不存在时退回旧的顶层行星键路径(保持对旧形状的兼容,两种形状都要有测试)。
|
||||
- 不吸收 `house_chart` 以外来源不明的字段;未知键一律不复制。
|
||||
|
||||
### 验收
|
||||
|
||||
- 单元测试双形状覆盖(golden 新形状 + 既有旧形状)。
|
||||
- 复现管线跑通后:`charts` 至少含 D1/D2/D9/D10/D11/D24;wealth 出 claim card,`demoteThemesMissingRequiredCharts` 不触发;D2/D11 回执 executed。
|
||||
- education / migration_home 等依赖分盘的主题在补充复现(9 主题全请求)中同样解锁,PROGRESS 记录逐主题结果。
|
||||
|
||||
---
|
||||
|
||||
## 任务 2(P0)· Transit 执行回执
|
||||
|
||||
### 做法
|
||||
|
||||
提取层读 `chart.modules.transits`:`status === "executed"` 时 upsert `Transit` 回执(`status: "partial"`、`executed: true`,与 ashtakavarga/dasha_sub_periods 的既有读取方式同风格);`status` 缺失或非 executed 时不产回执(fail closed,不得默认 executed)。
|
||||
|
||||
### 验收
|
||||
|
||||
- 单元测试:executed / 缺失 / 其他 status 三种输入。
|
||||
- 复现管线:timing 出 claim card;career 的 blocked 理由只剩 AmK(在任务 3 完成前)。
|
||||
|
||||
---
|
||||
|
||||
## 任务 3(P0)· 引擎挂 Chara Karaka + 前端 AmK/DK 回执
|
||||
|
||||
### 做法
|
||||
|
||||
- 引擎:`_attach_local_consultation_layers` 调用 `scripts/jaimini.py` 既有实现,把 Chara Karaka 挂到 `chart.modules.jaimini.chara_karakas`(结构建议:`{ "AmK": { "planet": ..., ... }, "DK": { ... }, ... }`,具体键名以 jaimini.py 现有输出为准,**新增字段不改既有 `arudha_padas`**)。带 Python 单元测试。
|
||||
- 前端:从 `modules.jaimini.chara_karakas` 中 AmK/DK 的存在性 upsert `AmK` / `DK` 回执(`partial` + `executed: true`);数据缺失时不产回执。
|
||||
- golden fixture 用引擎修复后的响应重新捕获(或叠加一份含 karakas 的 golden),形状契约测试同步覆盖新层。
|
||||
|
||||
### 验收
|
||||
|
||||
- Python 测试:consultation 响应含 `chara_karakas` 且 AmK/DK 数据来自 jaimini.py 现有输出。
|
||||
- 复现管线:**career/marriage/timing/wealth 四主题全部出 claim card,blockedSections 为空**;`executionLedger` 中 AmK/DK/Transit/D2/D11 均 executed。
|
||||
|
||||
### 止损
|
||||
|
||||
- 若 `jaimini.py` 现有实现无法在 consultation 输入上直接复用(缺参数、口径冲突),**停下**写 `BLOCKED.md`,不得重写算法、不得放宽最低证据组来绕过。
|
||||
|
||||
---
|
||||
|
||||
## 任务 4(P1)· 端到端与既有欠账
|
||||
|
||||
- 全套质量门:frontend `tsc --noEmit` / `eslint`(0 error)/ `tsx --test`(失败清单与基线逐条比对)/ `next build`;Python 相关测试真实跑过。
|
||||
- 部署后(委托方核对 health gitCommit)真实生成一份 personal_full 报告,验收:四主题有正文、不再全 blocked;顺带补上一轮欠的交付物——真实 writer 输出回溯抽查(≥3 处)与每章实测 `inputTokens`/墙钟对照(对照基线与 2 倍线裁决记录见 `PROGRESS-report-skill-parity-20260901.md` 与 `BLOCKED.md` 对应条目)。
|
||||
|
||||
## 不在本轮范围
|
||||
|
||||
- 主题最低证据组的增删改(决策记录 c)。
|
||||
- 引擎排盘算法、full-reading 路径、varga_full 既有形状的任何改动。
|
||||
- 知识包内容、writer prompt、成本优化(沿用已裁决结论)。
|
||||
- 章节并发、模型更换、计费、数据库结构。
|
||||
|
||||
## 收尾
|
||||
|
||||
- PROGRESS 文件名写 `PROGRESS-report-blocked-repairs-20260902.md`。
|
||||
- `docs/BUG_HISTORY.md` 新增条目(编号先对远端确认;根因 1 与 BUG-486 关联,注明 45f190a1/643f6f7a 是治标、本轮治本)。
|
||||
- 建议两次推送:任务 0+1+2(纯前端)一次;任务 3(引擎+前端)一次。staging push 触发全量构建+部署,全链路约 20 分钟,推送后核对 `https://staging.jyotisha.chat/api/health` 的 `.deployment.gitCommit`。
|
||||
- 不自行提升 main。
|
||||
|
||||
## 交付物清单
|
||||
|
||||
1. Golden fixture(真实响应派生)+ 形状契约测试;643f6f7a 旧 fixture 的替换说明
|
||||
2. `deriveVargaHousesFromEngine` 双形状兼容 + 测试;复现管线中 charts/D2/D11 复活证据
|
||||
3. Transit 回执提取 + 三态测试
|
||||
4. 引擎 `chara_karakas` 新增层 + Python 测试;前端 AmK/DK 回执 + 测试
|
||||
5. 复现管线修复前后对照:blockedSections 从 4 → 0,claimCards 从 0 → 4(9 主题全请求的逐主题表)
|
||||
6. 部署后真实报告验收 + 上一轮欠账(writer 输出回溯抽查、实测 tokens/墙钟对照)
|
||||
7. `docs/BUG_HISTORY.md` 条目、`BLOCKED.md`(任何触发止损的项)、`PROGRESS-report-blocked-repairs-20260902.md`
|
||||
8. 全套质量门实际输出(frontend 四件 + Python 测试)
|
||||
Reference in New Issue
Block a user