Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/envelope-field-present-check-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"adcontextprotocol": patch
---

Add `envelope_field_present` check type to the storyboard schema and update `v3-envelope-integrity.yaml` to use it for the `status` presence assertion. The new check type walks `protocol-envelope.json` rather than the step's `response_schema_ref`, eliminating the static-analysis `VERIFIER_UNREACHABLE` gap in adcp-client's storyboard-drift verifier. Requires adcp-client#1045.
7 changes: 4 additions & 3 deletions scripts/lint-storyboard-contradictions.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -445,15 +445,16 @@ function classifyOutcome(step) {
return { kind: 'error', codes };
}

// Looks like a success assertion path (field_present, response_schema,
// field_value on happy-path fields). Distinguish from "unspecified" —
// we need at least one positive assertion to call it success.
// Looks like a success assertion path (field_present, envelope_field_present,
// response_schema, field_value on happy-path fields). Distinguish from
// "unspecified" — we need at least one positive assertion to call it success.
const hasPositiveAssertion = validations.some((v) => {
if (!v || typeof v !== 'object') return false;
const check = v.check;
return (
check === 'response_schema' ||
check === 'field_present' ||
check === 'envelope_field_present' ||
check === 'field_value' ||
check === 'field_value_or_absent' ||
check === 'http_status' ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ validation_result:
field carries the transport failure).
required_fields:
- check # Validation kind from storyboard-schema.yaml:
# response_schema | field_present | field_value |
# response_schema | field_present |
# envelope_field_present | field_value |
# 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
Expand All @@ -91,6 +92,8 @@ validation_result:
# field_value_or_absent → value or allowed_values array
# from the storyboard validation
# field_present → the path that should resolve
# envelope_field_present → the path that should resolve
# in the protocol envelope
# status_code → expected status
# error_code → expected error code
# any_of → array of acceptable forms
Expand All @@ -105,6 +108,9 @@ validation_result:
# field_present → null (the field was missing)
# or the observed non-object
# value
# envelope_field_present → null (the field was missing)
# or the observed non-object
# value (scoped to envelope)
- schema_id # $id of the response schema applied. Required
# when check == response_schema, null otherwise.
- schema_url # Resolvable URL the implementor can fetch to
Expand Down
5 changes: 4 additions & 1 deletion static/compliance/source/universal/storyboard-schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,10 @@
#
# --- Validation ---
#
# check: string (what to validate: "response_schema", "field_present", "field_value",
# check: string (what to validate: "response_schema", "field_present",
# "envelope_field_present" (walks protocol-envelope.json instead of
# response_schema_ref — use for top-level envelope fields like `status`),
# "field_value",
# "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", "a2a_submitted_artifact")
Expand Down
6 changes: 4 additions & 2 deletions static/compliance/source/universal/v3-envelope-integrity.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ narrative: |
docs/building/implementation/task-lifecycle.mdx.

This storyboard documents the machine-check assertion and asserts the canonical v3
`status` field is present. The explicit envelope-root field-absence checks
`status` field is present using the `envelope_field_present` check type (added in
adcp-client#1045), which walks the protocol envelope rather than the inner response
schema. The explicit envelope-root field-absence checks
(asserting task_status and response_status are absent) require `field_absent`
runner support in @adcp/client — those checks are marked TODO below and are not
executed until the runner ships that check type. The schema-level constraint
Expand Down Expand Up @@ -82,7 +84,7 @@ phases:
validations:
- check: response_schema
description: "Response matches get-adcp-capabilities-response.json schema"
- check: field_present
- check: envelope_field_present
path: "status"
description: "Envelope carries the canonical v3 status field"
# TODO: restore these as field_absent checks once @adcp/client runner ships
Expand Down
10 changes: 10 additions & 0 deletions tests/lint-storyboard-contradictions.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,16 @@ test('classifyOutcome extracts error_code allowed_values as a Set', () => {
assert.deepEqual([...outcome.codes].sort(), ['A', 'B']);
});

test('classifyOutcome treats envelope_field_present as success assertion', () => {
const step = {
validations: [
{ check: 'envelope_field_present', path: 'status' },
],
};
const outcome = classifyOutcome(step);
assert.equal(outcome.kind, 'success');
});

test('outcomesAgree: error sets with overlap agree, disjoint disagree', () => {
const a = { kind: 'error', codes: new Set(['X', 'Y']) };
const b = { kind: 'error', codes: new Set(['Y', 'Z']) };
Expand Down