Turning a schema into a form, then validating output against it
A prose rulebook becomes executable when it is JSON Schema. How generated forms catch the field-level failures a pipeline otherwise inherits silently.
ES6 QA AI editorial · 10 November 2026 · 9 min read
Open the tool: Schema output validatorRules in a style document are not rules
The requirements for a feed record usually live in prose: SKU in this format, title under seventy characters, price above zero, no fields we did not ask for. Everybody agrees with them, nobody enforces them, and the model generating the records has never read them.
Written as JSON Schema, the same requirements become executable. A validator checks them mechanically, which means a violation is a fact rather than a matter of somebody remembering to look.
The second half of the idea is generating the form from the schema. Rather than a hand-built interface that drifts from the rules the moment either changes, the form is derived from the schema, so the two cannot disagree. A field that is not in the schema does not appear; a rule that is in the schema appears as an input constraint.
That matters for the review workflow too: a reviewer looking at a generated form is looking at the contract itself, not at somebody's interpretation of it.
What fits in a schema, and what fights it
Required fields, types, enumerations, string patterns and lengths, numeric ranges and array limits all validate cleanly and are worth declaring. additionalProperties false is the one to add by default, because it catches the field an LLM invents when it decides the output wants a subtitle nobody asked for.
Cross-field rules — end date after start date, discount below price — are expressible through oneOf, dependencies or conditional schemas, and they are where a schema starts to read like code. Keep those few and documented, or they become a second implementation nobody maintains.
Anything requiring judgement does not belong in a schema at all. Whether a description is on-brand, whether a title is accurate, whether a category is the right one for a product: those are review questions and encoding them as regexes produces confident nonsense.
The practical boundary is that a schema can check shape and constraints. The moment it tries to encode meaning, it stops being a contract and becomes a poorly documented guess about language.
- Good: types, required fields, enums, patterns, lengths, ranges.
- Good: additionalProperties false, to catch invented fields.
- Careful: cross-field and conditional rules — few and documented.
- Bad: brand voice, accuracy, category judgement.
Pasting an output to see where it breaks
The most useful thing the tool does is fill the generated form with a model's output. Errors then land on the field that caused them rather than arriving as a wall of text at the end of a pipeline, which changes the diagnosis from what is wrong with this payload to which field is wrong.
That is a small difference with a large effect on how long a fix takes. A message that names title.length as exceeding seventy characters is actionable in seconds; a rejected batch is a debugging session.
It also makes the failure legible to people who do not read JSON. A form with a red field is understood by an editor, a merchandiser or a client; a schema validation stack trace is not.
For a batch, spot-check a sample rather than every row. If three of twenty payloads fail on the same field, the model was not told the constraint, and that is a prompt problem rather than twenty data problems.
Better prompts come out of validation
Every validation failure is a sentence that was missing from the prompt. If the model returned a price as a string, the prompt never said the type; if it added a field, the prompt never forbade one. The validator does not just catch the payload, it shows you where the instruction was ambiguous.
That reframing is worth more than the check itself, because it moves the work upstream. A team that reads failures as prompt defects fixes one thing and stops seeing the error; a team that reads them as data defects writes another validation rule each time.
Show the model the schema rather than describing it. A JSON Schema pasted into the prompt communicates types, required fields and allowed values in the form the model is most likely to follow, and it eliminates most of the inference that produces invented shapes.
Then keep the failures you have seen as examples in the prompt. One line saying prices are integers in cents, for example 1999 not 19.99, prevents a class of error more reliably than any validator, because it removes the ambiguity rather than catching its consequence.
Versioning the contract
A schema without a version is a document that means different things in different months. When a field changes and a payload fails, the first question is whether the output moved or the contract did, and without a version you cannot tell.
Version the schema in the repository, date the change and describe it in one line: made sku required, narrowed price to integer. Three fields of metadata turn a mystery into a changelog entry.
Keep old versions rather than overwriting them, at least for the schemas that guard anything financial or contractual. The ability to validate an old payload against the contract that was in force when it was accepted is what makes a retrospective investigation possible.
And test the contract itself occasionally, with a payload that should fail. A schema that has quietly lost its required list will pass everything, and a validator that never fails is indistinguishable from one that is not running.
When the consumer is a spreadsheet
Plenty of schema-shaped data ends up in a spreadsheet, where types are suggestions. A payload that validates can still be mangled by the time a merchandiser sees it: long identifiers become scientific notation, leading zeros disappear, and a date becomes a number with no explanation.
If the data is going to a person rather than a program, validate against the contract and then check the export. The two checks catch different failures, and only the second one catches the case-sensitive SKU that the spreadsheet helpfully capitalised.
Write the destination into the rule: a spreadsheet wants identifiers stored as text and dates formatted explicitly, and saying so in the schema and the export settings prevents a class of error that no amount of validation upstream will catch.
The general lesson is that validity is relative to a consumer. The same payload is valid for an API and invalid for a person reading a grid, and knowing which one you are producing is part of the contract.
Errors that are better than silence
A rejected payload is a good outcome. The alternative is the same payload accepted, stored, and read by a template that formats a string as a currency, produces NaN on the page and looks like a design bug for a week.
Loud failures are cheaper than quiet ones, which is the argument for validating at the boundary rather than trusting a prompt. The prompt is an instruction; the validator is a test; only one of them can fail visibly.
Where a payload must be accepted, coerce narrowly and log. A date arriving as a string can be parsed, but the parse should be recorded so the prompt gets fixed rather than the coercion becoming permanent infrastructure.
And keep one valid payload and one invalid payload as fixtures. Two files are enough to prove the validation works after somebody refactors it, and refactors are when contracts quietly stop being enforced.
Where validation stops
A schema can insist a title is under seventy characters and a description longer than 120. It cannot tell you the title describes the wrong product or that the description is untrue. Structural validity is necessary and it is not the review.
It also cannot catch the output that is valid but wrong in aggregate: twenty records that each satisfy the schema and together describe the same product twice, or a catalogue whose categories are internally consistent and commercially useless.
Nor does it protect a downstream system from a schema that was itself wrong. A contract that permits a negative price will validate a negative price, cheerfully, and the validator will be blamed for it.
So the shape is checked mechanically and the content is checked by reading, in that order, because there is no point arguing about whether a description is accurate while the price is a string.
These rules are the same ones the console runs. Check a file against them now.