refactor(BA-6003): bulk-migrate all pydantic BaseModel subclasses to BackendAISchema#11554
Merged
Merged
Conversation
c58ca24 to
7e3616d
Compare
d01a227 to
12d448d
Compare
7e3616d to
8c2c119
Compare
12d448d to
93386f3
Compare
5 tasks
8c2c119 to
ce7ae34
Compare
93386f3 to
7217ac2
Compare
ce7ae34 to
97df2b1
Compare
7217ac2 to
1b8f247
Compare
97df2b1 to
b10f3aa
Compare
1b8f247 to
72f3436
Compare
b10f3aa to
78fe199
Compare
482c45d to
62cdbeb
Compare
78fe199 to
99c98c9
Compare
62cdbeb to
bf81956
Compare
99c98c9 to
91d023d
Compare
bf81956 to
a868875
Compare
91d023d to
d47aaed
Compare
a868875 to
fe7aeca
Compare
d47aaed to
3f520c5
Compare
fe7aeca to
2113729
Compare
jopemachine
commented
May 12, 2026
9bfc3ec to
4ffec61
Compare
ddcbcae to
942880b
Compare
a175db2 to
a7c6935
Compare
seedspirit
previously approved these changes
May 12, 2026
HyeockJinKim
previously approved these changes
May 12, 2026
1d0a038 to
fdd1034
Compare
Base automatically changed from
fix/BA-5978-pydantic-validation-domain-errors
to
main
May 12, 2026 09:12
The base branch was changed.
…endAISchema Stacked follow-up to #11514 (BA-5978), now squashed into a single commit on top of main since the parent landed. * Migrate every remaining ``class Foo(BaseModel)`` subclass under ``src/ai/backend/`` to ``BackendAISchema`` (~120 classes across ~120 files). ``RootModel`` subclasses and ``TypeDecorator[BaseModel]`` generics are intentionally out of scope. * Promote the three standalone classes in ``common/types.py`` (``MountInfoEntry``, ``MountPoint``, ``ResourceSlotEntry``) and the ``_OpenAICompatModel`` SDK response base. * Narrow ``type[BaseModel]`` -> ``type[BackendAISchema]`` at helper / decorator boundaries (``common/meta``, ``common/configs/*``, ``manager/openapi``, ``manager/sokovan/deployment/strategy``, ``appproxy/common``, ``appproxy/coordinator/models``). * Collapse the dual ``except BackendAISchemaValidationFailed`` / ``except ValidationError`` blocks introduced when call sites were swapped over into a single tuple-catch; the ``ValidationError`` arm still covers any stray plain ``BaseModel`` subclass that bypasses the override. * Route the seven CLI ``_build_dto`` helpers through ``model_validate`` so they surface the wrapped ``BackendAISchemaValidationFailed``. * Update test assertions across ``tests/unit`` and ``tests/component`` to accept the wrapped exception via ``pytest.raises((BackendAISchemaValidationFailed, ValidationError))``. * News fragment ``changes/11554.enhance.md``. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fdd1034 to
60ab51b
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
This PR completes a bulk, mechanical migration across the Backend.AI codebase from direct pydantic.BaseModel subclasses to BackendAISchema, so validation via model_validate() / model_validate_json() raises a domain-specific BackendAISchemaValidationFailed (HTTP 400) instead of leaking raw Pydantic ValidationError (500s). It also updates a number of validation-error catch sites and CLI DTO builders to use the new behavior consistently.
Changes:
- Migrate many
BaseModelsubclasses (DTOs/configs/internal schemas) to inheritBackendAISchema. - Update call sites to catch
(BackendAISchemaValidationFailed, ValidationError)and/or switch DTO construction tomodel_validate(...). - Update tests and add a changelog entry for the migration.
Reviewed changes
Copilot reviewed 149 out of 149 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/common/configs/test_meta.py | Update test models to inherit BackendAISchema. |
| tests/unit/common/configs/test_inspector.py | Update test models to inherit BackendAISchema. |
| tests/unit/common/configs/test_generator.py | Update test models to inherit BackendAISchema. |
| src/ai/backend/storage/volumes/stats/types.py | Redis-serialized model migrated to BackendAISchema. |
| src/ai/backend/storage/volumes/hammerspace/types.py | Config model migrated to BackendAISchema. |
| src/ai/backend/storage/volumes/hammerspace/schema/uoid.py | Schema model migrated to BackendAISchema. |
| src/ai/backend/storage/volumes/hammerspace/schema/storage_volume.py | Schema model migrated to BackendAISchema. |
| src/ai/backend/storage/volumes/hammerspace/schema/site.py | Schema model migrated to BackendAISchema. |
| src/ai/backend/storage/volumes/hammerspace/schema/share.py | Schema models migrated to BackendAISchema. |
| src/ai/backend/storage/volumes/hammerspace/schema/placement_objective.py | Schema model migrated to BackendAISchema. |
| src/ai/backend/storage/volumes/hammerspace/schema/objective.py | Schema models migrated to BackendAISchema. |
| src/ai/backend/storage/volumes/hammerspace/schema/node.py | Schema model migrated to BackendAISchema. |
| src/ai/backend/storage/volumes/hammerspace/schema/metric.py | Schema models migrated to BackendAISchema. |
| src/ai/backend/storage/volumes/hammerspace/schema/logical_volume.py | Schema model migrated to BackendAISchema. |
| src/ai/backend/storage/volumes/hammerspace/schema/location.py | Schema models migrated to BackendAISchema. |
| src/ai/backend/storage/volumes/hammerspace/schema/df_entry.py | Schema model migrated to BackendAISchema. |
| src/ai/backend/storage/volumes/hammerspace/schema/capacity.py | Schema model migrated to BackendAISchema. |
| src/ai/backend/storage/volumes/hammerspace/schema/address.py | Schema models migrated to BackendAISchema. |
| src/ai/backend/storage/volumes/hammerspace/client.py | Catch BackendAISchemaValidationFailed during parsing. |
| src/ai/backend/manager/types.py | Migrate manager model to BackendAISchema. |
| src/ai/backend/manager/sokovan/recorder/types.py | Migrate recorder models to BackendAISchema. |
| src/ai/backend/manager/sokovan/deployment/strategy/types.py | Registry type annotation updated to BackendAISchema. |
| src/ai/backend/manager/services/metric/types.py | Migrate service model to BackendAISchema. |
| src/ai/backend/manager/scheduler/types.py | Scheduler state models migrated to BackendAISchema. |
| src/ai/backend/manager/plugin/totp/config.py | Plugin config migrated to BackendAISchema. |
| src/ai/backend/manager/plugin/openid/config.py | Plugin configs migrated to BackendAISchema. |
| src/ai/backend/manager/plugin/keypair/webapp.py | Web request model migrated to BackendAISchema. |
| src/ai/backend/manager/plugin/keypair/utils.py | Token model migrated to BackendAISchema. |
| src/ai/backend/manager/openapi.py | OpenAPI extraction now targets BackendAISchema models. |
| src/ai/backend/manager/models/scaling_group/types.py | Spec model migrated to BackendAISchema. |
| src/ai/backend/manager/models/scaling_group/row.py | Options model migrated to BackendAISchema. |
| src/ai/backend/manager/models/resource_slot/types.py | Config model migrated to BackendAISchema. |
| src/ai/backend/manager/models/prometheus_query_preset/row.py | Options model migrated to BackendAISchema. |
| src/ai/backend/manager/models/health.py | Health models migrated to BackendAISchema. |
| src/ai/backend/manager/models/deployment_revision_preset/types.py | DTO model migrated to BackendAISchema. |
| src/ai/backend/manager/models/deployment_policy/row.py | Deployment policy specs migrated to BackendAISchema. |
| src/ai/backend/manager/models/base.py | Pydantic list-column entries migrated to BackendAISchema. |
| src/ai/backend/manager/idle.py | Threshold model migrated to BackendAISchema. |
| src/ai/backend/manager/data/session/types.py | Session history model migrated to BackendAISchema. |
| src/ai/backend/manager/data/deployment/types.py | Deployment models migrated to BackendAISchema. |
| src/ai/backend/manager/data/deployment/inference_runtime_config.py | Runtime config base migrated to BackendAISchema. |
| src/ai/backend/manager/config/bootstrap.py | Bootstrap config migrated to BackendAISchema. |
| src/ai/backend/manager/clients/agent/client.py | RPC envelope migrated to BackendAISchema. |
| src/ai/backend/manager/bgtask/tasks/purge_images.py | Task/spec models migrated to BackendAISchema. |
| src/ai/backend/manager/api/utils.py | Catch schema validation failures during request parsing. |
| src/ai/backend/manager/api/gql/graphql_ws/types.py | WS protocol models migrated to BackendAISchema. |
| src/ai/backend/logging/validation_context.py | Validation context migrated to BackendAISchema. |
| src/ai/backend/logging/config.py | Base logging config model migrated to BackendAISchema. |
| src/ai/backend/install/types.py | Installer models migrated to BackendAISchema. |
| src/ai/backend/common/types.py | Promote remaining standalone models to BackendAISchema. |
| src/ai/backend/common/typed_validators.py | Catch (BackendAISchemaValidationFailed, ValidationError). |
| src/ai/backend/common/service_discovery/service_discovery.py | Service-discovery models migrated to BackendAISchema. |
| src/ai/backend/common/meta/meta.py | Meta helpers now typed to BackendAISchema. |
| src/ai/backend/common/events/event_types/service_discovery/anycast.py | Event payload models migrated to BackendAISchema. |
| src/ai/backend/common/events/event_types/notification/anycast.py | Event model migrated to BackendAISchema. |
| src/ai/backend/common/dto/storage/request.py | Token payload model migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/vfolder/response.py | Response DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/v2/user/response.py | Response DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/v2/runtime_variant_preset/types.py | DTO types migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/v2/group/response.py | Response DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/v2/domain/response.py | Response DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/v2/deployment/types.py | DTO types migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/user/response.py | Response DTO migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/template/response.py | Template DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/streaming/types.py | Streaming DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/storage/response.py | Storage DTO migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/scaling_group/response.py | Response DTO migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/resource_slot/response.py | Response DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/resource_policy/response.py | Response DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/rbac/response.py | Response DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/quota_scope/response.py | Response DTO migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/prometheus_query_preset/response.py | Response DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/pagination.py | Pagination DTO migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/notification/response.py | Response DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/model_serving/response.py | Response DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/infra/response.py | Response DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/image/response.py | Response DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/group/response.py | Response DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/fair_share/response.py | Fair-share DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/fair_share/request.py | Request input migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/event_stream/response.py | SSE payload migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/error_log/response.py | Response DTO migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/domain/response.py | Response DTO migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/deployment/response.py | Deployment response DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/config/response.py | Config response DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/auto_scaling_rule/response.py | Response DTO migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/auth/types.py | Auth response types migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/artifact/response.py | Artifact response DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/artifact_registry/response.py | Artifact-registry response DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/artifact_registry/request.py | Request input migrated to BackendAISchema. |
| src/ai/backend/common/dto/manager/agent/response.py | Agent response DTO migrated to BackendAISchema. |
| src/ai/backend/common/dto/internal/health.py | Internal health DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/clients/prometheus/response.py | Prometheus DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/clients/prometheus/request.py | Prometheus request DTO migrated to BackendAISchema. |
| src/ai/backend/common/dto/clients/openai_compat/response.py | OpenAI-compat DTO base migrated to BackendAISchema. |
| src/ai/backend/common/dto/clients/openai_compat/request.py | OpenAI-compat request DTOs migrated to BackendAISchema. |
| src/ai/backend/common/dto/agent/response.py | Agent DTOs migrated to BackendAISchema. |
| src/ai/backend/common/data/storage/types.py | Storage data models migrated to BackendAISchema. |
| src/ai/backend/common/data/storage/registries/types.py | Registry data models migrated to BackendAISchema. |
| src/ai/backend/common/data/notification/types.py | Notification config models migrated to BackendAISchema. |
| src/ai/backend/common/data/notification/messages.py | Message base migrated to BackendAISchema. |
| src/ai/backend/common/data/image/types.py | Image info migrated to BackendAISchema. |
| src/ai/backend/common/data/bgtask/types.py | Background-task progress migrated to BackendAISchema. |
| src/ai/backend/common/data/artifact/types.py | Artifact tracking models migrated to BackendAISchema. |
| src/ai/backend/common/data/artifact_registry/types.py | Registry state model migrated to BackendAISchema. |
| src/ai/backend/common/data/agent/types.py | Agent data models migrated to BackendAISchema. |
| src/ai/backend/common/container_registry.py | Registry model migrated to BackendAISchema. |
| src/ai/backend/common/configs/redis.py | Redis config models migrated to BackendAISchema. |
| src/ai/backend/common/configs/inspector/extractor.py | Inspector typed to BackendAISchema. |
| src/ai/backend/common/configs/generator/toml.py | TOML generator typed to BackendAISchema. |
| src/ai/backend/common/clients/valkey_client/valkey_session/types.py | Valkey session models migrated to BackendAISchema. |
| src/ai/backend/common/clients/valkey_client/valkey_artifact/client.py | Catch schema validation failures for cached payloads. |
| src/ai/backend/common/bgtask/types.py | Background-task key info migrated to BackendAISchema. |
| src/ai/backend/common/bgtask/task/base.py | Background-task base models migrated to BackendAISchema. |
| src/ai/backend/common/api_handlers.py | Catch schema validation failures during param extraction. |
| src/ai/backend/client/cli/v2/model_card/commands.py | Use model_validate and catch schema validation failures. |
| src/ai/backend/client/cli/v2/deployment/chat/types.py | CLI cache/config/history models migrated to BackendAISchema. |
| src/ai/backend/client/cli/v2/admin/runtime_variant.py | Use model_validate and catch schema validation failures. |
| src/ai/backend/client/cli/v2/admin/runtime_variant_preset.py | Use model_validate and catch schema validation failures. |
| src/ai/backend/client/cli/v2/admin/resource_preset.py | Use model_validate and catch schema validation failures. |
| src/ai/backend/client/cli/v2/admin/resource_policy.py | Use model_validate and catch schema validation failures. |
| src/ai/backend/client/cli/v2/admin/model_card.py | Use model_validate and catch schema validation failures. |
| src/ai/backend/client/cli/v2/admin/deployment_revision_preset.py | Use model_validate and catch schema validation failures. |
| src/ai/backend/appproxy/worker/config.py | Catch (BackendAISchemaValidationFailed, ValidationError) in config load. |
| src/ai/backend/appproxy/worker/api/setup.py | Request/response models migrated to BackendAISchema. |
| src/ai/backend/appproxy/coordinator/types.py | App config migrated to BackendAISchema. |
| src/ai/backend/appproxy/coordinator/server.py | Log schema validation errors safely (errors() dump). |
| src/ai/backend/appproxy/coordinator/models/base.py | Structured JSON column schema typed to BackendAISchema. |
| src/ai/backend/appproxy/coordinator/api/worker_v2.py | API models migrated to BackendAISchema. |
| src/ai/backend/appproxy/coordinator/api/worker_v1.py | API response model migrated to BackendAISchema. |
| src/ai/backend/appproxy/coordinator/api/types.py | Shared API models migrated to BackendAISchema. |
| src/ai/backend/appproxy/coordinator/api/slot_v2.py | Request/response models migrated to BackendAISchema. |
| src/ai/backend/appproxy/coordinator/api/slot_v1.py | Response model migrated to BackendAISchema. |
| src/ai/backend/appproxy/coordinator/api/proxy.py | Request/response models migrated to BackendAISchema. |
| src/ai/backend/appproxy/coordinator/api/health.py | Health response models migrated to BackendAISchema. |
| src/ai/backend/appproxy/coordinator/api/endpoint.py | Endpoint API models migrated to BackendAISchema. |
| src/ai/backend/appproxy/coordinator/api/conf.py | Token response model migrated to BackendAISchema. |
| src/ai/backend/appproxy/coordinator/api/circuit_v2.py | Bulk request model migrated to BackendAISchema. |
| src/ai/backend/appproxy/common/utils.py | Catch schema validation failures in request parsing. |
| src/ai/backend/appproxy/common/types.py | Core AppProxy models migrated to BackendAISchema. |
| src/ai/backend/appproxy/common/openapi.py | OpenAPI schema parsing typed to BackendAISchema. |
| src/ai/backend/appproxy/common/config.py | Base schema migrated to BackendAISchema. |
| src/ai/backend/agent/server.py | Catch BackendAISchemaValidationFailed for config validation. |
| src/ai/backend/agent/scratch/types.py | Scratch model migrated to BackendAISchema. |
| src/ai/backend/agent/proxy.py | Path-pair model migrated to BackendAISchema. |
| src/ai/backend/agent/kernel_registry/types.py | Recovery model migrated to BackendAISchema. |
| src/ai/backend/account_manager/config.py | Account-manager base schema migrated to BackendAISchema. |
| src/ai/backend/account_manager/api/utils.py | Catch schema validation failures in request parsing. |
| changes/11554.enhance.md | Changelog entry for bulk migration. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
237
to
+241
| f"type={first_error['type']}", # format as symbol | ||
| *(f"{k}={v!r}" for k, v in metadata.items()), | ||
| ] | ||
| msg = f"{first_error['msg']} [{', '.join(metadata_formatted_items)}]" | ||
| # To reuse the json serialization provided by pydantic, we call ex.json() and re-parse it. | ||
| raise InvalidAPIParameters(msg, extra_data=load_json(ex.json())) from ex | ||
| raise InvalidAPIParameters(msg, extra_data={"errors": ex.errors()}) from ex |
Comment on lines
+239
to
+241
| raise InvalidAPIParameters( | ||
| "Input validation error", | ||
| extra_data={"errors": e.errors()}, |
Comment on lines
+181
to
+183
| raise InvalidAPIParameters( | ||
| "Input validation error", | ||
| extra_data={"errors": e.errors()}, |
* Sort imports in tests/unit/common/configs/{test_meta,test_generator,test_inspector}.py
(ruff I001).
* Expand the catch tuple in tests/unit/common/test_typed_validators.py
to also accept BackendAISchemaValidationFailed alongside ValidationError
and TypeError — HostPortPair now inherits BackendAISchema so
model_validate raises the wrapped exception.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
b6db4c1 to
26a0e95
Compare
seedspirit
approved these changes
May 12, 2026
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.
Stacked PRs
This PR is part of a stack:
fix/BA-5978-pydantic-validation-domain-errors(parent)Foundational machinery:
BackendAISchema,BackendAISchemaValidationFailed,build_validation_erroroverride hook, and the four model overrides (ModelDefinition,ModelDefinitionDraft,SessionSpec,DeploymentConfigInput). Also promotes the foundational base classes so anything that already inherits them participates automatically. Merge first.feat/BA-6003-bulk-basemodel-migration← this PRMechanical migration on top of refactor(BA-5978): introduce BackendAISchema for per-domain validation errors #11514: every remaining
class Foo(BaseModel)subclass undersrc/ai/backend/switched toBackendAISchema, the matchingexcept ValidationError→except (BackendAISchemaValidationFailed, ValidationError)swaps, and the seven CLI_build_dtohelpers routed throughmodel_validate.Summary
Stacked on top of #11514 (BA-5978).
Follow-up to BA-5978. The parent PR introduces
BackendAISchemaand promotes the project's foundational pydantic base classes (BaseRequestModel,BaseFieldModel,BaseResponseModel,BaseConfigSchema,BaseConfigModel,_OptionsBaseModel,_DraftBaseModel,_SpecBaseModel,BaseAgentRequestModel,BaseAgentResponseModel, and the test/tester variants). This PR finishes the migration by:class Foo(BaseModel)subclass undersrc/ai/backend/toclass Foo(BackendAISchema)(121 files, ~120 classes).common/types.py(MountInfoEntry,MountPoint,ResourceSlotEntry).ai.backend.logging.config.BaseConfigModelandai.backend.logging.validation_context.BaseConfigValidationContexttoo (no circular import sincecommon.typesdoesn't transitively reachai.backend.logging)..model_validate(...)on a now-migrated class, replacingexcept ValidationErrorwith a single tuple-catchexcept (BackendAISchemaValidationFailed, ValidationError) as e:. Both classes expose the sameerrors()interface, so the handler body stays uniform; theValidationErrorarm continues to cover any stray plainBaseModelsubclass that bypasses the override.tests/unit/manager/test_errors.pyunit-test file.Naming note
The parent PR (#11514) renamed the foundational types from
BackendAIModel/BackendAIModelValidationFailed/ModelValidationFailureInfotoBackendAISchema/BackendAISchemaValidationFailed/SchemaValidationFailureInfoto avoid confusion with LLM-model terminology in client-facing surfaces. This PR applies the same rename to every migrated call site.Out of scope
RootModelsubclasses — different pydantic base, cannot inheritBackendAISchema.TypeDecorator[BaseModel]generics (SQLAlchemy column types).Model(field=...)) call sites — still raise rawValidationErrorbecause the auto-conversion is opt-in on themodel_validateclassmethods only.Test plan
pants lint --changed-since=...cleanpants check --changed-since=...cleanPOST /v2/domainswith{}triggersBackendAISchemaValidationFailedwith structured per-field errors.🤖 Generated with Claude Code