DynamicForm.qml types every field from p.type, and reaches the array form
({"type":["integer","null"]}, which is what schemaJson emits for a rule-3
strong id under $defs) through Array.isArray:
const types = Array.isArray(p.type) ? p.type : (p.type === undefined ? [] : [p.type])
...
isInteger: types.indexOf("integer") !== -1,
jsonType: types.length > 0 ? types[0] : ""
Array.isArray is false for a QVariantList. So when schema reaches the form
as a QVariant rather than as a JS object — an initial property, a
setProperty from C++, createTemporaryObject(..., {schema: ...}) — every
array-valued type is wrapped instead of unpacked, isInteger comes out false,
and the field falls through to the plain-text encoding: the id is submitted as a
quoted JSON string, which the server rejects with parse_number_failure.
That is the same symptom morph#189 fixed for the anyOf shape, reappearing
through a different door.
Verification status: reproduced, and not a shipped-app defect
Measured at 1f7a4619, Qt 6.11.2, QT_QPA_PLATFORM=offscreen, via a scratch
tst_*.qml through morph_forms_qml_tests -input <dir>, using
schemaJson<kanban::AddComment>() verbatim.
Declarative binding — the shape every shipped app uses
(schema: page.schemas["AddComment"] || ({}), and schema: JSON.parse(...)):
BOUND: resolved.type=["integer","null"] Array.isArray(resolved.type)=true
BOUND FIELD taskId jsonType="integer" isInteger=true
BOUND ready=true previewLine={"taskId":7,"body":"hello"} <- number. correct.
INLINE: resolved.type=["integer","null"] Array.isArray(resolved.type)=true
INLINE FIELD taskId jsonType="integer" isInteger=true
INLINE ready=true previewLine={"taskId":7,"body":"hello"} <- number. correct.
Same schema, assigned as an initial property
(createTemporaryObject(formComponent, this, { schema: ... })):
AddComment FIELD taskId jsonType=["integer","null"] isInteger=false
AddComment ready: true
AddComment previewLine: {"taskId":"7","body":"hello"} <- quoted. wrong.
Note jsonType in the broken case: it is the whole ["integer","null"] array,
which is types[0] when types == [["integer","null"]] — i.e. the
Array.isArray branch was not taken.
So no shipped rung is currently affected, and I am filing this as a
robustness gap rather than a live bug: every app binds schema declaratively.
What is affected is anything that hands the form a schema imperatively, which
is the natural thing for a C++-driven test to do and the thing I did first when
writing one (examples/kanban/tests/test_gui_forms_render.cpp reached the
correct result only because the schema goes through QML bindings there).
Not verified: whether x-rules, x-layout or any other array-valued schema
key degrades the same way under the same conversion. Very likely — the same
Array.isArray idiom appears at :186 (anyOf/oneOf branches), :249-252
(required), :411-431 (x-layout groups) — but I only measured type.
Why it is worth fixing rather than documenting
The failure is silent and type-shaped: no warning, no error, a ready form, and
a body the server refuses. A one-line helper (function asArray(v) { return Array.isArray(v) ? v : (v && typeof v.length === 'number' && typeof v !== 'string' ? Array.prototype.slice.call(v) : ...) }) or an explicit
JSON.parse(JSON.stringify(schema)) normalisation at the schema property
would remove a whole class of "works in the app, mistyped in the harness"
confusion.
What would change the verdict
Close when a DynamicForm given the same schema as a QVariantMap and as a JS
object produces identical fields and identical previewLine, asserted by a
test in src/qt/forms/tests/. Re-open if a later refactor reintroduces a bare
Array.isArray on schema data.
DynamicForm.qmltypes every field fromp.type, and reaches the array form(
{"type":["integer","null"]}, which is whatschemaJsonemits for a rule-3strong id under
$defs) throughArray.isArray:Array.isArrayis false for aQVariantList. So whenschemareaches the formas a
QVariantrather than as a JS object — an initial property, asetPropertyfrom C++,createTemporaryObject(..., {schema: ...})— everyarray-valued
typeis wrapped instead of unpacked,isIntegercomes out false,and the field falls through to the plain-text encoding: the id is submitted as a
quoted JSON string, which the server rejects with
parse_number_failure.That is the same symptom morph#189 fixed for the
anyOfshape, reappearingthrough a different door.
Verification status: reproduced, and not a shipped-app defect
Measured at
1f7a4619, Qt 6.11.2,QT_QPA_PLATFORM=offscreen, via a scratchtst_*.qmlthroughmorph_forms_qml_tests -input <dir>, usingschemaJson<kanban::AddComment>()verbatim.Declarative binding — the shape every shipped app uses
(
schema: page.schemas["AddComment"] || ({}), andschema: JSON.parse(...)):Same schema, assigned as an initial property
(
createTemporaryObject(formComponent, this, { schema: ... })):Note
jsonTypein the broken case: it is the whole["integer","null"]array,which is
types[0]whentypes == [["integer","null"]]— i.e. theArray.isArraybranch was not taken.So no shipped rung is currently affected, and I am filing this as a
robustness gap rather than a live bug: every app binds
schemadeclaratively.What is affected is anything that hands the form a schema imperatively, which
is the natural thing for a C++-driven test to do and the thing I did first when
writing one (
examples/kanban/tests/test_gui_forms_render.cppreached thecorrect result only because the schema goes through QML bindings there).
Not verified: whether
x-rules,x-layoutor any other array-valued schemakey degrades the same way under the same conversion. Very likely — the same
Array.isArrayidiom appears at:186(anyOf/oneOfbranches),:249-252(
required),:411-431(x-layoutgroups) — but I only measuredtype.Why it is worth fixing rather than documenting
The failure is silent and type-shaped: no warning, no error, a
readyform, anda body the server refuses. A one-line helper (
function asArray(v) { return Array.isArray(v) ? v : (v && typeof v.length === 'number' && typeof v !== 'string' ? Array.prototype.slice.call(v) : ...) }) or an explicitJSON.parse(JSON.stringify(schema))normalisation at theschemapropertywould remove a whole class of "works in the app, mistyped in the harness"
confusion.
What would change the verdict
Close when a
DynamicFormgiven the same schema as aQVariantMapand as a JSobject produces identical
fieldsand identicalpreviewLine, asserted by atest in
src/qt/forms/tests/. Re-open if a later refactor reintroduces a bareArray.isArrayon schema data.