# Configuration Validation


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

## Schema Metadata Constants

Constants for field metadata keys used in dataclass configuration. These
enable validation and are compatible with JSON schema generation for UI
form builders.

## Field Validation

Functions for validating field values against metadata constraints.

------------------------------------------------------------------------

### validate_field_value

``` python

def validate_field_value(
    value:Any, # Value to validate
    metadata:Dict, # Field metadata containing constraints
    field_name:str='', # Field name for error messages
)->Tuple: # (is_valid, error_message)

```

*Validate a value against field metadata constraints.*

------------------------------------------------------------------------

### validate_config

``` python

def validate_config(
    config:Any, # Configuration dataclass instance to validate
)->Tuple: # (is_valid, error_message)

```

*Validate all fields in a configuration dataclass against their metadata
constraints.*

## Dataclass Configuration Utilities

These functions provide utilities for working with dataclass-based
capability configurations.

------------------------------------------------------------------------

### config_to_dict

``` python

def config_to_dict(
    config:Any, # Configuration dataclass instance
)->Dict: # Dictionary representation of the configuration

```

*Convert a configuration dataclass instance to a dictionary.*

Converts a dataclass configuration instance to a dictionary for
serialization or passing to other systems. Also accepts dict input for
passthrough convenience.

------------------------------------------------------------------------

### dict_to_config

``` python

def dict_to_config(
    config_class:Type, # Configuration dataclass type
    data:Optional=None, # Dictionary with configuration values
    validate:bool=False, # Whether to validate against metadata constraints
    strict:bool=True, # SG-8: reject unknown keys (default); set False to log+filter for forward-compat
)->T: # Instance of the configuration dataclass

```

*Create a configuration dataclass instance from a dictionary.*

SG-8: by default, unknown keys raise `CapabilityConfigError`. The
previous behavior (silently filter unknowns) is available via
`strict=False`, which logs a warning so the drift is still visible in
operator logs.

------------------------------------------------------------------------

### extract_defaults

``` python

def extract_defaults(
    config_class:Type, # Configuration dataclass type
)->Dict: # Default values from the dataclass

```

*Extract default values from a configuration dataclass type.*

## JSON Schema Conversion

Functions for converting dataclass configurations to JSON Schema format,
enabling automatic form generation in UIs.

------------------------------------------------------------------------

### dataclass_to_jsonschema

``` python

def dataclass_to_jsonschema(
    cls:type, # Dataclass with field metadata
)->Dict: # JSON schema dictionary

```

*Convert a dataclass to a JSON schema for form generation.*

``` python
# Test _python_type_to_json_type
from typing import List, Optional

assert _python_type_to_json_type(str) == {"type": "string"}
assert _python_type_to_json_type(int) == {"type": "integer"}
assert _python_type_to_json_type(float) == {"type": "number"}
assert _python_type_to_json_type(bool) == {"type": "boolean"}
assert _python_type_to_json_type(List[str]) == {"type": "array", "items": {"type": "string"}}

optional_result = _python_type_to_json_type(Optional[int])
assert optional_result["type"] == ["integer", "null"]

print("Type conversion tests passed")
```

    Type conversion tests passed

``` python
# Test dataclass_to_jsonschema using ExampleConfig defined below
# (This test runs after the ExampleConfig is defined in the notebook)
def _test_jsonschema():
    """Test JSON schema generation with ExampleConfig."""
    schema = dataclass_to_jsonschema(ExampleConfig)
    
    # Check structure
    assert schema["name"] == "ExampleConfig"
    assert schema["type"] == "object"
    assert "properties" in schema
    
    # Check field properties
    assert schema["properties"]["model"]["type"] == "string"
    assert schema["properties"]["model"]["title"] == "Model"
    assert schema["properties"]["model"]["enum"] == ["tiny", "base", "small", "medium", "large"]
    assert schema["properties"]["model"]["default"] == "base"
    
    assert schema["properties"]["temperature"]["type"] == "number"
    assert schema["properties"]["temperature"]["minimum"] == 0.0
    assert schema["properties"]["temperature"]["maximum"] == 1.0
    
    assert schema["properties"]["batch_size"]["type"] == "integer"
    assert schema["properties"]["enabled"]["type"] == "boolean"
    assert schema["properties"]["tags"]["type"] == "array"
    
    print("dataclass_to_jsonschema tests passed")
    return schema
```

