JustDummies

Just dummies — but seriously powerful ones.

Documentation sections

JD022: ParallelDrawWithoutPerItemSeed

PropertyValue
CategoryReproducibility (JustDummies.Reproducibility)
Severity🔵 Info
Enabled by defaultYes

The ambient seed scope flows with the execution context, so a scope opened around a parallel loop reaches every worker — and their draws interleave. Neither the sequence nor the multiset is stable across runs, so the run replays nothing even though a seed was pinned.

This is the shape the library’s own documentation names, and the fix it prescribes: a scope opened inside the loop body gives each unit of work its own sequence, and the whole run replays.

Noncompliant

Parallel.For(0, 64, index => {
    sut.Handle(Any.String().NonEmpty().Generate());   // JD022: one shared sequence, interleaved
});

Compliant

const int runSeed = 20240501;   // recorded by hand: keep it to replay, change it to explore

Parallel.For(0, 64, index => {
    // a distinct, deterministic sub-seed per work item, floor-safe on netstandard2.0
    using (Any.UseSeed(unchecked(runSeed * 397 ^ index))) {
        sut.Handle(Any.String().NonEmpty().Generate());
    }
});

No code fix

The repair needs a run seed the developer must choose and record, plus a per-item derivation from the loop variable. An analyzer cannot invent a seed someone intends to keep — generating one would produce exactly the committed-replay-seed problem JD019 describes.

What it does not flag

  • A body that already opens an Any.UseSeed scope.
  • A draw from an isolated Any.WithSeed(...) context, or a generator reached through a local rather than written inline from Any.
  • A per-item scope opened in a helper the body calls — a one-hop miss the rule deliberately accepts rather than attempt interprocedural analysis.

Read the source, or correct it there opens in a new tab· Mirrored from lib-v1.0.0-preview.6