Files
Jyotisha/tests/test_pyjhora_compare_cli.py
T
ClaudeandClaude Opus 5.5 74169e1bfc fix(benchmark): pass the ayanamsa to both engines and refuse a mismatched baseline
The local baseline still claimed "lahiri_assumed_by_skill" after the engine
default moved to Raman, so the PyJHora comparison reported 59% instead of
~95% (every longitude 1.446 deg off). The baseline now passes --ayanamsa and
--node-mode to the engine and records what the engine reports; the compare
takes --ayanamsa and stops when the baseline was built differently. The nine
public Rodden AA backtest figures join the fixed samples.

Raman run (19 samples): ascendant, planets, nakshatras, D2/D4/D9/D10 and
Ashtakavarga all 100%; Shadbala and three old-chart dashas differ (separate).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyeZrYn6ryNcSe5Y2Y
2026-11-04 11:55:22 +08:00

110 lines
4.8 KiB
Python

import subprocess
import sys
from datetime import datetime, timezone
from pathlib import Path
from benchmarks.jyotish.scripts.run_pyjhora_compare import write_report
from benchmarks.jyotish.scripts.run_pyjhora_compare import compare_one
ROOT = Path(__file__).resolve().parents[1]
RUNNER = ROOT / "benchmarks" / "jyotish" / "scripts" / "run_pyjhora_compare.py"
def test_pyjhora_compare_help_is_non_executing():
result = subprocess.run(
[sys.executable, str(RUNNER), "--help"], cwd=ROOT, capture_output=True, text=True, timeout=15
)
assert result.returncode == 0
assert "--build-local" in result.stdout
assert "--refresh-local" in result.stdout
assert "--output-prefix" in result.stdout
assert "FileNotFoundError" not in result.stderr
def test_pyjhora_report_uses_supplied_utc_generation_timestamp():
report = write_report(
[],
[],
generated_at=datetime(2026, 7, 15, 4, 30, tzinfo=timezone.utc),
)
assert "生成时间:2026-07-15T04:30:00+00:00" in report
assert "生成时间:2026-06-03" not in report
def test_pyjhora_comparison_includes_d2_d4_bav_sav_and_shadbala_rows():
bodies = ["Ascendant", "Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn", "Rahu", "Ketu"]
chart = {body: {"sign": "Aries", "degree_in_sign": 1.0} for body in bodies}
planet = {body: {"sign": "Aries", "degree_in_sign": 1.0, "nakshatra": "Ashwini", "nakshatra_pada": 1} for body in bodies[1:]}
local = {
"ascendant": chart["Ascendant"], "planets": planet,
"varga": {"D2": chart, "D4": chart, "D9": chart, "D10": chart},
"dasha": {},
"ashtakavarga": {"bav": {name: [1] * 12 for name in ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn", "Lagna"]}, "sav": [7] * 12},
"shadbala": {name: 100.0 for name in ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"]},
}
pyjhora = {
"ascendant": chart["Ascendant"], "planets": planet,
"varga": {"D2": chart, "D4": chart, "D9": chart, "D10": chart},
"dasha": {},
"ashtakavarga": local["ashtakavarga"], "shadbala": local["shadbala"],
}
sections = {row["section"] for row in compare_one("fixture", local, pyjhora)}
assert {"D2", "D4", "Ashtakavarga_BAV", "Ashtakavarga_SAV", "Shadbala"} <= sections
def test_baseline_records_the_engine_ayanamsa_and_the_compare_refuses_a_mismatch():
# 2026-11-04: the engine default moved from Lahiri to Raman while the
# baseline still claimed "lahiri_assumed_by_skill"; the comparison then
# reported 59% instead of ~95% because every longitude was 1.446 deg off.
from benchmarks.jyotish.scripts.run_pyjhora_compare import baseline_settings_error
from benchmarks.jyotish.scripts.run_skill_baseline import canonicalize
data = {"birth_info": {"ayanamsa_name": "raman", "node_mode": "mean"}, "modules": {"chart": {}}}
canon = canonicalize({"id": "fixture", "label": "x", "category": "smoke", "birth": {}}, data)
assert canon["parameters"]["ayanamsa"] == "raman"
assert canon["parameters"]["node_mode"] == "mean"
assert baseline_settings_error(canon, ayanamsa="raman", node_mode="mean") is None
assert "lahiri" in baseline_settings_error(canon, ayanamsa="lahiri", node_mode="mean")
assert "unrecorded" in baseline_settings_error({"parameters": {}}, ayanamsa="lahiri", node_mode="mean")
def test_baseline_passes_ayanamsa_and_node_mode_to_the_engine(monkeypatch, tmp_path):
from benchmarks.jyotish.scripts import run_skill_baseline as rsb
seen = {}
class Done:
returncode = 1
stdout = ""
stderr = "stub"
def fake_run(cmd, **kwargs):
seen["cmd"] = cmd
return Done()
monkeypatch.setattr(rsb, "RAW", tmp_path / "raw")
monkeypatch.setattr(rsb, "CANON", tmp_path / "canon")
monkeypatch.setattr(rsb.subprocess, "run", fake_run)
sample = {"id": "fixture", "birth": {"year": 2000, "month": 1, "day": 1, "hour": 0, "minute": 0, "lat": 0, "lon": 0, "tz": 0}}
rsb.run_sample(sample, ayanamsa="raman", node_mode="true")
cmd = seen["cmd"]
assert cmd[cmd.index("--ayanamsa") + 1] == "raman"
assert cmd[cmd.index("--node-mode") + 1] == "true"
rsb.run_sample(sample)
assert seen["cmd"][seen["cmd"].index("--ayanamsa") + 1] == "lahiri"
def test_fixed_samples_include_the_public_rodden_aa_backtest_figures():
import json
samples = json.loads((ROOT / "benchmarks" / "jyotish" / "data" / "benchmark_samples.json").read_text())
ids = {sample["id"] for sample in samples}
for figure in ["steve_jobs", "barack_obama", "elizabeth_taylor", "marilyn_monroe", "judy_garland", "edith_piaf", "frida_kahlo", "george_w_bush", "zinedine_zidane"]:
assert figure in ids
assert all(sample.get("privacy") in {"fictional_or_public_test", "public_rodden_aa"} for sample in samples)