chore(release): harden premium skill packaging

This commit is contained in:
732642856
2026-07-10 22:31:28 +08:00
parent 52266a3b64
commit 3cbc9ca585
30 changed files with 1567 additions and 40 deletions
+2
View File
@@ -62,6 +62,8 @@ For large architecture or release work, also read:
| ERR-029 | Basic git and premium cloud-drive skill packages can blur contents, privacy exclusions, and external-engine promises. | mitigated 2026-07-09 | `scripts/skill_release_manifest.py` must define edition contents, excluded private material, acceptance commands, and external-engine runtime boundaries before packaging. |
| ERR-030 | Release packaging can misread non-ASCII tracked filenames when parsing quoted `git ls-files` output. | mitigated 2026-07-09 | Package builders must use `git ls-files -z` and decode NUL-separated paths before writing zip archives. |
| ERR-031 | Premium skill zip can ship without user install prompts or replay schemas, leaving users and future oracle imports without a contract. | mitigated 2026-07-09 | `skill_release_package.py` must inject `INSTALL.md` and `USER_PROMPTS.md`; replay contracts must live in `references/real_case_calibration/` and `references/oracle/`. |
| ERR-032 | Full smoke files can time out while focused slices pass; `test_full_reading_reports_ayanamsa_metadata_and_ai_prompt_pack` currently exposes `external_oracle_gap_summary=null`. | observed 2026-07-10 | Do not claim full `tests/test_cli_smoke.py` or full `tests/test_vedastro_external_technique_evidence.py` passed unless run to completion; use focused slices for related changes and track the prompt-pack gap separately. |
| ERR-033 | Premium skill zip validation can accidentally depend on a parent Git repository, so a cloud-drive user may fail in a clean unzip directory. | mitigated 2026-07-10 | Release acceptance must include `tests/test_skill_release_clean_trial.py`; scripts such as `public_release_privacy_scan.py` must support non-Git unpacked zip directories. |
## Fragment Sweep Command Set
+14
View File
@@ -712,6 +712,8 @@ def _execute_mcp_consultation_workflow(
entry_mode: str = "direct_chart",
theme: list[str] | None = None,
events: list[dict[str, Any]] | None = None,
western_evidence_packet: dict[str, Any] | None = None,
western_oracle_payload: dict[str, Any] | None = None,
) -> Dict[str, Any]:
from jyotish_api_server import JyotishAPIHandler, execute_consultation_workflow
@@ -733,6 +735,8 @@ def _execute_mcp_consultation_workflow(
"entry_mode": entry_mode,
"theme": theme or [],
"events": events or [],
**({"western_evidence_packet": western_evidence_packet} if isinstance(western_evidence_packet, dict) else {}),
**({"western_oracle_payload": western_oracle_payload} if isinstance(western_oracle_payload, dict) else {}),
},
surface="skill_mcp",
)
@@ -4186,6 +4190,8 @@ def strict_workflow(
age: int,
transit_date: str,
node_mode: str = "mean",
western_evidence_packet: Optional[Dict[str, Any]] = None,
western_oracle_payload: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
"""
Strict workflow router: routes question to the correct analysis path.
@@ -4208,6 +4214,8 @@ def strict_workflow(
age: Current age
transit_date: Transit date for prediction (YYYY-MM-DD)
node_mode: 'mean' or 'true'
western_evidence_packet: Optional pre-normalized Western evidence packet
western_oracle_payload: Optional external Western oracle JSON export
Returns:
JSON with routed analysis and confidence level
@@ -4229,6 +4237,8 @@ def strict_workflow(
node_mode=node_mode,
entry_mode="direct_chart",
theme=normalized_themes,
western_evidence_packet=western_evidence_packet,
western_oracle_payload=western_oracle_payload,
)
chart = result.get("chart") if isinstance(result, dict) else {}
route = _safe_get(result, "routing", "question_type") or route_packet["question_type"] or "general"
@@ -4276,6 +4286,9 @@ def strict_workflow(
result["interpretation_source_runtime_coverage"] = interpretation_coverage
result["machine_evidence_packet"] = machine_evidence_packet
result["real_case_calibration"] = real_case_calibration
western_packet = result.get("western_evidence_packet")
if not isinstance(western_packet, dict) or not western_packet:
western_packet = western_evidence_packet if isinstance(western_evidence_packet, dict) else None
result["runtime_evidence_log"] = _UNIFIED_CONSULTATION_ORCHESTRATOR.runtime_evidence_log(
surface="skill_mcp",
entry_mode=result.get("entry_mode", "direct_chart"),
@@ -4286,6 +4299,7 @@ def strict_workflow(
interpretation_source_runtime_coverage=interpretation_coverage,
machine_evidence_packet=machine_evidence_packet,
real_case_calibration=real_case_calibration,
western_evidence_packet=western_packet,
blind=False,
)
except Exception:
+69
View File
@@ -876,3 +876,72 @@
- 已启用 Hermes fallback 插件:`hermes plugins enable squeez-fallback` 成功,提示下一 session 生效。
- 已验证 `ccusage` 可通过 `npx` 临时运行,版本 `20.0.14`;本轮未全局安装。
- 仍需用户重启 Codex/相关 CLI,让已安装 hooks 在新 session 中生效。
## 2026-07-10T00:00:00+08:00 - 西占/印占协同仲裁层 MVP
- 用户要求按规划执行“印度占星主链 + 西方占星交叉验证”的高级版能力。
- 新增 `scripts/western_evidence_packet.py`:定义西占证据包最小合同,只接收已生成的本命/时序/信号证据,不内置 Kerykeion、pyswisseph、Flatlib、Immanuel 等外部项目源码。
- 新增 `scripts/cross_system_arbitrator.py`:比较 Jyotish 与 Western evidence signals,输出 shared signals、conflicts、blocked items 和 Technique Audit rows。
- `scripts/unified_consultation_orchestrator.py` 的 `runtime_evidence_log()` 新增可选 `western_evidence_packet`,并把 `Western Cross-Validation`、`Cross-System Arbitration` 纳入 Technique Audit Table 与 required rows。
- 新增测试:`tests/test_western_evidence_packet.py`、`tests/test_cross_system_arbitrator.py`,并扩展 `tests/test_unified_consultation_orchestrator.py`。
- 验证:`python3 -m pytest -q tests/test_western_evidence_packet.py tests/test_cross_system_arbitrator.py tests/test_unified_consultation_orchestrator.py tests/test_mcp_strict_workflow_career.py tests/test_vedastro_external_technique_evidence.py::test_vedastro_adapter_declares_external_technique_evidence_policy tests/test_vedastro_external_technique_evidence.py::test_vedastro_adapter_builds_external_technique_preview_without_network` 通过,39 passed;`python3 scripts/pre_work_check.py --remote-timeout 8 --command-timeout 45` 通过。
- 边界:本轮不声称已完成西占排盘引擎内置或真实案例 replay complete;外部西占项目仍按 license boundary 作为 oracle/adapters,不直接复制进高级闭源包。
## 2026-07-10T00:00:00+08:00 - 西占外部 oracle JSON adapter
- 新增 `scripts/western_oracle_adapter.py`:读取外部西占 JSON,输出标准 `western_evidence_packet`。
- 支持两种输入:显式 `signals` 直通;或从 `aspects` 派生少量可审计 signals。
- 当前派生规则只覆盖三类高价值 career signals:Uranus 合 MC、Jupiter 拱/六合 Mercury/Venus/MC、Saturn 合 Sun/Mercury/Venus。
- 新增 `references/oracle/western_oracle_adapter_contract.md`,说明输入格式、CLI、派生规则和许可证边界。
- 新增 `tests/test_western_oracle_adapter.py`。
- 验证:`python3 -m pytest -q tests/test_western_oracle_adapter.py tests/test_western_evidence_packet.py tests/test_cross_system_arbitrator.py tests/test_unified_consultation_orchestrator.py` 通过,22 passed;MCP/外部证据 focused 20 passed。
- 边界:adapter 不执行西占排盘,不内置 Kerykeion/Flatlib/Immanuel/pyswisseph;这些仍作为外部 oracle 或用户导出 JSON 来源。
## 2026-07-10T00:00:00+08:00 - 西占 oracle 入口闭环
- API 共享执行器 `execute_consultation_workflow(...)` 现在接受 `western_evidence_packet` 或 `western_oracle_payload`,会把外部西占导出 JSON 标准化后传入 `runtime_evidence_log()`。
- MCP `strict_workflow(...)` 现在也可透传同样的西占证据包/外部 oracle payload,并在二次 strict adjudication 后保留 `Western Cross-Validation` 与 `Cross-System Arbitration` audit。
- `machine_evidence_packet()` 现在保留上游已生成的 `cross_system_signals`,只做证据透传,不自行生成解释性结论。
- `references/oracle/western_oracle_adapter_contract.md` 已补 API/MCP 入口字段说明。
- 新增入口测试:`test_consultation_workflow_accepts_western_oracle_payload`、`test_mcp_strict_workflow_preserves_western_evidence_packet`。
- 验证:`python3 -m pytest -q tests/test_api_server_security.py::test_consultation_workflow_accepts_western_oracle_payload tests/test_mcp_strict_workflow_career.py::test_mcp_strict_workflow_preserves_western_evidence_packet tests/test_western_oracle_adapter.py tests/test_western_evidence_packet.py tests/test_cross_system_arbitrator.py tests/test_unified_consultation_orchestrator.py` 通过,24 passed;扩展 MCP/API focused 回归通过,24 passed。
- 边界:若 Jyotish 侧没有生成同主题 `cross_system_signals`,cross-system arbitration 仍会诚实显示 `partial`,不会把单边西占信号伪装成双系统互证。
## 2026-07-10T00:00:00+08:00 - 真实案例 outcome replay manifest 守门
- 新增 `references/real_case_calibration/replay_manifest.json`:先固定真实案例 outcome replay 导入合同;当前 `cases=[]`,状态明确 blocked,不伪装为 complete。
- 新增 `scripts/real_case_replay_validator.py`:无第三方依赖,检查 case/source/event/replay 必填字段,输出 `case_count`、`replay_ready_count`、`blocked_reason` 和结构错误列表。
- `real_case_calibration_catalog()` 现在暴露 `required_replay_schema` 与 `outcome_replay_manifest`,让 runtime evidence 能显示真实案例 replay 是否真的完成。
- 新增测试:`tests/test_real_case_replay_validator.py`。
- 验证:`python3 -m pytest -q tests/test_real_case_replay_validator.py tests/test_calibration_replay_schemas.py tests/test_unified_consultation_orchestrator.py tests/test_western_oracle_adapter.py tests/test_cross_system_arbitrator.py tests/test_api_server_security.py::test_consultation_workflow_accepts_western_oracle_payload tests/test_mcp_strict_workflow_career.py::test_mcp_strict_workflow_preserves_western_evidence_packet` 通过,27 passed。
- 边界:本轮只完成 replay 合同与机器守门;尚未导入全球真实案例 raw/outcome 数据,因此 `Real Case Calibration` 仍应保持 partial/blocked 置信边界。
## 2026-07-10T00:00:00+08:00 - 三引擎 parity replay manifest 守门
- 新增 `references/oracle/three_engine_parity_replay_manifest.json`:固定 VedAstro / PyJHora-JHora / jyotishganit 同盘 replay 导入合同;当前无 comparison rows,明确 blocked。
- 新增 `scripts/three_engine_parity_replay_validator.py`:无第三方依赖,校验 required engines、comparison rows、row status,输出 `tested`、match/mismatch/blocked counts 和 `blocked_reason`。
- `scripts/diagnose_external_engine_adapters.py` 的 `same_chart_parity_contract` 现在包含 `replay_manifest`,避免把 readiness 误读成真实同盘 parity 已测试。
- 新增测试:`tests/test_three_engine_parity_replay_validator.py`,并扩展 `tests/test_external_engine_adapter_diagnostics.py`。
- 验证:`python3 -m pytest -q tests/test_unified_consultation_orchestrator.py tests/test_western_oracle_adapter.py tests/test_cross_system_arbitrator.py tests/test_api_server_security.py::test_consultation_workflow_accepts_western_oracle_payload tests/test_mcp_strict_workflow_career.py::test_mcp_strict_workflow_preserves_western_evidence_packet tests/test_external_engine_adapter_diagnostics.py tests/test_three_engine_parity_replay_validator.py tests/test_real_case_replay_validator.py` 通过,28 passed。
- 边界:本轮只完成 parity replay 合同与诊断守门;未安装/调用外部专业软件,不声称 VedAstro/PyJHora/JHora/jyotishganit 已完成同盘比对。
## 2026-07-10T00:00:00+08:00 - 高级版 Skill 打包最终验收
- `scripts/skill_release_package.py` 现在会生成 `RELEASE_MANIFEST.json` 和 `PACKAGE_ACCEPTANCE.json`,并把 acceptance 状态写入 dry-run/zip plan。
- `INSTALL.md` 生成内容已补基础 Git 地址 `https://github.com/732642856/yinduzhanxing`、普通用户验收命令和 VedAstro official raw 边界。
- `USER_PROMPTS.md` 生成内容已补最高品质调用模板:统一主链、Technique Audit Table、三引擎 parity replay、真实案例 replay、`western_oracle_payload` 边界。
- 高级版 zip 会强制包含三类合同:`references/real_case_calibration/replay_manifest.json`、`references/oracle/three_engine_parity_replay_manifest.json`、`references/oracle/western_oracle_adapter_contract.md`,即使这些合同是当前工作区新文件。
- 修复 `scripts/user_invocation_acceptance_check.py`:外部引擎诊断 `status=complete` 现在视为可用状态,不再误报 `external_adapter_status_unusable`。
- 已生成本地验收产物:`scratch/local/releases/jyotish-premium-skill.zip`,大小约 20 MB,`PACKAGE_ACCEPTANCE.json.status=pass`,关键文件缺失列表为空。
- 验证:`python3 -m pytest -q tests/test_skill_release_package.py tests/test_skill_release_manifest.py tests/test_user_invocation_acceptance_contract.py tests/test_external_engine_adapter_diagnostics.py tests/test_three_engine_parity_replay_validator.py tests/test_real_case_replay_validator.py` 通过,14 passed;`git diff --check` 通过;`python3 scripts/pre_work_check.py --remote-timeout 8 --command-timeout 45` 通过。
- 边界:zip 产物只在本地 scratch,尚未提交或推送;外部 official raw/parity rows 未导入,包内 acceptance 只证明 release hygiene 和合同齐备。
## 2026-07-10T00:00:00+08:00 - 高级版 Skill 干净目录解压试用验收
- 新增 `tests/test_skill_release_clean_trial.py`:测试会生成高级版 zip、解压到 pytest 临时干净目录,再在解压目录中运行隐私扫描和普通用户调用验收。
- 修复 `scripts/public_release_privacy_scan.py`:当目录没有 `.git` 或 `git ls-files` 不可用时,自动退回目录遍历;这覆盖云盘 zip 解压后的真实用户环境。
- 新增 `test_public_release_privacy_scan_supports_unpacked_zip_without_git`,防止隐私扫描再次只适配源码仓。
- 手工 clean trial 已跑过:`scratch/local/clean_skill_trial` 关键文件缺失列表为空,`public_release_privacy_scan.py` 0 findings,`diagnose_external_engine_adapters.py --json` 返回 `status=complete`,`user_invocation_acceptance_check.py` 返回 `status=pass`。
- 已用修复后的脚本重新生成 `scratch/local/releases/jyotish-premium-skill.zip`;并在仓外 `/tmp/jyotish-clean-trial.MvZWWX` 解压验证,确认无 `.git` 环境下 `public_release_privacy_scan.py`、`diagnose_external_engine_adapters.py --json`、`user_invocation_acceptance_check.py` 均可运行,用户调用验收 `status=pass`。
- 验证:`python3 -m pytest -q tests/test_public_release_privacy_scan.py tests/test_skill_release_clean_trial.py` 通过,4 passed;release 组合回归 `python3 -m pytest -q tests/test_skill_release_clean_trial.py tests/test_skill_release_package.py tests/test_skill_release_manifest.py tests/test_user_invocation_acceptance_contract.py tests/test_external_engine_adapter_diagnostics.py tests/test_three_engine_parity_replay_validator.py tests/test_real_case_replay_validator.py tests/test_public_release_privacy_scan.py` 通过,18 passed。
- 边界:这是本地 macOS/Python 干净目录验收,不代表 VedAstro official raw、PyJHora/JHora 或真实案例 replay 已完成外部数据闭环。
@@ -0,0 +1,25 @@
{
"case_id": "contract_ready_no_same_chart_rows",
"birth_data_policy": "operator_local_only",
"status": "not_started",
"engines": {
"VedAstro": {
"status": "blocked",
"official_raw_response_path": "",
"artifact_hash": ""
},
"PyJHora_JHora": {
"status": "blocked",
"raw_output_path": "",
"settings": {}
},
"jyotishganit": {
"status": "blocked",
"raw_output_path": "",
"settings": {}
}
},
"comparison_rows": [],
"blocked_reason": "no_same_chart_oracle_rows_imported",
"runtime_boundary": "This manifest defines the same-chart parity replay contract only. It does not prove VedAstro/PyJHora/JHora/jyotishganit parity until raw oracle rows are imported."
}
@@ -0,0 +1,76 @@
# Western Oracle Adapter Contract
This contract defines how external Western astrology outputs enter the high-rigor Jyotish workflow.
## Purpose
`scripts/western_oracle_adapter.py` converts an external Western astrology JSON export into the standard `western_evidence_packet`.
It is an evidence adapter, not a bundled Western astrology engine.
## Accepted Input
```json
{
"source_engine": "kerykeion_external_json",
"natal": {
"ascendant": "Virgo",
"mc": "Gemini"
},
"timing_techniques": {
"solar_return": {
"annual_focus": "career"
}
},
"aspects": [
{
"date": "2026-07-07",
"planet": "Uranus",
"aspect": "conjunction",
"target": "MC"
}
]
}
```
Explicit `signals` may be provided. When present, explicit signals are preserved and aspect-derived signals are not guessed.
## Derived Signal Rules
The adapter currently maps only a small auditable subset:
| Aspect Pattern | Signal |
|---|---|
| Uranus conjunction MC/Midheaven | `career_relocation / career_triggered_relocation` |
| Jupiter trine/sextile Mercury/Venus/MC | `career / client_cooperation_opportunity` |
| Saturn conjunction Sun/Mercury/Venus | `career / career_responsibility_test` |
More mappings require tests and source notes before being added.
## Entry Points
API and MCP callers may pass either field:
- `western_oracle_payload`: raw external Western astrology JSON export; the project normalizes it with `western_oracle_adapter`.
- `western_evidence_packet`: pre-normalized packet; the project carries it directly into `runtime_evidence_log`.
When Jyotish evidence also carries matching `cross_system_signals`, `Cross-System Arbitration` can become `used`. If only Western evidence is present, arbitration stays `partial` or `blocked`.
## CLI
```bash
python3 scripts/western_oracle_adapter.py \
--input /path/to/western_oracle.json \
--theme career \
--question-type career
```
The command prints a `western_evidence_packet` JSON object.
## License Boundary
The premium skill may accept JSON exports from Kerykeion, Flatlib, Immanuel, Astro.com, GongShenXing, or desktop software.
Do not copy third-party source code into the premium package unless the exact project and dependency licenses permit bundling.
The adapter stores derived evidence and source labels only.
@@ -0,0 +1,8 @@
{
"schema_version": "1.0",
"status": "contract_ready_no_cases",
"case_schema": "references/real_case_calibration/catalog.schema.json",
"cases": [],
"blocked_reason": "no_structured_outcome_replay_cases_imported",
"runtime_boundary": "This manifest defines the replay import contract only. No real-case outcome replay is complete until structured cases are imported and validated."
}
+139
View File
@@ -0,0 +1,139 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Cross-system Jyotish/Western evidence arbitration."""
from __future__ import annotations
from typing import Any
def _packet_status(packet: dict[str, Any] | None) -> str:
if not isinstance(packet, dict) or not packet:
return "blocked"
return str(packet.get("status") or "partial")
def _signals(packet: dict[str, Any] | None) -> list[dict[str, Any]]:
if not isinstance(packet, dict):
return []
raw = packet.get("signals")
if not isinstance(raw, list):
raw = packet.get("cross_system_signals")
if not isinstance(raw, list):
return []
signals: list[dict[str, Any]] = []
for item in raw:
if isinstance(item, dict) and item.get("theme") and item.get("claim"):
signals.append(
{
"theme": str(item.get("theme")),
"claim": str(item.get("claim")),
"timing": str(item.get("timing") or "unspecified"),
"source": str(item.get("source") or "unspecified"),
}
)
return signals
def _audit_row(name: str, status: str, used: bool, effect: str) -> dict[str, Any]:
return {
"technique": name,
"status": status,
"used": used,
"effect_on_confidence": effect,
}
def build_cross_system_arbitration(
*,
route_packet: dict[str, Any],
jyotish_evidence: dict[str, Any] | None,
western_evidence: dict[str, Any] | None,
) -> dict[str, Any]:
"""Compare materialized Jyotish and Western evidence packets."""
primary_theme = str(route_packet.get("primary_theme") or route_packet.get("question_type") or "general")
jyotish_status = _packet_status(jyotish_evidence)
western_status = _packet_status(western_evidence)
blocked_items: list[str] = []
if jyotish_status == "blocked":
blocked_items.append("jyotish_evidence_packet_missing")
if western_status == "blocked":
blocked_items.append("western_evidence_packet_missing")
jyotish_signals = _signals(jyotish_evidence)
western_signals = _signals(western_evidence)
shared: list[dict[str, Any]] = []
conflicts: list[dict[str, Any]] = []
for jyotish_signal in jyotish_signals:
for western_signal in western_signals:
if jyotish_signal["theme"] != western_signal["theme"]:
continue
if jyotish_signal["claim"] == western_signal["claim"]:
shared.append(
{
"theme": jyotish_signal["theme"],
"claim": jyotish_signal["claim"],
"timing": (
jyotish_signal["timing"]
if jyotish_signal["timing"] == western_signal["timing"]
else f"{jyotish_signal['timing']} | western:{western_signal['timing']}"
),
"jyotish_source": jyotish_signal["source"],
"western_source": western_signal["source"],
"confidence_effect": "raises_confidence",
}
)
else:
conflicts.append(
{
"theme": jyotish_signal["theme"],
"jyotish_claim": jyotish_signal["claim"],
"western_claim": western_signal["claim"],
"jyotish_timing": jyotish_signal["timing"],
"western_timing": western_signal["timing"],
"confidence_effect": "lowers_confidence",
}
)
if blocked_items:
status = "blocked"
elif conflicts and not shared:
status = "conflict"
elif shared:
status = "used"
else:
status = "partial"
return {
"status": status,
"primary_theme": primary_theme,
"jyotish_cross_validation": {"status": jyotish_status, "signal_count": len(jyotish_signals)},
"western_cross_validation": {"status": western_status, "signal_count": len(western_signals)},
"shared_signals": shared,
"conflicts": conflicts,
"blocked_items": blocked_items,
"technique_audit_rows": [
_audit_row(
"Western Cross-Validation",
western_status,
western_status in {"complete", "used"} or bool(western_signals),
"western_oracle_available_for_trigger_refinement"
if western_status != "blocked"
else "blocked_until_western_evidence_packet_is_materialized",
),
_audit_row(
"Cross-System Arbitration",
status,
status == "used",
"shared_signals_raise_confidence"
if status == "used"
else "confidence_capped_until_systems_share_a_theme_signal",
),
],
"boundary": (
"Arbitration compares materialized evidence only; it does not replace Jyotish adjudication or "
"claim Western calculations were run when the western packet is missing."
),
}
@@ -10,10 +10,12 @@ try:
from diagnose_vedastro_mode import build_report as build_vedastro_report
from diagnose_pyjhora_adapter import build_report as build_pyjhora_report
from diagnose_jyotishganit_adapter import build_report as build_jyotishganit_report
from three_engine_parity_replay_validator import validate_manifest as validate_parity_replay_manifest
except Exception: # pragma: no cover - import path varies in tests/CLI
from scripts.diagnose_vedastro_mode import build_report as build_vedastro_report
from scripts.diagnose_pyjhora_adapter import build_report as build_pyjhora_report
from scripts.diagnose_jyotishganit_adapter import build_report as build_jyotishganit_report
from scripts.three_engine_parity_replay_validator import validate_manifest as validate_parity_replay_manifest
REQUIRED_PARITY_OUTPUTS = ["D1", "D9", "D10", "D2", "D4", "Vimshottari", "Shadbala", "Ashtakavarga"]
@@ -29,6 +31,7 @@ def _same_chart_parity_contract(engines: dict) -> dict:
"blocked": not available,
"blocking_reason": "" if available else engine["status"],
}
replay_manifest = validate_parity_replay_manifest("references/oracle/three_engine_parity_replay_manifest.json")
return {
"status": "ready" if all(state["available"] for state in engine_states.values()) else "blocked",
"required_outputs": REQUIRED_PARITY_OUTPUTS,
@@ -56,6 +59,7 @@ def _same_chart_parity_contract(engines: dict) -> dict:
"jyotishganit": ["raw_output_path", "panchanga", "tithi", "nakshatra", "yoga", "karana"],
},
"engine_states": engine_states,
"replay_manifest": replay_manifest,
"boundary": "This is a parity contract, not proof that the same-chart comparison has run.",
}
+31
View File
@@ -30,6 +30,10 @@ try:
from scripts.unified_consultation_orchestrator import UnifiedConsultationOrchestrator
except ModuleNotFoundError: # pragma: no cover - script execution path
from unified_consultation_orchestrator import UnifiedConsultationOrchestrator
try:
from scripts.western_oracle_adapter import build_packet_from_oracle_payload
except ModuleNotFoundError: # pragma: no cover - script execution path
from western_oracle_adapter import build_packet_from_oracle_payload
SCRIPTS_DIR = os.path.dirname(os.path.abspath(__file__))
REPO_ROOT = os.path.abspath(os.path.join(SCRIPTS_DIR, '..'))
@@ -41,6 +45,27 @@ _HIGH_RIGOR_JOB_SCOPE = 'high_rigor_workflow'
_UNIFIED_CONSULTATION_ORCHESTRATOR = UnifiedConsultationOrchestrator()
def _western_evidence_packet_from_body(body: dict, route_packet: dict) -> dict | None:
explicit_packet = body.get('western_evidence_packet')
if isinstance(explicit_packet, dict):
return explicit_packet
oracle_payload = body.get('western_oracle_payload') or body.get('western_astrology_oracle')
if not isinstance(oracle_payload, dict):
return None
try:
return build_packet_from_oracle_payload(oracle_payload, route_packet=route_packet)
except Exception as exc: # pragma: no cover - defensive contract boundary
return {
'system': 'western_astrology',
'status': 'blocked',
'route': dict(route_packet),
'signals': [],
'missing_sections': ['western_oracle_payload'],
'adapter_error': exc.__class__.__name__,
'boundary': 'Western oracle payload was supplied but could not be normalized.',
}
def execute_consultation_workflow(
handler,
*,
@@ -55,6 +80,7 @@ def execute_consultation_workflow(
entry_mode = body.get('entry_mode', 'direct_chart')
high_rigor = bool(body.get('return_high_rigor_shape'))
route_packet = _UNIFIED_CONSULTATION_ORCHESTRATOR.resolve_route(question, themes)
western_evidence_packet = _western_evidence_packet_from_body(body, route_packet)
unified_contract = _UNIFIED_CONSULTATION_ORCHESTRATOR.shared_contract(
entry_mode=entry_mode,
question=question,
@@ -97,8 +123,11 @@ def execute_consultation_workflow(
route_packet=route_packet,
executed_steps=[],
skipped_steps=known_steps,
western_evidence_packet=western_evidence_packet,
blind=bool(body.get('blind') or body.get('blind_technical_mode')),
)
if western_evidence_packet:
result['western_evidence_packet'] = western_evidence_packet
if body.get('return_high_rigor_shape'):
result['endpoint'] = 'high_rigor_workflow'
return result
@@ -207,6 +236,7 @@ def execute_consultation_workflow(
interpretation_source_runtime_coverage=interpretation_source_runtime_coverage,
machine_evidence_packet=machine_evidence_packet,
real_case_calibration=real_case_calibration,
western_evidence_packet=western_evidence_packet,
blind=bool(body.get('blind') or body.get('blind_technical_mode')),
)
@@ -253,6 +283,7 @@ def execute_consultation_workflow(
'runtime_truth': runtime_truth,
'interpretation_source_runtime_coverage': interpretation_source_runtime_coverage,
'machine_evidence_packet': machine_evidence_packet,
'western_evidence_packet': western_evidence_packet or {},
'real_case_calibration': real_case_calibration,
'runtime_evidence_log': runtime_evidence_log,
'next_questions': handler._high_rigor_next_questions(rectification, historical_backtest),
+46 -27
View File
@@ -5,6 +5,7 @@ from __future__ import annotations
import argparse
import json
import os
import re
import subprocess
from pathlib import Path
@@ -40,28 +41,38 @@ TEXT_SUFFIXES = {
".yml",
}
DENY_PATTERNS: list[tuple[str, re.Pattern[str]]] = [
("private_exact_iso_birth_date", re.compile(r"REDACTED_DATE")),
("private_compact_birth_datetime", re.compile(r"REDACTED_DATE[_-]?REDACTED_TIME")),
("private_slug_birth_date", re.compile(r"REDACTED_YEAR[_-]04[_-]17")),
("private_birth_time_literal", re.compile(r"REDACTED_YEAR.{0,120}\bREDACTED_TIME\b|\bREDACTED_TIME\b.{0,120}REDACTED_YEAR|REDACTED_TIME")),
("private_place_han", re.compile(r"REDACTED_PLACE|REDACTED_PLACE|REDACTED_HOSPITAL")),
("private_case_slug", re.compile(r"user_REDACTED_YEAR|redacted_place", re.IGNORECASE)),
(
"private_birth_dict_tuple",
re.compile(
r"(?s)(?:year|--year|datetime\()\D*REDACTED_YEAR.{0,220}"
r"(?:month|--month|,\s*)\D*4.{0,220}"
r"(?:day|--day|,\s*)\D*17.{0,220}"
r"(?:hour|--hour|,\s*)\D*14.{0,220}"
r"(?:minute|--minute|,\s*)\D*49"
),
),
]
LOCAL_DENY_PATTERN_FILE = Path("scratch/local/public_release_deny_patterns.txt")
ENV_DENY_PATTERNS = "PUBLIC_RELEASE_DENY_PATTERNS"
def _is_skipped(path: Path) -> bool:
rel = path.relative_to(ROOT).as_posix()
def _literal_patterns(values: Iterable[str], prefix: str) -> list[tuple[str, re.Pattern[str]]]:
patterns: list[tuple[str, re.Pattern[str]]] = []
for index, value in enumerate(values, start=1):
value = value.strip()
if not value or value.startswith("#"):
continue
patterns.append((f"{prefix}_{index:02d}", re.compile(re.escape(value), re.IGNORECASE)))
return patterns
def deny_patterns(root: Path = ROOT) -> list[tuple[str, re.Pattern[str]]]:
patterns = _literal_patterns(os.environ.get(ENV_DENY_PATTERNS, "").splitlines(), "private_env_pattern")
local_file = root / LOCAL_DENY_PATTERN_FILE
if local_file.is_file():
patterns.extend(
_literal_patterns(
local_file.read_text(encoding="utf-8", errors="ignore").splitlines(),
"private_local_pattern",
)
)
return patterns
def _is_skipped(path: Path, root: Path = ROOT) -> bool:
try:
rel = path.relative_to(root).as_posix()
except ValueError:
rel = path.as_posix()
if rel in SKIP_FILES:
return True
return any(rel == item or rel.startswith(f"{item}/") for item in SKIP_DIRS)
@@ -73,23 +84,30 @@ def iter_release_files(root: Path = ROOT) -> Iterable[Path]:
cwd=root,
text=True,
capture_output=True,
check=True,
check=False,
)
for line in completed.stdout.splitlines():
path = root / line
if not path.is_file() or _is_skipped(path):
if completed.returncode == 0:
candidates = (root / line for line in completed.stdout.splitlines())
else:
candidates = (path for path in root.rglob("*") if path.is_file())
for path in candidates:
if not path.is_file() or _is_skipped(path, root):
continue
if path.suffix.lower() in TEXT_SUFFIXES:
yield path
def scan_text(path: Path, text: str) -> list[dict[str, object]]:
def scan_text(
path: Path,
text: str,
patterns: Iterable[tuple[str, re.Pattern[str]]] | None = None,
) -> list[dict[str, object]]:
findings: list[dict[str, object]] = []
try:
display_path = path.relative_to(ROOT).as_posix()
except ValueError:
display_path = path.as_posix()
for rule_id, pattern in DENY_PATTERNS:
for rule_id, pattern in (patterns if patterns is not None else deny_patterns()):
for match in pattern.finditer(text):
line = text.count("\n", 0, match.start()) + 1
findings.append(
@@ -105,13 +123,14 @@ def scan_text(path: Path, text: str) -> list[dict[str, object]]:
def build_report(root: Path = ROOT) -> dict[str, object]:
findings: list[dict[str, object]] = []
scanned = 0
patterns = deny_patterns(root)
for path in iter_release_files(root):
try:
text = path.read_text(encoding="utf-8")
except UnicodeDecodeError:
text = path.read_text(encoding="utf-8", errors="ignore")
scanned += 1
findings.extend(scan_text(path, text))
findings.extend(scan_text(path, text, patterns))
return {
"scope": "public_release_privacy_scan",
"scanned_files": scanned,
+117
View File
@@ -0,0 +1,117 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Validate structured real-case outcome replay manifests."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
from typing import Any
CASE_REQUIRED_FIELDS = {
"case_id",
"source",
"chart_signature",
"event_outcomes",
"similarity",
"replay",
}
SOURCE_REQUIRED_FIELDS = {"url", "source_grade", "license_or_quote_boundary"}
EVENT_REQUIRED_FIELDS = {"event_type", "event_date", "outcome"}
def _missing(mapping: dict[str, Any], required: set[str]) -> list[str]:
return sorted(name for name in required if name not in mapping)
def _case_errors(case: Any, index: int) -> list[dict[str, Any]]:
if not isinstance(case, dict):
return [{"case_index": index, "field": "case", "error": "not_object"}]
errors: list[dict[str, Any]] = []
for field in _missing(case, CASE_REQUIRED_FIELDS):
errors.append({"case_id": case.get("case_id"), "field": field, "error": "missing"})
source = case.get("source")
if isinstance(source, dict):
for field in _missing(source, SOURCE_REQUIRED_FIELDS):
errors.append({"case_id": case.get("case_id"), "field": f"source.{field}", "error": "missing"})
elif "source" in case:
errors.append({"case_id": case.get("case_id"), "field": "source", "error": "not_object"})
events = case.get("event_outcomes")
if isinstance(events, list):
if not events:
errors.append({"case_id": case.get("case_id"), "field": "event_outcomes", "error": "empty"})
for event_index, event in enumerate(events):
if not isinstance(event, dict):
errors.append({"case_id": case.get("case_id"), "field": f"event_outcomes[{event_index}]", "error": "not_object"})
continue
for field in _missing(event, EVENT_REQUIRED_FIELDS):
errors.append({"case_id": case.get("case_id"), "field": f"event_outcomes[{event_index}].{field}", "error": "missing"})
elif "event_outcomes" in case:
errors.append({"case_id": case.get("case_id"), "field": "event_outcomes", "error": "not_array"})
return errors
def validate_manifest(path: str | Path) -> dict[str, Any]:
manifest_path = Path(path)
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
cases = manifest.get("cases")
if not isinstance(cases, list):
return {
"status": "blocked",
"manifest_path": str(manifest_path),
"case_count": 0,
"replay_ready_count": 0,
"blocked_reason": "cases_not_array",
"errors": [{"field": "cases", "error": "not_array"}],
}
errors: list[dict[str, Any]] = []
replay_ready_count = 0
for index, case in enumerate(cases):
case_errors = _case_errors(case, index)
errors.extend(case_errors)
replay = case.get("replay") if isinstance(case, dict) else {}
if not case_errors and isinstance(replay, dict) and replay.get("outcome_replay_status") == "replayed":
replay_ready_count += 1
if errors:
status = "invalid"
blocked_reason = "case_contract_errors"
elif not cases:
status = "blocked"
blocked_reason = manifest.get("blocked_reason") or "no_structured_outcome_replay_cases_imported"
elif replay_ready_count == len(cases):
status = "pass"
blocked_reason = None
else:
status = "partial"
blocked_reason = "some_cases_not_replayed"
return {
"status": status,
"manifest_path": str(manifest_path),
"schema_version": manifest.get("schema_version"),
"case_schema": manifest.get("case_schema"),
"case_count": len(cases),
"replay_ready_count": replay_ready_count,
"blocked_reason": blocked_reason,
"errors": errors,
"runtime_boundary": manifest.get("runtime_boundary", ""),
}
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("manifest", nargs="?", default="references/real_case_calibration/replay_manifest.json")
args = parser.parse_args(argv)
print(json.dumps(validate_manifest(args.manifest), ensure_ascii=False, indent=2, sort_keys=True))
return 0
if __name__ == "__main__":
raise SystemExit(main())
+57 -4
View File
@@ -24,11 +24,14 @@ SKIP_NAMES = {".env", ".env.local"}
GENERATED_DOCS = {
"INSTALL.md": """# Jyotish Skill Install
Basic Git version: https://github.com/732642856/yinduzhanxing
1. Unzip this package into a local folder.
2. Run `python3 scripts/public_release_privacy_scan.py`.
3. Run `python3 scripts/user_invocation_acceptance_check.py`.
4. If the check passes, load this folder as a Codex skill/plugin or call `mcp_server.py`.
5. VedAstro cloud evidence is optional. Without `official_raw_response`, reports must say `official_blocked` or `local_fallback`.
4. Run `python3 scripts/skill_release_package.py --edition premium_cloud_drive`.
5. If the checks pass, load this folder as a Codex skill/plugin or call `mcp_server.py`.
6. VedAstro cloud evidence is optional. Without `official_raw_response`, reports must say `official_blocked` or `local_fallback`.
Do not add private birth data, API keys, or desktop oracle screenshots to this package.
""",
@@ -43,6 +46,11 @@ Do not add private birth data, API keys, or desktop oracle screenshots to this p
请使用 strict_workflow,并在输出中标明 VedAstro / PyJHora-JHora / jyotishganit / Real Case Calibration 的状态。
如果没有 VedAstro official_raw_response,请标记 official_blocked 或 local_fallback。
如果我提供西方占星导出,请作为 western_oracle_payload 进入统一主链,不要把单边西占信号说成双系统互证。
## Highest Quality Mode
请走高级版最高品质流程:direct_chart 或 rectification 入口 → evidence_packet → Technique Audit Table → VedAstro 三态 → 三引擎 parity replay 状态 → Real Case outcome replay 状态 → guided_topics。
## Birth-Time Rectification
@@ -50,6 +58,14 @@ Do not add private birth data, API keys, or desktop oracle screenshots to this p
""",
}
REQUIRED_CONTRACTS = [
"references/real_case_calibration/replay_manifest.json",
"references/oracle/three_engine_parity_replay_manifest.json",
"references/oracle/western_oracle_adapter_contract.md",
"scripts/user_invocation_acceptance_check.py",
"scripts/diagnose_external_engine_adapters.py",
]
def _git_files() -> list[str]:
completed = subprocess.run(["git", "ls-files", "-z"], cwd=ROOT, capture_output=True, check=True)
@@ -70,15 +86,49 @@ def _edition_files(edition: str) -> list[str]:
if edition not in manifest["editions"]:
raise ValueError(f"unknown edition: {edition}")
files = _git_files()
files = sorted(set(files) | {path for path in REQUIRED_CONTRACTS if (ROOT / path).is_file()})
if edition == "basic_git":
keep = ("SKILL.md", "README.md", "mcp_server.py", ".codex-plugin/", "scripts/", "tests/")
files = [path for path in files if path in keep or any(path.startswith(prefix) for prefix in keep if prefix.endswith("/"))]
return [path for path in files if _allowed(path)]
def _required_contracts() -> dict[str, bool]:
return {path: (ROOT / path).is_file() for path in REQUIRED_CONTRACTS}
def _package_acceptance(edition: str, privacy: dict[str, Any], files: list[str]) -> dict[str, Any]:
contracts = _required_contracts()
return {
"scope": "skill_release_package_acceptance",
"schema_version": 1,
"edition": edition,
"status": "pass" if privacy["status"] == "pass" and all(contracts.values()) else "blocked",
"privacy_scan_status": privacy["status"],
"file_count": len(files),
"required_contracts": contracts,
"acceptance_commands": release_manifest()["acceptance_commands"],
"boundary": (
"Package acceptance proves release hygiene and contracts only; it does not prove external oracle raw "
"closure or same-chart parity until replay manifests contain imported rows."
),
}
def _generated_docs(edition: str, privacy: dict[str, Any], files: list[str]) -> dict[str, str]:
manifest = release_manifest()
acceptance = _package_acceptance(edition, privacy, files)
docs = dict(GENERATED_DOCS)
docs["RELEASE_MANIFEST.json"] = json.dumps(manifest, ensure_ascii=False, indent=2, sort_keys=True) + "\n"
docs["PACKAGE_ACCEPTANCE.json"] = json.dumps(acceptance, ensure_ascii=False, indent=2, sort_keys=True) + "\n"
return docs
def build_package_plan(edition: str = "premium_cloud_drive") -> dict[str, Any]:
privacy = privacy_scan()
files = _edition_files(edition)
generated_docs = _generated_docs(edition, privacy, files)
acceptance = _package_acceptance(edition, privacy, files)
return {
"scope": "skill_release_package",
"schema_version": 1,
@@ -87,7 +137,9 @@ def build_package_plan(edition: str = "premium_cloud_drive") -> dict[str, Any]:
"privacy_scan_status": privacy["status"],
"file_count": len(files),
"files": files,
"generated_files": sorted(GENERATED_DOCS),
"generated_files": sorted(generated_docs),
"required_contracts": acceptance["required_contracts"],
"package_acceptance_status": acceptance["status"],
"boundary": "Dry-run plan only; use --write-zip to create a local zip, then upload manually if desired.",
}
@@ -100,7 +152,8 @@ def write_zip(edition: str, output: Path) -> dict[str, Any]:
with zipfile.ZipFile(output, "w", compression=zipfile.ZIP_DEFLATED) as archive:
for rel in plan["files"]:
archive.write(ROOT / rel, rel)
for rel, text in GENERATED_DOCS.items():
privacy = privacy_scan()
for rel, text in _generated_docs(edition, privacy, plan["files"]).items():
archive.writestr(rel, text)
return {**plan, "mode": "write_zip", "zip_path": str(output)}
@@ -0,0 +1,98 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Validate same-chart three-engine parity replay manifests."""
from __future__ import annotations
import argparse
import json
from pathlib import Path
from typing import Any
REQUIRED_ENGINES = {"VedAstro", "PyJHora_JHora", "jyotishganit"}
REQUIRED_ROW_FIELDS = {"section", "field", "local_value", "oracle_values", "status"}
VALID_ROW_STATUSES = {"match", "mismatch", "blocked", "not_comparable"}
def _row_errors(row: Any, index: int) -> list[dict[str, Any]]:
if not isinstance(row, dict):
return [{"row_index": index, "field": "row", "error": "not_object"}]
errors: list[dict[str, Any]] = []
for field in sorted(REQUIRED_ROW_FIELDS - set(row)):
errors.append({"row_index": index, "field": field, "error": "missing"})
if row.get("status") not in VALID_ROW_STATUSES:
errors.append({"row_index": index, "field": "status", "error": "invalid"})
if "oracle_values" in row and not isinstance(row.get("oracle_values"), dict):
errors.append({"row_index": index, "field": "oracle_values", "error": "not_object"})
return errors
def validate_manifest(path: str | Path) -> dict[str, Any]:
manifest_path = Path(path)
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
engines = manifest.get("engines") if isinstance(manifest.get("engines"), dict) else {}
rows = manifest.get("comparison_rows")
errors: list[dict[str, Any]] = []
missing_engines = sorted(REQUIRED_ENGINES - set(engines))
for engine in missing_engines:
errors.append({"field": f"engines.{engine}", "error": "missing"})
if not isinstance(rows, list):
rows = []
errors.append({"field": "comparison_rows", "error": "not_array"})
for index, row in enumerate(rows):
errors.extend(_row_errors(row, index))
counts = {"match": 0, "mismatch": 0, "blocked": 0, "not_comparable": 0}
for row in rows:
if isinstance(row, dict) and row.get("status") in counts:
counts[row["status"]] += 1
if errors:
status = "invalid"
blocked_reason = "parity_manifest_contract_errors"
elif not rows:
status = "blocked"
blocked_reason = manifest.get("blocked_reason") or "no_same_chart_oracle_rows_imported"
elif counts["mismatch"]:
status = "mismatch"
blocked_reason = None
elif counts["blocked"]:
status = "partial"
blocked_reason = "some_comparison_rows_blocked"
else:
status = "pass"
blocked_reason = None
return {
"status": status,
"tested": status in {"pass", "mismatch", "partial"},
"manifest_path": str(manifest_path),
"case_id": manifest.get("case_id"),
"birth_data_policy": manifest.get("birth_data_policy"),
"engine_count": len(engines),
"required_engines": sorted(REQUIRED_ENGINES),
"missing_engines": missing_engines,
"comparison_row_count": len(rows),
"match_count": counts["match"],
"mismatch_count": counts["mismatch"],
"blocked_row_count": counts["blocked"],
"not_comparable_count": counts["not_comparable"],
"blocked_reason": blocked_reason,
"errors": errors,
"runtime_boundary": manifest.get("runtime_boundary", ""),
}
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("manifest", nargs="?", default="references/oracle/three_engine_parity_replay_manifest.json")
args = parser.parse_args(argv)
print(json.dumps(validate_manifest(args.manifest), ensure_ascii=False, indent=2, sort_keys=True))
return 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -18,11 +18,21 @@ try:
except Exception: # pragma: no cover - import path varies in tests/CLI
from scripts.diagnose_jyotishganit_adapter import build_report as build_jyotishganit_adapter_report
try:
from cross_system_arbitrator import build_cross_system_arbitration
except Exception: # pragma: no cover - import path varies in tests/CLI
from scripts.cross_system_arbitrator import build_cross_system_arbitration
try:
from functional_benefics import derive_functional_benefic_malefic
except Exception: # pragma: no cover - import path varies in tests/CLI
from scripts.functional_benefics import derive_functional_benefic_malefic
try:
from real_case_replay_validator import validate_manifest as validate_real_case_replay_manifest
except Exception: # pragma: no cover - import path varies in tests/CLI
from scripts.real_case_replay_validator import validate_manifest as validate_real_case_replay_manifest
@dataclass(frozen=True)
class RouteDefinition:
@@ -426,12 +436,16 @@ class UnifiedConsultationOrchestrator:
),
}
missing = [name for name, section in sections.items() if section.get("status") == "missing"]
signals = chart_data.get("cross_system_signals")
if not isinstance(signals, list):
signals = modules.get("cross_system_signals") if isinstance(modules.get("cross_system_signals"), list) else []
return {
"status": "complete" if not missing else "partial",
"route": dict(route_packet),
"required_sections": list(self.EVIDENCE_PACKET_REQUIRED_SECTIONS),
"sections": sections,
"functional_benefic_malefic": functional_layer,
"signals": [item for item in signals if isinstance(item, dict)],
"missing_sections": missing,
}
@@ -463,6 +477,8 @@ class UnifiedConsultationOrchestrator:
"event_trigger_keywords": ["UL", "Darapada", "7th lord", "DK"],
},
}
replay_manifest_path = Path(__file__).resolve().parents[1] / "references/real_case_calibration/replay_manifest.json"
replay_manifest = validate_real_case_replay_manifest(replay_manifest_path)
candidate_refs = case_index_by_domain.get(route, [])
packet = machine_evidence_packet if isinstance(machine_evidence_packet, dict) else {}
sections = packet.get("sections") if isinstance(packet.get("sections"), dict) else {}
@@ -518,6 +534,8 @@ class UnifiedConsultationOrchestrator:
"route": route,
"source_roots": ["references/real_case_studies", "docs/benchmark"],
"case_index_by_domain": case_index_by_domain,
"required_replay_schema": "references/real_case_calibration/catalog.schema.json",
"outcome_replay_manifest": replay_manifest,
"candidate_refs": list(candidate_refs),
"scored_candidates": scored_candidates,
"reference_grade": scored_candidates[0]["reference_grade"] if scored_candidates else "ungraded_until_similarity_scored",
@@ -539,6 +557,7 @@ class UnifiedConsultationOrchestrator:
interpretation_source_runtime_coverage: dict[str, Any] | None = None,
machine_evidence_packet: dict[str, Any] | None = None,
real_case_calibration: dict[str, Any] | None = None,
western_evidence_packet: dict[str, Any] | None = None,
blind: bool = False,
) -> dict[str, Any]:
official = vedastro_official if isinstance(vedastro_official, dict) else {}
@@ -575,6 +594,13 @@ class UnifiedConsultationOrchestrator:
blocked_items.append("real_case_calibration_not_yet_materialized")
elif case_status != "complete":
blocked_items.append("real_case_calibration_partial")
cross_system_arbitration = build_cross_system_arbitration(
route_packet=route_packet,
jyotish_evidence=packet,
western_evidence=western_evidence_packet,
)
if cross_system_arbitration["status"] != "used":
blocked_items.append("cross_system_arbitration_not_complete")
technique_audit_table = [
{
"technique": "VedAstro Cloud State",
@@ -606,6 +632,7 @@ class UnifiedConsultationOrchestrator:
else "claims_capped_until_pyjhora_jhora_jyotishganit_are_invoked_for_this_run"
),
},
*cross_system_arbitration["technique_audit_rows"],
{
"technique": "Evidence Packet",
"status": packet_status,
@@ -653,6 +680,7 @@ class UnifiedConsultationOrchestrator:
"vedastro_cloud_state": vedastro_state,
"vedastro_runtime_truth": dict(runtime_truth),
"external_engine_cross_validation": external_cross_validation,
"cross_system_arbitration": cross_system_arbitration,
"source_priority": {
"mode": self.SOURCE_PRIORITY["mode"],
"priority": list(self.SOURCE_PRIORITY["priority"]),
@@ -691,7 +719,10 @@ class UnifiedConsultationOrchestrator:
"technique_audit_table": technique_audit_table,
"required_rows": [
"VedAstro Cloud State",
"VedAstro Raw Archive Manifest",
"External Engine Cross-Validation",
"Western Cross-Validation",
"Cross-System Arbitration",
"Evidence Packet",
"Blind Technical Mode",
"MEVG / Global Web Evidence",
+3 -2
View File
@@ -158,7 +158,8 @@ def main() -> int:
if cursor in (None, [], ""):
errors.append(f"missing_entrypoint_{'_'.join(path)}")
if adapter_report.get("status") not in {"pass", "partial"}:
usable_adapter_statuses = {"pass", "partial", "complete"}
if adapter_report.get("status") not in usable_adapter_statuses:
errors.append("external_adapter_status_unusable")
result = {
@@ -168,7 +169,7 @@ def main() -> int:
"checks": {
"user_invocation_tests": pytest_check["returncode"] == 0,
"guided_topics_entrypoint": entrypoint["returncode"] == 0 and not any(e.startswith("missing_entrypoint_") for e in errors),
"external_adapter_diagnostics": adapter_report.get("status") in {"pass", "partial"},
"external_adapter_diagnostics": adapter_report.get("status") in usable_adapter_statuses,
},
"entrypoint_runtime_mode": _runtime_summary(entrypoint_report),
"entrypoint_strict_workflow": _strict_summary(entrypoint_report),
+71
View File
@@ -0,0 +1,71 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Western astrology evidence packet contract."""
from __future__ import annotations
from typing import Any
REQUIRED_SECTIONS = [
"natal",
"timing_techniques",
"signals",
]
def _section(value: Any, source_path: str) -> dict[str, Any]:
present = bool(value)
return {
"status": "used" if present else "missing",
"source_path": source_path,
}
def _normalize_signals(signals: list[dict[str, Any]] | None) -> list[dict[str, Any]]:
normalized: list[dict[str, Any]] = []
for item in signals or []:
if not isinstance(item, dict) or not item.get("theme") or not item.get("claim"):
continue
normalized.append(
{
"theme": str(item.get("theme")),
"claim": str(item.get("claim")),
"timing": str(item.get("timing") or "unspecified"),
"source": str(item.get("source") or "western_evidence_packet"),
}
)
return normalized
def build_western_evidence_packet(
*,
route_packet: dict[str, Any],
natal: dict[str, Any] | None,
timing_techniques: dict[str, Any] | None,
signals: list[dict[str, Any]] | None,
) -> dict[str, Any]:
"""Materialize a small auditable Western evidence packet."""
normalized_signals = _normalize_signals(signals)
sections = {
"natal": _section(natal, "western.natal"),
"timing_techniques": _section(timing_techniques, "western.timing_techniques"),
"signals": _section(normalized_signals, "western.signals"),
}
missing = [name for name in REQUIRED_SECTIONS if sections[name]["status"] == "missing"]
return {
"system": "western_astrology",
"status": "complete" if not missing else "partial",
"route": dict(route_packet),
"required_sections": list(REQUIRED_SECTIONS),
"sections": sections,
"natal": natal or {},
"timing_techniques": timing_techniques or {},
"signals": normalized_signals,
"missing_sections": missing,
"license_boundary": (
"This packet stores derived evidence only. Kerykeion, pyswisseph, Flatlib, Immanuel, or desktop "
"software outputs must remain external oracle inputs unless their licenses permit bundling."
),
}
+134
View File
@@ -0,0 +1,134 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Normalize external Western astrology oracle JSON into a western evidence packet."""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
from typing import Any
try:
from western_evidence_packet import build_western_evidence_packet
except Exception: # pragma: no cover - import path varies in tests/CLI
from scripts.western_evidence_packet import build_western_evidence_packet
_ASPECT_ALIASES = {
"conj": "conjunction",
"conjunction": "conjunction",
"trine": "trine",
"sextile": "sextile",
"square": "square",
"opposition": "opposition",
"opp": "opposition",
}
def _norm(value: Any) -> str:
return str(value or "").strip().lower().replace("-", "_").replace(" ", "_")
def _aspect_label(item: dict[str, Any]) -> tuple[str, str, str]:
planet = _norm(item.get("planet") or item.get("transit_planet"))
aspect = _ASPECT_ALIASES.get(_norm(item.get("aspect")), _norm(item.get("aspect")))
target = _norm(item.get("target") or item.get("point") or item.get("natal_point"))
return planet, aspect, target
def _timing(item: dict[str, Any]) -> str:
return str(item.get("timing") or item.get("date") or item.get("window") or "unspecified")
def _signals_from_aspects(aspects: list[dict[str, Any]]) -> list[dict[str, Any]]:
signals: list[dict[str, Any]] = []
for item in aspects:
if not isinstance(item, dict):
continue
planet, aspect, target = _aspect_label(item)
timing = _timing(item)
source = str(item.get("source") or f"{planet} {aspect} {target}").replace("_", " ")
if planet == "uranus" and aspect == "conjunction" and target in {"mc", "midheaven"}:
signals.append(
{
"theme": "career_relocation",
"claim": "career_triggered_relocation",
"timing": timing,
"source": source,
}
)
if planet == "jupiter" and aspect in {"trine", "sextile"} and target in {"mercury", "venus", "mc", "midheaven"}:
signals.append(
{
"theme": "career",
"claim": "client_cooperation_opportunity",
"timing": timing,
"source": source,
}
)
if planet == "saturn" and aspect == "conjunction" and target in {"sun", "mercury", "venus"}:
signals.append(
{
"theme": "career",
"claim": "career_responsibility_test",
"timing": timing,
"source": source,
}
)
return signals
def build_packet_from_oracle_payload(
payload: dict[str, Any],
*,
route_packet: dict[str, Any],
) -> dict[str, Any]:
"""Build a standard Western packet from an external-oracle JSON payload."""
explicit_signals = payload.get("signals") if isinstance(payload.get("signals"), list) else []
aspects = payload.get("aspects") if isinstance(payload.get("aspects"), list) else []
signals = list(explicit_signals) or _signals_from_aspects(aspects)
timing_techniques = payload.get("timing_techniques")
if not isinstance(timing_techniques, dict):
timing_techniques = {}
if aspects and "aspects" not in timing_techniques:
timing_techniques = {**timing_techniques, "aspects": aspects}
packet = build_western_evidence_packet(
route_packet=route_packet,
natal=payload.get("natal") if isinstance(payload.get("natal"), dict) else {},
timing_techniques=timing_techniques,
signals=signals,
)
packet["source_engine"] = str(payload.get("source_engine") or payload.get("engine") or "external_western_oracle_json")
packet["adapter_boundary"] = {
"bundles_external_code": False,
"accepted_input": "external_json_export",
"role": "western_cross_validation_evidence",
}
return packet
def _parse_args(argv: list[str]) -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--input", required=True, help="Path to external Western oracle JSON export.")
parser.add_argument("--theme", default="general", help="Primary theme, e.g. career/marriage/wealth.")
parser.add_argument("--question-type", default=None, help="Question type override.")
return parser.parse_args(argv)
def main(argv: list[str] | None = None) -> int:
args = _parse_args(list(argv or sys.argv[1:]))
payload = json.loads(Path(args.input).read_text(encoding="utf-8"))
route_packet = {
"question_type": args.question_type or args.theme,
"primary_theme": args.theme,
}
packet = build_packet_from_oracle_payload(payload, route_packet=route_packet)
print(json.dumps(packet, ensure_ascii=False, indent=2, sort_keys=True))
return 0
if __name__ == "__main__": # pragma: no cover
raise SystemExit(main())
+60
View File
@@ -2327,6 +2327,66 @@ def test_consultation_workflow_uses_unified_orchestrator_contract(monkeypatch) -
assert result['chart']['special_lagnas']['precision'] == 'sunrise_correct'
def test_consultation_workflow_accepts_western_oracle_payload(monkeypatch) -> None:
handler = _handler()
fake_chart = {
'success': True,
'birth_info': {'date': '1955-02-24', 'time': '19:15', 'tz': 8},
'ascendant': {'lon': 92.0, 'sign': 'Cancer'},
'planets': _sample_planets(),
'chart': {
'ascendant': {'lon': 92.0, 'sign': 'Cancer'},
'planets': _sample_planets(),
},
'modules': {},
'cross_system_signals': [
{
'theme': 'career_relocation',
'claim': 'career_triggered_relocation',
'timing': '2026-07',
'source': 'jyotish_runtime_signal',
}
],
}
monkeypatch.setattr(handler, '_compute_chart', lambda body: fake_chart)
monkeypatch.setattr(handler, '_compute_rectification_gate', lambda body: {'endpoint': 'rectification_gate'})
monkeypatch.setattr(handler, '_compute_thematic_report', lambda body: {'endpoint': 'thematic_report'})
result = handler._compute_consultation_workflow({
'entry_mode': 'direct_chart',
'question': 'career relocation timing',
'year': 1955,
'month': 2,
'day': 24,
'hour': 19,
'minute': 15,
'lat': 37.7749,
'lon': -122.4194,
'tz': 8,
'theme': ['career'],
'western_oracle_payload': {
'source_engine': 'kerykeion_external_json',
'natal': {'ascendant': 'Virgo', 'mc': 'Gemini'},
'timing_techniques': {'transits': [{'date': '2026-07'}]},
'aspects': [
{
'date': '2026-07',
'planet': 'Uranus',
'aspect': 'conjunction',
'target': 'MC',
}
],
},
})
assert result['western_evidence_packet']['source_engine'] == 'kerykeion_external_json'
assert result['runtime_evidence_log']['cross_system_arbitration']['status'] == 'used'
assert result['runtime_evidence_log']['cross_system_arbitration']['shared_signals'][0]['claim'] == 'career_triggered_relocation'
audit = result['runtime_evidence_log']['quality_gate']['technique_audit_table']
assert any(row['technique'] == 'Western Cross-Validation' and row['used'] is True for row in audit)
def test_consultation_workflow_reuses_chart_data_for_thematic_report_without_recursive_full_reading(monkeypatch) -> None:
handler = _handler()
fake_chart = {
+72
View File
@@ -0,0 +1,72 @@
#!/usr/bin/env python3
"""Cross-system Jyotish/Western arbitration contract tests."""
from __future__ import annotations
from scripts.cross_system_arbitrator import build_cross_system_arbitration
def test_cross_system_arbitrator_promotes_shared_timed_signal() -> None:
packet = build_cross_system_arbitration(
route_packet={"question_type": "career", "primary_theme": "career"},
jyotish_evidence={
"status": "complete",
"signals": [
{
"theme": "career_relocation",
"claim": "career_triggered_relocation",
"timing": "2026-08-24..2026-09-28",
"source": "Saturn/Ketu + Rahu 4H/10H axis",
}
],
},
western_evidence={
"status": "complete",
"signals": [
{
"theme": "career_relocation",
"claim": "career_triggered_relocation",
"timing": "2026-08-24..2026-09-28",
"source": "Uranus conjunct MC opposite IC",
}
],
},
)
assert packet["status"] == "used"
assert packet["primary_theme"] == "career"
assert packet["shared_signals"][0]["theme"] == "career_relocation"
assert packet["shared_signals"][0]["claim"] == "career_triggered_relocation"
assert packet["shared_signals"][0]["timing"] == "2026-08-24..2026-09-28"
assert packet["shared_signals"][0]["confidence_effect"] == "raises_confidence"
assert packet["conflicts"] == []
def test_cross_system_arbitrator_blocks_without_western_packet() -> None:
packet = build_cross_system_arbitration(
route_packet={"question_type": "career", "primary_theme": "career"},
jyotish_evidence={"status": "partial", "signals": []},
western_evidence=None,
)
assert packet["status"] == "blocked"
assert packet["western_cross_validation"]["status"] == "blocked"
assert "western_evidence_packet_missing" in packet["blocked_items"]
def test_cross_system_arbitrator_marks_conflicting_claims() -> None:
packet = build_cross_system_arbitration(
route_packet={"question_type": "career", "primary_theme": "career"},
jyotish_evidence={
"status": "complete",
"signals": [{"theme": "career", "claim": "stable_internal_role", "timing": "2026-07"}],
},
western_evidence={
"status": "complete",
"signals": [{"theme": "career", "claim": "external_project_pivot", "timing": "2026-07"}],
},
)
assert packet["status"] == "conflict"
assert packet["conflicts"][0]["theme"] == "career"
assert packet["conflicts"][0]["confidence_effect"] == "lowers_confidence"
@@ -37,4 +37,6 @@ def test_external_engine_adapter_diagnostics_aggregates_three_engines() -> None:
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["replay_manifest"]["tested"] is False
assert contract["replay_manifest"]["blocked_reason"] == "no_same_chart_oracle_rows_imported"
assert report["status"] in {"complete", "partial"}
+68
View File
@@ -186,6 +186,74 @@ def test_mcp_strict_workflow_returns_runtime_evidence_log(monkeypatch) -> None:
assert result["runtime_evidence_log"]["quality_gate"]["technique_audit_table"][1]["technique"] == "VedAstro Raw Archive Manifest"
def test_mcp_strict_workflow_preserves_western_evidence_packet(monkeypatch) -> None:
seen = {}
def fake_execute(**kwargs):
seen.update(kwargs)
return {
"chart": {
"modules": {},
"cross_system_signals": [
{
"theme": "career_relocation",
"claim": "career_triggered_relocation",
"timing": "2026-07",
"source": "jyotish_runtime_signal",
}
],
"ai_prompt_pack": {
"evidence_snapshot": {
"vedastro_official_snapshot": {
"status": "ok",
"official_primary_evidence": {"chart_core": {"status": "ok"}},
}
}
},
},
"routing": {"question_type": "career", "primary_theme": "career"},
"entry_mode": "direct_chart",
"runtime_planner": {"executed_steps": ["compute_chart"], "skipped_steps": []},
"western_evidence_packet": kwargs["western_evidence_packet"],
}
western_packet = {
"system": "western_astrology",
"status": "complete",
"signals": [
{
"theme": "career_relocation",
"claim": "career_triggered_relocation",
"timing": "2026-07",
"source": "western_oracle_signal",
}
],
}
monkeypatch.setattr(mcp_server, "_execute_mcp_consultation_workflow", fake_execute)
monkeypatch.setattr(mcp_server, "_maybe_attach_vedastro_evidence", lambda route, chart, **kwargs: chart)
monkeypatch.setattr(mcp_server, "_collect_strict_evidence", lambda route, chart: {"question_type": route})
result = mcp_server.strict_workflow(
question="career relocation timing",
year=1955,
month=2,
day=24,
hour=19,
minute=15,
lat=37.7749,
lon=-122.4194,
tz=8,
age=33,
transit_date="2026-07-05",
western_evidence_packet=western_packet,
)
assert seen["western_evidence_packet"] == western_packet
assert result["runtime_evidence_log"]["cross_system_arbitration"]["status"] == "used"
assert result["runtime_evidence_log"]["cross_system_arbitration"]["shared_signals"][0]["claim"] == "career_triggered_relocation"
def test_career_blocks_label_when_d10_is_missing_but_preserves_jaimini_context() -> None:
result = _base_career_result()
del result["modules"]["varga_full"]["D10_Dasamsa"]
+16 -6
View File
@@ -2,20 +2,30 @@ from __future__ import annotations
from pathlib import Path
from scripts.public_release_privacy_scan import build_report, scan_text
from scripts.public_release_privacy_scan import build_report, deny_patterns, iter_release_files, scan_text
def test_public_release_privacy_scan_finds_private_birth_tuple() -> None:
def test_public_release_privacy_scan_finds_private_configured_pattern(monkeypatch) -> None:
monkeypatch.setenv("PUBLIC_RELEASE_DENY_PATTERNS", "SECRET_BIRTH_TOKEN")
findings = scan_text(
Path("sample.py"),
'{"year": REDACTED_YEAR, "month": 4, "day": 17, "hour": 14, "minute": 49}',
"safe text SECRET_BIRTH_TOKEN",
deny_patterns(),
)
assert {item["rule_id"] for item in findings} >= {"private_birth_dict_tuple"}
assert {item["rule_id"] for item in findings} == {"private_env_pattern_01"}
def test_public_release_privacy_scan_has_no_release_findings() -> None:
report = build_report()
assert report["status"] == "pass", report["findings"][:20]
assert report["finding_count"] == 0
def test_public_release_privacy_scan_supports_unpacked_zip_without_git(tmp_path: Path) -> None:
(tmp_path / "INSTALL.md").write_text("safe install text\n", encoding="utf-8")
(tmp_path / "scratch").mkdir()
(tmp_path / "scratch" / "ignored.md").write_text("SECRET_BIRTH_TOKEN\n", encoding="utf-8")
assert [path.name for path in iter_release_files(tmp_path)] == ["INSTALL.md"]
report = build_report(tmp_path)
assert report["status"] == "pass", report["findings"]
+73
View File
@@ -0,0 +1,73 @@
from __future__ import annotations
import json
from pathlib import Path
from scripts.real_case_replay_validator import validate_manifest
from scripts.unified_consultation_orchestrator import UnifiedConsultationOrchestrator
ROOT = Path(__file__).resolve().parents[1]
def test_real_case_replay_manifest_blocks_when_no_cases_are_imported() -> None:
result = validate_manifest(ROOT / "references/real_case_calibration/replay_manifest.json")
assert result["status"] == "blocked"
assert result["case_count"] == 0
assert result["replay_ready_count"] == 0
assert result["blocked_reason"] == "no_structured_outcome_replay_cases_imported"
def test_real_case_replay_validator_accepts_one_structured_case(tmp_path: Path) -> None:
manifest = {
"schema_version": "1.0",
"status": "ready",
"case_schema": "references/real_case_calibration/catalog.schema.json",
"cases": [
{
"case_id": "public_case_001",
"source": {
"url": "https://example.com/public-case",
"source_grade": "verified_secondary",
"license_or_quote_boundary": "summary_only",
},
"chart_signature": {"lagna": "Leo", "notable_yogas": ["career_yoga"]},
"event_outcomes": [
{
"event_type": "career_breakthrough",
"event_date": "2000-01",
"outcome": "public_success",
}
],
"similarity": {
"score": 0.72,
"matching_factors": ["D10", "dasha"],
"dissimilar_factors": [],
},
"replay": {
"outcome_replay_status": "replayed",
"do_not_use_for_prediction": False,
},
}
],
}
path = tmp_path / "replay_manifest.json"
path.write_text(json.dumps(manifest), encoding="utf-8")
result = validate_manifest(path)
assert result["status"] == "pass"
assert result["case_count"] == 1
assert result["replay_ready_count"] == 1
def test_orchestrator_exposes_real_case_replay_manifest_status() -> None:
orchestrator = UnifiedConsultationOrchestrator()
route = {"question_type": "career", "primary_theme": "career"}
packet = orchestrator.real_case_calibration_catalog(route_packet=route, machine_evidence_packet={})
replay = packet["outcome_replay_manifest"]
assert replay["status"] == "blocked"
assert replay["case_count"] == 0
assert packet["required_replay_schema"] == "references/real_case_calibration/catalog.schema.json"
+70
View File
@@ -0,0 +1,70 @@
from __future__ import annotations
import json
import subprocess
import sys
import zipfile
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def test_premium_skill_zip_runs_from_clean_directory(tmp_path: Path) -> None:
zip_path = tmp_path / "jyotish-premium.zip"
release = subprocess.run(
[
sys.executable,
"scripts/skill_release_package.py",
"--edition",
"premium_cloud_drive",
"--write-zip",
str(zip_path),
],
cwd=ROOT,
text=True,
capture_output=True,
timeout=120,
check=False,
)
assert release.returncode == 0, release.stderr or release.stdout
extract_dir = tmp_path / "clean"
with zipfile.ZipFile(zip_path) as archive:
archive.extractall(extract_dir)
required = [
"INSTALL.md",
"USER_PROMPTS.md",
"PACKAGE_ACCEPTANCE.json",
"references/real_case_calibration/replay_manifest.json",
"references/oracle/three_engine_parity_replay_manifest.json",
"references/oracle/western_oracle_adapter_contract.md",
]
assert [path for path in required if not (extract_dir / path).exists()] == []
acceptance = json.loads((extract_dir / "PACKAGE_ACCEPTANCE.json").read_text(encoding="utf-8"))
assert acceptance["status"] == "pass"
privacy = subprocess.run(
[sys.executable, "scripts/public_release_privacy_scan.py"],
cwd=extract_dir,
text=True,
capture_output=True,
timeout=120,
check=False,
)
assert privacy.returncode == 0, privacy.stderr or privacy.stdout
user_acceptance = subprocess.run(
[sys.executable, "scripts/user_invocation_acceptance_check.py"],
cwd=extract_dir,
text=True,
capture_output=True,
timeout=240,
check=False,
)
assert user_acceptance.returncode == 0, user_acceptance.stderr or user_acceptance.stdout
report = json.loads(user_acceptance.stdout)
assert report["status"] == "pass"
assert report["checks"]["guided_topics_entrypoint"] is True
+18
View File
@@ -1,5 +1,6 @@
from __future__ import annotations
import json
import zipfile
from scripts.skill_release_package import build_package_plan, write_zip
@@ -17,6 +18,13 @@ def test_skill_release_package_dry_run_uses_safe_tracked_files() -> None:
assert ".env.local" not in plan["files"]
assert not any(path.startswith("scratch/") for path in plan["files"])
assert not any("private" in path.lower() for path in plan["files"])
assert "RELEASE_MANIFEST.json" in plan["generated_files"]
assert "PACKAGE_ACCEPTANCE.json" in plan["generated_files"]
assert plan["required_contracts"]["references/real_case_calibration/replay_manifest.json"] is True
assert plan["required_contracts"]["references/oracle/three_engine_parity_replay_manifest.json"] is True
assert "references/real_case_calibration/replay_manifest.json" in plan["files"]
assert "references/oracle/three_engine_parity_replay_manifest.json" in plan["files"]
assert "references/oracle/western_oracle_adapter_contract.md" in plan["files"]
def test_skill_release_package_can_write_zip(tmp_path) -> None:
@@ -31,10 +39,20 @@ def test_skill_release_package_can_write_zip(tmp_path) -> None:
assert "scripts/skill_release_manifest.py" in names
assert "INSTALL.md" in names
assert "USER_PROMPTS.md" in names
assert "RELEASE_MANIFEST.json" in names
assert "PACKAGE_ACCEPTANCE.json" in names
assert "references/real_case_calibration/replay_manifest.json" in names
assert "references/oracle/three_engine_parity_replay_manifest.json" in names
assert "references/oracle/western_oracle_adapter_contract.md" in names
assert ".env.local" not in names
with zipfile.ZipFile(target) as archive:
install = archive.read("INSTALL.md").decode("utf-8")
prompts = archive.read("USER_PROMPTS.md").decode("utf-8")
acceptance = json.loads(archive.read("PACKAGE_ACCEPTANCE.json").decode("utf-8"))
assert "python3 scripts/user_invocation_acceptance_check.py" in install
assert "https://github.com/732642856/yinduzhanxing" in install
assert "guided_topics" in prompts
assert "official_blocked" in prompts
assert "western_oracle_payload" in prompts
assert acceptance["status"] in {"pass", "blocked"}
assert acceptance["required_contracts"]["references/oracle/three_engine_parity_replay_manifest.json"] is True
@@ -0,0 +1,48 @@
from __future__ import annotations
import json
from pathlib import Path
from scripts.three_engine_parity_replay_validator import validate_manifest
ROOT = Path(__file__).resolve().parents[1]
def test_three_engine_parity_manifest_blocks_without_oracle_rows() -> None:
result = validate_manifest(ROOT / "references/oracle/three_engine_parity_replay_manifest.json")
assert result["status"] == "blocked"
assert result["comparison_row_count"] == 0
assert result["tested"] is False
assert result["blocked_reason"] == "no_same_chart_oracle_rows_imported"
def test_three_engine_parity_validator_accepts_one_same_chart_row(tmp_path: Path) -> None:
manifest = {
"case_id": "public_same_chart_001",
"birth_data_policy": "public_case_only",
"status": "tested",
"engines": {
"VedAstro": {"status": "official_verified", "official_raw_response_path": "references/oracle/artifacts/vedastro.json"},
"PyJHora_JHora": {"status": "tested", "raw_output_path": "references/oracle/artifacts/pyjhora.txt"},
"jyotishganit": {"status": "tested", "raw_output_path": "references/oracle/artifacts/jyotishganit.json"},
},
"comparison_rows": [
{
"section": "D1",
"field": "Sun.longitude",
"local_value": 27.1,
"oracle_values": {"VedAstro": 27.1, "PyJHora_JHora": 27.1, "jyotishganit": 27.1},
"status": "match",
}
],
}
path = tmp_path / "three_engine_parity_replay_manifest.json"
path.write_text(json.dumps(manifest), encoding="utf-8")
result = validate_manifest(path)
assert result["status"] == "pass"
assert result["tested"] is True
assert result["comparison_row_count"] == 1
assert result["match_count"] == 1
@@ -3,6 +3,7 @@
from __future__ import annotations
from scripts.western_evidence_packet import build_western_evidence_packet
from scripts.unified_consultation_orchestrator import UnifiedConsultationOrchestrator
@@ -193,6 +194,8 @@ def test_runtime_evidence_log_exposes_blind_packet_case_and_quality_gate_contrac
"VedAstro Cloud State",
"VedAstro Raw Archive Manifest",
"External Engine Cross-Validation",
"Western Cross-Validation",
"Cross-System Arbitration",
"Evidence Packet",
"Blind Technical Mode",
"MEVG / Global Web Evidence",
@@ -212,8 +215,54 @@ def test_runtime_evidence_log_exposes_blind_packet_case_and_quality_gate_contrac
assert engines["jyotishganit"]["adapter_status"] == "available"
assert engines["jyotishganit"]["license"] == "MIT"
assert log["external_engine_cross_validation"]["status"] == "partial"
assert log["cross_system_arbitration"]["status"] == "blocked"
assert "western_evidence_packet_missing" in log["cross_system_arbitration"]["blocked_items"]
assert log["quality_gate"]["blocked_items"]
def test_runtime_evidence_log_uses_cross_system_shared_signal_when_packets_align() -> None:
orchestrator = UnifiedConsultationOrchestrator()
western_packet = build_western_evidence_packet(
route_packet={"question_type": "career", "primary_theme": "career"},
natal={"ascendant": "Virgo", "mc": "Gemini"},
timing_techniques={"transits": [{"aspect": "Uranus conjunct MC"}]},
signals=[
{
"theme": "career_relocation",
"claim": "career_triggered_relocation",
"timing": "2026-08-24..2026-09-28",
"source": "Uranus conjunct MC opposite IC",
}
],
)
log = orchestrator.runtime_evidence_log(
surface="api_web",
entry_mode="direct_chart",
route_packet={"question_type": "career", "primary_theme": "career"},
executed_steps=["compute_chart"],
skipped_steps=[],
machine_evidence_packet={
"status": "complete",
"sections": {"vedastro_official_raw_archive_manifest": {"status": "used"}},
"functional_benefic_malefic": {"status": "used"},
"signals": [
{
"theme": "career_relocation",
"claim": "career_triggered_relocation",
"timing": "2026-08-24..2026-09-28",
"source": "Saturn/Ketu + Rahu 4H/10H axis",
}
],
},
western_evidence_packet=western_packet,
)
assert log["cross_system_arbitration"]["status"] == "used"
assert log["cross_system_arbitration"]["shared_signals"][0]["claim"] == "career_triggered_relocation"
audit = {row["technique"]: row for row in log["quality_gate"]["technique_audit_table"]}
assert audit["Western Cross-Validation"]["used"] is True
assert audit["Cross-System Arbitration"]["used"] is True
packet = orchestrator.machine_evidence_packet(
chart={"chart": {"planets": {"Sun": {}}, "ascendant": {"sign": "Leo"}}},
route_packet={"question_type": "career", "primary_theme": "career"},
@@ -149,4 +149,4 @@ def test_one_command_user_invocation_acceptance_check() -> None:
assert report["checks"]["user_invocation_tests"] is True
assert report["checks"]["guided_topics_entrypoint"] is True
assert report["checks"]["external_adapter_diagnostics"] is True
assert report["external_adapter_status"] in {"pass", "partial"}
assert report["external_adapter_status"] in {"pass", "partial", "complete"}
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env python3
"""Western evidence packet contract tests."""
from __future__ import annotations
from scripts.western_evidence_packet import build_western_evidence_packet
def test_western_evidence_packet_materializes_auditable_sections() -> None:
packet = build_western_evidence_packet(
route_packet={"question_type": "career", "primary_theme": "career"},
natal={"ascendant": "Virgo", "mc": "Gemini"},
timing_techniques={
"transits": [{"aspect": "Uranus conjunct MC"}],
"solar_return": {"annual_focus": "career"},
},
signals=[
{
"theme": "career_relocation",
"claim": "career_triggered_relocation",
"timing": "2026-08-24..2026-09-28",
"source": "Uranus conjunct MC opposite IC",
}
],
)
assert packet["system"] == "western_astrology"
assert packet["status"] == "complete"
assert packet["sections"]["natal"]["status"] == "used"
assert packet["sections"]["timing_techniques"]["status"] == "used"
assert packet["sections"]["signals"]["status"] == "used"
assert packet["signals"][0]["claim"] == "career_triggered_relocation"
def test_western_evidence_packet_marks_missing_timing_as_partial() -> None:
packet = build_western_evidence_packet(
route_packet={"question_type": "career", "primary_theme": "career"},
natal={"ascendant": "Virgo"},
timing_techniques=None,
signals=[],
)
assert packet["status"] == "partial"
assert "timing_techniques" in packet["missing_sections"]
assert "signals" in packet["missing_sections"]
+120
View File
@@ -0,0 +1,120 @@
#!/usr/bin/env python3
"""Western external-oracle adapter tests."""
from __future__ import annotations
import json
import subprocess
import sys
from pathlib import Path
from scripts.western_oracle_adapter import build_packet_from_oracle_payload
ROOT = Path(__file__).resolve().parents[1]
def test_western_oracle_adapter_maps_external_aspects_to_standard_signals() -> None:
packet = build_packet_from_oracle_payload(
{
"source_engine": "kerykeion_external_json",
"natal": {"ascendant": "Virgo", "mc": "Gemini"},
"timing_techniques": {"solar_return": {"annual_focus": "career"}},
"aspects": [
{
"date": "2026-07-07",
"planet": "Uranus",
"aspect": "conjunction",
"target": "MC",
"orb": 0.2,
},
{
"date": "2026-07-20",
"planet": "Jupiter",
"aspect": "trine",
"target": "Venus",
"orb": 0.4,
},
{
"date": "2027-07-14",
"planet": "Saturn",
"aspect": "conjunction",
"target": "Sun",
"orb": 0.1,
},
],
},
route_packet={"question_type": "career", "primary_theme": "career"},
)
assert packet["status"] == "complete"
assert packet["source_engine"] == "kerykeion_external_json"
claims = {signal["claim"] for signal in packet["signals"]}
assert "career_triggered_relocation" in claims
assert "client_cooperation_opportunity" in claims
assert "career_responsibility_test" in claims
assert packet["adapter_boundary"]["bundles_external_code"] is False
def test_western_oracle_adapter_preserves_explicit_signals() -> None:
packet = build_packet_from_oracle_payload(
{
"source_engine": "manual_astro_com_export",
"natal": {"ascendant": "Virgo"},
"timing_techniques": {"transits": []},
"signals": [
{
"theme": "career",
"claim": "external_project_pivot",
"timing": "2026-07",
"source": "manual review",
}
],
},
route_packet={"question_type": "career", "primary_theme": "career"},
)
assert packet["signals"] == [
{
"theme": "career",
"claim": "external_project_pivot",
"timing": "2026-07",
"source": "manual review",
}
]
def test_western_oracle_adapter_cli_reads_json_file(tmp_path: Path) -> None:
input_path = tmp_path / "western_oracle.json"
input_path.write_text(
json.dumps(
{
"source_engine": "gongshenxing_export",
"natal": {"ascendant": "Virgo", "mc": "Gemini"},
"aspects": [{"date": "2026-07-07", "planet": "Uranus", "aspect": "conj", "target": "MC"}],
}
),
encoding="utf-8",
)
completed = subprocess.run(
[
sys.executable,
"scripts/western_oracle_adapter.py",
"--input",
str(input_path),
"--theme",
"career",
"--question-type",
"career",
],
cwd=ROOT,
text=True,
capture_output=True,
timeout=30,
check=False,
)
assert completed.returncode == 0, completed.stderr
packet = json.loads(completed.stdout)
assert packet["source_engine"] == "gongshenxing_export"
assert packet["signals"][0]["claim"] == "career_triggered_relocation"