feat(oracle): compare verified template evidence
This commit is contained in:
@@ -194,6 +194,15 @@ python3 scripts/oracle_evidence_validator.py \
|
||||
|
||||
该验证器输出 `external_oracle_evidence_validation`,会检查 `evidence_packet` 必填元数据、`target_placeholders` 是否已填、是否覆盖 `target_fields`、是否包含外部 artifact,以及是否错误使用本仓库本地引擎输出。当前 draft 队列会保持 `valid_packets: 0` / `ready_for_calibration: 0`;只有状态为 `external_verified` 且证据完整的包才会进入可复核状态。
|
||||
|
||||
证据包通过 validator 之后,再运行边界差异审计,比较本地引擎与外部 Dasha/Shadbala 目标值:
|
||||
|
||||
```bash
|
||||
python3 scripts/oracle_boundary_audit.py \
|
||||
--oracle-file references/oracle/dasha_shadbala_oracle_cases.json
|
||||
```
|
||||
|
||||
审计报告中的 `template_comparisons` 会列出 external-verified template 的 Dasha 起点差异、Shadbala 七曜分量/总分差异,并继续保持 `production_tuning_recommended: false`,防止用单个样本调生产常数。
|
||||
|
||||
`full-reading` 也会输出 `ai_prompt_pack`:这是给网页/app、skill 或后端 AI 代理使用的结构化 Prompt/RAG 上下文包。它不会硬编码断语,而是携带 D1/D9/Dasha/Shadbala/Ashtakavarga 的证据快照、推荐检索文档和边界提示,要求大模型基于计算证据交叉验证,避免单一配置下结论。
|
||||
|
||||
### Prerequisites
|
||||
|
||||
@@ -232,6 +232,99 @@ def _audit_template_case(case: dict[str, Any]) -> dict[str, Any]:
|
||||
}
|
||||
|
||||
|
||||
def _namespace_from_template(case: dict[str, Any]) -> argparse.Namespace:
|
||||
birth = dict(case.get("birth", {}))
|
||||
settings = case.get("settings", {})
|
||||
if "node_mode" not in birth and settings.get("node_mode"):
|
||||
birth["node_mode"] = settings["node_mode"]
|
||||
return _namespace_from_birth(
|
||||
birth,
|
||||
ayanamsa=settings.get("ayanamsa", "lahiri"),
|
||||
moon_lon=None,
|
||||
nakshatra=None,
|
||||
pada=None,
|
||||
birthdate=None,
|
||||
today=None,
|
||||
years=120,
|
||||
table=False,
|
||||
)
|
||||
|
||||
|
||||
def _first_dasha_start(result: dict[str, Any]) -> str | None:
|
||||
timeline = result.get("timeline")
|
||||
if isinstance(timeline, list) and timeline:
|
||||
return timeline[0].get("start")
|
||||
return None
|
||||
|
||||
|
||||
def _date_delta_days(engine_date: str | None, target_date: str | None) -> int | None:
|
||||
if not engine_date or not target_date:
|
||||
return None
|
||||
from datetime import date
|
||||
|
||||
try:
|
||||
engine_parts = [int(part) for part in engine_date.split("-")[:3]]
|
||||
target_parts = [int(part) for part in target_date.split("-")[:3]]
|
||||
return (date(*engine_parts) - date(*target_parts)).days
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _template_shadbala_comparison(case: dict[str, Any]) -> dict[str, Any]:
|
||||
target_components = case.get("target", {}).get("shadbala_components")
|
||||
if not isinstance(target_components, dict):
|
||||
return {"status": "missing_external_shadbala_components", "planets": {}}
|
||||
|
||||
result = engine.cmd_shadbala(_namespace_from_template(case))
|
||||
if "error" in result:
|
||||
return {"status": "engine_error", "error": result["error"], "planets": {}}
|
||||
|
||||
rows: dict[str, Any] = {}
|
||||
for planet in SHADBALA_PLANETS:
|
||||
external_row = target_components.get(planet, {})
|
||||
engine_row = result.get("planets", {}).get(planet, {})
|
||||
engine_components = _component_totals(engine_row) if engine_row else {}
|
||||
external_total = external_row.get("total_rupa") if isinstance(external_row, dict) else None
|
||||
engine_total = round(float(engine_row.get("total_rupas", 0.0)), 4) if engine_row else None
|
||||
rows[planet] = {
|
||||
"engine_total_rupa": engine_total,
|
||||
"external_total_rupa": external_total,
|
||||
"total_rupa_delta": (
|
||||
round(engine_total - float(external_total), 4)
|
||||
if engine_total is not None and isinstance(external_total, (int, float))
|
||||
else None
|
||||
),
|
||||
"engine_components": engine_components,
|
||||
"external_components": external_row,
|
||||
}
|
||||
return {"status": "compared", "planets": rows}
|
||||
|
||||
|
||||
def _audit_external_verified_template_case(case: dict[str, Any]) -> dict[str, Any]:
|
||||
target = case.get("target", {})
|
||||
dasha_result = engine.cmd_dasha(_namespace_from_template(case))
|
||||
engine_start = _first_dasha_start(dasha_result) if "error" not in dasha_result else None
|
||||
target_start = target.get("vimshottari_start_date")
|
||||
return {
|
||||
"case_id": case.get("id") or case.get("case_id"),
|
||||
"status": case.get("status"),
|
||||
"source": case.get("source"),
|
||||
"metadata": case.get("evidence_packet", {}).get("metadata", {}),
|
||||
"dasha": {
|
||||
"status": "compared" if engine_start and target_start else "missing_dasha_target",
|
||||
"engine_start_date": engine_start,
|
||||
"target_start_date": target_start,
|
||||
"date_delta_days": _date_delta_days(engine_start, target_start),
|
||||
},
|
||||
"shadbala": _template_shadbala_comparison(case),
|
||||
"calibration_decision": "do_not_tune_single_template",
|
||||
"finding": (
|
||||
"External-verified template rows are comparison evidence. Production constants require "
|
||||
"a multi-source sample matrix and must not be tuned to a single packet."
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def _status_counts(rows: list[dict[str, Any]]) -> dict[str, int]:
|
||||
counts: dict[str, int] = {}
|
||||
for row in rows:
|
||||
@@ -242,6 +335,11 @@ def _status_counts(rows: list[dict[str, Any]]) -> dict[str, int]:
|
||||
|
||||
def build_report(oracle: dict[str, Any]) -> dict[str, Any]:
|
||||
template_rows = [_audit_template_case(case) for case in oracle.get("template_cases", [])]
|
||||
template_comparisons = [
|
||||
_audit_external_verified_template_case(case)
|
||||
for case in oracle.get("template_cases", [])
|
||||
if case.get("status") in ORACLE_TEMPLATE_READY_STATUSES and not _missing_target_fields(case.get("target", {}))
|
||||
]
|
||||
dasha_rows = [_audit_dasha_case(case) for case in oracle.get("dasha_cases", [])]
|
||||
longitude_rows = [_audit_longitude_case(case) for case in oracle.get("longitude_cases", [])]
|
||||
shadbala_rows = [_audit_shadbala_case(case) for case in oracle.get("shadbala_cases", [])]
|
||||
@@ -251,6 +349,7 @@ def build_report(oracle: dict[str, Any]) -> dict[str, Any]:
|
||||
"summary": {
|
||||
"template_cases": len(template_rows),
|
||||
"template_status_counts": _status_counts(template_rows),
|
||||
"external_verified_template_cases": len(template_comparisons),
|
||||
"dasha_cases": len(dasha_rows),
|
||||
"longitude_cases": len(longitude_rows),
|
||||
"shadbala_cases": len(shadbala_rows),
|
||||
@@ -262,6 +361,7 @@ def build_report(oracle: dict[str, Any]) -> dict[str, Any]:
|
||||
],
|
||||
},
|
||||
"template_cases": template_rows,
|
||||
"template_comparisons": template_comparisons,
|
||||
"dasha_cases": dasha_rows,
|
||||
"longitude_cases": longitude_rows,
|
||||
"shadbala_cases": shadbala_rows,
|
||||
|
||||
@@ -72,3 +72,65 @@ def test_oracle_boundary_audit_reports_dasha_and_shadbala_boundaries() -> None:
|
||||
assert template["status"] == "template_only"
|
||||
assert template["ready_for_calibration"] is False
|
||||
assert template["missing_target_fields"]
|
||||
|
||||
|
||||
def test_oracle_boundary_audit_compares_external_verified_template_rows(tmp_path: Path) -> None:
|
||||
oracle = json.loads((ROOT / "references/oracle/dasha_shadbala_oracle_cases.json").read_text(encoding="utf-8"))
|
||||
case = oracle["template_cases"][1]
|
||||
case["status"] = "external_verified"
|
||||
case["target"]["vimshottari_start_date"] = "1951-11-01"
|
||||
case["target"]["shadbala_components"] = {
|
||||
planet: {
|
||||
"sthana": 1.0,
|
||||
"dig": 2.0,
|
||||
"kala": 3.0,
|
||||
"chesta": 4.0,
|
||||
"naisargika": 5.0,
|
||||
"drik": 6.0,
|
||||
"total_rupa": 21.0,
|
||||
}
|
||||
for planet in ["Sun", "Moon", "Mars", "Mercury", "Jupiter", "Venus", "Saturn"]
|
||||
}
|
||||
case["evidence_packet"] = {
|
||||
"capture_id": "external_template_steve_jobs_dasha_lahiri",
|
||||
"status": "external_verified",
|
||||
"metadata": {
|
||||
"tool_name": "JHora",
|
||||
"tool_version_or_url": "manual-jhora-8.0",
|
||||
"capture_date": "2026-06-26",
|
||||
"source_artifact": "references/oracle/artifacts/steve_jobs_jhora_redacted.png",
|
||||
"ayanamsa": "lahiri",
|
||||
"node_mode": "true",
|
||||
"timezone": "UTC-08:00",
|
||||
"operator_note": "Typed from redacted external JHora screenshot.",
|
||||
},
|
||||
}
|
||||
oracle_path = tmp_path / "oracle.json"
|
||||
oracle_path.write_text(json.dumps(oracle, ensure_ascii=False), encoding="utf-8")
|
||||
|
||||
completed = subprocess.run(
|
||||
[
|
||||
sys.executable,
|
||||
"scripts/oracle_boundary_audit.py",
|
||||
"--oracle-file",
|
||||
str(oracle_path),
|
||||
],
|
||||
cwd=ROOT,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
timeout=60,
|
||||
check=False,
|
||||
)
|
||||
|
||||
assert completed.returncode == 0, completed.stderr or completed.stdout
|
||||
report = json.loads(completed.stdout)
|
||||
assert report["summary"]["external_verified_template_cases"] == 1
|
||||
assert report["summary"]["production_tuning_recommended"] is False
|
||||
comparison = report["template_comparisons"][0]
|
||||
assert comparison["case_id"] == "template_steve_jobs_dasha_lahiri"
|
||||
assert comparison["status"] == "external_verified"
|
||||
assert comparison["dasha"]["target_start_date"] == "1951-11-01"
|
||||
assert comparison["dasha"]["date_delta_days"] is not None
|
||||
assert comparison["shadbala"]["planets"]["Sun"]["external_total_rupa"] == 21.0
|
||||
assert comparison["shadbala"]["planets"]["Sun"]["total_rupa_delta"] is not None
|
||||
assert comparison["calibration_decision"] == "do_not_tune_single_template"
|
||||
|
||||
Reference in New Issue
Block a user