Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41862634f3 |
@@ -0,0 +1,170 @@
|
||||
# TASK:占星师验收清单的七个反例,从引擎到数据卡端到端测试(2026-11-09)
|
||||
|
||||
- 分支:`codex/counterexamples-20261109`(基于 staging `b453505d`)
|
||||
- Bug 编号:BUG-1812(开工时核对 `docs/BUG_HISTORY.md` 的最大编号;1809–1830 已预留给本批任务)
|
||||
- 负责验收:Claude(jyotisha-2a)
|
||||
|
||||
## 背景
|
||||
|
||||
占星师 2026-11-08《近期六轮问题闭环与网站验收清单》§7 原文:“另加入缺月相、低档强弱未决、AD未决但MD已定、Moon自参照、出生余额、第二周期与0年等反例。”
|
||||
|
||||
§5 的要求:每个问题沿“计算 → 数据卡 → 模型输入 → 回答 → 导出”五个阶段验收。原文:“不要只测第一阶段,再从最后一阶段‘读起来不错’推断中间过程正确。”数据卡阶段必须检查:“是否丢失必要分盘、父段、限制、冲突;不能把未送达写成未计算。”
|
||||
|
||||
§3 P0 的通过标准:“只阻塞依赖项;旧候选不可冒充主结果;缺失不能产生评分;独立确定的MD保留。”
|
||||
|
||||
**本任务把七个反例都做成从计算一路到数据卡的测试。** 测试暴露的数据卡漏字段,在本任务内补上。回答阶段的盲测由 Claude 另做。
|
||||
|
||||
## 测试怎么做(现有机制)
|
||||
|
||||
仓库里没有在同一次运行里同时调用 Python 和 TS 数据卡的测试。现有做法分两层:
|
||||
|
||||
1. **Python 层**:调用真实引擎函数,断言状态字段。
|
||||
2. **TS 层**:用真实引擎输出抓取的 golden,经过真实前端链路生成数据卡。链路是 `consultationWorkflowResponseSchema.parse` → `toAgentConsultationContext` → `toModelOutput` → `buildEvidenceCard`。
|
||||
- 模板:`frontend/tests/consult-self-reference-pipeline-20261108.test.ts`。它对 golden 做 `structuredClone`,把形状与引擎一致的行注入 `chart.consultation_native_layers.*`。
|
||||
- golden 文件:`frontend/tests/fixtures/consult-evidence-card-golden.json`。生成脚本是 `scripts/research/capture_consult_evidence_card_golden.py`,含 Jobs、Obama、Taylor 三张公开盘。
|
||||
|
||||
**端到端的要求**:每个反例都要有一个 Python 测试。这个测试调用真实引擎函数,把输出的那一段 JSON 写成 fixture,放在 `frontend/tests/fixtures/counterexamples-20261109/<case>.json`。
|
||||
|
||||
- 生成方式写成脚本 `scripts/research/capture_counterexample_fixtures_20261109.py`,可重复运行。
|
||||
- Python 测试断言:“现在引擎的输出 == fixture”,防止 fixture 过期。
|
||||
|
||||
TS 测试读同一份 fixture,经真实前端链路生成数据卡,再断言卡上的字段。**不得在 TS 里手造引擎形状。**
|
||||
|
||||
只用公开名人盘(golden 里已有的那些)或合成输入(`tests/neutral_subject.py`,或像 `tests/test_round6_r1_r2_narayana.py` 那样构造的 lagna + 经度字典)。
|
||||
|
||||
## 七个反例(b453505d 实测位置,行号以符号为准)
|
||||
|
||||
### (a) 缺月相
|
||||
|
||||
- **引擎**:`scripts/functional_benefics.py` 的 `_pvr_roles`(约 :276–301)。动宫上升、`moon_paksha=None` 时,结果为 `movable_lagna_moon = {status:"blocked", reason:"moon_paksha_missing", ...}`,`blocked_planets:["Moon"]`。只阻塞月亮。
|
||||
- **已知真实缺陷,本任务要修**:Obama 盘(golden 内)出现两层结果不一致。
|
||||
- `chart.modules.functional_benefic_malefic.movable_lagna_moon` 为 waning / neutral。
|
||||
- `consultation_native_layers.career_analysis.functional_benefic_malefic.movable_lagna_moon` 却是 `blocked / moon_paksha_missing`。
|
||||
- 原因:`scripts/consultation_native_layers.py` 的 `build_career_analysis`(约 :1280)传入的是 `_affliction_planets`(约 :1210)的行。这些行没有度数,`scripts/career_analysis.py`(约 :93)因此算不出月相。
|
||||
- 修法:让事业层拿到月亮与太阳的经度,或直接拿到基础层已经算好的月相。修复点只在 `consultation_native_layers.py` 或 `career_analysis.py`。
|
||||
- **数据卡**:`frontend/src/lib/consultation-evidence-card.ts` 的 `functionalProfileFields`(约 :1325–1345)只抄了 `{status, moon_paksha, role}`,丢掉了 `reason`。要补上 `reason`。
|
||||
- **断言**:
|
||||
- 真缺月相(合成盘不给月亮经度)时:卡上为 `blocked` 且 `reason` 为 `moon_paksha_missing`;只有月亮被阻塞,其他行星的功能吉凶照常;月亮不参与吉凶计票。
|
||||
- Obama 盘修复后,两层月相一致。
|
||||
|
||||
### (b) 低档强弱未决
|
||||
|
||||
- **Narayana**:`scripts/narayana_rath.py` 的 `compare_signs`(约 :562–614)返回 `status:"undecided"`、`comparison_status:"unresolved"`、`blocked_level`。
|
||||
- `calc_narayana_rath`(约 :1001)在种子判不出时为 `status:"blocked"`、`blocked_step:"seed"`;年数判不出时为 `status:"partial_blocked"`、`blocked_step:"years"`。
|
||||
- 产品视图:`scripts/narayana_legacy_label.py` 的 `rath_narayana_view`(约 :252)与 `narayana_method_status`(约 :194)。
|
||||
- 卡上:`consultation-evidence-card.ts` 的 `narayanaMethodStatus`(约 :1703)与 `baseTiming`(约 :1786、:1834–1846)。
|
||||
- **Shadbala**:
|
||||
- `scripts/shadbala_service/sensitivity.py` 的 `attach_parameter_sensitivity`(约 :237);
|
||||
- `scripts/shadbala_display.py` 的 `row_fields`(约 :47–63),输出 `minimum_check:"parameter_sensitive"`;
|
||||
- 卡上:`SHADBALA_CARD_KEYS` 与 `shadbalaCardRows`(约 :1438–1449)。
|
||||
- **断言**:
|
||||
- 卡上 Narayana 的未决步骤被点名(种子 / 年数 / 双宫主),不出现“已确认”字样的状态,`used_for_scoring` 为 false。
|
||||
- Shadbala 为 `parameter_sensitive` 的行星,卡上保留这个标记,并且不以“达标 / 不达标”计入支持或压力(第五轮第 4 条:“只能标为 parameter_sensitive,不能用它决定聊天里的吉凶结论”)。
|
||||
|
||||
### (c) 小运(AD)未决,大运(MD)已定
|
||||
|
||||
- **引擎**:`narayana_rath.py` 的 `antardasha`(约 :921)返回 `{status:"blocked", reason, rows:[]}`;`branch_under`(约 :1362)返回 `ad:None, ad_status:"blocked", ad_reason`。
|
||||
- 默认 `STRENGTH_SCOPE_DEFAULT = seed_only_v0`(BUG-1784)。默认设置下,现实的触发条件是土星与计都同在大运星座(`saturn_ketu_priority_unresolved`),或者像 `tests/test_round6_r1_r2_narayana.py:86` 那样在测试里显式放宽范围。两种都要测。
|
||||
- **卡上的缺口**:`scripts/consultation_native_layers.py` 的 `build_dasha_systems`(约 :1676–1760)在 AD 未决时省略了 `nar["ad"]`。`consultation-evidence-card.ts` 的 `baseTiming`(约 :1826–1830)只在有值时才抄 md / ad / pd。所以现在 AD 未决在卡上只表现为“没有 ad”,与“没算”分不开。这违反 §5 的“不能把未送达写成未计算”。
|
||||
- **修法**:卡上 Narayana 增加 `ad_status` 与 `ad_reason`(从引擎原样带过来),`narayanaRunningLine`(约 :1769)在 AD 未决时写明“子运未决”。
|
||||
- **断言**:
|
||||
- MD 的星座和日期保留,并与引擎相等;
|
||||
- AD 为未决,且原因被点名;
|
||||
- 卡上不出现由旧算法补出的 AD。
|
||||
|
||||
### (d) 月亮自参照
|
||||
|
||||
- **引擎**:`scripts/main_yoga_detectors.py` 的 `neecha_bhanga_rows`(约 :129–163)输出 `self_reference`、`independent_confirmation_allowed:false`。
|
||||
- **卡上**:`consultation-evidence-card.ts` 的 `yogaSelfReference`(约 :1008–1030)与 `evidenceCardIndependence`(约 :1065)。
|
||||
- **已有测试**:`frontend/tests/consult-self-reference-pipeline-20261108.test.ts`、`tests/test_round6_self_reference.py`。本任务不重写这两个,只补端到端缺的一环:引擎真输出 → fixture → 卡。
|
||||
- **断言**:只由月亮自参照形成的格局,不进入 `support`;同一事实重复引用只算一票(现有规则见 BUG-1773、BUG-1774)。
|
||||
|
||||
### (e) 出生余额
|
||||
|
||||
- **引擎**:`scripts/chart_dasha/birth_moment.py` 的 `antardashas(md, visible_from=)`(约 :88–112):`parent_period_start` 是未裁剪的父段起点,`visible_period_start = max(start, birth)`。
|
||||
- **服务器**:`scripts/jyotish_api_server.py` 的 `_consultation_dasha_sub_periods` 下的 `boundary()`(约 :1504–1514)。**只读,不改。**
|
||||
- **卡上**:`CLIPPED_PERIOD_KEYS`(约 :1349)与 `baseTiming`(约 :1786–1812)。
|
||||
- **缺口**:golden 里三位都是成年人,参考日 2026-09-27 时都已不在出生大运内,所以卡上的“裁剪”分支从未被真实数据覆盖。请用一张合成的年轻盘(参考日落在出生 MD 之内)。
|
||||
- **断言**:
|
||||
- 卡上 MD 与 AD 同时带 `parent_period_start` 和 `visible_period_start`,二者不同,且都等于引擎值;
|
||||
- 子运边界不因裁剪而改变(第五轮第 5 条)。
|
||||
|
||||
### (f) 第二周期
|
||||
|
||||
- **引擎**:
|
||||
- `narayana_rath.py` 的 `mahadasha_sequence`(约 :820)设 `cycle_index` 为 1 或 2(第二周期用 12 减去年数);
|
||||
- `branch_under` 设 `md_cycle`;
|
||||
- Vimshottari 用 `birth_moment.py` 的 `next_cycle_mahadashas`(约 :35)。
|
||||
- **缺口**:卡上 `NARAYANA_MD_CARD_KEYS`(约 :1782)没有 `cycle_index`,卡说不出“这是第二周期”。要补上 `cycle_index`。
|
||||
- **断言**:
|
||||
- 合成盘的参考年龄落在 Narayana 第二周期内时,卡上当前 MD 带 `cycle_index: 2`,年数等于引擎值;
|
||||
- Vimshottari 跨过 120 年后,当前段等于引擎值(可参照 `tests/test_vimshottari_second_cycle.py`);
|
||||
- 其他大运 `not_available_yet` 的行,在卡上进入 gaps,不显示为“当前”。
|
||||
|
||||
### (g) 0 年大运
|
||||
|
||||
- **引擎**:`narayana_rath.py` 的 `mahadasha_sequence`(约 :828/:860/:886)设 `zero_duration`。
|
||||
- 判断“当前”的区间是半开的 `[start, end)`:`_running_age`(约 :1355)、`narayana_legacy_label.py` 的 `_running`(约 :235)、`consultation_native_layers.py` 的 `_running`(约 :1505)。
|
||||
- **卡上**:`timingFollowing`(约 :1633、过滤在 :1667–1671)。golden 里没有 `zero_duration:true` 的行。
|
||||
- **断言**:
|
||||
- 合成一张会产生 0 年 Narayana 段的盘(可参照 `tests/test_round5_item_reply_n1_k3_20261108.py:181` 的人马座 0 年 / 12 年构造),参考日恰好落在该段起点;
|
||||
- 卡上当前 MD 不是 0 年段;
|
||||
- 0 年段保留在数据里,并带 `zero_duration` 标记(若卡上需要展示时序,就补上这个键)。
|
||||
|
||||
## 要改的文件(以实际代码为准)
|
||||
|
||||
- **新建**:
|
||||
- `scripts/research/capture_counterexample_fixtures_20261109.py`
|
||||
- `frontend/tests/fixtures/counterexamples-20261109/*.json`
|
||||
- `tests/test_counterexamples_engine_20261109.py`
|
||||
- `frontend/tests/consult-counterexamples-card-20261109.test.ts`
|
||||
- **修改**:
|
||||
- `frontend/src/lib/consultation-evidence-card.ts`:只改上面点名的函数和常量,即 `functionalProfileFields`、`NARAYANA_MD_CARD_KEYS`、`baseTiming` 的 Narayana 段、`narayanaRunningLine`、`timingFollowing`。**不做结构性重排**,压缩是 #170 的事。
|
||||
- `scripts/consultation_native_layers.py`:(a) 的事业层月相、(c) 的 `ad_status` 透传。
|
||||
- `scripts/career_analysis.py`:如 (a) 的修复需要。
|
||||
- 若卡片新增字段导致 `frontend/tests/consult-evidence-card-20260927.test.ts` 的体积上限超出,只许按实测增量放宽,并写三栏注释。
|
||||
|
||||
## 不要碰
|
||||
|
||||
- `references/**`(占星师方法文件)、`frontend/src/lib/consult-preset-prompts.ts`、`references/product_runtime_contract.md`。
|
||||
- 冻结文件:
|
||||
- `scripts/jyotish_api_server.py`(只读);
|
||||
- `scripts/functional_benefics.py`、`scripts/narayana_dasha.py`、`scripts/dasha_analyzer.py`、`scripts/domain_calculation_service.py`、`scripts/shadbala.py`、`scripts/ashtakavarga.py`、`scripts/jaimini.py`、`scripts/varga.py`。
|
||||
- `scripts/narayana_rath.py`:不改公式与规则,本任务只测。
|
||||
- 其他单子的地盘:
|
||||
- `frontend/src/mastra/consultation-tools.ts` 全文(#171/#173 在改);
|
||||
- `frontend/src/app/api/consult/route.ts`(#172);
|
||||
- `consultation-evidence-card.ts` 里的 `EVIDENCE_LOOKUP_SECTIONS` 与 `evidenceCardIndependence` 的结构(#170/#171)。
|
||||
- 不改大运计算公式,不改计分权重。
|
||||
|
||||
## 验收标准
|
||||
|
||||
1. 七个反例各有一条 Python 引擎测试,以及一条读同一 fixture 的数据卡测试,共 14 条以上,全部通过。
|
||||
2. fixture 由脚本重新生成后与仓内一致。Python 测试断言“引擎当前输出 == fixture”。
|
||||
3. (a)、(c)、(f) 三处卡上缺字段已补,Obama 两层月相不一致已修。每处修复各有一条“修前会失败”的回归断言。在 PROGRESS 里写明:先在未修代码上跑出失败,再修。
|
||||
4. 所有“未决 / 阻塞”的反例都断言了不计分、不增票:不进入 `support` 或压力计数,`used_for_scoring` 为 false。
|
||||
5. 改既有断言时写“原值 / 新值 / 原因”三栏注释。原因写:`占星师 2026-11-08 验收清单 §7 反例:未决不得写成未计算`。
|
||||
6. 在 `docs/BUG_HISTORY.md` 末尾追加 BUG-1812。记录 Obama 事业层月相不一致、卡上缺 `reason` / `ad_status` / `cycle_index` 这三处。不写个人出生资料。
|
||||
7. 只用公开名人盘或合成数据。
|
||||
|
||||
## 自测命令(Windows / PowerShell)
|
||||
|
||||
- `frontend\node_modules\.bin\tsc --noEmit -p frontend`
|
||||
- 在 `frontend` 下运行 `npm run lint`
|
||||
- 在 `frontend` 下运行 `node node_modules/tsx/dist/cli.mjs --test tests/consult-counterexamples-card-20261109.test.ts tests/consult-self-reference-pipeline-20261108.test.ts tests/consult-evidence-card-20260927.test.ts tests/consult-evidence-card-v2-20260927.test.ts`
|
||||
- `.venv\Scripts\python scripts/research/capture_counterexample_fixtures_20261109.py`
|
||||
- `.venv\Scripts\python -m pytest tests/test_counterexamples_engine_20261109.py tests/test_round6_r1_r2_narayana.py tests/test_round5_item_reply_n1_k3_20261108.py tests/test_round6_self_reference.py -q`
|
||||
|
||||
前端全量测试和 Python 快速门由 Claude 在验收时跑。
|
||||
|
||||
## 进度记录
|
||||
|
||||
`docs/tasks/PROGRESS-counterexamples-20261109.md`。
|
||||
|
||||
其中要有一张七行的表,列为:反例 | 引擎函数 | 卡上字段 | 修前结果 | 修后结果 | 测试名。
|
||||
|
||||
## 何时停下来选“需拍板”
|
||||
|
||||
- 某个反例要修好,就必须改冻结文件(例如 `functional_benefics.py`)或 `narayana_rath.py` 的规则时。
|
||||
- 引擎本身给出的状态就与占星师的裁定相反时,例如 AD 未决却把 MD 也一起阻塞了。不要自己改引擎,写清楚现象。
|
||||
- 找不到能产生某个反例(例如 0 年段落在当前)的合法合成输入时。写清楚试过哪些输入。
|
||||
Reference in New Issue
Block a user