From 1ef101f85150271de29eeae7ea278c2e0bde149d Mon Sep 17 00:00:00 2001 From: gamer147 Date: Mon, 1 Jun 2026 17:37:55 -0400 Subject: [PATCH] feat(battle-node): push Judge after opponent TurnEnd so client transitions Third frame in the burst, per prod TurnEnd -> Judge pairing observed in battle-traffic_tk2_regular.ndjson (positions 10->11, 17->18, etc.). The client's TurnEndOperation sends its own Judge and gates the next turn on a server-pushed Judge via JudgeOperation -> ControlTurnStartPlayer. Closes the v1.1 'Opponent's turn... forever' hang caught during smoke. --- SVSim.BattleNode/Sessions/BattleSession.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/SVSim.BattleNode/Sessions/BattleSession.cs b/SVSim.BattleNode/Sessions/BattleSession.cs index 0e11500..9ec1f21 100644 --- a/SVSim.BattleNode/Sessions/BattleSession.cs +++ b/SVSim.BattleNode/Sessions/BattleSession.cs @@ -257,14 +257,17 @@ public sealed class BattleSession } case NetworkBattleUri.TurnEnd when Phase == BattleSessionPhase.AfterReady: case NetworkBattleUri.TurnEndFinal when Phase == BattleSessionPhase.AfterReady: - // Scripted opponent: opens its turn, immediately ends it, hands control back. - // Two-frame burst — see docs/superpowers/specs/2026-06-01-battle-node-opponent-turn-loop-design.md. + // Scripted opponent: opens its turn, ends it, then pushes Judge so the + // client's JudgeOperation -> ControlTurnStartPlayer fires and the player's + // next turn begins. Three-frame burst — see + // docs/superpowers/plans/2026-06-01-battle-node-opponent-turn-judge.md. // OpponentTurn is set then cleared within the same call to document intent; // the only externally-observable phase after the call is AfterReady, ready for // the next player TurnEnd to fire the cycle again. Phase = BattleSessionPhase.OpponentTurn; result.Add((ScriptedLifecycle.BuildOpponentTurnStart(), NoStock: false)); result.Add((ScriptedLifecycle.BuildOpponentTurnEnd(), NoStock: false)); + result.Add((ScriptedLifecycle.BuildOpponentJudge(), NoStock: false)); Phase = BattleSessionPhase.AfterReady; break; case NetworkBattleUri.Retire: