feat(server): default validation=strict in serve() — wire-conformance by default#439
Merged
feat(server): default validation=strict in serve() — wire-conformance by default#439
Conversation
… by default
Promote strict-by-default schema validation across `serve()`,
`create_mcp_server()`, `create_a2a_server()`, and the `ADCPAgentExecutor`
constructor. Adopters who omitted the `validation=` kwarg previously got
no enforcement; the recent `pricing_options` regression
(`{"type", "rate"}` vs spec `{"pricing_model", "fixed_price"}`) shipped
because Pydantic models with `extra="allow"` silently swallowed the
unknown shape past type-validation. Strict-by-default puts the
schema check on every adopter's serve path so the next bug of this
class fails on first call rather than during a buyer's storyboard run.
Default values resolve to a shared canonical
`SERVER_DEFAULT_VALIDATION = ValidationHookConfig(requests="strict",
responses="strict")` exposed from `adcp.validation` and re-aliased as
`adcp.server.serve.DEFAULT_VALIDATION`. Adopters opt out via
`validation=ValidationHookConfig(responses="warn")` (warn-only) or
`validation=None` (off entirely) — both paths are documented and
exercised by tests.
Test fixtures focused on transport plumbing (middleware composition,
context-factory propagation, parser dispatch, idempotency scoping) opt
out via `validation=None` rather than grow full spec-conformant
`Product` / `adcp.idempotency` payloads on minimal stubs. Affected
files: `tests/test_a2a_server.py` (module-level `ADCPAgentExecutor`
wrapper sets `validation=None` once), `tests/test_handler_typevar.py`,
`tests/test_mcp_middleware_composition.py`,
`tests/test_server_caller_identity.py`. New
`tests/test_serve_validation_default.py` pins the strict default in
`serve` / `create_mcp_server` / `create_a2a_server` signatures.
The v3 reference seller already opted into strict; its `validation=`
arg is now redundant with the framework default but kept explicit so
the seller's posture remains self-documenting.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1583258 to
68c91b3
Compare
…ation
Three integration tests under tests/integration/ use stub handlers
that send synthetic non-spec payloads (e.g. {'brief': 'x'}) to
exercise A2A context-id passthrough and v0.3 wire compat — not
request shape conformance. The new strict default in serve() correctly
caught their non-spec payloads (catch is a feature) but these tests
shouldn't validate at all. Pass validation=None on the create_a2a_server
sites, matching the same pattern used for unit-test fixtures.
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
serve(),create_mcp_server(),create_a2a_server(), andADCPAgentExecutor.__init__. Adopters who omitvalidation=now get strict requests + strict responses; thepricing_optionsclass of bug (extra=\"allow\"Pydantic silently swallowing an unknown shape) fails on first call rather than during a buyer's storyboard run.adcp.validation.SERVER_DEFAULT_VALIDATIONand is re-aliased asadcp.server.serve.DEFAULT_VALIDATION. Adopters opt out viavalidation=ValidationHookConfig(responses=\"warn\")(warn-only on response drift) orvalidation=None(off entirely).validation=Nonerather than grow full spec-conformantProduct/adcp.idempotencypayloads on minimal stubs.Test fixtures touched
Count: 4 test files (19 transport-plumbing tests originally surfaced as failures under strict-by-default; all now pass with explicit
validation=None):tests/test_a2a_server.py— module-levelADCPAgentExecutorwrapper setsvalidation=Noneonce for all 17 dispatch sitestests/test_handler_typevar.py— 2 sites addvalidation=Nonetests/test_mcp_middleware_composition.py— 2create_mcp_server(...)fixtures addvalidation=Nonetests/test_server_caller_identity.py— 4ADCPAgentExecutor(...)constructions addvalidation=NoneNew tests
tests/test_serve_validation_default.py— pins the strict default inserve/create_mcp_server/create_a2a_serversignatures viainspect.signature.tests/test_serve_validation_passthrough.py— replacedtest_serve_validation_default_is_nonewithtest_serve_validation_default_is_strictand addedtest_serve_validation_explicit_none_disables.Test plan
ruff check,mypy, pre-commit hooks pass.validation=kwarg now redundant with framework default but kept self-documenting).serve(handler)with no args now get strict validation; logs/errors should reflect VALIDATION_ERROR on the first malformed call.🤖 Generated with Claude Code