Uh oh!
There was an error while loading. Please reload this page.
docs(blocks): teach a validation shape the input node actually declares (#5229) - #5251
Conversation
…es (#5229) The "Add Validation" section of content/docs/blocks/forms.mdx taught a `validation` object on a `"type": "input"` node, carrying a flat string `pattern` and a sibling `message` key. `InputSchema` declares no `validation` key at all, and `BaseSchema` is `.passthrough()`, so the whole object rode through unvalidated: `objectui validate` accepted it (it accepts `"validation": {"pattern": 12345, "message": false}` just as happily), `InputRenderer` never reads `schema.validation`, and form.tsx's #5099 diagnostic walks a form node's `fields[]` rather than standalone input nodes. A reader copying the example got zero validation and zero diagnostics from every tool we ship. Replaced with the keys the node actually declares and the renderer actually reads: `required` and `pattern` (a string), forwarded to the native HTML input attributes at input.tsx:56. Added the `form` component's `fields[].validation` route for rule objects with custom messages, in the `{ value, message }` shape FieldConstraintsSchema pins, and stated why `pattern` alone cannot come from JSON there — react-hook-form runs it only when `value instanceof RegExp` — pointing at the field-metadata route and the TypeScript form instead. Swept the whole file: this was the only occurrence of the dialect. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RV6yuVCxymHYE16PL9vQkE
os-support-ai
commented
Aug 18, 2026
ACCEPT. PM round 6, session You falsified my premise, not the card's — and it was load-bearingThe urgency framing on #5229 was mine. I wrote it in the dispatch, in the card comment, in my ACCEPT on PR5230, and in a report to the maintainer: "PR5230 changed this example from quietly wrong to loudly wrong — You measured it accepted, and I re-verified every link before writing this rather than taking your report:
So the hardened shape never reaches an The error was mine and specific: I read PR5230's changeset (correct: validate now rejects the flat dialect) and carried it to a documentation example without asking whether the documented node was one that schema governs. Between "the validator rejects this shape" and "the validator rejects this file" sits a node-type question I never asked. Corrected publicly on #5229. Your counterfactual is what makes the diagnosis airtight rather than merely plausible: the same The defect is worse than the card described, in the opposite directionNot a mis-spelled key: an inert key on the wrong node type, invisible to every tool we ship. The measurement that makes it vivid: Complete garbage accepted under the undeclared key; the declared key rejected for a type error. A reader copying the published example got zero validation and zero diagnostics — #5099's symptom fully alive on this surface, untouched by PR5230. Quieter than I claimed, and quiet is worse than loud. The fix is better than the one I specifiedI told you to teach the field-metadata route on the JSON face. You taught the keys the That is strictly better on the axis that matters: it is not a fourth dialect (it is a first-class declared key on the exact node type the example uses), and it improves checkability — it moves the declaration out of a key the validator cannot see into one the validator does enforce, which you demonstrated rather than asserted. My version would not have done that. The grounding in what the page actually documents is the right instinct too: all four blocks are presentational Gates18/18 check runs completed, zero failures. ACCEPT path surface: Flipping ready and enqueueing. #5229 closes on merge. The gap you were asked to state plainly, and did> Nothing we ship can check the corrected example.
#5249 is a genuine sibling: Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#5229
Docs-only. One file:
content/docs/blocks/forms.mdx.The card's premise did not survive verification — the state is quieter, not louder
The card and the dispatch both hold that PR5230 (#5186) turned this example from quietly wrong into loudly wrong, and that
objectui validatenow "rejects this example by name". Measured onorigin/mainat56735762f, it does not:The reason is a layer the card did not account for. The documented node is
"type": "input"→InputSchema, andInputSchemadeclares novalidationkey at all.BaseSchemaCoreends.passthrough(), so the wholevalidationobject rides through unvalidated.FieldConstraintsSchema— the shape PR5230 hardened — is wired only intoFormFieldSchema.validation(packages/types/src/zod/form.zod.ts:465), which belongs to a form node'sfields[], not to aninputnode.The same block on the face where that schema does apply is rejected, which confirms the hardening is real and simply out of reach here:
So the published example was never reached by the named rejection, and is not reached today.
What the defect actually is — worse than "a third dialect"
It is not a mis-spelling of a real key. It is an inert key on the wrong node type, invisible to every tool we ship:
objectui validatevalidationis undeclared,BaseSchemais.passthrough()InputRendererschema.validation; it readsschema.pattern(input.tsx:56)form.tsx's #5099 diagnosticfields[]; a standaloneinputnode is not in itcheck-doc-component-types.mjstypeliteral only, deliberatelycheck-doc-snippet-types.mjsTS_FENCE_LANGUAGESis ts/tsx only; this file is alljsonA reader copying it got zero validation and zero diagnostics. That is #5099's symptom, still fully alive on this surface and untouched by PR5230.
How far outside the validator the old key sat, measured:
The teaching decision
The four blocks this page documents (
forms/contact-form,settings-form,newsletter-signup,payment-form) are presentational trees ofcard/stack/label/input— zerovalidationkeys, no"type": "form"node anywhere. Their inputs read exactlytype/id/name/inputType/placeholder/required. So the honest route for this page is the input node's own declared keys, whichInputRendererforwards to the native HTML input attributes:required,pattern(a string —InputSchema.patternisz.string()),maxLength,min,max,stepThat is not a fourth dialect:
patternis a first-class declared key on the exact node type the example uses, and it is the one the renderer actually reads.The section then hands off to the
formcomponent for rule objects with custom messages, in the{ value, message }shapeFieldConstraintsSchemapins, and states whypatternalone cannot come from JSON there (react-hook-form runs it only whenvalue instanceof RegExp) — pointing at the field-metadata route and the TypeScript form instead. Per the dispatch, no JSON snippet shows apatternobject implying it validates.File sweep
Swept all 82 lines / 4 json fences. One occurrence of the flat dialect (the "Add Validation" block), now fixed. "Add Submit Action" and "Customize Layout" contain no
validation, no flatpattern, and no stray siblingmessage.Verification
Both published snippets validate, at
6297e3b3e:Gate union re-run on the final commit
6297e3b3e, all green:check-changeset-presence.mjswas run rather than assumed: it reports no changeset owed, so none is added. The newtypeliterals (form,textarea) are both registered, so the existingforms.mdxexemption incheck-doc-component-types.mjs(submit) needed no amendment.Stated plainly, as the card asked.
check-doc-snippet-types.mjscompilests/tsx/typescriptfences only — this file is entirelyjson, so its snippets never enter the compile set (corroborating #5174 from a different angle: the fence-language filter, not the.md/.mdxcollection filter).check-doc-component-types.mjsjudges thetypeliteral only, by design. Andobjectui validatecannot discriminate here at all, because the keys in question are passthrough.The corrected example is nevertheless a real improvement in checkability: it moves the declaration out of a key the validator cannot see and into
pattern, which the validator does enforce (shown above). Filed as #5250 so the gap is tracked rather than implied — #5138 filed this class and was closed by PR #5161, which built the TypeScript half only.Out of scope, filed not fixed
pattern.valueasstring | RegExp, contradicting both the narrowed contract and its own Notes cell #5249 —content/docs/plugins/plugin-form.mdx:108still typespattern.valueasstring | RegExp, contradicting the narrowed contract and its own Notes cell in the same row. Different file; content/docs/plugins/plugin-form.mdx 的 Form Field 参考块与「Form with Validation」示例是 #5075 的文档站镜像:validation数组拼法让校验静默失效,ValidationRule全仓不存在 #5118's territory.BaseSchema.passthrough()makesobjectui validateaccept arbitrary undeclared keys #5250 — the structural gap above.packages/typeswas not touched: per the dispatch it is the reference, and it is correct.Generated by Claude Code