Skip to content

forms: a plain "number" member is submitted as a JSON string — fieldJsonLiteral has no branch for bare double/float #802

Description

@Yaraslaut

Found while fixing the readiness defect for nested aggregates, and deliberately
left out of that change to keep its blast radius at zero. Filed rather than
folded, because it is a different member shape with a different fix.

What

DynamicForm.qml's fieldJsonLiteral has no branch for a schema property
declared plain "number" — a bare double or float member with no
x-decimalPlaces and no Quantity wrapper. Such a member falls through to the
same JSON-string encoding that an object-typed member used to get, so the
submitted body carries "3.5" where the schema asks for 3.5.

The action then receives a string for a numeric field. Unlike the
nested-aggregate case this is not an exotic shape: double is an ordinary
member type, and an author has no reason to expect it needs a wrapper.

Why nothing has noticed

Measured on e3471f80:

  • No rung declares one. All eight (pastebin, polls, bookmarks,
    kanban, ledger, lims, crm, bank) have zero bare double/float
    members in their action headers — they use integers, Rational, or
    units::Quantity.
  • The schema side is exercised, the rendering side is not.
    tests/test_nested_forms.cpp declares such a member and calls schemaJson
    17 times, so a "number" property is generated and asserted on. It never
    constructs a DynamicForm (zero references), so the missing encoding branch
    is never reached.

So the gap sits exactly between a schema that is produced correctly and a
renderer that cannot encode it, with no test spanning the two.

Verification status

Inferred from reading the dispatch in fieldJsonLiteral, not reproduced.
No fixture drives a bare-number member through DynamicForm, which is the
same reason the defect has gone unseen. The supporting counts above are
measured (grep over the eight rungs' action headers, and over
tests/test_nested_forms.cpp).

Not verified: whether the resulting string is rejected at the action
boundary with a useful diagnostic, or silently coerced. That determines whether
this presents as a clear failure or as a wrong value, and it changes the
severity rather than the validity.

Not verified: whether x-decimalPlaces-tagged numbers, Rational, and
units::Quantity all have working branches — they were not the subject here.
Those three are the shapes the rungs actually use, so they are presumably fine,
but "presumably" is the word.

Relationship to the readiness fix

The nested-aggregate fix treats an unencodable member as unrepresentable,
which keeps the form unready and tells the caller why. That mechanism is
already in place and is the obvious home for this — but pointing it at
"number" would be wrong: a bare number is representable, it just needs an
encoding branch. The fix here is to add the branch, not to declare the member
unrenderable.

Getting that backwards would make every form with a double unready, which is
strictly worse than the current wrong encoding.

What would change the verdict

Close when a form whose schema carries a plain "number" member submits a JSON
number, proven by a case that fails against the current encoding.

Close as invalid if bare double/float members are deliberately
unsupported in action types — in which case schemaJson<A>() should
static_assert on them the way it already does for an enum with no
glz::meta, rather than generating a schema the renderer cannot honour.

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 workingtriage: validWell-framed; implement as written

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions