From yinduzhanxing branch codex/local-web-verification-20261026 (remote SHA checked): - kernel: a 180-degree opposition keeps its 180 target (it was matched as 0); exact and equal-speed states are no longer called applying or separating - named-yoga authority rows carry source_review_status and factor_promotion_allowed: false; the annual year-chart layer honours the flag, so no Tajika yoga (Ithasala / Easarapha included) becomes a factor - the five annual oracle cases go back to template_only (archived text kept); the dashboards no longer claim annual closure Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
98 lines
3.6 KiB
Python
98 lines
3.6 KiB
Python
# Synced from yinduzhanxing 3509ccd7 for BUG-1655.
|
|
import pytest
|
|
|
|
from scripts.tajika_kernel import calculate_tajika_interactions, evaluate_tajika_pair
|
|
|
|
|
|
@pytest.mark.parametrize('longitude,motion', [(179.0, 'applying'), (181.0, 'separating'), (180.0, 'exact')])
|
|
def test_opposition_is_retained_instead_of_tested_as_conjunction(longitude, motion):
|
|
pair = evaluate_tajika_pair('Sun', 'Moon', {
|
|
'Sun': {'longitude': 0.0, 'speed': 1.0},
|
|
'Moon': {'longitude': longitude, 'speed': 13.0},
|
|
})
|
|
assert pair is not None
|
|
assert pair['aspect'] == 180.0
|
|
assert pair['motion'] == motion
|
|
|
|
|
|
def test_equal_speed_contact_is_not_a_separating_yoga():
|
|
planets = _seven()
|
|
planets['Moon'] = {'longitude': 59.0, 'speed': 1.0}
|
|
result = calculate_tajika_interactions(planets)
|
|
pair = next(row for row in result['interactions'] if row['planets'] == ['Sun', 'Moon'])
|
|
assert pair['motion'] == 'stationary_relative'
|
|
assert not any(row['planets'] == ['Sun', 'Moon'] for row in result['candidate_yogas'])
|
|
|
|
|
|
def test_exact_contact_is_preserved_without_inventing_separation():
|
|
planets = _seven()
|
|
planets['Moon']['longitude'] = 60.0
|
|
result = calculate_tajika_interactions(planets)
|
|
pair = next(row for row in result['interactions'] if row['planets'] == ['Sun', 'Moon'])
|
|
assert pair['motion'] == 'exact'
|
|
assert not any(row['planets'] == ['Sun', 'Moon'] for row in result['candidate_yogas'])
|
|
|
|
|
|
def _seven():
|
|
return {
|
|
"Sun": {"longitude": 0, "speed": 1.0}, "Moon": {"longitude": 49, "speed": 13.0},
|
|
"Mars": {"longitude": 180, "speed": 0.5}, "Mercury": {"longitude": 260, "speed": 1.2},
|
|
"Jupiter": {"longitude": 310, "speed": 0.08}, "Venus": {"longitude": 130, "speed": 1.0},
|
|
"Saturn": {"longitude": 220, "speed": 0.03}, "Rahu": {"longitude": 60, "speed": -0.05},
|
|
}
|
|
|
|
|
|
def test_kernel_detects_cross_sign_aspect_and_excludes_nodes():
|
|
result = calculate_tajika_interactions(_seven())
|
|
|
|
pair = next(row for row in result["interactions"] if row["planets"] == ["Sun", "Moon"])
|
|
assert pair["aspect"] == 60.0
|
|
assert pair["motion"] == "applying"
|
|
candidate = next(row for row in result["candidate_yogas"] if row["planets"] == ["Sun", "Moon"])
|
|
assert candidate["name"] == "Ithasala_candidate"
|
|
assert candidate["status"] == "partial"
|
|
assert result["nodes_excluded"] is True
|
|
assert all("Rahu" not in row["planets"] for row in result["interactions"])
|
|
|
|
|
|
def test_kernel_blocks_missing_speed_instead_of_guessing_motion():
|
|
planets = _seven()
|
|
del planets["Venus"]["speed"]
|
|
|
|
result = calculate_tajika_interactions(planets)
|
|
|
|
assert result["status"] == "blocked"
|
|
assert "Venus" in result["missing"]
|
|
|
|
|
|
def test_pair_motion_uses_instantaneous_residual_derivative_not_a_one_day_step():
|
|
pair = evaluate_tajika_pair(
|
|
"Moon",
|
|
"Mercury",
|
|
{
|
|
# The Moon reaches the exact 60-degree aspect in less than a day,
|
|
# then overshoots it. It is still applying at this instant.
|
|
"Moon": {"longitude": 339.0, "speed": 12.9},
|
|
"Mercury": {"longitude": 282.0, "speed": 0.9},
|
|
},
|
|
)
|
|
|
|
assert pair is not None
|
|
assert pair["residual"] == 3.0
|
|
assert pair["motion"] == "applying"
|
|
|
|
|
|
def test_pair_motion_marks_residual_moving_away_as_separating():
|
|
pair = evaluate_tajika_pair(
|
|
"Mars",
|
|
"Saturn",
|
|
{
|
|
"Mars": {"longitude": 234.3, "speed": 0.48},
|
|
"Saturn": {"longitude": 288.57, "speed": 0.01},
|
|
},
|
|
)
|
|
|
|
assert pair is not None
|
|
assert pair["residual"] < 0
|
|
assert pair["motion"] == "separating"
|