feat(net): N6 - ConnectResponse retransmit + fragment assembler eviction
Campaign N Slice N6, the final implementation slice.
ConnectResponse handshake retransmit:
- While the connection is unconfirmed, the Connect character-list pump
resends the IDENTICAL cleartext ConnectResponse (same sequence 1, same
cookie, the one encoded datagram - no new outbound state) on retail's
strict 0.333333333 s gate. Retail: ClientNet::ProcessConnection
@ 0x00545450, case cs_ConnectionRequestAcked @ 0x0054547B (the constant
load at 0x00545481; the mask-0x41 strictly-greater x87 test at
0x0054548C); ClientNet::SendConnectAck @ 0x005440F0 re-stamps
lastSentHandshake_ (0x00544102) and rebuilds the same cookie packet.
- Confirmation = the first checksum-valid post-negotiation packet whose
header lacks the ConnectRequest flag: retail's cs_ConnectionRequestAcked
-> cs_Connected edge (ClientNet::ProcessPacket @ 0x00545100, the 0x40000
exclusion at 0x0054514E, SetConnectionState(..., 5) at 0x00545160).
- The cadence rides the TransportClock (virtual-clock testable through
TransportClockSource); the Connect deadline stays wall-clock.
- ACE safety pinned against the N0 model: a duplicate while still
AuthConnectResponse re-routes idempotently through NetworkManager's
pre-route; after acceptance CheckState clause 2 drops it pre-CRC at
zero keystream cost.
- Pre-N6, one lost ConnectResponse was a hang to the Connect deadline;
the N5 decorator deliberately arms after this window, so nothing
covered it.
FragmentAssembler eviction (divergence register row AD-52):
- Partials evict 60 s after their last ACCEPTED fragment; the stamp
refreshes on every new fragment (retail's re-stamp rule,
ArrivedEphInfo::UpdateNetBlobID @ 0x0054AE00), so a merely-slow partial
can never age out - 60 s is a floor, not a tunable. Swept from
ReliableTransport.Sweep on retail's 5 s flush cadence
(Indicator::FlushTimedOutEphInfo @ 0x0054A3D0, the gate at 0x0054A3DC;
per-entry ArrivedEphInfo::fTimedOut @ 0x0054AE30). N4's RejectRetransmit
abandonment made an unrecoverable partial a REACHABLE permanent state;
the TTL reclaims it.
- A 64-entry completed-sequence ring drops late duplicate fragments of
already-completed messages instead of allocating a fresh partial that
can never complete (the completed-then-duplicate leak).
Fold-ins:
- N5 review LOW-5: NetProbeTests + LossyTransportDecoratorTests (the
static NetDiagnostics / Console.SetOut mutators) share one
DisableParallelization xunit collection so they never run alongside
classes constructing WorldSession.
- Campaign section 9: N6 ledger row recorded; N5 row verified carrying
4e290f00.
Gates: 757 Core.Net Release tests green (10 new); full solution Release
green (0 failures / 5 skips); connected lifecycle gate PASS; the
N5-strengthened connected loss gate PASS on its first live run (2%/seed 1:
dropped out=3 in=10, resends=1 nak-in=1 nak-out=5, cksum-fail=0
sanity-drop=0 uncached-nak=0).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
3899ebe0fd
commit
f9c5e47e7f
10 changed files with 691 additions and 19 deletions
25
tests/AcDream.Core.Net.Tests/NetProcessStaticsCollection.cs
Normal file
25
tests/AcDream.Core.Net.Tests/NetProcessStaticsCollection.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
namespace AcDream.Core.Net.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Campaign N Slice N6 fold-in (N5 review LOW-5): test classes that mutate
|
||||
/// process-global state — the <c>NetDiagnostics</c> typed toggles
|
||||
/// (<c>ProbeNet</c>, <c>NetDropPercent</c>, ...) or <c>Console.SetOut</c> —
|
||||
/// must never run in parallel with any test constructing a
|
||||
/// <c>WorldSession</c>, whose production paths read those statics (the
|
||||
/// public constructor's <c>LossyTransportDecorator.WrapIfConfigured</c>
|
||||
/// seam, the probe-gated <c>[net-tick]</c>/<c>[net-final]</c> console
|
||||
/// emission in <c>Tick</c>/<c>Dispose</c>).
|
||||
///
|
||||
/// <para>
|
||||
/// <c>DisableParallelization = true</c> makes xunit run this collection's
|
||||
/// classes strictly serially, AFTER every parallel collection has finished
|
||||
/// — never alongside anything. Apply
|
||||
/// <c>[Collection(NetProcessStaticsCollection.Name)]</c> to any new test
|
||||
/// class that touches those statics.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[CollectionDefinition(Name, DisableParallelization = true)]
|
||||
public sealed class NetProcessStaticsCollection
|
||||
{
|
||||
public const string Name = "net process statics";
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue