feat(narayana-rath): AD direction checked against p.51, book divergence listed (BUG-1225)

Round-6 ruling Q7: default by the AD start sign's odd/even (Table 13, as in
Table 25); Saturn in the MD sign -> always zodiacal (Table 11); Ketu ->
reversed (Table 14); both -> Ketu first. Each AD rule now carries
direction.book_divergence (p.47 J.S. 1.1.34; J.S. 2.4.31-32), not applied;
reference report shows one line, English twins added. Table 25 Taurus 12/12.

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:
Jesse_Chen
2026-10-04 07:35:11 +08:00
co-authored by Claude Opus 5.5
parent 61bd4425cd
commit 57ef4560ce
7 changed files with 148 additions and 4 deletions
+16
View File
@@ -162,6 +162,7 @@ def rath_report_lines_zh(rath: Any) -> List[str]:
"",
f"- 当前大运 {md.get('sign')} 的子运:比较 {compared[0]} 与 {compared[-1]},较强 {rule.get('stronger_sign')}"
f"(第 {rule.get('strength_level_decided')} 级),从宫主 {rule.get('lord')} 所在 {rule.get('start_sign')} 起,12 等分",
*_ad_direction_lines_zh(rule.get("direction")),
"",
"| Rath AD | 星座 | 起始年龄 | 结束年龄 |",
"|---------|------|----------|----------|",
@@ -171,6 +172,21 @@ def rath_report_lines_zh(rath: Any) -> List[str]:
return lines
AD_DIRECTION_WORD_ZH = {"zodiacal": "顺行", "reverse": "逆行"}
def _ad_direction_lines_zh(direction: Any) -> List[str]:
"""AD direction applied + the book's two other statements, flagged as a
book divergence and not applied (round-6 ruling Q7, BUG-1225)."""
if not isinstance(direction, dict) or not direction.get("rule_text"):
return []
others = ";".join(
f"{row.get('rule_text')} → {AD_DIRECTION_WORD_ZH.get(row.get('direction'), '-')}"
for row in direction.get("book_divergence") or [] if isinstance(row, dict))
line = f"- 子运方向:{direction['rule_text']},{AD_DIRECTION_WORD_ZH.get(direction.get('direction'), '-')}"
return [line + (f"(书内分歧,未采用:{others})" if others else "")]
def rath_summary_line_zh(rath: Any) -> Optional[str]:
"""One report line naming the Rath start sign and running MD (BUG-1218)."""
if not isinstance(rath, dict) or not rath:
+53 -2
View File
@@ -42,8 +42,12 @@ exception, exalted +1 / debilitated -1); Scorpio / Aquarius lords by
AD [p.48 Arambha Rasi, p.50 note 2]: compare the MD sign and its 7th with the
same seven levels, take the stronger, start from the sign holding that sign's
lord (dual lords by the same rule), twelve equal parts. Order: Table 13 from
the start sign; Saturn in the MD sign -> Table 11 (zodiacal); Ketu in the MD
sign -> Table 14 (Ketu first when both).
the start sign (direction by the start sign's odd/even, as in Table 25;
round-6 ruling Q7); Saturn in the MD sign -> Table 11 (zodiacal); Ketu in the
MD sign -> Table 14 (Ketu first when both) [p.51]. The book's other two
statements (p.47 J.S. 1.1.34: by the MD sign; J.S. 2.4.31-32: by the MD sign
or its lord's sign) disagree with Table 25; each AD rule carries them as
`direction.book_divergence` (BUG-1225), not applied.
Ported verbatim from upstream yinduzhanxing c7117f92 `scripts/narayana_dasha.py`:
`_rath_ketu_table12_sequence` (the `rath_ketu_table12_v1` branch of
@@ -318,6 +322,52 @@ def _ad_order_profile(md_sign_idx: int, planet_lons: Dict[str, float]) -> Tuple[
return "rath_table13_v1", None
# AD direction (round-6 ruling Q7): default by the odd/even of the AD start
# sign (Table 13 practice, as the book's Table 25 shows); exceptions p.51:
# Saturn in the MD sign -> always zodiacal (Table 11); Ketu in the MD sign ->
# reversed (Table 14); both -> Ketu first (product owner 2026-10-03). Two
# other statements in the book disagree with Table 25 and are reported, not
# applied (`book_divergence`).
AD_DIRECTION_RULE = {
"rath_table13_v1": ("按子运起点星座奇偶(Table 13)", "by the odd/even of the AD start sign (Table 13)"),
"rath_saturn_table11_v1": ("大运星座有土星:一律顺行(Table 11)", "Saturn in the MD sign: always zodiacal (Table 11)"),
"rath_ketu_table14_v1": ("大运星座有计都:反向(Table 14)", "Ketu in the MD sign: reversed (Table 14)"),
}
AD_BOOK_DIVERGENCE = (
("rath_p47_js_1_1_34", "Rath p.47 (J.S. 1.1.34)",
"p.47(J.S. 1.1.34)看大运星座奇偶", "p.47 (J.S. 1.1.34) by the odd/even of the MD sign"),
("js_2_4_31_32", "J.S. 2.4.31-32 (Rath p.47-48)",
"J.S. 2.4.31–32 看大运星座或其宫主所落星座", "J.S. 2.4.31-32 by the MD sign or the sign its lord occupies"),
)
def _is_odd_sign(sign_idx: int) -> bool:
return sign_idx % 2 == 0 # Aries (index 0) is the first, odd sign
def ad_direction(md_sign_idx: int, start_sign_idx: int, profile: str, planet_lons: Dict[str, float]) -> Dict[str, Any]:
"""Applied AD direction plus the two book statements it does not follow."""
order = nd.build_narayana_antardasha_order_sequence(start_sign_idx, profile=profile)
applied = "zodiacal" if order[1] == (start_sign_idx + 1) % 12 else "reverse"
lord_sign = nd._get_planet_sign(_lord(md_sign_idx, planet_lons), planet_lons)
by_rule = {
"rath_p47_js_1_1_34": "zodiacal" if _is_odd_sign(md_sign_idx) else "reverse",
"js_2_4_31_32": "zodiacal" if _is_odd_sign(md_sign_idx) or (lord_sign is not None and _is_odd_sign(lord_sign)) else "reverse",
}
zh, en = AD_DIRECTION_RULE[profile]
return {
"direction": applied,
"rule": profile,
"rule_text": zh,
"rule_text_en": en,
"book_divergence": [
{"id": key, "source": source, "rule_text": rule_zh, "rule_text_en": rule_en,
"direction": by_rule[key], "differs": by_rule[key] != applied, "applied": False}
for key, source, rule_zh, rule_en in AD_BOOK_DIVERGENCE
],
}
def mahadasha_sequence(seed_sign_idx: int, planet_lons: Dict[str, float],
*, start_age: float = 0.0, cycle_count: int = 2) -> Dict[str, Any]:
"""Rath MD rows from one start sign (cycle 2 = twelve minus cycle 1)."""
@@ -384,6 +434,7 @@ def antardasha(md_row: Dict[str, Any], planet_lons: Dict[str, float]) -> Dict[st
"start_sign": SIGNS[start],
"order_profile": profile,
"method_note": note,
"direction": ad_direction(md_sign_idx, start, profile, planet_lons),
},
}
+14
View File
@@ -174,6 +174,20 @@ _PHRASES: dict[str, str] = {
"| Rath MD | 星座 | 宫主 | 起始年龄 | 结束年龄 | 年数 |": "| Rath MD | Sign | Lord | Start age | End age | Years |",
"| Rath AD | 星座 | 起始年龄 | 结束年龄 |": "| Rath AD | Sign | Start age | End age |",
" 的子运:比较 ": " sub-periods: compare ",
# BUG-1225: narayana_legacy_label._ad_direction_lines_zh (AD direction + book divergence)
"- 子运方向:": "- AD direction: ",
"按子运起点星座奇偶(Table 13)": "by the odd/even of the AD start sign (Table 13)",
"大运星座有土星:一律顺行(Table 11)": "Saturn in the MD sign: always zodiacal (Table 11)",
"大运星座有计都:反向(Table 14)": "Ketu in the MD sign: reversed (Table 14)",
"(书内分歧,未采用:": " (book divergence, not applied: ",
"p.47(J.S. 1.1.34)看大运星座奇偶": "p.47 (J.S. 1.1.34) by the odd/even of the MD sign",
"J.S. 2.4.31–32 看大运星座或其宫主所落星座": "J.S. 2.4.31-32 by the MD sign or the sign its lord occupies",
" → 顺行;": " -> zodiacal; ",
" → 逆行;": " -> reverse; ",
" → 顺行)": " -> zodiacal)",
" → 逆行)": " -> reverse)",
",顺行": ", zodiacal",
",逆行": ", reverse",
",12 等分": ", twelve equal parts",
# BUG-1214: tajika_year_lord.selection_basis_text (zh) → its en twin.
"年盘不全,暂用 Muntha 主星": "Annual chart incomplete; Muntha sign lord used for now",