Skip to content

forms: a bare math::Rational member is classified unrepresentable, so the form never reaches ready #804

Description

@Yaraslaut

Found while fixing the plain-"number" encoding gap, and deliberately not folded
into it: different member shape, different fix, and a worse symptom.

What

A bare morph::math::Rational member makes a generated form never reach
ready
. Its schema is an inline object of num / den / dp with no
x-decimalPlaces, so DynamicForm finds no typed control that claims it,
classifies it unrepresentable, and holds the form short of ready — with the
reason shown, so the user sees a form they cannot submit and no way to fix it.

That is a harder failure than the plain-"number" one it was found beside. A
wrong JSON type reaches the action boundary and is rejected there; an unready
form cannot be submitted at all.

It is already declared, in two rungs

examples/ledger/include/ledger/dto/budget_dto.hpp:45   SetBudgetLimit::limit
examples/ledger/include/ledger/dto/budget_dto.hpp:59   limit
examples/ledger/include/ledger/dto/budget_dto.hpp:60   spent
examples/crm/include/crm/dto/quote_dto.hpp:47          quantity

No shipped form is affected, and only by accident: ledger's QML is
hand-built with no MorphForms dependency, and crm has no GUI layer at all —
measured at zero QML and zero gui_lib lines. So the blast radius is zero
today for the same reason the plain-number gap's was: nobody has pointed the
generated renderer at these types yet.

It is encodable — this is a recognition rule, not a new encoder

x-decimalPlaces on the property hands it the exact-decimal control, and that
control's literal is precisely the num/den/dp shape the schema
describes. Measured in the new plain-number suite:

{"limit":{"num":350,"den":100,"dp":2}}

So nothing needs writing to encode a Rational; what is missing is the rule
that recognises the inline num/den/dp object as that control's input.

Verification status

The declarations are measured — grep over all eight rungs' action headers,
on 7a994c15. The schema shape and the working literal are measured, in the
suite added alongside the plain-number fix.

Not verified: that adding the recognition rule is sufficient rather than
merely necessary — nobody has driven a Rational-bearing action through a
generated form end to end, because no such form exists. That is the experiment
that would close this.

Not verified: whether Quantity-wrapped and x-decimalPlaces-tagged
numbers share enough of the path that one rule covers all three. The
plain-number work established that x-decimalPlaces and Quantity are one
shape rather than two — "type": ["object","null"] with ExtUnits — so a
third arm is plausible but unmeasured.

The trap, which is the mirror of the one next door

The plain-"number" gap must not be routed through the unrepresentable
path, because a bare number is representable and needs an encoder. This one is
the opposite: Rational is currently routed through the unrepresentable
path, correctly given what the renderer knows, and the fix is to teach it to
recognise the shape — not to add an encoder, and not to relax readiness.

Getting these two backwards in either direction produces a form that submits a
wrong payload while claiming to be ready, which is what both fixes exist to
prevent.

What would change the verdict

Close when an action declaring a bare morph::math::Rational renders a form
that reaches ready and submits {"num":…,"den":…,"dp":…}, proven by a case
that fails against today's renderer.

Close as invalid if bare Rational members are deliberately unsupported and
authors are meant to tag them — in which case schemaJson<A>() should say so at
compile time rather than emitting a schema the renderer classifies as
unrenderable, and the four declarations above need changing.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: formsSubsystem: formsarea: qtSubsystem: qtbugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions