84e6191fc2
Co-authored-by: Cursor <cursoragent@cursor.com>
255 lines
9.9 KiB
Python
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"]
|