Files
Jyotisha/tests/test_punarphoo_observation.py
T
Jesse_ChenandCursor 04ad3325d5
Independent Staging Quality Gate / validate (push) Successful in 11m26s
Independent Staging Quality Gate / publish (push) Successful in 13m24s
fix(relationship): freeze marriage event classes and add conditional dashas (BUG-608)
Venus/Jupiter/Moon periods no longer collapse into one marriage-opportunity line. Full reading reports the ten BPHS conditional dasha families; Skill 6.9.16.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-09 16:04:52 +08:00

155 lines
6.0 KiB
Python

#!/usr/bin/env python3
"""Punarphoo observation detector + relationship event-class split."""
from __future__ import annotations
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "scripts"))
from punarphoo import CLAIM_BOUNDARY, circular_degree_gap, detect_punarphoo # noqa: E402
from relationship_analysis import analyze_relationship, classify_relationship_event_class # noqa: E402
def test_circular_degree_gap_wraps_around_zero() -> None:
assert circular_degree_gap(359.0, 1.0) == 2.0
assert circular_degree_gap(10.0, 20.0) == 10.0
def test_detect_punarphoo_natal_same_house_within_orb() -> None:
planets = {
"Moon": {"longitude": 311.48, "house": 7},
"Saturn": {"longitude": 319.01, "house": 7},
}
result = detect_punarphoo(planets)
assert result["natal_present"] is True
assert result["same_house"] is True
assert result["orb_deg"] < 10.0
assert result["status"] == "observation_only"
assert result["production_tuning_allowed"] is False
assert result["claim_boundary"] == CLAIM_BOUNDARY
assert result["timing_observation_active"] is False
def test_detect_punarphoo_saturn_return_to_natal_moon() -> None:
planets = {
"Moon": {"longitude": 311.48, "house": 7},
"Saturn": {"longitude": 319.01, "house": 7},
}
result = detect_punarphoo(planets, transit_saturn_longitude=311.78)
assert result["natal_present"] is True
assert result["timing_observation_active"] is True
assert result["saturn_return_to_natal_moon"]["active"] is True
assert result["claim_boundary"] == CLAIM_BOUNDARY
def test_natal_punarphoo_alone_does_not_classify_as_romantic_activation() -> None:
planets = {
"Moon": {"longitude": 311.48, "house": 7, "sign": "Aquarius"},
"Saturn": {"longitude": 319.01, "house": 7, "sign": "Aquarius"},
"Venus": {"longitude": 341.99, "house": 8, "sign": "Pisces"},
"Jupiter": {"longitude": 165.27, "house": 2, "sign": "Virgo"},
}
split = classify_relationship_event_class(
planets,
asc_sign="Leo",
dasha_info={"maha_dasha": "Saturn", "antar_dasha": "Mercury"},
ul_sign="Libra",
darakaraka="Sun",
)
assert "Punarphoo" not in split["romantic_activation"]["hits"]
assert "7H_Moon" in split["romantic_activation"]["natal_structure"]
assert "natal_Punarphoo" in split["romantic_activation"]["natal_structure"]
assert split["event_class"] != "romantic_activation"
assert split["claim_status"] == "observation_only"
assert split["negative_holdout"]["production_tuning_allowed"] is False
def test_saturn_return_to_moon_adds_punarphoo_romantic_hit() -> None:
planets = {
"Moon": {"longitude": 311.48, "house": 7, "sign": "Aquarius"},
"Saturn": {"longitude": 319.01, "house": 7, "sign": "Aquarius"},
"Venus": {"longitude": 341.99, "house": 8, "sign": "Pisces"},
}
split = classify_relationship_event_class(
planets,
asc_sign="Leo",
dasha_info={"maha_dasha": "Saturn", "antar_dasha": "Mercury"},
transit_saturn_longitude=311.48,
)
assert "Punarphoo" in split["romantic_activation"]["hits"]
assert split["event_class"] == "romantic_activation"
def test_pratyantar_does_not_drive_event_class() -> None:
planets = {
"Moon": {"longitude": 313.26, "house": 7, "sign": "Aquarius"},
"Saturn": {"longitude": 305.73, "house": 7, "sign": "Aquarius"},
"Jupiter": {"longitude": 165.27, "house": 2, "sign": "Virgo"},
"Venus": {"longitude": 341.99, "house": 8, "sign": "Pisces"},
}
jupiter_pd = classify_relationship_event_class(
planets,
asc_sign="Leo",
dasha_info={"maha_dasha": "Saturn", "antar_dasha": "Mercury", "pratyantar": "Jupiter"},
)
assert "5L_dasha" not in jupiter_pd["romantic_activation"]["hits"]
assert "5L_pd" in jupiter_pd["pd_hits"]
assert jupiter_pd["event_class"] != "romantic_activation"
venus_pd = classify_relationship_event_class(
planets,
asc_sign="Leo",
dasha_info={"maha_dasha": "Saturn", "antar_dasha": "Ketu", "pratyantar": "Venus"},
)
assert "Venus_dasha" not in venus_pd["legal_marriage"]["hits"]
assert "Venus_pd" in venus_pd["pd_hits"]
assert venus_pd["event_class"] != "legal_marriage"
def test_venus_to_natal_moon_does_not_drive_romantic_class() -> None:
planets = {
"Moon": {"longitude": 313.26, "house": 7, "sign": "Aquarius"},
"Saturn": {"longitude": 305.73, "house": 7, "sign": "Aquarius"},
"Venus": {"longitude": 341.99, "house": 8, "sign": "Pisces"},
}
split = classify_relationship_event_class(
planets,
asc_sign="Leo",
dasha_info={"maha_dasha": "Saturn", "antar_dasha": "Ketu", "pratyantar": "Venus"},
transit_venus_longitude=311.28,
)
assert "7H_Venus_to_Moon" not in split["romantic_activation"]["hits"]
assert split["event_class"] != "romantic_activation"
assert "Venus_dasha" not in split["legal_marriage"]["hits"]
venus_obs = split["romantic_activation"]["venus_to_natal_moon"]
assert venus_obs["active"] is True
assert venus_obs["drives_event_class"] is False
assert venus_obs["status"] == "observation_only"
def test_analyze_relationship_does_not_flatten_timing_into_one_label() -> None:
planets = {
"Venus": {"sign": "Pisces", "house": 8},
"Moon": {"sign": "Aquarius", "house": 7, "longitude": 311.48},
"Saturn": {"sign": "Aquarius", "house": 7, "longitude": 319.01},
"Jupiter": {"sign": "Virgo", "house": 2},
}
analysis = analyze_relationship(
planets,
asc_sign="Leo",
dasha_info={"maha_dasha": "Saturn"},
ul_sign="Libra",
darakaraka="Sun",
)
assert analysis["event_class_split"]["claim_status"] == "observation_only"
assert analysis["timing"][0]["event_class"] in {
"romantic_activation",
"relationship_formation",
"legal_marriage",
"unclassified",
}
assert "不得合并" in analysis["timing"][0]["note"]