test: port Goel Jaimini strength checks onto our Niryaana selector

Issue #94 T2. Keep the upstream test and retarget select_niryaana_shoola_start_sign to scripts.rashi_dashas_native. Add test_full_reading_exposes_goel_jaimini_strength using the existing fictional BASE_BIRTH_ARGS.

Co-Authored-By: Grok (agent loop)
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jesse-ux
2026-10-22 00:54:02 +08:00
co-authored by Grok (agent loop) Cursor
parent 424f03a4d5
commit eb67962d70
2 changed files with 143 additions and 0 deletions
+9
View File
@@ -63,3 +63,12 @@ def test_varga_cli_d9_uses_same_navamsa_mapping_as_varga_full() -> None:
assert short["ascendant"] == full["Ascendant"]["sign"]
for planet in ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn", "Rahu", "Ketu"]:
assert short[planet]["sign"] == full[planet]["sign"]
def test_full_reading_exposes_goel_jaimini_strength() -> None:
report = _run_engine("full-reading", *BASE_BIRTH_ARGS)
goel = report["modules"]["jaimini"]
assert goel["goel_full_strength"]["status"] == "executed"
assert len(goel["goel_full_strength"]["rashi_strengths"]) == 12
assert set(goel["goel_special_points"]) == {"Brahma", "Maheshwara", "Rudra"}
assert goel["niryaana_shoola_strength"]["deprecated"] is True
+134
View File
@@ -0,0 +1,134 @@
"""Hand-checked synthetic positions, plus Goel's printed p15 worked table.
No private birth data; these fixtures exercise supplied-position arithmetic.
"""
from copy import deepcopy
import importlib
import importlib.util
import math
import pytest
SYNTHETIC = dict(Sun=29., Moon=58., Mars=87., Mercury=116.,
Jupiter=145., Venus=174., Saturn=203., Rahu=245., Ketu=65.)
def module():
assert importlib.util.find_spec('scripts.goel_jaimini_strength'), 'Goel producer must be published'
return importlib.import_module('scripts.goel_jaimini_strength')
def test_synthetic_five_component_totals_and_special_points():
original = deepcopy(SYNTHETIC)
result = module().build_goel_chart_evidence(SYNTHETIC, 0.)
strength = result['strength']
assert strength['atmakaraka'] == 'Sun'
assert {p: row['total'] for p, row in strength['planets'].items()} == dict(
Sun=180, Moon=135, Mars=172.5, Mercury=90, Jupiter=187.5,
Venus=86.25, Saturn=123.75)
assert {p: row['value'] for p, row in result['special_points'].items()} == dict(
Brahma='Jupiter', Maheshwara='Mars', Rudra='Mars')
assert strength['rashi_strengths'][0]['total'] == 367.5
assert strength['rashi_strengths'][6]['total'] == 225
assert SYNTHETIC == original
def test_node_policy_only_changes_sthana_and_sign_total():
m = module()
text = m.calculate_goel_strength(SYNTHETIC)
example = m.calculate_goel_strength(SYNTHETIC, node_occupancy_policy='exclude_nodes_worked_example')
assert text['planets'] == example['planets']
# Gemini has Mars+Ketu; Sagittarius has only Rahu.
assert (text['rashi_strengths'][2]['sthana'], example['rashi_strengths'][2]['sthana']) == (75, 60)
assert (text['rashi_strengths'][8]['sthana'], example['rashi_strengths'][8]['sthana']) == (60, 0)
assert text['rashi_strengths'][2]['total'] - example['rashi_strengths'][2]['total'] == 15
assert text['rashi_strengths'][8]['total'] - example['rashi_strengths'][8]['total'] == 60
def test_goel_printed_p15_numeric_example_without_birth_identity():
positions = dict(Sun=20+18/60, Moon=210+20+15/60, Mars=210+23+2/60,
Mercury=30+11+12/60, Jupiter=150+3+13/60,
Venus=330+17+28/60, Saturn=7+7/60,
Rahu=330+5+58/60, Ketu=150+5+58/60)
result = module().calculate_goel_strength(positions, node_occupancy_policy='exclude_nodes_worked_example')
assert {p: r['total'] for p, r in result['planets'].items()} == dict(
Sun=240, Moon=93.75, Mars=210, Mercury=97.5, Jupiter=101.25,
Venus=172.5, Saturn=146.25)
assert [r['total'] for r in result['rashi_strengths']] == [
412.5, 337.5, 217.5, 228.75, 330, 281.25, 247.5, 465,
281.25, 221.25, 236.25, 363.75]
def test_equal_karaka_degrees_block_all_special_point_choices():
result = module().build_goel_chart_evidence(dict(SYNTHETIC, Moon=59.), 0.)
assert result['strength']['status'] == 'blocked'
assert all(result['special_points'][p]['status'] == 'blocked'
for p in ('Brahma', 'Maheshwara', 'Rudra'))
@pytest.mark.parametrize('bad', [math.nan, math.inf, -1., 360., True, '0'])
def test_invalid_ascendant_rejected(bad):
with pytest.raises(ValueError):
module().build_goel_chart_evidence(SYNTHETIC, bad)
def test_legacy_lagna_seventh_alias_does_not_replace_pvr_second_eighth():
result = module().build_goel_chart_evidence(SYNTHETIC, 0.)
legacy = result['niryaana_shoola_strength']
assert (legacy['lagna'], legacy['seventh']) == (367.5, 225)
assert legacy['deprecated'] is True
assert legacy['comparison'] == 'lagna_vs_seventh'
from scripts.rashi_dashas_native import select_niryaana_shoola_start_sign
pvr = select_niryaana_shoola_start_sign(ascendant_longitude=0., planet_longitudes=SYNTHETIC)
assert pvr['selected_sign_idx'] == 1
assert pvr['profile'] == 'pvr_niryaana_shoola_ayur_rasi_strength_v1'
def test_brahma_ak_eighth_occupancy_overrides_lagna_selector():
result = module().build_goel_chart_evidence(dict(SYNTHETIC, Sun=239., Mercury=86.), 0.)
assert result['special_points']['Brahma']['value'] == 'Mercury'
assert result['special_points']['Brahma']['rule'] == 'eighth_lord_from_AK_occupies_eighth_from_AK'
def test_exalted_ak_eighth_lord_compares_twelfth_for_maheshwara():
result = module().build_goel_chart_evidence(dict(SYNTHETIC, Mars=297.), 0.)
assert result['special_points']['Maheshwara']['value'] == 'Jupiter'
assert result['special_points']['Maheshwara']['candidates'] == {'Mars': 150, 'Jupiter': 187.5}
def test_rudra_weaker_malefic_contact_exception():
result = module().build_goel_chart_evidence(dict(SYNTHETIC, Sun=329., Rahu=125., Ketu=305.), 0.)
planets = result['strength']['planets']
assert planets['Mars']['total'] == 127.5
assert planets['Mars']['malefic_contacts'] == []
assert planets['Venus']['total'] == 101.25
assert planets['Venus']['malefic_contacts'] == ['Mars']
assert result['special_points']['Rudra']['value'] == 'Venus'
def test_incomplete_chart_entry_preserves_blocked_points():
from scripts.jyotish_engine import _goel_jaimini_evidence
result = _goel_jaimini_evidence({}, 0.)
assert result['goel_full_strength']['status'] == 'blocked'
assert all(r['status'] == 'blocked' for r in result['goel_special_points'].values())
assert 'niryaana_shoola_strength' not in result
@pytest.mark.parametrize('bad', [dict(SYNTHETIC, Sun=math.nan),
dict(SYNTHETIC, Ketu=66.), {p: v for p, v in SYNTHETIC.items() if p != 'Saturn'}])
def test_incomplete_or_inconsistent_positions_rejected(bad):
with pytest.raises(ValueError):
module().calculate_goel_strength(bad)
def test_jaimini_special_entry_exposes_real_goel_results(monkeypatch):
from types import SimpleNamespace
from scripts import jyotish_engine as engine
chart = {'planets': {p: {'degree': v} for p, v in SYNTHETIC.items()},
'ascendant': {'degree': 0.}}
monkeypatch.setattr(engine, '_compute_chart_from_args', lambda args: (chart, 0, 2451545., 24.))
result = engine.cmd_jaimini(SimpleNamespace(mode='special', hour=12, minute=0))
assert result.get('goel_full_strength', {}).get('atmakaraka') == 'Sun'
assert result['goel_special_points']['Brahma']['value'] == 'Jupiter'
assert result['niryaana_shoola_strength']['deprecated'] is True