fix: harden accuracy and api guardrails

This commit is contained in:
732642856
2026-06-26 00:44:09 +08:00
parent ab643c3e4d
commit d11cebacf8
11 changed files with 825 additions and 568 deletions
+49
View File
@@ -4,8 +4,10 @@
from __future__ import annotations
import base64
import json
import os
import sys
from io import BytesIO
import pytest
@@ -27,6 +29,40 @@ def _handler() -> JyotishAPIHandler:
return JyotishAPIHandler.__new__(JyotishAPIHandler)
class _FakeHeaders(dict):
def get(self, key, default=None):
return super().get(key, default)
class _FakeServer:
allowed_origins = DEFAULT_ALLOWED_ORIGINS
class _ResponseCaptureHandler(JyotishAPIHandler):
def __init__(self) -> None:
self.headers = _FakeHeaders()
self.server = _FakeServer()
self.path = '/api/capability_audit'
self.wfile = BytesIO()
self.status_code = None
self.response_headers = []
def send_response(self, code, message=None): # noqa: ANN001
self.status_code = code
def send_header(self, key, value): # noqa: ANN001
self.response_headers.append((key, value))
def end_headers(self):
return None
def _capability_audit(self):
raise RuntimeError('simulated internal failure')
def payload(self) -> dict:
return json.loads(self.wfile.getvalue().decode('utf-8'))
def test_default_cors_origins_are_local_only() -> None:
assert 'http://localhost:3456' in DEFAULT_ALLOWED_ORIGINS
assert '*' not in DEFAULT_ALLOWED_ORIGINS
@@ -40,6 +76,19 @@ def test_env_cors_parser_ignores_empty_entries() -> None:
}
def test_get_internal_errors_are_json_wrapped() -> None:
handler = _ResponseCaptureHandler()
handler.do_GET()
assert handler.status_code == 500
assert ('Content-Type', 'application/json; charset=utf-8') in handler.response_headers
payload = handler.payload()
assert payload['success'] is False
assert payload['error'] == 'Internal server error'
assert payload['error_code'] == 'ERR_INTERNAL'
@pytest.mark.parametrize(
('key', 'value', 'minimum', 'maximum'),
[
+19 -1
View File
@@ -891,11 +891,14 @@ def test_quality_gate_declares_fast_browser_release_profiles() -> None:
readme = (ROOT / "README.md").read_text(encoding="utf-8")
for token in [
"--profile",
"choices=[\"quick\", \"browser\", \"release\"]",
"choices=[\"quick\", \"browser\", \"release\", \"accuracy\"]",
"QUALITY_GATE_PROFILES",
"quick",
"browser",
"release",
"accuracy",
"skip_local_accuracy_report",
"scripts/local_accuracy_report.py",
"skip_slow",
"skip_yoga_logic",
"skip_frontend_click",
@@ -913,9 +916,11 @@ def test_quality_gate_declares_fast_browser_release_profiles() -> None:
"quick:快速开发守门",
"browser:完整浏览器守门",
"release:发布前守门",
"accuracy:本地准确率守门",
"python3 scripts/run_quality_gate.py --profile quick",
"python3 scripts/run_quality_gate.py --profile browser",
"python3 scripts/run_quality_gate.py --profile release",
"python3 scripts/run_quality_gate.py --profile accuracy",
]:
assert token in readme
@@ -938,6 +943,19 @@ def test_release_quality_gate_tracks_untracked_product_files() -> None:
assert path in quality_gate.RELEASE_CRITICAL_UNTRACKED_PATHS
def test_accuracy_quality_gate_runs_local_accuracy_report_without_frontend_click() -> None:
quality_gate = load_quality_gate_module()
profile = quality_gate.QUALITY_GATE_PROFILES["accuracy"]
assert profile["skip_frontend_click"] is True
assert profile["skip_frontend_runtime"] is True
assert profile["skip_real_cases"] is False
assert profile["skip_dasha_audit"] is False
assert profile["skip_oracle_audit"] is False
assert profile["skip_yoga_logic"] is False
assert profile["skip_local_accuracy_report"] is False
def test_github_release_quality_gate_runs_browser_release_profile() -> None:
workflow = (ROOT / ".github" / "workflows" / "release-quality-gate.yml").read_text(encoding="utf-8")
for token in [
+107 -5
View File
@@ -15,13 +15,15 @@ SHADBALA_COMPONENTS = ["sthana", "dig", "kala", "chesta", "naisargika", "drik"]
def complete_shadbala_components() -> dict[str, dict[str, float]]:
return {
planet: {
component: float(40 + planet_index * 3 + component_index)
result = {}
for planet_index, planet in enumerate(SHADBALA_PLANETS):
row = {
component: round(0.1 + planet_index * 0.01 + component_index * 0.02, 4)
for component_index, component in enumerate(SHADBALA_COMPONENTS)
}
for planet_index, planet in enumerate(SHADBALA_PLANETS)
}
row["total_rupa"] = round(sum(row[component] for component in SHADBALA_COMPONENTS), 4)
result[planet] = row
return result
def build_queue() -> dict:
@@ -209,6 +211,106 @@ def test_validator_rejects_non_numeric_or_negative_shadbala_components(tmp_path:
assert "invalid_shadbala_component_negative:Moon.dig" in first["problems"]
def test_validator_rejects_missing_shadbala_total_rupa(tmp_path: Path) -> None:
queue = build_queue()
packet = queue["tasks"][0]["evidence_packet"]
shadbala = complete_shadbala_components()
del shadbala["Sun"]["total_rupa"]
packet["metadata"] = {
"tool_name": "JHora",
"tool_version_or_url": "manual-screenshot-v1",
"capture_date": "2026-06-25",
"source_artifact": "references/oracle/artifacts/manual_jhora_user_REDACTED_YEAR.png",
"ayanamsa": "lahiri",
"node_mode": "mean",
"timezone": "UTC+08:00",
"operator_note": "Manual external screenshot; values typed from JHora screen.",
}
packet["target_placeholders"] = {
"target.moon_sidereal_longitude_deg": 311.7897,
"target.vimshottari_start_date": "1986-05-18",
"target.shadbala_components": shadbala,
}
packet["status"] = "external_verified"
queue_path = tmp_path / "queue.json"
queue_path.write_text(json.dumps(queue, ensure_ascii=False), encoding="utf-8")
completed = run_validator(queue_path)
assert completed.returncode == 0, completed.stderr or completed.stdout
report = json.loads(completed.stdout)
first = report["packets"][0]
assert first["valid"] is False
assert "missing_shadbala_total_rupa:Sun" in first["problems"]
def test_validator_rejects_shadbala_component_values_above_20_rupas(tmp_path: Path) -> None:
queue = build_queue()
packet = queue["tasks"][0]["evidence_packet"]
shadbala = complete_shadbala_components()
shadbala["Sun"]["sthana"] = 20.01
shadbala["Sun"]["total_rupa"] = round(sum(shadbala["Sun"][component] for component in SHADBALA_COMPONENTS), 4)
packet["metadata"] = {
"tool_name": "JHora",
"tool_version_or_url": "manual-screenshot-v1",
"capture_date": "2026-06-25",
"source_artifact": "references/oracle/artifacts/manual_jhora_user_REDACTED_YEAR.png",
"ayanamsa": "lahiri",
"node_mode": "mean",
"timezone": "UTC+08:00",
"operator_note": "Manual external screenshot; values typed from JHora screen.",
}
packet["target_placeholders"] = {
"target.moon_sidereal_longitude_deg": 311.7897,
"target.vimshottari_start_date": "1986-05-18",
"target.shadbala_components": shadbala,
}
packet["status"] = "external_verified"
queue_path = tmp_path / "queue.json"
queue_path.write_text(json.dumps(queue, ensure_ascii=False), encoding="utf-8")
completed = run_validator(queue_path)
assert completed.returncode == 0, completed.stderr or completed.stdout
report = json.loads(completed.stdout)
first = report["packets"][0]
assert first["valid"] is False
assert "invalid_shadbala_component_range:Sun.sthana" in first["problems"]
def test_validator_rejects_shadbala_total_rupa_sum_mismatch(tmp_path: Path) -> None:
queue = build_queue()
packet = queue["tasks"][0]["evidence_packet"]
shadbala = complete_shadbala_components()
shadbala["Sun"]["total_rupa"] = round(shadbala["Sun"]["total_rupa"] + 0.06, 4)
packet["metadata"] = {
"tool_name": "JHora",
"tool_version_or_url": "manual-screenshot-v1",
"capture_date": "2026-06-25",
"source_artifact": "references/oracle/artifacts/manual_jhora_user_REDACTED_YEAR.png",
"ayanamsa": "lahiri",
"node_mode": "mean",
"timezone": "UTC+08:00",
"operator_note": "Manual external screenshot; values typed from JHora screen.",
}
packet["target_placeholders"] = {
"target.moon_sidereal_longitude_deg": 311.7897,
"target.vimshottari_start_date": "1986-05-18",
"target.shadbala_components": shadbala,
}
packet["status"] = "external_verified"
queue_path = tmp_path / "queue.json"
queue_path.write_text(json.dumps(queue, ensure_ascii=False), encoding="utf-8")
completed = run_validator(queue_path)
assert completed.returncode == 0, completed.stderr or completed.stdout
report = json.loads(completed.stdout)
first = report["packets"][0]
assert first["valid"] is False
assert "shadbala_total_rupa_sum_mismatch:Sun" in first["problems"]
def test_validator_rejects_invalid_ashtakoot_score_ranges(tmp_path: Path) -> None:
queue = build_queue_from_file(ROOT / "references/oracle/ashtakoot_oracle_cases.json")
packet = queue["tasks"][0]["evidence_packet"]