@@ -214,8 +214,23 @@ func (m *MemoryEventBus) Publish(ctx context.Context, event Event) error {
214214 return nil
215215 }
216216
217- // Optional rotation for fairness. We deliberately removed the previous random shuffle fallback
218- // (when rotation disabled) to preserve deterministic ordering and avoid per-publish RNG cost.
217+ // Optional rotation for fairness.
218+ // Rationale:
219+ // * Deterministic order when rotation disabled (stable slice) improves testability and
220+ // reasoning about delivery ordering.
221+ // * When rotation enabled we perform a logical rotation using an incrementing counter
222+ // rather than allocating + copying on every publish via append/slice tricks or
223+ // performing a random shuffle. This yields O(n) copies only when the starting offset
224+ // changes (and only for length > 1) with no RNG cost and avoids uint64->int casts
225+ // that would require additional lint suppression.
226+ // * Slice re-slicing with append could avoid an allocation in the start!=0 case, but the
227+ // explicit copy keeps the code straightforward and side-effect free (no aliasing that
228+ // could surprise future mutations) while cost is negligible relative to handler work.
229+ // * We intentionally do not randomize: fairness over time is achieved by round‑robin
230+ // style rotation (pubCounter % len) which ensures equal start positions statistically
231+ // without introducing randomness into delivery order for reproducibility.
232+ // If performance profiling later shows this allocation hot, a specialized in-place rotate
233+ // could be introduced guarded by benchmarks.
219234 if m .config .RotateSubscriberOrder && len (allMatchingSubs ) > 1 {
220235 pc := atomic .AddUint64 (& m .pubCounter , 1 ) - 1
221236 ln := len (allMatchingSubs ) // ln >= 2 here due to enclosing condition
0 commit comments