Note: Someone else (I think @karenetheridge, possibly others as well) came up with this a while ago and apparently I objected to it (which I 100% believe but no longer recall the reason).
JSON Schema has an architectural principle that individual assertion keywords that fail cannot be un-failed. While the assertion result can be manipulated at the schema object level (e.g. by not or oneOf, which pass when one or more subschemas fail), doing so at the individual keyword level violates the principles of a layered constraint system.
This means that a keyword can only produce an assertion result if it has all of the information necessary to determine the final result. Only contains can meet this criteria out of these three keywords, and only if it knows the values of minContains and maxContains.
This means that minContains and maxContains cannot produce a failed assertion result. They only exist to provide extra input to contains.
One subtlety is that since we describe interactions in terms of annotations (even though they do not need to be implemented that way), and because the absence of a keyword cannot produce an annotation (§7.3 ¶2), this means that the default minContains behavior of 1 must be specified as how contains behaves in the absence of minContains, not simply as the default value of minContains.
To make the behavior of this group of keywords clear, and because minContains and maxContains no longer have assertion-failing behavior, they should be moved to the applicator vocabulary with contains.
Note: Someone else (I think @karenetheridge, possibly others as well) came up with this a while ago and apparently I objected to it (which I 100% believe but no longer recall the reason).
JSON Schema has an architectural principle that individual assertion keywords that fail cannot be un-failed. While the assertion result can be manipulated at the schema object level (e.g. by
not
oroneOf
, which pass when one or more subschemas fail), doing so at the individual keyword level violates the principles of a layered constraint system.This means that a keyword can only produce an assertion result if it has all of the information necessary to determine the final result. Only
contains
can meet this criteria out of these three keywords, and only if it knows the values ofminContains
andmaxContains
.This means that
minContains
andmaxContains
cannot produce a failed assertion result. They only exist to provide extra input tocontains
.One subtlety is that since we describe interactions in terms of annotations (even though they do not need to be implemented that way), and because the absence of a keyword cannot produce an annotation (§7.3 ¶2), this means that the default
minContains
behavior of1
must be specified as howcontains
behaves in the absence ofminContains
, not simply as the default value ofminContains
.To make the behavior of this group of keywords clear, and because
minContains
andmaxContains
no longer have assertion-failing behavior, they should be moved to the applicator vocabulary withcontains
.