# Data Contract Templates

Templates for creating data contracts with schema, coercion rules, validation rules, and metadata.

## Quick Start

```python
from pycharter import parse_contract, validate_with_contract

# Option 1: Complete contract in one file
contract = {
    "schema": {
        "type": "object",
        "properties": {
            "id": {"type": "string"},
            "name": {"type": "string", "minLength": 1},
        },
        "required": ["id", "name"]
    },
    "metadata": {"version": "1.0.0"},
    "ownership": {"owner": "data-team"}
}

# Validate data
result = validate_with_contract(contract, {"id": "123", "name": "Alice"})
print(f"Valid: {result.is_valid}")
```

## Template Files

| Template | Description |
|----------|-------------|
| `template_contract.yaml` | Complete contract (schema + rules + metadata + optional lifecycle and ontology) |
| `template_schema.yaml` | JSON Schema with PyCharter extensions |
| `template_coercion_rules.yaml` | Data type transformation rules |
| `template_validation_rules.yaml` | Business validation rules |
| `template_metadata.yaml` | Ownership, governance, and optional FSM lifecycle binding |
| `template_ontology.yaml` | Semantic field annotations (concepts, definitions, lineage, relationships) |

Seed data for contracts is in `pycharter/data/seed/` (contracts, schemas, metadata, coercion, validation, ontologies). Run `pycharter db seed` to load; ontologies are stored in Wiki `contract_versions` when using PostgreSQL.

## Contract Structure

```yaml
# Complete contract structure (parse_contract / create-mixed compatible)
schema:               # JSON Schema (required). May include inline coercion/validations
  type: object
  title: my_entity
  version: "1.0.0"
  properties:
    field_name:
      type: string
      coercion: coerce_to_string      # Optional: inline coercion
      validations:                     # Optional: inline validation rules
        max_length: {threshold: 100}

# Optional: top-level rules (same format as template_coercion_rules / template_validation_rules)
coercion_rules:
  version: "1.0.0"
  rules:
    field_name: coerce_to_string
validation_rules:
  version: "1.0.0"
  rules:
    field_name: { max_length: { threshold: 100 } }

# Metadata: version, description; ownership and governance_rules must be nested here
metadata:
  version: "1.0.0"
  description: "Contract description"
  ownership:          # Nested in metadata (not top-level)
    owner: team-name
    team: department
  governance_rules:   # Nested in metadata
    data_retention: {days: 365}
    pii_fields: {fields: [email]}

# Optional: ontology (semantic field annotations; see Wiki / Concepts)
# ontology:
#   version: "1.0.0"
#   fields:
#     email: { concept: user_email, definition: "Primary email address" }

versions:             # Optional: explicit version tracking
  schema: "1.0.0"
  coercion_rules: "1.0.0"
  validation_rules: "1.0.0"
  metadata: "1.0.0"
  ontology: "1.0.0"   # When ontology section is present
```

## Coercion Rules

Applied BEFORE Pydantic validation to transform input data:

| Rule | Description |
|------|-------------|
| `coerce_to_string` | Convert to string |
| `coerce_to_integer` | Convert to int |
| `coerce_to_float` | Convert to float |
| `coerce_to_boolean` | Convert to bool |
| `coerce_to_datetime` | Parse datetime |
| `coerce_to_date` | Parse date |
| `coerce_to_uuid` | Parse UUID |
| `coerce_to_lowercase` | Lowercase string |
| `coerce_to_uppercase` | Uppercase string |
| `coerce_to_stripped_string` | Trim whitespace |
| `coerce_to_nullable_*` | Handle null values |

## Validation Rules

Applied AFTER Pydantic validation for business rules:

| Rule | Parameters | Description |
|------|------------|-------------|
| `min_length` | `{threshold: N}` | Minimum string length |
| `max_length` | `{threshold: N}` | Maximum string length |
| `greater_than_or_equal_to` | `{threshold: N}` | Minimum value |
| `less_than_or_equal_to` | `{threshold: N}` | Maximum value |
| `only_allow` | `{allowed_values: [...]}` | Enum validation |
| `non_empty_string` | `null` | Non-empty string |
| `is_email` | `null` | Email format |
| `is_url` | `null` | URL format |
| `matches_regex` | `{pattern: "..."}` | Regex match |

## Ontology

Semantic annotations for schema fields. Use under `ontology:` in a full contract or as a standalone file. Parsed by the Wiki ontology parser; supports concept taxonomy, definitions, lineage, and field-to-field relationships.

| Field key | Description |
|-----------|-------------|
| `version` | Ontology version (e.g. `"1.0.0"`) |
| `fields` | Map of schema field name → annotation object |

Per-field annotation keys:

| Key | Description |
|-----|-------------|
| `concept` | Semantic concept name (required) |
| `broader` | Parent concept in hierarchy |
| `definition` | Human-readable definition |
| `tags` | List of tags |
| `owner` | Team or person owning the field |
| `lineage` | `{ derived_from?, source_system? }` |
| `relationships` | List of `{ target, type }` |

Relationship types: `references` | `derived_from` | `same_as` | `related_to`

See `template_ontology.yaml` for a full example.

## Usage Patterns

### 1. Validate with Contract

```python
from pycharter import validate_with_contract

result = validate_with_contract(
    "path/to/contract.yaml",  # or dict
    {"id": "123", "name": "Alice"}
)

if result.is_valid:
    print(f"Data: {result.data}")
else:
    print(f"Errors: {result.errors}")
```

### 2. Build Contract from Artifacts

```python
from pycharter import build_contract

contract = build_contract(
    schema=schema_dict,
    metadata=metadata_dict,
    coercion_rules=coercion_dict,
    validation_rules=validation_dict,
)
```

### 3. Quality Check

```python
from pycharter import QualityCheck

report = QualityCheck().run(
    contract=contract,
    data=records
)
print(f"Score: {report.quality_score.overall_score}/100")
```

## Examples

See `docs/notebooks/03_contracts.ipynb` and `docs/notebooks/04_validation_quality.ipynb` for working examples.
