Skip to content

keywords only exhibit the behaviors they're defined with #1577

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

gregsdennis
Copy link
Member

What kind of change does this PR introduce?

clarification

Issue & Discussion References

Summary

The previous language could imply that all keywords needed to have an assertion result, e.g. annotations would always produce a "true" assertion result.

For min/maxContains, I added explicit text that they do not produce an assertion result, emphasizing that the assertion comes from contains and that these keywords are informative.

This change clarifies that keywords only exhibit the behaviors they're defined with.

Does this PR introduce a breaking change?

No.

@gregsdennis gregsdennis requested a review from a team January 19, 2025 07:24
@gregsdennis gregsdennis added this to the stable-release milestone Jan 19, 2025
@gregsdennis gregsdennis self-assigned this Jan 19, 2025
@karenetheridge
Copy link
Member

karenetheridge commented Jan 19, 2025

So, what is the result of:

allOf: [
  { maxContains: 1 },
  { maxContains: 1 },
]

and

anyOf: [
  { maxContains: 1 },
  { maxContains: 1 },
]

and

oneOf: [
  { maxContains: 1 },
  { maxContains: 1 },
]

?

@gregsdennis
Copy link
Member Author

Good point. The keywords produce no assertions, but the subschemas still need to.

Granted, this is true with 2020-12, too. The validation spec doesn't actually define assertion results for any of the annotations, yet it's still considered a pass because there are no constraints.

I think this could be stated explicitly.

Copy link
Member

@jdesrosiers jdesrosiers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've always thought of all keywords having an assertion. Annotation-only keywords just always assert true. $defs is another example of a keyword always returns true although it's not an annotation.

I think the way this is worded is great because it allows for implementations to ignore non-assertions or just make them true. They can implement it however makes most sense for their implementation.

fit. Applicators apply subschemas to parts of the instance and combine their
results.
JSON Schema keywords may exhibit one or more behaviors. This specification
defines three such behaviors:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to say that all keyword behaviors in the specification are in these three categories, but the spec defines other behaviors for e.g. $id and $anchor/$dynamicAnchor. And $schema ... exists.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is an interesting point. I was thinking that these keywords don't exhibit a behavior so much as they are merely informative, like maxContains would be to contains.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great point! My implementation doesn't even treat those as keywords. They're meta-data used to process the schema, but they're not directly part of the validation/annotation process. So, I wouldn't consider them similar to maxContains that is involved in validation.

I'm not sure what I'd suggest, but I think something needs to be called that these aren't normal keywords.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a footnote. Let me know.

I tend to agree with @jdesrosiers on this. The $* keywords are more of directives than anything else, and I don't think we should be listing "directive" as a behavior. It would encourage people to try to make more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That footnote works for me. 'behavior' and 'directive' are implemented the same way in mine, the difference just being whether the behavior/directive takes an instance.

@gregsdennis gregsdennis force-pushed the gregsdennis/validation-not-required branch from 285a554 to 1a7a34a Compare April 12, 2025 01:19
Comment on lines +604 to +606
Applicator keywords also behave as assertions by defining how subschema or
referenced schema boolean [assertion](#assertions) results are modified and/or
combined to produce the boolean result of the applicator. Applicators may apply
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm finding this sentence difficult to follow. I'm not sure what "referenced" means in this context. Also, I don't think it's necessary to say subschema "or" boolean schema because boolean schemas are subschemas. I'm also unsure what "modified" means in this context. What does it mean for an applicator to modify the result of a subschema?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'referenced' seems okay to me; $ref has a referenced schema that isn't a subschema - although maybe that is better mentioned above in the initial description of applicator keyword behavior.

The 'boolean' refers to an assertion result, not type of subschema, though the words/phrases run together a bit and it's difficult to parse how they are grouped (even knowing all the terms, much less while learning them).

Suggested change
Applicator keywords also behave as assertions by defining how subschema or
referenced schema boolean [assertion](#assertions) results are modified and/or
combined to produce the boolean result of the applicator. Applicators may apply
Applicator keywords also behave as assertions, using the assertion results of
each subschema or referenced schema of the keyword. These boolean results are
modified (e.g. the `not` keyword negates its subschema's assertion) and/or
combined (e.g. `allOf` takes the conjunction of its subschemas' assertions)
to produce the boolean result of the applicator.

Not quite polished - not suggesting that be put in as is, just thinking through what I might find to read better. (The spec is always very light on examples, I assume intentionally so maybe those don't go in, but I do always find they make the more generalized spec language much easier to connect to what it is describing).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'referenced' seems okay to me; $ref has a referenced schema that isn't a subschema

$ref is just a keyword in a subschema. It's sufficient to call { "$ref": "..." } a subschema. It's not something different because it happens to contain a reference.

(I wouldn't say the same thing before 2019-09. Back then I would call it something different than a schema.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure, a schema containing a $ref isn't different than any other, but taking $ref as an applicator keyword, the schema it is doing application of is its referenced schema, not a subschema (I think I recall that your implementation does make it a subschema, but in the original document it isn't)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see what you mean. $ref is an applicator but its value isn't a subschema, it's a reference. Good point!

Comment on lines +1793 to +1794
This keyword produces no assertion result. The value of this keyword is used as
its annotation result.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to stick with the "behavior" terminology for these things. What does it even mean to "produce an assertion result"? Is it a statement about output? (Those are rhetorical questions.) I think sticking to "behavior" terminology avoids that confusion. What matters is that the keyword has no affect on the validation result.

Suggested change
This keyword produces no assertion result. The value of this keyword is used as
its annotation result.
This keyword has no assertion behavior. The value of this keyword is used as
its annotation result.

annotations in particular are extremely flexible. Complex behavior is usually
better delegated to applications on the basis of annotation data than
implemented directly as schema keywords. However, extension keywords MAY define
other behaviors for specialized purposes.

Implementations SHOULD NOT add unspecified behaviors to keywords.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what this is aiming to prevent.

Behaviors outside the three above? I'm not sure what that would be. That also seems more the concern of the definition of an extension keyword rather than an implementation.

Or behaviors within the three, but that aren't in a specification? If so, that seems just the nature of a specification, that an implementation of it sticks to its specified behaviors.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See, this thread.

For the purposes of this document, an instance "validating against a keyword"
means that the keyword produces an assertion result of `true` if the instance
satisfies the given constraint; otherwise an assertion result of `false` is
produced.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This references Core Spec Keyword Behaviors but then also repeats, or is redundant with, a significant amount of that section.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The validation spec uses the phrase "an instance validates against this keyword if...", or some variant of it, quite a lot. I just wanted to define what that means. The phrasing is different than "this keyword exhibits assertion behavior by...", which feels more clunky to me (and I'd have to change a lot of places).

Co-authored-by: Jason Desrosiers <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: In Progress
4 participants