formats: JSON Schema references in std/json-schema: $id, $ref, $defs, $anchor and a registry of supplied documents (step 2a of #80) #553
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 2a of #80 (
std/json-schema). Step 1 (#434) landed the model and the validator for the in-place keywords; a schema with$refis still refused. This step makes static references work:$id,$ref,$defs,$anchor, base URI resolution, JSON Pointer fragments and a registry of documents the caller supplies.$dynamicRef/$dynamicAnchorand the 2020-12 meta-schemas are the next piece (2b), because dynamic scope is a separate evaluation model and the meta-schemas need it. Step 2 of the epic is split into 2a and 2b here, as one PR of all of it would be too large to review.Source
std/json-schemastarted.Encode/Decode.std/uriresolves$id/$ref; the shared JSON Pointer type is added tostd/jsonby whichever of #80 and #81 lands first.std/jsonalready hasJsonPointerandJsonValue.get(std/json/src/pointer.trb), so this step reuses it and adds none.std/json-schema/tests/suite.test.trblists the groups and files that wait for references (ref,refRemote,anchor,defs,id,infinite-loop-detection,unknownKeyword, the groupitems and subitemsofitems); those exclusions are the checklist of this step.Design record point
JSON Schema 2020-12 core sections 8.2 (
$id,$anchor,$ref,$defs) and 9 (base URI, reference resolution); ROADMAP "Which versions a format supports"; ENCODING.md section 9. Decided by the loop:JsonSchemagets the fieldsid($id),anchor($anchor),reference($ref) anddefinitions($defs), read with the other keywords.$refis an applicator that sits next to sibling keywords (2020-12: siblings are evaluated too).SchemaRegistry(public, instd/json-schema) holds schemas by absolute URI:SchemaRegistry().add(uri: String, schema: JsonSchema)(method on a mutable registry, as the conventions ofstd/toml/std/xmlbuilders do; exact shape follows #146), andJsonSchema.validate(instance)gains an overload or a siblingvalidate(instance, registry). Resolution never touches the network or the file system: a$refto a document that is not in the registry (and not the root schema or one of its embedded$idresources) is a validation-timeJsonSchemaError/failure that names the unresolved URI.$id; each subschema with$idstarts a new base;$refis resolved against the current base withstd/uri. A fragment that is a JSON Pointer (#/$defs/name,#/properties/a) is followed withJsonPointerover the schema's sourceJsonValue; a plain-name fragment is an$anchorof the resource.$idis indexed at read time into the resource table of the root,$anchorper resource.infinite-loop-detection) is detected and reported as a failure naming the loop, not a stack overflow; recursion that consumes the instance (a tree schema) works.$dynamicRef,$dynamicAnchor,$vocabularyand the meta-schemas stay refused with aJsonSchemaErrorthat names them (2b), so this step never answers "valid" for a keyword it does not check.unevaluated*stays refused (step 3).schemaLocationis the evaluation path through the$ref(for example/properties/a/$ref/minimum),instanceLocationas before.Acceptance criteria
JsonSchema.readaccepts$id,$anchor,$ref,$defs; a schema using them validates per 2020-12, including$refwith sibling keywords, relative and absolute$refagainst$idbases, embedded resources with their own$id,$anchorfragments,#/#/...pointers with~0/~1and percent-encoding, and recursion through$ref(a tree).SchemaRegistryresolves a$refto a supplied document by absolute URI; a$refthat nothing resolves yields a failure that names the URI; no code path opens a socket or a file.infinite-loop-detection).std/json-schema/tests/suite-cases.trb, regenerated from the pinned release tag already in its header) gains the filesref,refRemote,anchor,defs,id,infinite-loop-detection,unknownKeyword; each case is its own test and passes.refRemoteloads the suite'sremotes/documents into aSchemaRegistry. Groups that need$dynamicRef, a meta-schema orunevaluated*(for example refs tohttps://json-schema.org/draft/2020-12/schema,$refto$dynamicRef) stay inexclusionswith the reason, andfileExclusionsloses the seven files above; the groupitems and subitemsexclusion goes.$dynamicRef,$dynamicAnchorandunevaluated*are still refused with an error that names the keyword.docs/standard-library/json-schema.mddocuments references andSchemaRegistrywith atrb checkexample (a$defsschema and a registry document);torb docs check,docs index --check,docs skill --checkanddoc --check --no-run stdare green; every public declaration has its doc comment; ROADMAP's Formats item keeps "started" and mentions references.sh tools/gates.sh a); touched files passtorb format --check.Touches the seed?
No. The compiler does not import
std/json-schemaand no std name is looked up by string; no two-commit rule applies. One or two Conventional Commits:feat(std/json-schema): resolve $ref, $id, $anchor and $defs against a registry of supplied documentsand, if the diff is large,docs(std/json-schema): ...(page, regeneratedskills/; the generated suite file may go in its owntest(std/json-schema): ...commit).Size
One PR, estimated 1.5 to 3 h of implementation: roughly 600 lines of TorbScript (resource table, resolver, cycle guard), the regenerated suite file and the page.
Dependencies
std/jsonJsonPointer(landed),std/uri(landed).$dynamicRef/$dynamicAnchor, the 2020-12 meta-schemas,vocabulary,dynamicRef), then step 3 (unevaluated*).[loop:torbscript] claim implement by session:loop-torbscript-20261028 until 2026-10-29T00:10:00Z
[loop:torbscript] implement checkpoint: done: read the contract, model and validator, worktree ready (branch
loop/553-json-schema-references), suite generator for the pinned release 23.1.0 written; in flight: reference resolver design; next: schema fields, registry, resolver with cycle guard, suite files, docs, PR.[loop:torbscript] checkpoint implement (worker): done: reference resolution in std/json-schema (
$id,$anchor,$ref,$defs,SchemaRegistry), 35/35 unit tests green locally. In flight: regenerated suite-cases.trb with the seven files plus remotes (843 cases), now deriving the remaining exclusions from the run. Branchloop/553-json-schema-references(not pushed yet). Next: docs page, ROADMAP, skills regeneration, commits, PR.[loop:torbscript] implement: PR #555 is open (
Closes #553, branchloop/553-json-schema-references, 3 commits). Local: std/json-schema unit tests 35/35, suite 846/846 (843 cases incl. ref, refRemote, anchor, defs, id, infinite-loop-detection, unknownKeyword),torb format --check, docs check/index/skill/declarations,doc --check --no-run stdand check-commits are green. Forge CI of the PR was still pending (all four checks queued, none started) after about 40 minutes, so it is unverified. Worker usage: one subagent, about 90 minutes. Worktree kept until the PR lands. next: review[loop:torbscript] review: PR #555 has no fix to make: tier B and gates are red on this head exactly as on
main(19 allocation-budget failures in file/path programs), and the review of argus asks for a re-run or rebase oncemainis green. The fix is PR #556 (issue #550). next: waiting (PR #556 landed and main tier B green, then rebase/re-run PR #555)[loop:torbscript] claim review by session:loop-torbscript-20261028 until 2026-10-29T04:50:00Z
[loop:torbscript] checkpoint: rebased loop/553-json-schema-references onto main
38d3edd4without conflicts (3 commits, linear), check-commits.sh ok, pushedb49afc8bwith --force-with-lease. Worktree code/wt/torbscript-language-553. In flight: forge CI wait. Next: WIP prefix removal + Argus review request once green.std/json-schema(step 2b of #80) #567std/json-schema(step 3 of #80) #690