From 1dd8e11bffd6f16fae03363b9cf0b3ce3211cec5 Mon Sep 17 00:00:00 2001 From: Jesse_Chen Date: Sun, 4 Oct 2026 07:35:37 +0800 Subject: [PATCH] feat(narayana-rath): flag Wadiyar pairs as book_software_rule8_exception (BUG-1226) Round-6 ruling Q6b: Table 25 Gemini/Sagittarius and Virgo/Pisces are the book software's seventh-level Rule 8 special case; keep the general result (Sagittarius, Pisces at level 5), every Rath output carries the note (known_book_differences), test pins the two pairs. Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE --- scripts/narayana_rath.py | 21 +++++++++++++++++++++ tests/test_narayana_rath_book_tables.py | 23 ++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/scripts/narayana_rath.py b/scripts/narayana_rath.py index c3655721..c8082c18 100644 --- a/scripts/narayana_rath.py +++ b/scripts/narayana_rath.py @@ -96,6 +96,26 @@ BOOK_EXAMPLES = { "stronger than Cancer. Audit docs/research/shared_engine_reuse_audit_2026_10_03.md N1."), }, } +# Book software verdicts the general rule does not follow (round-6 ruling +# Q6b, BUG-1226): Table 25 (Krishnaraja Wadiyar IV) takes Gemini over +# Sagittarius and Virgo over Pisces; the seven general levels decide +# Sagittarius / Pisces at level 5 (Mercury 1.3 deg vs Jupiter 10.0 deg). Only +# the book software's Rule 8 at the seventh level separates them that way — a +# software special case. The general result is kept and every output carries +# this note. +BOOK_SOFTWARE_RULE8 = "book_software_rule8_exception" +BOOK_SOFTWARE_DIFFERENCES = { + BOOK_SOFTWARE_RULE8: { + "book_table": "Table 25", + "pairs": [{"book": "Gemini", "general_rule": "Sagittarius", "general_level": 5}, + {"book": "Virgo", "general_rule": "Pisces", "general_level": 5}], + "kept": "general_rule", + "note": "原书软件判定差异:原书软件用第 7 级 Rule 8 取双子、处女;通则第 5 级取射手、双鱼,保持通则", + "note_en": ("Book software verdict differs: the book's software used Rule 8 at the seventh level to take " + "Gemini and Virgo; the general rule takes Sagittarius and Pisces at level 5 and is kept"), + "ruling": "astrologer round 6, 2026-10-04, Q6b (p.36, p.95)", + }, +} KETU_FIRST_NOTE = "PyJHora 兼容:计都优先" KETU_FIRST_NOTE_EN = "PyJHora-compatible: Ketu takes precedence" SOURCE = { @@ -461,6 +481,7 @@ def calc_narayana_rath(lagna_sign_idx: int, planet_lons: Dict[str, float], "source": SOURCE, "lagna_sign": SIGNS[lagna_sign_idx], "antardasha_start_rule": "stronger_of_md_sign_and_seventh_then_its_lord_sign (p.48, p.50 note 2)", + "known_book_differences": BOOK_SOFTWARE_DIFFERENCES, } if seed_sign_idx is not None: selection = {"status": "explicit", "selected_sign_idx": seed_sign_idx, diff --git a/tests/test_narayana_rath_book_tables.py b/tests/test_narayana_rath_book_tables.py index 99d8a7c2..6f04bdb2 100644 --- a/tests/test_narayana_rath_book_tables.py +++ b/tests/test_narayana_rath_book_tables.py @@ -164,7 +164,9 @@ VERDICT_TABLES = { # Expected misses, documented: Wadiyar Gemini/Sagittarius and Virgo/Pisces — # the book takes Gemini and Virgo; the general rule decides at level 5 # (Mercury 1.3 deg vs Jupiter 10.0 deg) for Sagittarius and Pisces. Not -# sensitive to node mode or ayanamsa (audit). Open question to the astrologer. +# sensitive to node mode or ayanamsa (audit). Round-6 ruling Q6b: the book's +# software used Rule 8 at the seventh level — a software special case; keep +# the general result, flagged `book_software_rule8_exception` (BUG-1226). EXPECTED_SIGN_MISSES = {("Table 25", "Gemini", "Sagittarius"), ("Table 25", "Virgo", "Pisces")} # Dual lords (Aquarius, Scorpio): book Table 23 Aquarius = Saturn (ours Rahu), # Table 25 Scorpio = Ketu (ours Mars). @@ -264,3 +266,22 @@ def test_table25_taurus_md_is_the_saturn_exception_and_carries_the_book_divergen assert rule["direction"]["direction"] == "zodiacal" p47, js = rule["direction"]["book_divergence"] assert (p47["direction"], p47["differs"]) == ("reverse", True) # Taurus is even: p.47 would run the ADs backwards + + +def test_wadiyar_pairs_are_the_flagged_book_software_rule8_exception() -> None: + """Round-6 ruling Q6b (BUG-1226): the two Table 25 misses are exactly the + registered `book_software_rule8_exception` pairs; the general result is + kept and the note travels with every Rath output.""" + from scripts.narayana_rath import BOOK_SOFTWARE_DIFFERENCES, BOOK_SOFTWARE_RULE8, compare_signs + + entry = BOOK_SOFTWARE_DIFFERENCES[BOOK_SOFTWARE_RULE8] + assert BOOK_SOFTWARE_RULE8 == "book_software_rule8_exception" + flagged = {(entry["book_table"], pair["book"], pair["general_rule"]) for pair in entry["pairs"]} + assert flagged == EXPECTED_SIGN_MISSES + assert entry["kept"] == "general_rule" and entry["note"] and entry["note_en"] + chart, asc, *_ = compute_chart_data(*VERDICT_TABLES["Table 25"][0], ayanamsa_name="lahiri") + lons = {name: row["degree"] for name, row in chart["planets"].items()} + for pair in entry["pairs"]: + result = compare_signs(SIGNS.index(pair["book"]), SIGNS.index(pair["general_rule"]), lons) + assert (result["selected_sign"], result["strength_level_decided"]) == (pair["general_rule"], pair["general_level"]) + assert calc_narayana_rath(asc, lons, cycle_count=1)["known_book_differences"][BOOK_SOFTWARE_RULE8] == entry