Merge branch 'fix/archreview-p2' into main (P2 tier: completeness & polish)

# Conflicts:
#	archreview/remediation/00-tracking.md
#	clients/dotnet/ZB.MOM.WW.MxGateway.Client.Cli/MxGatewayCliSecretRedactor.cs
#	clients/dotnet/ZB.MOM.WW.MxGateway.Client.Cli/MxGatewayClientCli.cs
#	src/ZB.MOM.WW.MxGateway.Worker.Tests/Ipc/WorkerFrameProtocolTests.cs
This commit is contained in:
Joseph Doherty
2026-07-12 22:12:41 -04:00
91 changed files with 7680 additions and 681 deletions
@@ -185,6 +185,90 @@ public sealed class SessionEventDistributorTests
Assert.Equal(new ulong[] { 3, 4, 5 }, replay.Select(e => e.WorkerSequence));
}
/// <summary>
/// Appending far more events than the capacity wraps the circular buffer's head
/// index past the array boundary multiple times; the retained window stays the
/// newest <c>capacity</c> events, in ascending order, and a replay from before the
/// window reports a gap and returns the whole retained tail.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ReplayBuffer_WrapsRingMultipleTimes_RetainsNewestInAscendingOrder()
{
Channel<MxEvent> source = Channel.CreateUnbounded<MxEvent>();
await using SessionEventDistributor distributor = CreateDistributor(
source.Reader,
replayBufferCapacity: 4,
replayRetentionSeconds: 0);
await distributor.StartAsync(CancellationToken.None);
// 13 events through a capacity-4 ring advances the head index 13 - 4 = 9 slots,
// wrapping the 4-slot array's boundary more than twice.
using IEventSubscriberLease lease = distributor.Register();
for (ulong sequence = 1; sequence <= 13; sequence++)
{
source.Writer.TryWrite(Event(sequence));
}
for (ulong sequence = 1; sequence <= 13; sequence++)
{
MxEvent e = await ReadOneAsync(lease.Reader);
Assert.Equal(sequence, e.WorkerSequence);
}
// Newest four (10, 11, 12, 13) retained in ascending order despite the wraps.
bool found = distributor.TryGetReplayFrom(0, out IReadOnlyList<MxEvent> replay, out bool gap);
Assert.True(found);
Assert.True(gap);
Assert.Equal(new ulong[] { 10, 11, 12, 13 }, replay.Select(e => e.WorkerSequence));
// A replay from inside the wrapped window returns only the newer entries, no gap,
// proving the modular scan reads the logical order and not the physical slots.
bool foundInner = distributor.TryGetReplayFrom(11, out IReadOnlyList<MxEvent> inner, out bool innerGap);
Assert.True(foundInner);
Assert.False(innerGap);
Assert.Equal(new ulong[] { 12, 13 }, inner.Select(e => e.WorkerSequence));
}
/// <summary>
/// A capacity-1 ring retains only the single newest event; each append overwrites
/// the sole slot, and a replay from before it reports a gap.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]
public async Task ReplayBuffer_Capacity1_RetainsOnlyNewest()
{
Channel<MxEvent> source = Channel.CreateUnbounded<MxEvent>();
await using SessionEventDistributor distributor = CreateDistributor(
source.Reader,
replayBufferCapacity: 1,
replayRetentionSeconds: 0);
await distributor.StartAsync(CancellationToken.None);
using IEventSubscriberLease lease = distributor.Register();
for (ulong sequence = 1; sequence <= 3; sequence++)
{
source.Writer.TryWrite(Event(sequence));
_ = await ReadOneAsync(lease.Reader);
}
// Only sequence 3 is retained; a request from 0 missed 1 and 2 => gap.
bool found = distributor.TryGetReplayFrom(0, out IReadOnlyList<MxEvent> replay, out bool gap);
Assert.True(found);
Assert.True(gap);
Assert.Equal(new ulong[] { 3 }, replay.Select(e => e.WorkerSequence));
// A request from exactly the newest retained sequence is caught up: empty, no gap.
bool foundCaughtUp = distributor.TryGetReplayFrom(3, out IReadOnlyList<MxEvent> caughtUp, out bool caughtUpGap);
Assert.True(foundCaughtUp);
Assert.False(caughtUpGap);
Assert.Empty(caughtUp);
}
/// <summary>Requesting replay from a sequence still inside the retained window returns only the newer events, with no gap.</summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Fact]