refactor(battlenode): single-source MsgEnvelope envelope keys (§E)

Behavior-preserving; 231 BattleNode tests green.

The envelope key set was encoded three times (ReservedEnvelopeKeys, the ToJson
writes, the FromJson reads). Added a private nested MsgEnvelope.Keys with a const
per key; the reserved set, writes, and reads now all draw from it, so a key added
in one place but not another (letting a body key shadow an envelope field) can no
longer happen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-05 07:33:54 -04:00
parent 7e167b1cef
commit d119d2c277

View File

@@ -24,9 +24,25 @@ public sealed record MsgEnvelope(
// EngineIoHandshake). Every wire key here is explicit via the manual ToJson layering below.
private static readonly JsonSerializerOptions Options = WireJsonOptions.CamelCase;
/// <summary>The fixed envelope wire keys, single-sourced. <see cref="ReservedEnvelopeKeys"/>,
/// the <see cref="ToJson"/> writes, and the <see cref="FromJson"/> reads all draw from here, so
/// the three encodings can't drift — adding a key in one place but not another (which would let a
/// body key silently shadow an envelope field) is no longer possible.</summary>
private static class Keys
{
public const string Uri = "uri";
public const string ViewerId = "viewerId";
public const string Uuid = "uuid";
public const string Bid = "bid";
public const string Try = "try";
public const string Cat = "cat";
public const string PubSeq = "pubSeq";
public const string PlaySeq = "playSeq";
}
private static readonly HashSet<string> ReservedEnvelopeKeys = new()
{
"uri", "viewerId", "uuid", "bid", "try", "cat", "pubSeq", "playSeq",
Keys.Uri, Keys.ViewerId, Keys.Uuid, Keys.Bid, Keys.Try, Keys.Cat, Keys.PubSeq, Keys.PlaySeq,
};
public static string ToJson(MsgEnvelope env)
@@ -37,14 +53,14 @@ public sealed record MsgEnvelope(
// field processed before "uri" is wiped before Matching.StartBattleLoad reads
// it back. The prod wire emits envelope keys first; we must too.
var result = new JsonObject();
result["uri"] = env.Uri.ToString();
result["viewerId"] = env.ViewerId;
result["uuid"] = env.Uuid;
result["try"] = env.RetryAttempt;
result["cat"] = (int)env.Cat;
if (env.Bid is not null) result["bid"] = env.Bid;
if (env.PubSeq.HasValue) result["pubSeq"] = env.PubSeq.Value;
if (env.PlaySeq.HasValue) result["playSeq"] = env.PlaySeq.Value;
result[Keys.Uri] = env.Uri.ToString();
result[Keys.ViewerId] = env.ViewerId;
result[Keys.Uuid] = env.Uuid;
result[Keys.Try] = env.RetryAttempt;
result[Keys.Cat] = (int)env.Cat;
if (env.Bid is not null) result[Keys.Bid] = env.Bid;
if (env.PubSeq.HasValue) result[Keys.PubSeq] = env.PubSeq.Value;
if (env.PlaySeq.HasValue) result[Keys.PlaySeq] = env.PlaySeq.Value;
if (env.Body is RawBody raw)
{
@@ -118,14 +134,14 @@ public sealed record MsgEnvelope(
using var doc = JsonDocument.Parse(json);
var root = doc.RootElement;
var uri = Enum.Parse<NetworkBattleUri>(root.GetProperty("uri").GetString()!);
var viewerId = root.GetProperty("viewerId").GetInt64();
var uuid = root.GetProperty("uuid").GetString()!;
var bid = root.TryGetProperty("bid", out var bidEl) ? bidEl.GetString() : null;
var retryAttempt = root.TryGetProperty("try", out var tryEl) ? tryEl.GetInt32() : 0;
var cat = root.TryGetProperty("cat", out var catEl) ? (EmitCategory)catEl.GetInt32() : EmitCategory.Battle;
var pubSeq = root.TryGetProperty("pubSeq", out var psEl) ? psEl.GetInt64() : (long?)null;
var playSeq = root.TryGetProperty("playSeq", out var plsEl) ? plsEl.GetInt64() : (long?)null;
var uri = Enum.Parse<NetworkBattleUri>(root.GetProperty(Keys.Uri).GetString()!);
var viewerId = root.GetProperty(Keys.ViewerId).GetInt64();
var uuid = root.GetProperty(Keys.Uuid).GetString()!;
var bid = root.TryGetProperty(Keys.Bid, out var bidEl) ? bidEl.GetString() : null;
var retryAttempt = root.TryGetProperty(Keys.Try, out var tryEl) ? tryEl.GetInt32() : 0;
var cat = root.TryGetProperty(Keys.Cat, out var catEl) ? (EmitCategory)catEl.GetInt32() : EmitCategory.Battle;
var pubSeq = root.TryGetProperty(Keys.PubSeq, out var psEl) ? psEl.GetInt64() : (long?)null;
var playSeq = root.TryGetProperty(Keys.PlaySeq, out var plsEl) ? plsEl.GetInt64() : (long?)null;
var bodyDict = new Dictionary<string, object?>();
foreach (var prop in root.EnumerateObject())