fix(yoga): full-reading yoga re-run passes the retrograde flag (T1 follow-up, BUG-1207)

Nine-figure check: Judy Garland's report said Bhadra 'combust within 14°' while
the card said 12° (retrograde Mercury). The full reading builds cmd_yoga's
planets string without retrograde; an optional 5th field 'R' now carries it.
Test pins report vs consultation reductions on that public chart.

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-03 14:56:05 +08:00
co-authored by Claude Opus 5.5
parent 0d6af77cea
commit b1185c63ac
2 changed files with 33 additions and 1 deletions
+8 -1
View File
@@ -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),
@@ -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"])