150 lines
5.2 KiB
Python
150 lines
5.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Audit whether D3 drift is caused by D3 mapping itself or dignity use in Shadbala."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
SCRIPT_DIR = ROOT / "scripts"
|
|
if str(SCRIPT_DIR) not in sys.path:
|
|
sys.path.insert(0, str(SCRIPT_DIR))
|
|
|
|
import jyotish_engine # type: ignore
|
|
from divisional_charts_extended import DivisionalChartsCalculator # type: ignore
|
|
from oracle_boundary_audit import _load_oracle, _namespace_from_template # type: ignore
|
|
from shadbala_sapta_dignity_whitelist import build_report as build_whitelist_report # type: ignore
|
|
from varga import calc_varga # type: ignore
|
|
|
|
|
|
def _normalize_dignity_bucket(score: float) -> str:
|
|
if score >= 50:
|
|
return "exalted"
|
|
if score >= 45:
|
|
return "own"
|
|
if score >= 35:
|
|
return "friend"
|
|
if score >= 25:
|
|
return "neutral"
|
|
if score >= 15:
|
|
return "enemy"
|
|
return "debilitated"
|
|
|
|
|
|
def _discover_cases(oracle: dict[str, Any]) -> dict[str, dict[str, Any]]:
|
|
cases: dict[str, dict[str, Any]] = {}
|
|
for key in ("template_cases", "shadbala_cases"):
|
|
for case in oracle.get(key, []):
|
|
cid = case.get("id") or case.get("case_id")
|
|
if isinstance(cid, str):
|
|
cases[cid] = case
|
|
return cases
|
|
|
|
|
|
def build_report(oracle_file: str) -> dict[str, Any]:
|
|
whitelist = build_whitelist_report(oracle_file)
|
|
oracle = _load_oracle(oracle_file)
|
|
cases = _discover_cases(oracle)
|
|
calc = DivisionalChartsCalculator()
|
|
|
|
rows = []
|
|
mapping_fault = 0
|
|
dignity_fault = 0
|
|
|
|
for row in whitelist.get("whitelist_rows", []):
|
|
if row.get("layer") != "D3":
|
|
continue
|
|
case = cases[row["case_id"]]
|
|
result = jyotish_engine.cmd_shadbala(_namespace_from_template(case))
|
|
chart, _asc_idx, _jd, _aya = jyotish_engine._compute_chart_from_args(_namespace_from_template(case))
|
|
planet = row["planet"]
|
|
planet_data = (chart or {}).get("planets", {}).get(planet, {})
|
|
lon = float(planet_data.get("degree", 0.0))
|
|
|
|
d3_simple = calc_varga(lon, 3)
|
|
d3_extended_abs = calc._calculate_d3(int(lon // 30), lon % 30)
|
|
d3_extended = {
|
|
"sign_idx": int(d3_extended_abs // 30) % 12,
|
|
"sign": calc.SIGNS[int(d3_extended_abs // 30) % 12],
|
|
}
|
|
|
|
sthana = ((result.get("planets") or {}).get(planet) or {}).get("sthana_bala") or {}
|
|
engine_d3_score = float(sthana.get("sapta_d3", 0.0))
|
|
dignity_bucket = _normalize_dignity_bucket(engine_d3_score)
|
|
mapping_matches = d3_simple.get("sign") == d3_extended["sign"]
|
|
|
|
suspected = "d3_dignity_path" if mapping_matches else "d3_mapping_path"
|
|
if mapping_matches:
|
|
dignity_fault += 1
|
|
else:
|
|
mapping_fault += 1
|
|
|
|
rows.append({
|
|
"case_id": row["case_id"],
|
|
"planet": planet,
|
|
"mapping_matches_engine_sign": mapping_matches,
|
|
"d3_simple_sign": d3_simple.get("sign"),
|
|
"d3_extended_sign": d3_extended["sign"],
|
|
"d3_dignity_bucket": dignity_bucket,
|
|
"sapta_d3_score": round(engine_d3_score, 2),
|
|
"suspected_path": suspected,
|
|
})
|
|
|
|
return {
|
|
"scope": "shadbala_d3_mapping_audit",
|
|
"schema_version": 1,
|
|
"summary": {
|
|
"case_count": len({row["case_id"] for row in rows}),
|
|
"row_count": len(rows),
|
|
"global_closure_blocked": True,
|
|
},
|
|
"suspected_fault_split": {
|
|
"d3_mapping_path": mapping_fault,
|
|
"d3_dignity_path": dignity_fault,
|
|
},
|
|
"rows": rows,
|
|
"boundary": (
|
|
"This audit compares two local D3 mapping paths against the D3 score consumed by Shadbala. "
|
|
"If both mappings agree, the remaining suspect is the dignity score path rather than the D3 sign mapping."
|
|
),
|
|
}
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(description="Audit D3 mapping vs dignity path for Shadbala")
|
|
parser.add_argument("--oracle-file", default="references/oracle/dasha_shadbala_oracle_cases.json")
|
|
parser.add_argument("--format", choices=("json", "markdown"), default="json")
|
|
args = parser.parse_args()
|
|
|
|
report = build_report(args.oracle_file)
|
|
if args.format == "markdown":
|
|
lines = [
|
|
"# Shadbala D3 Mapping Audit",
|
|
"",
|
|
f"- case_count: `{report['summary']['case_count']}`",
|
|
f"- row_count: `{report['summary']['row_count']}`",
|
|
"",
|
|
f"- suspected_fault_split: `{report['suspected_fault_split']}`",
|
|
"",
|
|
"| Case | Planet | Simple D3 | Extended D3 | D3 Dignity | Suspected Path |",
|
|
"| --- | --- | --- | --- | --- | --- |",
|
|
]
|
|
for row in report["rows"]:
|
|
lines.append(
|
|
f"| {row['case_id']} | {row['planet']} | {row['d3_simple_sign']} | {row['d3_extended_sign']} | "
|
|
f"{row['d3_dignity_bucket']} | {row['suspected_path']} |"
|
|
)
|
|
print("\n".join(lines))
|
|
return
|
|
|
|
print(json.dumps(report, ensure_ascii=False, indent=2))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|