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.
This commit is contained in:
gamer147
2026-06-01 17:37:55 -04:00
parent 007513e55c
commit 1ef101f851

View File

@@ -257,14 +257,17 @@ public sealed class BattleSession
} }
case NetworkBattleUri.TurnEnd when Phase == BattleSessionPhase.AfterReady: case NetworkBattleUri.TurnEnd when Phase == BattleSessionPhase.AfterReady:
case NetworkBattleUri.TurnEndFinal when Phase == BattleSessionPhase.AfterReady: case NetworkBattleUri.TurnEndFinal when Phase == BattleSessionPhase.AfterReady:
// Scripted opponent: opens its turn, immediately ends it, hands control back. // Scripted opponent: opens its turn, ends it, then pushes Judge so the
// Two-frame burst — see docs/superpowers/specs/2026-06-01-battle-node-opponent-turn-loop-design.md. // 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; // 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 only externally-observable phase after the call is AfterReady, ready for
// the next player TurnEnd to fire the cycle again. // the next player TurnEnd to fire the cycle again.
Phase = BattleSessionPhase.OpponentTurn; Phase = BattleSessionPhase.OpponentTurn;
result.Add((ScriptedLifecycle.BuildOpponentTurnStart(), NoStock: false)); result.Add((ScriptedLifecycle.BuildOpponentTurnStart(), NoStock: false));
result.Add((ScriptedLifecycle.BuildOpponentTurnEnd(), NoStock: false)); result.Add((ScriptedLifecycle.BuildOpponentTurnEnd(), NoStock: false));
result.Add((ScriptedLifecycle.BuildOpponentJudge(), NoStock: false));
Phase = BattleSessionPhase.AfterReady; Phase = BattleSessionPhase.AfterReady;
break; break;
case NetworkBattleUri.Retire: case NetworkBattleUri.Retire: