From b34937ea9d402cfdbc7e93e29eb37ba9acb55d60 Mon Sep 17 00:00:00 2001 From: agentson Date: Mon, 2 Mar 2026 09:44:24 +0900 Subject: [PATCH] risk: polish retry coverage and refresh failure summary --- src/core/kill_switch.py | 2 +- src/main.py | 10 ++++++++-- tests/test_main.py | 24 ++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/core/kill_switch.py b/src/core/kill_switch.py index 0f2b892..ef6aaf5 100644 --- a/src/core/kill_switch.py +++ b/src/core/kill_switch.py @@ -73,7 +73,7 @@ class KillSwitchOrchestrator: if result is False: raise RuntimeError("step returned False") return - except Exception as exc: # pragma: no cover - intentionally resilient + except Exception as exc: last_exc = exc if attempt >= attempts: break diff --git a/src/main.py b/src/main.py index 4d6ed14..a4ba69a 100644 --- a/src/main.py +++ b/src/main.py @@ -1375,7 +1375,10 @@ async def _cancel_pending_orders_for_kill_switch( ) if failures: - raise RuntimeError("; ".join(failures[:3])) + summary = "; ".join(failures[:3]) + if len(failures) > 3: + summary = f"{summary} (+{len(failures) - 3} more)" + raise RuntimeError(summary) async def _refresh_order_state_for_kill_switch( @@ -1402,7 +1405,10 @@ async def _refresh_order_state_for_kill_switch( ) failures.append(f"{market.code}/{market.exchange_code}: {exc}") if failures: - raise RuntimeError("; ".join(failures[:3])) + summary = "; ".join(failures[:3]) + if len(failures) > 3: + summary = f"{summary} (+{len(failures) - 3} more)" + raise RuntimeError(summary) def _reduce_risk_for_kill_switch() -> None: diff --git a/tests/test_main.py b/tests/test_main.py index 95bb754..47c2ad3 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -7154,3 +7154,27 @@ async def test_trigger_emergency_kill_switch_records_cancel_failure() -> None: ) assert any(err.startswith("cancel_pending_orders:") for err in report.errors) + + +@pytest.mark.asyncio +async def test_refresh_order_state_failure_summary_includes_more_count() -> None: + broker = MagicMock() + broker.get_balance = AsyncMock(side_effect=RuntimeError("domestic down")) + overseas_broker = MagicMock() + overseas_broker.get_overseas_balance = AsyncMock(side_effect=RuntimeError("overseas down")) + + markets = [] + for code, exchange in [("KR", "KRX"), ("US_PRE", "NASD"), ("US_DAY", "NYSE"), ("JP", "TKSE")]: + market = MagicMock() + market.code = code + market.exchange_code = exchange + market.is_domestic = code == "KR" + markets.append(market) + + with pytest.raises(RuntimeError, match=r"\(\+1 more\)$") as exc_info: + await main_module._refresh_order_state_for_kill_switch( + broker=broker, + overseas_broker=overseas_broker, + markets=markets, + ) + assert "KR/KRX" in str(exc_info.value)