The Drift Log · Model independence and repeatable builds
Seeding Randomness for Byte‑Identical Test Runs
7 November 2026 · 3 min read · 705 words · established

Eliminate flaky CI runs by replacing ambient system entropy and global PRNG state with hierarchical, per-test seed derivation.
A continuous integration pipeline fails on a merge commit. You rerun the job without changing a line of code, and it turns green. The build passes, the PR merges, and the test suite loses a fraction of its authority.
When tests fail intermittently because a fixture selected an unhandled edge case from an unseeded pseudo-random number generator (PRNG), engineers stop treating red builds as broken contracts. Flaky tests are rarely failures of logic; they are unrecorded inputs. If your test suite or build pipeline draws on ambient system entropy, you do not have reproducible builds. You have builds that happen to pass under particular, untracked conditions.
Eliminating this variance requires treating randomness as an explicit input parameter rather than a background service.
Where Entropy Enters the Test Suite
Ambient randomness enters test suites through three main entry points:
- Synthetic data generators: Libraries that generate fake names, emails, addresses, or payloads often initialise their own internal PRNG using system time or
/dev/urandomif not explicitly configured. - Identity generation: Calling standard UUID or token helpers (such as
crypto.randomUUID()or standard v4 generators) pulls directly from OS-level entropy. - Execution jitter and ordering: Shuffling test execution order to detect suite coupling relies on a PRNG. If the order generator does not log its starting state, a failed execution sequence cannot be reproduced.
When these generators run unconstrained, test runs diverge. A serializer test might pass for months until a random string generator produces an unescaped control character or a surrogate pair. If the seed that produced that character is lost, diagnosing the failure requires brute-force reproduction or guessing.
This is the same defect that occurs when software relies on external runtime models or unpinned execution environments: you introduce variance into what should be a static verification step. As discussed in our analysis of why model independence is an engineering posture, reliable verification requires systems that can be executed repeatedly from first principles without inheriting ambient state.
Why Global Seeding Fails
The standard attempt to fix this issue is global initialization:
## A common, but fragile, fix
import random
import numpy as np
def setup_test_suite():
random.seed(1337)
np.random.seed(1337)
This approach breaks under modern test runners.
First, modern runners execute tests across parallel worker processes or async event loops. If two concurrent tasks draw from the same global PRNG state, their sequence of draws depends entirely on thread scheduling and microtask execution order. This introduces the same race conditions discussed in eliminating clock-based flakiness in parallel tests.
Second, global seeding couples independent tests. If Test A runs before Test B, it consumes $N$ values from the stream. If an engineer runs Test B in isolation during local debugging, Test B receives the numbers Test A would have consumed, altering its test conditions.
Explicit Seed Derivation
The correct posture is hierarchical seed derivation. A single root seed is injected into the test run. From that root seed, child seeds are computed deterministically for each suite, file, and test case using a stable hash.
import { createHash } from "node:crypto";
class DeterministicPRNG {
private state: number;
constructor(seed: number) {
this.state = seed >>> 0;
}
// Linear congruential generator for deterministic 32-bit floats
next(): number {
this.state = (Math.imul(1664525, this.state) + 1013904223) >>> 0;
return this.state / 4294967296;
}
}
function deriveSeed(rootSeed: number, testIdentifier: string): number {
const hash = createHash("sha256")
.update(`${rootSeed}:${testIdentifier}`)
.digest();
return hash.readUInt32BE(0);
}
// Usage inside a test harness
const ROOT_SEED = Number(process.env.TEST_SEED) || 0xdeadbeef;
const testSeed = deriveSeed(ROOT_SEED, "users/create-user-preserves-unicode");
const rng = new DeterministicPRNG(testSeed);
const fixtureId = Math.floor(rng.next() * 1000000);
Under this pattern:
- Every test receives a dedicated PRNG instance.
- The order of test execution does not change the numbers drawn by any individual test.
- Running a single test locally with
TEST_SEED=12345executes the exact sequence that ran in CI. - Parallel processes can derive their local PRNGs without synchronisation locks.
If your artifact generation pipeline produces binary files, ensure that iteration over internal maps and sets is also pinned, as covered in pinning dictionary iteration order for byte-identical artifacts. Seeded randomness handles value variance; stable traversal handles structural variance.
What to Do on Monday
To bring seeded randomness into an existing codebase:
- Audit entropy sources in test code. Search your codebase for raw calls to
Math.random(),random.random(),crypto.randomUUID(), and unseeded fake-data generators. - Log the root seed on startup. Configure your CI runner to read an environment variable (for example,
SEED=${CI_PIPELINE_ID}) and printRUNNING WITH SEED: <value>at the top of the build log. If a test fails, that seed must allow an identical local reproduction of the failure. - Inject derived generators into fixtures. Ban global randomness in test helpers. Pass an explicit generator derived from the root seed and test path into each test context, and fail CI on any unseeded random call.
Keep reading
Next in the log
- Eliminating Clock-Based Flakiness in Parallel Tests
Eliminate flaky parallel tests and artificial sleep delays by replacing ambient system clock calls with an explicit virtual clock interface.
- Pinning Dictionary Iteration Order for Byte-Identical Artifacts
Runtime hash table randomization silently breaks reproducible builds. Here is how to pin serialization boundaries down to the byte in CI.
- Eliminating Network Socket Leaks in Parallel Test Execution
Eliminate parallel test flakes and EADDRINUSE errors by isolating TCP transports to in-memory streams, Unix domain sockets, and distinct loopback addresses.
The Strategic Master Library · written and reviewed under the house's own epistemic rules: nothing claimed that we cannot show.