Compare commits

..
Author SHA1 Message Date
ClaudeandClaude Opus 5.5 66c2bab6b8 docs(task): FIX-rect-layer-alias-1.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-09 14:37:49 +08:00
ClaudeandClaude Opus 5.5 a3f941586f docs(task): brief for rect-layer-alias (2026-11-09)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-09 14:03:27 +08:00
2 changed files with 135 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
# #184 范围补充:占星师第七轮回复 P1(2026-11-09)
本文件补充 `TASK-rect-layer-alias-20261109.md`。两者冲突时以本文件为准。占星师原文见她的《第七轮验收与 R2 裁定回复》§5 P1。
## 她的要求
1. **按真实计分粒度比较**,不能靠改缺失层的名称让合成例通过。原文:“禁止用改缺失名称的测试代替真实部分缺失路径。”
- 每一项计分贡献都要带上这些信息:`event_id`、`technique`/`layer`、`dependency`、`profile`、`points`、缺失原因。复用现有的计分证据,不另起一套。
- 如果大运和小运的合并分暂时拆不开,就对所有候选一致地排除这一项合并贡献,并写明理由。不能把缺这一项的候选当 0 分,而让有这一项的候选继续计分。
2. **区分三个计数**:`top_candidate_count`、`top_segment_count`、`unique_time`。
- 例子:共同分数 8:8,候选区间 12:00–12:01,`comparable_tied=false`。这可能是一个连续领先的区间,但不是唯一的分钟。
- 代表分钟不能冒充唯一解。
3. **`missing_mandatory_layers` 必须以真实字段暴露出来。** 现在回执里这个字段是 `null`,但 reason 里又写了 missing_mandatory_layers,两边对不上。要回传实际的字段路径和缺失列表,`null` 不能被读成“没有缺失”。
## 本单因此改为
- 原任务书里的层名对照(`Narayana_AD → Narayana_MD_AD`)**只能作为输入适配**:只在她的原文层名进入产品时做一次映射,并在回执里记下映射前后的名称。验收不能依赖它让合成例通过。
- 主要工作是上面第 1–3 条,改动范围限于 `scripts/active_rectification_events.py` 和相关回执。
- 反例测试至少包括:
- 真实路径上只缺小运(AD),大运(MD)有值;
- 大运和小运的合并贡献拆不开;
- 有负分的贡献;
- 8:8 连续区间:`top_segment_count = 1`,`unique_time = false`;
- `missing_mandatory_layers` 是非空列表,并且字段路径可以读到。
- 不改旧的 `can_apply` 含义,不改历史评分阈值。
- 不得自行写“产品决定”或“裁定”;任务书没写到的取舍一律选需拍板。
BUG-1827。自测命令与原任务书相同。
@@ -0,0 +1,107 @@
# TASK:校时可比性——占星师原文层名 Narayana_AD 与产品层名对齐(#184,BUG-1827,2026-11-09)
- Gitea:#184
- 分支:`codex/rect-layer-alias-20261109`(基于 staging `afac4ea92f293a4d2bc81f62563487d26f92e4d2`)
- Bug 编号:BUG-1827(开工时核对 `docs/BUG_HISTORY.md` 的最大编号;1809–1830 已为这一批预留)
- 负责验收:Claude(jyotisha-2a)
- 范围:只改校时可比性判定 `assess_leader_comparability` 读层名的那一步。打分、事件引擎、置信度门槛都不改。
不得自行写“产品决定/裁定”;任务书没写的取舍一律选需拍板。
## 现象(第七轮验收包 `rectification/her_synthetic_12_00_vs_12_01.json`)
占星师的匿名合成例(验收清单 §10):两个候选 12:00 / 12:01,总分 10 / 8,12:01 有一件事(e5)因为缺 Narayana 小运而**整件不计分**;5 件事、3 个领域。
| 写法 | 12:01 的 `missing_layers` | `coverage_comparison.comparison` | `comparable_leader` |
| --- | --- | --- | --- |
| 照她原文 | `["Narayana_AD"]` | `not_reducible`,`unreducible_layers = ["Narayana_AD"]` | `null` |
| 照产品测试(`tests/test_rectification_comparability_bug1801.py`) | `["Narayana_MD_AD"]` | `common_coverage`,`common_scores` 8 : 8 | 12:00–12:01(2 分钟) |
同一个例子,两边结果不同,只因为层名不一样。
## 根因(afac4ea9 实测,行号以符号为准)
- `scripts/active_rectification_events.py` 的 `EVENT_GATING_LAYERS`(约 :296)只认产品层名 `Narayana_MD_AD`:缺它时整件事不计分,可比性判定把这件事从所有候选里一起拿掉,再按共同覆盖比较。
- `assess_leader_comparability`(约 :317)把不在 `EVENT_GATING_LAYERS`、也不能按层拆分的差异层算作 `unexplained` → `not_reducible`。
- **注意产品自己也用 `Narayana_AD` 这个名字,但意思不同**:`scripts/active_rectification_event_engine.py` 约 :760–764(占星师第六轮 R2)在“大运已定、只缺小运”时记 `Narayana_AD`,**这件事照常计分**(只缺小运那一项,分数折在 `dasha_varga_core` 里拆不开)。这时 `not_reducible` 是对的,不能改。
- 她原文的 `Narayana_AD` = 这件事整件不计分 = 产品的 `Narayana_MD_AD`。
- 产品的 `Narayana_AD` = 这件事计分、只缺小运那一项。
- 所以**不能**无条件把 `Narayana_AD` 换成 `Narayana_MD_AD`,否则产品自己的“只缺小运”会被当成整件缺失,变成“未知当相等”(她 R2 明确禁止)。
## 要做的
### 1. 对照表(`scripts/active_rectification_events.py`,紧挨 `EVENT_GATING_LAYERS`)
```python
# 占星师原文层名 → 产品层名(只在“该候选整件事缺失”时适用,见 _explained_by_alias)。
ASTROLOGER_EVENT_LAYER_ALIASES: Final[dict[str, str]] = {
"Narayana_AD": "Narayana_MD_AD",
}
```
表里只放 `Narayana_AD` 这一条。别的层名(如 Vimshottari 各级)占星师没有给出原文写法,不要猜着加;需要时选“需拍板”。
### 2. 条件判定(同文件,新私有函数,供 `assess_leader_comparability` 调用)
对每个“差异层” `L`(现有代码里的 `differing`):
- 若 `L` 在 `EVENT_GATING_LAYERS` 或可拆分层里:照旧算已解释。
- 若 `L` 在 `ASTROLOGER_EVENT_LAYER_ALIASES` 里,**且**对每个带 `L` 的候选都满足:
1. 该候选至少有一件事整件缺失(它的覆盖单元里缺少别的候选有的某个 `event_id` 的全部单元);
2. 该候选**每一件**出现在它自己覆盖单元里的事,单元集合与共同覆盖一致(没有“事件在、但少了某层”的情况);
3. 该候选的 `missing_layers` 里没有其他 `EVENT_GATING_LAYERS` 成员(否则说不清缺失的那件事是哪一层造成的);
则 `L` 视为对照表里的产品层名,算已解释。
- 只要有一个带 `L` 的候选不满足以上三条,`L` 照旧算 `unexplained`,结果仍是 `not_reducible`。
### 3. 输出记录
`coverage_comparison` 在用到对照表时多一个字段 `layer_aliases_applied: {"Narayana_AD": "Narayana_MD_AD"}`;没用到时不出现这个字段。其他字段、顺序、取值都不变。
### 4. 测试 `tests/test_rectification_layer_alias_bug1827.py`
只用合成匿名行(照 `tests/test_rectification_comparability_bug1801.py` 的 `_row` 写法):
1. 她原文写法(12:01 缺 e5,`missing_layers = ["Narayana_AD"]`)与产品测试写法(`["Narayana_MD_AD"]`)跑 `adjudicate_candidate_rows`:`top_score`、`second_score`、`winning_segment`、`provisional_leader`、`comparable_leader`、`leader_status`、`confidence`、`can_apply`、`reasons`,以及 `coverage_comparison` 中除 `layer_aliases_applied` 以外的全部字段,**两边完全相等**;原文写法的 `layer_aliases_applied == {"Narayana_AD": "Narayana_MD_AD"}`,产品写法没有该字段。
2. 产品自己的“只缺小运”:两个候选都有 e1–e5,12:01 带 `layer_points`、`missing_layers = ["Narayana_AD"]`、e5 的单元与 12:00 相同但分数不同 → 仍是 `not_reducible`,`unreducible_layers == ["Narayana_AD"]`,`comparable_leader is None`,没有 `layer_aliases_applied`。
3. 同一候选既缺整件事又有 `Narayana_MD_AD` 以外的另一个门控层(如 `D9`)同时带 `Narayana_AD` → 不套用对照表,`not_reducible`。
4. `tests/test_rectification_comparability_bug1801.py` 的全部用例不改、照样通过。
另跑一遍验收包脚本作对照(只读,不改它):
`PYTHONHASHSEED=0 python -I /workspace/eval-upstream-1107/acceptance_round7/scripts/rect_her_synthetic.py <本分支工作树> <输出.json>` 在 Windows 上没有这个路径,**不要求** Grok 跑;Claude 验收时跑。
### 5. 记录
- `docs/BUG_HISTORY.md` 末尾追加 BUG-1827(关联 BUG-1801、BUG-1759、BUG-1785;写明两种 `Narayana_AD` 含义的区别)。只在末尾追加。
- `docs/tasks/PROGRESS-rect-layer-alias-20261109.md`。
## 允许改的文件(只有这些)
- `scripts/active_rectification_events.py`:只加对照表常量、一个私有判定函数、`assess_leader_comparability` 里调用它和写 `layer_aliases_applied` 的几行。改动处写“原值 / 新值 / 原因”三栏注释,原因写 `占星师验收清单 §10:原文层名 Narayana_AD 与产品 Narayana_MD_AD 对齐(BUG-1827)`。
- 新建 `tests/test_rectification_layer_alias_bug1827.py`、`docs/tasks/PROGRESS-rect-layer-alias-20261109.md`
- `docs/BUG_HISTORY.md`(末尾追加)
## 不要碰
- `references/**`(占星师方法文件),一字不改;包括 `references/product_runtime_contract.md`。
- `frontend/**` 全部,特别是 `frontend/src/lib/consult-preset-prompts.ts`。
- `scripts/active_rectification_event_engine.py`:产品记 `Narayana_AD` / `Narayana_MD_AD` 的地方一字不改(层名的产生方不改,只改判定方怎么读)。
- `scripts/chart_choice/**`、`scripts/research/precision_gate_lib.py`:不改。
- `EVENT_GATING_LAYERS` 的成员、`_coverage_units`、`adjudicate_candidate_rows` 的打分与置信度门槛、`COMPARABILITY_POLICY` 名字:不改。
- 冻结文件只许 import 调用,不许改:`scripts/jyotish_api_server.py`、`scripts/jyotish_engine.py`、`scripts/domain_calculation_service.py`、`scripts/dasha_analyzer.py`、`scripts/narayana_dasha.py`、`scripts/shadbala.py`、`scripts/ashtakavarga.py`、`scripts/jaimini.py`、`scripts/varga.py`、`scripts/functional_benefics.py`、`scripts/divisional_charts_extended.py`。
- 其他未完成单子的文件:`scripts/ondemand_calc/**`(#174–#178)、`frontend/src/mastra/consultation-tools.ts`(#171)、`frontend/src/lib/consultation-evidence-card.ts`(#170 / #172)、`frontend/src/mastra/consultation-workflow.ts` 与 `frontend/src/lib/consultation-route-service.ts`(#185)。
- R2 扩大范围(`seed_only_v0` 低档平局当相等)在等占星师选 A–D,本单不碰。
- 既有断言不得弱化。
## 自测命令(Windows / PowerShell)
- `.venv\Scripts\python -m pytest tests/test_rectification_layer_alias_bug1827.py tests/test_rectification_comparability_bug1801.py tests/test_active_rectification_events.py tests/test_rectification_api_can_apply_guard_bug1802.py tests/test_rectification_technique_contract.py -q`
Python 快速门、前端全量测试和 eslint 由 Claude 在验收时跑。
## 何时停下来选“需拍板”
- 上面三条条件不足以区分两种 `Narayana_AD`,必须改事件引擎或层名产生方时。
- 需要加 `Narayana_AD` 以外的对照条目时。
- 任何改动会让既有校时用例(BUG-1801 / 1802 / 1785 / 1759)结果变化时。
- 任务书没写到的任何取舍。