| Property | Value |
|---|---|
| Category | Reproducibility (JustDummies.Reproducibility) |
| Severity | 🔵 Info |
| Enabled by default | Yes |
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.UseSeedscope. - A draw from an isolated
Any.WithSeed(...)context, or a generator reached through a local rather than written inline fromAny. - A per-item scope opened in a helper the body calls — a one-hop miss the rule deliberately accepts rather than attempt interprocedural analysis.