The sanctioned Fief.Vnode implementation (implementation.md §7): a plain
key→pid map with monitors in the impl state (Decision: no Registry —
every lookup already happens in the agent, so concurrent-read machinery
buys nothing), key servers under a linked DynamicSupervisor started from
init/2 (on_fence: :terminate) or the instance's Fief.Key.Limbo
(weaker modes — see Fief.Key), and the M5 migration machines embedded
per their moduledoc obligations. Built purely on the public behaviour —
the proof the contract is sufficient.
Migration embedding (build-order M5 obligations → here)
handoff_out→ two-phase freeze (docs/key-redesign.md§4.2): every live key server gets the freeze advisory ({:fief_key_freeze, deadline_ms}, an EEP 76 priority message via the key's alias, normal-send fallback) then:fief_key_extract(parallel across servers — the agent is not the bottleneck); completions come back through the impl-message channel (handle_info/2, the M6 contract change). One per-freeze deadline timer (extract_deadlineopt) backstops a key that never drains: at expiry every still-pending key is killed and converges through the died-before-extract path. Decision: the Donor machine is created when the ledger is complete; peer messages arriving mid-freeze are buffered and replayed into the machine in arrival order (a pull cannot be answered before the key's extraction settles anyway). A:frozencheckpoint marks completion.handoff_in(session)→Recipient.new/1;handoff_in(nil)afterhandoff_out→Donor.regained/1(the taint rule); an observed settle/abort while serving (the agent's reconcile rebind,handoff_in(nil)) →Recipient.session_over/1.handle_peer→ the five delivery events; key liveness is the key→pid map, consulted honestly — live keys are messaged directly and never reach the machine;first_touchruns only for non-live keys;live?for grant/push/not-here isMap.has_key?(keys, key_id).- The two tick cadences are seam timers armed in the agent
(
:fief_key_sweep/:fief_key_pull_retry, matched by ref — the impl-level stale-timer catch-all), interpreted throughDonor.tick/1/Recipient.tick/1. Effects are interpreted in list order.
Decisions recorded here
- Cold-start origin (
init/3,docs/key-redesign.md§2.3, §4.1): every incarnation runs the oneinit(key, source, ctx)callback; this impl choosessourceandctx.origin.{:escheat, key}effects and taint memory (escheat_next:Donor.regained/1's shipped set, surviving the machine) start keys{:fresh, :escheat}; a cold start with no machine and no memory is{:fresh, :first_touch}. A fresh owner after donor death cannot distinguish "existed elsewhere before" from "never existed" —:freshis the locate-durable-truth path (design §8: "Start/locate is transparent"); the:escheatorigin is the informational signal that the protocol knows recovery is happening. - Residual arrival vs resume:
{:inject, key, blob}(grant/push arrival) starts{{:residual, blob}, :transfer};{:resume, key, blob}and a late mid-freeze extraction start{{:residual, blob}, :resume}. Either way the blob is exactly anextract_state/1product handed back toinit/3. - Blob cap enforced at freeze (ledger assembly), the earliest
donor-side ship gate — see
Fief.Transfer.Channel. The ledger only ever holds shippable (already-ship/2-ed) blobs;fetch/2runs before a{:residual, blob}init/3and before a resume. - Sweep pacing is
sweep_ratekeys persweep_intervalms (two opts composed with the seam-timer cadence, in place of §9's{100, :per_second}sketch);pull_retry_intervalis the recipient cadence. Timers are armed lazily and cancelled when idle.
Impl opts (vnode_impl: {Fief.Key.VnodeImpl, ...}): hasher
(Fief.Hasher.Default, a Fief.Hasher module — the fingerprinted key→vnode
seam), sweep_rate (100),
sweep_interval (1_000 ms), pull_retry_interval (1_000 ms),
extract_deadline (5_000 ms — the per-freeze extract backstop, per-node
tuning like the sweep/pull cadences, not fingerprinted),
max_pending_per_key (128), max_blob_size (65_536),
channel (Fief.Transfer.Channel.InBand).