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.
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'sfieldJsonLiteralhas no branch for a schema propertydeclared plain
"number"— a baredoubleorfloatmember with nox-decimalPlacesand noQuantitywrapper. Such a member falls through to thesame JSON-string encoding that an object-typed member used to get, so the
submitted body carries
"3.5"where the schema asks for3.5.The action then receives a string for a numeric field. Unlike the
nested-aggregate case this is not an exotic shape:
doubleis an ordinarymember type, and an author has no reason to expect it needs a wrapper.
Why nothing has noticed
Measured on
e3471f80:pastebin,polls,bookmarks,kanban,ledger,lims,crm,bank) have zero baredouble/floatmembers in their action headers — they use integers,
Rational, orunits::Quantity.tests/test_nested_forms.cppdeclares such a member and callsschemaJson17 times, so a
"number"property is generated and asserted on. It neverconstructs a
DynamicForm(zero references), so the missing encoding branchis 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-
numbermember throughDynamicForm, which is thesame 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, andunits::Quantityall 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 anencoding branch. The fix here is to add the branch, not to declare the member
unrenderable.
Getting that backwards would make every form with a
doubleunready, which isstrictly worse than the current wrong encoding.
What would change the verdict
Close when a form whose schema carries a plain
"number"member submits a JSONnumber, proven by a case that fails against the current encoding.
Close as
invalidif baredouble/floatmembers are deliberatelyunsupported in action types — in which case
schemaJson<A>()shouldstatic_asserton them the way it already does for an enum with noglz::meta, rather than generating a schema the renderer cannot honour.