1761 lines
86 KiB
Python
1761 lines
86 KiB
Python
#!/usr/bin/env python3
|
|
"""Shared orchestration contract for skill/MCP and web/API surfaces."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import re
|
|
from dataclasses import asdict, dataclass, field
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
try:
|
|
from consultation_domain_registry import (
|
|
CANONICAL_DOMAINS,
|
|
DEFAULT_THEMES,
|
|
DOMAIN_ALIASES,
|
|
normalize_domain,
|
|
)
|
|
from consultation_domain_registry import (
|
|
normalize_themes as normalize_consultation_themes,
|
|
)
|
|
except ImportError: # pragma: no cover - import path varies in tests/CLI
|
|
from scripts.consultation_domain_registry import (
|
|
CANONICAL_DOMAINS,
|
|
DEFAULT_THEMES,
|
|
DOMAIN_ALIASES,
|
|
normalize_domain,
|
|
)
|
|
from scripts.consultation_domain_registry import (
|
|
normalize_themes as normalize_consultation_themes,
|
|
)
|
|
|
|
|
|
def _formal_divisions() -> tuple[int, ...]:
|
|
registry = Path(__file__).resolve().parents[1] / "references/oracle/d1_d60_varga_mapping_registry_2026_07_19.json"
|
|
rows = json.loads(registry.read_text(encoding="utf-8"))["rows"]
|
|
return tuple(int(row["number"]) for row in rows if row.get("formal_name_present"))
|
|
|
|
|
|
FORMAL_DIVISIONS = _formal_divisions()
|
|
|
|
try:
|
|
from diagnose_pyjhora_adapter import build_report as build_pyjhora_adapter_report
|
|
except Exception: # pragma: no cover - import path varies in tests/CLI
|
|
from scripts.diagnose_pyjhora_adapter import build_report as build_pyjhora_adapter_report
|
|
|
|
try:
|
|
from diagnose_jyotishganit_adapter import build_report as build_jyotishganit_adapter_report
|
|
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 specialized_indian_closure_review import build_specialized_indian_closure_review
|
|
except Exception: # pragma: no cover - research helper is not vendored here
|
|
try:
|
|
from scripts.specialized_indian_closure_review import build_specialized_indian_closure_review
|
|
except Exception:
|
|
def build_specialized_indian_closure_review(**kwargs):
|
|
return {"status": "blocked", "reason": "specialized_indian_closure_review_absent"}
|
|
|
|
try:
|
|
from finance_astrology_support_review import build_finance_astrology_support_review
|
|
except Exception: # pragma: no cover - research helper is not vendored here
|
|
try:
|
|
from scripts.finance_astrology_support_review import build_finance_astrology_support_review
|
|
except Exception:
|
|
def build_finance_astrology_support_review(**kwargs):
|
|
return {"status": "blocked", "reason": "finance_astrology_support_review_absent"}
|
|
|
|
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
|
|
_EMPTY_METHODOLOGY_ROLES = {
|
|
"core": [],
|
|
"enhancement": [],
|
|
"adjudication": [],
|
|
"annual_trigger": [],
|
|
"blocked": [],
|
|
}
|
|
_DEFAULT_AUTHORITY_ORDER = ["core", "enhancement", "adjudication", "annual_trigger", "blocked"]
|
|
_DOCUMENT_ROUTE_BY_CANONICAL = {
|
|
"career": "career-timing-strict",
|
|
"marriage": "relationship-timing-strict",
|
|
"wealth": "finance-timing-strict",
|
|
"health": "health-timing-strict",
|
|
"timing": "event-timing-strict",
|
|
"general": "full-reading-strict",
|
|
}
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class RouteDefinition:
|
|
question_type: str
|
|
primary_theme: str
|
|
focus_techniques: list[str]
|
|
display_label: str
|
|
methodology_roles: dict[str, list[str]] = field(default_factory=lambda: dict(_EMPTY_METHODOLOGY_ROLES))
|
|
authority_order: list[str] = field(default_factory=lambda: list(_DEFAULT_AUTHORITY_ORDER))
|
|
|
|
|
|
class UnifiedConsultationOrchestrator:
|
|
"""Normalizes user intent and exposes a surface-agnostic workflow contract."""
|
|
|
|
NAME = "UnifiedConsultationOrchestrator"
|
|
SOURCE_PRIORITY = {
|
|
"mode": "vedastro_official_snapshot_first",
|
|
"priority": [
|
|
"vedastro_official_snapshot",
|
|
"local_supplemental_modules",
|
|
"local_fallback_only_when_official_blocked",
|
|
],
|
|
"boundary": (
|
|
"Official VedAstro raw evidence is preferred; local modules supplement, "
|
|
"cross-check, and fallback when official calls are blocked."
|
|
),
|
|
}
|
|
EVIDENCE_PACKET_REQUIRED_SECTIONS = [
|
|
"D1",
|
|
"D9",
|
|
"D10",
|
|
"D2",
|
|
"D4",
|
|
"D6",
|
|
"D8",
|
|
"D30",
|
|
"planet_degrees",
|
|
"house_degrees",
|
|
"dasha_boundaries",
|
|
"narayana_dasha",
|
|
"shadbala",
|
|
"ashtakavarga",
|
|
"yogas",
|
|
"functional_benefic_malefic",
|
|
"transit",
|
|
"non_medical_boundary",
|
|
"UL",
|
|
"A7",
|
|
"A10",
|
|
"KP_cusp",
|
|
"external_oracle_status",
|
|
"vedastro_official_raw_response",
|
|
"vedastro_official_raw_archive_manifest",
|
|
]
|
|
_THEME_ALIASES = DOMAIN_ALIASES
|
|
_DEFAULT_THEMES = list(DEFAULT_THEMES)
|
|
_ALLOWED_THEMES = set(CANONICAL_DOMAINS)
|
|
_ROUTE_DEFINITIONS = {
|
|
"career": RouteDefinition(
|
|
question_type="career",
|
|
primary_theme="career",
|
|
focus_techniques=["D10", "Dasha", "Shadbala", "Transit", "Narayana Dasha"],
|
|
display_label="career",
|
|
methodology_roles={
|
|
"core": ["D10", "Dasha", "Shadbala", "Transit", "Narayana Dasha"],
|
|
"enhancement": ["A10"],
|
|
"adjudication": [],
|
|
"annual_trigger": [],
|
|
"blocked": [],
|
|
},
|
|
authority_order=["core", "enhancement", "adjudication", "annual_trigger", "blocked"],
|
|
),
|
|
"marriage": RouteDefinition(
|
|
question_type="marriage",
|
|
primary_theme="marriage",
|
|
focus_techniques=["D9", "UL Upapada", "Dasha", "Nakshatra", "Vivah Saham"],
|
|
display_label="marriage",
|
|
),
|
|
"wealth": RouteDefinition(
|
|
question_type="wealth",
|
|
primary_theme="wealth",
|
|
focus_techniques=["D2", "D11", "Dasha", "Shadbala", "Ashtakavarga"],
|
|
display_label="wealth",
|
|
),
|
|
"health": RouteDefinition(
|
|
question_type="health",
|
|
primary_theme="health",
|
|
focus_techniques=[
|
|
"D6",
|
|
"D8",
|
|
"D30",
|
|
"Dasha",
|
|
"Narayana Dasha",
|
|
"Shadbala",
|
|
"Transit",
|
|
"Functional Benefic/Malefic",
|
|
],
|
|
display_label="health",
|
|
),
|
|
"education": RouteDefinition(
|
|
question_type="education",
|
|
primary_theme="education",
|
|
focus_techniques=["D5", "D24", "5th house", "9th house", "Dasha"],
|
|
display_label="education",
|
|
methodology_roles={
|
|
"core": ["D24", "D10", "Dasha", "Narayana Dasha", "Shadbala", "Transit"],
|
|
"enhancement": ["A10"],
|
|
"adjudication": [],
|
|
"annual_trigger": [],
|
|
"blocked": [],
|
|
},
|
|
authority_order=["core", "enhancement", "adjudication", "annual_trigger", "blocked"],
|
|
),
|
|
"migration": RouteDefinition(
|
|
question_type="migration",
|
|
primary_theme="migration",
|
|
focus_techniques=["D4", "D12", "12th house", "Dasha", "Narayana Dasha"],
|
|
display_label="migration",
|
|
),
|
|
"family": RouteDefinition(
|
|
question_type="family",
|
|
primary_theme="family",
|
|
focus_techniques=["D7", "D12", "4th house", "5th house", "9th house", "Dasha"],
|
|
display_label="family",
|
|
),
|
|
"annual": RouteDefinition(
|
|
question_type="annual",
|
|
primary_theme="annual",
|
|
focus_techniques=["Annual chart boundary", "Dasha", "Transit", "Tajika candidate", "claim boundary"],
|
|
display_label="annual",
|
|
),
|
|
"timing": RouteDefinition(
|
|
question_type="timing",
|
|
primary_theme="timing",
|
|
focus_techniques=["Dasha", "Transit", "Double Transit", "Gochara"],
|
|
display_label="timing",
|
|
methodology_roles={
|
|
"core": ["Dasha", "Narayana Dasha", "Transit", "Double Transit", "Gochara"],
|
|
"enhancement": [],
|
|
"adjudication": [],
|
|
"annual_trigger": [],
|
|
"blocked": [],
|
|
},
|
|
authority_order=["core", "enhancement", "adjudication", "annual_trigger", "blocked"],
|
|
),
|
|
"general": RouteDefinition(
|
|
question_type="general",
|
|
primary_theme="general",
|
|
focus_techniques=["D1", "D9", "Dasha", "Yoga", "Shadbala", "Ashtakavarga"],
|
|
display_label="general",
|
|
methodology_roles={
|
|
"core": ["D1", "D9", "Dasha", "Shadbala", "Ashtakavarga"],
|
|
"enhancement": ["Yoga"],
|
|
"adjudication": [],
|
|
"annual_trigger": [],
|
|
"blocked": [],
|
|
},
|
|
authority_order=["core", "enhancement", "adjudication", "annual_trigger", "blocked"],
|
|
),
|
|
}
|
|
_SYNC_STEPS_BY_ROUTE = {
|
|
"career": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
|
|
"marriage": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
|
|
"wealth": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
|
|
"health": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
|
|
"migration": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
|
|
"family": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
|
|
"education": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
|
|
"annual": ["compute_chart", "run_rectification_gate", "run_muhurta_panchanga", "run_thematic_report"],
|
|
"timing": ["compute_chart", "run_rectification_gate", "run_muhurta_panchanga", "run_thematic_report"],
|
|
"general": ["compute_chart", "run_rectification_gate", "run_thematic_report"],
|
|
}
|
|
_ASYNC_CANDIDATES = [
|
|
"historical_event_backtest",
|
|
"official_event_radar_expansion",
|
|
"extended_prompt_pack_refresh",
|
|
]
|
|
_DOMAIN_PROFILE_SECTIONS = {
|
|
"marriage": ["core_partner_profile", "temperament_and_compatibility", "timing_windows", "red_flags", "verification_questions"],
|
|
"career": ["career_direction", "role_and_responsibility", "income_and_recognition", "opportunity_windows", "risks_and_verification_questions"],
|
|
"wealth": ["wealth_path", "income_structure", "asset_and_cashflow_pattern", "opportunity_windows", "verification_questions"],
|
|
"health": ["pressure_windows", "event_risk_windows", "recovery_support_windows", "non_medical_boundary", "verification_questions"],
|
|
"migration": ["relocation_pattern", "foreign_link", "candidate_windows", "verification_questions"],
|
|
"family": ["family_structure", "home_and_care", "children_boundary", "verification_questions"],
|
|
"education": ["study_vs_work_fit", "exam_and_degree_path", "candidate_windows", "verification_questions"],
|
|
"annual": ["annual_themes", "candidate_windows", "claim_boundaries", "verification_questions"],
|
|
"timing": ["active_themes", "candidate_windows", "triggering_techniques", "verification_questions"],
|
|
"general": ["life_themes", "strengths_and_pressures", "candidate_windows", "verification_questions"],
|
|
}
|
|
_THEME_VARGA_DISPATCH = {
|
|
"career": ("D1", "D10", "D24"),
|
|
"marriage": ("D1", "D9", "D7", "D12"),
|
|
"wealth": ("D1", "D2", "D11", "D4"),
|
|
"health": ("D1", "D6", "D8", "D30"),
|
|
"migration": ("D1", "D4", "D12"),
|
|
"family": ("D1", "D7", "D12"),
|
|
"education": ("D1", "D5", "D24"),
|
|
"annual": ("D1", "D9", "D10"),
|
|
"timing": ("D1", "D9", "D10"),
|
|
"general": ("D1", "D9"),
|
|
}
|
|
_THEME_TECHNIQUE_IDENTIFIERS = {
|
|
"career": {"D10", "A10"},
|
|
"marriage": {"D9", "UL", "UPAPADA", "VIVAH"},
|
|
"wealth": {"D2", "D11"},
|
|
"health": {"D6", "D8", "D30"},
|
|
"migration": {"D4", "D12"},
|
|
"family": {"D7", "D12"},
|
|
"education": {"D5", "D24"},
|
|
"annual": {"DASHA", "TRANSIT", "TAJIKA"},
|
|
"timing": {"DASHA", "TRANSIT", "GOCHARA"},
|
|
"general": {"D1", "D9"},
|
|
}
|
|
|
|
@staticmethod
|
|
def route_surface_contract(question_type: str) -> dict[str, Any]:
|
|
raw = str(question_type or "").strip().lower()
|
|
try:
|
|
runtime_route = normalize_domain(raw or "general")
|
|
except ValueError:
|
|
runtime_route = raw or "general"
|
|
document_route = _DOCUMENT_ROUTE_BY_CANONICAL.get(
|
|
runtime_route,
|
|
runtime_route.replace("_", "-"),
|
|
)
|
|
registry_route = document_route.replace("-", "_")
|
|
alias_set = {runtime_route, registry_route, document_route, raw} - {""}
|
|
if runtime_route == "wealth":
|
|
alias_set.update({
|
|
"finance",
|
|
"money",
|
|
"wealth-timing-strict",
|
|
"wealth_timing_strict",
|
|
"finance-timing-strict",
|
|
"finance_timing_strict",
|
|
})
|
|
elif runtime_route == "marriage":
|
|
alias_set.update({"relationship", "relationship-timing-strict", "relationship_timing_strict"})
|
|
elif runtime_route == "timing":
|
|
alias_set.update({"event-timing-strict", "event_timing_strict"})
|
|
elif runtime_route == "general":
|
|
alias_set.update({"full-reading-strict", "full_reading_strict", "comprehensive"})
|
|
return {
|
|
"runtime_route": runtime_route,
|
|
"registry_route": registry_route,
|
|
"document_route": document_route,
|
|
"audit_route": runtime_route,
|
|
"route_aliases": sorted(alias_set),
|
|
}
|
|
|
|
@classmethod
|
|
def route_profile_contract(cls, route_name: str) -> dict[str, Any]:
|
|
"""Expose reader sections without replacing runtime technique audit."""
|
|
try:
|
|
route = normalize_domain(route_name)
|
|
except ValueError:
|
|
route = "general"
|
|
return {
|
|
"version": "domain_profile_v1",
|
|
"route": route,
|
|
"sections": list(cls._DOMAIN_PROFILE_SECTIONS[route]),
|
|
"assertion_levels": [
|
|
"multi_system_consensus", "single_system_inference", "parameter_sensitive",
|
|
"unclosed_divisional_chart", "user_history_verification_required", "blocked",
|
|
],
|
|
"execution_boundary": "Profile labels do not replace Technique Audit Table execution status.",
|
|
}
|
|
|
|
@classmethod
|
|
def evidence_packet_required_sections(cls, route_name: str | None = None) -> list[str]:
|
|
required = list(cls.EVIDENCE_PACKET_REQUIRED_SECTIONS)
|
|
try:
|
|
route = normalize_domain(route_name) if route_name else "general"
|
|
except ValueError:
|
|
route = route_name or "general"
|
|
if route == "health":
|
|
for section in ("D6", "D8", "D30", "narayana_dasha", "functional_benefic_malefic", "transit", "non_medical_boundary"):
|
|
if section not in required:
|
|
required.append(section)
|
|
return required
|
|
|
|
def normalize_themes(self, raw: Any) -> list[str]:
|
|
return normalize_consultation_themes(raw)
|
|
|
|
def resolve_route(
|
|
self,
|
|
question: str,
|
|
themes: list[str] | None = None,
|
|
*,
|
|
declared_route: str | None = None,
|
|
) -> dict[str, Any]:
|
|
"""Resolve the workflow route, preferring an explicitly declared one over the question text.
|
|
|
|
``declared_route`` comes from server-issued plan metadata and is already allowlisted, so it
|
|
decides execution: one question asked for several domains would otherwise let keyword
|
|
matching answer for at most one of them. Callers that declare nothing keep text routing.
|
|
"""
|
|
if declared_route is not None:
|
|
route = self._ROUTE_DEFINITIONS.get(declared_route)
|
|
if route is None:
|
|
raise ValueError(f"unknown declared consultation route: {declared_route}")
|
|
return self._route_packet(route, source="declared_plan")
|
|
|
|
text = (question or "").lower()
|
|
normalized_themes = self.normalize_themes(themes)
|
|
explicit_timing_tokens = ("when", "timing", "何时", "什么时候", "应期", "几月", "哪月", "哪天", "日期")
|
|
|
|
domain_tokens = {
|
|
"career": ("career", "job", "work", "promotion", "business", "profession", "事业", "工作", "升职", "生意"),
|
|
"marriage": ("marriage", "married", "wedding", "relationship", "love", "spouse", "partner", "divorce", "婚恋", "婚姻", "感情", "配偶", "恋爱", "结婚", "marry"),
|
|
"wealth": ("money", "wealth", "finance", "investment", "property", "income", "财务", "财富", "投资", "房产", "收入"),
|
|
"health": ("health", "illness", "medical", "disease", "vitality", "健康", "疾病", "病", "体力", "医疗"),
|
|
"migration": ("migration", "foreign", "abroad", "overseas", "relocation", "home", "迁移", "海外", "出国", "搬迁", "远方"),
|
|
"family": ("family", "children", "mother", "father", "家庭", "子女", "孩子", "父母", "家宅"),
|
|
"education": ("education", "study", "learning", "school", "degree", "学习", "教育", "学历", "学校", "考试"),
|
|
"annual": ("annual", "yearly", "this year", "next year", "年度", "流年", "今年", "明年", "年运"),
|
|
}
|
|
first_hits: list[tuple[int, str]] = []
|
|
for route_name, tokens in domain_tokens.items():
|
|
indexes = [text.find(token) for token in tokens if token in text]
|
|
indexes = [idx for idx in indexes if idx >= 0]
|
|
if indexes:
|
|
first_hits.append((min(indexes), route_name))
|
|
|
|
if text.strip() and any(token in text for token in explicit_timing_tokens) and "marriage" not in normalized_themes:
|
|
route = self._ROUTE_DEFINITIONS["timing"]
|
|
elif first_hits:
|
|
route_name = sorted(first_hits, key=lambda item: item[0])[0][1]
|
|
route = self._ROUTE_DEFINITIONS[route_name]
|
|
elif not text.strip():
|
|
route = self._ROUTE_DEFINITIONS["general"]
|
|
elif any(token in text for token in ("when", "timing", "event", "prediction", "future", "应期", "预测", "何时", "将来")):
|
|
route = self._ROUTE_DEFINITIONS["timing"]
|
|
elif "career" in normalized_themes:
|
|
route = self._ROUTE_DEFINITIONS["career"]
|
|
elif "marriage" in normalized_themes:
|
|
route = self._ROUTE_DEFINITIONS["marriage"]
|
|
elif "wealth" in normalized_themes:
|
|
route = self._ROUTE_DEFINITIONS["wealth"]
|
|
elif "health" in normalized_themes:
|
|
route = self._ROUTE_DEFINITIONS["health"]
|
|
elif "migration" in normalized_themes:
|
|
route = self._ROUTE_DEFINITIONS["migration"]
|
|
elif "family" in normalized_themes:
|
|
route = self._ROUTE_DEFINITIONS["family"]
|
|
elif "education" in normalized_themes:
|
|
route = self._ROUTE_DEFINITIONS["education"]
|
|
elif "annual" in normalized_themes:
|
|
route = self._ROUTE_DEFINITIONS["annual"]
|
|
elif "timing" in normalized_themes:
|
|
route = self._ROUTE_DEFINITIONS["timing"]
|
|
else:
|
|
route = self._ROUTE_DEFINITIONS["general"]
|
|
|
|
return self._route_packet(route, source="question_text")
|
|
|
|
@staticmethod
|
|
def _route_packet(route: RouteDefinition, *, source: str) -> dict[str, Any]:
|
|
surface = UnifiedConsultationOrchestrator.route_surface_contract(route.question_type)
|
|
return {
|
|
"question_type": route.question_type,
|
|
"primary_theme": route.primary_theme,
|
|
"focus_techniques": list(route.focus_techniques),
|
|
"display_label": route.display_label,
|
|
"route_source": source,
|
|
**surface,
|
|
}
|
|
|
|
def route_profile(self, question: str, themes: list[str] | None = None) -> dict[str, Any]:
|
|
"""Select presentation depth and on-demand Vargas without changing routing."""
|
|
normalized_themes = self.normalize_themes(themes)
|
|
request = (question or "").lower()
|
|
is_research = any(token in request for token in ("研究模式", "research_mode", "原始数据", "全量数据", "raw_data"))
|
|
selected: list[str] = []
|
|
for theme in normalized_themes:
|
|
for code in self._THEME_VARGA_DISPATCH.get(theme, ("D1",)):
|
|
if code not in selected:
|
|
selected.append(code)
|
|
formal = [f"D{division}" for division in FORMAL_DIVISIONS]
|
|
research = [f"D{division}" for division in range(2, 61) if division not in FORMAL_DIVISIONS]
|
|
return {
|
|
"question": question or "",
|
|
"themes": normalized_themes,
|
|
"presentation_mode": "research" if is_research else "default",
|
|
"appendix_expanded": is_research,
|
|
"varga_dispatch": {
|
|
"mode": "full_spectrum",
|
|
"selected_theme_vargas": selected,
|
|
"all_formal_vargas": formal,
|
|
"research_dn_vargas": research,
|
|
"deferred_vargas": [],
|
|
"rule": "主题相关分盘优先解读;D1–D60 正式分盘与其余 D-N 研究分盘均已计算,未计算的标 blocked,不得静默省略。",
|
|
},
|
|
}
|
|
|
|
@staticmethod
|
|
def _deduplicate_sentences(text: str) -> str:
|
|
parts = re.split(r"(?<=[.!?。!?])", text)
|
|
seen: set[str] = set()
|
|
kept: list[str] = []
|
|
for part in parts:
|
|
key = part.strip()
|
|
if key and key not in seen:
|
|
seen.add(key)
|
|
kept.append(part)
|
|
return "".join(kept)
|
|
|
|
@classmethod
|
|
def _suppress_definitive_claims(cls, text: str) -> str:
|
|
conditional = text.replace("确定", "尚无法确认").replace("必然", "未必").replace("一定", "尚无法确认")
|
|
conditional = re.sub(r"\bwill\s+(?:definitely|certainly|inevitably)\b", "may", conditional, flags=re.IGNORECASE)
|
|
return re.sub(r"\b(?:definitely|certainly|certain|inevitably|guaranteed)(?:\s+(?:definitely|certainly|certain|inevitably|guaranteed))*\b", "not yet verified", conditional, flags=re.IGNORECASE)
|
|
|
|
def _audit_applies_to_theme(self, row: dict[str, Any], theme: str) -> bool:
|
|
for field in ("theme", "domain"):
|
|
if str(row.get(field) or "").lower() == theme:
|
|
return True
|
|
for field in ("themes", "domains", "applicable_themes"):
|
|
values = row.get(field)
|
|
if isinstance(values, str) and values.lower() == theme:
|
|
return True
|
|
if isinstance(values, list) and theme in {str(value).lower() for value in values}:
|
|
return True
|
|
technique = str(row.get("technique") or row.get("name") or "").upper()
|
|
identifiers = set(re.findall(r"\b[A-Z]+\d*\b", technique))
|
|
return bool(identifiers & self._THEME_TECHNIQUE_IDENTIFIERS.get(theme, set()))
|
|
|
|
@staticmethod
|
|
def _infer_technique_system(row: dict[str, Any]) -> str:
|
|
technique = str(row.get("technique") or row.get("name") or "").lower()
|
|
if "cross-system" in technique or "cross system" in technique:
|
|
return "cross_system"
|
|
if any(token in technique for token in ("western", "solar return", "secondary progression", "solar arc", "midpoint")):
|
|
return "western"
|
|
return "jyotish"
|
|
|
|
def _normalize_audit_row(self, row: dict[str, Any]) -> dict[str, Any]:
|
|
normalized = dict(row)
|
|
status = str(normalized.get("status") or "unknown").lower()
|
|
normalized["system"] = str(normalized.get("system") or self._infer_technique_system(normalized))
|
|
normalized["confidence_label"] = str(normalized.get("confidence_label") or {
|
|
"executed": "multi_system_consensus", "used": "multi_system_consensus", "complete": "multi_system_consensus",
|
|
"partial": "parameter_sensitive", "research_only": "parameter_sensitive", "blocked": "blocked",
|
|
}.get(status, "single_system_inference"))
|
|
normalized["user_visible_summary"] = str(normalized.get("user_visible_summary") or f"{normalized.get('technique') or normalized.get('name') or 'Technique'} · {normalized['system']} · {status}")
|
|
return normalized
|
|
|
|
@staticmethod
|
|
def _audit_overview(rows: list[dict[str, Any]]) -> dict[str, Any]:
|
|
statuses: dict[str, int] = {}
|
|
systems: dict[str, int] = {}
|
|
for row in rows:
|
|
status, system = str(row.get("status") or "unknown").lower(), str(row.get("system") or "unknown").lower()
|
|
statuses[status] = statuses.get(status, 0) + 1
|
|
systems[system] = systems.get(system, 0) + 1
|
|
return {"status_counts": statuses, "system_counts": systems, "blocked_count": statuses.get("blocked", 0)}
|
|
|
|
def build_reader_report(
|
|
self,
|
|
route_profile: dict[str, Any],
|
|
theme_reports: dict[str, Any],
|
|
raw_data: Any = None,
|
|
technique_audit: list[dict[str, Any]] | None = None,
|
|
conflicts: list[Any] | None = None,
|
|
) -> dict[str, Any]:
|
|
"""Build summary -> narrative -> appendix while preserving blocked truth."""
|
|
audit_rows = [self._normalize_audit_row(row) for row in list(technique_audit or [])]
|
|
narrative: dict[str, Any] = {}
|
|
for theme, report in theme_reports.items():
|
|
item = dict(report) if isinstance(report, dict) else {"summary": str(report)}
|
|
blocked = str(item.get("status") or "").lower() == "blocked" or any(
|
|
str(row.get("status") or "").lower() == "blocked" and self._audit_applies_to_theme(row, theme)
|
|
for row in audit_rows
|
|
)
|
|
for field, value in list(item.items()):
|
|
if isinstance(value, str):
|
|
item[field] = self._deduplicate_sentences(self._suppress_definitive_claims(value) if blocked else value)
|
|
views = {
|
|
"jyotish": item.get("jyotish_summary") or item.get("vedic_summary"),
|
|
"western": item.get("western_summary"),
|
|
"consensus": item.get("consensus_summary") or item.get("cross_system_summary"),
|
|
}
|
|
if any(views.values()):
|
|
item["system_views"] = {key: value for key, value in views.items() if value}
|
|
narrative[theme] = item
|
|
dispatch = route_profile.get("varga_dispatch") if isinstance(route_profile.get("varga_dispatch"), dict) else {}
|
|
return {
|
|
"executive_summary": {
|
|
"themes": list(route_profile.get("themes") or []),
|
|
"presentation_mode": route_profile.get("presentation_mode") or "default",
|
|
"selected_theme_vargas": list(dispatch.get("selected_theme_vargas") or []),
|
|
},
|
|
"thematic_narrative": narrative,
|
|
"evidence_appendix": {
|
|
"expanded": bool(route_profile.get("appendix_expanded")),
|
|
"raw_data": raw_data,
|
|
"technique_audit": audit_rows,
|
|
"audit_overview": self._audit_overview(audit_rows),
|
|
"blocked_techniques": [str(row.get("technique") or row.get("name") or "unknown") for row in audit_rows if str(row.get("status") or "").lower() == "blocked"],
|
|
"conflicts": list(conflicts or []),
|
|
"varga_dispatch": dispatch,
|
|
},
|
|
}
|
|
|
|
def _build_key_time_nodes(
|
|
self,
|
|
route_profile: dict[str, Any],
|
|
narrative: dict[str, Any],
|
|
) -> list[dict[str, Any]]:
|
|
themes = list(route_profile.get("themes") or narrative.keys())
|
|
nodes: list[dict[str, Any]] = []
|
|
for theme in themes:
|
|
item = narrative.get(theme)
|
|
if not isinstance(item, dict):
|
|
continue
|
|
for section in ("timing_windows", "candidate_windows", "opportunity_windows"):
|
|
raw_nodes = item.get(section)
|
|
if not isinstance(raw_nodes, list):
|
|
continue
|
|
for raw_node in raw_nodes:
|
|
normalized = self._normalize_key_time_node(theme, section, raw_node)
|
|
if normalized:
|
|
nodes.append(normalized)
|
|
return nodes[:7]
|
|
|
|
@staticmethod
|
|
def _normalize_key_time_node(theme: str, section: str, raw_node: Any) -> dict[str, Any] | None:
|
|
if isinstance(raw_node, str):
|
|
text = raw_node.strip()
|
|
if not text:
|
|
return None
|
|
return {
|
|
"theme": theme,
|
|
"section": section,
|
|
"label": text,
|
|
"window": text,
|
|
"status": "parameter_sensitive",
|
|
}
|
|
if not isinstance(raw_node, dict):
|
|
return None
|
|
label = str(
|
|
raw_node.get("label")
|
|
or raw_node.get("title")
|
|
or raw_node.get("name")
|
|
or raw_node.get("window")
|
|
or raw_node.get("date_range")
|
|
or raw_node.get("date")
|
|
or ""
|
|
).strip()
|
|
window = str(
|
|
raw_node.get("window")
|
|
or raw_node.get("date_range")
|
|
or raw_node.get("date")
|
|
or raw_node.get("timeframe")
|
|
or label
|
|
).strip()
|
|
if not label and not window:
|
|
return None
|
|
node = {
|
|
"theme": theme,
|
|
"section": section,
|
|
"label": label or window,
|
|
"window": window or label,
|
|
"status": str(raw_node.get("status") or "parameter_sensitive"),
|
|
}
|
|
for key in ("strength", "basis", "trigger_condition", "verification_hint", "source", "priority"):
|
|
value = raw_node.get(key)
|
|
if value not in (None, "", [], {}):
|
|
node[key] = value
|
|
return node
|
|
|
|
def shared_contract(
|
|
self,
|
|
*,
|
|
entry_mode: str,
|
|
question: str,
|
|
themes: list[str],
|
|
route_packet: dict[str, Any],
|
|
surface: str,
|
|
) -> dict[str, Any]:
|
|
return {
|
|
"name": self.NAME,
|
|
"surface": surface,
|
|
"entry_mode": entry_mode,
|
|
"question": question or "",
|
|
"themes": list(themes),
|
|
"route": dict(route_packet),
|
|
"route_profile_contract": self.route_profile_contract(str(route_packet.get("question_type") or "general")),
|
|
"source_priority": {
|
|
"mode": self.SOURCE_PRIORITY["mode"],
|
|
"priority": list(self.SOURCE_PRIORITY["priority"]),
|
|
"boundary": self.SOURCE_PRIORITY["boundary"],
|
|
},
|
|
"shared_capabilities": [
|
|
"theme_normalization",
|
|
"question_routing",
|
|
"vedastro_official_priority",
|
|
"rectification_gate_reuse",
|
|
"thematic_report_reuse",
|
|
],
|
|
}
|
|
|
|
def runtime_planner(
|
|
self,
|
|
*,
|
|
entry_mode: str,
|
|
question: str,
|
|
themes: list[str],
|
|
route_packet: dict[str, Any],
|
|
events: list[dict[str, Any]] | None,
|
|
surface: str,
|
|
high_rigor: bool,
|
|
) -> dict[str, Any]:
|
|
route_name = route_packet.get("question_type") or "general"
|
|
sync_steps = list(self._SYNC_STEPS_BY_ROUTE.get(route_name, self._SYNC_STEPS_BY_ROUTE["general"]))
|
|
if entry_mode == "rectification":
|
|
sync_steps = [step for step in sync_steps if step != "run_rectification_gate"]
|
|
sync_steps.insert(0, "run_rectification_gate")
|
|
elif entry_mode == "prashna":
|
|
sync_steps = [step for step in sync_steps if step not in {"compute_chart", "run_rectification_gate"}]
|
|
sync_steps.insert(0, "run_prashna")
|
|
if high_rigor and "run_historical_event_backtest" not in sync_steps and events:
|
|
sync_steps.append("run_historical_event_backtest")
|
|
|
|
async_candidates = list(self._ASYNC_CANDIDATES)
|
|
if not events:
|
|
async_candidates = [step for step in async_candidates if step != "historical_event_backtest"]
|
|
|
|
return {
|
|
"planner_name": "UnifiedConsultationRuntimePlanner",
|
|
"surface": surface,
|
|
"entry_mode": entry_mode,
|
|
"high_rigor": bool(high_rigor),
|
|
"route": dict(route_packet),
|
|
"question_context": {
|
|
"question": question or "",
|
|
"themes": list(themes),
|
|
"event_count": len(events or []),
|
|
},
|
|
"sync_steps": sync_steps,
|
|
"async_candidates": async_candidates,
|
|
"source_priority": {
|
|
"mode": self.SOURCE_PRIORITY["mode"],
|
|
"priority": list(self.SOURCE_PRIORITY["priority"]),
|
|
"boundary": self.SOURCE_PRIORITY["boundary"],
|
|
},
|
|
"reuse_contract": {
|
|
"chart": "compute_chart",
|
|
"rectification": "rectification_gate",
|
|
"thematic_report": "thematic_report",
|
|
"historical_backtest": "historical_event_backtest",
|
|
},
|
|
"boundary": (
|
|
"This runtime planner unifies entry routing and module reuse. It does not imply that every VedAstro "
|
|
"catalog method executes on every request; route-relevant official evidence is still subject to live "
|
|
"availability, cache policy, and async limits."
|
|
),
|
|
}
|
|
|
|
@staticmethod
|
|
def _vedastro_cloud_state(vedastro_official: dict[str, Any] | None) -> str:
|
|
official = vedastro_official if isinstance(vedastro_official, dict) else {}
|
|
runtime_truth = official.get("runtime_truth") if isinstance(official.get("runtime_truth"), dict) else {}
|
|
layers = runtime_truth.get("official_execution_layers") if isinstance(runtime_truth.get("official_execution_layers"), dict) else {}
|
|
status = str(runtime_truth.get("status") or official.get("status") or "blocked")
|
|
fallback_active = bool(runtime_truth.get("fallback_active") or official.get("fallback_used"))
|
|
if fallback_active:
|
|
return "local_fallback"
|
|
if layers.get("chart_core") == "ok" and status in {"ok", "partial", "available"}:
|
|
return "official_verified"
|
|
return "official_blocked"
|
|
|
|
@staticmethod
|
|
def _named_varga_chart(varga: dict[str, Any], division: int) -> Any:
|
|
exact = f"D{division}"
|
|
if exact in varga:
|
|
return varga[exact]
|
|
prefix = f"D{division}_"
|
|
for key, value in varga.items():
|
|
if not isinstance(key, str) or not key.startswith(prefix):
|
|
continue
|
|
rest = key[len(prefix):]
|
|
if rest and not rest[0].isdigit():
|
|
return value
|
|
return None
|
|
|
|
@staticmethod
|
|
def _section(value: Any, source_path: str) -> dict[str, Any]:
|
|
present = bool(value)
|
|
return {
|
|
"status": "used" if present else "missing",
|
|
"source_path": source_path,
|
|
}
|
|
|
|
@staticmethod
|
|
def _build_professional_support_cross_reference(narrative: dict[str, Any]) -> dict[str, Any]:
|
|
topics: dict[str, Any] = {}
|
|
support_statuses: list[str] = []
|
|
for theme, item in narrative.items():
|
|
if not isinstance(item, dict):
|
|
continue
|
|
system_views = item.get("system_views") if isinstance(item.get("system_views"), dict) else {}
|
|
support_topics = sorted(system_views)
|
|
if system_views:
|
|
support_statuses.append(str(item.get("status") or "used"))
|
|
topics[theme] = {
|
|
"status": str(item.get("status") or "used"),
|
|
"system_views": system_views,
|
|
"support_topics": support_topics,
|
|
"summary": item.get("summary") or item.get("consensus_summary") or "",
|
|
}
|
|
return {
|
|
"status": "used" if support_statuses else "blocked",
|
|
"topics": topics,
|
|
"supported_theme_count": len(support_statuses),
|
|
}
|
|
|
|
@staticmethod
|
|
def _build_restricted_materials_reference(audit_rows: list[dict[str, Any]]) -> dict[str, Any]:
|
|
blocked = [
|
|
str(row.get("technique") or row.get("name") or "unknown")
|
|
for row in audit_rows
|
|
if str(row.get("report_adoption") or row.get("status") or "").lower() == "blocked"
|
|
]
|
|
conditional = [
|
|
str(row.get("technique") or row.get("name") or "unknown")
|
|
for row in audit_rows
|
|
if str(row.get("report_adoption") or "").lower() == "conditional_evidence"
|
|
]
|
|
return {
|
|
"status": "used" if blocked or conditional else "blocked",
|
|
"blocked_techniques": blocked,
|
|
"conditional_evidence": conditional,
|
|
"blocked_count": len(blocked),
|
|
"conditional_count": len(conditional),
|
|
}
|
|
|
|
@staticmethod
|
|
def _external_engine_cross_validation(vedastro_state: str) -> dict[str, Any]:
|
|
repo_root = Path(__file__).resolve().parents[1]
|
|
pyjhora_refs = [
|
|
repo_root / "docs/benchmark/jyotish_external_oracle_closure_master_dashboard.json",
|
|
repo_root / "references/oracle/artifacts/pyjhora_oracle_artifact_manifest.json",
|
|
]
|
|
pyjhora_adapter = repo_root / "benchmarks/jyotish/scripts/run_pyjhora_compare.py"
|
|
pyjhora_adapter_report = build_pyjhora_adapter_report()
|
|
pyjhora_adapter_status = {
|
|
"available": "available",
|
|
"missing_dependency": f"blocked_missing_python_module:{pyjhora_adapter_report.get('missing_dependency') or 'jhora'}",
|
|
"missing_adapter": "blocked_missing_adapter_script",
|
|
}.get(str(pyjhora_adapter_report.get("status")), "runtime_error")
|
|
jyotishganit_ref = repo_root / "references/open_source_sources/jyotishganit"
|
|
jyotishganit_adapter_report = build_jyotishganit_adapter_report()
|
|
|
|
engines = {
|
|
"VedAstro": {
|
|
"status": vedastro_state,
|
|
"runtime_invoked": vedastro_state == "official_verified",
|
|
"source_path": "vedastro_official.runtime_truth",
|
|
},
|
|
"PyJHora/JHora": {
|
|
"status": (
|
|
"reference_available_not_runtime_invoked"
|
|
if any(path.exists() for path in pyjhora_refs)
|
|
else "blocked_no_reference_artifact"
|
|
),
|
|
"runtime_invoked": False,
|
|
"adapter_command": (
|
|
"python3 benchmarks/jyotish/scripts/run_pyjhora_compare.py"
|
|
if pyjhora_adapter.exists()
|
|
else None
|
|
),
|
|
"adapter_status": pyjhora_adapter_status,
|
|
"source_path": "docs/benchmark + references/oracle/artifacts",
|
|
},
|
|
"jyotishganit": {
|
|
"status": (
|
|
"reference_available_not_runtime_invoked"
|
|
if jyotishganit_ref.exists()
|
|
else "blocked_no_reference_checkout"
|
|
),
|
|
"runtime_invoked": False,
|
|
"adapter_path": "references/open_source_sources/jyotishganit" if jyotishganit_ref.exists() else None,
|
|
"adapter_status": jyotishganit_adapter_report.get("status"),
|
|
"license": jyotishganit_adapter_report.get("license"),
|
|
"source_path": "references/open_source_sources/jyotishganit",
|
|
},
|
|
}
|
|
status = "complete" if all(item["runtime_invoked"] for item in engines.values()) else "partial"
|
|
return {
|
|
"status": status,
|
|
"engines": engines,
|
|
"boundary": (
|
|
"This records runtime/reference closure state only. Reference artifacts do not mean the engine was "
|
|
"invoked for the current consultation."
|
|
),
|
|
}
|
|
|
|
def machine_evidence_packet(
|
|
self,
|
|
*,
|
|
chart: dict[str, Any] | None,
|
|
route_packet: dict[str, Any],
|
|
vedastro_official: dict[str, Any] | None = None,
|
|
vedastro_archive_manifest: dict[str, Any] | None = None,
|
|
) -> dict[str, Any]:
|
|
chart_data = chart if isinstance(chart, dict) else {}
|
|
modules = chart_data.get("modules") if isinstance(chart_data.get("modules"), dict) else {}
|
|
nested_chart = chart_data.get("chart") if isinstance(chart_data.get("chart"), dict) else {}
|
|
base_chart = modules.get("chart") if isinstance(modules.get("chart"), dict) else nested_chart or chart_data
|
|
varga = modules.get("varga_full") if isinstance(modules.get("varga_full"), dict) else {}
|
|
special_lagnas = (
|
|
chart_data.get("special_lagnas")
|
|
if isinstance(chart_data.get("special_lagnas"), dict)
|
|
else modules.get("special_lagnas") if isinstance(modules.get("special_lagnas"), dict) else {}
|
|
)
|
|
arudha_padas = (
|
|
chart_data.get("arudha_padas")
|
|
if isinstance(chart_data.get("arudha_padas"), dict)
|
|
else modules.get("arudha_padas") if isinstance(modules.get("arudha_padas"), dict) else {}
|
|
)
|
|
if not arudha_padas and isinstance(modules.get("jaimini"), dict):
|
|
jaimini_arudha = modules["jaimini"].get("arudha_padas")
|
|
arudha_padas = jaimini_arudha if isinstance(jaimini_arudha, dict) else {}
|
|
pada_map = arudha_padas.get("padas") if isinstance(arudha_padas.get("padas"), dict) else arudha_padas
|
|
jaimini_packet = (
|
|
chart_data.get("jaimini")
|
|
if isinstance(chart_data.get("jaimini"), dict)
|
|
else modules.get("jaimini") if isinstance(modules.get("jaimini"), dict) else {}
|
|
)
|
|
sudarshana_packet = (
|
|
chart_data.get("sudarshana")
|
|
if isinstance(chart_data.get("sudarshana"), dict)
|
|
else modules.get("sudarshana") if isinstance(modules.get("sudarshana"), dict) else {}
|
|
)
|
|
sahams_packet = (
|
|
chart_data.get("sahams")
|
|
if isinstance(chart_data.get("sahams"), dict)
|
|
else modules.get("sahams") if isinstance(modules.get("sahams"), dict) else {}
|
|
)
|
|
ascendant = base_chart.get("ascendant") if isinstance(base_chart.get("ascendant"), dict) else {}
|
|
ascendant_sign = ascendant.get("sign") if isinstance(ascendant, dict) else None
|
|
functional_layer = derive_functional_benefic_malefic(ascendant_sign)
|
|
official = vedastro_official if isinstance(vedastro_official, dict) else {}
|
|
archive_manifest = vedastro_archive_manifest if isinstance(vedastro_archive_manifest, dict) else {}
|
|
raw_response = (
|
|
official.get("raw_response")
|
|
or official.get("official_raw_response")
|
|
or official.get("raw_payload")
|
|
or official.get("raw")
|
|
)
|
|
official_state = self._vedastro_cloud_state(vedastro_official)
|
|
route_name = str(
|
|
(route_packet or {}).get("question_type")
|
|
or (route_packet or {}).get("primary_theme")
|
|
or "general"
|
|
)
|
|
raw_response_section = (
|
|
self._section(raw_response, "vedastro_official.raw_response")
|
|
if official_state == "official_verified"
|
|
else {
|
|
"status": "received_unverified" if raw_response else "missing",
|
|
"source_path": "vedastro_official.raw_response",
|
|
}
|
|
)
|
|
sections = {
|
|
"D1": self._section(
|
|
base_chart.get("planets") and base_chart.get("ascendant"),
|
|
"chart.planets+chart.ascendant",
|
|
),
|
|
"D9": self._section(self._named_varga_chart(varga, 9), "modules.varga_full.D9"),
|
|
"D10": self._section(self._named_varga_chart(varga, 10), "modules.varga_full.D10"),
|
|
"D2": self._section(self._named_varga_chart(varga, 2), "modules.varga_full.D2"),
|
|
"D4": self._section(self._named_varga_chart(varga, 4), "modules.varga_full.D4"),
|
|
"planet_degrees": self._section(base_chart.get("planets"), "chart.planets"),
|
|
"house_degrees": self._section(base_chart.get("houses") or chart_data.get("houses"), "chart.houses"),
|
|
"dasha_boundaries": self._section(modules.get("dasha") or chart_data.get("dasha"), "modules.dasha"),
|
|
# The mahadasha list above and the antardasha cut below are different claims: one says
|
|
# which decade, the other which months. They are separate sections so that an answer
|
|
# policy can require the second without the first standing in for it.
|
|
"dasha_sub_periods": self._section(modules.get("dasha_sub_periods"), "modules.dasha_sub_periods"),
|
|
"narayana_dasha": self._section(modules.get("narayana_dasha"), "modules.narayana_dasha"),
|
|
"shadbala": self._section(modules.get("shadbala") or chart_data.get("shadbala"), "modules.shadbala"),
|
|
"ashtakavarga": self._section(modules.get("ashtakavarga") or chart_data.get("ashtakavarga"), "modules.ashtakavarga"),
|
|
"yogas": self._section(modules.get("yogas") or chart_data.get("yogas"), "modules.yogas"),
|
|
"UL": self._section(
|
|
pada_map.get("UL")
|
|
or arudha_padas.get("upapada")
|
|
or special_lagnas.get("UL")
|
|
or special_lagnas.get("Upapada_Lagna"),
|
|
"modules.arudha_padas.UL",
|
|
),
|
|
"A7": self._section(
|
|
pada_map.get("A7") or special_lagnas.get("A7") or special_lagnas.get("Darapada"),
|
|
"modules.arudha_padas.A7",
|
|
),
|
|
"A10": self._section(
|
|
pada_map.get("A10") or special_lagnas.get("A10") or special_lagnas.get("A10_Karma_Pada"),
|
|
"modules.arudha_padas.A10",
|
|
),
|
|
"KP_cusp": self._section(modules.get("kp") or modules.get("kp_cusps") or chart_data.get("kp_cusps"), "modules.kp_cusps"),
|
|
"functional_benefic_malefic": self._section(
|
|
functional_layer if functional_layer.get("status") == "used" else None,
|
|
"chart.ascendant.sign -> scripts.functional_benefics",
|
|
),
|
|
"external_oracle_status": {
|
|
"status": official_state,
|
|
"source_path": "vedastro_official.runtime_truth",
|
|
},
|
|
"vedastro_official_raw_response": raw_response_section,
|
|
"vedastro_official_raw_archive_manifest": self._section(
|
|
archive_manifest if archive_manifest.get("archive_count") else None,
|
|
"vedastro_gateway.archives",
|
|
),
|
|
"jaimini": self._section(jaimini_packet, "chart.modules.jaimini"),
|
|
"sudarshana": self._section(sudarshana_packet, "chart.modules.sudarshana"),
|
|
"sahams": self._section(sahams_packet, "chart.modules.sahams"),
|
|
}
|
|
if route_name == "health":
|
|
transits = modules.get("transits") if isinstance(modules.get("transits"), dict) else {}
|
|
sections["transit"] = {
|
|
"status": (
|
|
"used"
|
|
if str(transits.get("status") or "").lower() in {"executed", "used", "ready"}
|
|
else "blocked"
|
|
),
|
|
"source_path": "modules.transits",
|
|
}
|
|
sections["non_medical_boundary"] = {
|
|
"status": "used",
|
|
"source_path": "route_profile_contract.health.non_medical_boundary",
|
|
}
|
|
for division in FORMAL_DIVISIONS:
|
|
if division == 1:
|
|
continue
|
|
key = f"D{division}"
|
|
if key not in sections:
|
|
sections[key] = self._section(
|
|
self._named_varga_chart(varga, division),
|
|
f"modules.varga_full.{key}",
|
|
)
|
|
spectrum = modules.get("varga_spectrum") if isinstance(modules.get("varga_spectrum"), dict) else {}
|
|
sections["varga_spectrum"] = self._section(
|
|
spectrum if spectrum.get("status") == "used" else None,
|
|
"modules.varga_spectrum",
|
|
)
|
|
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": self.evidence_packet_required_sections(route_name),
|
|
"sections": sections,
|
|
"functional_benefic_malefic": functional_layer,
|
|
"signals": [item for item in signals if isinstance(item, dict)],
|
|
"missing_sections": missing,
|
|
}
|
|
|
|
def real_case_calibration_catalog(
|
|
self,
|
|
*,
|
|
route_packet: dict[str, Any],
|
|
machine_evidence_packet: dict[str, Any] | None = None,
|
|
) -> dict[str, Any]:
|
|
route = normalize_domain(route_packet.get("question_type") or route_packet.get("primary_theme") or "general")
|
|
case_index_by_domain = {
|
|
"career": ["references/real_case_studies/vedicka/career-success-poverty-prosperity.md"],
|
|
"wealth": ["references/real_case_studies/vedicka/career-success-poverty-prosperity.md"],
|
|
"marriage": ["docs/benchmark/legacy-marriage-v6.1/verify-results-v6.1.json"],
|
|
}
|
|
case_profiles = {
|
|
"references/real_case_studies/vedicka/career-success-poverty-prosperity.md": {
|
|
"domains": ["career", "wealth"],
|
|
"evidence_sections": ["D1", "D10", "dasha_boundaries", "yogas"],
|
|
"recorded_outcome": "poverty_to_prosperity_global_recognition",
|
|
"event_trigger_keywords": ["Saturn dasha poverty", "Mercury dasha breakthrough", "Ketu dasha consolidation"],
|
|
},
|
|
"docs/benchmark/legacy-marriage-v6.1/verify-results-v6.1.json": {
|
|
"domains": ["marriage"],
|
|
"evidence_sections": ["D1", "D9", "UL", "dasha_boundaries"],
|
|
"recorded_outcome": "relationship_structure_validation_dataset",
|
|
"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)
|
|
holdout_manifest_path = Path(__file__).resolve().parents[1] / "references/real_case_calibration/replay_manifest_holdout_v2.json"
|
|
holdout_manifest = (
|
|
validate_real_case_replay_manifest(holdout_manifest_path)
|
|
if holdout_manifest_path.exists()
|
|
else {
|
|
"status": "blocked",
|
|
"case_count": 0,
|
|
"replay_ready_count": 0,
|
|
"blocked_reason": "holdout_replay_manifest_missing",
|
|
"path": "references/real_case_calibration/replay_manifest_holdout_v2.json",
|
|
}
|
|
)
|
|
benchmark_path = Path(__file__).resolve().parents[1] / "docs/benchmark/public_real_case_20_case_closure_2026_07_11.json"
|
|
if benchmark_path.exists():
|
|
benchmark_payload = json.loads(benchmark_path.read_text(encoding="utf-8"))
|
|
public_outcome_benchmark = {
|
|
"status": "used",
|
|
"path": "docs/benchmark/public_real_case_20_case_closure_2026_07_11.json",
|
|
"summary": benchmark_payload.get("summary") or {},
|
|
"method": benchmark_payload.get("method") or {},
|
|
"strict_workflow_batch": benchmark_payload.get("strict_workflow_batch") or {},
|
|
"holdout_promotion": benchmark_payload.get("holdout_promotion") or {},
|
|
"technique_debt": benchmark_payload.get("technique_debt") or {},
|
|
}
|
|
else:
|
|
public_outcome_benchmark = {
|
|
"status": "blocked",
|
|
"path": "docs/benchmark/public_real_case_20_case_closure_2026_07_11.json",
|
|
"blocked_reason": "public_outcome_benchmark_missing",
|
|
}
|
|
supplemental_path = Path(__file__).resolve().parents[1] / "docs/benchmark/public_real_case_probe3_v2_2026_07_11.json"
|
|
combined_observation_path = Path(__file__).resolve().parents[1] / "docs/benchmark/public_real_case_23_case_observation_2026_07_11.json"
|
|
if supplemental_path.exists() and combined_observation_path.exists():
|
|
supplemental_payload = json.loads(supplemental_path.read_text(encoding="utf-8"))
|
|
combined_payload = json.loads(combined_observation_path.read_text(encoding="utf-8"))
|
|
supplemental_public_probe = {
|
|
"status": "used",
|
|
"path": "docs/benchmark/public_real_case_probe3_v2_2026_07_11.json",
|
|
"summary": supplemental_payload.get("summary") or {},
|
|
"combined_observation": combined_payload.get("summary") or {},
|
|
"boundary": "Three-case independent probe is contradictory generalization evidence, not a promotion or accuracy estimate.",
|
|
}
|
|
else:
|
|
supplemental_public_probe = {
|
|
"status": "blocked",
|
|
"blocked_reason": "supplemental_public_probe_missing",
|
|
}
|
|
corrected_v21_path = Path(__file__).resolve().parents[1] / "docs/benchmark/public_real_case_23_case_v21_corrected_observation_2026_07_11.json"
|
|
if corrected_v21_path.exists():
|
|
corrected_payload = json.loads(corrected_v21_path.read_text(encoding="utf-8"))
|
|
corrected_v21_observation = {
|
|
"status": "used",
|
|
"path": "docs/benchmark/public_real_case_23_case_v21_corrected_observation_2026_07_11.json",
|
|
"summary": corrected_payload.get("summary") or {},
|
|
"domain_summaries": corrected_payload.get("domain_summaries") or {},
|
|
"ashtakavarga_audit_status": corrected_payload.get("ashtakavarga_audit_status"),
|
|
"ashtakavarga_descriptive": corrected_payload.get("ashtakavarga_descriptive") or {},
|
|
"boundary": corrected_payload.get("boundary"),
|
|
}
|
|
else:
|
|
corrected_v21_observation = {
|
|
"status": "blocked",
|
|
"blocked_reason": "corrected_v21_observation_missing",
|
|
}
|
|
negative_control_path = Path(__file__).resolve().parents[1] / "docs/benchmark/public_real_case_negative_control_pilot_2026_07_11.json"
|
|
if negative_control_path.exists():
|
|
negative_payload = json.loads(negative_control_path.read_text(encoding="utf-8"))
|
|
negative_summary = negative_payload.get("summary") or {}
|
|
negative_control_pilot = {
|
|
"status": "used",
|
|
"path": "docs/benchmark/public_real_case_negative_control_pilot_2026_07_11.json",
|
|
"summary": negative_summary,
|
|
"boundary": negative_payload.get("boundary"),
|
|
}
|
|
else:
|
|
negative_control_pilot = {
|
|
"status": "blocked",
|
|
"blocked_reason": "negative_control_pilot_missing",
|
|
}
|
|
negative_summary = {}
|
|
annual_control_path = Path(__file__).resolve().parents[1] / "docs/benchmark/public_real_case_annual_control_pilot_2026_07_11.json"
|
|
if annual_control_path.exists():
|
|
annual_payload = json.loads(annual_control_path.read_text(encoding="utf-8"))
|
|
annual_control_pilot = {
|
|
"status": "used",
|
|
"path": "docs/benchmark/public_real_case_annual_control_pilot_2026_07_11.json",
|
|
"summary": annual_payload.get("summary") or {},
|
|
"boundary": annual_payload.get("boundary"),
|
|
}
|
|
else:
|
|
annual_control_pilot = {
|
|
"status": "blocked",
|
|
"blocked_reason": "annual_control_pilot_missing",
|
|
}
|
|
if negative_control_pilot.get("status") == "used" and annual_control_pilot.get("status") == "used":
|
|
timing_precision_gate = {
|
|
"status": "blocked",
|
|
"maximum_supported_precision": "unvalidated_broad_window",
|
|
"blocked_claims": ["exact_day", "exact_month_from_current_replay_score"],
|
|
"domain_support": {"career": "blocked", "marriage": "partial_candidate"},
|
|
"reason": "near_and_annual_control_rankings_below_gate",
|
|
"observed_positive_top_1_rate": negative_summary.get("positive_top_1_rate"),
|
|
"observed_positive_top_3_rate": negative_summary.get("positive_top_3_rate"),
|
|
"annual_positive_top_1_rate": (annual_control_pilot.get("summary") or {}).get("positive_top_1_rate"),
|
|
}
|
|
else:
|
|
timing_precision_gate = {
|
|
"status": "blocked",
|
|
"maximum_supported_precision": "unvalidated_broad_window",
|
|
"blocked_claims": ["exact_day", "exact_month_from_current_replay_score"],
|
|
"domain_support": {"career": "blocked", "marriage": "partial_candidate"},
|
|
"reason": "control_pilot_missing",
|
|
}
|
|
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 {}
|
|
used_sections = {name for name, section in sections.items() if isinstance(section, dict) and section.get("status") == "used"}
|
|
dasha_used = "dasha_boundaries" in used_sections
|
|
external_oracle_status = (
|
|
sections.get("external_oracle_status", {}).get("status")
|
|
if isinstance(sections.get("external_oracle_status"), dict)
|
|
else "missing"
|
|
)
|
|
scored_candidates = []
|
|
for ref in candidate_refs:
|
|
profile = case_profiles.get(ref, {"domains": [], "evidence_sections": []})
|
|
overlap = sorted(used_sections & set(profile["evidence_sections"]))
|
|
trigger_score = (10 if dasha_used else 0) + (10 if external_oracle_status == "official_verified" else 0)
|
|
score = (50 if route in profile["domains"] else 0) + min(30, len(overlap) * 5) + trigger_score
|
|
scored_candidates.append({
|
|
"case_source": ref,
|
|
"score": score,
|
|
"reference_grade": "partial_reference" if score >= 50 else "reference_only",
|
|
"recorded_outcome": profile.get("recorded_outcome"),
|
|
"similarities": {
|
|
"route_match": route in profile["domains"],
|
|
"evidence_section_overlap": overlap,
|
|
},
|
|
"differences": {
|
|
"unmatched_required_sections": sorted(set(profile["evidence_sections"]) - used_sections),
|
|
},
|
|
"event_trigger_match": {
|
|
"status": (
|
|
"partial_match_official_timing_available"
|
|
if dasha_used and external_oracle_status == "official_verified"
|
|
else "partial_match_official_timing_blocked"
|
|
if dasha_used
|
|
else "not_matched_missing_dasha"
|
|
),
|
|
"checks": {
|
|
"dasha_boundaries": "used" if dasha_used else "missing",
|
|
"external_oracle_status": external_oracle_status,
|
|
"recorded_trigger_keywords": list(profile.get("event_trigger_keywords", [])),
|
|
},
|
|
"boundary": "Trigger check uses available timing evidence only; it is not event outcome validation.",
|
|
},
|
|
"outcome_validation": {
|
|
"status": "local_outcome_recorded_trigger_not_replayed",
|
|
"recorded_outcome": profile.get("recorded_outcome"),
|
|
"boundary": "Outcome is read from the local case source profile; this does not replay the case chart or prove similarity.",
|
|
},
|
|
})
|
|
return {
|
|
"status": "partial_scored" if scored_candidates else "catalog_available_matching_not_run",
|
|
"batch_id": "real_case_studies_batch1",
|
|
"route": route,
|
|
"source_roots": ["references/real_case_studies", "references/real_case_calibration", "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,
|
|
"holdout_replay_manifest": holdout_manifest,
|
|
"public_outcome_benchmark": public_outcome_benchmark,
|
|
"supplemental_public_probe": supplemental_public_probe,
|
|
"corrected_v21_observation": corrected_v21_observation,
|
|
"negative_control_pilot": negative_control_pilot,
|
|
"annual_control_pilot": annual_control_pilot,
|
|
"timing_precision_gate": timing_precision_gate,
|
|
"candidate_refs": list(candidate_refs),
|
|
"scored_candidates": scored_candidates,
|
|
"reference_grade": scored_candidates[0]["reference_grade"] if scored_candidates else "ungraded_until_similarity_scored",
|
|
"boundary": (
|
|
"The public benchmark replays twenty dated outcomes, including a frozen ten-case holdout, but it contains positive events only. It can "
|
|
"measure activation recall, not specificity or scientific predictive accuracy; user-chart "
|
|
"similarity still requires separate structured matching."
|
|
),
|
|
}
|
|
|
|
def runtime_evidence_log(
|
|
self,
|
|
*,
|
|
surface: str,
|
|
entry_mode: str,
|
|
route_packet: dict[str, Any],
|
|
executed_steps: list[str],
|
|
skipped_steps: list[str],
|
|
vedastro_official: dict[str, Any] | None = None,
|
|
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 {}
|
|
route_name = str(route_packet.get("question_type") or route_packet.get("primary_theme") or "general")
|
|
runtime_truth = official.get("runtime_truth") if isinstance(official.get("runtime_truth"), dict) else {}
|
|
vedastro_state = self._vedastro_cloud_state(official)
|
|
external_cross_validation = self._external_engine_cross_validation(vedastro_state)
|
|
blocked_items: list[str] = []
|
|
if vedastro_state != "official_verified":
|
|
blocked_items.append("vedastro_official_raw_snapshot_not_verified")
|
|
if external_cross_validation["status"] != "complete":
|
|
blocked_items.append("external_engine_cross_validation_partial")
|
|
packet = machine_evidence_packet if isinstance(machine_evidence_packet, dict) else {}
|
|
packet_status = packet.get("status") or "required_not_satisfied"
|
|
packet_sections = packet.get("sections") if isinstance(packet.get("sections"), dict) else {}
|
|
archive_section = packet_sections.get("vedastro_official_raw_archive_manifest")
|
|
archive_status = (
|
|
archive_section.get("status")
|
|
if isinstance(archive_section, dict)
|
|
else "required_not_satisfied"
|
|
)
|
|
if not packet:
|
|
blocked_items.append("machine_evidence_packet_not_yet_materialized")
|
|
elif packet_status != "complete":
|
|
blocked_items.append("machine_evidence_packet_partial")
|
|
if archive_status != "used":
|
|
blocked_items.append("vedastro_official_raw_archive_manifest_missing")
|
|
case_packet = real_case_calibration if isinstance(real_case_calibration, dict) else {}
|
|
case_status = case_packet.get("status") or "required_not_satisfied"
|
|
timing_precision = case_packet.get("timing_precision_gate") if isinstance(case_packet.get("timing_precision_gate"), dict) else {}
|
|
timing_precision_status = timing_precision.get("status") or "blocked"
|
|
functional_packet = packet.get("functional_benefic_malefic") if isinstance(packet.get("functional_benefic_malefic"), dict) else {}
|
|
functional_status = functional_packet.get("status") or "blocked"
|
|
if functional_status != "used":
|
|
blocked_items.append("functional_benefic_malefic_blocked")
|
|
if not case_packet:
|
|
blocked_items.append("real_case_calibration_not_yet_materialized")
|
|
elif case_status != "complete":
|
|
blocked_items.append("real_case_calibration_partial")
|
|
if timing_precision_status != "pass":
|
|
blocked_items.append("timing_precision_gate_blocked")
|
|
cross_system_arbitration = build_cross_system_arbitration(
|
|
route_packet=route_packet,
|
|
jyotish_evidence=packet,
|
|
western_evidence=western_evidence_packet,
|
|
)
|
|
specialized_indian_closure_review = build_specialized_indian_closure_review(
|
|
jaimini_packet=packet_sections.get("jaimini"),
|
|
sudarshana_packet=packet.get("sudarshana") if isinstance(packet.get("sudarshana"), dict) else packet_sections.get("sudarshana"),
|
|
sahams_packet=packet.get("sahams") if isinstance(packet.get("sahams"), dict) else packet_sections.get("sahams"),
|
|
)
|
|
finance_astrology_support_review = build_finance_astrology_support_review(
|
|
route_packet=route_packet,
|
|
machine_evidence_packet=packet,
|
|
runtime_evidence_log={
|
|
"quality_gate": {"technique_audit_table": []},
|
|
"cross_system_arbitration": cross_system_arbitration,
|
|
},
|
|
)
|
|
if cross_system_arbitration["status"] != "used":
|
|
blocked_items.append("cross_system_arbitration_not_complete")
|
|
technique_audit_table = [
|
|
{
|
|
"technique": "VedAstro Cloud State",
|
|
"status": vedastro_state,
|
|
"used": vedastro_state == "official_verified",
|
|
"effect_on_confidence": (
|
|
"official_cloud_evidence_available"
|
|
if vedastro_state == "official_verified"
|
|
else "confidence_capped_without_verified_official_cloud"
|
|
),
|
|
},
|
|
{
|
|
"technique": "VedAstro Raw Archive Manifest",
|
|
"status": archive_status,
|
|
"used": archive_status == "used",
|
|
"effect_on_confidence": (
|
|
"official_raw_archive_is_auditable"
|
|
if archive_status == "used"
|
|
else "official_raw_archive_not_auditable_for_this_run"
|
|
),
|
|
},
|
|
{
|
|
"technique": "External Engine Cross-Validation",
|
|
"status": external_cross_validation["status"],
|
|
"used": external_cross_validation["status"] == "complete",
|
|
"effect_on_confidence": (
|
|
"three_engine_runtime_closure_available"
|
|
if external_cross_validation["status"] == "complete"
|
|
else "claims_capped_until_pyjhora_jhora_jyotishganit_are_invoked_for_this_run"
|
|
),
|
|
},
|
|
*cross_system_arbitration["technique_audit_rows"],
|
|
{
|
|
"technique": "Evidence Packet",
|
|
"status": packet_status,
|
|
"used": bool(packet),
|
|
"effect_on_confidence": "complete_packet_required_for_high_confidence" if packet_status != "complete" else "supports_high_confidence",
|
|
},
|
|
{
|
|
"technique": "Blind Technical Mode",
|
|
"status": "used" if blind else "available_not_requested",
|
|
"used": bool(blind),
|
|
"effect_on_confidence": "prevents_conversation_feedback_leakage" if blind else "normal_runtime_mode",
|
|
},
|
|
{
|
|
"technique": "MEVG / Global Web Evidence",
|
|
"status": "blocked",
|
|
"used": False,
|
|
"effect_on_confidence": "caps_claims_until_global_web_evidence_runs",
|
|
},
|
|
{
|
|
"technique": "Real Case Calibration",
|
|
"status": case_status,
|
|
"used": bool(case_packet),
|
|
"effect_on_confidence": "partial_reference_only_until_outcome_replay" if case_status != "complete" else "supports_calibration",
|
|
},
|
|
{
|
|
"technique": "Timing Precision Gate",
|
|
"status": timing_precision_status,
|
|
"used": bool(timing_precision),
|
|
"maximum_supported_precision": timing_precision.get("maximum_supported_precision", "unvalidated_broad_window"),
|
|
"blocked_claims": timing_precision.get("blocked_claims", ["exact_day", "exact_month_from_current_replay_score"]),
|
|
"domain_support": timing_precision.get("domain_support", {}),
|
|
"effect_on_confidence": "blocks_false_precision_until_control_date_rankings_pass",
|
|
},
|
|
{
|
|
"technique": "Functional Benefic/Malefic",
|
|
"status": functional_status,
|
|
"used": functional_status == "used",
|
|
"key_functional_benefics": functional_packet.get("functional_benefics", []),
|
|
"key_functional_malefics": functional_packet.get("functional_malefics", []),
|
|
"yogakarakas": functional_packet.get("yogakarakas", []),
|
|
"effect_on_confidence": functional_packet.get(
|
|
"effect_on_confidence",
|
|
"high_rigor_claims_blocked_until_functional_nature_layer_is_present",
|
|
),
|
|
},
|
|
]
|
|
return {
|
|
"name": "UnifiedConsultationRuntimeEvidenceLog",
|
|
"surface": surface,
|
|
"entry_mode": entry_mode,
|
|
"route": dict(route_packet),
|
|
"executed_steps": list(executed_steps),
|
|
"skipped_steps": list(skipped_steps),
|
|
"vedastro_cloud_state": vedastro_state,
|
|
"vedastro_runtime_truth": dict(runtime_truth),
|
|
"external_engine_cross_validation": external_cross_validation,
|
|
"cross_system_arbitration": cross_system_arbitration,
|
|
"kp_western_support": {
|
|
"convergence": cross_system_arbitration.get("kp_western_convergence") or {},
|
|
"negative_evidence": cross_system_arbitration.get("negative_evidence") or {},
|
|
"real_case_support": cross_system_arbitration.get("western_real_case_support") or {},
|
|
},
|
|
"specialized_indian_closure_review": specialized_indian_closure_review,
|
|
"finance_astrology_support_review": finance_astrology_support_review,
|
|
"source_priority": {
|
|
"mode": self.SOURCE_PRIORITY["mode"],
|
|
"priority": list(self.SOURCE_PRIORITY["priority"]),
|
|
},
|
|
"evidence_sources": {
|
|
"vedastro_official": vedastro_state,
|
|
"local_modules": "used" if executed_steps else "not_used",
|
|
"interpretation_source_runtime_coverage": (
|
|
"used" if isinstance(interpretation_source_runtime_coverage, dict) and interpretation_source_runtime_coverage else "not_used"
|
|
),
|
|
},
|
|
"evidence_packet_contract": {
|
|
"status": packet_status,
|
|
"required_sections": self.evidence_packet_required_sections(route_name),
|
|
"missing_sections": packet.get("missing_sections", []),
|
|
},
|
|
"blind_technical_mode": {
|
|
"enabled": bool(blind),
|
|
"allowed_sources": ["birth_payload", "pdf", "machine_evidence_packet"],
|
|
"disallowed_sources": ["conversation_feedback", "memory_linked_personal_history"],
|
|
},
|
|
"real_case_calibration": {
|
|
"status": case_status,
|
|
"required_fields": [
|
|
"case_source",
|
|
"chart_similarity",
|
|
"transit_or_dasha_trigger",
|
|
"event",
|
|
"similarities",
|
|
"differences",
|
|
"reference_grade",
|
|
],
|
|
},
|
|
"quality_gate": {
|
|
"technique_audit_table_required": True,
|
|
"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",
|
|
"KP-Western Convergence",
|
|
"Western Negative Evidence",
|
|
"Western Real-Case Calibration",
|
|
"Evidence Packet",
|
|
"Blind Technical Mode",
|
|
"MEVG / Global Web Evidence",
|
|
"Real Case Calibration",
|
|
"Timing Precision Gate",
|
|
"Functional Benefic/Malefic",
|
|
"Specialized Indian Closure Review",
|
|
"Finance Astrology Support Review",
|
|
],
|
|
"status": "blocked" if blocked_items else "pass",
|
|
"blocked_items": blocked_items,
|
|
},
|
|
}
|
|
|
|
def build_expert_judgment_shadow_input(
|
|
self,
|
|
*,
|
|
question: str,
|
|
route_packet: dict[str, Any],
|
|
route_profile: dict[str, Any] | None = None,
|
|
machine_evidence_packet: dict[str, Any] | None = None,
|
|
runtime_evidence_log: dict[str, Any] | None = None,
|
|
legacy_prediction_payload: dict[str, Any] | None = None,
|
|
legacy_strict_workflows: dict[str, Any] | None = None,
|
|
request_id: str | None = None,
|
|
) -> dict[str, Any]:
|
|
"""Build Phase 1 shadow input without introducing judgment behavior."""
|
|
try:
|
|
from scripts.expert_judgment import ExpertJudgmentRequest, assemble_expert_judgment_input
|
|
from scripts.expert_judgment.adapters import (
|
|
build_activation_layer,
|
|
build_legacy_prediction_hint,
|
|
build_legacy_strict_evidence_items,
|
|
)
|
|
except Exception: # pragma: no cover - research helper is not vendored here
|
|
try:
|
|
from expert_judgment import ExpertJudgmentRequest, assemble_expert_judgment_input
|
|
from expert_judgment.adapters import (
|
|
build_activation_layer,
|
|
build_legacy_prediction_hint,
|
|
build_legacy_strict_evidence_items,
|
|
)
|
|
except Exception:
|
|
return {"status": "blocked", "reason": "expert_judgment_module_absent"}
|
|
|
|
packet = machine_evidence_packet if isinstance(machine_evidence_packet, dict) else {}
|
|
sections = packet.get("sections") if isinstance(packet.get("sections"), dict) else {}
|
|
route = dict(route_packet or {})
|
|
profile = dict(route_profile or {})
|
|
runtime_log = runtime_evidence_log if isinstance(runtime_evidence_log, dict) else {}
|
|
quality_gate = runtime_log.get("quality_gate") if isinstance(runtime_log.get("quality_gate"), dict) else {}
|
|
question_id = str(request_id or route.get("request_id") or route.get("question_id") or "shadow-request")
|
|
domain = str(route.get("primary_theme") or route.get("question_type") or "general")
|
|
question_type = str(route.get("question_type") or domain)
|
|
mode = str(profile.get("presentation_mode") or "default")
|
|
request = ExpertJudgmentRequest(
|
|
schema_version="expert_judgment_request.v1",
|
|
request_context={
|
|
"question_id": question_id,
|
|
"question_text": question or "",
|
|
"domain": domain,
|
|
"question_type": question_type,
|
|
"precision_target": "quarter_window",
|
|
"mode": mode if mode in {"default", "high_rigor", "research"} else "default",
|
|
},
|
|
)
|
|
audit_payload = {
|
|
"audit_id": f"{question_id}-audit",
|
|
"status": self._normalize_shadow_status(quality_gate.get("status") or "blocked"),
|
|
"required_rows": self._shadow_required_audit_rows(quality_gate),
|
|
"blocked_items": list(quality_gate.get("blocked_items") or []),
|
|
"claim_boundaries": [
|
|
"shadow input only",
|
|
"no final judgment",
|
|
"legacy hints stay isolated",
|
|
],
|
|
}
|
|
activation_layer = build_activation_layer(
|
|
vimshottari=self._shadow_activation_payload(sections.get("dasha_boundaries"), "Vimshottari"),
|
|
narayana=self._shadow_activation_payload(sections.get("narayana_dasha"), "Narayana"),
|
|
blocked_sources=self._shadow_activation_blocked_sources(sections),
|
|
)
|
|
legacy_strict_items = build_legacy_strict_evidence_items(legacy_strict_workflows)
|
|
assembled = assemble_expert_judgment_input(
|
|
request,
|
|
domain_context={
|
|
"domain": domain,
|
|
"question_type": question_type,
|
|
"themes": list(profile.get("themes") or []),
|
|
"route_label": route.get("display_label"),
|
|
},
|
|
audit_context={
|
|
"status": audit_payload["status"],
|
|
"timing_precision_gate": dict(
|
|
(runtime_log.get("real_case_calibration") or {}).get("timing_precision_gate") or {}
|
|
),
|
|
},
|
|
evidence_graph_ref={"graph_id": f"{question_id}-graph"},
|
|
activation_layer=activation_layer,
|
|
legacy_prediction=build_legacy_prediction_hint(legacy_prediction_payload),
|
|
evidence_items=self._build_shadow_evidence_items(sections) + legacy_strict_items,
|
|
audit_payload=audit_payload,
|
|
runtime_log_path="runtime_evidence_log",
|
|
technique_audit_table_path="runtime_evidence_log.quality_gate.technique_audit_table",
|
|
required_rows=audit_payload["required_rows"],
|
|
)
|
|
created_at = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
|
|
shadow_run_id = f"shadow-input://{question_id}"
|
|
return {
|
|
"shadow_run_id": shadow_run_id,
|
|
"request_id": question_id,
|
|
"expert_input_ref": f"expert_judgment_input://{question_id}",
|
|
"audit_snapshot_ref": f"audit_snapshot://{question_id}",
|
|
"created_at": created_at,
|
|
"status": "generated",
|
|
"shadow_snapshot": {
|
|
"shadow_run_id": shadow_run_id,
|
|
"request_id": question_id,
|
|
"expert_input_ref": f"expert_judgment_input://{question_id}",
|
|
"audit_snapshot_ref": f"audit_snapshot://{question_id}",
|
|
"created_at": created_at,
|
|
"status": "generated",
|
|
},
|
|
"expert_judgment_input": asdict(assembled),
|
|
"audit_snapshot": dict(assembled.audit_context),
|
|
"boundary": "Shadow input only; no verdict, confidence, or final judgment.",
|
|
}
|
|
|
|
def build_shadow_judgment_runtime(
|
|
self,
|
|
*,
|
|
expert_judgment_shadow: dict[str, Any] | None,
|
|
) -> dict[str, Any]:
|
|
"""Build Phase 2C shadow adjudication artifacts without product promotion."""
|
|
try:
|
|
from scripts.expert_judgment import (
|
|
build_judgment_shadow_output,
|
|
build_shadow_judgment_artifact,
|
|
build_shadow_review_packet,
|
|
build_shadow_stage_archive,
|
|
)
|
|
from scripts.expert_judgment.schemas import ExpertJudgmentInput
|
|
except ModuleNotFoundError: # pragma: no cover - script execution path
|
|
from expert_judgment import (
|
|
build_judgment_shadow_output,
|
|
build_shadow_judgment_artifact,
|
|
build_shadow_review_packet,
|
|
build_shadow_stage_archive,
|
|
)
|
|
from expert_judgment.schemas import ExpertJudgmentInput
|
|
|
|
shadow = expert_judgment_shadow if isinstance(expert_judgment_shadow, dict) else {}
|
|
input_payload = shadow.get("expert_judgment_input") if isinstance(shadow.get("expert_judgment_input"), dict) else None
|
|
if not isinstance(input_payload, dict):
|
|
raise ValueError("expert_judgment_shadow must contain expert_judgment_input")
|
|
|
|
expert_input = ExpertJudgmentInput(**input_payload)
|
|
shadow_output = build_judgment_shadow_output(expert_input)
|
|
stage_archive = build_shadow_stage_archive(
|
|
shadow_run_id=str(shadow.get("shadow_run_id") or "shadow-input://unknown"),
|
|
request_id=str(shadow.get("request_id") or "shadow-request"),
|
|
shadow_output=shadow_output,
|
|
audit_snapshot=dict(shadow.get("audit_snapshot") or {}),
|
|
created_at=str(shadow.get("created_at") or datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")),
|
|
)
|
|
shadow_artifact = build_shadow_judgment_artifact(
|
|
shadow_run_id=stage_archive["shadow_run_id"],
|
|
request_id=stage_archive["request_id"],
|
|
shadow_stage_archive=stage_archive,
|
|
)
|
|
shadow_review = build_shadow_review_packet(
|
|
shadow_run_id=stage_archive["shadow_run_id"],
|
|
request_id=stage_archive["request_id"],
|
|
expert_judgment_input=input_payload,
|
|
shadow_stage_archive=stage_archive,
|
|
shadow_judgment_artifact=shadow_artifact,
|
|
)
|
|
return {
|
|
"shadow_run_id": stage_archive["shadow_run_id"],
|
|
"request_id": stage_archive["request_id"],
|
|
"shadow_stage_archive_ref": f"{stage_archive['shadow_run_id']}#stage_archive",
|
|
"shadow_judgment_artifact_ref": f"{stage_archive['shadow_run_id']}#judgment_artifact",
|
|
"shadow_review_ref": f"{stage_archive['shadow_run_id']}#review",
|
|
"status": "generated",
|
|
"shadow_stage_archive": stage_archive,
|
|
"shadow_judgment_artifact": shadow_artifact,
|
|
"shadow_review": shadow_review,
|
|
"boundary": "Shadow adjudication runtime only; no final adjudication, confidence, or product promotion.",
|
|
}
|
|
|
|
@staticmethod
|
|
def _normalize_shadow_status(status: Any) -> str:
|
|
status_text = str(status or "").strip().lower()
|
|
if status_text in {"used", "complete", "executed", "official_verified", "pass"}:
|
|
return "executed"
|
|
if status_text in {"partial", "partial_scored", "local_fallback", "available_not_requested"}:
|
|
return "partial"
|
|
if status_text == "parameter_sensitive":
|
|
return "parameter_sensitive"
|
|
if status_text == "not_applicable":
|
|
return "not_applicable"
|
|
return "blocked"
|
|
|
|
def _build_shadow_evidence_items(self, sections: dict[str, Any]) -> list[dict[str, Any]]:
|
|
items: list[dict[str, Any]] = []
|
|
for section_name, section_payload in sections.items():
|
|
if not isinstance(section_payload, dict):
|
|
continue
|
|
items.append(
|
|
{
|
|
"ref_id": f"shadow-{section_name.lower()}",
|
|
"source_module": "scripts.unified_consultation_orchestrator",
|
|
"source_path": str(section_payload.get("source_path") or f"machine_evidence_packet.sections.{section_name}"),
|
|
"payload_key": f"machine_evidence_packet.sections.{section_name}",
|
|
"status": self._normalize_shadow_status(section_payload.get("status")),
|
|
"summary": {"section": section_name},
|
|
"claim_boundary": "reference only; no final judgment",
|
|
"evidence_graph_node": f"evidence://shadow/{section_name.lower()}",
|
|
}
|
|
)
|
|
return items
|
|
|
|
@staticmethod
|
|
def _shadow_required_audit_rows(quality_gate: dict[str, Any]) -> list[str]:
|
|
rows = quality_gate.get("technique_audit_table") if isinstance(quality_gate.get("technique_audit_table"), list) else []
|
|
required_rows: list[str] = []
|
|
for row in rows:
|
|
technique = row.get("technique") if isinstance(row, dict) else None
|
|
if isinstance(technique, str) and technique:
|
|
required_rows.append(technique)
|
|
return required_rows or ["Evidence Packet", "Real Case Calibration", "Timing Precision Gate"]
|
|
|
|
def _shadow_activation_payload(
|
|
self,
|
|
section_payload: dict[str, Any] | None,
|
|
system_name: str,
|
|
) -> dict[str, Any] | None:
|
|
if not isinstance(section_payload, dict):
|
|
return None
|
|
status = self._normalize_shadow_status(section_payload.get("status"))
|
|
if status == "blocked":
|
|
return None
|
|
return {
|
|
"status": status,
|
|
"source_path": section_payload.get("source_path"),
|
|
"system": system_name,
|
|
}
|
|
|
|
def _shadow_activation_blocked_sources(self, sections: dict[str, Any]) -> list[dict[str, Any]]:
|
|
blocked_sources: list[dict[str, Any]] = []
|
|
for section_name, system_name in (
|
|
("dasha_boundaries", "Vimshottari"),
|
|
("narayana_dasha", "Narayana"),
|
|
):
|
|
section_payload = sections.get(section_name)
|
|
if not isinstance(section_payload, dict):
|
|
blocked_sources.append(
|
|
{"name": system_name, "status": "blocked", "reason": "missing_section"}
|
|
)
|
|
continue
|
|
if self._normalize_shadow_status(section_payload.get("status")) == "blocked":
|
|
blocked_sources.append(
|
|
{
|
|
"name": system_name,
|
|
"status": "blocked",
|
|
"reason": str(section_payload.get("source_path") or "blocked_source"),
|
|
}
|
|
)
|
|
return blocked_sources
|