Skip to content

Console buildSections drops the field-level maxLength override while its own docstring promises overrides win — the input gets the object's ceiling, not the form's #5595

Description

@os-sales

Found while implementing #5542. Filed unassigned for PM triage — outside that card's
declared file surface (the type declaration and its pin, not the merge logic).

Mechanism

apps/console/src/components/FormPage.tsxbuildSections merges a FormView's field
overrides with the target object's field definitions. Its docstring states the rule, at
:340 on the merged ref cad512fe1:

 * Field-level FormField overrides take precedence over object defaults.

Every key in the loop is built that way — override.label ?? def.label,
override.required ?? def.required, override.readonly ?? false, and so on. One is
not, at :367:

maxLength: def.maxLength,

No override.maxLength ??. The object schema's ceiling wins unconditionally, and the
form's own is discarded.

It is load-bearing, not decorative — the value reaches the DOM twice, at :875 and
:983:

maxLength={field.maxLength}

So an author who sets a tighter per-form limit (a short public intake form over a field
whose object-level ceiling is generous) gets the generous one, silently. There is no
diagnostic, and the form still submits, so the symptom is a value the author believed
was refused at the input being accepted.

Why it survived

The console's local FormFieldSpec did not declare maxLength at all until #5542, so
nobody typing a spec in this app could write the override in the first place — the key
was unreachable from the type side, and the merge gap it exposes was therefore never
exercised. #5542 converged that type onto the shared app-shell declaration, which does
declare maxLength, so the key is now writable here and lands on the inert branch.

The behaviour is unchanged by #5542 in both directions: the runtime always ignored the
override, and it still does. What changed is that the gap is now expressible, which is
why it is worth recording rather than leaving as an accident of a too-narrow type.
FormPage.fieldSpec.test.ts (added by #5542) records the current answer explicitly
rather than assuming it:

expect(row.maxLength).toBeUndefined();

so whichever way triage rules, the existing pin says which behaviour is being changed.

The decision triage owns

Two coherent outcomes, and picking by "which is less work" would be wrong:

  • honour itmaxLength: override.maxLength ?? def.maxLength, matching the
    docstring and every sibling key. One line, and the docstring becomes true.
  • declare it object-only — if a per-form ceiling is deliberately not a thing (a
    storage constraint is not a presentation choice), then the docstring's blanket claim
    is what is wrong, and it should name the exception.

Related but distinct: #5201 and #5253 (both closed) recorded max_length ceilings
failing to reach the DOM in the built-in form branches. Same key, different renderer and
different mechanism — those were spelling/lookup failures, this one is a merge branch
that was never written.

Boundary

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpm:dispatched

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions