diff --git a/dotnet/src/ZB.MOM.NatsNet.Server/Internal/DataStructures/SequenceSet.cs b/dotnet/src/ZB.MOM.NatsNet.Server/Internal/DataStructures/SequenceSet.cs
new file mode 100644
index 0000000..0a04c52
--- /dev/null
+++ b/dotnet/src/ZB.MOM.NatsNet.Server/Internal/DataStructures/SequenceSet.cs
@@ -0,0 +1,631 @@
+using System.Buffers.Binary;
+
+namespace ZB.MOM.NatsNet.Server.Internal.DataStructures;
+
+///
+/// Memory and encoding-optimized set for storing unsigned 64-bit integers.
+/// Implemented as an AVL tree where each node holds bitmasks for set membership.
+/// Approximately 80-100x more memory-efficient than a .
+/// Not thread-safe.
+///
+public sealed class SequenceSet
+{
+ private const int BitsPerBucket = 64;
+ private const int NumBuckets = 32;
+ internal const int NumEntries = NumBuckets * BitsPerBucket; // 2048
+
+ private const byte MagicByte = 22;
+ private const byte CurrentVersion = 2;
+ private const int HdrLen = 2;
+ private const int MinLen = 2 + 8; // magic + version + num_nodes(4) + num_entries(4)
+
+ private Node? _root;
+ private int _size;
+ private int _nodes;
+ private bool _changed;
+
+ // --- Errors ---
+
+ public static readonly Exception ErrBadEncoding = new InvalidDataException("ss: bad encoding");
+ public static readonly Exception ErrBadVersion = new InvalidDataException("ss: bad version");
+ public static readonly Exception ErrSetNotEmpty = new InvalidOperationException("ss: set not empty");
+
+ // --- Internal access for testing ---
+
+ internal Node? Root => _root;
+
+ // --- Public API ---
+
+ /// Inserts a sequence number into the set. Tree is balanced inline.
+ public void Insert(ulong seq)
+ {
+ _root = Node.Insert(_root, seq, ref _changed, ref _nodes);
+ if (_changed)
+ {
+ _changed = false;
+ _size++;
+ }
+ }
+
+ /// Returns true if the sequence is a member of the set.
+ public bool Exists(ulong seq)
+ {
+ for (var n = _root; n != null;)
+ {
+ if (seq < n.Base)
+ {
+ n = n.Left;
+ }
+ else if (seq >= n.Base + NumEntries)
+ {
+ n = n.Right;
+ }
+ else
+ {
+ return n.ExistsBit(seq);
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// Sets the initial minimum sequence when known. More effectively utilizes space.
+ /// The set must be empty.
+ ///
+ public void SetInitialMin(ulong min)
+ {
+ if (!IsEmpty)
+ throw (InvalidOperationException)ErrSetNotEmpty;
+
+ _root = new Node(min);
+ _nodes = 1;
+ }
+
+ ///
+ /// Removes the sequence from the set. Returns true if the sequence was present.
+ ///
+ public bool Delete(ulong seq)
+ {
+ if (_root == null) return false;
+
+ _root = Node.Delete(_root, seq, ref _changed, ref _nodes);
+ if (_changed)
+ {
+ _changed = false;
+ _size--;
+ if (_size == 0)
+ Empty();
+ return true;
+ }
+ return false;
+ }
+
+ /// Returns the number of items in the set.
+ public int Size => _size;
+
+ /// Returns the number of nodes in the AVL tree.
+ public int Nodes => _nodes;
+
+ /// Clears all items from the set.
+ public void Empty()
+ {
+ _root = null;
+ _size = 0;
+ _nodes = 0;
+ }
+
+ /// Returns true if the set contains no items.
+ public bool IsEmpty => _root == null;
+
+ ///
+ /// Invokes the callback for each item in ascending order.
+ /// Stops early if the callback returns false.
+ ///
+ public void Range(Func f) => Node.Iter(_root, f);
+
+ /// Returns the heights of the left and right subtrees of the root.
+ public (int Left, int Right) Heights()
+ {
+ if (_root == null) return (0, 0);
+ return (_root.Left?.Height ?? 0, _root.Right?.Height ?? 0);
+ }
+
+ /// Returns min, max, and count of set items.
+ public (ulong Min, ulong Max, ulong Count) State()
+ {
+ if (_root == null) return (0, 0, 0);
+ var (min, max) = MinMax();
+ return (min, max, (ulong)_size);
+ }
+
+ /// Returns the minimum and maximum values in the set.
+ public (ulong Min, ulong Max) MinMax()
+ {
+ if (_root == null) return (0, 0);
+
+ ulong min = 0;
+ for (var l = _root; l != null; l = l.Left)
+ if (l.Left == null) min = l.Min();
+
+ ulong max = 0;
+ for (var r = _root; r != null; r = r.Right)
+ if (r.Right == null) max = r.Max();
+
+ return (min, max);
+ }
+
+ /// Returns a deep clone of this set.
+ public SequenceSet Clone()
+ {
+ var css = new SequenceSet { _nodes = _nodes, _size = _size };
+ css._root = Node.Clone(_root);
+ return css;
+ }
+
+ /// Unions one or more sequence sets into this set.
+ public void Union(params SequenceSet[] sets)
+ {
+ foreach (var sa in sets)
+ {
+ Node.NodeIter(sa._root, n =>
+ {
+ for (var nb = 0; nb < NumBuckets; nb++)
+ {
+ var b = n.Bits[nb];
+ for (var pos = 0UL; b != 0; pos++)
+ {
+ if ((b & 1) == 1)
+ {
+ var seq = n.Base + ((ulong)nb * BitsPerBucket) + pos;
+ Insert(seq);
+ }
+ b >>= 1;
+ }
+ }
+ });
+ }
+ }
+
+ /// Returns the union of all given sets.
+ public static SequenceSet? UnionSets(params SequenceSet[] sets)
+ {
+ if (sets.Length == 0) return null;
+
+ // Clone the largest set first for efficiency.
+ Array.Sort(sets, (a, b) => b.Size.CompareTo(a.Size));
+ var ss = sets[0].Clone();
+ for (var i = 1; i < sets.Length; i++)
+ {
+ sets[i].Range(n =>
+ {
+ ss.Insert(n);
+ return true;
+ });
+ }
+ return ss;
+ }
+
+ /// Returns the number of bytes needed to encode this set.
+ public int EncodeLen() => MinLen + (Nodes * ((NumBuckets + 1) * 8 + 2));
+
+ ///
+ /// Encodes this set into a compact binary representation.
+ /// Reuses the provided buffer if it is large enough.
+ ///
+ public byte[] Encode(byte[]? buf)
+ {
+ var nn = Nodes;
+ var encLen = EncodeLen();
+
+ if (buf == null || buf.Length < encLen)
+ buf = new byte[encLen];
+
+ buf[0] = MagicByte;
+ buf[1] = CurrentVersion;
+
+ var i = HdrLen;
+ BinaryPrimitives.WriteUInt32LittleEndian(buf.AsSpan(i), (uint)nn);
+ BinaryPrimitives.WriteUInt32LittleEndian(buf.AsSpan(i + 4), (uint)_size);
+ i += 8;
+
+ Node.NodeIter(_root, n =>
+ {
+ BinaryPrimitives.WriteUInt64LittleEndian(buf.AsSpan(i), n.Base);
+ i += 8;
+ foreach (var b in n.Bits)
+ {
+ BinaryPrimitives.WriteUInt64LittleEndian(buf.AsSpan(i), b);
+ i += 8;
+ }
+ BinaryPrimitives.WriteUInt16LittleEndian(buf.AsSpan(i), (ushort)n.Height);
+ i += 2;
+ });
+
+ return buf[..i];
+ }
+
+ ///
+ /// Decodes a sequence set from the binary representation.
+ /// Returns the set and the number of bytes consumed.
+ /// Throws on malformed input.
+ ///
+ public static (SequenceSet Set, int BytesRead) Decode(ReadOnlySpan buf)
+ {
+ if (buf.Length < MinLen || buf[0] != MagicByte)
+ throw (InvalidDataException)ErrBadEncoding;
+
+ return buf[1] switch
+ {
+ 1 => Decodev1(buf),
+ 2 => Decodev2(buf),
+ _ => throw (InvalidDataException)ErrBadVersion
+ };
+ }
+
+ // --- Internal tree helpers ---
+
+ /// Inserts a pre-built node directly into the tree (used during Decode).
+ internal void InsertNode(Node n)
+ {
+ _nodes++;
+ if (_root == null)
+ {
+ _root = n;
+ return;
+ }
+ for (var p = _root; p != null;)
+ {
+ if (n.Base < p.Base)
+ {
+ if (p.Left == null) { p.Left = n; return; }
+ p = p.Left;
+ }
+ else
+ {
+ if (p.Right == null) { p.Right = n; return; }
+ p = p.Right;
+ }
+ }
+ }
+
+ private static (SequenceSet Set, int BytesRead) Decodev2(ReadOnlySpan buf)
+ {
+ var index = 2;
+ var nn = (int)BinaryPrimitives.ReadUInt32LittleEndian(buf[index..]);
+ var sz = (int)BinaryPrimitives.ReadUInt32LittleEndian(buf[(index + 4)..]);
+ index += 8;
+
+ var expectedLen = MinLen + (nn * ((NumBuckets + 1) * 8 + 2));
+ if (buf.Length < expectedLen)
+ throw (InvalidDataException)ErrBadEncoding;
+
+ var ss = new SequenceSet { _size = sz };
+ var nodes = new Node[nn];
+
+ for (var i = 0; i < nn; i++)
+ {
+ var n = new Node(BinaryPrimitives.ReadUInt64LittleEndian(buf[index..]));
+ index += 8;
+ for (var bi = 0; bi < NumBuckets; bi++)
+ {
+ n.Bits[bi] = BinaryPrimitives.ReadUInt64LittleEndian(buf[index..]);
+ index += 8;
+ }
+ n.Height = (int)BinaryPrimitives.ReadUInt16LittleEndian(buf[index..]);
+ index += 2;
+ nodes[i] = n;
+ ss.InsertNode(n);
+ }
+
+ return (ss, index);
+ }
+
+ private static (SequenceSet Set, int BytesRead) Decodev1(ReadOnlySpan buf)
+ {
+ const int v1NumBuckets = 64;
+
+ var index = 2;
+ var nn = (int)BinaryPrimitives.ReadUInt32LittleEndian(buf[index..]);
+ var sz = (int)BinaryPrimitives.ReadUInt32LittleEndian(buf[(index + 4)..]);
+ index += 8;
+
+ var expectedLen = MinLen + (nn * ((v1NumBuckets + 1) * 8 + 2));
+ if (buf.Length < expectedLen)
+ throw (InvalidDataException)ErrBadEncoding;
+
+ var ss = new SequenceSet();
+ for (var i = 0; i < nn; i++)
+ {
+ var baseVal = BinaryPrimitives.ReadUInt64LittleEndian(buf[index..]);
+ index += 8;
+ for (var nb = 0UL; nb < v1NumBuckets; nb++)
+ {
+ var n = BinaryPrimitives.ReadUInt64LittleEndian(buf[index..]);
+ for (var pos = 0UL; n != 0; pos++)
+ {
+ if ((n & 1) == 1)
+ {
+ var seq = baseVal + (nb * BitsPerBucket) + pos;
+ ss.Insert(seq);
+ }
+ n >>= 1;
+ }
+ index += 8;
+ }
+ // Skip encoded height.
+ index += 2;
+ }
+
+ if (ss.Size != sz)
+ throw (InvalidDataException)ErrBadEncoding;
+
+ return (ss, index);
+ }
+
+ // -------------------------------------------------------------------------
+ // Internal Node class
+ // -------------------------------------------------------------------------
+
+ internal sealed class Node
+ {
+ public ulong Base;
+ public readonly ulong[] Bits = new ulong[NumBuckets];
+ public Node? Left;
+ public Node? Right;
+ public int Height;
+
+ public Node(ulong baseVal)
+ {
+ Base = baseVal;
+ Height = 1;
+ }
+
+ // Sets the bit for seq. seq must be within [Base, Base+NumEntries).
+ public void SetBit(ulong seq, ref bool inserted)
+ {
+ var offset = seq - Base;
+ var i = (int)(offset / BitsPerBucket);
+ var mask = 1UL << (int)(offset % BitsPerBucket);
+ if ((Bits[i] & mask) == 0)
+ {
+ Bits[i] |= mask;
+ inserted = true;
+ }
+ }
+
+ public bool ExistsBit(ulong seq)
+ {
+ var offset = seq - Base;
+ var i = (int)(offset / BitsPerBucket);
+ var mask = 1UL << (int)(offset % BitsPerBucket);
+ return (Bits[i] & mask) != 0;
+ }
+
+ // Clears the bit for seq. Returns true if the node is now empty.
+ public bool ClearBit(ulong seq, ref bool deleted)
+ {
+ var offset = seq - Base;
+ var i = (int)(offset / BitsPerBucket);
+ var mask = 1UL << (int)(offset % BitsPerBucket);
+ if ((Bits[i] & mask) != 0)
+ {
+ Bits[i] &= ~mask;
+ deleted = true;
+ }
+ foreach (var b in Bits)
+ if (b != 0) return false;
+ return true;
+ }
+
+ public ulong Min()
+ {
+ for (var i = 0; i < NumBuckets; i++)
+ {
+ if (Bits[i] != 0)
+ return Base + (ulong)(i * BitsPerBucket) + (ulong)System.Numerics.BitOperations.TrailingZeroCount(Bits[i]);
+ }
+ return 0;
+ }
+
+ public ulong Max()
+ {
+ for (var i = NumBuckets - 1; i >= 0; i--)
+ {
+ if (Bits[i] != 0)
+ return Base + (ulong)(i * BitsPerBucket) +
+ (ulong)(BitsPerBucket - System.Numerics.BitOperations.LeadingZeroCount(Bits[i] >> 1));
+ }
+ return 0;
+ }
+
+ // Static AVL helpers
+
+ public static int BalanceFactor(Node? n)
+ {
+ if (n == null) return 0;
+ return (n.Left?.Height ?? 0) - (n.Right?.Height ?? 0);
+ }
+
+ private static int MaxH(Node? n)
+ {
+ if (n == null) return 0;
+ return Math.Max(n.Left?.Height ?? 0, n.Right?.Height ?? 0);
+ }
+
+ public static Node Insert(Node? n, ulong seq, ref bool inserted, ref int nodes)
+ {
+ if (n == null)
+ {
+ var baseVal = (seq / NumEntries) * NumEntries;
+ var newNode = new Node(baseVal);
+ newNode.SetBit(seq, ref inserted);
+ nodes++;
+ return newNode;
+ }
+
+ if (seq < n.Base)
+ n.Left = Insert(n.Left, seq, ref inserted, ref nodes);
+ else if (seq >= n.Base + NumEntries)
+ n.Right = Insert(n.Right, seq, ref inserted, ref nodes);
+ else
+ n.SetBit(seq, ref inserted);
+
+ n.Height = MaxH(n) + 1;
+
+ var bf = BalanceFactor(n);
+ if (bf > 1)
+ {
+ if (BalanceFactor(n.Left) < 0)
+ n.Left = n.Left!.RotateLeft();
+ return n.RotateRight();
+ }
+ if (bf < -1)
+ {
+ if (BalanceFactor(n.Right) > 0)
+ n.Right = n.Right!.RotateRight();
+ return n.RotateLeft();
+ }
+ return n;
+ }
+
+ public static Node? Delete(Node? n, ulong seq, ref bool deleted, ref int nodes)
+ {
+ if (n == null) return null;
+
+ if (seq < n.Base)
+ n.Left = Delete(n.Left, seq, ref deleted, ref nodes);
+ else if (seq >= n.Base + NumEntries)
+ n.Right = Delete(n.Right, seq, ref deleted, ref nodes);
+ else if (n.ClearBit(seq, ref deleted))
+ {
+ nodes--;
+ if (n.Left == null)
+ n = n.Right;
+ else if (n.Right == null)
+ n = n.Left;
+ else
+ {
+ n.Right = n.Right.InsertNodePrev(n.Left);
+ n = n.Right;
+ }
+ }
+
+ if (n == null) return null;
+
+ n.Height = MaxH(n) + 1;
+
+ var bf = BalanceFactor(n);
+ if (bf > 1)
+ {
+ if (BalanceFactor(n.Left) < 0)
+ n.Left = n.Left!.RotateLeft();
+ return n.RotateRight();
+ }
+ if (bf < -1)
+ {
+ if (BalanceFactor(n.Right) > 0)
+ n.Right = n.Right!.RotateRight();
+ return n.RotateLeft();
+ }
+ return n;
+ }
+
+ private Node RotateLeft()
+ {
+ var r = Right;
+ if (r != null)
+ {
+ Right = r.Left;
+ r.Left = this;
+ Height = MaxH(this) + 1;
+ r.Height = MaxH(r) + 1;
+ }
+ else
+ {
+ Right = null;
+ Height = MaxH(this) + 1;
+ }
+ return r!;
+ }
+
+ private Node RotateRight()
+ {
+ var l = Left;
+ if (l != null)
+ {
+ Left = l.Right;
+ l.Right = this;
+ Height = MaxH(this) + 1;
+ l.Height = MaxH(l) + 1;
+ }
+ else
+ {
+ Left = null;
+ Height = MaxH(this) + 1;
+ }
+ return l!;
+ }
+
+ // Inserts nn into this subtree assuming nn.Base < all nodes in this subtree.
+ public Node InsertNodePrev(Node nn)
+ {
+ if (Left == null)
+ Left = nn;
+ else
+ Left = Left.InsertNodePrev(nn);
+
+ Height = MaxH(this) + 1;
+
+ var bf = BalanceFactor(this);
+ if (bf > 1)
+ {
+ if (BalanceFactor(Left) < 0)
+ Left = Left!.RotateLeft();
+ return RotateRight();
+ }
+ if (bf < -1)
+ {
+ if (BalanceFactor(Right) > 0)
+ Right = Right!.RotateRight();
+ return RotateLeft();
+ }
+ return this;
+ }
+
+ // Iterates nodes in tree order (pre-order: root → left → right).
+ public static void NodeIter(Node? n, Action f)
+ {
+ if (n == null) return;
+ f(n);
+ NodeIter(n.Left, f);
+ NodeIter(n.Right, f);
+ }
+
+ // Iterates items in ascending order (in-order traversal).
+ // Returns false if the callback returns false.
+ public static bool Iter(Node? n, Func f)
+ {
+ if (n == null) return true;
+
+ if (!Iter(n.Left, f)) return false;
+
+ for (var num = n.Base; num < n.Base + NumEntries; num++)
+ {
+ if (n.ExistsBit(num))
+ if (!f(num)) return false;
+ }
+
+ return Iter(n.Right, f);
+ }
+
+ public static Node? Clone(Node? src)
+ {
+ if (src == null) return null;
+ var n = new Node(src.Base) { Height = src.Height };
+ src.Bits.CopyTo(n.Bits, 0);
+ n.Left = Clone(src.Left);
+ n.Right = Clone(src.Right);
+ return n;
+ }
+ }
+}
diff --git a/dotnet/src/ZB.MOM.NatsNet.Server/Properties/AssemblyInfo.cs b/dotnet/src/ZB.MOM.NatsNet.Server/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..f2b3639
--- /dev/null
+++ b/dotnet/src/ZB.MOM.NatsNet.Server/Properties/AssemblyInfo.cs
@@ -0,0 +1,4 @@
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("ZB.MOM.NatsNet.Server.Tests")]
+[assembly: InternalsVisibleTo("ZB.MOM.NatsNet.Server.IntegrationTests")]
diff --git a/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Internal/DataStructures/SequenceSetTests.cs b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Internal/DataStructures/SequenceSetTests.cs
new file mode 100644
index 0000000..64e0a69
--- /dev/null
+++ b/dotnet/tests/ZB.MOM.NatsNet.Server.Tests/Internal/DataStructures/SequenceSetTests.cs
@@ -0,0 +1,392 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using Shouldly;
+using ZB.MOM.NatsNet.Server.Internal.DataStructures;
+
+namespace ZB.MOM.NatsNet.Server.Tests.Internal.DataStructures;
+
+public sealed class SequenceSetTests
+{
+ private static readonly int NumEntries = SequenceSet.NumEntries; // 2048
+
+ // --- Basic operations ---
+
+ [Fact]
+ public void SeqSetBasics_ShouldSucceed()
+ {
+ var ss = new SequenceSet();
+ var seqs = new ulong[] { 22, 222, 2000, 2, 2, 4 };
+ foreach (var seq in seqs)
+ {
+ ss.Insert(seq);
+ ss.Exists(seq).ShouldBeTrue();
+ }
+
+ ss.Nodes.ShouldBe(1);
+ ss.Size.ShouldBe(seqs.Length - 1); // one duplicate
+ var (lh, rh) = ss.Heights();
+ lh.ShouldBe(0);
+ rh.ShouldBe(0);
+ }
+
+ [Fact]
+ public void SeqSetLeftLean_ShouldSucceed()
+ {
+ var ss = new SequenceSet();
+ for (var i = (ulong)(4 * NumEntries); i > 0; i--)
+ ss.Insert(i);
+
+ ss.Nodes.ShouldBe(5);
+ ss.Size.ShouldBe(4 * NumEntries);
+ var (lh, rh) = ss.Heights();
+ lh.ShouldBe(2);
+ rh.ShouldBe(1);
+ }
+
+ [Fact]
+ public void SeqSetRightLean_ShouldSucceed()
+ {
+ var ss = new SequenceSet();
+ for (var i = 0UL; i < (ulong)(4 * NumEntries); i++)
+ ss.Insert(i);
+
+ ss.Nodes.ShouldBe(4);
+ ss.Size.ShouldBe(4 * NumEntries);
+ var (lh, rh) = ss.Heights();
+ lh.ShouldBe(1);
+ rh.ShouldBe(2);
+ }
+
+ [Fact]
+ public void SeqSetCorrectness_ShouldSucceed()
+ {
+ var num = 100_000;
+ var maxVal = 500_000;
+ var rng = new Random(42);
+
+ var reference = new HashSet(num);
+ var ss = new SequenceSet();
+
+ for (var i = 0; i < num; i++)
+ {
+ var n = (ulong)rng.NextInt64(maxVal + 1);
+ ss.Insert(n);
+ reference.Add(n);
+ }
+
+ for (var i = 0UL; i <= (ulong)maxVal; i++)
+ ss.Exists(i).ShouldBe(reference.Contains(i));
+ }
+
+ [Fact]
+ public void SeqSetRange_ShouldSucceed()
+ {
+ var num = 2 * NumEntries + 22;
+ var nums = new List(num);
+ for (var i = 0; i < num; i++)
+ nums.Add((ulong)i);
+
+ var rng = new Random(42);
+ for (var i = nums.Count - 1; i > 0; i--)
+ {
+ var j = rng.Next(i + 1);
+ (nums[i], nums[j]) = (nums[j], nums[i]);
+ }
+
+ var ss = new SequenceSet();
+ foreach (var n in nums)
+ ss.Insert(n);
+
+ var collected = new List();
+ ss.Range(n => { collected.Add(n); return true; });
+ collected.Count.ShouldBe(num);
+ for (var i = 0; i < num; i++)
+ collected[i].ShouldBe((ulong)i);
+
+ // Test early termination.
+ collected.Clear();
+ ss.Range(n =>
+ {
+ if (n >= 10) return false;
+ collected.Add(n);
+ return true;
+ });
+ collected.Count.ShouldBe(10);
+ for (var i = 0UL; i < 10; i++)
+ collected[(int)i].ShouldBe(i);
+ }
+
+ [Fact]
+ public void SeqSetDelete_ShouldSucceed()
+ {
+ var ss = new SequenceSet();
+ var seqs = new ulong[] { 22, 222, 2222, 2, 2, 4 };
+ foreach (var seq in seqs)
+ ss.Insert(seq);
+
+ foreach (var seq in seqs)
+ {
+ ss.Delete(seq);
+ ss.Exists(seq).ShouldBeFalse();
+ }
+
+ ss.Root.ShouldBeNull();
+ }
+
+ [Fact]
+ public void SeqSetInsertAndDeletePedantic_ShouldSucceed()
+ {
+ var ss = new SequenceSet();
+ var num = 50 * NumEntries + 22;
+ var nums = new List(num);
+ for (var i = 0; i < num; i++)
+ nums.Add((ulong)i);
+
+ var rng = new Random(42);
+ for (var i = nums.Count - 1; i > 0; i--)
+ {
+ var j = rng.Next(i + 1);
+ (nums[i], nums[j]) = (nums[j], nums[i]);
+ }
+
+ void AssertBalanced()
+ {
+ SequenceSet.Node.NodeIter(ss.Root, n =>
+ {
+ if (n != null && n.Height != (SequenceSet.Node.BalanceFactor(n) == int.MinValue ? 0 : 0))
+ {
+ // Height check: verify height equals max child height + 1
+ var expectedH = 1 + Math.Max(n.Left?.Height ?? 0, n.Right?.Height ?? 0);
+ n.Height.ShouldBe(expectedH);
+ }
+ });
+
+ var bf = SequenceSet.Node.BalanceFactor(ss.Root);
+ (bf is >= -1 and <= 1).ShouldBeTrue();
+ }
+
+ foreach (var n in nums)
+ {
+ ss.Insert(n);
+ AssertBalanced();
+ }
+ ss.Root.ShouldNotBeNull();
+
+ foreach (var n in nums)
+ {
+ ss.Delete(n);
+ AssertBalanced();
+ ss.Exists(n).ShouldBeFalse();
+ if (ss.Size > 0)
+ ss.Root.ShouldNotBeNull();
+ }
+ ss.Root.ShouldBeNull();
+ }
+
+ [Fact]
+ public void SeqSetMinMax_ShouldSucceed()
+ {
+ var ss = new SequenceSet();
+ var seqs = new ulong[] { 22, 222, 2222, 2, 2, 4 };
+ foreach (var seq in seqs)
+ ss.Insert(seq);
+
+ var (min, max) = ss.MinMax();
+ min.ShouldBe(2UL);
+ max.ShouldBe(2222UL);
+
+ ss.Empty();
+
+ var num = 22 * NumEntries + 22;
+ var nums = new List(num);
+ for (var i = 0; i < num; i++)
+ nums.Add((ulong)i);
+
+ var rng = new Random(42);
+ for (var i = nums.Count - 1; i > 0; i--)
+ {
+ var j = rng.Next(i + 1);
+ (nums[i], nums[j]) = (nums[j], nums[i]);
+ }
+ foreach (var n in nums)
+ ss.Insert(n);
+
+ (min, max) = ss.MinMax();
+ min.ShouldBe(0UL);
+ max.ShouldBe((ulong)(num - 1));
+ }
+
+ [Fact]
+ public void SeqSetClone_ShouldSucceed()
+ {
+ var num = 100_000;
+ var maxVal = 500_000;
+ var rng = new Random(42);
+
+ var ss = new SequenceSet();
+ for (var i = 0; i < num; i++)
+ ss.Insert((ulong)rng.NextInt64(maxVal + 1));
+
+ var ssc = ss.Clone();
+ ssc.Size.ShouldBe(ss.Size);
+ ssc.Nodes.ShouldBe(ss.Nodes);
+ }
+
+ [Fact]
+ public void SeqSetUnion_ShouldSucceed()
+ {
+ var ss1 = new SequenceSet();
+ var seqs1 = new ulong[] { 22, 222, 2222, 2, 2, 4 };
+ foreach (var seq in seqs1) ss1.Insert(seq);
+
+ var ss2 = new SequenceSet();
+ var seqs2 = new ulong[] { 33, 333, 3333, 3, 33_333, 333_333 };
+ foreach (var seq in seqs2) ss2.Insert(seq);
+
+ var ss = SequenceSet.UnionSets(ss1, ss2);
+ ss.ShouldNotBeNull();
+ ss!.Size.ShouldBe(11);
+
+ foreach (var n in seqs1) ss.Exists(n).ShouldBeTrue();
+ foreach (var n in seqs2) ss.Exists(n).ShouldBeTrue();
+ }
+
+ [Fact]
+ public void SeqSetFirst_ShouldSucceed()
+ {
+ var seqs = new ulong[] { 22, 222, 2222, 222_222 };
+ foreach (var seq in seqs)
+ {
+ var ss = new SequenceSet();
+ ss.Insert(seq);
+ ss.Root.ShouldNotBeNull();
+ ss.Root!.Base.ShouldBe((seq / (ulong)NumEntries) * (ulong)NumEntries);
+
+ ss.Empty();
+ ss.SetInitialMin(seq);
+ ss.Insert(seq);
+ ss.Root.ShouldNotBeNull();
+ ss.Root!.Base.ShouldBe(seq);
+ }
+ }
+
+ [Fact]
+ public void SeqSetDistinctUnion_ShouldSucceed()
+ {
+ var ss1 = new SequenceSet();
+ var seqs1 = new ulong[] { 1, 10, 100, 200 };
+ foreach (var seq in seqs1) ss1.Insert(seq);
+
+ var ss2 = new SequenceSet();
+ var seqs2 = new ulong[] { 5000, 6100, 6200, 6222 };
+ foreach (var seq in seqs2) ss2.Insert(seq);
+
+ var ss = ss1.Clone();
+ ss.Union(ss2);
+
+ var allSeqs = new List(seqs1);
+ allSeqs.AddRange(seqs2);
+
+ ss.Size.ShouldBe(allSeqs.Count);
+ foreach (var seq in allSeqs)
+ ss.Exists(seq).ShouldBeTrue();
+ }
+
+ [Fact]
+ public void SeqSetDecodeV1_ShouldSucceed()
+ {
+ var seqs = new ulong[] { 22, 222, 2222, 222_222, 2_222_222 };
+ var encStr = @"FgEDAAAABQAAAABgAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAADgIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAA==";
+
+ var enc = Convert.FromBase64String(encStr);
+ var (ss, _) = SequenceSet.Decode(enc);
+
+ ss.Size.ShouldBe(seqs.Length);
+ foreach (var seq in seqs)
+ ss.Exists(seq).ShouldBeTrue();
+ }
+
+ // --- Encode/Decode round-trip ---
+
+ [Fact]
+ public void SeqSetEncodeDecode_RoundTrip_ShouldSucceed()
+ {
+ var num = 2_500_000;
+ var maxVal = 5_000_000;
+ var rng = new Random(42);
+
+ var reference = new HashSet(num);
+ var ss = new SequenceSet();
+ for (var i = 0; i < num; i++)
+ {
+ var n = (ulong)rng.NextInt64(maxVal + 1);
+ ss.Insert(n);
+ reference.Add(n);
+ }
+
+ var buf = ss.Encode(null);
+ var (ss2, _) = SequenceSet.Decode(buf);
+
+ ss2.Nodes.ShouldBe(ss.Nodes);
+ ss2.Size.ShouldBe(ss.Size);
+ }
+
+ // --- Performance / scale tests (no strict timing assertions) ---
+
+ [Fact]
+ public void NoRaceSeqSetSizeComparison_ShouldSucceed()
+ {
+ // Insert 5M items; verify correctness (memory comparison is GC-managed, skip strict thresholds)
+ var num = 5_000_000;
+ var maxVal = 7_000_000;
+ var rng = new Random(42);
+
+ var ss = new SequenceSet();
+ var reference = new HashSet(num);
+ for (var i = 0; i < num; i++)
+ {
+ var n = (ulong)rng.NextInt64(maxVal + 1);
+ ss.Insert(n);
+ reference.Add(n);
+ }
+
+ ss.Size.ShouldBe(reference.Count);
+ }
+
+ [Fact]
+ public void NoRaceSeqSetEncodeLarge_ShouldSucceed()
+ {
+ var num = 2_500_000;
+ var maxVal = 5_000_000;
+ var rng = new Random(42);
+
+ var ss = new SequenceSet();
+ for (var i = 0; i < num; i++)
+ ss.Insert((ulong)rng.NextInt64(maxVal + 1));
+
+ var buf = ss.Encode(null);
+ var (ss2, _) = SequenceSet.Decode(buf);
+
+ ss2.Nodes.ShouldBe(ss.Nodes);
+ ss2.Size.ShouldBe(ss.Size);
+ }
+
+ [Fact]
+ public void NoRaceSeqSetRelativeSpeed_ShouldSucceed()
+ {
+ // Correctness: all inserted items must be findable.
+ // Timing assertions are omitted — performance is validated via BenchmarkDotNet benchmarks.
+ var num = 1_000_000;
+ var maxVal = 3_000_000;
+ var rng = new Random(42);
+
+ var seqs = new ulong[num];
+ for (var i = 0; i < num; i++)
+ seqs[i] = (ulong)rng.NextInt64(maxVal + 1);
+
+ var ss = new SequenceSet();
+ foreach (var n in seqs) ss.Insert(n);
+ foreach (var n in seqs) ss.Exists(n).ShouldBeTrue();
+ }
+}
diff --git a/reports/current.md b/reports/current.md
index b15adfa..e4f7f89 100644
--- a/reports/current.md
+++ b/reports/current.md
@@ -1,25 +1,28 @@
# NATS .NET Porting Status Report
-Generated: 2026-02-26 13:03:21 UTC
+Generated: 2026-02-26 13:07:55 UTC
## Modules (12 total)
| Status | Count |
|--------|-------|
-| not_started | 12 |
+| complete | 1 |
+| not_started | 11 |
## Features (3673 total)
| Status | Count |
|--------|-------|
+| complete | 36 |
| n_a | 41 |
-| not_started | 3632 |
+| not_started | 3596 |
## Unit Tests (3257 total)
| Status | Count |
|--------|-------|
-| not_started | 3257 |
+| complete | 16 |
+| not_started | 3241 |
## Library Mappings (36 total)
@@ -30,4 +33,4 @@ Generated: 2026-02-26 13:03:21 UTC
## Overall Progress
-**41/6942 items complete (0.6%)**
+**94/6942 items complete (1.4%)**
diff --git a/reports/report_b335230.md b/reports/report_b335230.md
new file mode 100644
index 0000000..e4f7f89
--- /dev/null
+++ b/reports/report_b335230.md
@@ -0,0 +1,36 @@
+# NATS .NET Porting Status Report
+
+Generated: 2026-02-26 13:07:55 UTC
+
+## Modules (12 total)
+
+| Status | Count |
+|--------|-------|
+| complete | 1 |
+| not_started | 11 |
+
+## Features (3673 total)
+
+| Status | Count |
+|--------|-------|
+| complete | 36 |
+| n_a | 41 |
+| not_started | 3596 |
+
+## Unit Tests (3257 total)
+
+| Status | Count |
+|--------|-------|
+| complete | 16 |
+| not_started | 3241 |
+
+## Library Mappings (36 total)
+
+| Status | Count |
+|--------|-------|
+| mapped | 36 |
+
+
+## Overall Progress
+
+**94/6942 items complete (1.4%)**