Files
Jyotisha/tests/test_vedastro_external_technique_evidence.py
T
2026-07-08 18:34:13 +08:00

487 lines
18 KiB
Python

#!/usr/bin/env python3
"""VedAstro external calculation-method evidence boundary tests."""
from __future__ import annotations
import json
import os
import subprocess
import sys
from copy import deepcopy
from pathlib import Path
from unittest import mock
import mcp_server
from mcp_server import _collect_strict_evidence
ROOT = Path(__file__).resolve().parents[1]
def test_vedastro_adapter_declares_external_technique_evidence_policy() -> None:
completed = subprocess.run(
[sys.executable, "scripts/vedastro_service_adapter.py", "--print-schema"],
cwd=ROOT,
text=True,
capture_output=True,
timeout=120,
check=False,
)
assert completed.returncode == 0, completed.stderr or completed.stdout
schema = json.loads(completed.stdout)
assert "external_technique_request_contract" in schema
assert "method" in schema["external_technique_request_contract"]
assert "api_endpoint" in schema["external_technique_request_contract"]
assert schema["external_technique_adjudicator_policy"] == {
"role": "external_technique_evidence",
"can_change_score": False,
"can_set_dominant_label": False,
"can_set_payout_label": False,
"allowed_destinations": ["secondary_context", "technique_audit"],
}
def test_vedastro_adapter_builds_external_technique_preview_without_network() -> None:
env = os.environ.copy()
env["VEDASTRO_API_ENDPOINT"] = "https://example.invalid/vedastro"
env["VEDASTRO_ENABLE_NETWORK"] = "0"
env["JYOTISH_SKIP_LOCAL_ENV"] = "1"
completed = subprocess.run(
[
sys.executable,
"scripts/vedastro_service_adapter.py",
"--external-technique",
"--domain",
"wealth",
"--method",
"CalculateShadbala",
"--api-endpoint",
"Calculate/Shadbala",
"--case",
"beijing_first_use_demo",
],
cwd=ROOT,
text=True,
capture_output=True,
timeout=120,
check=False,
env=env,
)
assert completed.returncode == 0, completed.stderr or completed.stdout
report = json.loads(completed.stdout)
assert report["backend"] == "vedastro_service_adapter_candidate"
assert report["status"] == "network_execution_disabled"
assert report["request_preview"]["operation"] == "calculation_method"
assert report["request_preview"]["role"] == "external_technique_evidence"
assert report["request_preview"]["domain"] == "wealth"
assert report["request_preview"]["method"] == "CalculateShadbala"
assert report["request_preview"]["api_endpoint"] == "Calculate/Shadbala"
assert report["adjudicator_policy"]["can_change_score"] is False
assert report["adjudicator_policy"]["can_set_dominant_label"] is False
assert report["adjudicator_policy"]["can_set_payout_label"] is False
def _finance_modules() -> dict:
return {
"varga_full": {
"D2_Hora": {"available": True},
"D10_Dasamsa": {"available": True},
},
"shadbala": {
"planets": {
"Jupiter": {
"sthana_bala": 1,
"dig_bala": 1,
"kala_bala": 1,
"chesta_bala": 1,
"naisargika_bala": 1,
"drik_bala": 1,
}
}
},
"ashtakavarga": {
"house_scores": {
"2": 28,
"11": 29,
}
},
"dasha": {
"current_dasha": {
"mahadasha": "Saturn",
"antardasha": "Mercury",
}
},
"narayana_dasha": {
"current_dasha": {
"sign": "Gemini",
"lord": "Mercury",
}
},
"dasa_convergence": {
"domain_activations": {
"wealth_family": {
"convergence_level": "L1",
"probability": "+15-20%",
}
}
},
"chart": {
"ascendant": {
"sign": "Leo",
}
},
}
def test_strict_workflow_uses_external_technique_as_context_only() -> None:
base_result = {"modules": _finance_modules()}
with_external = {"modules": deepcopy(base_result["modules"])}
with_external["modules"]["external_technique_evidence"] = {
"evidence_ledger": [
{
"source": "vedastro_service_adapter_candidate",
"operation": "calculation_method",
"role": "external_technique_evidence",
"domain": "wealth",
"method": "CalculateShadbala",
"api_endpoint": "Calculate/Shadbala",
"status": "ok",
"summary": "VedAstro Shadbala node returned as external evidence.",
}
]
}
base = _collect_strict_evidence("finance", base_result)
strict = _collect_strict_evidence("finance", with_external)
base_judgement = base["event_judgement"]
judgement = strict["event_judgement"]
assert strict["present_evidence"]["external_technique_evidence"]["level"] == "context_only"
assert strict["present_evidence"]["external_technique_evidence"]["methods"] == ["CalculateShadbala"]
assert "external_technique_evidence" in judgement["secondary_context"]
assert {
"technique": "VedAstro EventsAtRange / 596+ Calculator Radar",
"status": "blocked",
"role": "required_external_timing_radar",
"effect": "confidence_boundary_only_no_score_or_label_lift",
} in strict["technique_audit"]
assert {
"technique": "VedAstro External Technique Evidence",
"status": "used",
"role": "external_evidence_only",
"methods": ["CalculateShadbala"],
"effect": "secondary_context_only_no_score_or_label_lift",
} in strict["technique_audit"]
assert judgement["score"] == base_judgement["score"]
assert judgement["dominant_label"] == base_judgement["dominant_label"]
assert judgement["payout_label"] == base_judgement["payout_label"]
def test_strict_workflow_requires_vedastro_range_scan_boundary_for_timing_routes() -> None:
strict = _collect_strict_evidence("finance", {"modules": _finance_modules()})
assert strict["present_evidence"]["external_activation"]["level"] == "missing_required_external_radar"
assert strict["present_evidence"]["external_activation"]["source"] == "vedastro_service_adapter_candidate"
assert strict["present_evidence"]["external_activation"]["required"] is True
assert "vedastro_range_scan_missing" in strict["event_judgement"]["secondary_context"]
assert {
"technique": "VedAstro EventsAtRange / 596+ Calculator Radar",
"status": "blocked",
"role": "required_external_timing_radar",
"effect": "confidence_boundary_only_no_score_or_label_lift",
} in strict["technique_audit"]
def test_strict_workflow_exposes_official_snapshot_as_primary_evidence_layer() -> None:
modules = _finance_modules()
modules["vedastro_official_full_snapshot"] = {
"status": "partial",
"available": True,
"operation": "official_full_snapshot",
"primary_source": "vedastro_official",
"official_chart": {
"source": "vedastro_official",
"planets": {"Sun": {"source": "vedastro_official", "sign": "Aries"}},
"ascendant": {"source": "vedastro_official", "sign": "Leo"},
},
}
modules["source_priority"] = {
"mode": "vedastro_official_primary",
"priority": [
"vedastro_official_snapshot",
"local_supplemental_modules",
"local_engine_fallback_when_official_blocked",
],
"local_engine_role": "supplemental_crosscheck_or_fallback",
"official_snapshot_status": "partial",
}
strict = _collect_strict_evidence("finance", {"modules": modules})
official = strict["present_evidence"]["vedastro_official_snapshot"]
assert official["level"] == "primary"
assert official["source"] == "vedastro_official"
assert official["status"] == "partial"
assert strict["present_evidence"]["source_priority"]["mode"] == "vedastro_official_primary"
assert any(
row["technique"] == "VedAstro Official Full Snapshot"
and row["status"] == "used"
and row["role"] == "primary_raw_evidence"
for row in strict["technique_audit"]
)
def test_strict_workflow_marks_vedastro_range_scan_used_without_score_or_label_override() -> None:
base_result = {"modules": _finance_modules()}
with_range_scan = {"modules": deepcopy(base_result["modules"])}
with_range_scan["modules"]["external_activation"] = {
"evidence_ledger": [
{
"source": "vedastro_service_adapter_candidate",
"operation": "range_scan",
"domain": "wealth",
"event_id": "GocharJupiterIn11th",
"signal_label": "Jupiter in 11th gains window",
"score": 76,
"tags": ["wealth", "transit"],
}
]
}
base = _collect_strict_evidence("finance", base_result)
strict = _collect_strict_evidence("finance", with_range_scan)
assert strict["present_evidence"]["external_activation"]["level"] == "moderate"
assert "external_activation_support" in strict["event_judgement"]["secondary_context"]
assert "vedastro_range_scan_missing" not in strict["event_judgement"]["secondary_context"]
assert any(
row["technique"] == "VedAstro EventsAtRange / 596+ Calculator Radar"
and row["status"] == "used"
and row["event_count"] == 1
for row in strict["technique_audit"]
)
assert strict["missing_evidence"] == ["wealth_promise_strength"]
assert strict["event_judgement"]["score"] == base["event_judgement"]["score"]
assert strict["event_judgement"]["dominant_label"] == base["event_judgement"]["dominant_label"]
assert strict["event_judgement"]["payout_label"] == base["event_judgement"]["payout_label"]
def test_strict_workflow_auto_ingests_live_vedastro_range_scan_for_finance_route() -> None:
fake_range_scan = {
"backend": "vedastro_service_adapter_candidate",
"available": True,
"status": "ok",
"operation": "range_scan",
"domain": "wealth",
"event_count": 1,
"evidence_ledger": [
{
"source": "vedastro_service_adapter_candidate",
"operation": "range_scan",
"domain": "wealth",
"event_id": "GocharJupiterIn11th",
"signal_label": "Jupiter in 11th gains window",
"score": 76,
"tags": ["wealth", "transit"],
}
],
"source_metadata": {"sampling_mode": "at_time_sweep"},
}
with mock.patch.object(mcp_server, "_run_engine") as run_engine, mock.patch.object(
mcp_server,
"_maybe_attach_vedastro_evidence",
) as attach_vedastro:
run_engine.return_value = {"modules": _finance_modules()}
attach_vedastro.return_value = {
"modules": {
**_finance_modules(),
"vedastro_range_scan_result": fake_range_scan,
}
}
result = mcp_server.strict_workflow(
question="今年的财富机会怎么样?",
year=1955,
month=2,
day=24,
hour=19,
minute=15,
lat=37.7749,
lon=-122.4194,
tz=8.0,
age=33,
transit_date="2026-06-29",
node_mode="mean",
)
strict = result["strict_workflow"]
attach_vedastro.assert_called_once()
assert strict["present_evidence"]["external_activation"]["level"] == "moderate"
assert "external_activation_support" in strict["event_judgement"]["secondary_context"]
assert "vedastro_range_scan_missing" not in strict["event_judgement"]["secondary_context"]
def test_strict_workflow_auto_ingests_live_vedastro_external_technique_as_context_only() -> None:
fake_external_technique = {
"backend": "vedastro_service_adapter_candidate",
"available": True,
"status": "ok",
"operation": "calculation_method",
"role": "external_technique_evidence",
"domain": "wealth",
"evidence_ledger": [
{
"source": "vedastro_service_adapter_candidate",
"operation": "calculation_method",
"role": "external_technique_evidence",
"domain": "wealth",
"method": "CalculateShadbala",
"api_endpoint": "Calculate/Shadbala",
"status": "ok",
"summary": "VedAstro Shadbala node returned as external evidence.",
}
],
}
with mock.patch.object(mcp_server, "_run_engine") as run_engine, mock.patch.object(
mcp_server,
"_maybe_attach_vedastro_evidence",
) as attach_vedastro:
run_engine.return_value = {"modules": _finance_modules()}
attach_vedastro.return_value = {
"modules": {
**_finance_modules(),
"external_technique_evidence": fake_external_technique,
}
}
result = mcp_server.strict_workflow(
question="我的财务今年如何?",
year=1955,
month=2,
day=24,
hour=19,
minute=15,
lat=37.7749,
lon=-122.4194,
tz=8.0,
age=33,
transit_date="2026-06-29",
node_mode="mean",
)
strict = result["strict_workflow"]
assert strict["present_evidence"]["external_technique_evidence"]["level"] == "context_only"
assert strict["present_evidence"]["external_technique_evidence"]["methods"] == ["CalculateShadbala"]
assert "external_technique_evidence" in strict["event_judgement"]["secondary_context"]
def test_strict_workflow_reports_unified_orchestrator_metadata() -> None:
with mock.patch.object(mcp_server, "_run_engine") as run_engine, mock.patch.object(
mcp_server,
"_maybe_attach_vedastro_evidence",
) as attach_vedastro:
run_engine.return_value = {"modules": _finance_modules()}
attach_vedastro.return_value = {"modules": _finance_modules()}
result = mcp_server.strict_workflow(
question="我的财务今年如何?",
year=1955,
month=2,
day=24,
hour=19,
minute=15,
lat=37.7749,
lon=-122.4194,
tz=8.0,
age=33,
transit_date="2026-06-29",
node_mode="mean",
)
unified = result["unified_orchestrator"]
assert unified["name"] == "UnifiedConsultationOrchestrator"
assert unified["surface"] == "skill_mcp"
assert unified["route"]["question_type"] == "finance"
assert unified["source_priority"]["priority"][0] == "vedastro_official_snapshot"
planner = result["runtime_planner"]
assert planner["planner_name"] == "UnifiedConsultationRuntimePlanner"
assert planner["surface"] == "skill_mcp"
assert planner["route"]["question_type"] == "finance"
assert planner["sync_steps"][0] == "compute_chart"
def test_strict_workflow_uses_shared_consultation_executor(monkeypatch) -> None:
fake_result = {
"success": True,
"endpoint": "consultation_workflow",
"entry_mode": "direct_chart",
"routing": {"question_type": "finance"},
"unified_orchestrator": {
"name": "UnifiedConsultationOrchestrator",
"surface": "skill_mcp",
"route": {"question_type": "finance"},
},
"runtime_planner": {
"planner_name": "UnifiedConsultationRuntimePlanner",
"surface": "skill_mcp",
"entry_mode": "direct_chart",
"route": {"question_type": "finance"},
"sync_steps": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
"executed_steps": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
"skipped_steps": ["run_historical_event_backtest"],
},
"chart": {"modules": _finance_modules()},
"rectification": {"success": True, "endpoint": "rectification_gate"},
"thematic_report": {"success": True, "endpoint": "thematic_report"},
"vedastro_official": {"available": True},
"runtime_truth": {
"catalog_boundary": "catalog_recognized_not_full_runtime_execution",
"official_execution_layers": {"chart_core": "ok", "event_radar": "partial"},
},
"interpretation_source_runtime_coverage": {
"source_pack_status": "used",
"proven_runtime_markers": ["dasha_timing_layer_used"],
"runtime_visibility_status": "partial",
},
}
seen = {}
def fake_executor(**kwargs):
seen.update(kwargs)
return fake_result
monkeypatch.setattr(mcp_server, "_execute_mcp_consultation_workflow", fake_executor)
result = mcp_server.strict_workflow(
question="我的财务今年如何?",
year=1955,
month=2,
day=24,
hour=19,
minute=15,
lat=37.7749,
lon=-122.4194,
tz=8.0,
age=33,
transit_date="2026-06-29",
node_mode="mean",
)
assert seen["entry_mode"] == "direct_chart"
assert seen["question"] == "我的财务今年如何?"
# strict_workflow recomputes the official summary from chart evidence; a
# shared executor cannot upgrade missing raw official evidence to ok.
assert result["runtime_truth"]["official_execution_layers"]["chart_core"] == "blocked"
assert result["interpretation_source_runtime_coverage"]["source_pack_status"] == "used"
assert result["interpretation_source_runtime_coverage"]["runtime_visibility_status"] == "blocked"
assert result["runtime_planner"]["surface"] == "skill_mcp"
assert result["routing"]["question_type"] == "finance"