diff --git a/docs/BUG_HISTORY.md b/docs/BUG_HISTORY.md index 0253c47a..c941cdf4 100644 --- a/docs/BUG_HISTORY.md +++ b/docs/BUG_HISTORY.md @@ -1551,3 +1551,19 @@ - 相关记录:BUG-082、BUG-083 - 复发自:无 - 修复版本:待提交(本地可测) + +## BUG-085 | 无严格领域路由时 full-reading 丢失解释源回退 + +- 状态:resolved +- 首次发现:2026-07-28 +- 最近更新:2026-07-28 +- 影响面:`scripts/run_quality_gate.py` quick profile、`full-reading` AI prompt pack +- 用户现象:CORE_PYTEST_TARGETS 在 `tests/test_cli_smoke.py::test_full_reading_reports_ayanamsa_metadata_and_ai_prompt_pack` 失败,`interpretation_source_pack.core_rule_source_refs` 实际为空数组。 +- 触发条件:full-reading 结果没有可选为 primary 的 career、relationship 或 finance strict workflow contract。 +- 根因:存在两个 Windows 直接执行兼容问题:引擎只把 `scripts/` 而非仓库根加入导入路径,使 strict evidence 服务找不到根目录 `mcp_server.py`;修复该处后,同一测试又暴露 `NamedTemporaryFile` 在仍打开时交给子进程读取会触发 `PermissionError`。此外 prompt pack 只把已加载 fallback 用于 `domain_invocation_layers`,其他解释源字段仍只读取可能为空的 primary strict audit;继续执行 quick 集合还发现能力审计测试仍固定为旧的三条应用路由,未包含现有三个后台页面,以及 Shadbala 常量路径测试硬编码 POSIX 分隔符而在 Windows 失败。 +- 修复:直接执行引擎时显式加入仓库根路径;primary strict audit 缺失时从 `existing_interpretation_source_pack()` 回退解释源字段;oracle queue 改为在临时目录中写入已关闭的普通文件后再交给 validator 子进程;能力审计断言同步为当前六条应用路由;Shadbala 路径断言改为解析后比较末级路径组件。 +- 验证:目标失败测试通过;CORE_PYTEST_TARGETS quick pytest 集合全量通过(仅 1 条既有跳过及弃用警告)。 +- 防复发:无 primary strict route 的 full-reading 也必须保留仓库解释源清单;CLI smoke 继续锁定核心五源的精确顺序。 +- 相关记录:BUG-014、ERR-032 +- 复发自:无 +- 修复版本:待提交(本地可测) diff --git a/scripts/jyotish_engine.py b/scripts/jyotish_engine.py index 72fc2958..ebb85d6f 100644 --- a/scripts/jyotish_engine.py +++ b/scripts/jyotish_engine.py @@ -73,6 +73,8 @@ from ayanamsa_utils import ( # ============================================================================ SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) ROOT_DIR = os.path.dirname(SCRIPT_DIR) +if ROOT_DIR not in sys.path: + sys.path.insert(0, ROOT_DIR) HOME_DIR = os.path.expanduser('~') CLAW_DIR = os.path.join(HOME_DIR, 'WorkBuddy', 'Claw') DB_PATH = os.path.join(CLAW_DIR, 'vedic_astrology_validation.db') @@ -868,7 +870,8 @@ def _oracle_progress_snapshot(): root = Path(__file__).resolve().parents[1] oracle_file = root / 'references' / 'oracle' / 'dasha_shadbala_oracle_cases.json' - with tempfile.NamedTemporaryFile('w+', suffix='.json', delete=True, encoding='utf-8') as handle: + with tempfile.TemporaryDirectory() as temp_dir: + queue_path = Path(temp_dir) / 'oracle-queue.json' queue = subprocess.run( [sys.executable, 'scripts/oracle_collection_queue.py', '--oracle-file', str(oracle_file), '--format', 'json'], cwd=root, @@ -879,10 +882,9 @@ def _oracle_progress_snapshot(): ) if queue.returncode != 0: raise RuntimeError(queue.stderr.strip() or queue.stdout.strip()) - handle.write(queue.stdout) - handle.flush() + queue_path.write_text(queue.stdout, encoding='utf-8') validation = subprocess.run( - [sys.executable, 'scripts/oracle_evidence_validator.py', '--queue-file', handle.name], + [sys.executable, 'scripts/oracle_evidence_validator.py', '--queue-file', str(queue_path)], cwd=root, text=True, capture_output=True, @@ -1749,12 +1751,12 @@ 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 [], + 'status': interpretation_source_audit.get('status') or fallback_source_pack.get('status') or 'blocked', + 'source': interpretation_source_audit.get('source') or fallback_source_pack.get('source') or 'repo_existing_interpretation_sources', + 'core_rule_source_refs': interpretation_source_audit.get('core_rule_source_refs') or fallback_source_pack.get('core_rule_source_layer', {}).get('source_refs') or [], + 'promote_batch2_source_refs': interpretation_source_audit.get('promote_batch2_source_refs') or fallback_source_pack.get('promote_batch2_topic_layer', {}).get('source_refs') or [], + 'reference_only_source_refs': interpretation_source_audit.get('reference_only_source_refs') or fallback_source_pack.get('reference_only_conflict_layer', {}).get('source_refs') or [], + 'missing_refs': interpretation_source_audit.get('missing_refs') or fallback_source_pack.get('missing_refs') or [], }, 'prediction_boundary_contract': primary_prediction_boundary_contract or {}, 'domain_invocation_layers': primary_domain_invocation_layers or fallback_domain_layers or {}, diff --git a/tests/test_api_server_security.py b/tests/test_api_server_security.py index 3f868ef6..6ae2ba11 100644 --- a/tests/test_api_server_security.py +++ b/tests/test_api_server_security.py @@ -1567,7 +1567,14 @@ def test_capability_audit_scans_registry_and_local_sources() -> None: assert audit['local_open_source']['source_count'] >= 3 assert any(source['name'] == 'dashaflow' for source in audit['local_open_source']['sources']) assert all(gap.get('command') != 'varga-full' for gap in audit['priority_gaps']) - assert audit['surfaces']['app_routes'] == ['admin/codes', 'home', 'login'] + assert audit['surfaces']['app_routes'] == [ + 'admin/codes', + 'admin/packages', + 'admin/payments', + 'admin/users', + 'home', + 'login', + ] assert set(audit['surfaces']['app_visible_topics']) == { 'Birth Rectification', 'Case Validation', diff --git a/tests/test_shadbala_complete.py b/tests/test_shadbala_complete.py index cc7e88e0..9569d8d1 100644 --- a/tests/test_shadbala_complete.py +++ b/tests/test_shadbala_complete.py @@ -3,6 +3,7 @@ from __future__ import annotations import json +from pathlib import Path import sys, os, pytest SCRIPTS = os.path.join(os.path.dirname(__file__), '..', 'scripts') @@ -221,8 +222,9 @@ class TestDrikBala: class TestShadbalaFull: def test_shadbala_module_exposes_reference_constants_path(self): - assert SHADBALA_CONSTANTS_PATH.endswith('references/shat_bala_constants.json') - assert os.path.exists(SHADBALA_CONSTANTS_PATH) + constants_path = Path(SHADBALA_CONSTANTS_PATH).resolve() + assert constants_path.parts[-2:] == ('references', 'shat_bala_constants.json') + assert constants_path.exists() def test_static_shadbala_constants_are_loaded_from_reference_json(self): constants = _shadbala_constants()