pub fn to_value_or_null<T: Serialize>(value: T) -> ValueExpand description
Serialise a T: Serialize into a serde_json::Value, folding the
(in-practice unreachable) serde_json::to_value error to
serde_json::Value::Null — the ONE substrate owner of the “serde-
serialise a caller-supplied T into a JSON slot value, falling back
to Value::Null on the residual Err arm the round-trip’s contract
permits but no in-workspace payload triggers” shape.
Pre-lift the SAME serde_json::to_value(<T>).unwrap_or(Value::Null)
chain was hand-authored at TWO consumer sites past the ★★
PRIME-DIRECTIVE ≥ 2 duplication threshold, each restating the same
three-link chain (to_value → unwrap_or → Value::Null fallback)
to seed a JSON slot value from a caller-supplied serde-serialisable
payload:
annotation_body— folds the caller’svalue: impl Serializeinto themetadata.annotations.<key>leaf on the single-annotation merge-body composer. Every downstream single-annotation writer (signals-strip,RELEASED_FROMstamp,return-triggerstamp) rides through this fold.tatara_reconciler::patch::phase_status_with— folds the caller’svalue: impl Serializeinto the caller-named third slot on the phase-transition status-patch composer. Every downstream extra-slot phase-transition writer (Running-entryfluxResourcesattach, Attested-entryattestationattach, and — via [crate::patch::phase_status]’sSomearm delegating through the composer — the Forking-entryidentityattach) rides through this fold. The reconciler-side callsite reaches THIS substrate primitive by fully-qualified name (tatara_process::patch::to_value_or_null).
Both sites walked the SAME three-link chain — serde_json::to_value
on the caller-supplied T, Result::unwrap_or on the residual
Err arm, serde_json::Value::Null as the fallback constant.
Differing only in the T slot’s downstream consumer (an
annotations.<key> leaf vs a phase_status_base sibling slot).
Post-lift each callsite reads to_value_or_null(v) and the
three-link chain lives at ONE substrate owner.
A future normalization of the fold discipline — a promotion of the
Value::Null fallback to a typed error return so a caller’s
Serialize impl that legitimately fails at runtime surfaces at the
composer rather than being silently dropped to null; a
canonicalization pass over the produced Value (a sort-map-keys
walk for deterministic byte output, a whitespace-strip for size);
a tracing::warn! span at the Err arm so the silent drop leaves
an operator-visible breadcrumb; a switch to serde_json::to_value’s
Cow-returning peer for zero-copy on already-Value inputs —
lands at THIS ONE substrate primitive and both downstream fold
consumers (plus every future JSON-slot-seeded-from-T: Serialize
writer that grows a third consumer) inherit the upgrade
mechanically. No per-site edit at annotation_body or at
phase_status_with; a new consumer (a hypothetical typed labels
composer, an annotations-batch composer, a per-slot status-patch
composer) picks up the sibling primitive by name and inherits the
same fold discipline.
Sibling to crate::three_pillar::pillar_bytes on the (T: Serialize → wire-shape) axis pair: pillar_bytes owns the
serde_json::to_vec(<T>).unwrap_or_default() fold for the
attestation-pillar bytes axis (returning Vec<u8> with a
Vec::default() empty fallback); this primitive owns the
serde_json::to_value(<T>).unwrap_or(Value::Null) fold for the
JSON-slot value axis (returning Value with a Value::Null
fallback). Both hold the invariant that a caller-supplied
serde-serialisable payload folds into a wire-form value at ONE
substrate owner rather than at each per-site hand-authored chain.
The T: Serialize bound accepts owned or borrowed values of any
serde-serialisable type without widening the signature — matches
annotation_body’s impl Serialize value slot verbatim and
matches phase_status_with’s T: Serialize extra slot verbatim.
A serialisation failure (the Err arm the serde_json::to_value
contract permits) resolves to serde_json::Value::Null, matching
the pre-lift discipline both callsites carried before this lift.
In practice the shapes each callsite passes (a Value::Null, a
String, a &'static str, an &Identity, a &Vec<FluxResourceRef>,
a &ProcessAttestation) never fail to serialise; the fallback is a
defensive guard against a future caller passing a T whose
Serialize impl signals a runtime error at that boundary.
Theory anchor: THEORY.md §VI.1 (generation over composition — the
3-link serde_json::to_value(<T>).unwrap_or(Value::Null) chain
recurred at 2 hand-authored sites past the ★★ PRIME-DIRECTIVE ≥ 2
duplication trigger inside two workspace crates, and is lifted onto
ONE substrate owner here). THEORY.md §II.1 invariant 5 (composition
preserves proofs — the pin block below binds the composer at
fail-before-pass-after granularity, so a regression that drifts the
serialiser choice, flips the fallback constant, reshapes the return
form, or narrows the T: Serialize bound surfaces HERE rather than
as silent JSON-slot-value skew across the two consumer sites).