feat(validation): schema-driven validation with client hooks and opt-in server middleware#694
Merged
Conversation
…in server middleware Adds JSON-schema validation (AJV) against the bundled AdCP schemas on both sides of the wire, so field-name drift is caught at the SDK layer instead of at storyboard-run time. Closes #688. - Core validator loads `bundled/` sync + flat-tree async variants, selects the response variant by `status` shape, emits structured `VALIDATION_ERROR` with JSON Pointer + schema path - Client: `validation.requests` / `validation.responses` on SingleAgentClient, default request=warn / response=strict-in-dev, `off` short-circuits - Server: opt-in `validation` on createAdcpServer; strict returns `adcpError('VALIDATION_ERROR')` with `details.issues` carrying every pointer - Build: copies `schemas/cache/<ver>/{bundled,core,...}` → `dist/lib/schemas-data/` - 28 new tests, all 3910 pass Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI's code-quality integrity job runs `npm clean && build:lib` without first running `sync-schemas`, so the cache at schemas/cache/<ver>/ isn't present. Skip the copy with a warning so the build still succeeds — the runtime loader falls back to the same source path and tests that need the schemas run from the Test & Build job where sync-schemas is wired in. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Upstream sales-catalog-driven storyboard adds an expect_substitution_safe step (runner inspects the preview artifact from a prior step). It is a harness assertion, not an AdCP tool, so it belongs alongside the expect_webhook* pseudo-tasks in HARNESS_TASKS. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolved package.json/package-lock.json conflicts (both branches added to dependencies — kept ajv + ajv-formats alongside fast-check). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bokelley
added a commit
that referenced
this pull request
Apr 21, 2026
Resolves two conflicts in generated files (core.generated.ts, schemas.generated.ts) by regenerating after `sync-schemas`. Also aligns the conformance schema loader with main's new `copy-schemas-to-dist.ts` pattern from #694: prefer `dist/lib/schemas-data/<ver>/bundled/` (staged at build time) and fall back to `schemas/cache/<ver>/bundled/` for dev. Removes the now- redundant `schemas/cache/latest/bundled/**/*.json` entry from the package's `files` field — the copy script ships them through `dist/lib/**` instead. `detectSchemaVersion()` now reads the canonical `ADCP_VERSION` constant from `src/lib/version.ts` (kept in sync by `sync-version`) rather than reading the on-disk `ADCP_VERSION` file at runtime. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced Apr 21, 2026
Closed
bokelley
added a commit
that referenced
this pull request
Apr 22, 2026
Flip createAdcpServer's request validation default from 'off' to 'warn'
when NODE_ENV !== 'production', mirroring the asymmetric default already
in place for responses ('strict' in dev/test, 'off' in production).
Production behaviour is unchanged: the default stays 'off' when
NODE_ENV === 'production', so prod request paths pay no AJV cost.
Warn mode logs a single Schema validation warning (request) line per
mismatched payload through the configured logger and still dispatches
to the handler — nothing is rejected. Keeps the two validation sides
symmetric and surfaces upstream schema tightenings (e.g. adcp#2795's
required asset_type discriminator) as diagnostics during handler
development instead of as a downstream VALIDATION_ERROR after deploy.
Opt out via validation: { requests: 'off' } or NODE_ENV=production.
Refs #694 (original intent for requests: 'warn'), #727 A (response-side
default precedent).
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merged
5 tasks
KonstantinMirin
pushed a commit
to KonstantinMirin/adcp-client-python
that referenced
this pull request
May 13, 2026
…in server middleware Port the TS SDK's schema validator (adcontextprotocol/adcp-client#694) so field-name drift is caught at the SDK layer instead of at storyboard-run time (closes adcontextprotocol#249). - Bundled AdCP JSON schemas drive validation via jsonschema; compiled validators cached by (tool, direction) and resolved against the packaged ``_schemas/`` tree or the repo-relative ``schemas/cache/``. - Client hooks: pre-send request validation + post-receive response validation on both MCP and A2A adapters, configurable per side (strict / warn / off). Threaded through ``ADCPClient(validation=...)``. - Server middleware: opt-in on ``create_tool_caller`` / ``create_mcp_tools`` — strict raises ``ADCPTaskError(VALIDATION_ERROR)`` with every issue under ``details.issues`` (JSON Pointer + keyword + schema path). - Async variants (``-submitted``, ``-working``, ``-input-required``) selected by payload ``status`` shape, not tool name alone. - ``scripts/bundle_schemas.py`` mirrors ``schemas/cache/`` → ``src/adcp/_schemas/`` before wheel build; wired into ``make regenerate-schemas``, ``make build``, and CI. Defaults diverge from the TS port: Python responses default to ``warn`` (not ``strict``) because the SDK had no pre-existing strict response validator to preserve — breaking existing tests that stub non-spec payloads would be too noisy. Set ``ADCP_ENV=dev`` or pass ``ValidationHookConfig(responses="strict")`` to opt in. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
TaskExecutor, configurable per side (strict/warn/off).offshort-circuits before AJV runs for perf-sensitive prod.createAdcpServer— strict returnsadcpError('VALIDATION_ERROR')with every issue carried underdetails.issues(JSON Pointer + keyword + schemaPath).-submitted,-working,-input-required) selected by payloadstatusshape, not just task name.schemas/cache/<ver>/{bundled,core,…}→dist/lib/schemas-data/<ver>/so the validator reads schemas from the installed package.Defaults
requests: 'warn'everywhere — strict-by-default would break callers that intentionally send partial payloads (error-path tests, exploratory probes). Storyboards and third-party clients setstrictexplicitly.responses: 'strict'in dev/test,'warn'in production — preserves existingstrictSchemaValidationcontract. LegacystrictSchemaValidation: falsestill maps to responsewarn.Test plan
test/lib/schema-validation.test.jsexercising the core validator (variant selection, JSON Pointer accuracy,additionalPropertiestolerance, mode defaults)test/lib/schema-validation-server.test.jsfor the server middleware viadispatchTestRequest🤖 Generated with Claude Code