From 50c936406a93d4aee54770bd32f4d3e0c943b00e Mon Sep 17 00:00:00 2001 From: 732642856 <732642856@qq.com> Date: Sun, 12 Jul 2026 15:48:05 +0800 Subject: [PATCH] record public PyJHora parity evidence --- .../jyotish/scripts/run_pyjhora_compare.py | 6 ++- .../pyjhora_same_chart_parity_2026_07_12.md | 51 +++++++++++++++++++ ...me_chart_parity_public_smoke_manifest.json | 21 ++++++++ scripts/diagnose_external_engine_adapters.py | 15 +++++- ...est_external_engine_adapter_diagnostics.py | 5 +- tests/test_pyjhora_compare_cli.py | 1 + 6 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 docs/research/pyjhora_same_chart_parity_2026_07_12.md create mode 100644 references/oracle/pyjhora_same_chart_parity_public_smoke_manifest.json diff --git a/benchmarks/jyotish/scripts/run_pyjhora_compare.py b/benchmarks/jyotish/scripts/run_pyjhora_compare.py index e6009193..cc6c32a5 100644 --- a/benchmarks/jyotish/scripts/run_pyjhora_compare.py +++ b/benchmarks/jyotish/scripts/run_pyjhora_compare.py @@ -329,6 +329,7 @@ def main(argv=None): parser.add_argument('--sample-id', action='append', default=[], help='Run only a named benchmark sample; repeatable.') parser.add_argument('--build-local', action='store_true', help='Explicitly generate missing local canonical baselines.') parser.add_argument('--node-mode', choices=['mean', 'true'], default='mean', help='Match the node convention before comparing.') + parser.add_argument('--output-prefix', default='', help='Optional filename prefix for resumable batch artifacts.') args = parser.parse_args(argv) PYJHORA_OUT.mkdir(parents=True, exist_ok=True) samples = json.loads(DATA.read_text()) @@ -356,13 +357,14 @@ def main(argv=None): local = json.loads(local_path.read_text()) all_rows.extend(compare_one(sample['id'], local, pyjhora)) - matrix = OUT / 'pyjhora_comparison_matrix.csv' + prefix = f"{args.output_prefix}_" if args.output_prefix else '' + matrix = OUT / f'{prefix}pyjhora_comparison_matrix.csv' with matrix.open('w', newline='') as f: writer = csv.DictWriter(f, fieldnames=['sample_id', 'section', 'body', 'field', 'local_skill', 'pyjhora', 'delta', 'status']) writer.writeheader() writer.writerows(all_rows) - report = OUT / 'jyotish_benchmark_round3_pyjhora_compare.md' + report = OUT / f'{prefix}jyotish_benchmark_round3_pyjhora_compare.md' report.write_text(write_report(samples, all_rows)) print(json.dumps({'report': str(report), 'matrix': str(matrix), 'samples': len(samples), 'fields': len(all_rows)}, ensure_ascii=False, indent=2)) diff --git a/docs/research/pyjhora_same_chart_parity_2026_07_12.md b/docs/research/pyjhora_same_chart_parity_2026_07_12.md new file mode 100644 index 00000000..4b427fdf --- /dev/null +++ b/docs/research/pyjhora_same_chart_parity_2026_07_12.md @@ -0,0 +1,51 @@ +# PyJHora Same-Chart Parity: Public Smoke Batch + +Date: 2026-07-12 + +## Scope + +Ten public/synthetic smoke birth records were replayed through the local +canonical baseline and an isolated PyJHora comparison runner. Both sides used +Lahiri ayanamsa and Mean Node mode. No user birth record or private event data +was used. + +## Result + +| Field status | Count | +|---|---:| +| `match` | 836 | +| `boundary_sensitive` | 4 | +| `mismatch` | 0 | +| Total compared | 840 | + +The four boundary-sensitive rows are D10 values at divisional boundaries. They +are retained as downgraded evidence, not silently counted as exact matches. + +Covered outputs: + +- D1: ascendant and nine planetary rows +- D9 +- D10 +- current Vimshottari boundaries + +Not yet compared: + +- D2 / D4 +- Shadbala +- Ashtakavarga +- VedAstro official raw snapshot +- JHora desktop export +- jyotishganit outside its Panchanga-oriented raw coverage + +## Reproduction + +Use `benchmarks/jyotish/scripts/run_pyjhora_compare.py` with explicit +`--build-local --node-mode mean`. Use `--output-prefix` for resumable batches. +Summarize each matrix through `scripts/pyjhora_parity_summary.py`. + +## Boundary + +This is partial external verification for the listed outputs only. It does not +establish full three-engine parity, global algorithmic accuracy, or event +prediction accuracy. VedAstro remains `official_blocked` until an official raw +response is captured and normalized. diff --git a/references/oracle/pyjhora_same_chart_parity_public_smoke_manifest.json b/references/oracle/pyjhora_same_chart_parity_public_smoke_manifest.json new file mode 100644 index 00000000..e5c0576d --- /dev/null +++ b/references/oracle/pyjhora_same_chart_parity_public_smoke_manifest.json @@ -0,0 +1,21 @@ +{ + "scope": "pyjhora_same_chart_parity_public_smoke", + "status": "partial_verified", + "tested": true, + "birth_data_policy": "public_synthetic_smoke_only", + "settings": { + "ayanamsa": "lahiri", + "node_mode": "mean" + }, + "sample_count": 10, + "comparison_rows": { + "total": 840, + "match": 836, + "boundary_sensitive": 4, + "mismatch": 0 + }, + "covered_outputs": ["D1", "D9", "D10", "Vimshottari"], + "missing_required_outputs": ["D2", "D4", "Shadbala", "Ashtakavarga"], + "source_report": "docs/research/pyjhora_same_chart_parity_2026_07_12.md", + "boundary": "Partial PyJHora verification only. It is not JHora desktop verification, VedAstro official raw closure, jyotishganit full-chart parity, or global predictive validation." +} diff --git a/scripts/diagnose_external_engine_adapters.py b/scripts/diagnose_external_engine_adapters.py index e3d1551c..bd24e6bf 100644 --- a/scripts/diagnose_external_engine_adapters.py +++ b/scripts/diagnose_external_engine_adapters.py @@ -5,6 +5,7 @@ from __future__ import annotations import argparse import json +from pathlib import Path try: from diagnose_vedastro_mode import build_report as build_vedastro_report @@ -21,13 +22,22 @@ except Exception: # pragma: no cover - import path varies in tests/CLI REQUIRED_PARITY_OUTPUTS = ["D1", "D9", "D10", "D2", "D4", "Vimshottari", "Shadbala", "Ashtakavarga"] +def _public_pyjhora_parity_manifest() -> dict: + path = Path("references/oracle/pyjhora_same_chart_parity_public_smoke_manifest.json") + try: + return json.loads(path.read_text(encoding="utf-8")) + except (OSError, json.JSONDecodeError): + return {"status": "not_available", "tested": False} + + def _same_chart_parity_contract(engines: dict) -> dict: + pyjhora_public = _public_pyjhora_parity_manifest() engine_states = {} for name, engine in engines.items(): available = engine["status"] == "available" engine_states[name] = { "available": available, - "tested": False, + "tested": bool(name == "PyJHora/JHora" and pyjhora_public.get("tested")), "blocked": not available, "blocking_reason": "" if available else engine["status"], } @@ -60,7 +70,8 @@ def _same_chart_parity_contract(engines: dict) -> dict: }, "engine_states": engine_states, "replay_manifest": replay_manifest, - "boundary": "This is a parity contract, not proof that the same-chart comparison has run.", + "partial_verifications": {"PyJHora/JHora": pyjhora_public}, + "boundary": "This is a parity contract. Public PyJHora partial verification does not close missing outputs or other engine raw-oracle requirements.", } diff --git a/tests/test_external_engine_adapter_diagnostics.py b/tests/test_external_engine_adapter_diagnostics.py index 3288df1e..a35079bb 100644 --- a/tests/test_external_engine_adapter_diagnostics.py +++ b/tests/test_external_engine_adapter_diagnostics.py @@ -36,7 +36,10 @@ def test_external_engine_adapter_diagnostics_aggregates_three_engines() -> None: assert "official_raw_response" in contract["expected_oracle_fields"]["VedAstro"] assert "raw_output_path" in contract["expected_oracle_fields"]["PyJHora/JHora"] assert contract["engine_states"]["jyotishganit"]["available"] is True - assert contract["engine_states"]["PyJHora/JHora"]["tested"] is False + assert contract["engine_states"]["PyJHora/JHora"]["tested"] is True + pyjhora = contract["partial_verifications"]["PyJHora/JHora"] + assert pyjhora["status"] == "partial_verified" + assert pyjhora["missing_required_outputs"] == ["D2", "D4", "Shadbala", "Ashtakavarga"] assert contract["replay_manifest"]["tested"] is False assert contract["replay_manifest"]["blocked_reason"] == "no_same_chart_oracle_rows_imported" assert report["status"] in {"complete", "partial"} diff --git a/tests/test_pyjhora_compare_cli.py b/tests/test_pyjhora_compare_cli.py index af20eb8f..20a2364b 100644 --- a/tests/test_pyjhora_compare_cli.py +++ b/tests/test_pyjhora_compare_cli.py @@ -14,4 +14,5 @@ def test_pyjhora_compare_help_is_non_executing(): assert result.returncode == 0 assert "--build-local" in result.stdout + assert "--output-prefix" in result.stdout assert "FileNotFoundError" not in result.stderr