Two specifications CONTRACT-01 owes the slices that cannot be built without them. seed-derivation-v1: the versioned derivation of independent per-agent seeds from a recorded master seed and stable agent ids, the exact hashed material, the lane rule that keeps a seed away from zero (the pinned kernel RNG is an xorshift, whose state must not be zero), the properties a composition may rely on, and the test vectors both languages reproduce. checkpoint-envelope-v1: the exact byte layout of the new envelope per state-media-v1 section 4, with the header, canonical-JSON manifest, 112-byte payload table entries, eight-byte aligned payloads and the digest footer; the manifest field set; what a reader enforces and in what order; and the durable commit sequence of section 6, whose commit point is the store manifest rename. FLYSIM01 is unchanged, refused at the magic, and stays separately readable. Both are specifications with fixtures, not the store: generations, rotation, the capture queue and the restore flow remain STATE-01.
5.2 KiB
Seed derivation v1
Status: draft 1, 2026-09-22. Specified by CONTRACT-01 of the
implementation guide, required by
worker interfaces section 2 before the real-agent slice. Reference
implementations: services/flysim/crates/fly-session-types/src/seed.rs and
packages/session-types/src/seed.ts; test vectors:
services/flysim/crates/fly-session-types/fixtures/seed-vectors.json.
1. What this is for
Agent.Initialize takes seed, a signed 32-bit integer, matching the current RNG input.
Workers-v1 section 2 requires that the coordinator derive independent per-agent seeds from
its recorded master seed and stable agent IDs under a versioned algorithm, and that the
algorithm be specified and tested before the real agent slice. This is that algorithm.
It is a reproducibility rule, not a secret: a run manifest records the master seed in the clear, and anyone with the manifest can recompute every agent's seed. It is not a key derivation function and must not be used as one.
seed-derivation-v1 is part of composition identity. Changing any byte of it requires a new
identifier (seed-derivation-v2), because two runs that agree on every other identity but
disagree here are not the same experiment.
2. Inputs
| Input | Type | Source |
|---|---|---|
masterSeed |
U64 decimal string |
Recorded once per run by the application/supervisor |
agentId |
Id |
The configured agent identity, stable across restarts and epochs |
Both are the ipc-v1 section 2 scalars. An agentId that is not an Id is an error, not
something to normalize. The master seed is the whole 64-bit range: a 32-bit master seed would
be no wider than the seed it derives.
3. Derivation
material = "flybrain/seed-derivation-v1" LF masterSeed LF agentId LF
digest = SHA-256(material)
lanes = digest read as eight big-endian uint32 values, in order
seed = the first nonzero lane, reinterpreted as a two's-complement int32
LF is one 0x0a byte. masterSeed is its canonical decimal form: "0", or no leading
zero. The prefix is a domain separator, so a digest from this algorithm can never collide with
one taken over some other pair of strings.
Zero lanes are skipped because the pinned kernel's RNG is an xorshift generator, whose state
must not be zero: a derivation that could hand out 0 would silently produce a stalled
generator. If every one of the eight lanes were zero, the material is rehashed with a counter
suffix (material || "1" LF, then "2" LF, then "3" LF) and the search repeats; no input
has ever needed it, and four rounds exhausted is an error rather than a fallback seed.
The seed is the negative number when the lane's high bit is set. That is deliberate: the existing RNG input is a signed 32-bit integer, and half the range is negative.
4. Properties
- Deterministic. The seed is a function of the two recorded inputs and nothing else: not of wall time, agent order, port assignment, worker process or thread count.
- Independent per agent. Distinct agent IDs give unrelated seeds; there is no arithmetic
relationship between
fly-aandfly-bfor a caller to exploit or accidentally rely on. - Stable across recovery. Restore, episode reset and a new epoch do not re-derive a different seed for the same agent ID under the same master seed. The seed is persisted as run configuration and state, and the capture compatibility digest covers the resolved seed (workers-v1 section 2), so a checkpoint cannot be installed into a differently seeded instance.
- Equal IDs give equal seeds. That is the only way to get identical seeds, and workers-v1 allows identical seeds only when an experiment declares them. A composition therefore refuses a repeated agent ID rather than quietly sharing a seed between two agents.
Non-properties, stated so nobody assumes them: this is not uniform over the int32 range beyond what SHA-256 gives, it is not a stream (one seed per agent per run, not per step), and it says nothing about how a model consumes its seed.
5. Test vectors
fixtures/seed-vectors.json carries the full table: five master seeds (0, 1, 42, 2^63
and the U64 maximum) across four agent IDs, each with the exact material string, its SHA-256
and the derived seed, plus one four-agent composition and the inputs that must be refused.
Both implementations reproduce every row, and each records the material as well as the seed so
a third implementation can find where it diverges.
The first two rows:
| masterSeed | agentId | material | seed |
|---|---|---|---|
0 |
fly-a |
flybrain/seed-derivation-v1\n0\nfly-a\n |
1828176714 |
0 |
fly-b |
flybrain/seed-derivation-v1\n0\nfly-b\n |
1218785088 |
Refused: an agent ID that is not an Id (uppercase, empty, over 64 characters), a master seed
that is not a canonical U64, and a composition with a repeated agent ID.
6. Out of scope
Choosing the master seed, recording it in the run manifest, and the hand-selected explicit seeds that workers-v1 allows for the first synthetic composition. This document defines only the derivation. A profile that needs several independent streams inside one agent derives them from the agent's own seed under its own documented rule; that is a profile concern, not a session one.