Add Rangacharya comparison variant

This commit is contained in:
732642856
2026-07-17 01:03:50 +08:00
parent 1d61fbe535
commit 9bb054b0ae
13 changed files with 702 additions and 0 deletions
+50
View File
@@ -0,0 +1,50 @@
import os
import sys
SCRIPTS = os.path.join(os.path.dirname(__file__), "..", "scripts")
if SCRIPTS not in sys.path:
sys.path.insert(0, SCRIPTS)
from jyotish_api_server import JyotishAPIHandler # noqa: E402
def _handler() -> JyotishAPIHandler:
return JyotishAPIHandler.__new__(JyotishAPIHandler)
def _planets():
return {
"Sun": {"lon": 10.0},
"Moon": {"lon": 45.0},
"Mars": {"lon": 80.0},
"Mercury": {"lon": 110.0},
"Jupiter": {"lon": 145.0},
"Venus": {"lon": 200.0},
"Saturn": {"lon": 250.0},
"Rahu": {"lon": 300.0},
"Ketu": {"lon": 120.0},
}
def test_jaimini_default_does_not_include_rangacharya():
result = _handler()._compute_jaimini({
"mode": "arudha",
"ascendant": {"lon": 0.0},
"planets": _planets(),
})
assert "rangacharya" not in result["result"]
assert "rangacharya_diff" not in result["result"]
def test_jaimini_variant_all_includes_current_variant_and_diff():
result = _handler()._compute_jaimini({
"mode": "arudha",
"variant": "all",
"ascendant": {"lon": 0.0},
"planets": _planets(),
})
assert result["result"]["rangacharya"]["adjudication_enabled"] is False
assert result["result"]["rangacharya_diff"]["adjudication_enabled"] is False
assert result["result"]["rangacharya"]["arudha_padas"]["AL"]["source_card_status"] == "transcribed"
assert result["result"]["rangacharya"]["active_lagna"]["source_card_id"] == "active_effective_lagna"
@@ -0,0 +1,16 @@
import pytest
from scripts import rangacharya
def test_assert_adjudication_allowed_rejects_default_variant():
result = rangacharya.calc_rangacharya_variant(0, {"Sun": 10.0})
with pytest.raises(rangacharya.RangacharyaValidationError):
rangacharya.assert_adjudication_allowed(result)
def test_validation_summary_lists_blocking_rules():
result = rangacharya.calc_rangacharya_variant(0, {"Sun": 10.0})
summary = rangacharya.validation_summary(result)
assert summary["adjudication_enabled"] is False
assert summary["blocking_statuses"]
+14
View File
@@ -0,0 +1,14 @@
from scripts import rangacharya_readiness
def test_readiness_reports_blocked_until_no_adjudication_cards():
report = rangacharya_readiness.build_report()
assert report["scope"] == "rangacharya_readiness"
assert report["adjudication_enabled"] is False
assert report["blocked_count"] >= 1
assert "rangacharya_core_arudha" in report["cards"]
def test_readiness_does_not_expose_secrets():
report = rangacharya_readiness.build_report()
assert "sk_live_" not in str(report)
+17
View File
@@ -0,0 +1,17 @@
import json
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
REGISTRY = ROOT / "references" / "technique_registry.json"
def test_rangacharya_variant_registered_as_comparison_only():
techniques = json.loads(REGISTRY.read_text(encoding="utf-8"))["techniques"]
entry = techniques["rangacharya_jaimini_variant"]
assert entry["status"] == "comparison-only"
assert entry["verification_level"]["calculation"] == "experimental"
assert entry["verification_level"]["prediction"] == "blocked"
assert entry["conclusion_policy"] == "Display current-vs-variant differences only; do not use for verdicts or timing."
assert entry["evidence_role"] == "comparison_only"
assert "references/rangacharya_source_cards.json" in entry["knowledge_refs"]
+50
View File
@@ -0,0 +1,50 @@
import json
from pathlib import Path
CARDS = Path("references/rangacharya_source_cards.json")
REQUIRED_CARD_IDS = {
"rangacharya_core_arudha",
"active_effective_lagna",
"prakriti_sanmukha",
"rangacharya_special_mappings",
"rangacharya_named_yogas",
"rangacharya_ul_family_rules",
"article_warehouse_future_tracks",
}
def _cards():
return json.loads(CARDS.read_text(encoding="utf-8"))
def test_source_cards_exist_with_required_schema():
data = _cards()
assert data["schema_version"] == 1
assert isinstance(data["cards"], list)
for card in data["cards"]:
assert card["id"]
assert card["status"] in {
"transcribed",
"source_verified",
"golden_verified",
"engine_cross_checked",
"case_calibrated",
"blocked",
}
assert card["adjudication_enabled"] is False
assert "evidence" in card
def test_source_cards_cover_phase2_rule_groups():
data = _cards()
found = {card["id"] for card in data["cards"]}
assert REQUIRED_CARD_IDS <= found
def test_source_cards_do_not_contain_secrets():
text = CARDS.read_text(encoding="utf-8")
assert "sk_live_" not in text
assert "VEDASTRO_API_KEY" not in text
+50
View File
@@ -0,0 +1,50 @@
import json
from pathlib import Path
MANIFEST = Path("references/rangacharya_source_manifest.json")
def test_manifest_exists_and_has_required_sections():
data = json.loads(MANIFEST.read_text(encoding="utf-8"))
assert data["schema_version"] == 1
assert "sources" in data
assert "rules" in data
assert "validation_ladder" in data
def test_manifest_does_not_contain_secrets():
text = MANIFEST.read_text(encoding="utf-8")
assert "sk_live_" not in text
assert "api_key" not in text.lower()
def test_rules_default_below_adjudication():
data = json.loads(MANIFEST.read_text(encoding="utf-8"))
for rule in data["rules"]:
assert rule["status"] in {
"transcribed",
"source_verified",
"golden_verified",
"engine_cross_checked",
"case_calibrated",
"blocked",
}
assert rule["status"] != "adjudication_enabled"
assert rule["adjudication_enabled"] is False
def test_screenshot_source_paths_are_located_and_hashed():
data = json.loads(MANIFEST.read_text(encoding="utf-8"))
source = next(item for item in data["sources"] if item["id"] == "uploaded_screenshots_20260716")
assert source["extraction_status"] == "located_and_hashed_ocr_blocked_tesseract_missing"
assert len(source["paths"]) == 6
assert all("/文件仓库/印度占星文章/260716/" in path for path in source["paths"])
assert set(source["sha256"]) == {
"IMG_3502.PNG",
"IMG_3503.PNG",
"IMG_3504.PNG",
"IMG_3505.PNG",
"IMG_3506.PNG",
"IMG_3507.PNG",
}
+42
View File
@@ -0,0 +1,42 @@
from scripts import rangacharya
SAMPLE_LONGS = {
"Sun": 10.0,
"Moon": 45.0,
"Mars": 80.0,
"Mercury": 110.0,
"Jupiter": 145.0,
"Venus": 200.0,
"Saturn": 250.0,
"Rahu": 300.0,
"Ketu": 120.0,
}
def test_variant_result_is_experimental_and_not_for_adjudication():
result = rangacharya.calc_rangacharya_variant(0, SAMPLE_LONGS)
assert result["variant"] == "rangacharya"
assert result["adjudication_enabled"] is False
assert result["status"] == "experimental_not_for_adjudication"
def test_variant_includes_core_sections():
result = rangacharya.calc_rangacharya_variant(0, SAMPLE_LONGS)
assert "source_status" in result
assert "arudha_padas" in result
assert "active_lagna" in result
assert "effective_lagna" in result
assert result["arudha_padas"]["AL"]["source_card_id"] == "rangacharya_core_arudha"
assert result["arudha_padas"]["AL"]["source_card_status"] == "transcribed"
assert result["active_lagna"]["source_card_id"] == "active_effective_lagna"
assert result["effective_lagna"]["source_card_id"] == "active_effective_lagna"
def test_diff_marks_algorithm_names():
current = {"AL": {"sign": "Aries"}}
variant = {"arudha_padas": {"AL": {"sign": "Taurus"}}}
diff = rangacharya.diff_current_vs_rangacharya(current, variant)
assert diff["current_algorithm"] == "current_jaimini"
assert diff["variant_algorithm"] == "rangacharya"
assert diff["differences"][0]["key"] == "AL.sign"