Test-build Fief.Seam: real unless hooked (implementation.md §5, §10).
Each function consults Fief.Sim for a per-process binding and falls through
to Fief.Seam.Real when nothing is bound, so test-compiled beams on real
distributed nodes behave exactly like prod.
Time
If the calling process has a simulation clock bound (Fief.Sim.bind_clock/1),
reads and timers go through it; otherwise everything delegates to
Fief.Seam.Real.
Two bound shapes are supported: a Fief.Sim.ManualClock server reference
(a pid or local name — the clock-only hook), or a {module, handle}
provider — the shape Fief.Sim.Scheduler.clock/3 returns — where module
implements ManualClock's call contract with the server reference
generalized to handle: monotonic_time/1, send_after/4,
cancel_timer/2.
Randomness
seed/1 binds a deterministic PRNG state to the calling process; subsequent
draws in that process are reproducible. Unhooked processes fall through to
Fief.Seam.Real.
Transport
A process bound to a scheduler context (Fief.Sim.bind/1 with a
Fief.Sim.Scheduler.context/3 map) gets the simulated transport; anything
else falls through to Fief.Seam.Real.
Simulated names
Under simulation one BEAM impersonates a cluster, so registered vnode names
must be unique per simulated node: vnode_name/2 qualifies with the
binder's node identity — sim_vnode_name/3,
:"fief_sim<sim_id>_vnode_<v>::<node_id>". Two deliberate departures from
the real scheme, both test-substrate decisions:
- The scheduler's unique
sim_idreplaces the instance atom as the namespace scope. Simulated same-namespace instances necessarily use distinct instance atoms in one BEAM (every other registered name in the instance tree derives from the atom — the M3 multi-instance substrate), so the atom cannot identify the shared namespace; the simulation they joined can. One namespace per scheduler is assumed. - The
sim_idalso keeps concurrently-running tests (each with its own scheduler) from racing for the same atoms.
Simulated sends
send/3 addressed to simulated node n re-qualifies the name for n
(the sender minted it qualified by its own identity), resolves the
destination pid, and posts the delivery into the scheduler's queue as a
pending event — labelled {:transport, node, kind} — for the test to
step/3 or drop/2: this is where peer-link faults (delay via ordering,
drop, partition) are injected. An unregistered destination is silently
dropped (:ok), exactly like a dist send to an unregistered name.
Checkpoints
emit/2 is the test-build target for Fief.Seam.checkpoint/2. It sends
{:fief_checkpoint, tag, meta, self()} to the calling process's bound tracer
(Fief.Sim.bind_tracer/1); silently no-ops when unhooked.
Emission is a plain async send: the harness owns ordering. A scheduler waiting for quiescence blocks on the checkpoint message that its last delivery must produce, so no synchronous ack is needed.
Summary
Functions
Bind a deterministic PRNG to the calling process.
The simulated planner-channel name at simulated node node_id (same
::-qualification scheme as sim_vnode_name/3, so send/3 re-qualifies it
by destination like any other name).
The simulated registered name for vnode_id at simulated node node_id
within the scheduler identified by sim_id (see Fief.Sim.Scheduler.context/3).
Node identities must be atoms under simulation.
Functions
@spec seed(integer()) :: :ok
Bind a deterministic PRNG to the calling process.
The simulated planner-channel name at simulated node node_id (same
::-qualification scheme as sim_vnode_name/3, so send/3 re-qualifies it
by destination like any other name).
@spec sim_vnode_name(term(), non_neg_integer(), term()) :: atom()
The simulated registered name for vnode_id at simulated node node_id
within the scheduler identified by sim_id (see Fief.Sim.Scheduler.context/3).
Node identities must be atoms under simulation.