Files
Jyotisha/scripts/pyjhora_parity_summary.py
T
2026-07-12 15:13:30 +08:00

62 lines
2.4 KiB
Python

#!/usr/bin/env python3
"""Summarize reviewable PyJHora comparison matrices without overstating coverage."""
from __future__ import annotations
import argparse
import csv
import json
from collections import Counter, defaultdict
from pathlib import Path
from typing import Any
REQUIRED_FULL_PARITY = ("D1", "D9", "D10", "D2", "D4", "Vimshottari", "Shadbala", "Ashtakavarga")
MATRIX_SECTION_MAP = {"ascendant": "D1", "planet": "D1", "dasha": "Vimshottari", "D9": "D9", "D10": "D10"}
def summarize_matrix(path: str | Path, *, settings: dict[str, Any]) -> dict[str, Any]:
path = Path(path)
rows = list(csv.DictReader(path.open(encoding="utf-8")))
status_counts = Counter(str(row.get("status") or "unknown") for row in rows)
sections: dict[str, dict[str, int]] = defaultdict(lambda: {"total": 0, "match": 0, "mismatch": 0})
covered = set()
for row in rows:
section = MATRIX_SECTION_MAP.get(str(row.get("section") or ""))
if not section:
continue
covered.add(section)
sections[section]["total"] += 1
if row.get("status") == "match":
sections[section]["match"] += 1
elif row.get("status") == "mismatch":
sections[section]["mismatch"] += 1
missing = [field for field in REQUIRED_FULL_PARITY if field not in covered]
return {
"scope": "pyjhora_same_chart_parity_summary",
"matrix_path": str(path),
"tested": bool(rows),
"settings": settings,
"row_counts": dict(status_counts),
"coverage": dict(sorted(sections.items())),
"covered_outputs": sorted(covered),
"missing_required_outputs": missing,
"status": "partial_verified" if rows and not status_counts.get("mismatch") else "partial_mismatch",
"full_parity_verified": not missing and not status_counts.get("mismatch"),
"boundary": "Only covered outputs are compared. This summary cannot promote full parity while required outputs are absent.",
}
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("matrix")
parser.add_argument("--ayanamsa", default="lahiri")
parser.add_argument("--node-mode", default="mean", choices=["mean", "true"])
args = parser.parse_args()
print(json.dumps(summarize_matrix(args.matrix, settings={"ayanamsa": args.ayanamsa, "node_mode": args.node_mode}), ensure_ascii=False, indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main())