Krikri::DifferentialFuzz::Runner
Runs the SAME generated expression through both evaluators and compares them at the JSON-compact string level:
- hand-rolled side:
ExpressionEvaluator#evaluate(the entry pointVarSubstitutor#substituteuses for a plain{{ }}span; lenient, "undefined" sentinel). - krikri-jinja side:
JinjaRenderer#evaluate_value!(the delegation target, raw structured JSON::Any) rendered through the SAMEVariableLookup#format_valueconvention the hand-rolled side uses for its own structured results, so container/bool/float spellings are compared under one convention instead of flooding on format.
Agreement: identical strings, OR both sides parse as numbers and are numerically equal (int-vs-float spellings like "3" vs "3.0" are formatting, not semantics). Both sides raising on the same input is agreement on invalid input. One side raising while the other returns a value, or differing values, is a disagreement - either a real bug or a documented deliberate limit, for the caller to classify.
Constants
Jinja error messages meaning "a FILTER received an operand/value of
the wrong type" - the FilterEngine's per-filter argument leniency
(| sum on strings, | list on a scalar, | abs on a string,
| length on a bool, | first on an empty sequence, ...), which
the hand-rolled side answers leniently. Deliberately out of scope
for the strictness fixes (per-filter argument validation is its own
project).
Constructors
Class methods
Whether expr is a nested/compound shape rather than a bare
comparison: ternary conditions, and/or value selectors, is
tests, not-prefixed conditions, or filter-piped operands. Those
route through fallback evaluators (ConditionalEvaluator, the
heuristic not (...)/lookup fallbacks) whose comparison handling
is still class-lenient.
Instance methods
When false, triaged known differences are reported as findings too (the unfiltered strict view).
When false, triaged known differences are reported as findings too (the unfiltered strict view).