FeatureSpec records feature semantics, definition identifiers, input requirements, shared
intermediates, symbolic costs, invariance claims, and references. The
catalogue renders registered instances of this model.
Backend-specific execution properties belong to FeatureCapability: supported devices,
dtypes, and the declared autograd behavior. They are separate from mathematical definitions.
@dataclass(frozen=True,slots=True)classFeatureSpec:"""Complete metadata contract for one individually selectable output."""name:strgroup:strkind:MetricKinddefinition:strsummary:strrequirements:frozenset[InputRequirement]intermediates:tuple[str,...]cost:CostModeldeterministic:boolinvariances:tuple[InvarianceClaim,...]=()references:tuple[Reference,...]=()legacy_names:tuple[str,...]=()minimum_observations:int=1notes:tuple[str,...]=field(default_factory=tuple)def__post_init__(self)->None:if_FEATURE_ID.fullmatch(self.name)isNone:raiseValueError(f"invalid feature name: {self.name!r}")ifnotself.grouporself.name.split(".",1)[0]!=self.group:raiseValueError("feature group must equal the first component of the feature name")if_DEFINITION_ID.fullmatch(self.definition)isNone:raiseValueError(f"invalid definition identifier: {self.definition!r}")ifnotself.summary.strip():raiseValueError("feature summary must not be empty")ifself.kindisMetricKind.LANDSCAPEandInputRequirement.Ynotinself.requirements:raiseValueError("landscape features must explicitly require objective observations y")ifself.kindisMetricKind.DESIGNandInputRequirement.Xnotinself.requirements:raiseValueError("design descriptors must explicitly require decision observations X")ifself.minimum_observations<1:raiseValueError("minimum_observations must be positive")iflen(set(self.intermediates))!=len(self.intermediates):raiseValueError("intermediate identifiers must be unique")transformations=[claim.transformationforclaiminself.invariances]iflen(set(transformations))!=len(transformations):raiseValueError("a feature may declare at most one claim per transformation")iflen(set(self.legacy_names))!=len(self.legacy_names):raiseValueError("legacy feature names must be unique")
@dataclass(frozen=True,slots=True)classCostModel:"""Auditable symbolic cost model for a single feature request."""tier:CostTiercpu:strmemory:stradditional_objective_evaluations:str="0"def__post_init__(self)->None:ifnotself.cpu.strip()ornotself.memory.strip():raiseValueError("CPU and memory cost descriptions must not be empty")ifnotself.additional_objective_evaluations.strip():raiseValueError("objective-evaluation cost must not be empty")
classCostTier(str,Enum):"""Coarse cost class used for discovery and safe defaults."""SAMPLE_ONLY="sample_only"ADDITIONAL_EVALUATIONS="additional_evaluations"OPTIMIZATION="optimization"
classInvarianceBehavior(str,Enum):"""Declared behavior under a transformation."""INVARIANT="invariant"EQUIVARIANT="equivariant"NON_INVARIANT="non_invariant"UNKNOWN="unknown"
classTransformation(str,Enum):"""Transformations considered by metamorphic verification."""ROW_PERMUTATION="row_permutation"VARIABLE_PERMUTATION="variable_permutation"X_TRANSLATION="x_translation"X_POSITIVE_SCALING="x_positive_scaling"X_ORTHOGONAL_ROTATION="x_orthogonal_rotation"Y_TRANSLATION="y_translation"Y_POSITIVE_SCALING="y_positive_scaling"OBJECTIVE_SENSE_REVERSAL="objective_sense_reversal"
@dataclass(frozen=True,slots=True)classReference:"""Literature or software reference supporting a feature definition."""citation:strdoi:str|None=Noneurl:str|None=Nonedef__post_init__(self)->None:ifnotself.citation.strip():raiseValueError("reference citation must not be empty")ifself.doiisNoneandself.urlisNone:raiseValueError("reference must provide a DOI or URL")
@dataclass(frozen=True,slots=True)classFeatureCapability:"""Execution properties that belong to an implementation, not its mathematics."""feature_name:strbackend:BackendNameautograd:AutogradSupportdevices:tuple[DeviceType,...]dtypes:tuple[FloatingDType,...]notes:tuple[str,...]=()def__post_init__(self)->None:ifnotself.feature_name:raiseValueError("feature name must not be empty")ifself.backendnotin("numpy","torch"):raiseValueError(f"unsupported backend: {self.backend!r}")ifself.autogradnotin("smooth","piecewise","none"):raiseValueError(f"unsupported autograd support: {self.autograd!r}")ifnotself.devices:raiseValueError("at least one device type is required")ifnotself.dtypes:raiseValueError("at least one floating dtype is required")ifany(devicenotin("cpu","cuda","mps")fordeviceinself.devices):raiseValueError(f"unsupported device types: {self.devices!r}")ifany(dtypenotin("float32","float64")fordtypeinself.dtypes):raiseValueError(f"unsupported floating dtypes: {self.dtypes!r}")iflen(set(self.devices))!=len(self.devices):raiseValueError("device types must be unique")iflen(set(self.dtypes))!=len(self.dtypes):raiseValueError("floating dtypes must be unique")