"""BUG-1318: D9 marriage rating is an evidence band, not an outcome claim. Upstream f891a2c1. The five bands must not say the relationship is stable, ending, repeated, or in need of premarital counseling. The DK evidence line keeps the 0-1 index and does not print a fake /100 score. """ from __future__ import annotations import importlib.util import json import os import re import sys from pathlib import Path ROOT = os.path.join(os.path.dirname(__file__), "..") SCRIPTS = os.path.join(ROOT, "scripts") if SCRIPTS not in sys.path: sys.path.insert(0, SCRIPTS) from jyotish_engine import compute_chart_data # noqa: E402 def _api_handler(): """Reuse the existing unbound handler helper. Do not add another forgery site.""" path = os.path.join(os.path.dirname(__file__), "test_api_server_security.py") spec = importlib.util.spec_from_file_location("_api_security_helpers", path) module = importlib.util.module_from_spec(spec) spec.loader.exec_module(module) return module._handler() from marriage_counting import ( # noqa: E402 D9_CLAIM_BOUNDARY, D9_EVIDENCE_BANDS, _assess_d9_marriage_quality, marriage_counting_full_analysis, render_d9_evidence_report, ) from varga import calc_varga # noqa: E402 BANNED = re.compile(r"稳定|离婚|再婚|婚前咨询|几段") def _quality(points_chart: dict) -> dict: return _assess_d9_marriage_quality(points_chart, None) def test_five_bands_have_no_outcome_claims_and_keep_the_boundary() -> None: samples = { "supportive_evidence_stronger": {"Venus": 331.0, "Mars": 271.0, "Jupiter": 91.0}, "supportive_evidence_mixed_positive": {"Venus": 31.0}, "mixed_evidence": {"Venus": 10.0}, "pressure_evidence_mixed": {"Venus": 151.0}, "pressure_evidence_stronger": {"Venus": 151.0, "Mars": 91.0, "Jupiter": 271.0}, } seen = [] for key, chart in samples.items(): quality = _quality(chart) assert quality["quality_band"] == key assert quality["claim_boundary"] == D9_CLAIM_BOUNDARY assert quality["claim_boundary_en"] assert not BANNED.search(quality["quality_rating"]) assert not BANNED.search(quality["quality_rating_en"]) seen.append(quality["quality_band"]) assert seen == [band[0] for band in D9_EVIDENCE_BANDS] def test_public_chart_report_snapshots_in_both_languages() -> None: cases = json.loads( Path(ROOT, "references/real_case_calibration/minute_rectification_development_v1.json").read_text(encoding="utf-8") )["cases"] birth = next(case for case in cases if case["case_id"] == "steve_jobs_1955_development")["birth"] assert birth["source"]["rodden_rating"] == "AA" year, month, day = (int(part) for part in birth["date"].split("-")) hour, minute = (int(part) for part in birth["time"].split(":")) chart, *_ = compute_chart_data( year, month, day, hour, minute, birth["latitude"], birth["longitude"], birth["timezone_offset"], ayanamsa_name="raman", ) longitudes = {name: row["degree_raw"] for name, row in chart["planets"].items()} d9 = {} for name, lon in longitudes.items(): divisional = calc_varga(lon, 9) d9[name] = divisional["sign_idx"] * 30 + divisional["degree_in_sign"] result = marriage_counting_full_analysis(chart["houses"]["house_7"]["lord"], longitudes, d9) quality = result["d9_marriage_quality"] assert quality["quality_band"] == "mixed_evidence" assert quality["quality_points"] == 0 chinese = render_d9_evidence_report(quality, "zh") english = render_d9_evidence_report(quality, "en") assert chinese == ( "D9 证据档位:证据混杂\n" "D9 结构证据指数,不预测婚姻次数、稳定、离婚、伴侣好坏,也不提示需要婚前咨询" ) assert english == ( "D9 evidence band: Mixed evidence\n" "D9 structural evidence index. It does not predict marriage count, stability, " "divorce, or partner quality, and it does not suggest premarital counseling." ) assert "/100" not in chinese assert "/100" not in english def test_dk_evidence_line_prints_the_zero_to_one_index() -> None: cases = json.loads( Path(ROOT, "references/real_case_calibration/minute_rectification_development_v1.json").read_text(encoding="utf-8") )["cases"] birth = next(case for case in cases if case["case_id"] == "steve_jobs_1955_development")["birth"] year, month, day = (int(part) for part in birth["date"].split("-")) hour, minute = (int(part) for part in birth["time"].split(":")) chart, asc_idx, *_ = compute_chart_data( year, month, day, hour, minute, birth["latitude"], birth["longitude"], birth["timezone_offset"], ayanamsa_name="raman", ) longitudes = {name: row["degree_raw"] for name, row in chart["planets"].items()} handler = _api_handler() evidence = handler._compute_relationship_timing_evidence( {}, chart["planets"], longitudes, asc_idx, chart["ascendant"]["sign"], ) notes = [row["note"] for row in evidence["evidence"] if row.get("label") == "Darakaraka (DK)"] assert len(notes) == 1 assert "/100" not in notes[0] assert "婚姻质量指数" in notes[0] assert "(0到1)" in notes[0] score = evidence["darakaraka"]["marriage_quality_score"] assert isinstance(score, float) assert 0.0 <= score <= 1.0 assert str(score) in notes[0]