feat(oracle): compare verified template evidence

This commit is contained in:
732642856
2026-06-26 17:14:19 +08:00
parent e6710e1e2a
commit 5578ba6e29
3 changed files with 171 additions and 0 deletions
+9
View File
@@ -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
+100
View File
@@ -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,
+62
View File
@@ -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"