Enforce interpretation source content contracts
This commit is contained in:
@@ -313,6 +313,7 @@ function buildChartContext(cd, guidedTopicContext = null) {
|
||||
const primaryRoute = officialSnapshot.strict_workflow_primary_route || Object.keys(strictContracts)[0] || '';
|
||||
const topReaderContract = primaryRoute ? (strictContracts[primaryRoute] || {}) : {};
|
||||
const adjudicationStages = topReaderContract.adjudication_stages || {};
|
||||
const predictionBoundaryContract = topReaderContract.prediction_boundary_contract || cd.ai_prompt_pack.evidence_snapshot.prediction_boundary_contract || {};
|
||||
const multiReferenceSummary = topReaderContract.multi_reference_reading_summary || {};
|
||||
const techniqueAuditSummary = topReaderContract.technique_audit_summary || {};
|
||||
const runtimePlannerBoundary = runtimePlanner && typeof runtimePlanner === 'object' && Object.keys(runtimePlanner).length
|
||||
@@ -341,6 +342,14 @@ function buildChartContext(cd, guidedTopicContext = null) {
|
||||
`main_conflicts=${(topReaderContract.main_conflicts || []).map(item => item?.type).filter(Boolean).join('/') || 'none'}`,
|
||||
].join('\n')
|
||||
: '';
|
||||
const predictionBoundary = predictionBoundaryContract && typeof predictionBoundaryContract === 'object' && Object.keys(predictionBoundaryContract).length
|
||||
? [
|
||||
'【Prediction Boundary Contract】',
|
||||
`source_refs=${(predictionBoundaryContract.source_refs || []).join(' / ') || '-'}`,
|
||||
`promise=${predictionBoundaryContract.promise?.status || adjudicationStages.promise?.status || 'missing'} · activation=${predictionBoundaryContract.activation?.status || adjudicationStages.activation?.status || 'missing'} · manifestation=${predictionBoundaryContract.manifestation?.status || adjudicationStages.manifestation?.status || 'missing'} · label=${predictionBoundaryContract.label?.value || topReaderContract.dominant_label || '-'}`,
|
||||
`mevg=${predictionBoundaryContract.confidence_boundary?.mevg_status || 'blocked'} · real_case=${predictionBoundaryContract.confidence_boundary?.real_case_calibration_status || 'blocked'} · policy=${predictionBoundaryContract.confidence_boundary?.unverified_claim_policy || 'downgrade_or_block'}`,
|
||||
].join('\n')
|
||||
: '';
|
||||
const vedastroBoundary = vedastroOverview && typeof vedastroOverview === 'object'
|
||||
? [
|
||||
'【VedAstro Overview Boundary】',
|
||||
@@ -370,6 +379,8 @@ function buildChartContext(cd, guidedTopicContext = null) {
|
||||
'',
|
||||
topReaderBoundary,
|
||||
'',
|
||||
predictionBoundary,
|
||||
'',
|
||||
guidedTopicBoundary,
|
||||
'',
|
||||
vedastroBoundary,
|
||||
|
||||
+139
-1
@@ -128,6 +128,37 @@ CORE_RULE_SOURCE_REFS = [
|
||||
"references/transit-multi-reference-guide.md",
|
||||
]
|
||||
|
||||
PROMOTE_BATCH2_TOPIC_SOURCE_REFS = [
|
||||
"references/vimshottari_dasha_guide.md",
|
||||
"references/pratyantar-calculation-guide.md",
|
||||
"references/divisional-chart-deep-reading.md",
|
||||
"references/shadbala-complete-methodology.md",
|
||||
"references/ashtakavarga-complete-system.md",
|
||||
"references/tajika-yoga-complete-guide.md",
|
||||
"references/jaimini-complete-system.md",
|
||||
"references/kp-astrology-complete-system.md",
|
||||
"references/argala-complete-guide.md",
|
||||
"references/badhaka-obstacle-planet-guide.md",
|
||||
"references/condition-dasha-complete.md",
|
||||
]
|
||||
|
||||
REFERENCE_ONLY_CONFLICT_SOURCE_REFS = [
|
||||
"references/dasa-convergence-methodology.md",
|
||||
"references/multi-dasha-convergence-protocol.md",
|
||||
"references/yoga-strength-scoring-system.md",
|
||||
]
|
||||
|
||||
BLOCKED_NON_RUNTIME_SOURCE_REFS = [
|
||||
"references/varga-system-quick-reference.md",
|
||||
"references/yoga-list-chinese.md",
|
||||
"references/analysis-full-reading-v4.0.md",
|
||||
"references/analysis-full-reading-v1.8-review.md",
|
||||
"references/audit-skill-full-test-2026-05-04.md",
|
||||
"references/feature-gap-matrix-2026.md",
|
||||
"references/kp-practical-event-timing.md",
|
||||
"references/consultation-case-library.md",
|
||||
]
|
||||
|
||||
|
||||
def _build_interpretation_source_inventory(source_refs: List[str]) -> Dict[str, Any]:
|
||||
primary_truth = [
|
||||
@@ -166,6 +197,8 @@ def _build_interpretation_source_inventory(source_refs: List[str]) -> Dict[str,
|
||||
"references/open_source_sources/vedic-astro-skills/codex/skills/vedic-core/resources/p1_p12.md",
|
||||
"references/open_source_sources/vedic-astro-skills/codex/skills/vedic-core/resources/house_framework.md",
|
||||
*CORE_RULE_SOURCE_REFS,
|
||||
*PROMOTE_BATCH2_TOPIC_SOURCE_REFS,
|
||||
*REFERENCE_ONLY_CONFLICT_SOURCE_REFS,
|
||||
*frontend_interpretation,
|
||||
*qa_governance,
|
||||
*reader_validation,
|
||||
@@ -223,6 +256,28 @@ def _build_interpretation_source_inventory(source_refs: List[str]) -> Dict[str,
|
||||
"missing_refs": [path for path in CORE_RULE_SOURCE_REFS if not _repo_relative_exists(path)],
|
||||
"boundary": "First promoted core references; visible to strict workflows but still subject to conflict arbitration.",
|
||||
},
|
||||
"promote_batch2_topic_sources": {
|
||||
"status": "available",
|
||||
"promotion_status": "reference_layer_candidate",
|
||||
"promotion_batch": "priority1_batch1_remaining_promote_11",
|
||||
"source_refs": _existing_paths(PROMOTE_BATCH2_TOPIC_SOURCE_REFS),
|
||||
"missing_refs": [path for path in PROMOTE_BATCH2_TOPIC_SOURCE_REFS if not _repo_relative_exists(path)],
|
||||
"boundary": "Topic-specific promoted references; visible as supporting layers, not all-at-once primary truth.",
|
||||
},
|
||||
"reference_only_conflict_sources": {
|
||||
"status": "available",
|
||||
"promotion_status": "reference_only",
|
||||
"source_refs": _existing_paths(REFERENCE_ONLY_CONFLICT_SOURCE_REFS),
|
||||
"missing_refs": [path for path in REFERENCE_ONLY_CONFLICT_SOURCE_REFS if not _repo_relative_exists(path)],
|
||||
"boundary": "Useful conflict/reference material; must not outrank primary rule sources or tested contracts.",
|
||||
},
|
||||
"blocked_non_runtime_sources": {
|
||||
"status": "blocked",
|
||||
"promotion_status": "not_truth_source",
|
||||
"source_refs": _existing_paths(BLOCKED_NON_RUNTIME_SOURCE_REFS),
|
||||
"missing_refs": [path for path in BLOCKED_NON_RUNTIME_SOURCE_REFS if not _repo_relative_exists(path)],
|
||||
"boundary": "Duplicate, obsolete, or quarantined files; never expose through runtime source_refs.",
|
||||
},
|
||||
"quarantined_drafts": {
|
||||
"status": "quarantined",
|
||||
"promotion_status": "not_truth_source",
|
||||
@@ -233,8 +288,10 @@ def _build_interpretation_source_inventory(source_refs: List[str]) -> Dict[str,
|
||||
}
|
||||
missing_refs = [path for layer in layers.values() for path in layer["missing_refs"]]
|
||||
quarantined_refs = set(layers["quarantined_drafts"]["source_refs"])
|
||||
blocked_non_runtime_refs = set(layers["blocked_non_runtime_sources"]["source_refs"])
|
||||
promoted_quarantined = sorted(quarantined_refs.intersection(source_refs))
|
||||
status = "used" if not missing_refs and not promoted_quarantined else "partial"
|
||||
promoted_blocked_non_runtime = sorted(blocked_non_runtime_refs.intersection(source_refs))
|
||||
status = "used" if not missing_refs and not promoted_quarantined and not promoted_blocked_non_runtime else "partial"
|
||||
return {
|
||||
"status": status,
|
||||
"source": "repo_interpretation_source_inventory_v1",
|
||||
@@ -243,11 +300,14 @@ def _build_interpretation_source_inventory(source_refs: List[str]) -> Dict[str,
|
||||
"primary_truth_count": len(layers["primary_truth"]["source_refs"]),
|
||||
"reference_layer_count": len(_existing_paths(reference_layer)),
|
||||
"quarantined_draft_count": len(layers["quarantined_drafts"]["source_refs"]),
|
||||
"blocked_non_runtime_count": len(layers["blocked_non_runtime_sources"]["source_refs"]),
|
||||
"missing_ref_count": len(missing_refs),
|
||||
"promoted_quarantined_count": len(promoted_quarantined),
|
||||
"promoted_blocked_non_runtime_count": len(promoted_blocked_non_runtime),
|
||||
},
|
||||
"missing_refs": missing_refs,
|
||||
"promoted_quarantined_refs": promoted_quarantined,
|
||||
"promoted_blocked_non_runtime_refs": promoted_blocked_non_runtime,
|
||||
"boundary": "Inventory is explicit and conservative; local drafts are indexed but not treated as truth sources.",
|
||||
}
|
||||
|
||||
@@ -267,6 +327,9 @@ def _existing_interpretation_source_pack() -> Dict[str, Any]:
|
||||
mevg_path = "references/mandatory-verification-gate-protocol.md"
|
||||
real_case_checklist_path = "references/real-reading-quality-checklist.md"
|
||||
core_rule_paths = CORE_RULE_SOURCE_REFS
|
||||
promote_batch2_paths = PROMOTE_BATCH2_TOPIC_SOURCE_REFS
|
||||
reference_only_paths = REFERENCE_ONLY_CONFLICT_SOURCE_REFS
|
||||
blocked_non_runtime_paths = BLOCKED_NON_RUNTIME_SOURCE_REFS
|
||||
frontend_interpretation_paths = [
|
||||
"jyotish-app/interpretation.js",
|
||||
"jyotish-app/analysis-deep.js",
|
||||
@@ -308,6 +371,8 @@ def _existing_interpretation_source_pack() -> Dict[str, Any]:
|
||||
mevg_path,
|
||||
real_case_checklist_path,
|
||||
*core_rule_paths,
|
||||
*promote_batch2_paths,
|
||||
*reference_only_paths,
|
||||
*frontend_interpretation_paths,
|
||||
*planet_house_paths,
|
||||
qa_rules_path,
|
||||
@@ -337,6 +402,8 @@ def _existing_interpretation_source_pack() -> Dict[str, Any]:
|
||||
"mevg_mandatory_external_verification",
|
||||
"real_case_quality_checklist",
|
||||
"priority1_batch1_core_rule_sources",
|
||||
"priority1_batch1_promote_topic_sources",
|
||||
"reference_only_conflict_sources",
|
||||
"qa_governance_rules",
|
||||
"reader_validation_rules",
|
||||
"frontend_interpretation_layer",
|
||||
@@ -354,6 +421,25 @@ def _existing_interpretation_source_pack() -> Dict[str, Any]:
|
||||
"promotion_batch": "priority1_batch1_core5",
|
||||
"boundary": "Audit-promoted core references; use as visible rule sources with conflict arbitration.",
|
||||
},
|
||||
"promote_batch2_topic_layer": {
|
||||
"status": "available" if all(_repo_relative_exists(path) for path in promote_batch2_paths) else "partial",
|
||||
"source_refs": promote_batch2_paths,
|
||||
"promotion_status": "reference_layer_candidate",
|
||||
"promotion_batch": "priority1_batch1_remaining_promote_11",
|
||||
"boundary": "Topic-specific promoted references; wire by domain and do not flatten into primary truth.",
|
||||
},
|
||||
"reference_only_conflict_layer": {
|
||||
"status": "available" if all(_repo_relative_exists(path) for path in reference_only_paths) else "partial",
|
||||
"source_refs": reference_only_paths,
|
||||
"promotion_status": "reference_only",
|
||||
"boundary": "Reference-only sources can explain conflicts but cannot override primary rule sources.",
|
||||
},
|
||||
"blocked_non_runtime_layer": {
|
||||
"status": "blocked",
|
||||
"source_refs": blocked_non_runtime_paths,
|
||||
"promotion_status": "not_truth_source",
|
||||
"boundary": "Duplicate, obsolete, and quarantined files are deliberately excluded from runtime source_refs.",
|
||||
},
|
||||
"frontend_interpretation_layer": {
|
||||
"status": "available" if all(_repo_relative_exists(path) for path in frontend_interpretation_paths) else "partial",
|
||||
"source_refs": frontend_interpretation_paths,
|
||||
@@ -2553,6 +2639,16 @@ def _build_technique_audit_summary(route: str, strict: Dict[str, Any]) -> Dict[s
|
||||
if isinstance(interpretation_source_pack.get("core_rule_source_layer"), dict)
|
||||
else []
|
||||
),
|
||||
"promote_batch2_source_refs": (
|
||||
interpretation_source_pack.get("promote_batch2_topic_layer", {}).get("source_refs")
|
||||
if isinstance(interpretation_source_pack.get("promote_batch2_topic_layer"), dict)
|
||||
else []
|
||||
),
|
||||
"reference_only_source_refs": (
|
||||
interpretation_source_pack.get("reference_only_conflict_layer", {}).get("source_refs")
|
||||
if isinstance(interpretation_source_pack.get("reference_only_conflict_layer"), dict)
|
||||
else []
|
||||
),
|
||||
"missing_refs": interpretation_source_pack.get("missing_refs") or [],
|
||||
"effect_on_confidence": (
|
||||
"uses existing BPHS/Raman/frontend/template source layers; missing refs lower confidence"
|
||||
@@ -2646,6 +2742,47 @@ def _build_adjudication_stages(route: str, present: Dict[str, Any], event_judgem
|
||||
}
|
||||
|
||||
|
||||
def _build_prediction_boundary_contract(route: str, strict: Dict[str, Any]) -> Dict[str, Any]:
|
||||
stages = strict.get("adjudication_stages") if isinstance(strict.get("adjudication_stages"), dict) else {}
|
||||
audit = strict.get("technique_audit_summary") if isinstance(strict.get("technique_audit_summary"), dict) else {}
|
||||
mevg = audit.get("mevg_global_web_evidence") if isinstance(audit.get("mevg_global_web_evidence"), dict) else {}
|
||||
real_case = audit.get("real_case_calibration") if isinstance(audit.get("real_case_calibration"), dict) else {}
|
||||
interpretation_source_pack = (
|
||||
audit.get("interpretation_source_pack")
|
||||
if isinstance(audit.get("interpretation_source_pack"), dict)
|
||||
else {}
|
||||
)
|
||||
return {
|
||||
"route": route,
|
||||
"status": "used",
|
||||
"source_refs": interpretation_source_pack.get("core_rule_source_refs") or CORE_RULE_SOURCE_REFS,
|
||||
"event_judgment_skeleton": {
|
||||
"status": "used",
|
||||
"required_sections": ["promise", "activation", "manifestation", "label"],
|
||||
"source_ref": "references/event_judgment_skeleton.md",
|
||||
},
|
||||
"promise": stages.get("promise") or {},
|
||||
"activation": stages.get("activation") or {},
|
||||
"manifestation": stages.get("manifestation") or {},
|
||||
"label": stages.get("label") or {},
|
||||
"confidence_boundary": {
|
||||
"status": "used",
|
||||
"source_ref": "references/prediction-boundary-protocol.md",
|
||||
"confidence_cap": strict.get("confidence_cap"),
|
||||
"blocked": bool(strict.get("blocked")),
|
||||
"mevg_status": mevg.get("status") or "blocked",
|
||||
"real_case_calibration_status": real_case.get("status") or "blocked",
|
||||
"unverified_claim_policy": "downgrade_or_block",
|
||||
"precision_policy": "timing_window_not_guaranteed_event_form",
|
||||
},
|
||||
"modifier_rule_sources": {
|
||||
"dignity": "references/planetary-dignity-complete-reference.md",
|
||||
"planetary_conditions": "references/retrograde-combustion-war-guide.md",
|
||||
"transit": "references/transit-multi-reference-guide.md",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
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),
|
||||
@@ -2671,6 +2808,7 @@ def _attach_top_reader_contract(route: str, strict: Dict[str, Any]) -> Dict[str,
|
||||
event_judgement = {}
|
||||
strict["technique_audit_summary"] = _build_technique_audit_summary(route, strict)
|
||||
strict["adjudication_stages"] = _build_adjudication_stages(route, present, event_judgement)
|
||||
strict["prediction_boundary_contract"] = _build_prediction_boundary_contract(route, strict)
|
||||
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)
|
||||
|
||||
@@ -768,3 +768,12 @@
|
||||
- `technique_audit_summary.interpretation_source_pack` 现在直接暴露 `core_rule_source_refs`,career / relationship / finance strict workflow 都能看到同一组核心源头。
|
||||
- 新增 `tests/test_interpretation_source_core5_strict_visibility.py`;同时加固 `tests/test_interpretation_source_inventory_gate.py` 对核心层的断言。
|
||||
- 边界仍保留:核心 5 已进入调用链可见性层,但具体解释仍需冲突仲裁、MEVG、真实案例校准和领域分盘/大运证据。
|
||||
|
||||
## 2026-07-02T15:42:00+08:00 - 核心 5 内容级调用与第二批资料层闭环
|
||||
|
||||
- 核心 5 不再只是可见:career / relationship / finance strict workflow 现在生成 `prediction_boundary_contract`,强制绑定 `promise -> activation -> manifestation -> label`、MEVG blocked、Real Case Calibration blocked 与核心 5 source refs。
|
||||
- 第二批 promote 11 个专题源头已接成 `promote_batch2_topic_layer`:Vimshottari、Pratyantar、分盘深读、Shadbala、Ashtakavarga、Tajika、Jaimini、KP、Argala、Badhaka、Condition Dasha。
|
||||
- `reference-only` 3 个源头已接成 `reference_only_conflict_layer`,只允许作为冲突/参考材料:`dasa-convergence-methodology`、`multi-dasha-convergence-protocol`、`yoga-strength-scoring-system`。
|
||||
- duplicate / obsolete / quarantine 8 个文件已列入 `blocked_non_runtime_layer`,并由 inventory gate 检查不进入 runtime source refs;重点包括 `kp-practical-event-timing.md` 与 `consultation-case-library.md`。
|
||||
- Prompt Pack / API fallback / AI Chat 已同步 `prediction_boundary_contract`、核心 5、第二批 11、reference-only 3;AI Chat 上下文新增 `【Prediction Boundary Contract】` 段落。
|
||||
- 真实 full-reading 回归确认:REDACTED_DATE REDACTED_TIME REDACTED_PLACE矿区样例中 relationship / career / finance 三条 strict contract 均带 prediction boundary,且 MEVG 与真实案例校准仍为 blocked。
|
||||
|
||||
@@ -3901,6 +3901,8 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
|
||||
'不要仅凭单一配置下结论;核心判断至少交叉 D1、D9、Dasha、Shadbala/Ashtakavarga 或 Transit 中的两个证据层。',
|
||||
'必须显式标注置信度和边界:Dasha/PDF 起点差异、Shadbala 外部绝对值 oracle 尚未完成时,不得声称已经完全校准。',
|
||||
'VedAstro 官方全量快照是第一原始证据层;若该层 blocked,必须把本地结果标记为 fallback。',
|
||||
'必须按 promise → activation → manifestation → label 输出;每个判断都要说明属于承诺、激活、落地形式还是标签层。',
|
||||
'未完成 MEVG / Real Case Calibration 时必须降级或标 blocked,不得把内部一致性写成已验证结论。',
|
||||
]
|
||||
oracle_progress = {
|
||||
'scope': 'external_oracle_evidence_validation',
|
||||
@@ -3938,6 +3940,53 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
|
||||
'shadbala_ranking': top_strength,
|
||||
},
|
||||
'functional_benefic_malefic': functional_layer,
|
||||
'interpretation_source_pack': {
|
||||
'status': 'fallback_prompt_pack_only',
|
||||
'source': 'api_chart_prompt_pack_fallback',
|
||||
'core_rule_source_refs': [
|
||||
'references/prediction-boundary-protocol.md',
|
||||
'references/event_judgment_skeleton.md',
|
||||
'references/planetary-dignity-complete-reference.md',
|
||||
'references/retrograde-combustion-war-guide.md',
|
||||
'references/transit-multi-reference-guide.md',
|
||||
],
|
||||
'promote_batch2_source_refs': [
|
||||
'references/vimshottari_dasha_guide.md',
|
||||
'references/pratyantar-calculation-guide.md',
|
||||
'references/divisional-chart-deep-reading.md',
|
||||
'references/shadbala-complete-methodology.md',
|
||||
'references/ashtakavarga-complete-system.md',
|
||||
'references/tajika-yoga-complete-guide.md',
|
||||
'references/jaimini-complete-system.md',
|
||||
'references/kp-astrology-complete-system.md',
|
||||
'references/argala-complete-guide.md',
|
||||
'references/badhaka-obstacle-planet-guide.md',
|
||||
'references/condition-dasha-complete.md',
|
||||
],
|
||||
'reference_only_source_refs': [
|
||||
'references/dasa-convergence-methodology.md',
|
||||
'references/multi-dasha-convergence-protocol.md',
|
||||
'references/yoga-strength-scoring-system.md',
|
||||
],
|
||||
},
|
||||
'prediction_boundary_contract': {
|
||||
'status': 'fallback_prompt_pack_only',
|
||||
'source_refs': [
|
||||
'references/prediction-boundary-protocol.md',
|
||||
'references/event_judgment_skeleton.md',
|
||||
'references/planetary-dignity-complete-reference.md',
|
||||
'references/retrograde-combustion-war-guide.md',
|
||||
'references/transit-multi-reference-guide.md',
|
||||
],
|
||||
'event_judgment_skeleton': {
|
||||
'required_sections': ['promise', 'activation', 'manifestation', 'label'],
|
||||
},
|
||||
'confidence_boundary': {
|
||||
'mevg_status': 'blocked',
|
||||
'real_case_calibration_status': 'blocked',
|
||||
'unverified_claim_policy': 'downgrade_or_block',
|
||||
},
|
||||
},
|
||||
'vedastro_official_full_snapshot': vedastro_official_full_snapshot,
|
||||
'vedastro_overview': vedastro_overview,
|
||||
'guided_topics': guided_topics,
|
||||
@@ -3952,7 +4001,24 @@ class JyotishAPIHandler(BaseHTTPRequestHandler):
|
||||
'references/ai-reading-workflow-prompt.md',
|
||||
'references/comprehensive-reading-workflow.md',
|
||||
'references/prediction-boundary-protocol.md',
|
||||
'references/event_judgment_skeleton.md',
|
||||
'references/planetary-dignity-complete-reference.md',
|
||||
'references/retrograde-combustion-war-guide.md',
|
||||
'references/transit-multi-reference-guide.md',
|
||||
'references/vimshottari_dasha_guide.md',
|
||||
'references/pratyantar-calculation-guide.md',
|
||||
'references/divisional-chart-deep-reading.md',
|
||||
'references/shadbala-complete-methodology.md',
|
||||
'references/ashtakavarga-complete-system.md',
|
||||
'references/tajika-yoga-complete-guide.md',
|
||||
'references/jaimini-complete-system.md',
|
||||
'references/kp-astrology-complete-system.md',
|
||||
'references/argala-complete-guide.md',
|
||||
'references/badhaka-obstacle-planet-guide.md',
|
||||
'references/condition-dasha-complete.md',
|
||||
'references/dasa-convergence-methodology.md',
|
||||
'references/multi-dasha-convergence-protocol.md',
|
||||
'references/yoga-strength-scoring-system.md',
|
||||
'references/shadbala-interpretation-methodology.md',
|
||||
'references/navamsa-d9-interpretation-template.md',
|
||||
],
|
||||
|
||||
@@ -1432,6 +1432,7 @@ def _compact_strict_workflow_contract(strict):
|
||||
'conflicts': strict.get('conflicts') or [],
|
||||
'technique_audit_summary': strict.get('technique_audit_summary') or {},
|
||||
'adjudication_stages': strict.get('adjudication_stages') or {},
|
||||
'prediction_boundary_contract': strict.get('prediction_boundary_contract') 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 {},
|
||||
@@ -1558,6 +1559,21 @@ def _build_ai_prompt_pack(report):
|
||||
vedastro_official_full_snapshot = _build_vedastro_official_full_snapshot_payload(modules)
|
||||
strict_workflow_contracts = _extract_strict_workflow_contracts(modules)
|
||||
strict_workflow_primary_route, primary_strict_contract = _preferred_strict_workflow_contract(strict_workflow_contracts)
|
||||
primary_prediction_boundary_contract = (
|
||||
primary_strict_contract.get('prediction_boundary_contract')
|
||||
if isinstance(primary_strict_contract, dict)
|
||||
else {}
|
||||
)
|
||||
primary_audit = (
|
||||
primary_strict_contract.get('technique_audit_summary')
|
||||
if isinstance(primary_strict_contract, dict)
|
||||
else {}
|
||||
)
|
||||
interpretation_source_audit = (
|
||||
primary_audit.get('interpretation_source_pack')
|
||||
if isinstance(primary_audit, dict) and isinstance(primary_audit.get('interpretation_source_pack'), dict)
|
||||
else {}
|
||||
)
|
||||
guided_topics = modules.get('guided_topics') if isinstance(modules.get('guided_topics'), list) else build_guided_topics(report)
|
||||
capability_evidence_pool = build_capability_evidence_pool_summary()
|
||||
|
||||
@@ -1630,6 +1646,15 @@ def _build_ai_prompt_pack(report):
|
||||
},
|
||||
'oracle_progress': oracle_progress,
|
||||
'functional_benefic_malefic': functional_layer,
|
||||
'interpretation_source_pack': {
|
||||
'status': interpretation_source_audit.get('status') or 'blocked',
|
||||
'source': interpretation_source_audit.get('source') or 'repo_existing_interpretation_sources',
|
||||
'core_rule_source_refs': interpretation_source_audit.get('core_rule_source_refs') or [],
|
||||
'promote_batch2_source_refs': interpretation_source_audit.get('promote_batch2_source_refs') or [],
|
||||
'reference_only_source_refs': interpretation_source_audit.get('reference_only_source_refs') or [],
|
||||
'missing_refs': interpretation_source_audit.get('missing_refs') or [],
|
||||
},
|
||||
'prediction_boundary_contract': primary_prediction_boundary_contract or {},
|
||||
'strict_workflow_primary_route': strict_workflow_primary_route,
|
||||
'strict_workflow_routes_available': list(strict_workflow_contracts.keys()),
|
||||
'strict_workflow_contracts': strict_workflow_contracts,
|
||||
@@ -1660,6 +1685,8 @@ def _build_ai_prompt_pack(report):
|
||||
"若 evidence_snapshot.vedastro_overview.status 为 ok,请把它作为用户可见外部概览证据明确写出,但不要把 overview-only 结果误当作长周期精扫结论。",
|
||||
"VedAstro 官方全量快照是第一原始证据层;若 evidence_snapshot.vedastro_official_full_snapshot.status 不是 ok/partial,必须说明官方全量资料 blocked,并把本地结果标记为 fallback。",
|
||||
"若 evidence_snapshot.capability_evidence_pool 存在,请把 89 项视为后台备选证据池;不要把所有能力条目平铺成结论,也不要让 audit_only/alias 条目影响占星判断。",
|
||||
"必须按 promise → activation → manifestation → label 输出;每个判断都要说明属于承诺、激活、落地形式还是标签层。",
|
||||
"未完成 MEVG / Real Case Calibration 时必须降级或标 blocked,不得把内部一致性写成已验证结论。",
|
||||
]
|
||||
|
||||
return {
|
||||
@@ -1672,7 +1699,24 @@ def _build_ai_prompt_pack(report):
|
||||
'references/ai-reading-workflow-prompt.md',
|
||||
'references/comprehensive-reading-workflow.md',
|
||||
'references/prediction-boundary-protocol.md',
|
||||
'references/event_judgment_skeleton.md',
|
||||
'references/planetary-dignity-complete-reference.md',
|
||||
'references/retrograde-combustion-war-guide.md',
|
||||
'references/transit-multi-reference-guide.md',
|
||||
'references/vimshottari_dasha_guide.md',
|
||||
'references/pratyantar-calculation-guide.md',
|
||||
'references/divisional-chart-deep-reading.md',
|
||||
'references/shadbala-complete-methodology.md',
|
||||
'references/ashtakavarga-complete-system.md',
|
||||
'references/tajika-yoga-complete-guide.md',
|
||||
'references/jaimini-complete-system.md',
|
||||
'references/kp-astrology-complete-system.md',
|
||||
'references/argala-complete-guide.md',
|
||||
'references/badhaka-obstacle-planet-guide.md',
|
||||
'references/condition-dasha-complete.md',
|
||||
'references/dasa-convergence-methodology.md',
|
||||
'references/multi-dasha-convergence-protocol.md',
|
||||
'references/yoga-strength-scoring-system.md',
|
||||
'references/shadbala-interpretation-methodology.md',
|
||||
'references/navamsa-d9-interpretation-template.md',
|
||||
'references/interpretation_template_registry.json',
|
||||
|
||||
@@ -286,6 +286,24 @@ def test_full_reading_reports_ayanamsa_metadata_and_ai_prompt_pack() -> None:
|
||||
assert any(row["technique"] == "MEVG / Global Web Evidence" for row in audit_table)
|
||||
assert any(row["technique"] == "Real Case Calibration" for row in audit_table)
|
||||
assert any(row["technique"] == "Interpretation Source Pack" for row in audit_table)
|
||||
interpretation_source_pack = prompt_pack["evidence_snapshot"]["interpretation_source_pack"]
|
||||
assert interpretation_source_pack["core_rule_source_refs"] == [
|
||||
"references/prediction-boundary-protocol.md",
|
||||
"references/event_judgment_skeleton.md",
|
||||
"references/planetary-dignity-complete-reference.md",
|
||||
"references/retrograde-combustion-war-guide.md",
|
||||
"references/transit-multi-reference-guide.md",
|
||||
]
|
||||
assert "references/vimshottari_dasha_guide.md" in interpretation_source_pack["promote_batch2_source_refs"]
|
||||
assert "references/yoga-strength-scoring-system.md" in interpretation_source_pack["reference_only_source_refs"]
|
||||
prediction_boundary = prompt_pack["evidence_snapshot"]["prediction_boundary_contract"]
|
||||
assert prediction_boundary["confidence_boundary"]["unverified_claim_policy"] == "downgrade_or_block"
|
||||
assert prediction_boundary["event_judgment_skeleton"]["required_sections"] == [
|
||||
"promise",
|
||||
"activation",
|
||||
"manifestation",
|
||||
"label",
|
||||
]
|
||||
functional_rows = [row for row in audit_table if row["technique"] == "Functional Benefic/Malefic"]
|
||||
assert functional_rows
|
||||
assert functional_rows[0]["status"] == "used"
|
||||
@@ -359,6 +377,7 @@ def test_full_reading_reports_ayanamsa_metadata_and_ai_prompt_pack() -> None:
|
||||
assert "finance" in vedastro_official_snapshot["strict_workflow_contracts"]
|
||||
career_contract = vedastro_official_snapshot["strict_workflow_contracts"]["career"]
|
||||
assert "adjudication_stages" in career_contract
|
||||
assert "prediction_boundary_contract" in career_contract
|
||||
assert "multi_reference_reading_summary" in career_contract
|
||||
assert "modifier_frame" in career_contract["multi_reference_reading_summary"]
|
||||
assert vedastro_official_snapshot["strict_workflow_primary_route"] in {"relationship", "career", "finance", None}
|
||||
|
||||
@@ -332,6 +332,9 @@ def test_frontend_consumes_top_reader_contract_in_prompt_pack_and_ai_chat() -> N
|
||||
assert "Top-reader adjudication" in main
|
||||
assert "multi_reference_reading_summary" in ai_chat
|
||||
assert "adjudication_stages" in ai_chat
|
||||
assert "prediction_boundary_contract" in ai_chat
|
||||
assert "【Prediction Boundary Contract】" in ai_chat
|
||||
assert "unverified_claim_policy" in ai_chat
|
||||
assert "technique_audit_summary" in ai_chat
|
||||
assert "【Top Reader Contract】" in ai_chat
|
||||
assert ".ai-prompt-pack-contract-card" in style
|
||||
|
||||
@@ -51,6 +51,14 @@ def test_interpretation_source_inventory_gate_reports_layered_source_pack() -> N
|
||||
"references/retrograde-combustion-war-guide.md",
|
||||
"references/transit-multi-reference-guide.md",
|
||||
]
|
||||
assert layers["promote_batch2_topic_sources"]["promotion_batch"] == "priority1_batch1_remaining_promote_11"
|
||||
assert "references/vimshottari_dasha_guide.md" in layers["promote_batch2_topic_sources"]["source_refs"]
|
||||
assert "references/condition-dasha-complete.md" in layers["promote_batch2_topic_sources"]["source_refs"]
|
||||
assert layers["reference_only_conflict_sources"]["promotion_status"] == "reference_only"
|
||||
assert "references/multi-dasha-convergence-protocol.md" in layers["reference_only_conflict_sources"]["source_refs"]
|
||||
assert layers["blocked_non_runtime_sources"]["promotion_status"] == "not_truth_source"
|
||||
assert "references/kp-practical-event-timing.md" in layers["blocked_non_runtime_sources"]["source_refs"]
|
||||
assert report["summary"]["blocked_non_runtime_count"] >= 8
|
||||
|
||||
draft_refs = layers["quarantined_drafts"]["source_refs"]
|
||||
source_refs = set(report["runtime_source_refs"])
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Regression tests for source-pack content contracts beyond visibility."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from mcp_server import _collect_strict_evidence, _existing_interpretation_source_pack
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
CORE5 = [
|
||||
"references/prediction-boundary-protocol.md",
|
||||
"references/event_judgment_skeleton.md",
|
||||
"references/planetary-dignity-complete-reference.md",
|
||||
"references/retrograde-combustion-war-guide.md",
|
||||
"references/transit-multi-reference-guide.md",
|
||||
]
|
||||
|
||||
PROMOTE_BATCH2 = [
|
||||
"references/vimshottari_dasha_guide.md",
|
||||
"references/pratyantar-calculation-guide.md",
|
||||
"references/divisional-chart-deep-reading.md",
|
||||
"references/shadbala-complete-methodology.md",
|
||||
"references/ashtakavarga-complete-system.md",
|
||||
"references/tajika-yoga-complete-guide.md",
|
||||
"references/jaimini-complete-system.md",
|
||||
"references/kp-astrology-complete-system.md",
|
||||
"references/argala-complete-guide.md",
|
||||
"references/badhaka-obstacle-planet-guide.md",
|
||||
"references/condition-dasha-complete.md",
|
||||
]
|
||||
|
||||
REFERENCE_ONLY = [
|
||||
"references/dasa-convergence-methodology.md",
|
||||
"references/multi-dasha-convergence-protocol.md",
|
||||
"references/yoga-strength-scoring-system.md",
|
||||
]
|
||||
|
||||
NON_RUNTIME = [
|
||||
"references/varga-system-quick-reference.md",
|
||||
"references/yoga-list-chinese.md",
|
||||
"references/analysis-full-reading-v4.0.md",
|
||||
"references/analysis-full-reading-v1.8-review.md",
|
||||
"references/audit-skill-full-test-2026-05-04.md",
|
||||
"references/feature-gap-matrix-2026.md",
|
||||
"references/kp-practical-event-timing.md",
|
||||
"references/consultation-case-library.md",
|
||||
]
|
||||
|
||||
|
||||
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": {"sign": "Capricorn", "lord": "Saturn"}},
|
||||
"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 _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 test_core5_sources_drive_prediction_boundary_contract_for_all_strict_routes() -> None:
|
||||
for route in ["career", "relationship", "finance"]:
|
||||
strict = _collect_strict_evidence(route, _base_modules())
|
||||
contract = strict["prediction_boundary_contract"]
|
||||
|
||||
assert contract["source_refs"] == CORE5
|
||||
assert contract["event_judgment_skeleton"]["required_sections"] == [
|
||||
"promise",
|
||||
"activation",
|
||||
"manifestation",
|
||||
"label",
|
||||
]
|
||||
assert contract["promise"]["status"] == strict["adjudication_stages"]["promise"]["status"]
|
||||
assert contract["activation"]["status"] == strict["adjudication_stages"]["activation"]["status"]
|
||||
assert contract["manifestation"]["status"] == strict["adjudication_stages"]["manifestation"]["status"]
|
||||
assert contract["confidence_boundary"]["mevg_status"] == "blocked"
|
||||
assert contract["confidence_boundary"]["real_case_calibration_status"] == "blocked"
|
||||
assert contract["confidence_boundary"]["unverified_claim_policy"] == "downgrade_or_block"
|
||||
|
||||
|
||||
def test_batch2_and_reference_only_layers_are_wired_without_polluting_truth_sources() -> None:
|
||||
source_pack = _existing_interpretation_source_pack()
|
||||
|
||||
assert source_pack["promote_batch2_topic_layer"]["status"] == "available"
|
||||
assert source_pack["promote_batch2_topic_layer"]["source_refs"] == PROMOTE_BATCH2
|
||||
assert source_pack["reference_only_conflict_layer"]["status"] == "available"
|
||||
assert source_pack["reference_only_conflict_layer"]["source_refs"] == REFERENCE_ONLY
|
||||
assert source_pack["reference_only_conflict_layer"]["promotion_status"] == "reference_only"
|
||||
|
||||
runtime_refs = set(source_pack["source_refs"])
|
||||
for path in PROMOTE_BATCH2 + REFERENCE_ONLY:
|
||||
assert path in runtime_refs
|
||||
for path in NON_RUNTIME:
|
||||
assert path not in runtime_refs
|
||||
|
||||
inventory = source_pack["interpretation_source_inventory"]
|
||||
assert inventory["layers"]["promote_batch2_topic_sources"]["source_refs"] == PROMOTE_BATCH2
|
||||
assert inventory["layers"]["reference_only_conflict_sources"]["source_refs"] == REFERENCE_ONLY
|
||||
assert inventory["summary"]["blocked_non_runtime_count"] >= len(NON_RUNTIME)
|
||||
|
||||
|
||||
def test_prompt_pack_and_real_reading_regression_expose_content_contracts() -> 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",
|
||||
)
|
||||
prompt_pack = result["ai_prompt_pack"]
|
||||
snapshot = prompt_pack["evidence_snapshot"]
|
||||
|
||||
assert snapshot["prediction_boundary_contract"]["source_refs"] == CORE5
|
||||
assert snapshot["interpretation_source_pack"]["core_rule_source_refs"] == CORE5
|
||||
assert snapshot["interpretation_source_pack"]["promote_batch2_source_refs"] == PROMOTE_BATCH2
|
||||
assert snapshot["interpretation_source_pack"]["reference_only_source_refs"] == REFERENCE_ONLY
|
||||
assert "必须按 promise → activation → manifestation → label 输出" in prompt_pack["prompt_zh"]
|
||||
assert "未完成 MEVG / Real Case Calibration 时必须降级或标 blocked" in prompt_pack["prompt_zh"]
|
||||
|
||||
docs = prompt_pack["retrieval_plan"]["local_reference_docs"]
|
||||
for path in CORE5 + PROMOTE_BATCH2 + REFERENCE_ONLY:
|
||||
assert path in docs
|
||||
for path in NON_RUNTIME:
|
||||
assert path not in docs
|
||||
|
||||
for route in ["career", "relationship", "finance"]:
|
||||
contract = snapshot["strict_workflow_contracts"][route]
|
||||
assert contract["prediction_boundary_contract"]["source_refs"] == CORE5
|
||||
audit = contract["technique_audit_summary"]
|
||||
assert audit["mevg_global_web_evidence"]["status"] == "blocked"
|
||||
assert audit["real_case_calibration"]["status"] == "blocked"
|
||||
assert audit["interpretation_source_pack"]["core_rule_source_refs"] == CORE5
|
||||
Reference in New Issue
Block a user