Skip to content

No pre-decode validation seam for Rational -- setWire clamps hostile wire input instead of rejecting #131

Description

@Yaraslaut

Summary

No pre-decode validation seam exists for morph::math::RationalRational::setWire (the glaze wire-codec entry point) silently clamps hostile wire input to a plausible value instead of rejecting the decode. A wire payload like {"num":5,"den":0,"dp":2} decodes into a plausible 5/1 rather than failing, and every dispatch path decodes before any model-level validate() runs, so an application has no seam to catch a clamped value as clamped — it only ever sees an already-plausible Rational.

Evidence

include/morph/util/rational.hpp's codec: Rational::setWire rebuilds through the canonicalising constructor, which silently clamps den == 0 to 1 (among other clamps: out-of-range dp, INT64_MIN components whose negation would overflow) instead of asserting or rejecting.

Confirmed via a real test (examples/ledger/tests/test_ledger_model.cpp, rung 5 / ledger): decoding {"num":5,"den":0,"dp":2} through glz::read_json into a Rational succeeds silently, producing 5/1. A ledger-shaped application's own zero-sum business invariant happens to catch most clamped legs incidentally (a clamped value is unlikely to still sum to zero) — but that's coincidental protection from a business rule, not a validation guarantee the framework provides. An application with a less-convenient invariant (or none at all) would have no way to know the value it received was ever clamped.

Suggested direction

A pre-decode validation hook — reject rather than clamp by default, or at minimum a decode-time flag surfacing "this value was clamped" that a caller can check — would close the gap for any application whose own invariants don't happen to catch it incidentally.

Reference

Filed from LASTRADA-Software/morph, branch ladder-ledger-rung5 (not yet merged), as docs/findings/002-rational-no-predecode-validation-seam.md (see that file for the same summary in the ladder's own findings-pipeline format, examples/FINDINGS.md) and the "clamped Rational leg" test in examples/ledger/tests/test_ledger_model.cpp for the reproducing test.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: utilSubsystem: utilenhancementNew feature or requesttriage: rescopeReal problem, wrong framing; rewrite before building

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions