Lossless JSON-safe encoding for checkpoint payloads.
Graph state holds arbitrary Elixir terms — message structs, atoms,
tuples, and maps with non-string keys. Plain JSON encoding destroys
those shapes: structs come back as string-keyed maps and pattern
matching on restored state breaks. This serializer tags each rich
term so decode/1 rebuilds the exact original value.
Module names and struct field keys are resolved with
String.to_existing_atom/1 — they must already exist to rebuild the value,
which also bounds atom-table growth from those structural names. Value atoms
are the app's own checkpointed data: decode prefers an existing atom but
falls back to creating one, so a checkpoint round-trips in a fresh VM or
after a deploy where a stored atom is not loaded yet.
Encoding scheme
| Term | Encoded form |
|---|---|
nil/bool/num | as-is |
| UTF-8 binary | as-is |
| other binary | %{"~b" => base64} |
| atom | %{"~a" => "name"} |
| tuple | %{"~t" => [encoded...]} |
| struct | %{"~s" => "Elixir.Mod", "~f" => %{...}} |
| map | %{"~m" => [[encoded_key, encoded_value], ...]} |
| list | JSON array of encoded elements |