diff --git a/.changeset/field-value-or-absent-check-enum.md b/.changeset/field-value-or-absent-check-enum.md new file mode 100644 index 0000000000..e18943dc32 --- /dev/null +++ b/.changeset/field-value-or-absent-check-enum.md @@ -0,0 +1,4 @@ +--- +--- + +Document `field_value_or_absent` check matcher in storyboard-schema.yaml and runner-output-contract.yaml. The matcher shipped in `@adcp/client` 5.16.0; this update keeps the normative compliance spec in sync and unblocks storyboards that need to assert on envelope-optional fields like `replayed`. diff --git a/static/compliance/source/universal/runner-output-contract.yaml b/static/compliance/source/universal/runner-output-contract.yaml index a73772853e..7a84247c37 100644 --- a/static/compliance/source/universal/runner-output-contract.yaml +++ b/static/compliance/source/universal/runner-output-contract.yaml @@ -71,9 +71,9 @@ validation_result: required_fields: - check # Validation kind from storyboard-schema.yaml: # response_schema | field_present | field_value | - # status_code | http_status | http_status_in | - # error_code | on_401_require_header | - # resource_equals_agent_url | any_of + # field_value_or_absent | status_code | http_status | + # http_status_in | error_code | on_401_require_header | + # resource_equals_agent_url | any_of | refs_resolve - passed # boolean - description # human-readable description copied from the # storyboard validation entry (so the implementor @@ -86,21 +86,25 @@ validation_result: # failures. Null only when the failure is # transport-level and no payload was returned. - expected # machine-readable expected value: - # response_schema → schema $id that was applied - # field_value → expected value (any JSON type) - # field_present → the path that should resolve - # status_code → expected status - # error_code → expected error code - # any_of → array of acceptable forms + # response_schema → schema $id that was applied + # field_value → expected value (any JSON type) + # field_value_or_absent → value or allowed_values array + # from the storyboard validation + # field_present → the path that should resolve + # status_code → expected status + # error_code → expected error code + # any_of → array of acceptable forms - actual # machine-readable actual value observed: - # response_schema → array of schema errors - # (each { instance_path, - # schema_path, keyword, - # message }) - # field_value → actual value (any JSON type) - # field_present → null (the field was missing) - # or the observed non-object - # value + # response_schema → array of schema errors + # (each { instance_path, + # schema_path, keyword, + # message }) + # field_value → actual value (any JSON type) + # field_value_or_absent → actual value (any JSON type); + # null when the field was absent + # field_present → null (the field was missing) + # or the observed non-object + # value - schema_id # $id of the response schema applied. Required # when check == response_schema, null otherwise. - schema_url # Resolvable URL the implementor can fetch to diff --git a/static/compliance/source/universal/storyboard-schema.yaml b/static/compliance/source/universal/storyboard-schema.yaml index c665c7e4ec..e01e12e7c2 100644 --- a/static/compliance/source/universal/storyboard-schema.yaml +++ b/static/compliance/source/universal/storyboard-schema.yaml @@ -553,14 +553,28 @@ # --- Validation --- # # check: string (what to validate: "response_schema", "field_present", "field_value", -# "status_code", "http_status", "http_status_in", "error_code", -# "on_401_require_header", "resource_equals_agent_url", "any_of", -# "refs_resolve") +# "field_value_or_absent", "status_code", "http_status", "http_status_in", +# "error_code", "on_401_require_header", "resource_equals_agent_url", +# "any_of", "refs_resolve") # path: string (JSON path to the field, e.g., "formats[0].format_id") -# value: any (expected value — string, number, or boolean; required when check is "field_value") -# allowed_values: array (acceptable values for "field_value", "http_status_in", "error_code", "any_of") +# value: any (expected value — string, number, or boolean; required when check is "field_value"; +# accepted (optional) when check is "field_value_or_absent") +# allowed_values: array (acceptable values for "field_value", "field_value_or_absent", +# "http_status_in", "error_code", "any_of") # description: string (human-readable description of validation) # +# field_value_or_absent check: +# Passes when the field is absent OR present and equal to `value` / contained in +# `allowed_values`; fails only when the field is present with a disallowed value. +# Use for fields that the spec permits to be omitted but MUST NOT carry a wrong value +# when present (e.g., a `replayed` flag that MAY be omitted on a fresh path but MUST +# NOT be true). Accepts both `value` (single expected value) and `allowed_values` (set +# membership); at least one of the two MUST be provided. A `field_value_or_absent` check +# that declares neither `value` nor `allowed_values` is a storyboard-load error; runners +# MUST reject the storyboard before execution begins. +# For fields that are required by the response schema, pair this check with a separate +# `check: field_present` to avoid silently accepting absent fields that are required. +# # Error-shape validation — use `check: error_code`: # The `error_code` check is shape-agnostic. The runner resolves the code from # any of the transport-binding locations defined by the client detection