diff --git a/references/oracle/evidence_packet_index_2026_07_19.json b/references/oracle/evidence_packet_index_2026_07_19.json index 6a328345..260d123b 100644 --- a/references/oracle/evidence_packet_index_2026_07_19.json +++ b/references/oracle/evidence_packet_index_2026_07_19.json @@ -5,7 +5,7 @@ "production_tuning_allowed": false, "boundary": "Index of current governance packets only. Raw oracle artifacts remain in references/oracle/artifacts and are not all duplicated here.", "summary": { - "packet_count": 64, + "packet_count": 65, "blocked_or_partial_count": 40, "human_review_required_count": 1 }, @@ -521,6 +521,14 @@ "claim_status": "partial", "consumer_policy": "research_to_commercial_contract_only", "claim_boundary": "Classifies all 42 same-unit Shadbala rows into closed observation, method variant, or open mismatch; does not assert absolute formula truth." + }, + { + "packet_id": "muhurta_factor_scoring_readiness", + "path": "references/oracle/muhurta_factor_scoring_readiness_2026_07_19.json", + "domain": "muhurta_factor_scoring", + "claim_status": "partial", + "consumer_policy": "research_to_commercial_contract_only", + "claim_boundary": "Classifies Muhurta factors as supporting-context only; no scored verdict readiness until formulas, weights, public examples, and replay hashes close." } ] } diff --git a/references/oracle/muhurta_factor_scoring_readiness_2026_07_19.json b/references/oracle/muhurta_factor_scoring_readiness_2026_07_19.json new file mode 100644 index 00000000..e1b68810 --- /dev/null +++ b/references/oracle/muhurta_factor_scoring_readiness_2026_07_19.json @@ -0,0 +1,95 @@ +{ + "boundary": "Muhurta factors may appear as supporting context only. No final scored Muhurta verdict is ready until formulas, weights, public worked examples, and raw/hash replay close.", + "claim_status": "partial", + "created_at": "2026-07-19", + "production_tuning_allowed": false, + "readiness_hash": "7cf64d13359c4186a08b77b1998e7659cc990ef561fb658cb8becc04cac0b42a", + "rows": [ + { + "allowed_product_use": "supporting_context_only", + "claim": "observation_only", + "factor": "panchanga_suddhi", + "missing_for_scored_verdict": [ + "license verification", + "formula weights", + "public worked example", + "same-input replay" + ], + "readiness": "reference_surface_only", + "source_status": "oss_surface_present" + }, + { + "allowed_product_use": "supporting_context_only", + "claim": "observation_only", + "factor": "activity_specific_rules", + "missing_for_scored_verdict": [ + "license verification", + "formula weights", + "public worked example", + "same-input replay" + ], + "readiness": "reference_surface_only", + "source_status": "oss_surface_present" + }, + { + "allowed_product_use": "supporting_context_only", + "claim": "observation_only", + "factor": "tarabala", + "missing_for_scored_verdict": [ + "OSS/public formula alignment", + "factor weighting rule", + "public worked example" + ], + "readiness": "local_probe_needs_formula_alignment", + "source_status": "local_probe_present_needs_oss_formula_alignment" + }, + { + "allowed_product_use": "supporting_context_only", + "claim": "observation_only", + "factor": "chandrabala", + "missing_for_scored_verdict": [ + "OSS/public formula alignment", + "factor weighting rule", + "public worked example" + ], + "readiness": "local_probe_needs_formula_alignment", + "source_status": "local_probe_present_needs_oss_formula_alignment" + }, + { + "allowed_product_use": "supporting_context_only", + "claim": "observation_only", + "factor": "rahu_kalam", + "missing_for_scored_verdict": [ + "date/location fixture", + "sunrise/sunset source", + "expected public interval", + "raw/hash" + ], + "readiness": "local_probe_needs_public_interval_fixture", + "source_status": "local_probe_present_needs_public_interval_fixture" + }, + { + "allowed_product_use": "supporting_context_only", + "claim": "observation_only", + "factor": "abhijit", + "missing_for_scored_verdict": [ + "date/location fixture", + "sunrise/sunset source", + "expected public interval", + "raw/hash" + ], + "readiness": "local_probe_needs_public_interval_fixture", + "source_status": "local_probe_present_needs_public_interval_fixture" + } + ], + "scope": "muhurta_factor_scoring_readiness", + "source_queue": "references/oracle/muhurta_oss_factor_scoring_queue_2026_07_19.json", + "status": "readiness_ledger_ready", + "summary": { + "blocked_unknown_status_count": 0, + "factor_count": 6, + "scored_verdict_ready_count": 0, + "supporting_context_only_count": 6 + }, + "truth_matrix_allowed": false +} diff --git a/scripts/muhurta_factor_scoring_readiness.py b/scripts/muhurta_factor_scoring_readiness.py new file mode 100644 index 00000000..7b811697 --- /dev/null +++ b/scripts/muhurta_factor_scoring_readiness.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +"""Classify Muhurta factor-scoring readiness from existing OSS/local queues.""" +from __future__ import annotations + +import hashlib +import json +from pathlib import Path +from typing import Any + + +ROOT = Path(__file__).resolve().parents[1] +QUEUE = ROOT / "references/oracle/muhurta_oss_factor_scoring_queue_2026_07_19.json" + + +def stable_json(data: Any) -> str: + return json.dumps(data, ensure_ascii=False, sort_keys=True, separators=(",", ":"), default=str) + + +def readiness(status: str) -> tuple[str, list[str]]: + if status == "oss_surface_present": + return ( + "reference_surface_only", + ["license verification", "formula weights", "public worked example", "same-input replay"], + ) + if status == "local_probe_present_needs_oss_formula_alignment": + return ( + "local_probe_needs_formula_alignment", + ["OSS/public formula alignment", "factor weighting rule", "public worked example"], + ) + if status == "local_probe_present_needs_public_interval_fixture": + return ( + "local_probe_needs_public_interval_fixture", + ["date/location fixture", "sunrise/sunset source", "expected public interval", "raw/hash"], + ) + return ("blocked_unknown_status", ["manual review"]) + + +def build() -> dict[str, Any]: + queue = json.loads(QUEUE.read_text(encoding="utf-8")) + rows = [] + for item in queue["factor_rows"]: + state, missing = readiness(item["status"]) + rows.append( + { + "factor": item["factor"], + "source_status": item["status"], + "claim": item["claim"], + "readiness": state, + "missing_for_scored_verdict": missing, + "allowed_product_use": ( + "supporting_context_only" + if state != "blocked_unknown_status" + else "hidden_until_review" + ), + } + ) + summary = { + "factor_count": len(rows), + "supporting_context_only_count": sum( + 1 for row in rows if row["allowed_product_use"] == "supporting_context_only" + ), + "scored_verdict_ready_count": 0, + "blocked_unknown_status_count": sum( + 1 for row in rows if row["readiness"] == "blocked_unknown_status" + ), + } + return { + "scope": "muhurta_factor_scoring_readiness", + "created_at": "2026-07-19", + "status": "readiness_ledger_ready", + "claim_status": "partial", + "production_tuning_allowed": False, + "truth_matrix_allowed": False, + "source_queue": str(QUEUE.relative_to(ROOT)), + "summary": summary, + "readiness_hash": hashlib.sha256(stable_json(rows).encode("utf-8")).hexdigest(), + "rows": rows, + "boundary": ( + "Muhurta factors may appear as supporting context only. No final " + "scored Muhurta verdict is ready until formulas, weights, public " + "worked examples, and raw/hash replay close." + ), + } + + +def main() -> int: + print(json.dumps(build(), ensure_ascii=False, indent=2, sort_keys=True)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tests/test_muhurta_factor_scoring_readiness.py b/tests/test_muhurta_factor_scoring_readiness.py new file mode 100644 index 00000000..01d083bc --- /dev/null +++ b/tests/test_muhurta_factor_scoring_readiness.py @@ -0,0 +1,46 @@ +import json +import subprocess +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +ARTIFACT = ROOT / "references/oracle/muhurta_factor_scoring_readiness_2026_07_19.json" +INDEX = ROOT / "references/oracle/evidence_packet_index_2026_07_19.json" + + +def test_muhurta_readiness_script_outputs_supporting_only_rows(): + data = json.loads( + subprocess.check_output( + ["python3", "scripts/muhurta_factor_scoring_readiness.py"], + cwd=ROOT, + text=True, + ) + ) + assert data["scope"] == "muhurta_factor_scoring_readiness" + assert data["claim_status"] == "partial" + assert data["truth_matrix_allowed"] is False + assert data["summary"]["factor_count"] == 6 + assert data["summary"]["scored_verdict_ready_count"] == 0 + + +def test_muhurta_readiness_artifact_blocks_final_scored_verdict(): + data = json.loads(ARTIFACT.read_text(encoding="utf-8")) + assert data["summary"]["supporting_context_only_count"] == 6 + assert all(row["allowed_product_use"] == "supporting_context_only" for row in data["rows"]) + assert {row["factor"] for row in data["rows"]} == { + "panchanga_suddhi", + "activity_specific_rules", + "tarabala", + "chandrabala", + "rahu_kalam", + "abhijit", + } + assert "No final scored Muhurta verdict is ready" in data["boundary"] + + +def test_evidence_index_registers_muhurta_readiness(): + packets = { + row["packet_id"]: row + for row in json.loads(INDEX.read_text(encoding="utf-8"))["packets"] + } + assert packets["muhurta_factor_scoring_readiness"]["claim_status"] == "partial"