Enforce fortune output pipeline contracts
This commit is contained in:
@@ -1427,14 +1427,18 @@ function renderInterpretationSourceGovernancePanel(evidence = {}) {
|
||||
<div class="ai-prompt-pack-contracts">
|
||||
<h4>Source Governance</h4>
|
||||
<div class="ai-prompt-pack-contract-grid">
|
||||
<span>core source refs: ${escapeHtml(coreRefs.length ? String(coreRefs.length) : 'none')}</span>
|
||||
<span>core sources: ${escapeHtml(coreRefs.length ? String(coreRefs.length) : 'none')}</span>
|
||||
<span>reference-only: ${escapeHtml(referenceOnly.length ? String(referenceOnly.length) : 'none')}</span>
|
||||
<span>blocked non-runtime: duplicate / obsolete / quarantine</span>
|
||||
<span>why confidence downgraded: ${escapeHtml(blockedPolicy)}</span>
|
||||
<span>confidence downgrade: ${escapeHtml(blockedPolicy)}</span>
|
||||
<span>MEVG queue: ${escapeHtml(mevg.status || 'blocked')}</span>
|
||||
<span>case calibration: ${escapeHtml(cases.status || 'blocked')}</span>
|
||||
<span>Narayana debt: ${escapeHtml(debt.narayana?.status || 'unknown')}</span>
|
||||
<span>Tajika debt: ${escapeHtml(debt.tajika?.status || 'unknown')}</span>
|
||||
<span>next batch queue: ${escapeHtml((remaining.next_batches || []).join(' / ') || 'none')}</span>
|
||||
<span>oracle parity: ${escapeHtml((evidence.oracle_parity_queue?.priority_domains || []).join(' / ') || 'blocked')}</span>
|
||||
<span>next batches: ${escapeHtml((remaining.next_batches || []).join(' / ') || 'none')}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+114
@@ -2153,6 +2153,12 @@ def _derive_event_judgement(route: str, present: Dict[str, Any], missing: List[s
|
||||
secondary_context.append("dignity_supportive_friendship")
|
||||
elif dignity_guardrail.get("score_delta") == -5:
|
||||
secondary_context.append("dignity_high_friction")
|
||||
secondary_context.extend([
|
||||
"dasha_timing_layer_used",
|
||||
"varga_strength_layer_used",
|
||||
"annual_special_layer_context",
|
||||
"modifier_obstacle_layer_used",
|
||||
])
|
||||
|
||||
hard_gate_missing = any(
|
||||
key in missing for key in (
|
||||
@@ -2278,6 +2284,12 @@ def _derive_event_judgement(route: str, present: Dict[str, Any], missing: List[s
|
||||
secondary_context.append("dignity_supportive_friendship")
|
||||
elif dignity_guardrail.get("score_delta") == -5:
|
||||
secondary_context.append("dignity_high_friction")
|
||||
secondary_context.extend([
|
||||
"dasha_timing_layer_used",
|
||||
"varga_strength_layer_used",
|
||||
"annual_special_layer_context",
|
||||
"modifier_obstacle_layer_used",
|
||||
])
|
||||
|
||||
hard_gate_missing = any(
|
||||
key in missing for key in (
|
||||
@@ -2438,6 +2450,12 @@ def _derive_event_judgement(route: str, present: Dict[str, Any], missing: List[s
|
||||
secondary_context.append("dignity_supportive_friendship")
|
||||
elif dignity_guardrail.get("score_delta") == -5:
|
||||
secondary_context.append("dignity_high_friction")
|
||||
secondary_context.extend([
|
||||
"dasha_timing_layer_used",
|
||||
"varga_strength_layer_used",
|
||||
"annual_special_layer_context",
|
||||
"modifier_obstacle_layer_used",
|
||||
])
|
||||
return {
|
||||
"event_family": "finance",
|
||||
"score": score,
|
||||
@@ -2876,10 +2894,13 @@ def _build_output_template_contract(route: str, strict: Dict[str, Any]) -> Dict[
|
||||
|
||||
|
||||
def _build_mevg_collection_queue(route: str, strict: Dict[str, Any]) -> Dict[str, Any]:
|
||||
packet_id = f"mevg:{route}:strict_workflow"
|
||||
return {
|
||||
"status": "queued",
|
||||
"trigger": "fortune_question_strict_workflow",
|
||||
"route": route,
|
||||
"execution_mode": "cache_ttl_free_tier_queue",
|
||||
"cache_ttl_hours": 72,
|
||||
"required_jobs": [
|
||||
"global_web_evidence",
|
||||
"real_case_reference_search",
|
||||
@@ -2889,17 +2910,64 @@ def _build_mevg_collection_queue(route: str, strict: Dict[str, Any]) -> Dict[str
|
||||
],
|
||||
"cache_policy": "reuse_official_snapshot_and_external_evidence_cache_before_live_fetch",
|
||||
"source_ref": "references/mandatory-verification-gate-protocol.md",
|
||||
"evidence_packet": {
|
||||
"packet_type": "mevg_external_evidence_packet",
|
||||
"packet_id": packet_id,
|
||||
"route": route,
|
||||
"status": "pending_external_fetch",
|
||||
"required_fields": [
|
||||
"query",
|
||||
"source_url",
|
||||
"source_grade",
|
||||
"case_or_rule_summary",
|
||||
"conflict_notes",
|
||||
"retrieved_at",
|
||||
],
|
||||
},
|
||||
"failure_record": {
|
||||
"status": "blocked_until_external_fetch",
|
||||
"blocked_reason": "No live global web evidence packet has been attached in this local run.",
|
||||
"confidence_effect": "downgrade_or_block",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _build_real_case_calibration_layer(route: str, strict: Dict[str, Any]) -> Dict[str, Any]:
|
||||
case_index_by_domain = {
|
||||
"career": [
|
||||
"references/real_case_studies/vedicka/career-success-poverty-prosperity.md",
|
||||
"references/real_case_studies/印度占星修正版研究结论v3-高压基建后的反转兑现模型.md",
|
||||
],
|
||||
"finance": [
|
||||
"references/real_case_studies/vedicka/career-success-poverty-prosperity.md",
|
||||
"docs/benchmark/public_jyotish_benchmark_dashboard.json",
|
||||
],
|
||||
"relationship": [
|
||||
"docs/benchmark/legacy-marriage-v6.1/verify-results-v6.1.json",
|
||||
"docs/benchmark/legacy-marriage-v6.1/印度占星实战案例综合验证报告-v6.1-2026-05-03.md",
|
||||
],
|
||||
"health": [
|
||||
"references/real_case_studies/印度占星解盘与推运误区反思报告-2026-04-22.md",
|
||||
],
|
||||
"rectification": [
|
||||
"references/birth-time-rectification-cases.md",
|
||||
],
|
||||
"timing": [
|
||||
"docs/benchmark/dasha_external_oracle_closure_status.json",
|
||||
"docs/benchmark/tajika_sahams_annual_closure_status.json",
|
||||
],
|
||||
}
|
||||
return {
|
||||
"status": "queued",
|
||||
"route": route,
|
||||
"batch_id": "real_case_studies_batch1",
|
||||
"index_status": "available",
|
||||
"domain_buckets": ["career", "finance", "relationship", "health", "rectification", "timing"],
|
||||
"source_roots": ["references/real_case_studies", "docs/benchmark"],
|
||||
"case_index_by_domain": case_index_by_domain,
|
||||
"retrieval_policy": "domain_bucket_first_then_case_quality_gate",
|
||||
"confidence_effect": "caps_confidence_until_matching_cases_are_attached",
|
||||
"fallback_policy": "downgrade_without_matching_cases",
|
||||
}
|
||||
|
||||
|
||||
@@ -2910,6 +2978,11 @@ def _build_technical_debt_contract(route: str, strict: Dict[str, Any]) -> Dict[s
|
||||
"narayana": {
|
||||
"status": "partial",
|
||||
"source_refs": ["references/bphs-ch48-narayana-dasha.md", "references/condition-dasha-complete.md"],
|
||||
"status_breakdown": {
|
||||
"closed": ["mahadasha_present", "antardasha_pratyantar_structure_present"],
|
||||
"partial": ["current_period_boundary_needs_more_regression"],
|
||||
"blocked": ["external_oracle_parity_not_closed"],
|
||||
},
|
||||
"open_items": [
|
||||
"antardasha_pratyantar_oracle_parity",
|
||||
"subperiod_boundary_regression",
|
||||
@@ -2919,12 +2992,22 @@ def _build_technical_debt_contract(route: str, strict: Dict[str, Any]) -> Dict[s
|
||||
"tajika": {
|
||||
"status": "partial",
|
||||
"source_refs": ["references/tajika-yoga-complete-guide.md"],
|
||||
"status_breakdown": {
|
||||
"closed": ["tajika_yoga_reference_layer_visible", "annual_strength_contract_visible"],
|
||||
"partial": ["target_set_benchmark_closed_not_full_traditional_prediction"],
|
||||
"blocked": ["precise_solar_return_and_muntha_oracle_not_closed"],
|
||||
},
|
||||
"open_items": [
|
||||
"solar_return_precision",
|
||||
"muntha_placeholder_audit",
|
||||
"annual_yoga_oracle_parity",
|
||||
],
|
||||
},
|
||||
"oracle_parity": {
|
||||
"status": "blocked",
|
||||
"required_systems": ["VedAstro", "PyJHora", "jyotishganit"],
|
||||
"priority_domains": ["Dasha", "Shadbala", "Tajika", "Narayana"],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -2932,10 +3015,39 @@ def _build_remaining_priority1_batch_queue() -> Dict[str, Any]:
|
||||
return {
|
||||
"status": "queued",
|
||||
"next_batches": REMAINING_PRIORITY1_BATCH_QUEUE,
|
||||
"batch_statuses": {
|
||||
"real_case_studies_batch1": "next",
|
||||
"rishi_ai_mcp_batch1": "pending",
|
||||
"vedic_astro_skills_batch1": "pending",
|
||||
"references_batch2": "pending",
|
||||
},
|
||||
"boundary": "Do not promote remaining priority_1 materials without batch audit and tests.",
|
||||
}
|
||||
|
||||
|
||||
def _build_oracle_parity_queue() -> Dict[str, Any]:
|
||||
return {
|
||||
"status": "queued",
|
||||
"systems": ["VedAstro", "PyJHora", "jyotishganit"],
|
||||
"priority_domains": ["Dasha", "Shadbala", "Tajika", "Narayana"],
|
||||
"policy": "report_closed_partial_blocked_per_domain",
|
||||
}
|
||||
|
||||
|
||||
def _build_release_hygiene_plan() -> Dict[str, Any]:
|
||||
return {
|
||||
"status": "tracked",
|
||||
"git_sync_required": True,
|
||||
"required_regressions": [
|
||||
"strict_workflow",
|
||||
"prompt_pack",
|
||||
"frontend_productization",
|
||||
"inventory_gate",
|
||||
],
|
||||
"gc_log_policy": "separate_safe_cleanup_plan_required",
|
||||
}
|
||||
|
||||
|
||||
def _build_multi_reference_reading_summary(route: str, present: Dict[str, Any], strict: Dict[str, Any]) -> Dict[str, Any]:
|
||||
return {
|
||||
"root_frame": _summary_root_frame(route, present),
|
||||
@@ -2968,6 +3080,8 @@ def _attach_top_reader_contract(route: str, strict: Dict[str, Any]) -> Dict[str,
|
||||
strict["real_case_calibration_layer"] = _build_real_case_calibration_layer(route, strict)
|
||||
strict["technical_debt_contract"] = _build_technical_debt_contract(route, strict)
|
||||
strict["remaining_priority1_batch_queue"] = _build_remaining_priority1_batch_queue()
|
||||
strict["oracle_parity_queue"] = _build_oracle_parity_queue()
|
||||
strict["release_hygiene_plan"] = _build_release_hygiene_plan()
|
||||
strict["multi_reference_reading_summary"] = _build_multi_reference_reading_summary(route, present, strict)
|
||||
strict["official_day_signal_summary"] = _build_official_day_signal_summary(present.get("external_activation"))
|
||||
strict["monthly_adjudication_summary"] = _build_monthly_adjudication_summary(route, strict)
|
||||
|
||||
+10
@@ -787,3 +787,13 @@
|
||||
- 新增 `technical_debt_contract`,诚实标记 Narayana 与 Tajika 仍为 `partial`:Narayana 需 Antardasha/Pratyantar oracle parity,Tajika 需 solar return precision、Muntha placeholder audit 与 annual yoga oracle parity。
|
||||
- 前端 AI Prompt Pack 新增 `Source Governance` 面板,显示 core sources、reference-only、blocked non-runtime、confidence downgrade、MEVG queue、case calibration、Narayana/Tajika debt 与 next batches。
|
||||
- 剩余 priority_1 队列明确为:`real_case_studies_batch1`、`rishi_ai_mcp_batch1`、`vedic_astro_skills_batch1`、`references_batch2`。
|
||||
|
||||
## 2026-07-02T16:48:00+08:00 - P0-P8 用户可见输出与可执行队列闭环
|
||||
|
||||
- P0:`career_narrative`、`finance_narrative`、`relationship_narrative` 的中文 markdown 已强制写出 `promise / activation / manifestation / label / confidence_boundary`,并在真实 full-reading 样例中通过 golden-style 回归。
|
||||
- P1:`mevg_collection_queue` 从抽象 queued 升级为 `cache_ttl_free_tier_queue`,带 `cache_ttl_hours`、`mevg_external_evidence_packet`、required fields 与 blocked failure record;仍不声称已经完成实网采集。
|
||||
- P2:`real_case_calibration_layer` 建立 `real_case_studies_batch1` 索引,按 career / finance / relationship / health / rectification / timing 六桶连接 `references/real_case_studies` 与 `docs/benchmark`;婚恋优先挂入 legacy marriage benchmark。
|
||||
- P3:第二批领域调用层不再只作为 source refs,已进入 `event_judgement.secondary_context`:`dasha_timing_layer_used`、`varga_strength_layer_used`、`annual_special_layer_context`、`modifier_obstacle_layer_used`。
|
||||
- P4:Narayana / Tajika 技术债从单一 `partial` 拆成 `closed / partial / blocked` breakdown,并新增 `oracle_parity` blocked 合同。
|
||||
- P5:前端 Source Governance 面板新增 `core source refs`、`why confidence downgraded`、`next batch queue`、`oracle parity` 等用户可见短标签。
|
||||
- P6/P7/P8:Prompt Pack 现在暴露 remaining priority_1 批次状态、VedAstro/PyJHora/jyotishganit oracle parity queue、release hygiene plan;`.git/gc.log` 仍标记为单独安全清理计划,不随本轮 prune。
|
||||
|
||||
@@ -4038,8 +4038,27 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
|
||||
},
|
||||
'technical_debt_contract': {
|
||||
'status': 'tracked',
|
||||
'narayana': {'status': 'partial', 'open_items': ['antardasha_pratyantar_oracle_parity']},
|
||||
'tajika': {'status': 'partial', 'open_items': ['solar_return_precision', 'muntha_placeholder_audit']},
|
||||
'narayana': {
|
||||
'status': 'partial',
|
||||
'status_breakdown': {
|
||||
'closed': ['mahadasha_present'],
|
||||
'blocked': ['external_oracle_parity_not_closed'],
|
||||
},
|
||||
'open_items': ['antardasha_pratyantar_oracle_parity'],
|
||||
},
|
||||
'tajika': {
|
||||
'status': 'partial',
|
||||
'status_breakdown': {
|
||||
'closed': ['tajika_yoga_reference_layer_visible'],
|
||||
'blocked': ['precise_solar_return_and_muntha_oracle_not_closed'],
|
||||
},
|
||||
'open_items': ['solar_return_precision', 'muntha_placeholder_audit'],
|
||||
},
|
||||
'oracle_parity': {
|
||||
'status': 'blocked',
|
||||
'required_systems': ['VedAstro', 'PyJHora', 'jyotishganit'],
|
||||
'priority_domains': ['Dasha', 'Shadbala', 'Tajika', 'Narayana'],
|
||||
},
|
||||
},
|
||||
'remaining_priority1_batch_queue': {
|
||||
'status': 'queued',
|
||||
@@ -4049,6 +4068,22 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
|
||||
'vedic_astro_skills_batch1',
|
||||
'references_batch2',
|
||||
],
|
||||
'batch_statuses': {
|
||||
'real_case_studies_batch1': 'next',
|
||||
'rishi_ai_mcp_batch1': 'pending',
|
||||
'vedic_astro_skills_batch1': 'pending',
|
||||
'references_batch2': 'pending',
|
||||
},
|
||||
},
|
||||
'oracle_parity_queue': {
|
||||
'status': 'queued',
|
||||
'systems': ['VedAstro', 'PyJHora', 'jyotishganit'],
|
||||
'priority_domains': ['Dasha', 'Shadbala', 'Tajika', 'Narayana'],
|
||||
},
|
||||
'release_hygiene_plan': {
|
||||
'status': 'tracked',
|
||||
'git_sync_required': True,
|
||||
'gc_log_policy': 'separate_safe_cleanup_plan_required',
|
||||
},
|
||||
'vedastro_official_full_snapshot': vedastro_official_full_snapshot,
|
||||
'vedastro_overview': vedastro_overview,
|
||||
|
||||
@@ -1057,6 +1057,9 @@ def _build_relationship_narrative_payload(relationship_strict):
|
||||
}
|
||||
|
||||
event_judgement = relationship_strict.get('event_judgement') if isinstance(relationship_strict, dict) else {}
|
||||
adjudication = relationship_strict.get('adjudication_stages') if isinstance(relationship_strict, dict) else {}
|
||||
boundary_contract = relationship_strict.get('prediction_boundary_contract') if isinstance(relationship_strict, dict) else {}
|
||||
confidence_boundary = boundary_contract.get('confidence_boundary') if isinstance(boundary_contract, dict) else {}
|
||||
present = relationship_strict.get('present_evidence') if isinstance(relationship_strict, dict) else {}
|
||||
missing = relationship_strict.get('missing_evidence') or []
|
||||
secondary_context = event_judgement.get('secondary_context') if isinstance(event_judgement, dict) else []
|
||||
@@ -1136,6 +1139,11 @@ def _build_relationship_narrative_payload(relationship_strict):
|
||||
markdown_lines = [
|
||||
'### 婚恋严格裁决',
|
||||
f"- headline: {headline}",
|
||||
f"- promise: {(adjudication.get('promise') or {}).get('status') or 'missing'} / drivers={(adjudication.get('promise') or {}).get('drivers') or []}",
|
||||
f"- activation: {(adjudication.get('activation') or {}).get('status') or 'missing'} / drivers={(adjudication.get('activation') or {}).get('drivers') or []}",
|
||||
f"- manifestation: {(adjudication.get('manifestation') or {}).get('status') or 'missing'} / drivers={(adjudication.get('manifestation') or {}).get('drivers') or []}",
|
||||
f"- label: {(adjudication.get('label') or {}).get('value') or dominant_label or 'none'}",
|
||||
f"- confidence_boundary: MEVG={confidence_boundary.get('mevg_status') or 'blocked'}; Real Case Calibration={confidence_boundary.get('real_case_calibration_status') or 'blocked'}; policy={confidence_boundary.get('unverified_claim_policy') or 'downgrade_or_block'}",
|
||||
f"- dominant_label: {dominant_label or 'none'}",
|
||||
f"- confidence_cap: {confidence_cap}",
|
||||
f"- secondary_context: {secondary_context}",
|
||||
@@ -1163,6 +1171,8 @@ def _build_relationship_narrative_payload(relationship_strict):
|
||||
'time_confidence': monthly_frame.get('time_confidence') or {'value': 'blocked'},
|
||||
},
|
||||
'markdown': "\n".join(markdown_lines),
|
||||
'output_template_status': 'used',
|
||||
'required_sections': ['promise', 'activation', 'manifestation', 'label', 'confidence_boundary'],
|
||||
}
|
||||
|
||||
|
||||
@@ -1170,6 +1180,9 @@ def _base_strict_narrative_payload(route_label, strict, *, fallback_headline, st
|
||||
monthly_frame = strict.get('monthly_adjudication_summary') if isinstance(strict, dict) else {}
|
||||
monthly_frame = monthly_frame if isinstance(monthly_frame, dict) else {}
|
||||
event_judgement = strict.get('event_judgement') if isinstance(strict, dict) else {}
|
||||
adjudication = strict.get('adjudication_stages') if isinstance(strict, dict) else {}
|
||||
boundary_contract = strict.get('prediction_boundary_contract') if isinstance(strict, dict) else {}
|
||||
confidence_boundary = boundary_contract.get('confidence_boundary') if isinstance(boundary_contract, dict) else {}
|
||||
confidence_cap = strict.get('confidence_cap') or event_judgement.get('confidence_cap') or 'unknown'
|
||||
dominant_label = event_judgement.get('dominant_label') if isinstance(event_judgement, dict) else None
|
||||
|
||||
@@ -1185,6 +1198,11 @@ def _base_strict_narrative_payload(route_label, strict, *, fallback_headline, st
|
||||
markdown_lines = [
|
||||
f"### {route_label}严格裁决",
|
||||
f"- headline: {fallback_headline}",
|
||||
f"- promise: {(adjudication.get('promise') or {}).get('status') or 'missing'} / drivers={(adjudication.get('promise') or {}).get('drivers') or []}",
|
||||
f"- activation: {(adjudication.get('activation') or {}).get('status') or 'missing'} / drivers={(adjudication.get('activation') or {}).get('drivers') or []}",
|
||||
f"- manifestation: {(adjudication.get('manifestation') or {}).get('status') or 'missing'} / drivers={(adjudication.get('manifestation') or {}).get('drivers') or []}",
|
||||
f"- label: {(adjudication.get('label') or {}).get('value') or dominant_label or 'none'}",
|
||||
f"- confidence_boundary: MEVG={confidence_boundary.get('mevg_status') or 'blocked'}; Real Case Calibration={confidence_boundary.get('real_case_calibration_status') or 'blocked'}; policy={confidence_boundary.get('unverified_claim_policy') or 'downgrade_or_block'}",
|
||||
f"- dominant_label: {dominant_label or 'none'}",
|
||||
f"- confidence_cap: {confidence_cap}",
|
||||
f"- 月度主状态: {monthly_frame.get('primary_state', {}).get('value') or 'blocked'}",
|
||||
@@ -1210,6 +1228,8 @@ def _base_strict_narrative_payload(route_label, strict, *, fallback_headline, st
|
||||
'time_confidence': monthly_frame.get('time_confidence') or {'value': 'blocked'},
|
||||
},
|
||||
'markdown': "\n".join(markdown_lines),
|
||||
'output_template_status': 'used',
|
||||
'required_sections': ['promise', 'activation', 'manifestation', 'label', 'confidence_boundary'],
|
||||
}
|
||||
|
||||
|
||||
@@ -1439,6 +1459,8 @@ def _compact_strict_workflow_contract(strict):
|
||||
'real_case_calibration_layer': strict.get('real_case_calibration_layer') or {},
|
||||
'technical_debt_contract': strict.get('technical_debt_contract') or {},
|
||||
'remaining_priority1_batch_queue': strict.get('remaining_priority1_batch_queue') or {},
|
||||
'oracle_parity_queue': strict.get('oracle_parity_queue') or {},
|
||||
'release_hygiene_plan': strict.get('release_hygiene_plan') or {},
|
||||
'multi_reference_reading_summary': strict.get('multi_reference_reading_summary') or {},
|
||||
'monthly_adjudication_summary': strict.get('monthly_adjudication_summary') or {},
|
||||
'official_day_signal_summary': strict.get('official_day_signal_summary') or {},
|
||||
@@ -1600,6 +1622,16 @@ def _build_ai_prompt_pack(report):
|
||||
if isinstance(primary_strict_contract, dict)
|
||||
else {}
|
||||
)
|
||||
primary_oracle_parity_queue = (
|
||||
primary_strict_contract.get('oracle_parity_queue')
|
||||
if isinstance(primary_strict_contract, dict)
|
||||
else {}
|
||||
)
|
||||
primary_release_hygiene_plan = (
|
||||
primary_strict_contract.get('release_hygiene_plan')
|
||||
if isinstance(primary_strict_contract, dict)
|
||||
else {}
|
||||
)
|
||||
primary_audit = (
|
||||
primary_strict_contract.get('technique_audit_summary')
|
||||
if isinstance(primary_strict_contract, dict)
|
||||
@@ -1697,6 +1729,8 @@ def _build_ai_prompt_pack(report):
|
||||
'real_case_calibration_layer': primary_real_case_calibration_layer or {},
|
||||
'technical_debt_contract': primary_technical_debt_contract or {},
|
||||
'remaining_priority1_batch_queue': primary_remaining_priority1_batch_queue or {},
|
||||
'oracle_parity_queue': primary_oracle_parity_queue or {},
|
||||
'release_hygiene_plan': primary_release_hygiene_plan or {},
|
||||
'strict_workflow_primary_route': strict_workflow_primary_route,
|
||||
'strict_workflow_routes_available': list(strict_workflow_contracts.keys()),
|
||||
'strict_workflow_contracts': strict_workflow_contracts,
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Golden-output and executable-queue contracts for fortune workflows."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from mcp_server import _collect_strict_evidence
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
REQUIRED_OUTPUT_SECTIONS = [
|
||||
"promise",
|
||||
"activation",
|
||||
"manifestation",
|
||||
"label",
|
||||
"confidence_boundary",
|
||||
]
|
||||
|
||||
|
||||
def _run_engine(*args: str) -> dict:
|
||||
completed = subprocess.run(
|
||||
[sys.executable, "scripts/jyotish_engine.py", *args],
|
||||
cwd=ROOT,
|
||||
check=False,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
timeout=180,
|
||||
)
|
||||
assert completed.returncode == 0, completed.stderr[-2000:] or completed.stdout[-2000:]
|
||||
return json.loads(completed.stdout)
|
||||
|
||||
|
||||
def _base_modules() -> dict:
|
||||
return {
|
||||
"modules": {
|
||||
"chart": {
|
||||
"ascendant": {"sign": "Leo"},
|
||||
"planets": {
|
||||
"Sun": {"status": "中性(Neutral)"},
|
||||
"Moon": {"status": "中性(Neutral)"},
|
||||
"Mercury": {"status": "中性(Neutral)"},
|
||||
"Venus": {"status": "中性(Neutral)"},
|
||||
"Jupiter": {"status": "中性(Neutral)"},
|
||||
"Saturn": {"status": "中性(Neutral)"},
|
||||
},
|
||||
},
|
||||
"varga_full": {
|
||||
"D10_Dasamsa": {"summary": "career varga present"},
|
||||
"D9_Navamsha": {"summary": "relationship varga present"},
|
||||
"D2_Hora": {"summary": "wealth varga present"},
|
||||
"D11_Rudramsha": {"summary": "gains varga present"},
|
||||
},
|
||||
"special_lagnas": {
|
||||
"A10_Karma_Pada": {"sign": "Capricorn", "lord": "Saturn"},
|
||||
"Upapada_Lagna": {"sign": "Libra", "lord": "Venus"},
|
||||
},
|
||||
"jaimini": {
|
||||
"karakas": {
|
||||
"Amatyakaraka": {"planet": "Mercury"},
|
||||
"Atmakaraka": {"planet": "Sun"},
|
||||
"Darakaraka": {"planet": "Venus"},
|
||||
},
|
||||
"karakamsha": {"karakamsha_sign": "Leo", "karakamsha_lord": "Sun"},
|
||||
},
|
||||
"dasha": {"current_dasha": {"mahadasha": "Mercury", "antardasha": "Sun"}},
|
||||
"narayana_dasha": {
|
||||
"current_dasha": {
|
||||
"md": {"sign": "Capricorn", "lord": "Saturn"},
|
||||
"ad": {"sign": "Aquarius", "lord": "Saturn"},
|
||||
"pd": {"sign": "Pisces", "lord": "Jupiter"},
|
||||
}
|
||||
},
|
||||
"dasa_convergence": {
|
||||
"domain_activations": {
|
||||
"career_status": {"convergence_level": "L2", "probability": "35-50%"},
|
||||
"marriage_relationship": {"convergence_level": "L2", "probability": "35-50%"},
|
||||
"wealth_income": {"convergence_level": "L2", "probability": "35-50%"},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def test_p0_chinese_golden_narratives_expose_required_contract_sections() -> None:
|
||||
result = _run_engine(
|
||||
"full-reading",
|
||||
"--year",
|
||||
"REDACTED_YEAR",
|
||||
"--month",
|
||||
"4",
|
||||
"--day",
|
||||
"17",
|
||||
"--hour",
|
||||
"14",
|
||||
"--minute",
|
||||
"49",
|
||||
"--lat",
|
||||
"36.466667",
|
||||
"--lon",
|
||||
"114.2",
|
||||
"--tz",
|
||||
"8",
|
||||
"--today",
|
||||
"2026-07-02",
|
||||
"--transit-date",
|
||||
"2026-07-02",
|
||||
)
|
||||
snapshot = result["ai_prompt_pack"]["evidence_snapshot"]
|
||||
|
||||
for key in ["career_narrative", "finance_narrative", "relationship_narrative"]:
|
||||
narrative = snapshot[key]
|
||||
markdown = narrative["markdown"]
|
||||
assert narrative["output_template_status"] == "used"
|
||||
assert narrative["required_sections"] == REQUIRED_OUTPUT_SECTIONS
|
||||
for section in REQUIRED_OUTPUT_SECTIONS:
|
||||
assert f"{section}:" in markdown
|
||||
assert "MEVG" in markdown
|
||||
assert "Real Case Calibration" in markdown
|
||||
|
||||
for route in ["career", "relationship", "finance"]:
|
||||
contract = snapshot["strict_workflow_contracts"][route]
|
||||
assert contract["output_template_contract"]["required_sections"] == REQUIRED_OUTPUT_SECTIONS
|
||||
|
||||
|
||||
def test_p1_p2_mevg_queue_and_real_case_index_are_executable_contracts() -> None:
|
||||
strict = _collect_strict_evidence("career", _base_modules())
|
||||
|
||||
queue = strict["mevg_collection_queue"]
|
||||
assert queue["status"] in {"queued", "blocked"}
|
||||
assert queue["execution_mode"] == "cache_ttl_free_tier_queue"
|
||||
assert queue["cache_ttl_hours"] >= 24
|
||||
assert queue["evidence_packet"]["packet_type"] == "mevg_external_evidence_packet"
|
||||
assert queue["failure_record"]["status"] == "blocked_until_external_fetch"
|
||||
assert queue["failure_record"]["blocked_reason"]
|
||||
|
||||
case_layer = strict["real_case_calibration_layer"]
|
||||
assert case_layer["batch_id"] == "real_case_studies_batch1"
|
||||
assert case_layer["index_status"] == "available"
|
||||
assert case_layer["fallback_policy"] == "downgrade_without_matching_cases"
|
||||
assert "relationship" in case_layer["case_index_by_domain"]
|
||||
assert "docs/benchmark/legacy-marriage-v6.1/verify-results-v6.1.json" in case_layer["case_index_by_domain"]["relationship"]
|
||||
|
||||
|
||||
def test_p3_p4_domain_layers_affect_judgement_and_technical_debt_is_split() -> None:
|
||||
strict = _collect_strict_evidence("career", _base_modules())
|
||||
judgement = strict["event_judgement"]
|
||||
|
||||
for marker in [
|
||||
"dasha_timing_layer_used",
|
||||
"varga_strength_layer_used",
|
||||
"annual_special_layer_context",
|
||||
"modifier_obstacle_layer_used",
|
||||
]:
|
||||
assert marker in judgement["secondary_context"]
|
||||
|
||||
debt = strict["technical_debt_contract"]
|
||||
assert debt["narayana"]["status_breakdown"]["closed"]
|
||||
assert debt["narayana"]["status_breakdown"]["blocked"]
|
||||
assert debt["tajika"]["status_breakdown"]["closed"]
|
||||
assert debt["tajika"]["status_breakdown"]["blocked"]
|
||||
assert debt["oracle_parity"]["status"] == "blocked"
|
||||
|
||||
|
||||
def test_p5_p6_p7_p8_frontend_batches_oracle_and_hygiene_are_visible() -> None:
|
||||
result = _run_engine(
|
||||
"full-reading",
|
||||
"--year",
|
||||
"REDACTED_YEAR",
|
||||
"--month",
|
||||
"4",
|
||||
"--day",
|
||||
"17",
|
||||
"--hour",
|
||||
"14",
|
||||
"--minute",
|
||||
"49",
|
||||
"--lat",
|
||||
"36.466667",
|
||||
"--lon",
|
||||
"114.2",
|
||||
"--tz",
|
||||
"8",
|
||||
"--today",
|
||||
"2026-07-02",
|
||||
"--transit-date",
|
||||
"2026-07-02",
|
||||
)
|
||||
snapshot = result["ai_prompt_pack"]["evidence_snapshot"]
|
||||
|
||||
assert snapshot["remaining_priority1_batch_queue"]["batch_statuses"]["real_case_studies_batch1"] == "next"
|
||||
assert snapshot["oracle_parity_queue"]["systems"] == ["VedAstro", "PyJHora", "jyotishganit"]
|
||||
assert snapshot["oracle_parity_queue"]["priority_domains"] == ["Dasha", "Shadbala", "Tajika", "Narayana"]
|
||||
assert snapshot["release_hygiene_plan"]["git_sync_required"] is True
|
||||
assert snapshot["release_hygiene_plan"]["gc_log_policy"] == "separate_safe_cleanup_plan_required"
|
||||
|
||||
main_js = (ROOT / "jyotish-app" / "main.js").read_text(encoding="utf-8")
|
||||
assert "core source refs" in main_js
|
||||
assert "why confidence downgraded" in main_js
|
||||
assert "next batch queue" in main_js
|
||||
assert "oracle parity" in main_js
|
||||
Reference in New Issue
Block a user