formats: JSON Schema format assertion for the formats std can parse (step 4a of #80) #697
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Step 4a of the epic #80 (step 4 is split just in time: 4a here, 4b the hand-written formats and the
content*keywords). Steps 1, 2a, 2b and 3 have landed.std/json-schemavalidates every in-place keyword and reference of 2020-12, butformatis neither stored in the model nor checked, andtests/suite.test.trblistsformatandcontentunderfileExclusions. The specification lets a validator treatformatas an annotation or as an assertion; the epic decided annotation by default, assertion by option.Goal
formatbecomes a keyword of the model, and a caller can askvalidateto assert it for the formats whose syntaxstdalready parses.Source
src/schema.trb(model, reader),src/keywords.trb,src/validate.trb,tests/suite.test.trb(exclusions,fileExclusions),tests/suite-cases.trb(generated).Scope
src/schema.trb: fieldformat: String?, read fromformat(a string, else aJsonSchemaErrorat the keyword); kept as an annotation as before when not asserted.src/validate.trb:validate(instance, registry = SchemaRegistry(), assertFormat: Bool = false); the flag travels in theFrame. Where it istrue, a string document that does not satisfy the named format fails with keywordformat(location/format, message names the format). Non-strings and unknown format names always pass, as the specification says.src/formats.trb:fn formatFailure(name: String, text: String): String?, one function per format, each built on the parserstdhas:date-time,date,time(std/time:OffsetDateTime,Date,TimeOfDay+UtcOffset, RFC 3339 strict: upper-caseT/Z, leap second 23:59:60 accepted only at UTC 23:59:60),ipv4,ipv6(std/ip,Ipv4Address,Ipv6Address),uri,uri-reference,iri,iri-reference(std/uri,Uri,UriReference, the IRI forms ofstd/uri'siri),uri-template(UriTemplate),uuid(Uuid),regex(std/regex,Regex),json-pointer(JsonPointer.parse) andrelative-json-pointer(non-negative integer without leading zeros, optional#, or a JSON Pointer).email,idn-email,hostname,idn-hostname,duration) pass until step 4b; they are named in a documented list on the page, not silently ignored.Acceptance criteria
JsonSchema.readkeepsformat; a non-stringformatis refused with the place in the schema.validatenever fails onformat(annotation); withassertFormat: trueeach listed format accepts its valid examples and refuses its invalid ones; non-strings and unknown formats pass.tests/draft2020-12/optional/format/files for the listed formats (date-time,date,time,ipv4,ipv6,uri,uri-reference,iri,iri-reference,uri-template,uuid,regex,json-pointer,relative-json-pointer) andtests/draft2020-12/format.jsonare generated intosuite-cases.trb(header note updated) with the valid/invalid verdict as the suite says underassertFormat: true;formatdrops fromfileExclusions. Suite cases the std parser decides differently stay as namedexclusionswith the reason (a documented difference, to be fixed in the std package by its own issue, not here); the unlisted formats' files stay out.tests/json-schema.test.trb: default is annotation-only,assertFormatfails one case per format family, error location and message, unknown format passes.docs/standard-library/json-schema.md: theformatkeyword, the option, the table of asserted formats and the list that waits on 4b;skills/regenerated;sh tools/gates.sh agreen in forge CI.Design record point
ROADMAP "Which versions a format supports"; ENCODING.md section 9. Decided by the loop:
validate, not a field of the schema: assertion is a decision of the caller who validates, not a property of the schema text (the specification names it an implementation choice), and it keepsvalidate(instance)call sites unchanged. The vocabulary route (format-assertionin a meta-schema's$vocabulary) is step 4b with its meta-schema.std/time,std/ip,std/uri,std/identifier,std/regexandstd/json; no second grammar is written where one exists. A difference between astdparser and the suite is recorded as an exclusion and fixed in that package, not worked around here.Seed impact
None: the compiler does not import
std/json-schemaand no std name is looked up by string. No new native, no syntax change.Size
One PR, two Conventional Commits: (1)
feat(std/json-schema): assert format on request(model field, option,formats.trb, unit tests); (2)test(std/json-schema): run the format suite files(regenerated cases, exclusions, docs, skill regeneration).Dependencies
Needs #690 (landed). Part of #80; step 4b follows (email, hostname, duration,
format-assertionvocabulary,content*).[loop:torbscript] claim implementation by session:loop-torbscript-20261030 @anthropic:tkoehn until 2026-10-30T22:42Z
[loop:torbscript] release implementation by session:loop-torbscript-20261030 @anthropic:tkoehn: worker interrupted by a gateway restart after opening PR #700 (head
4bc6eb4b, mergeable, argus requested, not WIP). CI is still pending (gates, seed pack, archives, tier A); if it ends red, a fix worker takes it.next: review