expose formula-only prashna sphuta evidence
This commit is contained in:
@@ -90,6 +90,7 @@ For large architecture or release work, also read:
|
||||
| ERR-057 | The release quality profile checked untracked files but did not execute the privacy AST scan or the real Chromium report-isolation probe. | mitigated 2026-07-14 | `release_hygiene_check()` now requires `public_release_privacy_scan.py --json` and `report_renderer_isolation_poc.py --strict`; parity manifest validation also runs as a contract check. |
|
||||
| ERR-058 | Formula-based Sahams used the day/night operand rules but omitted the documented zodiacal-order `+30°` exception. | mitigated 2026-07-14 | `_calc_formula_saham()` applies the `references/saham_rules.json` forward-arc condition and one-sign correction; keep external numeric oracle parity as a separate `partial` requirement. |
|
||||
| ERR-059 | Gulika was either an approximate fallback or falsely implied as a chart module output. | mitigated 2026-07-14 | `scripts/gulika.py` computes Prasna Marga Ghatika segment Ascendant with Swiss sunrise/sunset and Lahiri sidereal houses. It is exposed only as `prashna_context.supporting_indicators.gulika`, remains `partial`, and cannot unlock Sphuta or verdict layers until external numeric parity exists. |
|
||||
| ERR-060 | Legacy Sphuta functions combined approximate Gulika with interpretive signals, while the exact formula could not be inspected in the production question context. | mitigated 2026-07-14 | `prashna_sphuta.py` exposes formula-only Trisphuta/Catusphuta/Pancasphuta from the partial Gulika evidence. It is supporting-only; Kunda, life-sensitive Sphutas and Prashna verdicts remain blocked pending external numeric parity. |
|
||||
|
||||
## Fragment Sweep Command Set
|
||||
|
||||
|
||||
@@ -452,7 +452,7 @@
|
||||
"timing",
|
||||
"life"
|
||||
],
|
||||
"status": "blocked",
|
||||
"status": "partial",
|
||||
"knowledge_refs": [
|
||||
"references/prashna-complete-guide.md",
|
||||
"references/single-event-inquiry-protocol.md"
|
||||
@@ -463,18 +463,16 @@
|
||||
"scripts/jyotish_engine.py --mode life"
|
||||
],
|
||||
"output_paths": [
|
||||
"scripts/prashna.py:calc_sphutas",
|
||||
"scripts/prashna.py:calc_life_sphutas",
|
||||
"kp_horary.sphutas"
|
||||
"prashna_context.supporting_indicators.sphuta"
|
||||
],
|
||||
"audit_label": "Sphuta/Trisphuta",
|
||||
"missing_impact": "Prashna energy convergence and life-sensitivity markers are absent, leaving horary and life-risk reading thinner than classical toolchains.",
|
||||
"missing_impact": "Formula-only Trisphuta/Catusphuta/Pancasphuta evidence is available from exact Gulika. Life-sensitive Sphutas, external numeric parity and all verdict use remain unavailable.",
|
||||
"entry_type": "supporting_indicator",
|
||||
"evidence_role": "secondary",
|
||||
"user_visibility": "expert_audit",
|
||||
"verification_level": {
|
||||
"calculation": "verified",
|
||||
"rule": "verified",
|
||||
"calculation": "partial",
|
||||
"rule": "partial",
|
||||
"prediction": "support_only"
|
||||
},
|
||||
"conclusion_policy": "Supporting evidence only; it can raise/lower confidence but cannot by itself decide an event or timing claim."
|
||||
|
||||
@@ -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.",
|
||||
}
|
||||
|
||||
@@ -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.",
|
||||
}
|
||||
@@ -22,7 +22,8 @@ def test_cli_prashna_uses_question_moment_swiss_context_only():
|
||||
assert payload["status"] == "computed"
|
||||
assert payload["chart_source"] == "swiss_ephemeris_backend"
|
||||
assert payload["supporting_indicators"]["gulika"]["status"] == "partial"
|
||||
assert "Trisphuta" in payload["blocked_layers"]
|
||||
assert payload["supporting_indicators"]["sphuta"]["status"] == "partial"
|
||||
assert "Kunda" in payload["blocked_layers"]
|
||||
|
||||
|
||||
def test_cli_prashna_blocks_legacy_approximation_modes():
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
from scripts.prashna_sphuta import calculate_sphuta_evidence
|
||||
|
||||
|
||||
def test_sphuta_formula_evidence_uses_exact_gulika_input() -> None:
|
||||
result = calculate_sphuta_evidence(
|
||||
ascendant_longitude=10,
|
||||
planet_longitudes={"Moon": 20, "Sun": 30, "Rahu": 40},
|
||||
gulika_longitude=50,
|
||||
)
|
||||
|
||||
assert result["status"] == "partial"
|
||||
assert result["points"] == {"trisphuta": 80.0, "catusphuta": 110.0, "pancasphuta": 150.0}
|
||||
|
||||
|
||||
def test_sphuta_evidence_blocks_missing_required_planet() -> None:
|
||||
result = calculate_sphuta_evidence(
|
||||
ascendant_longitude=10,
|
||||
planet_longitudes={"Moon": 20, "Sun": 30},
|
||||
gulika_longitude=50,
|
||||
)
|
||||
|
||||
assert result["status"] == "blocked"
|
||||
assert result["missing"] == ["Rahu"]
|
||||
Reference in New Issue
Block a user