Files
ai-exchange/tests/unit/test_analysis_decision_monitor.py
2026-05-11 23:37:47 +08:00

124 lines
5.1 KiB
Python

import contextlib
import io
import json
import os
import unittest
from unittest.mock import patch
os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://user:pass@localhost:5432/ai_ict_test")
from scripts import run_analysis_decision_monitor
class AnalysisDecisionMonitorTests(unittest.TestCase):
def test_evaluate_passes_analysis_decision_only_state_without_real_fills(self) -> None:
payload = run_analysis_decision_monitor.evaluate_analysis_decision_monitor_payloads(
payloads=_healthy_payloads(),
base_url="http://example.test",
instrument_id=1,
timeframe="1m",
)
self.assertTrue(payload["passed"])
self.assertEqual(payload["blockers"], [])
self.assertEqual(payload["observed"]["broker_fills"], 0)
self.assertFalse(payload["observed"]["real_trade_sample_gate_required"])
self.assertEqual(payload["observed"]["real_trade_sample_gate_status"], "deferred_analysis_decision_only")
def test_evaluate_blocks_when_real_fill_gate_returns_to_current_actions(self) -> None:
payloads = _healthy_payloads()
payloads["launch_readiness"] = {
**payloads["launch_readiness"],
"real_trade_sample_gate_required": True,
"real_trade_sample_gate_status": "waiting_for_real_fill_sample",
"warning_reasons": ["real_trade_sample_verified"],
"next_actions": ["wait_for_and_verify_real_fill_sample"],
}
payload = run_analysis_decision_monitor.evaluate_analysis_decision_monitor_payloads(
payloads=payloads,
base_url="http://example.test",
instrument_id=1,
timeframe="1m",
)
self.assertFalse(payload["passed"])
self.assertIn("real_trade_sample_gate_deferred", payload["blockers"])
self.assertIn("real_trade_sample_not_current_action", payload["blockers"])
def test_main_outputs_json_from_monitor_payload(self) -> None:
monitor_payload = {
"passed": True,
"generated_ts": "2026-05-11T00:00:00+00:00",
"blockers": [],
"warnings": [],
}
output = io.StringIO()
with patch("scripts.run_analysis_decision_monitor.run_monitor", return_value=monitor_payload), contextlib.redirect_stdout(output):
exit_code = run_analysis_decision_monitor.main(env={"ANALYSIS_DECISION_MONITOR_OUTPUT_JSON": "1"})
self.assertEqual(exit_code, 0)
self.assertEqual(json.loads(output.getvalue())["passed"], True)
def _healthy_payloads() -> dict:
return {
"health": {"app": "ai-ict", "database_configured": True},
"launch_readiness": {
"analysis_only_ready": True,
"restricted_decision_support_ready": True,
"decision_support_ready": False,
"operator_soft_rollout_ready": True,
"operator_soft_rollout_mode": "restricted_decision_support",
"real_trade_sample_gate_required": False,
"real_trade_sample_gate_status": "deferred_analysis_decision_only",
"blocking_reasons": [],
"warning_reasons": ["real_live_path_ready"],
"next_actions": ["start_restricted_decision_support_soft_rollout", "keep_real_live_disabled_until_adapter_ready"],
"market_state": {
"stream_state": {"code": "market_stream_connected"},
"freshness": {"code": "market_data_fresh"},
"data_gap_state": {"code": "market_data_gap_clear"},
},
},
"broker_state": {"status": "broker_state_ok", "fills": [], "positions": [], "orders": [], "error": None},
"runtime_status": {
"runtime_health": {"level": "ok"},
"current_blockers": [],
"current_warnings": [],
"degraded_mode_state": {"is_degraded": False},
"latest_market_state_by_symbol": {
"BTC-USDT": {
"stream_state": {"code": "market_stream_connected"},
"freshness": {"code": "market_data_fresh"},
"data_gap_state": {"code": "market_data_gap_clear"},
}
},
},
"decision_packet": {
"status": "monitoring",
"action_recommendation": "restricted_decision_support",
"operator_mode": "observe_only",
"trust_classification": "blacklist",
"execution_allowed": None,
"why_allowed": ["restricted_decision_support_allowed", "execution_assist_not_allowed"],
"why_blocked": ["trust_model_decision_support_restricted"],
},
"review_packet": {
"decision_packet": {"status": "monitoring"},
"trust_score": {"restricted_decision_support_list": ["SWEEP_MSS_FVG"]},
"research_council_summary": {"overall_stance": "observe_only"},
},
"p6_governance_tick": {
"status": "no_op_healthy",
"effective_health_state": "healthy",
"requires_cycle_run": False,
"requires_bounded_slice": False,
},
}
if __name__ == "__main__":
unittest.main()