Validation
Generated from the module documentation of crates/canon/src/validate/mod.rs.
Deterministic validation of a protocol/1 document.
Validation resolves every reference and reports every problem it finds, in a stable order that does not depend on the order the sections are written in:
- the format;
- malformed identifiers: the protocol id, then the ids declared in artifacts, evidence kinds,
claims, obligations, actions, outcomes, invalidation rules, case inputs and independence
dimensions, in that section order, then the capabilities and effect classes actions name and
the protocol each action's
case_opennames, in action order, then the decisions outcomes require, in outcome order, then the values case inputs declare, in input order; - duplicate identifiers, in the same section order;
- maximum ages that are not a whole number without leading zeros, followed by
s,m,hord, or that are but are too long to count in seconds (each with its own message), in the order the evidence kinds are written; - case inputs that declare no value (
empty-input-values, naming the input) or list a value more than once (duplicate-input-value, naming the input and the value, once for every listing after its first), in the order the inputs are written; - action argument schemas outside the argument-schema dialect (
action-arguments; the dialect, and the order within one schema, are stated with it), each naming the action, the JSON Pointer of the keyword inside the schema and why it is refused, one per offending keyword, in the order the actions are written; - unresolved references and malformed input tests and order forms (a claim, an evidence kind,
the artifact an evidence match names as its subject, which is reported after the kind it is
written beside, then the evidence match's
independent_on: an empty list,empty-independent-on, or a dimension it lists more than once,duplicate-independent-on, once for every listing after its first, then each dimension it lists that is not declared,undeclared-dimension, once, in the order listed, every one naming the declaration the match is written in; for an order form, each kind it names,first(orlast) beforethen, then its subject, then abeforewhosefirstandthenname one kind,self-ordered-evidence, naming it (anafteror asincemay name one kind as both: a record of a kind may follow the first, or the latest, record of that kind); for an input test, first an emptyinlist,empty-input-test, or a value it lists more than once,duplicate-input-test-value, once for every listing after its first, then an input it names that is not declared,undeclared-input, or a value it lists that its input does not declare,undeclared-input-value, each value once, in the order listed, every one naming the declaration the test is written in and the input; for achildrenform, first an emptyinlist,empty-child-outcomes, or an outcome it lists more than once,duplicate-child-outcome, once for every listing after its first, thenopenlisted,open-child-outcome, once, then the evidence kindcase_outcomewhen it is not declared,undeclared-evidence-kind, every one naming the declaration the form is written in): those in claims first, then those in obligations (each obligation's discharge predicate, followed by every evidence match, order form andchildrenform it holds, which a discharge predicate may not: it tests only claim values, each kind an order form names once, the kindcase_outcomefor achildrenform; then its applicability predicate, followed likewise by every evidence match, order form andchildrenform it holds,evidence-in-applicability: it tests only claim values and case inputs), then those in actions (each action's precondition, then each evidence kind it may produce, then the subject of the case it opens,undeclared-artifact, then an opening under the protocol's own id,self-opened-case, both naming the action), then those in outcomes, then those in invalidation rules (the upstream artifact, then each claim the rule invalidates); within a section, in the order its declarations are written, and within a declaration, in the order its references are written; - invalidation rules that name a claim reaching no evidence match, in its own predicate or in a
claim it tests through any number of claim references (
inert-invalidation), in the order the rules and their claims are written. An order form or achildrenform is not an evidence match here: it reads the history, which an invalidation rule does not change; - cycles between claims.
Within a section, entries come in the order they are written. Every message renders document text on one line. The same document always yields the same problems in the same order.
The argument-schema dialect
Generated from the module documentation of crates/canon/src/validate/arguments.rs.
Canon's argument-schema dialect (story:action-arguments): the JSON Schemas an action's
arguments may be.
The dialect is a subset of JSON Schema 2020-12. Every schema in it is a valid 2020-12 schema with the same meaning, so a runner can hand it to any 2020-12 validator; protocols load offline, so it has no reference at all.
- Every schema, the top level and each nested one, names exactly one
type:object,array,string,integer,number,booleanornull. The top level istype: object. titleanddescription, strings, anywhere.enum, on any type: a non-empty list of distinct JSON scalars, each of the schema's type.object:properties(a map of name to schema),required(a list of distinct names, each declared inproperties),additionalProperties(a boolean only).array:items(one schema),minItems,maxItems.string:minLength,maxLength.integerandnumber:minimum,maximum, integers.minItems,maxItems,minLengthandmaxLengthare non-negative integers, and each minimum is at most its maximum.- Schemas nest at most
MAX_SCHEMA_DEPTHdeep: the top level is one level, and each schema inpropertiesoritemsone more.
Anything else is outside the dialect: $ref, $defs, $schema, $id, allOf, anyOf,
oneOf, not, if, then, else, patternProperties, pattern, format, const,
exclusiveMinimum and exclusiveMaximum by name, a list-valued type, a schema-valued
additionalProperties, a keyword on a type it does not apply to and any unknown keyword.
check reports one problem per offending keyword, at the keyword's JSON Pointer inside the
schema (an element's, for an enum value or a required name): a schema that is not an object,
names no type or nests too deep is reported at its own pointer. A schema whose type is
missing or not one of the seven has its other keywords checked only for being in the dialect,
since which apply depends on the type. Problems come in document order, the keys of every
object in code-point order, and the walk keeps a stack of its own, never recursing.
Problem codes
| Code | Meaning |
|---|---|
unsupported-format | The document's format is not protocol/1. |
invalid-identifier | An identifier is empty or contains whitespace or a control character. |
duplicate-identifier | An identifier is declared more than once in one section. |
undeclared-claim | A predicate tests, or an invalidation rule invalidates, a claim that is not declared. |
self-ordered-evidence | A before order form names one evidence kind as both its first and its then: no record is observed strictly before itself. |
undeclared-evidence-kind | A predicate matches or orders, or an action may produce, an evidence kind that is not declared. |
undeclared-artifact | An evidence match or an order form names as its subject, or an invalidation rule as its upstream artifact, an artifact that is not declared. |
invalid-max-age | An evidence kind's max_age is not a whole number without leading zeros, followed by s, m, h or d, or is too long to count in seconds. |
evidence-in-discharge | A discharge predicate tests evidence; it may test only claim values. path locates the evidence match or order form inside the predicate, as discharged_when.all[1].evidence or discharged_when.first. |
evidence-in-applicability | An applicability predicate tests evidence; it may test only claim values and case inputs. path locates the evidence match or order form inside the predicate, as applicable_when.not.evidence or applicable_when.before. |
empty-input-values | A case input declares no value, so no case could give it one. |
duplicate-input-value | A case input lists a value more than once. |
empty-input-test | An input test lists no value, so it is false in every case. |
duplicate-input-test-value | An input test lists a value more than once. |
undeclared-input | An input test names an input that is not declared. |
undeclared-input-value | An input test lists a value its input does not declare. |
empty-independent-on | An evidence match demands independence on no dimension: independent_on is empty. |
duplicate-independent-on | An evidence match lists a dimension in independent_on more than once. |
undeclared-dimension | An evidence match demands independence on a dimension that is not declared. |
inert-invalidation | An invalidation rule names a claim that reaches no evidence match, in its own predicate or in a claim it tests, so no record could be kept from it. |
empty-child-outcomes | A children form lists no outcome, so no child case could end with one of them. |
duplicate-child-outcome | A children form lists an outcome more than once. |
open-child-outcome | A children form lists open, which is a running child case's outcome, never a terminal one: the form is unknown while a child is open. |
self-opened-case | An action opens a child case under the protocol's own id: a case could then open cases under its own protocol without end (D206). |
claim-cycle | Claims whose predicates test each other in a cycle; the first claim is repeated at the end. |
action-arguments | An action's argument schema is outside the argument-schema dialect: pointer is the JSON Pointer of the offending keyword inside the schema ("" for the schema itself) and reason why it is refused. |
More columns: swipe horizontally, or focus the table and use the arrow keys.
A document that is not well-formed YAML, or not shaped like protocol/1, fails earlier, while parsing; the command line reports it as parse.