feat: carry the document's declared constraints into the derivation - #91
Merged
Conversation
A document states more about a property than the derivation could see. format reached only the audit's value synthesis, and writeOnly, deprecated, uniqueItems and the length and size bounds were not parsed at all, so nothing downstream could act on them. specmodel reads them and the attribute carries them. Bounds fold first-wins, as the description and the enum do: a later branch stating the same bound states nothing new. Constraints are taken from the write side, because a constraint is a rule about what may be sent. Nothing reads them yet: this is what the sensitivity, the deprecation notice and the plan-time validators are decided from. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ShocOne
force-pushed
the
feat/schema-constraint-keywords
branch
from
August 14, 2026 14:43
1406b04 to
03709b6
Compare
This was referenced Aug 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
A document states more about a property than the derivation could see.
formatwas parsed but reached only the audit's value synthesiser(
audit/plan/synth.go,audit/run/strategize.go) — the IR flattener'sflatstruct did not carry it, so
format: passwordwas structurally unable toinfluence a generated schema.
writeOnly,deprecated,uniqueItems,minLength,maxLength,minItemsandmaxItemswere not parsed at all:specmodel's decoder islookup-driven, so they were silently dropped.This is the foundation three separate pieces of work need —
Sensitive(mapping.md row 4), the plan-time validators (row 9), and
SetAttribute(row 11) — and it is also what the
date-timefixture defect uncovered in #89turns out to require.
What changed
specmodel.SchemagainsWriteOnly,Deprecated,UniqueItems,MinLength,MaxLength,MinItems,MaxItems. The four flags decodethrough one table, sharing
readOnly's error message shape; the bounds sharethe existing numeric-bound table's.
flatgains all of them plusformat,patternand the numeric bounds.Bounds fold first-wins through
foldBound, matching how the descriptionand the enum already fold: a later
allOfbranch restating a bound statesnothing new.
ir.AttributegainsFormat,WriteOnly,Deprecated,UniqueItems,Pattern,Minimum,Maximum,MinLength,MaxLength,MinItems,MaxItems, allomitempty.Constraints are taken from the write side: a constraint is a rule about what
may be sent, and a response schema restating it says nothing extra.
WriteOnlycomes from the create side only — a response schema cannot declare it.
Nothing reads them yet. That is deliberate: this PR is parse-and-carry, so
it can be reviewed against a byte-identical output.
Measured effect
Generated output is byte-identical on all three pilots. Refusals are exactly
main's:tfpfgen provider verify— no drift on all three.What did change is
--print-ir, which now carries the facts:formatwrite_onlydeprecatedunique_itemsmin_length/max_lengthminimum/maximummin_items/max_itemspatternFormats that now reach the derivation include
password×43 (jamfpro),date-time×1,543,uuid×39,uri×5,640.Those
passwordandwrite_onlycounts are the security-visible defecthandoff.md:107names: they generate as plain, visible attributes today. Thenext PR acts on them.
Gates
gofmt -l internal cmd— emptyscripts/repo_hygiene_gate.sh— passgolangci-lint run— 0 issuesgo build ./... && go vet ./...— passgo test ./...— pass, coverage 91.3% total,internal/specmodel95.0%tfpfgen provider generate(postcheck) +provider verifyon all three — no driftNew tests:
internal/specmodel/constraints_test.go,internal/intermediate_representation/constraints_test.go, and three refusalcases for a non-boolean
writeOnly/uniqueItemsand a non-numericmaxLength.🤖 Generated with Claude Code