fix(tajika): year lord blocked instead of Muntha-lord stand-in (BUG-1223)
Panchadhikari blocked -> status blocked + reason, year_lord None, sentence 「年主暂无法确定(原因)」 on card and report; Tri-Pataka blocked with it; Mudda unchanged. Aligned with upstream 03bea6ed. Nine public charts: both producers byte-identical before/after. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
77645ce25f
commit
7dda1b45c3
@@ -0,0 +1,149 @@
|
||||
"""Year lord: no stand-in when Panchadhikari is blocked (BUG-1223).
|
||||
|
||||
Product owner 2026-10-04 (batch 5 T5), aligned with upstream yinduzhanxing
|
||||
03bea6ed (`docs/research/tajika_shared_entrypoint_repair_2026_10_03.md`
|
||||
item 3): when the year lord cannot be chosen (annual chart incomplete) the
|
||||
producers return `status: "blocked"` with the reason and no planet; the
|
||||
Muntha sign lord is no longer put in its place. The card and the report show
|
||||
"年主暂无法确定(原因)". Mudda is independent of the year lord (BUG-1216).
|
||||
Fictional chart.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import re
|
||||
import types
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
import tajika_year_lord as year_lord_module # the name the producers import
|
||||
from scripts.pl9_reader_english_terms import PHRASES_EN
|
||||
|
||||
BLOCKED = {"status": "blocked", "reason": "sun_or_moon_missing_for_panchadhikari"}
|
||||
FICTIONAL = {"birth": {"date": "1990-01-01", "time": "12:00:00", "latitude": 39.9, "longitude": 116.4, "utc_offset": "+08:00"},
|
||||
"settings": {"ayanamsa": "raman"}}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def blocked_selector(monkeypatch):
|
||||
monkeypatch.delenv("JYOTISH_YEAR_LORD_PYJHORA_REFERENCE", raising=False)
|
||||
monkeypatch.setattr(year_lord_module, "calc_panchadhikari_year_lord", lambda *a, **k: dict(BLOCKED))
|
||||
|
||||
|
||||
def test_selector_returns_blocked_without_a_stand_in_planet(blocked_selector) -> None:
|
||||
sr = {"asc_sign_idx": 0, "planet_lons": {}, "solar_return": {}, "annual_location": {}}
|
||||
data = year_lord_module.select_annual_year_lord(
|
||||
sr, natal_asc_sign_idx=4, completed_years=30, ayanamsa_name="raman",
|
||||
birth_lat=39.9, birth_lon=116.4, birth_tz=8.0)
|
||||
assert data["status"] == "blocked"
|
||||
assert data["reason"] == "sun_or_moon_missing_for_panchadhikari"
|
||||
assert data["year_lord"] is None
|
||||
assert "year_lord_sign" not in data and "fallback_reason" not in data
|
||||
assert data["selection_basis"] == year_lord_module.BLOCKED_BASIS
|
||||
assert data["selection_basis_text"] == "年主暂无法确定(年盘缺太阳或月亮位置)"
|
||||
assert data["selection_basis_text_en"].startswith("Year lord cannot be determined yet (")
|
||||
assert "Muntha" not in data["selection_basis_text"]
|
||||
|
||||
|
||||
def test_solar_return_producer_blocks_the_year_lord_and_tri_pataka_keeps_mudda(blocked_selector) -> None:
|
||||
from scripts.solar_return import solar_return_full_report
|
||||
|
||||
report = solar_return_full_report(1990, 1, 1, 12, 0, 39.9, 116.4, 8.0, 2026, ayanamsa_name="raman")
|
||||
assert report["year_lord"]["status"] == "blocked"
|
||||
assert report["year_lord"]["year_lord"] is None
|
||||
assert report["tri_pataka"] == {"status": "blocked", "reason": "year_lord_blocked"}
|
||||
assert report["mudda_dasha"]["status"] == "partial_verified"
|
||||
assert report["mudda_dasha"]["independent_of_year_lord"] is True
|
||||
|
||||
|
||||
def test_cmd_tajika_without_an_annual_chart_is_blocked_not_muntha_lord(monkeypatch) -> None:
|
||||
import solar_return as solar_return_module
|
||||
from scripts.jyotish_engine import cmd_tajika
|
||||
|
||||
monkeypatch.setattr(solar_return_module, "calc_solar_return_chart", lambda *a, **k: {"error": "fictional failure"})
|
||||
args = types.SimpleNamespace(year=1990, month=1, day=1, hour=12, minute=0, lat=39.9, lon=116.4, tz=8.0,
|
||||
age=36, mode="all", ayanamsa="raman")
|
||||
result = cmd_tajika(args)
|
||||
result = result.get("data", result) if isinstance(result.get("data"), dict) else result
|
||||
year_lord = result["year_lord"]
|
||||
assert year_lord["status"] == "blocked"
|
||||
assert year_lord["reason"] == "solar_return_chart_unavailable"
|
||||
assert year_lord["year_lord"] is None
|
||||
assert year_lord["selection_basis_text"] == "年主暂无法确定(年盘无法计算)"
|
||||
assert result["tri_pataka"] == {"status": "blocked", "reason": "year_lord_blocked"}
|
||||
|
||||
|
||||
def test_pack_and_card_show_the_blocked_sentence(blocked_selector) -> None:
|
||||
from scripts.annual_tajika_pack import build_annual_tajika_pack
|
||||
from scripts.consultation_native_layers import build_annual_tajika
|
||||
from scripts.jyotish_engine import compute_chart_data
|
||||
|
||||
pack = build_annual_tajika_pack({**FICTIONAL, "target_year": 2026})
|
||||
field = pack["year_lord"]
|
||||
assert field["status"] == "blocked"
|
||||
assert field["reason"] == "sun_or_moon_missing_for_panchadhikari"
|
||||
assert field["blocked_detail"]["year_lord"] is None
|
||||
assert pack["mudda_dasha"]["status"] == "partial_verified"
|
||||
|
||||
payload = {"year": 1990, "month": 1, "day": 1, "hour": 12, "minute": 0, "second": 0,
|
||||
"lat": 39.9, "lon": 116.4, "tz": 8.0, "ayanamsa": "raman", "node_mode": "mean"}
|
||||
chart, *_ = compute_chart_data(1990, 1, 1, 12, 0, 39.9, 116.4, 8.0, ayanamsa_name="raman")
|
||||
annual = build_annual_tajika(payload, chart, reference=datetime(2026, 10, 3))
|
||||
assert annual["status"] == "parameter_sensitive" # the card is not blocked by the year lord alone
|
||||
assert annual["varshesha"] is None
|
||||
assert annual["varshesha_basis"] == "年主暂无法确定(年盘缺太阳或月亮位置)"
|
||||
assert annual["mudda_dasha"]
|
||||
|
||||
|
||||
def test_report_shows_the_blocked_sentence_in_both_editions(blocked_selector) -> None:
|
||||
from scripts.annual_tajika_pack import build_annual_tajika_pack
|
||||
from scripts.pl9_reader_export import _pl9_export_markdown_for_edition
|
||||
from tests.test_report_english_edition import CASES, _packet
|
||||
|
||||
blocked_field = build_annual_tajika_pack({**FICTIONAL, "target_year": 2026})["year_lord"]
|
||||
packet = _packet(CASES["day"])
|
||||
replaced = 0
|
||||
|
||||
def walk(node):
|
||||
nonlocal replaced
|
||||
if isinstance(node, dict):
|
||||
for key, value in list(node.items()):
|
||||
if key == "year_lord" and isinstance(value, dict) and "producers_checked" in value:
|
||||
node[key] = copy.deepcopy(blocked_field)
|
||||
replaced += 1
|
||||
else:
|
||||
walk(value)
|
||||
elif isinstance(node, list):
|
||||
for value in node:
|
||||
walk(value)
|
||||
|
||||
walk(packet)
|
||||
assert replaced
|
||||
zh = _pl9_export_markdown_for_edition(copy.deepcopy(packet), "reader_main")
|
||||
english = copy.deepcopy(packet)
|
||||
english["report_language"] = "en"
|
||||
en = _pl9_export_markdown_for_edition(english, "reader_main")
|
||||
zh_rows = [line for line in zh.splitlines() if line.startswith("| Selection basis |")]
|
||||
en_rows = [line for line in en.splitlines() if line.startswith("| Selection basis |")]
|
||||
assert zh_rows and all("年主暂无法确定(年盘缺太阳或月亮位置)" in row for row in zh_rows)
|
||||
assert en_rows and all("Year lord cannot be determined yet" in row for row in en_rows)
|
||||
assert not re.search(r"[一-鿿]", "\n".join(en_rows))
|
||||
assert all("| Varshesha | - |" in zh for _ in zh_rows)
|
||||
|
||||
|
||||
def test_every_blocked_sentence_has_its_english_twin() -> None:
|
||||
phrases = dict(PHRASES_EN)
|
||||
for reason in [*year_lord_module.BLOCKED_REASON_TEXT, "unknown_reason"]:
|
||||
zh, en = year_lord_module.blocked_text(reason)
|
||||
assert phrases.get(zh) == en
|
||||
|
||||
|
||||
def test_no_producer_falls_back_to_the_muntha_lord() -> None:
|
||||
from pathlib import Path
|
||||
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
for name in ("tajika_year_lord.py", "solar_return.py", "jyotish_engine.py"):
|
||||
text = (root / "scripts" / name).read_text(encoding="utf-8")
|
||||
assert "fallback_muntha_sign_lord_after_panchadhikari_block" not in text
|
||||
Reference in New Issue
Block a user