Round-4 astrologer ruling Q3. tajika.calc_panchadhikari_year_lord and its
missing pieces (Tri-Rasi tables, planet index maps, ayanamsa-aware PyJHora
lookups) plus references/tajika_panchavargiya_rules.json (blob e8c15ac3) are
ported verbatim from yinduzhanxing c7117f92, with one keyword added
(muntha_sign_idx): upstream builds the Muntha-lord candidate from the annual
Lagna + years; ours stays natal Lagna + completed years (BUG-1212).
Both annual producers (solar_return_full_report, cmd_tajika) call the new
tajika_year_lord.select_annual_year_lord, so the pack conflict gate compares
the same rule. Output carries candidates / candidate_list with Panchavargiya
score and engine, aspect flags, selection_basis and a one-sentence basis
(zh/en). The product path always uses the native proxy (PyJHora is AGPL, absent
from the API image and CI); JYOTISH_YEAR_LORD_PYJHORA_REFERENCE=1 restores the
upstream PyJHora lookup for research. Card varshesha_basis and the report
'Selection basis' rows show the sentence; the BUG-1212 stand-in label is gone.
Mudda Dasha and Tri-Pataka follow the selected year lord.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N4f2nya58RoRu4yEmJgRGE
99 lines
5.5 KiB
Python
99 lines
5.5 KiB
Python
"""Year lord shows its selection basis on every surface (BUG-1212 → BUG-1214).
|
||
|
||
Astrologer rulings 2026-10-03 甲11 and round-4 Q3: Muntha = natal Lagna +
|
||
completed years (kept); the year lord is chosen by the Panchadhikari rule
|
||
(`tajika_year_lord`), and the card and both report editions carry its
|
||
one-sentence basis instead of the BUG-1212 "Muntha lord for now" label.
|
||
Fictional chart.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import copy
|
||
import re
|
||
from datetime import datetime
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
|
||
from scripts.consultation_native_layers import build_annual_tajika
|
||
from scripts.pl9_reader_export import _pl9_export_markdown_for_edition
|
||
from scripts.solar_return import SIGNS, solar_return_full_report
|
||
from tests.test_report_english_edition import CASES, _packet
|
||
|
||
ROOT = Path(__file__).resolve().parents[1]
|
||
|
||
|
||
@pytest.fixture(autouse=True)
|
||
def _native_panchavargiya(monkeypatch):
|
||
# Product path: native-proxy Panchavargiya unless the research opt-in is set.
|
||
monkeypatch.delenv("JYOTISH_YEAR_LORD_PYJHORA_REFERENCE", raising=False)
|
||
|
||
|
||
def test_report_shows_the_basis_in_both_editions() -> None:
|
||
# 原值:两版都断言「暂用 Muntha 主星;占星师口径为 Panchavargiya,待接入」
|
||
# 新值:断言 Panchadhikari 选法依据一句话(中文版含「年盘上升」与「本地近似计算」,
|
||
# 英文版是同一句的英文、不含中文)
|
||
# 原因:BUG-1214 接入 Panchadhikari 年主选法,去掉 BUG-1212 的暂用标注(任务书 T2)
|
||
packet = _packet(CASES["day"])
|
||
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 and "Panchavargiya 为本地近似计算" in row for row in zh_rows)
|
||
assert en_rows and all("annual Lagna" in row and "local approximation" in row for row in en_rows)
|
||
assert not re.search(r"[\u4e00-\u9fff]", "\n".join(en_rows))
|
||
assert "暂用 Muntha 主星" not in zh
|
||
assert zh.count("| Varshesha |") == zh.count("| Selection basis |")
|
||
|
||
|
||
def test_consultation_annual_card_carries_the_basis() -> None:
|
||
case = CASES["day"]
|
||
payload = {key: case[key] for key in ("year", "month", "day", "hour", "minute", "second", "lat", "lon", "tz", "ayanamsa", "node_mode")}
|
||
from scripts.jyotish_engine import compute_chart_data
|
||
chart, *_ = compute_chart_data(case["year"], case["month"], case["day"], case["hour"], case["minute"],
|
||
case["lat"], case["lon"], case["tz"], ayanamsa_name=case["ayanamsa"])
|
||
annual = build_annual_tajika(payload, chart, reference=datetime(2026, 10, 3))
|
||
assert annual["status"] == "parameter_sensitive"
|
||
# 原值:varshesha_basis == YEAR_LORD_BASIS(「暂用 Muntha 主星…待接入」)
|
||
# 新值:varshesha_basis 是年主选法依据一句话(tajika_year_lord.selection_basis_text)
|
||
# 原因:BUG-1214(任务书 T2)
|
||
assert "年盘上升" in annual["varshesha_basis"] and "暂用" not in annual["varshesha_basis"]
|
||
assert annual["varshesha_basis"].endswith("(Panchavargiya 为本地近似计算)")
|
||
card = (ROOT / "frontend/src/lib/consultation-evidence-card.ts").read_text(encoding="utf-8")
|
||
assert '"varshesha", "varshesha_basis"' in card
|
||
workflow = (ROOT / "frontend/src/mastra/consultation-workflow.ts").read_text(encoding="utf-8")
|
||
assert '"varsheshabasis"' in workflow
|
||
|
||
|
||
def test_main_path_muntha_is_natal_lagna_plus_completed_years() -> None:
|
||
from scripts.jyotish_engine import compute_chart_data
|
||
|
||
case = CASES["day"]
|
||
report = solar_return_full_report(case["year"], case["month"], case["day"], case["hour"], case["minute"],
|
||
case["lat"], case["lon"], case["tz"], 2026, ayanamsa_name="raman")
|
||
_chart, natal_asc, *_ = compute_chart_data(case["year"], case["month"], case["day"], case["hour"], case["minute"],
|
||
case["lat"], case["lon"], case["tz"], ayanamsa_name="raman")
|
||
muntha = report["muntha"]
|
||
completed = 2026 - case["year"]
|
||
assert (muntha["natal_asc_sign_idx"], muntha["age"]) == (natal_asc, completed)
|
||
assert muntha["muntha_sign_idx"] == (natal_asc + completed) % 12
|
||
assert muntha["muntha_sign"] == SIGNS[muntha["muntha_sign_idx"]]
|
||
# 原值:年主 == Muntha 主星
|
||
# 新值:年主由 Panchadhikari 选出;Muntha 主星一定在候选里(来源 muntha_lord),
|
||
# 候选 Muntha 用的是「本命上升 + 已满年数」
|
||
# 原因:BUG-1214(第四轮问 3)
|
||
year_lord = report["year_lord"]
|
||
assert year_lord["muntha_basis"] == "natal_ascendant_plus_completed_years"
|
||
assert year_lord["muntha_sign_idx"] == muntha["muntha_sign_idx"]
|
||
planets = {row["planet"] for row in year_lord["candidates"]}
|
||
assert muntha["muntha_lord"] in planets and year_lord["year_lord"] in planets
|
||
|
||
|
||
def test_sun_sign_muntha_variant_is_off_the_main_path() -> None:
|
||
pattern = re.compile(r"^\s*(from\s+(scripts\.)?muntha\s+import|import\s+(scripts\.)?muntha\b)|_load_local_module\(['\"]muntha['\"]\)", re.MULTILINE)
|
||
offenders = [path.name for path in (ROOT / "scripts").glob("*.py") if path.name != "muntha.py" and pattern.search(path.read_text(encoding="utf-8"))]
|
||
assert offenders == []
|