diff --git a/SVSim.BattleNode/Protocol/Bodies/PlayActionsBroadcastBody.cs b/SVSim.BattleNode/Protocol/Bodies/PlayActionsBroadcastBody.cs
index 22fac11..fcf477f 100644
--- a/SVSim.BattleNode/Protocol/Bodies/PlayActionsBroadcastBody.cs
+++ b/SVSim.BattleNode/Protocol/Bodies/PlayActionsBroadcastBody.cs
@@ -47,3 +47,23 @@ public sealed record KnownCardEntry(
public sealed record OppoTargetEntry(
[property: JsonPropertyName("targetIdx")] int TargetIdx,
[property: JsonPropertyName("isSelf")] int IsSelf);
+
+/// One entry in a relayed uList (the unapproved-movement list) — a skill-driven
+/// card movement (fetch / search / summon-from-deck / discard-reveal) the node forwards VERBATIM
+/// (bullet-3 audit F1; the node makes no reveal decision — cardId presence is the sender's
+/// call). The first five fields are always emitted; the rest are conditional in
+/// SendCardDataMaker.MakeUList (cardId when revealed, clan/cost when set, etc.) and omit when
+/// null. isSelf is actor-relative and passes through unchanged (F2).
+public sealed record UnapprovedCardEntry(
+ [property: JsonPropertyName("idxList")] IReadOnlyList IdxList,
+ [property: JsonPropertyName("from")] int From,
+ [property: JsonPropertyName("to")] int To,
+ [property: JsonPropertyName("isSelf")] int IsSelf,
+ [property: JsonPropertyName("skill")] string Skill,
+ [property: JsonPropertyName("cardId")] long? CardId = null,
+ [property: JsonPropertyName("clan")] int? Clan = null,
+ [property: JsonPropertyName("cost")] int? Cost = null,
+ [property: JsonPropertyName("skillKeyCardIdx")] IReadOnlyList? SkillKeyCardIdx = null,
+ [property: JsonPropertyName("randomTargetIdx")] IReadOnlyList? RandomTargetIdx = null,
+ [property: JsonPropertyName("isInvoke")] int? IsInvoke = null,
+ [property: JsonPropertyName("attachTarget")] string? AttachTarget = null);
diff --git a/SVSim.BattleNode/Sessions/Dispatch/KnownListBuilder.cs b/SVSim.BattleNode/Sessions/Dispatch/KnownListBuilder.cs
index 6d2cfe0..9ec92c0 100644
--- a/SVSim.BattleNode/Sessions/Dispatch/KnownListBuilder.cs
+++ b/SVSim.BattleNode/Sessions/Dispatch/KnownListBuilder.cs
@@ -222,6 +222,49 @@ internal static class KnownListBuilder
return result.Count == 0 ? null : result;
}
+ /// Map the sender's uList (unapproved-movement list) to the opponent-facing
+ /// list, VERBATIM — the node makes no reveal decision; it forwards
+ /// whatever the sender emitted (cardId present = the sender chose to reveal). The five always-present
+ /// fields (idxList/from/to/isSelf/skill) map directly; the conditionals map only when their key is
+ /// present (mirroring the emitter, SendCardDataMaker.MakeUList:188-244). Null for an
+ /// absent/empty list (mirrors ). isSelf/place-states pass through unchanged
+ /// (F2; same verbatim assumption already shipped for the synthesized knownList).
+ public static IReadOnlyList? RelayUList(object? uList)
+ {
+ if (uList is not IEnumerable