From cf78d4ca21fd7aa5765d43bb79e956cb8f5c1520 Mon Sep 17 00:00:00 2001 From: Jesse_Chen Date: Fri, 2 Oct 2026 23:39:44 +0800 Subject: [PATCH] fix: align combustion thresholds across engine (upstream 080c286c, adapted) One direct / retrograde orb table (Moon included) in the shared COMBUSTION_ORBS / is_combust, used by the full reading and the consultation graha-drishti layer. TASK-upstream-sync5-20261002 U3. (cherry picked from commit 080c286c, resolved onto our shared helper) Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE --- scripts/consultation_native_layers.py | 2 +- scripts/jyotish_engine.py | 26 ++++++++++++++++++++---- tests/test_consultation_native_layers.py | 21 +++++++++++++------ 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/scripts/consultation_native_layers.py b/scripts/consultation_native_layers.py index 871df393..dd7d1c30 100644 --- a/scripts/consultation_native_layers.py +++ b/scripts/consultation_native_layers.py @@ -643,7 +643,7 @@ def build_graha_drishti(engine, chart: dict) -> dict: for name in DRISHTI_CASTERS: lon = _planet_lon(planets.get(name)) if lon is not None and name in rows: - rows[name]["combust"] = bool(engine.is_combust(name, lon, sun_lon)) + rows[name]["combust"] = bool(engine.is_combust(name, lon, sun_lon, bool(_record(planets.get(name)).get("retrograde")))) for row in rows.values(): row.pop("house", None) return { diff --git a/scripts/jyotish_engine.py b/scripts/jyotish_engine.py index d7e75165..4f74b7f7 100644 --- a/scripts/jyotish_engine.py +++ b/scripts/jyotish_engine.py @@ -10730,13 +10730,29 @@ def _oracle_progress_snapshot(): # and Ketu have no orb here; the Sun is never combust. Shared with the web # consultation layer (consultation_native_layers.build_graha_drishti) so both # read the same rule (BUG-1154). -COMBUSTION_ORBS = {'Mars': 17, 'Mercury': 12, 'Jupiter': 11, 'Venus': 10, 'Saturn': 15} +# Upstream yinduzhanxing 080c286c (sync5 U3): one direct / retrograde orb +# table for the whole engine, the Moon included. +COMBUSTION_ORBS = { + 'Moon': {'direct': 12, 'retrograde': 12}, + 'Mars': {'direct': 17, 'retrograde': 10}, + 'Mercury': {'direct': 14, 'retrograde': 12}, + 'Jupiter': {'direct': 11, 'retrograde': 10}, + 'Venus': {'direct': 10, 'retrograde': 8}, + 'Saturn': {'direct': 15, 'retrograde': 10}, +} -def is_combust(planet_name, longitude, sun_longitude): +def combustion_threshold(planet_name, retrograde=False): + """Orb in degrees for `planet_name` (None when the body has no orb).""" + profile = COMBUSTION_ORBS.get(planet_name) + return profile['retrograde' if retrograde else 'direct'] if profile else None + + +def is_combust(planet_name, longitude, sun_longitude, retrograde=False): """True when `planet_name` is within its combustion orb of the Sun.""" separation = abs(((float(longitude) - float(sun_longitude) + 180) % 360) - 180) - return planet_name != 'Sun' and separation <= COMBUSTION_ORBS.get(planet_name, 0) + threshold = combustion_threshold(planet_name, retrograde) + return planet_name != 'Sun' and threshold is not None and separation <= threshold def _functional_benefic_malefic_snapshot(planets, ascendant): @@ -16369,7 +16385,9 @@ def cmd_full_reading(args): if longitude is None: continue planet.update(get_kp_lords(float(longitude))) - planet['combust'] = is_combust(planet_name, float(longitude), sun_longitude) + retrograde = bool(planet.get('retrograde')) + planet['combust'] = is_combust(planet_name, float(longitude), sun_longitude, retrograde) + planet['combustion_threshold_degrees'] = combustion_threshold(planet_name, retrograde) planet['r_c'] = 'R' if planet.get('retrograde') else 'C' if planet['combust'] else '' strength = sb_planets.get(planet_name) if isinstance(sb_planets.get(planet_name), dict) else {} if strength: diff --git a/tests/test_consultation_native_layers.py b/tests/test_consultation_native_layers.py index 53c9fbcd..e637fd19 100644 --- a/tests/test_consultation_native_layers.py +++ b/tests/test_consultation_native_layers.py @@ -283,15 +283,24 @@ def test_obama_saturn_aspects_the_sun_and_mercury_is_combust() -> None: assert drishti["planets"]["Mercury"]["combust"] is True -def test_combustion_rule_is_unchanged() -> None: - """The full reading's orbs, moved into a named helper without change.""" +def test_combustion_rule_follows_the_shared_orb_table() -> None: + """Shared orbs for the full reading and the consultation layer. + + 原值: COMBUSTION_ORBS 只有顺行一档且不含月亮(水 12°、金 10°),月亮按 0° 只算精确合 + 新值: 顺行 / 逆行两档并含月亮(月 12/12、火 17/10、水 14/12、木 11/10、金 10/8、土 15/10) + 原因: TASK-upstream-sync5-20261002 U3,上游 yinduzhanxing 080c286c 全引擎统一燃烧阈值 + """ engine = native._load_engine() - assert engine.COMBUSTION_ORBS == {"Mars": 17, "Mercury": 12, "Jupiter": 11, "Venus": 10, "Saturn": 15} - assert engine.is_combust("Mercury", 112.0, 100.0) is True - assert engine.is_combust("Mercury", 112.01, 100.0) is False + assert engine.COMBUSTION_ORBS["Mercury"] == {"direct": 14, "retrograde": 12} + assert engine.COMBUSTION_ORBS["Moon"] == {"direct": 12, "retrograde": 12} + assert engine.is_combust("Mercury", 114.0, 100.0) is True + assert engine.is_combust("Mercury", 114.01, 100.0) is False + assert engine.is_combust("Mercury", 113.0, 100.0, retrograde=True) is False assert engine.is_combust("Venus", 355.0, 5.0) is True # across 0° + assert engine.is_combust("Venus", 351.0, 0.0, retrograde=True) is False assert engine.is_combust("Sun", 100.0, 100.0) is False - assert engine.is_combust("Moon", 100.0, 100.0) is True # orb 0: only an exact conjunction + assert engine.is_combust("Moon", 111.0, 100.0) is True + assert engine.is_combust("Rahu", 100.0, 100.0) is False def test_saturn_from_moon_house_is_whole_sign_from_the_natal_moon() -> None: