diff --git a/CHANGELOG.md b/CHANGELOG.md index eafb0c7f..f4fe94b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## 2026-10-18 — 完整解读补上西占对照和五处缺失模块 - 个人报告里的西占对照层不再因为缺文件而整段空白。它仍只作对照,不拿来改印度占星的结论。 -- 完整解读补上上升是否在九分盘同星座、Pushkara 行星简表、Punarphoo 观察,以及 Navamsha / Niryaana Shoola 两套大运。后两套用本站自己的算法,不换回上游那份已停用的算法。 +- 完整解读补上上升是否在九分盘同星座、Pushkara 行星简表、Punarphoo 观察,以及 Navamsha 大运。Navamsha 用本站自己的算法。Niryaana Shoola 先不填表,标明口径更正中,合盘不拿它做应期。 - 页面没有单独的新入口。Skill 版本不变(BUG-1375、BUG-1376)。 ## 2026-10-18 — 婚恋合盘改为上游七项口径,本单只做计算和存储 diff --git a/docs/BUG_HISTORY.md b/docs/BUG_HISTORY.md index ed27d88b..68891215 100644 --- a/docs/BUG_HISTORY.md +++ b/docs/BUG_HISTORY.md @@ -36594,8 +36594,8 @@ - 现象:完整解读没有上升同星座、Pushkara 简表、Punarphoo、Navamsha 大运、Niryaana Shoola 大运这五个键。上游合盘校验因此把「次要大运互证」整项标成空白。 - 触发条件:对比上游 full-reading 的模块键;或用上游合盘校验器读两份完整解读。 - 根因:这几处是上游 2026 年 7 到 9 月加进 full-reading 的,同步时漏了。Punarphoo 文件其实已经在,只是没接上。 -- 修复:前三项按上游函数接上。后两项用本仓 `rashi_dashas_native` 的 `goel_method_1_v1` 和 `goel_nirayana_shoola_v1` 填键,不调用已停用的 `niryaana_shoola_dasha.py`。外层状态给校验器读,期间表仍是本仓的。 -- 验证:模块键覆盖上游那 86 个名字。两位公开名人的 Navamsha 首段星座和年数与上游 Goel Method 1 的算法一致。上游校验器里 Navamsha、Niryaana Shoola 两行不是空白,「次要大运互证」也不再是空白。屏蔽 PyJHora 后相关测试仍通过。 +- 修复:前三项按上游函数接上。Navamsha 用本仓 `rashi_dashas_native` 的 `goel_method_1_v1` 填键,不调用已停用的 `niryaana_shoola_dasha.py`。Niryaana Shoola 先不填表,只写「口径更正中」(修改单 M3):现有表和 Shoola 逐行相同,正确口径另单处理。 +- 验证:模块键覆盖上游那 86 个名字。两位公开名人的 Navamsha 首段星座和年数与上游 Goel Method 1 的算法一致。上游 7a773d13 校验器里 Navamsha 不是空白,Niryaana Shoola 为不适用,「次要大运互证」不因它变成空白。屏蔽 PyJHora 后相关测试仍通过。 - 防复发:`tests/test_full_reading_module_parity.py` 固定 86 个键,并跑上游校验器。`tests/test_rashi_dashas_native.py` 仍禁止那三份文件导入已停用的大运模块。 - 相关记录:BUG-1283、BUG-1375。编号 1370~1374 由 issue #79 预留,本单从 1375 起。 - 复发自:无。 diff --git a/docs/tasks/PROGRESS-full-reading-module-parity-20261018.md b/docs/tasks/PROGRESS-full-reading-module-parity-20261018.md index f27b152d..ab40a815 100644 --- a/docs/tasks/PROGRESS-full-reading-module-parity-20261018.md +++ b/docs/tasks/PROGRESS-full-reading-module-parity-20261018.md @@ -44,3 +44,25 @@ | 快速门 | 未跑 | 同上 | 解释器是本机 Anaconda,不是仓库 `.venv`(工作树里没有 `.venv`)。 + +## 修改单(产品选 A,2026-10-18) + +已 `git merge origin/staging`(合并提交在功能提交之后)。合入后 `scripts/` 根目录 `.py` 为 449,其中多出来的 3 个是本单的两个上游原样文件和本地辅助文件。 + +- M1:删除根目录 `scripts/_script_root.py`。上游文件只接住 `ModuleNotFoundError`,名字找不到时实际抛出的是 `ImportError`,只改 `sys.path` 接不住。按修改单允许的做法,把同样的路径辅助放进 `scripts/_script_root/`(子目录,不占根目录名额)。没有改两个上游文件。full-reading 组装处仍先把仓库根放进 `sys.path`。 +- M2:`ROOT_PY_BUDGET` 原值 446,新值 448。合入后 staging 仍是 446,只为本单两个上游原样文件加名额。删掉辅助文件后根目录为 448。 +- M3:`niryaana_shoola_dasha` 改为占位 `execution_status=blocked`,原因「口径更正中,见 TASK-niryaana-shoola-pvr-20261018」。`navamsha_dasha` 仍用 `goel_method_1_v1`。校验器改读 `upstream_full_synastry_7a773d13`:Niryaana 这一行是 `not_applicable`,次要大运互证不因它 blocked。 +- 断言三栏见 `tests/test_full_reading_module_parity.py` 与 `tests/test_python_hygiene_budget.py`。 + +## 修改单检查 + +解释器:`C:\Users\74082\anaconda3\python.exe`。工作树没有 `.venv`。 + +| 检查 | 命令 | 结果 | +| --- | --- | --- | +| 预算、大运红线、模块键 | `python -m pytest tests/test_python_hygiene_budget.py tests/test_rashi_dashas_native.py tests/test_full_reading_module_parity.py -q` | 21 通过 | +| 屏蔽 PyJHora 后再跑这三份 | 拦截 `jhora` 导入后同一条命令 | 21 通过 | +| 隐私标记 | `python -m pytest tests/test_repo_privacy_markers.py -q` | 通过 | +| 全量 pytest | `python -m pytest tests -q --tb=line` | 失败名单 176 条。上面三份测试都不在里面。抽样是 `python3` 退出码 9009、路径分隔符、控制台用 GBK 打不出表情符号。没有在 `origin/staging` 上把这 176 条再跑一遍做逐名差集。婚恋合盘修改轮在 Windows 上记录的也是 176 条,抽查原因同类。 | + +根目录 `.py` 在删掉辅助文件后是 448,与新上限一致。静默处理只剩上游原文那一处 `scripts/classical_astrology.py:12558`。 diff --git a/scripts/_script_root.py b/scripts/_script_root.py deleted file mode 100644 index 1d20c005..00000000 --- a/scripts/_script_root.py +++ /dev/null @@ -1,14 +0,0 @@ -"""Put the repository root on sys.path for scripts copied from upstream. - -Those modules optionally import ``_script_root`` before their other imports. -This file only adjusts the import path. It does not calculate charts. -""" -from __future__ import annotations - -import sys -from pathlib import Path - -ROOT = Path(__file__).resolve().parents[1] -root_text = str(ROOT) -if root_text not in sys.path: - sys.path.insert(0, root_text) diff --git a/scripts/_script_root/__init__.py b/scripts/_script_root/__init__.py new file mode 100644 index 00000000..a45bb88e --- /dev/null +++ b/scripts/_script_root/__init__.py @@ -0,0 +1,15 @@ +"""Put the repository root on sys.path for scripts copied from upstream. + +Those modules optionally import ``_script_root`` before their other imports. +This package only adjusts the import path. It does not calculate charts. +It lives in a subdirectory so it does not consume a ``scripts/`` root slot. +""" +from __future__ import annotations + +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +root_text = str(ROOT) +if root_text not in sys.path: + sys.path.insert(0, root_text) diff --git a/scripts/jyotish_engine.py b/scripts/jyotish_engine.py index a3d94040..94f9a916 100644 --- a/scripts/jyotish_engine.py +++ b/scripts/jyotish_engine.py @@ -16055,6 +16055,13 @@ def cmd_full_reading(args): 'reference_date': reference_date, 'reason': f'{module_name}_producer_failed:{e}', } + # Upstream western modules import ``scripts.*``. Running this file as a + # script only puts ``scripts/`` on the path, and the copied files treat + # ``_script_root`` as optional. Keep the repository root available here + # instead of adding a local helper under ``scripts/``. + _repo_root = str(Path(__file__).resolve().parents[1]) + if _repo_root not in sys.path: + sys.path.append(_repo_root) try: from unified_western_reading import build_unified_western_reading @@ -16117,20 +16124,18 @@ def cmd_full_reading(args): planet_lons, ) report['modules']['navamsha_dasha'] = _public_secondary_dasha_module(secondary_dashas.get('navamsha')) - report['modules']['niryaana_shoola_dasha'] = _public_secondary_dasha_module( - secondary_dashas.get('niryaana_shoola') - ) except Exception as e: report['modules']['navamsha_dasha'] = { 'status': 'blocked', 'reason': f'navamsha_dasha_producer_failed:{e}', 'periods': [], } - report['modules']['niryaana_shoola_dasha'] = { - 'status': 'blocked', - 'reason': f'niryaana_shoola_dasha_producer_failed:{e}', - 'periods': [], - } + # F2b: do not publish the current Niryaana Shoola table. It matches Shoola. + # The synastry validator marks this row not applicable, so the pair task stays open. + report['modules']['niryaana_shoola_dasha'] = { + 'execution_status': 'blocked', + 'reason': '口径更正中,见 TASK-niryaana-shoola-pvr-20261018', + } _record_stage_timing( stage_timings, 'dasha_and_core_varga_stack', diff --git a/tests/test_full_reading_module_parity.py b/tests/test_full_reading_module_parity.py index b4d4e278..a4f26066 100644 --- a/tests/test_full_reading_module_parity.py +++ b/tests/test_full_reading_module_parity.py @@ -15,9 +15,12 @@ from scripts.punarphoo import detect_punarphoo from scripts.rashi_dashas_native import SIGN_LORDS, navamsha_sign ROOT = Path(__file__).resolve().parents[1] +# 原值:docs/research/upstream_full_synastry_bde5d615/.../validate_full_synastry_packets.py.txt +# 新值:docs/research/upstream_full_synastry_7a773d13/.../validate_full_synastry_packets.py.txt +# 原因:修改单 M3。新校验器把 Niryaana Shoola 固定判为 not_applicable,合盘不用这套大运。 VALIDATOR = ( ROOT - / "docs/research/upstream_full_synastry_bde5d615/skill/scripts/validate_full_synastry_packets.py.txt" + / "docs/research/upstream_full_synastry_7a773d13/skill/scripts/validate_full_synastry_packets.py.txt" ) # Baseline full-reading keys on origin/staging b3ef2d815, plus the five keys this @@ -97,9 +100,12 @@ def _goel_method_1_first(d9_lagna: int, lord_sign_by_sign: dict[int, int]) -> tu def test_unified_western_reading_module_imports() -> None: + assert not (ROOT / "scripts" / "_script_root.py").exists() + import classical_astrology import unified_western_reading assert callable(unified_western_reading.build_unified_western_reading) + assert callable(classical_astrology.build_classical_astrology_packet) def test_engine_does_not_import_the_retired_niryaana_file() -> None: @@ -141,8 +147,10 @@ def test_secondary_dashas_use_native_profiles_and_match_goel_method_1(reports) - niryaana = modules["niryaana_shoola_dasha"] assert navamsha["status"] == "parameter_sensitive" assert navamsha["profile_id"] == "goel_method_1_v1" - assert niryaana["status"] == "parameter_sensitive" - assert niryaana["profile_id"] == "goel_nirayana_shoola_v1" + assert niryaana == { + "execution_status": "blocked", + "reason": "口径更正中,见 TASK-niryaana-shoola-pvr-20261018", + } assert navamsha["native_result"]["status"] == "listed" first = navamsha["periods"][0] d9 = modules["varga_full"]["D9_Navamsa"] @@ -173,8 +181,11 @@ def test_synastry_validator_accepts_the_secondary_dashas(reports) -> None: validator = _validator() receipt = validator.build_execution_receipt(reports["pitt"], reports["jolie"]) rows = {row["technique"]: row for row in receipt["individual_technique_audit"]} - for label in ("Navamsha Dasha", "Niryaana Shoola Dasha"): - assert rows[label]["status"] in {"executed", "parameter_sensitive"} + assert rows["Navamsha Dasha"]["status"] in {"executed", "parameter_sensitive"} + # 原值:Niryaana Shoola 必须是 executed 或 parameter_sensitive + # 新值:not_applicable + # 原因:修改单 M3。上游 7a773d13 校验器对这一行固定判不适用,合盘任务不因它 blocked。 + assert rows["Niryaana Shoola Dasha"]["status"] == "not_applicable" tasks = {row["task"]: row for row in receipt["pair_execution_tasks"]} assert tasks["secondary-dasha convergence and disagreement review"]["status"] != "blocked" diff --git a/tests/test_python_hygiene_budget.py b/tests/test_python_hygiene_budget.py index 7d081e84..85942e7c 100644 --- a/tests/test_python_hygiene_budget.py +++ b/tests/test_python_hygiene_budget.py @@ -11,8 +11,18 @@ SCRIPTS = ROOT / "scripts" # Measured at the end of TASK-python-hygiene-20261013. New silent handlers # must log or carry ``# noqa: BLE001`` with a reason. New research scripts # belong in scripts/audit or scripts/research. -SILENT_EXCEPT_BUDGET = 0 -ROOT_PY_BUDGET = 446 +# 原值:0 +# 新值:1 +# 原因:产品 2026-10-18(issue #81 选 A)要求 classical_astrology.py 保持上游原文。 +# 其中 scripts/classical_astrology.py:12558 是 except Exception: continue。本单不得改这个文件。 +# 本地新写的静默处理仍不得出现;允许的命中只有这一处。 +SILENT_EXCEPT_BUDGET = 1 +UPSTREAM_SILENT_EXCEPT = "scripts/classical_astrology.py:12558" +# 原值:446 +# 新值:448 +# 原因:产品 2026-10-18(issue #81 选 A):上游原样文件按上游路径放在 scripts/ 根目录, +# classical_astrology.py、unified_western_reading.py 两个;本地新写的文件仍不得增加。 +ROOT_PY_BUDGET = 448 def _silent_handlers() -> list[str]: @@ -45,6 +55,7 @@ def _silent_handlers() -> list[str]: def test_silent_except_budget_does_not_grow() -> None: hits = _silent_handlers() + assert hits == [UPSTREAM_SILENT_EXCEPT] assert len(hits) <= SILENT_EXCEPT_BUDGET, hits