Problem
BaseValueSchema.to_value_cls guards the ValueRegistry.load_value() call behind if not self.model_extra:
def to_value_cls(self, *extra_defs):
if not self.model_extra:
value_cls = ValueRegistry.DEFAULT.load_value(self)
if value_cls is not None:
return value_cls
return self.build_value_cls(*extra_defs)
When a registered Value subclass has json_schema_extra (e.g. {"x-resource-type": "collection"}), its generated JSON schema includes extra fields that end up in model_extra when parsed back as a ValueSchema. This causes the registry lookup to be skipped entirely, and build_value_cls resolves the schema structurally — e.g. AceTeamCollectionIdValue(Value[str]) becomes a plain StringValue subclass instead of the registered class.
This breaks can_cast_to because casts registered on AceTeamCollectionIdValue are not found on the anonymous StringValue subclass.
Expected behavior
to_value_cls should always consult the registry first. When model_extra contains non-type-semantic metadata (like x-resource-type), the registered class should still be returned. When model_extra contains actual constraints (like minimum, maxLength), a constrained subclass of the registered class should be built — not a subclass of the structural base type.
Suggested fix
def to_value_cls(self, *extra_defs):
value_cls = ValueRegistry.DEFAULT.load_value(self)
if value_cls is not None:
if not self.model_extra:
return value_cls
# Build a constrained subclass of the registered class,
# not the structural base (StringValue, IntegerValue, etc.)
return self.build_value_cls(*extra_defs, base_cls=value_cls)
return self.build_value_cls(*extra_defs)
This requires build_value_cls implementations to accept an optional base_cls override, falling back to the current structural base when not provided.
Workaround
We are currently monkeypatching to_value_cls to always try the registry first and return the registered class directly (ignoring constraints from model_extra). This is lossy for the constraint case but fixes the cast resolution.
Generated by Claude
Problem
BaseValueSchema.to_value_clsguards theValueRegistry.load_value()call behindif not self.model_extra:When a registered Value subclass has
json_schema_extra(e.g.{"x-resource-type": "collection"}), its generated JSON schema includes extra fields that end up inmodel_extrawhen parsed back as aValueSchema. This causes the registry lookup to be skipped entirely, andbuild_value_clsresolves the schema structurally — e.g.AceTeamCollectionIdValue(Value[str])becomes a plainStringValuesubclass instead of the registered class.This breaks
can_cast_tobecause casts registered onAceTeamCollectionIdValueare not found on the anonymousStringValuesubclass.Expected behavior
to_value_clsshould always consult the registry first. When model_extra contains non-type-semantic metadata (likex-resource-type), the registered class should still be returned. When model_extra contains actual constraints (likeminimum,maxLength), a constrained subclass of the registered class should be built — not a subclass of the structural base type.Suggested fix
This requires
build_value_clsimplementations to accept an optionalbase_clsoverride, falling back to the current structural base when not provided.Workaround
We are currently monkeypatching
to_value_clsto always try the registry first and return the registered class directly (ignoring constraints from model_extra). This is lossy for the constraint case but fixes the cast resolution.Generated by Claude