feat(battlenode): emit engine-resolved clan/tribe on knownList entries (M-HC-4e)
Prod always emits clan (int ClanType) + tribe (comma-joined int TribeType string, "0" for none) on every knownList entry (battle-traffic_tk2_regular .ndjson). Source both off the resolved engine (SessionBattleEngine.PlayedCardClan/ PlayedCardTribe -> BattleCardBase.Clan/Tribe), so skill-applied clan/tribe changes ride the wire rather than the static card-master value. Thread through KnownListBuilder.BuildPlayedCard + PlayActionsHandler; add clan/tribe to the KnownCardEntry DTO (always present, non-null). Node-side only; no engine edits, drift clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -294,7 +294,10 @@ public class CaptureConformanceTests
|
||||
var ourEntry = ourDoc.RootElement.GetProperty("knownList")[0];
|
||||
using var prodDoc = JsonDocument.Parse(prodEntry);
|
||||
|
||||
// We are responsible for idx/cardId/to (+ spellboost/attachTarget). cost/clan/tribe are deferred.
|
||||
// This is a pure-BUILDER shape check: idx/cardId/to are synthesized here; cost/clan/tribe are
|
||||
// ENGINE-sourced at the handler (PlayActionsHandler reads them off the resolved engine and passes them
|
||||
// to BuildPlayedCard — covered by HeadlessConductorTests), so this builder-only call leaves them at
|
||||
// their defaults and we assert only the structural keys.
|
||||
foreach (var key in new[] { "idx", "cardId", "to" })
|
||||
{
|
||||
Assert.That(ourEntry.TryGetProperty(key, out var ours), Is.True, $"knownList entry missing '{key}'");
|
||||
@@ -342,7 +345,8 @@ public class CaptureConformanceTests
|
||||
var ourEntry = ourDoc.RootElement.GetProperty("knownList")[0];
|
||||
using var prodDoc = JsonDocument.Parse(prodEntry);
|
||||
|
||||
// We own idx/cardId/to; cost/clan/tribe are deferred (receiver re-derives from cardId).
|
||||
// Pure-BUILDER shape check: idx/cardId/to are synthesized here; cost/clan/tribe are ENGINE-sourced at
|
||||
// the handler (covered by HeadlessConductorTests), so this builder-only call leaves them at defaults.
|
||||
foreach (var key in new[] { "idx", "cardId", "to" })
|
||||
{
|
||||
Assert.That(ourEntry.TryGetProperty(key, out var ours), Is.True, $"knownList entry missing '{key}'");
|
||||
@@ -424,7 +428,8 @@ public class CaptureConformanceTests
|
||||
// keyAction is {type,cardId} only (selectCard stripped for the hidden open:0 choice); knownList
|
||||
// reveals the generating DECK card. The choiceAdd lands a hidden token at idx 46 (candidates).
|
||||
// Subset check covers playIdx/type/keyAction — the parts we own; knownList idx/cardId/to are
|
||||
// asserted explicitly below (cost/clan/tribe are deferred, re-derived by the receiver from cardId).
|
||||
// asserted explicitly below (cost/clan/tribe are ENGINE-sourced at the handler, covered by
|
||||
// HeadlessConductorTests, so this builder-only call leaves them at defaults — not checked here).
|
||||
const string prodFrame = """
|
||||
{ "playIdx": 18, "type": 30,
|
||||
"keyAction": [ { "type": 1, "cardId": 810014030 } ] }
|
||||
@@ -471,8 +476,8 @@ public class CaptureConformanceTests
|
||||
Assert.That(ourKa.GetProperty("cardId").GetInt64(), Is.EqualTo(810014030L));
|
||||
|
||||
// The generating deck card reveals on its own play (idx 18 -> 810014030, to 30). cost/clan/tribe
|
||||
// are deferred (receiver re-derives from cardId), so only idx/cardId/to are checked — as in the
|
||||
// sibling SynthesizedKnownList_* tests.
|
||||
// are ENGINE-sourced at the handler (covered by HeadlessConductorTests); this builder-only call
|
||||
// leaves them at defaults, so only idx/cardId/to are checked — as in the sibling SynthesizedKnownList_* tests.
|
||||
var ourKnown = ourDoc.RootElement.GetProperty("knownList")[0];
|
||||
Assert.That(ourKnown.GetProperty("idx").GetInt32(), Is.EqualTo(18));
|
||||
Assert.That(ourKnown.GetProperty("cardId").GetInt64(), Is.EqualTo(810014030L));
|
||||
|
||||
Reference in New Issue
Block a user