Merge codex/pr2-final-response into staging integration
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Fail-closed contract for server-generated consultation workflow plans."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
PLAN_VERSION = "consultation-plan-v2"
|
||||
_ALLOWED_DEPTHS = {"concise", "standard", "deep", "research"}
|
||||
_ALLOWED_HORIZONS = {"next_3_months", "next_12_months", "next_24_months", "long_term"}
|
||||
_ALLOWED_PRECISION_BOUNDARIES = {"server_evidence_required", "precise_timing_blocked"}
|
||||
_PLAN_METADATA_KEYS = frozenset({
|
||||
"plan_version",
|
||||
"strict_workflow_route",
|
||||
"required_layers",
|
||||
"claim_boundary",
|
||||
"plan_depth",
|
||||
"requested_domains",
|
||||
"timing_horizon",
|
||||
"precision_boundary",
|
||||
"required_evidence_categories",
|
||||
})
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RouteContract:
|
||||
themes: tuple[str, ...]
|
||||
resolved_routes: tuple[str, ...]
|
||||
requested_domains: tuple[str, ...]
|
||||
required_evidence_categories: tuple[str, ...]
|
||||
required_layers: tuple[str, ...]
|
||||
claim_boundary: str
|
||||
|
||||
|
||||
_ROUTE_CONTRACTS = {
|
||||
"career": RouteContract(
|
||||
themes=("career",),
|
||||
resolved_routes=("career",),
|
||||
requested_domains=("career",),
|
||||
required_evidence_categories=("natal_foundation", "domain"),
|
||||
required_layers=("D1", "D10", "10th house/lord", "A10", "AmK", "Vimshottari", "Narayana", "Transit"),
|
||||
claim_boundary="career_direction_and_broad_timing_only",
|
||||
),
|
||||
"marriage": RouteContract(
|
||||
themes=("marriage",),
|
||||
resolved_routes=("marriage", "relationship"),
|
||||
requested_domains=("marriage",),
|
||||
required_evidence_categories=("natal_foundation", "domain"),
|
||||
required_layers=("D1", "D9", "7th house/lord", "Venus/Jupiter", "DK", "UL", "A7", "Vimshottari", "Narayana", "Transit"),
|
||||
claim_boundary="relationship_pattern_and_broad_window_only",
|
||||
),
|
||||
"wealth": RouteContract(
|
||||
themes=("wealth",),
|
||||
resolved_routes=("wealth", "finance"),
|
||||
requested_domains=("wealth",),
|
||||
required_evidence_categories=("natal_foundation", "domain"),
|
||||
required_layers=("D1", "D2", "D11", "2nd/11th/9th/5th houses", "Wealth Yogas", "Ashtakavarga", "Dasha"),
|
||||
claim_boundary="wealth_structure_not_financial_advice",
|
||||
),
|
||||
"health": RouteContract(
|
||||
themes=("health",),
|
||||
resolved_routes=("health",),
|
||||
requested_domains=("health",),
|
||||
required_evidence_categories=("natal_foundation", "domain"),
|
||||
required_layers=("D1", "D6", "D8", "6th/8th houses", "Dasha", "non-medical boundary"),
|
||||
claim_boundary="wellbeing_pressure_patterns_not_medical_diagnosis",
|
||||
),
|
||||
"education": RouteContract(
|
||||
themes=("education",),
|
||||
resolved_routes=("education",),
|
||||
requested_domains=("education",),
|
||||
required_evidence_categories=("natal_foundation", "domain"),
|
||||
required_layers=("D1", "D24", "5th/9th houses", "Mercury/Jupiter", "Dasha"),
|
||||
claim_boundary="learning_pattern_and_broad_timing_only",
|
||||
),
|
||||
"migration": RouteContract(
|
||||
themes=("migration",),
|
||||
resolved_routes=("migration",),
|
||||
requested_domains=("migration",),
|
||||
required_evidence_categories=("natal_foundation", "domain"),
|
||||
required_layers=("D1", "D4", "D12", "4th/12th houses", "Dasha", "Narayana"),
|
||||
claim_boundary="migration_and_home_direction_broad_window_only",
|
||||
),
|
||||
"family": RouteContract(
|
||||
themes=("family",),
|
||||
resolved_routes=("family",),
|
||||
requested_domains=("family",),
|
||||
required_evidence_categories=("natal_foundation", "domain"),
|
||||
required_layers=("D1", "D7", "D12", "4th/5th/9th houses", "Dasha"),
|
||||
claim_boundary="family_pattern_not_deterministic_event_claim",
|
||||
),
|
||||
"annual": RouteContract(
|
||||
themes=("annual",),
|
||||
resolved_routes=("annual",),
|
||||
requested_domains=("annual",),
|
||||
required_evidence_categories=("natal_foundation", "timing", "validation"),
|
||||
required_layers=("D1", "Annual chart boundary", "Dasha", "Transit", "Tajika candidate"),
|
||||
claim_boundary="annual_report_broad_periods_only",
|
||||
),
|
||||
"timing": RouteContract(
|
||||
themes=("timing",),
|
||||
resolved_routes=("timing",),
|
||||
requested_domains=("timing",),
|
||||
required_evidence_categories=("natal_foundation", "timing", "validation"),
|
||||
required_layers=("Vimshottari", "Narayana", "Transit", "Varga", "negative holdout gate"),
|
||||
claim_boundary="candidate_day_month_window_only_until_holdout_passes",
|
||||
),
|
||||
"general": RouteContract(
|
||||
themes=("general",),
|
||||
resolved_routes=("general",),
|
||||
requested_domains=("general",),
|
||||
required_evidence_categories=("natal_foundation", "domain"),
|
||||
required_layers=("D1", "D9", "D10", "D2", "Dasha", "Narayana", "Transit", "Functional Benefic/Malefic"),
|
||||
claim_boundary="multi_domain_summary_with_missing_layers_disclosed",
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
class ConsultationPlanContractError(ValueError):
|
||||
"""Raised when a versioned product plan does not match the server allowlist."""
|
||||
|
||||
|
||||
def _require_list(body: dict[str, Any], key: str) -> tuple[str, ...]:
|
||||
value = body.get(key)
|
||||
if not isinstance(value, list) or not value or any(not isinstance(item, str) or not item for item in value):
|
||||
raise ConsultationPlanContractError(f"invalid consultation plan field: {key}")
|
||||
return tuple(value)
|
||||
|
||||
|
||||
def validate_consultation_plan_contract(
|
||||
body: dict[str, Any],
|
||||
*,
|
||||
themes: list[str],
|
||||
route_packet: dict[str, Any],
|
||||
) -> dict[str, Any] | None:
|
||||
"""Validate the optional versioned plan without accepting free-form workflow control.
|
||||
|
||||
Older research/MCP callers may omit ``plan_version``. Product runtime calls include it
|
||||
and must match every server-owned route field exactly.
|
||||
"""
|
||||
|
||||
present_plan_keys = _PLAN_METADATA_KEYS.intersection(body)
|
||||
if not present_plan_keys:
|
||||
return None
|
||||
missing_plan_keys = _PLAN_METADATA_KEYS.difference(body)
|
||||
if missing_plan_keys:
|
||||
missing = ", ".join(sorted(missing_plan_keys))
|
||||
raise ConsultationPlanContractError(f"incomplete consultation plan metadata: {missing}")
|
||||
if body.get("plan_version") != PLAN_VERSION:
|
||||
raise ConsultationPlanContractError("unsupported consultation plan version")
|
||||
|
||||
strict_route = body.get("strict_workflow_route")
|
||||
contract = _ROUTE_CONTRACTS.get(strict_route)
|
||||
if contract is None:
|
||||
raise ConsultationPlanContractError("unsupported consultation workflow route")
|
||||
if tuple(themes) != contract.themes:
|
||||
raise ConsultationPlanContractError("consultation plan theme mismatch")
|
||||
|
||||
resolved_route = str(route_packet.get("question_type") or "")
|
||||
if resolved_route not in contract.resolved_routes:
|
||||
raise ConsultationPlanContractError("consultation plan route mismatch")
|
||||
if _require_list(body, "required_layers") != contract.required_layers:
|
||||
raise ConsultationPlanContractError("consultation plan required layers mismatch")
|
||||
if body.get("claim_boundary") != contract.claim_boundary:
|
||||
raise ConsultationPlanContractError("consultation plan claim boundary mismatch")
|
||||
if _require_list(body, "requested_domains") != contract.requested_domains:
|
||||
raise ConsultationPlanContractError("consultation plan requested domains mismatch")
|
||||
if _require_list(body, "required_evidence_categories") != contract.required_evidence_categories:
|
||||
raise ConsultationPlanContractError("consultation plan evidence categories mismatch")
|
||||
|
||||
depth = body.get("plan_depth")
|
||||
if depth not in _ALLOWED_DEPTHS:
|
||||
raise ConsultationPlanContractError("unsupported consultation plan depth")
|
||||
horizon = body.get("timing_horizon")
|
||||
if horizon is not None and horizon not in _ALLOWED_HORIZONS:
|
||||
raise ConsultationPlanContractError("unsupported consultation timing horizon")
|
||||
if strict_route in {"timing", "annual"} and horizon is None:
|
||||
raise ConsultationPlanContractError("timing consultation requires a horizon")
|
||||
|
||||
precision_boundary = body.get("precision_boundary")
|
||||
if precision_boundary not in _ALLOWED_PRECISION_BOUNDARIES:
|
||||
raise ConsultationPlanContractError("unsupported consultation precision boundary")
|
||||
|
||||
return {
|
||||
"plan_version": PLAN_VERSION,
|
||||
"strict_workflow_route": strict_route,
|
||||
"plan_depth": depth,
|
||||
"requested_domains": list(contract.requested_domains),
|
||||
"timing_horizon": horizon,
|
||||
"required_evidence_categories": list(contract.required_evidence_categories),
|
||||
"required_layers": list(contract.required_layers),
|
||||
"claim_boundary": contract.claim_boundary,
|
||||
"precision_boundary": precision_boundary,
|
||||
"enforcement": "server_allowlist_validated",
|
||||
}
|
||||
|
||||
|
||||
def apply_plan_precision_boundary(
|
||||
consumer_context: dict[str, Any],
|
||||
plan_contract: dict[str, Any] | None,
|
||||
) -> dict[str, Any]:
|
||||
"""Apply only a restrictive plan boundary; evidence policy remains authoritative."""
|
||||
|
||||
if not plan_contract or plan_contract.get("precision_boundary") != "precise_timing_blocked":
|
||||
return consumer_context
|
||||
answer_policy = consumer_context.get("answer_policy")
|
||||
if not isinstance(answer_policy, dict):
|
||||
return consumer_context
|
||||
return {
|
||||
**consumer_context,
|
||||
"answer_policy": {
|
||||
**answer_policy,
|
||||
"can_answer_precise_timing": False,
|
||||
"should_lead_with_limitations": True,
|
||||
"plan_precision_boundary": "precise_timing_blocked",
|
||||
},
|
||||
}
|
||||
@@ -852,6 +852,24 @@ def execute_consultation_workflow(
|
||||
Path(__file__).resolve().parents[1] / 'references/oracle/three_engine_parity_replay_manifest.json'
|
||||
)
|
||||
route_packet = _UNIFIED_CONSULTATION_ORCHESTRATOR.resolve_route(question, themes)
|
||||
try:
|
||||
from scripts.consultation_plan_contract import (
|
||||
ConsultationPlanContractError,
|
||||
apply_plan_precision_boundary,
|
||||
validate_consultation_plan_contract,
|
||||
)
|
||||
except ModuleNotFoundError: # pragma: no cover - direct script execution
|
||||
from consultation_plan_contract import (
|
||||
ConsultationPlanContractError,
|
||||
apply_plan_precision_boundary,
|
||||
validate_consultation_plan_contract,
|
||||
)
|
||||
try:
|
||||
consultation_plan_contract = validate_consultation_plan_contract(
|
||||
body, themes=themes, route_packet=route_packet,
|
||||
)
|
||||
except ConsultationPlanContractError as exc:
|
||||
raise BadRequest(str(exc)) from exc
|
||||
western_evidence_packet = _western_evidence_packet_from_body(body, route_packet, birth_payload=birth_payload)
|
||||
unified_contract = _UNIFIED_CONSULTATION_ORCHESTRATOR.shared_contract(
|
||||
entry_mode=entry_mode,
|
||||
@@ -889,6 +907,8 @@ def execute_consultation_workflow(
|
||||
'executed_steps': [],
|
||||
'skipped_steps': known_steps,
|
||||
}
|
||||
if consultation_plan_contract:
|
||||
result['consultation_plan_contract'] = consultation_plan_contract
|
||||
result['runtime_evidence_log'] = _UNIFIED_CONSULTATION_ORCHESTRATOR.runtime_evidence_log(
|
||||
surface=surface,
|
||||
entry_mode=entry_mode,
|
||||
@@ -1065,6 +1085,7 @@ def execute_consultation_workflow(
|
||||
machine_evidence_packet=machine_evidence_packet,
|
||||
vedastro_official=vedastro_official,
|
||||
)
|
||||
consumer_context = apply_plan_precision_boundary(consumer_context, consultation_plan_contract)
|
||||
real_case_calibration = _UNIFIED_CONSULTATION_ORCHESTRATOR.real_case_calibration_catalog(
|
||||
route_packet=route_packet,
|
||||
machine_evidence_packet=machine_evidence_packet,
|
||||
@@ -1098,6 +1119,7 @@ def execute_consultation_workflow(
|
||||
'executed_steps': executed_steps,
|
||||
'skipped_steps': skipped_steps,
|
||||
},
|
||||
'consultation_plan_contract': consultation_plan_contract,
|
||||
'source_priority': {
|
||||
'mode': 'vedastro_official_snapshot_first',
|
||||
'priority': [
|
||||
|
||||
Reference in New Issue
Block a user