Skip to content

SimpleObjectForm's inline-fields carve-out bypasses a declared submitHandler — measured onSuccess 1 / submitHandler 0 #6388

Description

@os-support-ai

Found while implementing #6300 (PR #6386), which fixed the equivalent hole in the five variant renderers. Out of scope there — this lands in ObjectForm.tsx, outside that card's five files, and it is #6176's defect class ("a declared submitHandler is not consulted") rather than #6300's ("a form with no persistence target reports success"). Filed unassigned and ungraded; routing and grading are triage's.

Dedup done before filing, with a control: a keyword pass (SimpleObjectForm, submitHandler, hasInlineFields, customFields, inline fields) over all 250 open issues in this repo, read from the REST list endpoint (/issues?state=open&per_page=100, pages 1-5 — GitHub search is 403 from this container seat, list is 200). Three hits, none of them this: #6300 (the card being implemented), #6152 (unrelated schema-mirror ledger), #6366 (unrelated spec-bridge field normalizer). So the zero is a real reading.

The defect

SimpleObjectForm.handleSubmit (packages/plugin-form/src/ObjectForm.tsx) opens with

// For inline fields without a dataSource, just call the success callbackif(hasInlineFields&&!dataSource){if(schema.onSuccess){awaitschema.onSuccess(formData);}returnformData;}

The carve-out is checked before the persistence chain, so a declared submitHandler is never reached. ObjectFormSchema.submitHandler is documented as "the form validates and hands the collected values to the host INSTEAD of calling dataSource.create / dataSource.update" — a seam that by construction needs no adapter of its own. A host that declared it owns the write gets a success signal for a write it was never asked to perform.

Measured

Driving formType: 'simple' through ObjectForm with customFields (inline), a submitHandler, and nodataSource:

fixtureonSuccesssubmitHandler
simple + customFields + submitHandler, no dataSource10
simple + customFields, no submitHandler, no dataSource (control — the legitimate inline collector)1n/a

Measured on 2e11c8c5b. The control is what shows the first row is about the seam being skipped, not about the carve-out firing at all.

Why it is worth a decision rather than a reflex fix

PR #6386 rules the opposite way for the five variant renderers, following #6300's triage direction: "when a submitHandler is declared, a missing dataSource must never bypass it." So as of that PR, simple and the other five disagree in exactly this cell:

simpletabbed / wizard / split / drawer / modal
inline fields + submitHandler + no dataSourceonSuccess(formData), seam skippedseam runs, then onSuccess(result)

One renderer family answering a declared seam two ways is the "N dialects" shape commandment #0.1 exists to prevent. The straightforward resolution is to move the carve-out after the submitHandler check in SimpleObjectForm, matching the five — mechanically small, and it is what the #6300 triage ruling already says for every renderer ObjectForm routes to. Recording it as an issue rather than doing it inside #6300's PR because it is a different card's surface and a different card's defect class.

Suggested surface

packages/plugin-form/src/ObjectForm.tsx, the hasInlineFields && !dataSource early return in SimpleObjectForm.handleSubmit. packages/plugin-form/src/submitTargetRefusal.test.tsx (added by PR #6386) is the natural home for the pin — its block 1 already asserts exactly this property for the other five.


Generated by Claude Code

Metadata

Metadata

Assignees

Labels

domain: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