#!/usr/bin/env python3 """Offline compute mixins: the handler-free path used by MCP and report scripts. TASK-api-server-backdoor-close-20260916. These assertions pin the two production call sites that no longer forge a ``JyotishAPIHandler`` without its constructor, and pin that the HTTP handler keeps the moved methods through inheritance. """ from __future__ import annotations import ast import os import sys SCRIPTS = os.path.join(os.path.dirname(__file__), '..', 'scripts') if SCRIPTS not in sys.path: sys.path.insert(0, SCRIPTS) from ashtakoot import calculate_ashtakoot # noqa: E402 from jyotish_api_server import JyotishAPIHandler # noqa: E402 from offline_compute_mixins import ( # noqa: E402 RequestParamMixin, SynastryMixin, VedastroEvidenceMixin, ) _CHART = { 'success': True, 'ascendant': {'sign': 'Aries', 'sign_idx': 0, 'degree': 12.0, 'lon': 12.0}, 'planets': { 'Sun': {'sign': 'Leo', 'lon': 130.0}, 'Moon': {'sign': 'Cancer', 'lon': 100.0}, }, } def test_synastry_mixin_needs_no_http_handler() -> None: """local_accuracy_report.py's path: score a pair without a handler.""" api = SynastryMixin()._compute_synastry({'male_moon': 0, 'female_moon': 60}) direct = calculate_ashtakoot(0, 60) assert api['total_score'] == direct['total_score'] assert api['male_details'] == direct['male_details'] assert api['female_details'] == direct['female_details'] def test_runtime_evidence_helpers_run_without_forging_a_handler() -> None: """mcp_server.py:4751 -> consultation_workflow_service.build_runtime_evidence_helpers.""" from consultation_workflow_service import build_runtime_evidence_helpers helpers = build_runtime_evidence_helpers(_CHART) assert set(helpers) == { 'vedastro_official', 'vedastro_archive_manifest', 'interpretation_coverage', } assert isinstance(helpers['vedastro_official'], dict) assert isinstance(helpers['vedastro_archive_manifest'], dict) assert isinstance(helpers['interpretation_coverage'], dict) def test_consultation_workflow_service_no_longer_forges_for_evidence() -> None: source = os.path.join(SCRIPTS, 'consultation_workflow_service.py') tree = ast.parse(open(source, encoding='utf-8').read()) fn = next( n for n in tree.body if isinstance(n, ast.FunctionDef) and n.name == 'build_runtime_evidence_helpers' ) body = ast.dump(fn) assert 'JyotishAPIHandler' not in body assert 'VedastroEvidenceMixin' in body def test_http_handler_still_inherits_the_moved_methods() -> None: """HTTP-visible behaviour must be unchanged: same methods, now via MRO.""" for name in ( '_get_float', '_check_range', '_normalize_degree', '_compute_synastry', '_high_rigor_vedastro_official_summary', '_compute_vedastro_gateway_archives', '_interpretation_source_runtime_coverage', ): assert hasattr(JyotishAPIHandler, name), name assert issubclass(JyotishAPIHandler, VedastroEvidenceMixin) assert issubclass(JyotishAPIHandler, SynastryMixin) assert issubclass(SynastryMixin, RequestParamMixin)