Validates values before they cross a Continuum journal boundary.
ETF can encode node-local identities, but decoding them during replay does not make them meaningful on another process or node. This validator rejects those identities recursively and reports their exact location.
Summary
Types
@type path() :: [path_segment()]
@type path_segment() :: atom() | {:field, term()} | {:index, non_neg_integer()} | :tail
Functions
@spec decode(binary()) :: {:ok, term()} | {:error, Continuum.DurableTermError.t()}
Non-raising decode!/1.
Decode a term Continuum wrote across a journal boundary.
Decoding is :safe, so it refuses to create atoms from journal bytes. On a
cold node, Continuum loads the modules declared by the node's loaded OTP
applications and retries once; this makes atoms from deployed workflow,
activity, and runtime code available without trusting database text. A final
refusal means one of three things: the stored bytes are corrupt, they were
written by code this node does not have, or workflow code journaled a
dynamically constructed atom — which was never replay-durable, because the
atom does not exist on a node that has not run the same input.
Raises Continuum.DurableTermError rather than leaking ArgumentError from
:erlang.binary_to_term/2.
@spec validate(term(), atom()) :: :ok | {:error, Continuum.DurableTermError.t()}