diff --git a/scripts/jyotish_engine.py b/scripts/jyotish_engine.py index 54b2ffd0..0ce6832b 100644 --- a/scripts/jyotish_engine.py +++ b/scripts/jyotish_engine.py @@ -12517,6 +12517,10 @@ def cmd_yoga(args): pdata["degree"] = float(parts[3].strip()) except ValueError: pass + # Optional 5th field "R": retrograde (combustion orb of the main + # Pancha Mahapurusha detector, BUG-1207). + if len(parts) >= 5 and parts[4].strip().upper() == "R": + pdata["retrograde"] = True planets[parts[0].strip()] = pdata context_json = getattr(args, 'context_json', None) if context_json: @@ -15663,11 +15667,14 @@ def cmd_full_reading(args): 'sign': pd['sign'], 'house': pd['house'], 'degree': pd.get('degree_in_sign', pd.get('degree')), + 'retrograde': bool(pd.get('retrograde')), } yoga_result = cmd_yoga(type('Args', (), { 'ascendant': asc_sign, 'planets': ','.join([ - f"{k}:{v['sign']}:{v['house']}" + (f":{v['degree']}" if v.get('degree') is not None else "") + f"{k}:{v['sign']}:{v['house']}" + + (f":{v['degree']}" if v.get('degree') is not None else "") + + (":R" if v.get('degree') is not None and v.get('retrograde') else "") for k, v in yoga_planets.items() ]), 'context_json': json.dumps(yoga_context, ensure_ascii=False), diff --git a/tests/test_pancha_mahapurusha_main_detector.py b/tests/test_pancha_mahapurusha_main_detector.py index 4f65c2c2..a82174f9 100644 --- a/tests/test_pancha_mahapurusha_main_detector.py +++ b/tests/test_pancha_mahapurusha_main_detector.py @@ -170,3 +170,28 @@ def test_report_yoga_rows_carry_retrograde_and_longitude() -> None: "retrograde": row["retrograde"]} for name, row in chart["planets"].items()} assert [(row["name"], row["reductions"]) for row in report] == [ (row["name"], row["reductions"]) for row in pancha_mahapurusha_rows(api)] + + +def test_full_reading_yoga_module_matches_the_consultation_path() -> None: + """The report's yoga table (cmd_full_reading modules.yoga, varga-context + re-run) gives the same reduced reasons as the consultation path; the + retrograde flag travels in the planets string (Judy Garland: retrograde + Mercury, combustion orb 12°).""" + from scripts.jyotish_engine import cmd_full_reading + + cases = json.loads((ROOT / "references/real_case_calibration/minute_rectification_holdout_v5.json").read_text(encoding="utf-8"))["cases"] + birth = next(case for case in cases if case["case_id"] == "judy_garland_1922_aa_v5_holdout")["birth"] + year, month, day = (int(part) for part in birth["date"].split("-")) + hour, minute = (int(part) for part in birth["time"].split(":")) + args = {"year": year, "month": month, "day": day, "hour": hour, "minute": minute, "second": 0, + "lat": birth["latitude"], "lon": birth["longitude"], "tz": birth["timezone_offset"], + "node_mode": "mean", "ayanamsa": "raman", "today": "2026-10-03", "target_year": 2026, "age": 104} + reading = cmd_full_reading(type("Args", (), args)()) + report = [row for row in reading["modules"]["yoga"]["yogas"] if row.get("category") == "mahapurusha"] + chart, *_ = compute_chart_data(year, month, day, hour, minute, birth["latitude"], birth["longitude"], + birth["timezone_offset"], ayanamsa_name="raman") + api = {name: {"sign": row["sign"], "house": row["house"], "lon": row["degree_raw"], "degree": row["degree_raw"], + "retrograde": row["retrograde"]} for name, row in chart["planets"].items()} + assert [(row["name"], row["reductions"]) for row in report] == [ + (row["name"], row["reductions"]) for row in pancha_mahapurusha_rows(api)] + assert any("12°" in reason for row in report for reason in row["reductions"])