From beaabe4e6a582b9312028d393a634ffdba9f8beb Mon Sep 17 00:00:00 2001 From: 732642856 <732642856@qq.com> Date: Wed, 8 Jul 2026 21:15:04 +0800 Subject: [PATCH] feat: carry VedAstro raw archive manifest in evidence packets --- docs/research/pre_work_error_ledger.md | 1 + mcp_server.py | 2 ++ scripts/jyotish_api_server.py | 2 ++ scripts/unified_consultation_orchestrator.py | 7 +++++++ tests/test_api_server_security.py | 6 ++++++ tests/test_mcp_strict_workflow_career.py | 1 + tests/test_unified_consultation_orchestrator.py | 17 +++++++++++++++++ 7 files changed, 36 insertions(+) diff --git a/docs/research/pre_work_error_ledger.md b/docs/research/pre_work_error_ledger.md index 142366aa..b7b1731a 100644 --- a/docs/research/pre_work_error_ledger.md +++ b/docs/research/pre_work_error_ledger.md @@ -51,6 +51,7 @@ For large architecture or release work, also read: | ERR-018 | External engine blockers can be described verbally but not carried into diagnostics. | mitigated 2026-07-05 | `diagnose_external_engine_adapters.py` must expose VedAstro closure plan and PyJHora/JHora install/license/ephemeris boundary; keep `docs/research/external_engine_blocker_research_2026_07_05.md` current. | | ERR-019 | WorkBuddy/cloud/local acceptance summaries can invent pass counts, stale asset counts, non-existent error docs, or wrong dasha windows. | mitigated 2026-07-06 | Read `docs/research/user_invocation_acceptance_error_log_2026_07_06.md`; run `scripts/user_invocation_acceptance_check.py` and `tests/test_user_invocation_acceptance_contract.py` before accepting ordinary-user skill invocation validation claims. | | ERR-020 | VedAstro official raw responses can be archived but hard to audit if no manifest/API listing exposes them. | mitigated 2026-07-08 | Keep `list_official_raw_response_archives()` and `GET /api/vedastro_gateway/archives`; tests must prove archived official raw responses are enumerable. | +| ERR-021 | VedAstro raw archive manifests can exist outside the high-rigor evidence packet, leaving final reports unable to prove whether official raw evidence was archived. | mitigated 2026-07-08 | Keep `vedastro_official_raw_archive_manifest` in `machine_evidence_packet.sections` for API and MCP strict workflows. | ## Fragment Sweep Command Set diff --git a/mcp_server.py b/mcp_server.py index 69b5d077..87fa074d 100644 --- a/mcp_server.py +++ b/mcp_server.py @@ -4254,11 +4254,13 @@ def strict_workflow( handler = JyotishAPIHandler.__new__(JyotishAPIHandler) vedastro_official = handler._high_rigor_vedastro_official_summary(chart) + vedastro_archive_manifest = handler._compute_vedastro_gateway_archives() interpretation_coverage = handler._interpretation_source_runtime_coverage(chart) machine_evidence_packet = _UNIFIED_CONSULTATION_ORCHESTRATOR.machine_evidence_packet( chart=chart, route_packet=result.get("routing") if isinstance(result.get("routing"), dict) else route_packet, vedastro_official=vedastro_official, + vedastro_archive_manifest=vedastro_archive_manifest, ) real_case_calibration = _UNIFIED_CONSULTATION_ORCHESTRATOR.real_case_calibration_catalog( route_packet=result.get("routing") if isinstance(result.get("routing"), dict) else route_packet, diff --git a/scripts/jyotish_api_server.py b/scripts/jyotish_api_server.py index 12d017ae..0504a084 100644 --- a/scripts/jyotish_api_server.py +++ b/scripts/jyotish_api_server.py @@ -183,6 +183,7 @@ def execute_consultation_workflow( executed_steps.append('run_thematic_report') vedastro_official = handler._high_rigor_vedastro_official_summary(chart) + vedastro_archive_manifest = handler._compute_vedastro_gateway_archives() runtime_truth = vedastro_official.get('runtime_truth') if isinstance(vedastro_official.get('runtime_truth'), dict) else {} interpretation_source_runtime_coverage = handler._interpretation_source_runtime_coverage(chart) skipped_steps = [step for step in known_steps if step not in executed_steps] @@ -190,6 +191,7 @@ def execute_consultation_workflow( chart=chart, route_packet=route_packet, vedastro_official=vedastro_official, + vedastro_archive_manifest=vedastro_archive_manifest, ) real_case_calibration = _UNIFIED_CONSULTATION_ORCHESTRATOR.real_case_calibration_catalog( route_packet=route_packet, diff --git a/scripts/unified_consultation_orchestrator.py b/scripts/unified_consultation_orchestrator.py index d743bdd6..d99c1efa 100644 --- a/scripts/unified_consultation_orchestrator.py +++ b/scripts/unified_consultation_orchestrator.py @@ -66,6 +66,7 @@ class UnifiedConsultationOrchestrator: "KP_cusp", "external_oracle_status", "vedastro_official_raw_response", + "vedastro_official_raw_archive_manifest", ] _THEME_ALIASES = { "relationship": "marriage", @@ -368,6 +369,7 @@ class UnifiedConsultationOrchestrator: 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 {} @@ -383,6 +385,7 @@ class UnifiedConsultationOrchestrator: 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") @@ -417,6 +420,10 @@ class UnifiedConsultationOrchestrator: "source_path": "vedastro_official.runtime_truth", }, "vedastro_official_raw_response": self._section(raw_response, "vedastro_official.raw_response"), + "vedastro_official_raw_archive_manifest": self._section( + archive_manifest if archive_manifest.get("archive_count") else None, + "vedastro_gateway.archives", + ), } missing = [name for name, section in sections.items() if section.get("status") == "missing"] return { diff --git a/tests/test_api_server_security.py b/tests/test_api_server_security.py index 908100da..b945cabf 100644 --- a/tests/test_api_server_security.py +++ b/tests/test_api_server_security.py @@ -2161,6 +2161,11 @@ def test_high_rigor_workflow_reuses_existing_rectification_backtest_and_vedastro return _load_local_module(name) monkeypatch.setattr(jyotish_api_server, '_load_local_module', fake_loader) + monkeypatch.setattr(handler, '_compute_vedastro_gateway_archives', lambda: { + 'scope': 'vedastro_official_raw_response_archive_manifest', + 'archive_count': 1, + 'archives': [{'job_id': 'job_1955', 'official_raw_response_available': True}], + }) result = handler._compute_high_rigor_workflow({ 'question': '请高严谨分析我的事业、婚恋和财富', @@ -2199,6 +2204,7 @@ def test_high_rigor_workflow_reuses_existing_rectification_backtest_and_vedastro assert result['unified_orchestrator']['name'] == 'UnifiedConsultationOrchestrator' assert result['unified_orchestrator']['surface'] == 'api_web' assert result['unified_orchestrator']['route']['question_type'] == 'career' + assert result['machine_evidence_packet']['sections']['vedastro_official_raw_archive_manifest']['status'] == 'used' def test_consultation_workflow_uses_unified_orchestrator_contract(monkeypatch) -> None: diff --git a/tests/test_mcp_strict_workflow_career.py b/tests/test_mcp_strict_workflow_career.py index 01bd1f68..c1d300e0 100644 --- a/tests/test_mcp_strict_workflow_career.py +++ b/tests/test_mcp_strict_workflow_career.py @@ -177,6 +177,7 @@ def test_mcp_strict_workflow_returns_runtime_evidence_log(monkeypatch) -> None: assert result["runtime_evidence_log"]["route"]["question_type"] == "career" assert result["runtime_evidence_log"]["vedastro_cloud_state"] == "official_verified" assert result["machine_evidence_packet"]["status"] == "partial" + assert "vedastro_official_raw_archive_manifest" in result["machine_evidence_packet"]["sections"] assert result["real_case_calibration"]["status"] == "partial_scored" assert result["runtime_evidence_log"]["evidence_packet_contract"]["status"] == "partial" assert result["runtime_evidence_log"]["real_case_calibration"]["status"] == "partial_scored" diff --git a/tests/test_unified_consultation_orchestrator.py b/tests/test_unified_consultation_orchestrator.py index 46f2defe..7cebd189 100644 --- a/tests/test_unified_consultation_orchestrator.py +++ b/tests/test_unified_consultation_orchestrator.py @@ -311,3 +311,20 @@ def test_real_case_calibration_catalog_exposes_local_sources_without_claiming_ma assert catalog["scored_candidates"][0]["event_trigger_match"]["checks"]["recorded_trigger_keywords"] assert catalog["scored_candidates"][0]["outcome_validation"]["status"] == "local_outcome_recorded_trigger_not_replayed" assert "D9" in catalog["scored_candidates"][0]["similarities"]["evidence_section_overlap"] + + +def test_machine_evidence_packet_carries_vedastro_raw_archive_manifest() -> None: + orchestrator = UnifiedConsultationOrchestrator() + packet = orchestrator.machine_evidence_packet( + chart={"chart": {"ascendant": {"sign": "Leo"}, "planets": {"Sun": {"sign": "Aquarius"}}}}, + route_packet={"question_type": "career", "primary_theme": "career"}, + vedastro_archive_manifest={ + "scope": "vedastro_official_raw_response_archive_manifest", + "archive_count": 1, + "archives": [{"job_id": "job_1955", "official_raw_response_available": True}], + }, + ) + + section = packet["sections"]["vedastro_official_raw_archive_manifest"] + assert section["status"] == "used" + assert section["source_path"] == "vedastro_gateway.archives"