feat(narayana): Table 18 as a flagged book example with the explicit seed; book software-verdict and Table 25 tests (BUG-1218)
Red line 3 revised by the product owner (2026-10-03 evening, audit da95d92d):
Indira Table 18 is a book-internal contradiction. calc_narayana_rath(...,
seed_sign_idx, book_example="rath_p66_indira_ak") reproduces it 12/12 flagged
book_example_exception and carries the general rule's Capricorn unchanged.
New tests: five D1 software-verdict tables 28/30 (two Wadiyar level-5 misses
pinned), co-lords 8/10, Table 25 sub-periods 24/36 (Gemini MD 0/12 pinned).
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
f5d24f42d2
commit
735d66fd65
@@ -52,8 +52,10 @@ upstream function). Tables 10 / 11 / 13 / 14, `_rasi_aspects`, the year and
|
||||
dual-lord functions are the same in both repositories and are reused from the
|
||||
frozen local `narayana_dasha.py`, which this module does not modify.
|
||||
|
||||
Not wired into scoring, consultation or reports (task red line 3: Table 18 is
|
||||
not reproduced by the general rule, see tests/test_narayana_rath_book_tables.py).
|
||||
Table 18 (Indira) is a book-internal contradiction (BOOK_EXAMPLES): the
|
||||
general rule's Capricorn is output as is; the book's Cancer only with the
|
||||
start sign given explicitly and flagged (product owner, 2026-10-03 evening).
|
||||
Not wired into scoring.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -72,6 +74,22 @@ DURATION_PROFILE = "jaimini_odd_footed_dignity_v2"
|
||||
DUAL_LORD_PROFILE = "jaimini_dual_lord_source_v1"
|
||||
ROLE_PROFILE = "rath_p36_role_conjunction_v1"
|
||||
INDIRA_EXCEPTION = "rath_p66_indira_ak"
|
||||
# Book examples whose printed start sign the general rule does not give.
|
||||
# Product owner ruling 2026-10-03 (evening, red line 3 revised): reproduce
|
||||
# them only with the start sign given explicitly, flagged; never by code that
|
||||
# bends the general rule.
|
||||
BOOK_EXAMPLES = {
|
||||
INDIRA_EXCEPTION: {
|
||||
"book_table": "Table 18",
|
||||
"book_start_sign": "Cancer",
|
||||
"book_internal_contradiction": True,
|
||||
"evidence": ("Hand example (PDF Page 62; astrologer cites p.65-66) concludes Cancer because "
|
||||
"'Saturn is the Atmakaraka and has gained the highest longitude', but Saturn sits in "
|
||||
"Cancer and rules Capricorn, so rules 5 and 6 read literally point to Capricorn; the "
|
||||
"book's own software verdict for the same native (Table 27) also has Capricorn "
|
||||
"stronger than Cancer. Audit docs/research/shared_engine_reuse_audit_2026_10_03.md N1."),
|
||||
},
|
||||
}
|
||||
KETU_FIRST_NOTE = "PyJHora 兼容:计都优先"
|
||||
KETU_FIRST_NOTE_EN = "PyJHora-compatible: Ketu takes precedence"
|
||||
SOURCE = {
|
||||
@@ -339,13 +357,19 @@ def antardasha(md_row: Dict[str, Any], planet_lons: Dict[str, float]) -> Dict[st
|
||||
|
||||
def calc_narayana_rath(lagna_sign_idx: int, planet_lons: Dict[str, float],
|
||||
*, seed_sign_idx: Optional[int] = None, cycle_count: int = 2,
|
||||
allow_book_example: bool = False) -> Dict[str, Any]:
|
||||
allow_book_example: bool = False,
|
||||
book_example: Optional[str] = None) -> Dict[str, Any]:
|
||||
"""Rath Narayana Dasha for one chart.
|
||||
|
||||
`seed_sign_idx` overrides the start sign (book-table replay only).
|
||||
`seed_sign_idx` overrides the start sign (book-table replay only); with
|
||||
`book_example` (a key of BOOK_EXAMPLES) the output is flagged
|
||||
`book_example_exception` and still carries the general rule's own
|
||||
verdict, unchanged, in `general_rule_selection`.
|
||||
`allow_book_example` lets the Indira AK example decide a full seven-level
|
||||
tie (flagged in the output).
|
||||
"""
|
||||
if book_example is not None and (seed_sign_idx is None or book_example not in BOOK_EXAMPLES):
|
||||
raise ValueError("book_example needs an explicit seed_sign_idx and a known BOOK_EXAMPLES key")
|
||||
base = {
|
||||
"profile": PROFILE,
|
||||
"duration_profile": DURATION_PROFILE,
|
||||
@@ -356,7 +380,14 @@ def calc_narayana_rath(lagna_sign_idx: int, planet_lons: Dict[str, float],
|
||||
}
|
||||
if seed_sign_idx is not None:
|
||||
selection = {"status": "explicit", "selected_sign_idx": seed_sign_idx,
|
||||
"strength_level_decided": None, "book_example_exception": None}
|
||||
"strength_level_decided": None, "book_example_exception": book_example}
|
||||
if book_example is not None:
|
||||
general = compare_signs(lagna_sign_idx, (lagna_sign_idx + 6) % 12, planet_lons)
|
||||
base["general_rule_selection"] = {
|
||||
key: general.get(key) for key in
|
||||
("status", "selected_sign", "strength_level_decided", "strength_level_name", "reason")
|
||||
}
|
||||
base["book_example"] = BOOK_EXAMPLES[book_example]
|
||||
else:
|
||||
selection = compare_signs(lagna_sign_idx, (lagna_sign_idx + 6) % 12, planet_lons,
|
||||
allow_book_example=allow_book_example)
|
||||
@@ -365,7 +396,9 @@ def calc_narayana_rath(lagna_sign_idx: int, planet_lons: Dict[str, float],
|
||||
base["book_example_exception"] = selection.get("book_example_exception")
|
||||
if selection["status"] in ("selected", "explicit"):
|
||||
seq = mahadasha_sequence(selection["selected_sign_idx"], planet_lons, cycle_count=cycle_count)
|
||||
if selection["status"] == "explicit":
|
||||
if selection["status"] == "explicit" and book_example is not None:
|
||||
status, basis = "book_example_exception", f"explicit_seed:book_example:{book_example}"
|
||||
elif selection["status"] == "explicit":
|
||||
status, basis = "explicit_seed", "explicit_seed"
|
||||
elif selection.get("book_example_exception"):
|
||||
status, basis = "book_example_exception", f"book_example:{selection['book_example_exception']}"
|
||||
|
||||
Reference in New Issue
Block a user