feat(battle-node): reveal generated tokens on play via remembered identity

PlayActionsHandler mines add ops into BattleSessionState.RecordToken each
frame; a token played in a later frame now synthesizes a knownList from the
remembered cardId instead of degrading. Bullet-3 audit F1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-03 23:36:44 -04:00
parent b6af8bfb7d
commit d8b5ef950d
3 changed files with 71 additions and 7 deletions

View File

@@ -250,7 +250,7 @@ public class BattleSessionDispatchTests
}
[Test]
public void Pvp_PlayActions_token_idx_degrades_to_no_knownList()
public void Pvp_PlayActions_ungenerated_token_idx_degrades_to_no_knownList()
{
var (s, a, b) = NewPvpSession();
DriveToAfterReady(s, a);
@@ -268,6 +268,49 @@ public class BattleSessionDispatchTests
Assert.That(pb.KnownList, Is.Null);
}
[Test]
public void Pvp_PlayActions_reveals_token_generated_in_an_earlier_frame()
{
var (s, a, b) = NewPvpSession();
DriveToAfterReady(s, a);
DriveToAfterReady(s, b);
// Frame 1: A plays deck card idx 3 (a spell, hand 10 -> cemetery 30) whose fanfare ADDS
// token idx 31 (cardId 900111010) to A's hand (limbo 50 -> hand 10).
var gen = new Dictionary<string, object?>
{
["playIdx"] = 3L,
["type"] = 30L,
["orderList"] = new List<object?>
{
new Dictionary<string, object?> { ["move"] = new Dictionary<string, object?>
{ ["idx"] = new List<object?> { 3L }, ["isSelf"] = 1L, ["from"] = 10L, ["to"] = 30L } },
new Dictionary<string, object?> { ["add"] = new Dictionary<string, object?>
{ ["idx"] = new List<object?> { 31L }, ["isSelf"] = 1L,
["card"] = new Dictionary<string, object?> { ["cardId"] = 900111010L } } },
new Dictionary<string, object?> { ["move"] = new Dictionary<string, object?>
{ ["idx"] = new List<object?> { 31L }, ["isSelf"] = 1L, ["from"] = 50L, ["to"] = 10L } },
},
};
var genRoutes = s.ComputeFrames(a, EnvWith(NetworkBattleUri.PlayActions, gen));
// The deck card itself reveals from the deck map; the token stays hidden (in hand).
var genBody = (PlayActionsBroadcastBody)genRoutes[0].Frame.Body;
Assert.That(genBody.KnownList!.Single().CardId, Is.EqualTo(100_011_010L), "deck card revealed");
// Frame 2 (later turn): A plays token idx 31 from hand (10) to field (20).
var play = MoveOrderList(idx: 31, from: 10, to: 20);
play["playIdx"] = 31L;
play["type"] = 30L;
var routes = s.ComputeFrames(a, EnvWith(NetworkBattleUri.PlayActions, play));
var pb = (PlayActionsBroadcastBody)routes[0].Frame.Body;
Assert.That(pb.PlayIdx, Is.EqualTo(31));
Assert.That(pb.KnownList, Is.Not.Null, "the token's identity was remembered from its add op");
Assert.That(pb.KnownList!.Single().Idx, Is.EqualTo(31));
Assert.That(pb.KnownList[0].CardId, Is.EqualTo(900_111_010L), "mined token cardId");
Assert.That(pb.KnownList[0].To, Is.EqualTo(20));
}
[Test]
public void Pvp_PlayActions_when_B_still_AwaitingSwap_drops()
{