Files
Jyotisha/tests/test_rectification_family_appearance_scoring.py
T

255 lines
9.9 KiB
Python

from __future__ import annotations
from datetime import date
from scripts.active_rectification_event_engine import (
AUXILIARY_DOMAINS,
AUXILIARY_SCORE_FACTOR,
DOMAIN_CONFIG,
_score_event,
compute_candidate_static_contexts,
compute_event_candidate_rows,
)
from scripts.rectification.contracts import (
is_primary_scoreable_event,
is_scoreable_event,
normalize_rectification_request,
)
from scripts.rectification.scoring_service import public_technique_layers
def test_family_event_is_scoreable_with_d12_and_kin_houses() -> None:
prefixes, houses = DOMAIN_CONFIG["family"]
assert prefixes == ("D12", "D7", "D3")
assert houses == (3, 4, 5, 9)
event = {
"id": "00000000-0000-4000-8000-000000000001",
"domain": "family",
"event_kind": "family_event",
"date_start": "2016-09-15",
"date_end": "2016-09-15",
"precision": "day",
"summary": "家人变化",
}
assert is_scoreable_event(event) is True
assert is_primary_scoreable_event(event) is True
coerced = normalize_rectification_request(
{
"birth_date": "1997-08-08",
"start_time": "05:13",
"end_time": "05:15",
"lat": 36.419,
"lon": 114.213,
"tz": 8,
"events": [{**event, "subject": "self"}],
},
today=date(2026, 7, 28),
)
assert coerced["events"][0]["subject"] == "family"
normalized = normalize_rectification_request(
{
"birth_date": "1997-08-08",
"start_time": "05:13",
"end_time": "05:15",
"lat": 36.419,
"lon": 114.213,
"tz": 8,
"events": [event],
},
today=date(2026, 7, 28),
)
assert normalized["events"][0]["subject"] == "family"
def test_career_event_always_exposes_d1_tenth_and_d10_layers() -> None:
prefixes, houses = DOMAIN_CONFIG["career"]
assert prefixes == ("D10",)
assert houses == (10,)
layers = public_technique_layers("career", ["vim_md_domain_house", "vim_md_domain_varga"])
assert "d1-rashi" in layers
assert "d10-dashamsa" in layers
scored = _score_event(
candidate_time="05:13",
event={
"id": "00000000-0000-4000-8000-000000000004",
"domain": "career",
"event_kind": "career_entry",
"date": "2016-09-15",
"precision": "day",
},
natal_chart={"ascendant": {"lon": 10.0, "sign": "Aries"}, "planets": {"Sun": {"house": 10, "lon": 12.0}}},
varga_charts=[{"Ascendant": {"sign_idx": 0}, "Sun": {"sign_idx": 9}}],
vimshottari=("Sun", "Moon", "Mars"),
narayana=(None, None),
arudha_padas={},
)
assert any(item.endswith("_domain_house") for item in scored["rule_ids"])
assert any(item.endswith("_domain_varga") for item in scored["rule_ids"])
def test_appearance_is_auxiliary_first_house_not_primary() -> None:
prefixes, houses = DOMAIN_CONFIG["appearance"]
assert prefixes == ()
assert houses == (1,)
assert "appearance" in AUXILIARY_DOMAINS
assert AUXILIARY_SCORE_FACTOR == 0.4
natal = {
"ascendant": {"lon": 10.0, "sign": "Aries"},
"planets": {"Sun": {"house": 1, "lon": 12.0}},
}
scored = _score_event(
candidate_time="05:13",
event={
"id": "00000000-0000-4000-8000-000000000002",
"domain": "appearance",
"event_kind": "birthmark_or_scar",
"date": "2010-01-01",
"precision": "year",
},
natal_chart=natal,
varga_charts=[],
vimshottari=("Sun", "Moon", "Mars"),
narayana=(None, None),
arudha_padas={},
)
assert "appearance_auxiliary_not_primary" in scored["rule_ids"]
primary = _score_event(
candidate_time="05:13",
event={
"id": "00000000-0000-4000-8000-000000000003",
"domain": "career",
"event_kind": "career_entry",
"date": "2010-01-01",
"precision": "year",
},
natal_chart={"ascendant": {"lon": 10.0, "sign": "Aries"}, "planets": {"Sun": {"house": 10, "lon": 12.0}}},
varga_charts=[{"Ascendant": {"sign_idx": 0}, "Sun": {"sign_idx": 9}}],
vimshottari=("Sun", "Moon", "Mars"),
narayana=(None, None),
arudha_padas={},
)
assert scored["points"] < primary["points"]
assert is_primary_scoreable_event({
"id": "00000000-0000-4000-8000-000000000002",
"domain": "appearance",
"event_kind": "appearance_note",
"date_start": "2010-01-01",
"date_end": "2010-12-31",
"precision": "year",
}) is False
def test_family_event_engine_rows_include_d12_and_are_not_skipped() -> None:
request = {
"birth_date": "1997-08-08",
"start_time": "05:13",
"end_time": "05:14",
"lat": 36.419,
"lon": 114.213,
"tz": 8.0,
"events": [{
"id": "00000000-0000-4000-8000-000000000001",
"domain": "family",
"event_kind": "family_event",
"date": "2016-09-15",
"precision": "day",
"summary": "家人变化",
}],
}
contexts = compute_candidate_static_contexts(request)
assert all("D12" in context["feature"]["available_layers"] for context in contexts)
assert all("D7" in context["feature"]["available_layers"] for context in contexts)
assert all("D3" in context["feature"]["available_layers"] for context in contexts)
assert all(context["varga_charts"]["D12"] is not None for context in contexts)
assert all(context["varga_charts"]["D7"] is not None for context in contexts)
assert all(context["varga_charts"]["D3"] is not None for context in contexts)
assert all(isinstance(context["feature"].get("pada_index"), int) for context in contexts)
assert all(0 <= context["feature"]["pada_index"] <= 107 for context in contexts)
assert all(isinstance(context["feature"].get("bhava_sign_index"), int) for context in contexts)
rows = compute_event_candidate_rows(request, static_contexts=contexts)
assert [row["time"] for row in rows] == ["05:13", "05:14"]
for row in rows:
assert "D12" not in row["missing_layers"]
assert "D7" not in row["missing_layers"]
assert row["evidence"], "family events must enter scoring instead of being skipped"
assert row["evidence"][0]["domain"] == "family"
assert "event_kind:family_event" in row["evidence"][0]["rule_ids"]
career = {
**request,
"events": [{
"id": "00000000-0000-4000-8000-000000000004",
"domain": "career",
"event_kind": "career_entry",
"date": "2016-09-15",
"precision": "day",
}],
}
career_rows = compute_event_candidate_rows(career, static_contexts=contexts)
assert all(row["evidence"] for row in career_rows)
career_rules = [rule for row in career_rows for item in row["evidence"] for rule in item["rule_ids"]]
layers = public_technique_layers("career", career_rules)
assert "d1-rashi" in layers and "d10-dashamsa" in layers
family_layers = public_technique_layers("family", ["vim_md_domain_house", "vim_md_domain_varga"])
assert "d12-dwadashamsha" in family_layers and "d7-saptamsha" in family_layers
assert "d3-drekkana" in family_layers
education_layers = public_technique_layers("education", ["vim_md_domain_house"])
assert "d5-panchamsha" in education_layers and "d24-chaturvimshamsha" in education_layers
finance_layers = public_technique_layers("finance", ["vim_md_domain_house"])
assert "d2-hora" in finance_layers and "d11-labhamsha" in finance_layers
health_layers = public_technique_layers("health_pressure", ["vim_md_domain_house"])
assert "d30-trimshamsha" in health_layers
occupation_layers = public_technique_layers("occupation", ["vim_md_domain_house"])
assert "d1-rashi" in occupation_layers and "d10-dashamsa" in occupation_layers
assert all("D10" in context["feature"]["available_layers"] for context in contexts)
assert all("D5" in context["feature"]["available_layers"] for context in contexts)
def test_occupation_is_auxiliary_tenth_house_independent_of_career() -> None:
prefixes, houses = DOMAIN_CONFIG["occupation"]
assert prefixes == ("D10",)
assert houses == (10,)
assert "occupation" in AUXILIARY_DOMAINS
event = {
"id": "00000000-0000-4000-8000-000000000005",
"domain": "occupation",
"event_kind": "occupation_note",
"date_start": "2019-01-01",
"date_end": "2019-12-31",
"precision": "year",
"summary": "长期工作",
}
assert is_scoreable_event(event) is True
assert is_primary_scoreable_event(event) is False
scored = _score_event(
candidate_time="05:13",
event={
"id": event["id"],
"domain": "occupation",
"event_kind": "occupation_note",
"date": "2019-01-01",
"precision": "year",
},
natal_chart={"ascendant": {"lon": 10.0, "sign": "Aries"}, "planets": {"Sun": {"house": 10, "lon": 12.0}}},
varga_charts=[{"Ascendant": {"sign_idx": 0}, "Sun": {"sign_idx": 9}}],
vimshottari=("Sun", "Moon", "Mars"),
narayana=(None, None),
arudha_padas={},
)
assert "occupation_auxiliary_not_primary" in scored["rule_ids"]
career = _score_event(
candidate_time="05:13",
event={
"id": "00000000-0000-4000-8000-000000000006",
"domain": "career",
"event_kind": "career_entry",
"date": "2019-01-01",
"precision": "year",
},
natal_chart={"ascendant": {"lon": 10.0, "sign": "Aries"}, "planets": {"Sun": {"house": 10, "lon": 12.0}}},
varga_charts=[{"Ascendant": {"sign_idx": 0}, "Sun": {"sign_idx": 9}}],
vimshottari=("Sun", "Moon", "Mars"),
narayana=(None, None),
arudha_padas={},
)
assert scored["points"] < career["points"]