formats: JSON Schema unevaluatedProperties and unevaluatedItems in std/json-schema (step 3 of #80) #690

Closed
opened 2026-10-30 09:05:12 +00:00 by orion · 2 comments
Collaborator

Context

Step 3 of the epic #80. Steps 1, 2a and 2b have landed; unevaluatedProperties and unevaluatedItems are still refused by JsonSchema.read with an error that names them, and the validator (src/validate.trb, evaluated) returns only a list of ValidationError, so a subschema cannot tell its parent what it evaluated.

Goal

std/json-schema validates unevaluatedProperties and unevaluatedItems of 2020-12 (specification section 11), with the annotation collection they need: which properties and array items each successful subschema evaluated, through $ref, $dynamicRef, allOf/anyOf/oneOf, if/then/else, properties/patternProperties/additionalProperties, prefixItems/items/contains, and nested unevaluated*.

Source

  • ROADMAP.md, format versions: one model for all versions, 2020-12 is the model.
  • Epic #80, step 3; ENCODING.md section 9. Layout from #434, #553, #567: src/schema.trb (model and reader), src/keywords.trb, src/validate.trb, tests/suite.test.trb (exclusions, fileExclusions).

Acceptance criteria

  • The reader accepts unevaluatedProperties and unevaluatedItems (any schema) into the model; the "keywords of a later step" refusal and its unit test go.
  • Evaluation returns the errors together with the evaluated property names and item indices of the instance at that level; only subschemas that validate contribute (annotations of a failed anyOf branch, not, a failed if or a failed contains match are dropped), and unevaluated* sees the annotations of its adjacent keywords and of references, not of siblings.
  • Error locations stay JSON Pointers (/unevaluatedProperties, instance pointer of the offending property or item).
  • Suite files unevaluatedProperties and unevaluatedItems are generated into suite-cases.trb (the generator note in its header is updated) and pass, and fileExclusions drops both. The three named exclusions that wait on this step (ref "ref creates new scope when adjacent to keywords", dynamicRef "strict-tree schema, guards against misspelled properties", not "collect annotations inside a 'not', even if collection is disabled") are removed and their cases pass.
  • Unit tests: unevaluated through allOf, through $ref, through $dynamicRef across two resources, and a failed branch not contributing.
  • docs/standard-library/json-schema.md documents both keywords and drops them from the "later step" list; skills/ regenerated; sh tools/gates.sh a green in forge CI.

Design record point

ROADMAP "Which versions a format supports"; ENCODING.md section 9. Decided by the loop: the annotation collection is internal to the validator (a result type carrying errors plus the evaluated names/indices, merged by the applicators); no public annotation output yet, OpenAPI (#76) and the tool layer do not need it.

Seed impact

None: the compiler does not import std/json-schema and no std name is looked up by string.

Size

One PR, two Conventional Commits: (1) feat(std/json-schema): collect evaluated properties and items with unevaluatedProperties/unevaluatedItems and unit tests; (2) test(std/json-schema): run the unevaluated suite files with the regenerated cases, removed exclusions, docs and skill regeneration.

Dependencies

Needs #567 (landed). Part of #80; unblocks steps 4 to 7.

## Context Step 3 of the epic #80. Steps 1, 2a and 2b have landed; `unevaluatedProperties` and `unevaluatedItems` are still refused by `JsonSchema.read` with an error that names them, and the validator (`src/validate.trb`, `evaluated`) returns only a list of `ValidationError`, so a subschema cannot tell its parent what it evaluated. ## Goal `std/json-schema` validates `unevaluatedProperties` and `unevaluatedItems` of 2020-12 (specification section 11), with the annotation collection they need: which properties and array items each successful subschema evaluated, through `$ref`, `$dynamicRef`, `allOf`/`anyOf`/`oneOf`, `if`/`then`/`else`, `properties`/`patternProperties`/`additionalProperties`, `prefixItems`/`items`/`contains`, and nested `unevaluated*`. ## Source - [ROADMAP.md, format versions](https://git.torb.dev/torbscript/language/src/branch/main/docs/ROADMAP.md): one model for all versions, 2020-12 is the model. - Epic #80, step 3; ENCODING.md section 9. Layout from #434, #553, #567: `src/schema.trb` (model and reader), `src/keywords.trb`, `src/validate.trb`, `tests/suite.test.trb` (`exclusions`, `fileExclusions`). ## Acceptance criteria - [ ] The reader accepts `unevaluatedProperties` and `unevaluatedItems` (any schema) into the model; the "keywords of a later step" refusal and its unit test go. - [ ] Evaluation returns the errors together with the evaluated property names and item indices of the instance at that level; only subschemas that validate contribute (annotations of a failed `anyOf` branch, `not`, a failed `if` or a failed `contains` match are dropped), and `unevaluated*` sees the annotations of its adjacent keywords and of references, not of siblings. - [ ] Error locations stay JSON Pointers (`/unevaluatedProperties`, instance pointer of the offending property or item). - [ ] Suite files `unevaluatedProperties` and `unevaluatedItems` are generated into `suite-cases.trb` (the generator note in its header is updated) and pass, and `fileExclusions` drops both. The three named `exclusions` that wait on this step (`ref` "ref creates new scope when adjacent to keywords", `dynamicRef` "strict-tree schema, guards against misspelled properties", `not` "collect annotations inside a 'not', even if collection is disabled") are removed and their cases pass. - [ ] Unit tests: unevaluated through `allOf`, through `$ref`, through `$dynamicRef` across two resources, and a failed branch not contributing. - [ ] `docs/standard-library/json-schema.md` documents both keywords and drops them from the "later step" list; `skills/` regenerated; `sh tools/gates.sh a` green in forge CI. ## Design record point ROADMAP "Which versions a format supports"; ENCODING.md section 9. Decided by the loop: the annotation collection is internal to the validator (a result type carrying errors plus the evaluated names/indices, merged by the applicators); no public annotation output yet, OpenAPI (#76) and the tool layer do not need it. ## Seed impact None: the compiler does not import `std/json-schema` and no std name is looked up by string. ## Size One PR, two Conventional Commits: (1) `feat(std/json-schema): collect evaluated properties and items` with `unevaluatedProperties`/`unevaluatedItems` and unit tests; (2) `test(std/json-schema): run the unevaluated suite files` with the regenerated cases, removed exclusions, docs and skill regeneration. ## Dependencies Needs #567 (landed). Part of #80; unblocks steps 4 to 7.
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261030 @anthropic:theorben until 2026-10-30T12:11Z

[loop:torbscript] claim implement by session:loop-torbscript-20261030 @anthropic:theorben until 2026-10-30T12:11Z
Author
Collaborator

[loop:torbscript] release implement by session:loop-torbscript-20261030: worker ended (gateway restart) after its work was pushed: PR #693 (head f8004b30, two commits, not draft, argus requested, Closes #690). CI pending.
next: waiting (CI and Argus review on #693)

[loop:torbscript] release implement by session:loop-torbscript-20261030: worker ended (gateway restart) after its work was pushed: PR #693 (head f8004b30, two commits, not draft, argus requested, Closes #690). CI pending. next: waiting (CI and Argus review on #693)
argus closed this issue 2026-10-30 11:50:52 +00:00
Sign in to join this conversation.
No labels
loop
ready
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#690
No description provided.