expose formula-only prashna sphuta evidence

This commit is contained in:
732642856
2026-07-14 18:36:50 +08:00
parent e5f7e0ddc0
commit 63f56f9457
6 changed files with 95 additions and 11 deletions
+20 -3
View File
@@ -13,6 +13,10 @@ try:
from scripts.gulika import calculate_gulika
except ModuleNotFoundError: # pragma: no cover - CLI execution path
from gulika import calculate_gulika
try:
from scripts.prashna_sphuta import calculate_sphuta_evidence
except ModuleNotFoundError: # pragma: no cover - CLI execution path
from prashna_sphuta import calculate_sphuta_evidence
class PrashnaContextError(ValueError):
@@ -69,6 +73,19 @@ def build_prashna_context(payload: dict[str, Any]) -> dict[str, Any]:
"status": "blocked",
"reason": f"gulika_supporting_indicator_failed:{type(exc).__name__}",
}
if gulika.get("status") == "partial":
longitudes = {
name: item.get("degree_raw", item.get("lon"))
for name, item in chart["planets"].items()
if isinstance(item, dict)
}
sphuta = calculate_sphuta_evidence(
ascendant_longitude=chart["ascendant"].get("degree_raw", chart["ascendant"].get("lon")),
planet_longitudes=longitudes,
gulika_longitude=gulika["longitude"],
)
else:
sphuta = {"status": "blocked", "reason": "gulika_supporting_indicator_unavailable"}
return {
"scope": "prashna_context",
"status": "computed",
@@ -82,7 +99,7 @@ def build_prashna_context(payload: dict[str, Any]) -> dict[str, Any]:
"planets": chart["planets"],
"calculation_contract": chart["calculation_contract"],
"result_hash": chart["result_hash"],
"supporting_indicators": {"gulika": gulika},
"blocked_layers": ["Trisphuta", "Kunda", "Prashna verdict"],
"boundary": "No client-supplied planets or ascendant are accepted. Gulika is supporting-only pending external numeric parity; Sphuta and verdict layers remain blocked.",
"supporting_indicators": {"gulika": gulika, "sphuta": sphuta},
"blocked_layers": ["Kunda", "Prashna verdict"],
"boundary": "No client-supplied planets or ascendant are accepted. Gulika and formula-only Sphuta are supporting-only pending external numeric parity; verdict layers remain blocked.",
}
+44
View File
@@ -0,0 +1,44 @@
"""Formula-only Prasna Marga Sphuta evidence, without verdict interpretation."""
from __future__ import annotations
from typing import Any
def _norm(value: float) -> float:
return float(value) % 360.0
def calculate_sphuta_evidence(
*,
ascendant_longitude: float,
planet_longitudes: dict[str, Any],
gulika_longitude: float,
) -> dict[str, Any]:
required = ("Sun", "Moon", "Rahu")
missing = [name for name in required if name not in planet_longitudes]
if missing:
return {"status": "blocked", "reason": "missing_sphuta_planets", "missing": missing}
asc = _norm(ascendant_longitude)
moon = _norm(planet_longitudes["Moon"])
sun = _norm(planet_longitudes["Sun"])
rahu = _norm(planet_longitudes["Rahu"])
gulika = _norm(gulika_longitude)
trisphuta = _norm(asc + moon + gulika)
catusphuta = _norm(trisphuta + sun)
pancasphuta = _norm(catusphuta + rahu)
return {
"scope": "prasna_marga_sphuta_evidence",
"status": "partial",
"points": {
"trisphuta": trisphuta,
"catusphuta": catusphuta,
"pancasphuta": pancasphuta,
},
"formula_trace": {
"trisphuta": "Lagna + Moon + Gulika",
"catusphuta": "Trisphuta + Sun",
"pancasphuta": "Catusphuta + Rahu",
},
"rule_source": "references/prashna-complete-guide.md#3.2-3.3",
"boundary": "Formula-only supporting evidence. No health, event, or Prashna verdict is permitted without external numeric parity and adjudication rules.",
}