Files
Jyotisha/tests/test_annual_tajika_pack.py
T
Jesse_Chen bab0718700
Independent Staging Quality Gate / validate (push) Failing after 9m41s
Independent Staging Quality Gate / publish (push) Has been skipped
feat(report): ship full-mode longform appendix beside the five-chapter report
Web export now calls the same full pack as the long skill report and caches an owner-only Markdown download. Appendix failure stays unavailable and does not change the main report status.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-05 11:10:44 +08:00

349 lines
15 KiB
Python
Executable File

import pytest
from scripts import annual_tajika_pack
from scripts.annual_tajika_pack import build_annual_tajika_pack
def _payload():
return {
"birth": {
"date": "1990-01-01",
"time": "12:00:00",
"utc_offset": "+08:00",
"place": "Beijing, China",
"latitude": 39.9,
"longitude": 116.4,
"coordinate_precision": "city",
},
"settings": {
"ayanamsa": "lahiri",
"node_mode": "mean",
"house_system": "whole_sign",
"position_mode": "legacy",
"dasha_year_days": 365.25,
"solar_return_location_mode": "birth_place",
"annual_year_policy": "solar_return_exact",
},
"target_year": 2026,
"age": 36,
}
def test_builds_annual_tajika_pack_contract() -> None:
pack = build_annual_tajika_pack(_payload())
assert list(pack.keys()) == [
"schema",
"profile",
"solar_return",
"annual_chart",
"muntha",
"year_lord",
"tajika_yogas",
"sahams",
"mudda_dasha",
"patyayini_dasha",
"monthly_windows",
"external_engine_comparison",
"report_sections",
"exports",
"audit",
]
assert pack["schema"] == "jyotish.annual_tajika_pack.v1"
assert pack["profile"]["profile_id"]
assert pack["solar_return"]["status"] in {"partial_verified", "blocked"}
assert pack["annual_chart"]["status"] in {"partial_verified", "blocked"}
assert pack["muntha"]["status"] in {"partial_verified", "blocked", "conflict"}
assert pack["year_lord"]["status"] in {"partial_verified", "blocked", "conflict"}
assert pack["tajika_yogas"]["status"] in {"partial_verified", "blocked"}
assert pack["sahams"]["status"] in {"partial_verified", "blocked"}
assert isinstance(pack["mudda_dasha"]["periods"], list)
assert isinstance(pack["patyayini_dasha"]["periods"], list)
assert isinstance(pack["monthly_windows"], list)
assert pack["external_engine_comparison"]["status"] in {"blocked", "partial_verified"}
assert pack["report_sections"]["executive_summary"]["status"] in {"blocked", "parameter_sensitive"}
assert isinstance(pack["report_sections"]["executive_summary"]["quick_takeaways"], list)
assert "tajika_yogas" in pack["report_sections"]["evidence_appendix"]["field_briefs"]
assert "sahams" in pack["report_sections"]["evidence_appendix"]["field_briefs"]
assert pack["report_sections"]["evidence_appendix"]["must_not_claim"] == ["exact_annual_event_prediction"]
assert pack["exports"]["json"]["schema"] == pack["schema"]
assert pack["exports"]["ai_evidence_bundle"]["profile_id"] == pack["profile"]["profile_id"]
unified = pack["exports"]["unified_report_pack_contract"]
assert unified["schema"] == "pl9.unified_report_pack_contract.v1"
assert unified["pack_id"] == "annual_tajika_pack"
assert unified["status"] in {"blocked", "parameter_sensitive"}
assert unified["status"] == pack["report_sections"]["executive_summary"]["status"]
assert pack["audit"]["technique_audit"][0]["technique"] == "Calculation Profile"
def test_annual_tajika_pack_marks_muntha_and_year_lord_conflicts() -> None:
pack = build_annual_tajika_pack(
_payload(),
solar_return_report={
"solar_return": {"dt_ut": "2026-01-01 00:00:00"},
"sr_chart_info": {"ascendant": {"sign": "Leo"}},
"muntha": {"muntha_sign": "Taurus", "muntha_lord": "Venus"},
"year_lord": {"year_lord": "Venus"},
},
tajika_report={
"muntha": {"muntha_sign": "Cancer", "muntha_lord": "Moon"},
"year_lord": {"year_lord": "Moon"},
},
)
assert pack["muntha"]["status"] == "conflict"
assert pack["muntha"]["values"] == [
{"producer": "solar_return", "value": {"muntha_sign": "Taurus", "muntha_lord": "Venus"}},
{"producer": "tajika", "value": {"muntha_sign": "Cancer", "muntha_lord": "Moon"}},
]
assert pack["year_lord"]["status"] == "conflict"
assert pack["year_lord"]["values"] == [
{"producer": "solar_return", "value": {"year_lord": "Venus"}},
{"producer": "tajika", "value": {"year_lord": "Moon"}},
]
assert pack["report_sections"]["executive_summary"]["status"] == "parameter_sensitive"
assert "muntha" in pack["report_sections"]["executive_summary"]["blocked_fields"]
assert "year_lord" in pack["report_sections"]["executive_summary"]["blocked_fields"]
def test_annual_tajika_pack_year_lord_conflict_exposes_canonical_field_contract() -> None:
pack = build_annual_tajika_pack(
_payload(),
solar_return_report={
"solar_return": {"dt_ut": "2026-01-01 00:00:00"},
"year_lord": {"year_lord": "Venus", "year_lord_sign": "Taurus"},
},
tajika_report={
"year_lord": {"year_lord": "Moon", "year_lord_sign": "Cancer"},
},
)
year_lord = pack["year_lord"]
assert year_lord["status"] == "conflict"
assert year_lord["field"] == "year_lord"
assert year_lord["reason"] == "same_profile_annual_producers_disagree"
assert year_lord["values"] == [
{"producer": "solar_return", "value": {"year_lord": "Venus", "year_lord_sign": "Taurus"}},
{"producer": "tajika", "value": {"year_lord": "Moon", "year_lord_sign": "Cancer"}},
]
assert "year_lord" in pack["report_sections"]["executive_summary"]["blocked_fields"]
def test_annual_tajika_pack_propagates_nested_blocked_field_statuses() -> None:
pack = build_annual_tajika_pack(
_payload(),
solar_return_report={
"solar_return": {"dt_ut": "2026-01-01 00:00:00"},
"tajika_yogas": {"status": "blocked", "reason": "legacy_tajika_input_lacks_planet_speeds"},
"sahams": {"status": "blocked", "reason": "saham_daynight_requires_wgs84_location_and_timezone"},
},
tajika_report={},
)
assert pack["tajika_yogas"]["status"] == "blocked"
assert pack["tajika_yogas"]["reason"] == "legacy_tajika_input_lacks_planet_speeds"
assert pack["sahams"]["status"] == "blocked"
assert pack["sahams"]["reason"] == "saham_daynight_requires_wgs84_location_and_timezone"
assert pack["report_sections"]["evidence_appendix"]["field_briefs"]["tajika_yogas"] == "Tajika Yogas: blocked"
assert pack["report_sections"]["evidence_appendix"]["field_briefs"]["sahams"] == "Sahams: blocked"
def test_annual_tajika_pack_exposes_tajika_and_sahams_reader_briefs_when_visible() -> None:
pack = build_annual_tajika_pack(
_payload(),
solar_return_report={
"solar_return": {"dt_ut": "2026-01-01 00:00:00"},
"sr_chart_info": {"ascendant": {"sign": "Leo"}},
"muntha": {"muntha_sign": "Taurus", "muntha_lord": "Venus"},
"year_lord": {"year_lord": "Venus"},
"tajika_yogas": {"ithasala": ["Sun/Mars"]},
"sahams": {"punya_saham": {"longitude": 123.4}},
},
tajika_report={},
)
appendix = pack["report_sections"]["evidence_appendix"]
assert appendix["field_briefs"]["tajika_yogas"] == "Tajika Yogas: annual candidate structures visible"
assert appendix["field_briefs"]["sahams"] == "Sahams: annual sensitive points visible"
assert pack["report_sections"]["executive_summary"]["quick_takeaways"] == [
"Muntha: Taurus / Venus",
"Year Lord: Venus",
]
def test_annual_tajika_pack_promotes_governed_named_yoga_authority_when_motion_inputs_exist() -> None:
pack = build_annual_tajika_pack(
_payload(),
solar_return_report={
"solar_return": {"dt_ut": "2026-01-01 00:00:00"},
"sr_chart_info": {"ascendant": {"sign": "Leo"}},
"muntha": {"muntha_sign": "Taurus", "muntha_lord": "Venus"},
"year_lord": {"year_lord": "Venus"},
"chart": {
"planets": {
"Sun": {"degree_raw": 0, "speed": 1.0},
"Moon": {"degree_raw": 49, "speed": 13.0},
"Mars": {"degree_raw": 180, "speed": 0.5},
"Mercury": {"degree_raw": 260, "speed": 1.2},
"Jupiter": {"degree_raw": 310, "speed": 0.08},
"Venus": {"degree_raw": 130, "speed": 1.0},
"Saturn": {"degree_raw": 220, "speed": 0.03},
}
},
"tajika_yogas": {"legacy_surface": "still_present_but_not_primary"},
},
tajika_report={},
)
tajika_field = pack["tajika_yogas"]
authority = tajika_field["data"]
appendix = pack["report_sections"]["evidence_appendix"]
assert tajika_field["status"] == "partial_verified"
assert tajika_field["producer"] == "Tajika Named Yoga Authority"
assert tajika_field["data_contract"] == "governed_named_yoga_authority_surface"
assert authority["status"] == "authority_ready"
assert authority["supported_named_yogas"] == ["Ithasala", "Easarapha"]
assert authority["blocked_named_yogas"] == ["Nakta", "Yamaya", "Manahoo", "Kamboola"]
assert appendix["field_briefs"]["tajika_yogas"] == "Tajika Yogas: governed authority surface visible for Ithasala/Easarapha (8 rows)"
assert pack["audit"]["technique_audit"][5] == {"technique": "Tajika Yogas", "status": "partial_verified"}
def test_annual_tajika_pack_accepts_pyjhora_external_replay_result() -> None:
replay = {
"engine": "PyJHora/JHora",
"license_boundary": {"mode": "external_reference_only"},
"input_profile_id": "will_be_replaced_by_builder_check",
"mudda_dasha": {"status": "partial_verified", "raw": {"periods": []}},
"patyayini_dasha": {"status": "partial_verified", "raw": {"periods": []}},
"sahams": {"status": "partial_verified", "raw": {}},
"solar_return_boundary": {"status": "partial_verified", "raw": []},
"status": "partial_verified",
}
pack = build_annual_tajika_pack(_payload(), pyjhora_replay=replay)
assert pack["external_engine_comparison"]["status"] == "partial_verified"
assert pack["external_engine_comparison"]["pyjhora"]["engine"] == "PyJHora/JHora"
assert pack["external_engine_comparison"]["pyjhora"]["license_boundary"]["mode"] == "external_reference_only"
assert pack["audit"]["technique_audit"][-1]["technique"] == "PyJHora Annual Replay"
assert pack["audit"]["technique_audit"][-1]["status"] == "partial_verified"
def test_annual_tajika_pack_preserves_patyayini_replay_tuple_semantics() -> None:
replay = {
"engine": "PyJHora/JHora",
"license_boundary": {"mode": "external_reference_only"},
"status": "partial_verified",
"evidence_scope": "pyjhora_behavior_only",
"parity_status": "not_multiengine_parity",
"patyayini_dasha": {
"status": "partial_verified",
"raw": {"periods": [((1, "L"), (2022, 2, 17, 5.63431528955698), 0.0438458145826713)]},
},
}
pack = build_annual_tajika_pack(_payload(), pyjhora_replay=replay)
patyayini = pack["external_engine_comparison"]["pyjhora"]["patyayini_dasha"]
assert patyayini["status"] == "partial_verified"
assert patyayini["normalized_rows"] == [{
"order": 1,
"main_code": 1,
"sub_code": "L",
"boundary_components": {"year": 2022, "month": 2, "day": 17, "hour_decimal": 5.63431528955698},
"boundary_display": "2022-02-17 05:38:03",
"duration_raw": 0.0438458145826713,
"timezone_semantics": "not_returned_by_pyjhora_tuple",
"boundary_semantics": "unresolved_external_tuple_boundary",
"evidence_status": "pyjhora_behavior_only / not_multiengine_parity",
}]
assert pack["patyayini_dasha"]["periods"] == []
def test_annual_tajika_pack_keeps_runtime_year_lord_replay_as_single_engine_evidence() -> None:
replay = {
"engine": "PyJHora/JHora",
"license_boundary": {"mode": "external_reference_only"},
"status": "partial_verified",
"evidence_scope": "pyjhora_behavior_only",
"parity_status": "not_multiengine_parity",
"year_lord_replay": {
"status": "partial_verified",
"reason": "pyjhora_tajaka_year_lord_callable_observed",
"callable": "jhora.horoscope.transit.tajaka.lord_of_the_year",
"pyjhora_version": "4.8.7",
"effective_ayanamsa": "LAHIRI",
"request_hash": "a" * 64,
"node_mode": {"requested": "mean", "status": "unsupported_by_replay_adapter"},
},
}
pack = build_annual_tajika_pack(_payload(), pyjhora_replay=replay)
external = pack["external_engine_comparison"]
assert external["evidence_scope"] == "pyjhora_behavior_only"
assert external["parity_status"] == "not_multiengine_parity"
assert external["raw_evidence_paths"] == []
assert external["raw_evidence_status"] == "runtime_observation_not_archived"
assert external["year_lord_replay"]["node_mode"]["status"] == "unsupported_by_replay_adapter"
assert pack["year_lord"]["status"] in {"partial_verified", "blocked", "conflict"}
def test_annual_tajika_pack_marks_vedastro_as_base_chart_boundary_not_varshaphala() -> None:
vedastro = {
"engine": "VedAstro official",
"status": "partial_verified_for_base_chart",
"chart_core": {"status": "partial_verified", "fields": ["Sun", "Moon", "Ascendant"]},
"dasha_all": {"status": "partial_verified", "range": "2026-01-01/2026-12-31"},
"varshaphala_status": "blocked",
"supported_annual_methods": [],
"secret_redaction": {"secret_material_included": False},
}
pack = build_annual_tajika_pack(_payload(), vedastro_reference=vedastro)
comparison = pack["external_engine_comparison"]
assert comparison["status"] == "partial_verified"
assert comparison["vedastro"]["status"] == "partial_verified_for_base_chart"
assert comparison["vedastro"]["varshaphala_status"] == "blocked"
assert comparison["vedastro"]["supported_annual_methods"] == []
assert "api_key" not in repr(comparison).lower()
assert pack["audit"]["technique_audit"][-1]["technique"] == "VedAstro Annual Boundary"
assert pack["audit"]["technique_audit"][-1]["status"] == "partial_verified_for_base_chart"
def test_annual_tajika_pack_infers_age_from_target_year_for_tajika_branch(monkeypatch: pytest.MonkeyPatch) -> None:
payload = _payload()
payload.pop("age")
captured = {}
def fake_solar_return(args):
return {
"solar_return": {"dt_ut": "2026-01-01 00:00:00"},
"sr_chart_info": {"ascendant": {"sign": "Leo"}},
"muntha": {"muntha_sign": "Taurus", "muntha_lord": "Venus"},
"year_lord": {"year_lord": "Venus", "year_lord_sign": "Taurus"},
}
def fake_tajika(args):
captured["age"] = args.age
return {
"muntha": {"muntha_sign": "Cancer", "muntha_lord": "Moon"},
"year_lord": {"year_lord": "Moon", "year_lord_sign": "Cancer"},
}
monkeypatch.setattr(annual_tajika_pack, "_safe_solar_return", fake_solar_return)
monkeypatch.setattr(annual_tajika_pack, "_safe_tajika", fake_tajika)
pack = build_annual_tajika_pack(payload)
assert captured["age"] == 36
assert pack["year_lord"]["status"] == "conflict"
assert pack["year_lord"]["values"] == [
{"producer": "solar_return", "value": {"year_lord": "Venus", "year_lord_sign": "Taurus"}},
{"producer": "tajika", "value": {"year_lord": "Moon", "year_lord_sign": "Cancer"}},
]