refactor(battle-node): ScriptedLifecycle.InitialHand as ImmutableArray<long>

Audit Md4 cleanup: the prior long[] allowed in-place modification by any
caller with the field reference. ImmutableArray<long> enforces the constant
contract at the type level. ComputeHandAfterSwap uses ToArray() to produce
its mutable working copy.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-01 13:02:23 -04:00
parent 6077844ee8
commit 1904ae4c0c

View File

@@ -1,3 +1,4 @@
using System.Collections.Immutable;
using SVSim.BattleNode.Bridge;
using SVSim.BattleNode.Protocol;
using SVSim.BattleNode.Protocol.Bodies;
@@ -59,9 +60,12 @@ public static class ScriptedLifecycle
/// <summary>
/// Initial 3-card hand idxs from <see cref="BuildDeal"/>. Each position in this array
/// is one card; the value is the card's deck idx.
/// is one card; the value is the card's deck idx. <see cref="ImmutableArray{T}"/> enforces
/// the "read-only constant" contract at the type level — callers cannot mutate it, even
/// accidentally (the prior <c>long[]</c> allowed in-place modification by anyone with the
/// field reference).
/// </summary>
private static readonly long[] InitialHand = { 1, 2, 3 };
private static readonly ImmutableArray<long> InitialHand = ImmutableArray.Create<long>(1, 2, 3);
/// <summary>
/// Compute the player's hand after a mulligan. For every idx in <paramref name="swapIndices"/>
@@ -70,7 +74,7 @@ public static class ScriptedLifecycle
/// </summary>
public static long[] ComputeHandAfterSwap(IReadOnlyList<long> swapIndices)
{
var hand = (long[])InitialHand.Clone();
var hand = InitialHand.ToArray();
var nextDeckIdx = 4L;
for (var pos = 0; pos < hand.Length; pos++)
{