pub fn operator_variant_label(
steps: &[PipelineDslStep],
) -> Result<String, DagMlError>Expand description
Compute a choice’s variant_label: the cross-language content fingerprint (hex sha256) of a
LOWERED operator sub-sequence (Phase 5).
CANONICAL FORM (a strict cross-language CONTRACT — the nirs4all host recomputes the SAME bytes
to map a per-variant report back to its operator-choice config): the sub-sequence is rendered as
a JSON array of steps in step order, each step the object
{"kind": <step-kind str>, "class": <operator FQN str>, "params": {<sorted JSON-safe params>}}.
Object keys are sorted everywhere (the value is built from a serde_json::Map, which is
BTreeMap-backed in this build, and params are carried in a BTreeMap); numbers are finite-only
(no NaN/Inf — rejected defensively, though JSON-sourced params can never carry them); a bool is
NOT a number; and the param value forms are preserved exactly as the DSL carries them (1 is not
coerced to 1.0). variant_label is the hex sha256 of serde_json::to_vec over that canonical
array — the SAME sha256(serde_json::to_vec(..)) primitive
stable_json_fingerprint uses, applied to the
explicitly-built canonical value (never a struct’s field order).
class is the step’s operator FQN as a string: a bare-string operator ("SNV") renders to
itself; an object operator ({"class": "sklearn...", ...}) renders to its compact canonical JSON
text (sorted keys, no whitespace), so any operator shape yields a deterministic string both sides
reproduce identically. Structural steps that carry no operator (merge, sequential, branch,
generator, concat_transform) render class as the empty string and params as {}; a
merge_model step carries its operator like a model step.