feat(testing): add envelope_field_present storyboard check (adcp#3429)#1045
Conversation
Storyboards that assert envelope-level fields (status, task_id, adcp_version, errors) need a way to tell static drift detection to walk protocol-envelope.json instead of the per-tool response schema. field_present pointed at the inner response schema, which doesn't contain envelope fields, so the v3-envelope-integrity storyboard needed a VERIFIER_UNREACHABLE exemption. This adds envelope_field_present as a recognized check type: - Runtime: identical semantics to field_present (TaskResult merges envelope fields into its surface, so dispatch passes through to validateFieldPresent). The result reports check name verbatim so reporters can distinguish. - Drift: walks ProtocolEnvelopeSchema instead of TOOL_RESPONSE_SCHEMAS for envelope_field_present entries. New describe block covers the case; the field_present block stays pinned to inner-response checks. Forward-compatible with current 3.0.1 storyboards (no consumers yet). Lights up when upstream PR migrates v3-envelope-integrity.yaml. The VERIFIER_UNREACHABLE entry stays for now and is dropped after adcp 3.0.2 ships the storyboard migration. Tests: - 3 runtime cases (pass, missing field, missing path) - Drift detector picks up envelope_field_present entries when present Refs adcp#3429.
Two reviews (code-reviewer, ad-tech-protocol-expert) on adcp-client#1045 landed three things: - Doc bug: my comments and changeset listed `errors` and `adcp_version` as v3-envelope fields. Verified against schemas/cache/3.0.1/core/protocol-envelope.json — `errors` lives inside `payload`, and `adcp_version` / `adcp_major_version` are request-side only. The actual envelope fields are `status`, `task_id`, `message`, `replayed`, `governance_context`, `timestamp`, `context_id`, `push_notification_config`. Fixed comments in types.ts (union JSDoc) and storyboard-drift.test.js (filter loop comment), plus the changeset wording. - Companion check types: protocol expert flagged that shipping just `envelope_field_present` half-paves the cowpath — `replayed`/`status` storyboards will need value matchers next. Added `envelope_field_value` and `envelope_field_value_or_absent` alongside, with the same passthrough-to-existing-handler dispatch pattern. Also wired both into scripts/conformance-replay.ts's IMPLEMENTED_CHECKS so storyboard replay grades them. Filed `field_absent` + `envelope_field_absent` as a follow-up since they need a new runtime check (no current `field_absent` handler). - Nit: `validateFieldPresent`'s `checkName` ternary is now just `validation.check` — the dispatcher has already narrowed the type by the time the value-shaping function runs, so the conditional was defensive coding without a real failure mode. Same simplification in `validateFieldValue` and `validateFieldValueOrAbsent`. - New tests: 4 cases for the new value checks (pass/fail x present/absent). Total: 514 tests pass, 0 fail.
|
Triage note: #1046 ( Generated by Claude Code |
|
Yes, fold it. The rebase concern is real and the scope is genuinely small — Two things to update before pushing:
Once those land on the branch, the Generated by Claude Code |
Per @bokelley's review comment: both checks share the same handler path as `envelope_field_present`, so the runtime delta is a single `validateFieldAbsent` function and two `case` entries in the switch. - `field_absent` / `envelope_field_absent` added to `StoryboardValidationCheck` type union - `validateFieldAbsent`: passes when path is absent (undefined/null), fails when present — mirrors `validateFieldPresent` semantics inverted - Drift detector: both checks collected by `collectFieldValidations` but skip reachability assertions (absence checks have no schema target) - 6 new tests in `storyboard-validations.test.js` (pass/fail/no-path for both `field_absent` and `envelope_field_absent`) - Changeset updated to list all five new check types; removes the "future PR" note since they ship here Unlocks the `v3-envelope-integrity.yaml` TODO block's MUST-NOT assertions (`task_status`/`response_status`) without a second SDK release. https://claude.ai/code/session_01R6VkP124L1RGqVART85gxo
|
Done — What landed:
The Generated by Claude Code |
|
Confirmed — the fold looks complete. All five check types ( Generated by Claude Code |
|
Acknowledged — noted that the fold is confirmed complete and the Generated by Claude Code |
Summary
Refs adcp#3429. Adds runtime + drift support for the storyboard validation that targets the v3 protocol envelope (`status`, `task_id`, `adcp_version`, `errors`) instead of per-tool response schemas.
Why
The 3.0.1 spec ships `universal/v3-envelope-integrity.yaml` with `field_present: status`, but `status` is on the v3 envelope (`protocol-envelope.json`), not the inner `get-adcp-capabilities-response.json`. The drift detector walks the inner response, so the assertion can't be statically verified — adcp-client#1039 had to add a `VERIFIER_UNREACHABLE` exemption.
adcp#3429 triage proposed two fixes:
This PR is the SDK side of Option B. Once the upstream storyboard migrates `field_present: status` → `envelope_field_present: status`, the SDK's drift detector validates against the envelope schema and the `VERIFIER_UNREACHABLE` exemption can be dropped.
What changed
`src/lib/testing/storyboard/types.ts` — `'envelope_field_present'` joins the `StoryboardValidationCheck` union with a JSDoc explaining the scope difference.
`src/lib/testing/storyboard/validations.ts` — `runValidation` dispatches `envelope_field_present` to `validateFieldPresent`. Runtime semantics are identical: `TaskResult` already merges envelope fields into its surface, so `data.status` is the envelope's `status`. The result object reports the original check name verbatim (`'envelope_field_present'`) so reporters can distinguish.
`test/lib/storyboard-drift.test.js` — `collectFieldValidations` picks up `envelope_field_present` entries; a new `describe` block walks `ProtocolEnvelopeSchema` instead of `TOOL_RESPONSE_SCHEMAS[task]`. Existing `field_present` block continues to pin to per-tool response schemas.
Forward-compat
No current 3.0.1 storyboard uses `envelope_field_present` yet. The SDK accepts it now so when the upstream storyboard PR lands (and `npm run sync-schemas` pulls the new compliance bundle), drift detection picks up the new check immediately. The `VERIFIER_UNREACHABLE` exemption in adcp-client#1039 gets dropped in a follow-up after the upstream change ships.
Test plan
🤖 Generated with Claude Code