docs(battlenode): document four latent low-tier hygiene hazards

Comment-only; behavior-preserving; 231 BattleNode tests green.

- OutboundSequencer._archive: name the unbounded-per-match growth + ack-prune point.
- NodeCrypto.BuildAes: SECURITY remarks on key-derived IV reuse + base64 entropy loss;
  warn against caching the session key.
- MatchContext/BattlePlayer: FOOTGUN notes on reference-based record equality over the deck list.
- RecordTokensFrom: TRUST note on isSelf/idx overwrite; name the idx>deckCount guard for
  untrusted peers (not added — trusted-LAN today).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-05 08:11:13 -04:00
parent 1007cf24d2
commit 9ff8948903
5 changed files with 29 additions and 1 deletions

View File

@@ -1,5 +1,10 @@
namespace SVSim.BattleNode.Bridge;
/// <summary>One player slot for a pending battle. Carries the viewer's identity and
/// the per-battle MatchContext snapshot built at do_matching time.</summary>
/// the per-battle MatchContext snapshot built at do_matching time.
/// <para>FOOTGUN: this is a <c>record</c>, but <see cref="Context"/> transitively holds an
/// <c>IReadOnlyList&lt;long&gt;</c> (the deck), so the synthesized value-equality is REFERENCE-based
/// on that list — two BattlePlayers with equal deck *contents* compare unequal. Don't use
/// BattlePlayer / <see cref="MatchContext"/> as dictionary keys or <c>Distinct()</c> / <c>HashSet</c>
/// operands without first giving them content equality. Not exercised today.</para></summary>
public sealed record BattlePlayer(long ViewerId, MatchContext Context);

View File

@@ -5,6 +5,9 @@ namespace SVSim.BattleNode.Bridge;
/// server-authored frame lifecycle on WS connect. SVSim.BattleNode does not know how to build this — the HTTP-side
/// per-mode controller is the source. Snapshot semantics: cosmetic changes between matching
/// and WS connect have no effect on the in-battle render.
/// <para>FOOTGUN: as a record holding <see cref="SelfDeckCardIds"/> (an IReadOnlyList), the
/// synthesized value-equality is reference-based on that list — see <see cref="BattlePlayer"/>.
/// Don't use as a dict key / <c>Distinct()</c> operand without content equality.</para>
/// </summary>
public sealed record MatchContext(
// Player's drafted deck — exactly 30 entries, idx 1..30 paired with the chosen cardIds