### Example: Working with Configuration Dataclasses

``` python
from dataclasses import dataclass, field
from typing import List

@dataclass
class ExampleConfig:
    """Example configuration dataclass with metadata constraints."""
    model:str = field(
        default="base",
        metadata={
            SCHEMA_TITLE: "Model",
            SCHEMA_DESC: "Model size to use",
            SCHEMA_ENUM: ["tiny", "base", "small", "medium", "large"]
        }
    )
    temperature:float = field(
        default=0.0,
        metadata={
            SCHEMA_TITLE: "Temperature",
            SCHEMA_DESC: "Sampling temperature",
            SCHEMA_MIN: 0.0,
            SCHEMA_MAX: 1.0
        }
    )
    batch_size:int = field(
        default=8,
        metadata={
            SCHEMA_TITLE: "Batch Size",
            SCHEMA_DESC: "Batch size for processing",
            SCHEMA_MIN: 1,
            SCHEMA_MAX: 32
        }
    )
    enabled:bool = field(
        default=True,
        metadata={SCHEMA_TITLE: "Enabled", SCHEMA_DESC: "Whether feature is enabled"}
    )
    tags:List[str] = field(
        default_factory=list,
        metadata={SCHEMA_TITLE: "Tags", SCHEMA_DESC: "Optional tags"}
    )

print("ExampleConfig dataclass defined with metadata constraints")
print(f"Fields: {[f.name for f in fields(ExampleConfig)]}")
```

    ExampleConfig dataclass defined with metadata constraints
    Fields: ['model', 'temperature', 'batch_size', 'enabled', 'tags']

``` python
# Test extract_defaults
defaults = extract_defaults(ExampleConfig)
print("Default values extracted from ExampleConfig:")
for k, v in defaults.items():
    print(f"  {k}: {v!r}")
```

    Default values extracted from ExampleConfig:
      model: 'base'
      temperature: 0.0
      batch_size: 8
      enabled: True
      tags: []

``` python
# Test dict_to_config with validation
print("Creating config from dictionary:")

# Valid config
config1 = dict_to_config(ExampleConfig, {"model": "large", "temperature": 0.7}, validate=True)
print(f"Valid config: {config1}")

# Config with defaults (all valid)
config2 = dict_to_config(ExampleConfig, {}, validate=True)
print(f"Config with defaults: {config2}")

# Test validation failure - invalid enum
try:
    config_bad = dict_to_config(ExampleConfig, {"model": "invalid"}, validate=True)
except ValueError as e:
    print(f"\n✓ Caught invalid enum: {e}")

# Test validation failure - value below minimum
try:
    config_bad = dict_to_config(ExampleConfig, {"temperature": -0.5}, validate=True)
except ValueError as e:
    print(f"✓ Caught below minimum: {e}")

# Test validation failure - value above maximum
try:
    config_bad = dict_to_config(ExampleConfig, {"batch_size": 100}, validate=True)
except ValueError as e:
    print(f"✓ Caught above maximum: {e}")
```

    Creating config from dictionary:
    Valid config: ExampleConfig(model='large', temperature=0.7, batch_size=8, enabled=True, tags=[])
    Config with defaults: ExampleConfig(model='base', temperature=0.0, batch_size=8, enabled=True, tags=[])

    ✓ Caught invalid enum: model: 'invalid' is not one of ['tiny', 'base', 'small', 'medium', 'large']
    ✓ Caught below minimum: temperature: -0.5 is less than minimum 0.0
    ✓ Caught above maximum: batch_size: 100 is greater than maximum 32

