#!/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"