fix(yoga): D9 debilitation only weakens Pancha Mahapurusha (BUG-1213)
Round-4 astrologer ruling 2026-10-03 Q1: the yoga stays formed with d9_dignity_modifier='weakened' and the reason 'D9 落陷,兑现减弱'; only a failed D1 condition is not_formed. The D9 sign is derived from the longitude when the caller does not pass navamsa_sign, so the card, report and /api/pancha_mahapurusha paths all check it. None of the nine public celebrity charts change. 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
52b3061fe5
commit
bc03bba26b
@@ -2,7 +2,7 @@
|
||||
|
||||
`scripts/pancha_mahapurusha.py` is the only detector: kendras from the Lagna,
|
||||
retrograde does not cancel, combustion and malefic conjunction / aspect only
|
||||
reduce the yoga, D9 debilitation still cancels it (current behaviour). The
|
||||
reduce the yoga, D9 debilitation only weakens it (round-4 ruling Q1, BUG-1213). The
|
||||
data-driven `mahapurusha_*`, `*_own`, `moolatrikona_*`, `hamsa_trikona` and the
|
||||
BVR Maalavya duplicate are `reference_only`, and `yogas_doshas` keeps its old
|
||||
aggregate for reference only, so a yoga the main detector rejects cannot come
|
||||
@@ -69,12 +69,42 @@ def test_malefic_aspect_reduces() -> None:
|
||||
assert _one({"Jupiter": _row("Cancer", 5.0), "Ketu": _row("Capricorn", 10.0)}, "Hamsa Yoga")["strength"] == "full"
|
||||
|
||||
|
||||
def test_d9_debilitation_still_cancels_when_the_caller_gives_d9() -> None:
|
||||
# Current behaviour kept (ruling silent): checked only when `navamsa_sign`
|
||||
# is supplied; product paths do not supply it.
|
||||
hamsa = _one({"Jupiter": _row("Cancer", 21.0, navamsa_sign="Capricorn")}, "Hamsa Yoga")
|
||||
assert hamsa["is_valid"] is False and hamsa["strength"] == "cancelled"
|
||||
assert _one({"Jupiter": _row("Cancer", 21.0)}, "Hamsa Yoga")["is_valid"] is True
|
||||
def test_d9_debilitation_only_weakens() -> None:
|
||||
# 原值:传 navamsa_sign 落陷 → is_valid False、strength cancelled(不传则不检查)
|
||||
# 新值:formed 不变,d9_dignity_modifier = weakened,原因「D9 落陷,兑现减弱」;
|
||||
# 不传 navamsa_sign 时由经度推出 D9(巨蟹 21° 的 D9 是摩羯)
|
||||
# 原因:占星师第四轮裁定 2026-10-03 问 1(BUG-1213)
|
||||
for row in (_row("Cancer", 21.0, navamsa_sign="Capricorn"), _row("Cancer", 21.0)):
|
||||
hamsa = _one({"Jupiter": row}, "Hamsa Yoga")
|
||||
assert (hamsa["status"], hamsa["is_valid"], hamsa["strength"]) == ("formed", True, "reduced")
|
||||
assert hamsa["d9_dignity_modifier"] == "weakened" and hamsa["d9_sign"] == "Capricorn"
|
||||
assert hamsa["reductions"] == ["D9 落陷,兑现减弱"]
|
||||
strong = _one({"Jupiter": _row("Cancer", 5.0)}, "Hamsa Yoga")
|
||||
assert strong["d9_dignity_modifier"] is None and strong["strength"] == "full"
|
||||
|
||||
|
||||
def test_d1_condition_not_met_is_not_formed() -> None:
|
||||
# Jupiter exalted but in the 9th from a Pisces Lagna (trikona, not kendra).
|
||||
rows = detect_pancha_mahapurusha({"Jupiter": _row("Cancer", 5.0, asc="Pisces")}, include_not_formed=True)
|
||||
hamsa = next(item for item in rows if item["planet"] == "Jupiter")
|
||||
assert (hamsa["status"], hamsa["is_valid"]) == ("not_formed", False)
|
||||
# Kendra but neither own nor exalted.
|
||||
rows = detect_pancha_mahapurusha({"Jupiter": _row("Leo", 5.0, asc="Leo")}, include_not_formed=True)
|
||||
assert next(item for item in rows if item["planet"] == "Jupiter")["status"] == "not_formed"
|
||||
assert detect_pancha_mahapurusha({"Jupiter": _row("Leo", 5.0, asc="Leo")}) == []
|
||||
|
||||
|
||||
def test_d9_weakened_yoga_reaches_the_card_and_the_report_rows_alike() -> None:
|
||||
planets = {"Jupiter": _row("Cancer", 21.0), "Moon": _row("Taurus", 3.0)}
|
||||
rows = pancha_mahapurusha_rows(planets)
|
||||
assert rows[0]["d9_dignity_modifier"] == "weakened"
|
||||
assert "D9 落陷,兑现减弱" in rows[0]["combination"]
|
||||
engine_rows = [row for row in YogaEngine(str(RULES)).detect(planets, "Cancer") if row.get("category") == "mahapurusha"]
|
||||
assert engine_rows == rows
|
||||
chart_rows = JyotishAPIHandler._detect_yogas(None, planets, SIGNS.index("Cancer"))
|
||||
entry = _compact_yoga_entry(next(row for row in chart_rows if row.get("category") == "PMC"))
|
||||
layer = build_traditional_yogas({"raman_support": {"yogas": {"status": "executed", "hits": [], "ungoverned_detected": [entry]}}})
|
||||
assert layer["names"] == ["Hamsa Yoga(Jupiter;部分减弱:D9 落陷,兑现减弱)"]
|
||||
|
||||
|
||||
def test_reference_only_rules_never_run() -> None:
|
||||
@@ -85,14 +115,17 @@ def test_reference_only_rules_never_run() -> None:
|
||||
|
||||
|
||||
def test_a_rejected_yoga_does_not_come_back_by_another_path() -> None:
|
||||
# Jupiter exalted in the Lagna (Cancer) but debilitated in D9; also in a
|
||||
# trikona, which the retired hamsa_trikona rule used to accept.
|
||||
planets = {"Jupiter": _row("Cancer", 21.0, navamsa_sign="Capricorn"), "Moon": _row("Taurus", 3.0), "Sun": _row("Aries", 10.0),
|
||||
"Mars": _row("Gemini", 1.0), "Mercury": _row("Pisces", 2.0), "Venus": _row("Aries", 2.0),
|
||||
"Saturn": _row("Leo", 2.0), "Rahu": _row("Virgo", 2.0), "Ketu": _row("Pisces", 2.0)}
|
||||
engine_rows = YogaEngine(str(RULES)).detect(planets, "Cancer")
|
||||
# 原值:木星在上升巨蟹入旺但 D9 落陷(被判不成立)作为「被拒格局」
|
||||
# 新值:木星入旺巨蟹但在双鱼上升的第 9 宫(三方宫,非角宫),D1 条件不成立
|
||||
# 原因:第四轮问 1(BUG-1213)D9 落陷不再拒绝格局;被拒样例改为 D1 不成立,
|
||||
# 仍是已退役的 hamsa_trikona 规则曾接受的三方宫
|
||||
asc = "Pisces"
|
||||
planets = {"Jupiter": _row("Cancer", 5.0, asc=asc), "Moon": _row("Taurus", 3.0, asc=asc), "Sun": _row("Aries", 10.0, asc=asc),
|
||||
"Mars": _row("Gemini", 1.0, asc=asc), "Mercury": _row("Aquarius", 2.0, asc=asc), "Venus": _row("Aries", 2.0, asc=asc),
|
||||
"Saturn": _row("Leo", 2.0, asc=asc), "Rahu": _row("Virgo", 2.0, asc=asc), "Ketu": _row("Pisces", 2.0, asc=asc)}
|
||||
engine_rows = YogaEngine(str(RULES)).detect(planets, asc)
|
||||
assert not [row for row in engine_rows if "Hamsa" in row["name"] or "汉萨" in row.get("name_cn", "")]
|
||||
chart_rows = JyotishAPIHandler._detect_yogas(None, planets, SIGNS.index("Cancer"))
|
||||
chart_rows = JyotishAPIHandler._detect_yogas(None, planets, SIGNS.index(asc))
|
||||
assert not [row for row in chart_rows if "Hamsa" in row["name"]]
|
||||
merged = merge_detected_yogas(
|
||||
[entry for entry in map(_compact_yoga_entry, chart_rows) if entry],
|
||||
@@ -100,13 +133,17 @@ def test_a_rejected_yoga_does_not_come_back_by_another_path() -> None:
|
||||
)
|
||||
layer = build_traditional_yogas({"raman_support": {"yogas": {"status": "executed", "hits": [], "ungoverned_detected": merged}}})
|
||||
assert not [name for name in layer["names"] if "Hamsa" in name]
|
||||
aggregate = calc_all_yogas_doshas(planets, {}, "Cancer", "Moon", "Taurus", 11, 12, 10, "Gemini")
|
||||
aggregate = calc_all_yogas_doshas(planets, {}, asc, "Moon", "Taurus", 11, 12, 10, "Gemini")
|
||||
assert aggregate["pancha_mahapurusha"]["status"] == "reference_only"
|
||||
assert aggregate["pancha_mahapurusha"]["yogas"] == []
|
||||
|
||||
|
||||
def test_reduced_yoga_reaches_the_card_with_its_reasons() -> None:
|
||||
planets = {"Jupiter": _row("Cancer", 5.0), "Saturn": _row("Capricorn", 10.0)}
|
||||
# 原值:土星摩羯 10°(D9 白羊,落陷;旧规则只在给 navamsa_sign 时检查)
|
||||
# 新值:土星摩羯 2°(D9 摩羯,本宫),断言不变
|
||||
# 原因:BUG-1213 起 D9 由经度推出,摩羯 10° 的萨萨会多一条「D9 落陷」减弱;
|
||||
# 本用例只测凶星照的原因上卡,换成 D9 不落陷的度数
|
||||
planets = {"Jupiter": _row("Cancer", 5.0), "Saturn": _row("Capricorn", 2.0)}
|
||||
all_rows = pancha_mahapurusha_rows(planets)
|
||||
engine_rows = [row for row in YogaEngine(str(RULES)).detect(planets, "Cancer") if row.get("category") == "mahapurusha"]
|
||||
assert engine_rows == all_rows
|
||||
|
||||
Reference in New Issue
Block a user