fix(yogas): lunar and solar yogas count only the five true planets; retire duplicate rules (upstream 2dd6062a)
bvr_002..004 (Sunaphaa/Anaphaa/Duradhara) and bvr_016..018 (Vesi/Vosi/ Ubhayachara) take upstream yinduzhanxing 2dd6062a's logic (Mars..Saturn only). kemadruma_yoga also ignores the nodes (product decision: classical definition; upstream still counts them). The six lunar/solar duplicates of upstream's RETIRED_RULE_IDS are retired; upstream's four other retirements are out of scope. TASK-upstream-sync4-20261002 T5. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
42d1582f4c
commit
f3ed950982
@@ -0,0 +1,48 @@
|
||||
"""sync4 T5: Sunaphaa / Anaphaa / Duradhara (Moon) and Vesi / Vosi / Ubhayachara
|
||||
(Sun) count only Mars, Mercury, Jupiter, Venus, Saturn; Rahu / Ketu alone next
|
||||
to the Moon or Sun do not form them, and Kemadruma ignores the nodes too.
|
||||
Rule logic for the six BVR rules is upstream yinduzhanxing 2dd6062a."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from scripts.yoga_engine import RETIRED_RULE_IDS, YogaEngine
|
||||
|
||||
RULES = Path(__file__).resolve().parents[1] / "references" / "yoga_rules.json"
|
||||
SIGNS = ["Aries", "Taurus", "Gemini", "Cancer", "Leo", "Virgo",
|
||||
"Libra", "Scorpio", "Sagittarius", "Capricorn", "Aquarius", "Pisces"]
|
||||
|
||||
|
||||
def _chart(**signs: str) -> dict:
|
||||
return {name: {"sign": sign, "house": SIGNS.index(sign) + 1, "degree": 15.0, "longitude": SIGNS.index(sign) * 30 + 15.0}
|
||||
for name, sign in signs.items()}
|
||||
|
||||
|
||||
def _names(planets: dict) -> set[str]:
|
||||
return {row["name"] for row in YogaEngine(str(RULES)).detect(planets, "Aries")}
|
||||
|
||||
|
||||
BASE = dict(Sun="Aquarius", Moon="Libra", Mars="Aquarius", Mercury="Aquarius",
|
||||
Jupiter="Cancer", Venus="Pisces", Saturn="Capricorn", Rahu="Pisces")
|
||||
|
||||
|
||||
def test_ketu_alone_behind_the_moon_is_not_anaphaa() -> None:
|
||||
names = _names(_chart(**BASE, Ketu="Virgo"))
|
||||
assert not {"Anaphaa Yoga", "Sunaphaa Yoga", "Duradhara Yoga"} & names
|
||||
|
||||
|
||||
def test_saturn_behind_the_moon_is_anaphaa() -> None:
|
||||
signs = {**BASE, "Saturn": "Virgo", "Ketu": "Virgo"}
|
||||
assert "Anaphaa Yoga" in _names(_chart(**signs))
|
||||
|
||||
|
||||
def test_ketu_alone_after_the_sun_is_not_vesi() -> None:
|
||||
signs = {**BASE, "Sun": "Leo", "Ketu": "Virgo", "Mars": "Capricorn", "Mercury": "Capricorn"}
|
||||
assert "Vesi Yoga" not in _names(_chart(**signs))
|
||||
|
||||
|
||||
def test_duplicate_lunar_solar_rules_are_retired() -> None:
|
||||
assert {"sunapha_yoga", "durudhura_yoga", "voshi_yoga", "veshi_yoga", "ubhayachari_yoga"} <= RETIRED_RULE_IDS
|
||||
ids = {rule["id"] for rule in YogaEngine(str(RULES)).rules}
|
||||
assert not ids & RETIRED_RULE_IDS
|
||||
@@ -161,7 +161,11 @@ def _globals_for(engine: YogaEngine, chart_index: int) -> dict:
|
||||
# ---------------------------------------------------------------------------
|
||||
def test_cached_compile_matches_pre_change_behaviour_for_every_rule_expression(engine) -> None:
|
||||
"""全部 192 条去重表达式,缓存版与参照版在三张示例盘上逐条同值。"""
|
||||
assert len(RULE_EXPRESSIONS) >= 190, "规则表表达式数量异常,等价证明的覆盖面不足"
|
||||
# 原值: >= 190
|
||||
# 新值: >= 184
|
||||
# 原因: TASK-upstream-sync4-20261002 T5:bvr_002~004、bvr_016~018 六条从 custom 表达式改为
|
||||
# 声明式 has_planet_in_house_from(上游 2dd6062a),表达式条数相应减少;等价证明仍覆盖其余全部表达式
|
||||
assert len(RULE_EXPRESSIONS) >= 184, "规则表表达式数量异常,等价证明的覆盖面不足"
|
||||
|
||||
mismatches = []
|
||||
for chart_index in range(len(SAMPLE_CHARTS)):
|
||||
|
||||
Reference in New Issue
Block a user