From 1904ae4c0c6610e75db9749510b03be1f1569728 Mon Sep 17 00:00:00 2001 From: gamer147 Date: Mon, 1 Jun 2026 13:02:23 -0400 Subject: [PATCH] refactor(battle-node): ScriptedLifecycle.InitialHand as ImmutableArray Audit Md4 cleanup: the prior long[] allowed in-place modification by any caller with the field reference. ImmutableArray enforces the constant contract at the type level. ComputeHandAfterSwap uses ToArray() to produce its mutable working copy. Co-Authored-By: Claude Opus 4.7 --- SVSim.BattleNode/Lifecycle/ScriptedLifecycle.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/SVSim.BattleNode/Lifecycle/ScriptedLifecycle.cs b/SVSim.BattleNode/Lifecycle/ScriptedLifecycle.cs index ccd84da..801d90b 100644 --- a/SVSim.BattleNode/Lifecycle/ScriptedLifecycle.cs +++ b/SVSim.BattleNode/Lifecycle/ScriptedLifecycle.cs @@ -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 /// /// Initial 3-card hand idxs from . 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. enforces + /// the "read-only constant" contract at the type level — callers cannot mutate it, even + /// accidentally (the prior long[] allowed in-place modification by anyone with the + /// field reference). /// - private static readonly long[] InitialHand = { 1, 2, 3 }; + private static readonly ImmutableArray InitialHand = ImmutableArray.Create(1, 2, 3); /// /// Compute the player's hand after a mulligan. For every idx in @@ -70,7 +74,7 @@ public static class ScriptedLifecycle /// public static long[] ComputeHandAfterSwap(IReadOnlyList swapIndices) { - var hand = (long[])InitialHand.Clone(); + var hand = InitialHand.ToArray(); var nextDeckIdx = 4L; for (var pos = 0; pos < hand.Length; pos++) {