``` python
# SG-8 regression: dict_to_config strict mode rejects unknown keys by default;
# lenient mode logs a warning and falls through to the historical filter behavior.
# CR-5 update: error attribute is `fields_invalid` (canonical CapabilityInputError name).
import logging as _logging

# Default-strict: an unknown key (e.g., a renamed field, typo, or stale legacy
# config) now raises CapabilityConfigError instead of being silently dropped.
try:
    dict_to_config(ExampleConfig, {"model": "base", "renamed_key": 42})
except CapabilityConfigError as e:
    print(f"✓ strict mode rejected: fields_invalid={e.fields_invalid}, class={e.config_class_name}")
    assert e.fields_invalid == ["renamed_key"]
    assert e.config_class_name == "ExampleConfig"

# Lenient mode logs the unknown key + filters it out (forward-compat path).
class _CaptureHandler(_logging.Handler):
    def __init__(self):
        super().__init__()
        self.records = []
    def emit(self, record):
        self.records.append(record)

capture = _CaptureHandler()
_logger.addHandler(capture)
try:
    cfg = dict_to_config(ExampleConfig, {"model": "tiny", "renamed_key": 42}, strict=False)
    assert cfg.model == "tiny"
    assert not hasattr(cfg, "renamed_key")
    assert any("renamed_key" in r.getMessage() for r in capture.records), \
        "lenient mode should emit a warning naming the dropped key"
    print("✓ lenient mode warned + filtered:", [r.getMessage() for r in capture.records])
finally:
    _logger.removeHandler(capture)
```

    ✓ strict mode rejected: fields_invalid=['renamed_key'], class=ExampleConfig
    ✓ lenient mode warned + filtered: ["ExampleConfig: ignoring unknown config keys ['renamed_key'] (lenient mode)"]

``` python
# Test validate_config directly
print("Testing validate_config:")

# Valid config
valid_config = ExampleConfig(model="small", temperature=0.5, batch_size=16)
is_valid, error = validate_config(valid_config)
print(f"Valid config: is_valid={is_valid}, error={error}")

# Invalid config - create without validation, then validate
invalid_config = ExampleConfig(model="invalid_model", temperature=0.5, batch_size=16)
is_valid, error = validate_config(invalid_config)
print(f"Invalid model: is_valid={is_valid}, error={error}")

# Test config_to_dict
print("\nConverting config to dictionary:")
config_dict = config_to_dict(valid_config)
print(f"As dictionary: {config_dict}")
```

    Testing validate_config:
    Valid config: is_valid=True, error=None
    Invalid model: is_valid=False, error=model: 'invalid_model' is not one of ['tiny', 'base', 'small', 'medium', 'large']

    Converting config to dictionary:
    As dictionary: {'model': 'small', 'temperature': 0.5, 'batch_size': 16, 'enabled': True, 'tags': []}

``` python
# Test JSON schema generation
import json

schema = _test_jsonschema()
print("\nGenerated JSON Schema:")
print(json.dumps(schema, indent=2))
```

    dataclass_to_jsonschema tests passed

    Generated JSON Schema:
    {
      "name": "ExampleConfig",
      "title": "ExampleConfig",
      "description": "Example configuration dataclass with metadata constraints.",
      "type": "object",
      "properties": {
        "model": {
          "type": "string",
          "title": "Model",
          "description": "Model size to use",
          "enum": [
            "tiny",
            "base",
            "small",
            "medium",
            "large"
          ],
          "default": "base"
        },
        "temperature": {
          "type": "number",
          "title": "Temperature",
          "description": "Sampling temperature",
          "minimum": 0.0,
          "maximum": 1.0,
          "default": 0.0
        },
        "batch_size": {
          "type": "integer",
          "title": "Batch Size",
          "description": "Batch size for processing",
          "minimum": 1,
          "maximum": 32,
          "default": 8
        },
        "enabled": {
          "type": "boolean",
          "title": "Enabled",
          "description": "Whether feature is enabled",
          "default": true
        },
        "tags": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "title": "Tags",
          "description": "Optional tags",
          "default": []
        }
      }
    }
