@@ -185,6 +185,7 @@ def test_run_strategy_cycle_persists_strategy_run_state(monkeypatch):
185185 assert stages == ["ORDERS_PLANNED" , "DRY_RUN_COMPLETED" ]
186186 assert result ["strategy_run_persisted" ] is True
187187 assert result ["strategy_run_period" ]
188+ assert result ["strategy_run_stage" ] == "DRY_RUN_COMPLETED"
188189 latest_payload = store .writes [- 2 ][1 ]
189190 assert latest_payload ["stage" ] == "DRY_RUN_COMPLETED"
190191 assert latest_payload ["submitted_orders" ][0 ]["symbol" ] == "AAA"
@@ -263,6 +264,7 @@ def test_run_strategy_cycle_persists_live_execution_blocked_without_terminal_sta
263264 assert result ["ok" ] is False
264265 assert result ["execution_blocked" ] is True
265266 assert result ["execution_block_retryable" ] is True
267+ assert result ["strategy_run_stage" ] == "EXECUTION_BLOCKED"
266268 assert latest_payload ["stage" ] == "EXECUTION_BLOCKED"
267269
268270
@@ -315,6 +317,7 @@ def evaluate(self, **inputs):
315317 assert result ["execution_blocked" ] is True
316318 assert result ["execution_block_retryable" ] is False
317319 assert result ["funding_blocked" ] is True
320+ assert result ["strategy_run_stage" ] == "FUNDING_BLOCKED"
318321 assert result ["skipped_orders" ][0 ]["reason" ] == "insufficient_cash_for_whole_share"
319322 assert latest_payload ["stage" ] == "FUNDING_BLOCKED"
320323
@@ -383,6 +386,7 @@ def get_quote(self, _account, symbol):
383386 assert result ["action_done" ] is True
384387 assert result ["ok" ] is False
385388 assert result ["execution_blocked" ] is True
389+ assert result ["strategy_run_stage" ] == "PARTIAL_SUBMITTED"
386390 assert latest_payload ["stage" ] == "PARTIAL_SUBMITTED"
387391
388392
@@ -525,14 +529,16 @@ def test_render_cycle_summary_formats_skipped_orders_in_unified_english_template
525529 assert "targets:" not in message
526530
527531
528- def test_render_cycle_summary_shows_execution_blocked_banner ():
532+ def test_render_cycle_summary_shows_funding_blocked_banner ():
529533 message = render_cycle_summary (
530534 {
531535 "account" : "****1234" ,
532536 "strategy_profile" : "mega_cap_leader_rotation_top50_balanced" ,
533537 "strategy_display_name" : "Mega Cap Leader Rotation Top50 Balanced" ,
534538 "dry_run_only" : False ,
535539 "execution_blocked" : True ,
540+ "execution_block_retryable" : False ,
541+ "funding_blocked" : True ,
536542 "execution_blocking_skips" : [
537543 {"symbol" : "NVDA" , "reason" : "insufficient_cash_for_whole_share" }
538544 ],
@@ -553,4 +559,36 @@ def test_render_cycle_summary_shows_execution_blocked_banner():
553559 lang = "zh" ,
554560 )
555561
556- assert "⚠️ 执行阻塞: 现金不足以买入一整股:NVDA" in message
562+ assert "⚠️ 资金不足,本周期不再自动重试: 现金不足以买入一整股:NVDA" in message
563+
564+
565+ def test_render_cycle_summary_shows_retryable_execution_blocked_banner ():
566+ message = render_cycle_summary (
567+ {
568+ "account" : "****1234" ,
569+ "strategy_profile" : "mega_cap_leader_rotation_top50_balanced" ,
570+ "strategy_display_name" : "Mega Cap Leader Rotation Top50 Balanced" ,
571+ "dry_run_only" : False ,
572+ "execution_blocked" : True ,
573+ "execution_block_retryable" : True ,
574+ "execution_blocking_skips" : [
575+ {"symbol" : "NVDA" , "reason" : "quote_unavailable" }
576+ ],
577+ "portfolio" : {
578+ "total_equity" : 500.0 ,
579+ "liquid_cash" : 500.0 ,
580+ "portfolio_rows" : (("NVDA" ,),),
581+ "market_values" : {"NVDA" : 0.0 },
582+ "quantities" : {"NVDA" : 0 },
583+ },
584+ "allocation" : {"targets" : {"NVDA" : 500.0 }},
585+ "execution" : {},
586+ "submitted_orders" : [],
587+ "skipped_orders" : [
588+ {"symbol" : "NVDA" , "reason" : "quote_unavailable" }
589+ ],
590+ },
591+ lang = "en" ,
592+ )
593+
594+ assert "⚠️ Execution blocked; retryable within window: quote unavailable:NVDA" in message
0 commit comments