# Validacion y Schemas

Gap identificado en el registry. Reimplementar desde cero.

No hay funciones de validacion de datos estructurados. Necesarias para el pipeline
de ingesta (validar documentos parseados) y para assertions mas ricas en operations.db.

## Funciones a implementar

### validate_json_schema

- **Dominio:** core
- **Lang:** Python
- **Purity:** pure
- **Signature:** `validate_json_schema(data: dict, schema: dict) -> tuple[bool, list[str]]`
- **Retorno:** (valid, errors) — True y lista vacia si cumple, False y lista de errores si no
- **Descripcion:** Valida un dict contra un schema JSON Schema (draft 2020-12) sin dependencias externas. Soporta types, required, properties, items, minimum/maximum, minLength/maxLength, pattern, enum. No pretende cubrir todo el spec — solo lo practico.
- **Algoritmo:**
  1. Validar type (string, number, integer, boolean, array, object, null)
  2. Para object: validar required, iterar properties recursivamente
  3. Para array: validar items recursivamente, minItems/maxItems
  4. Para string: pattern (re.match), minLength/maxLength, enum
  5. Para number/integer: minimum/maximum, exclusiveMinimum/exclusiveMaximum
  6. Acumular errores con path (ej: "$.address.zip: expected string, got int")
- **Deps:** `re` (solo stdlib)
- **Tests:**
  - Schema simple con types y required
  - Nested object validation
  - Array con items schema
  - Pattern validation en strings
  - Numeric ranges
  - Multiples errores acumulados con paths correctos
  - Schema vacio (acepta todo)
  - Data None contra required field

### validate_struct_fields

- **Dominio:** core
- **Lang:** Go
- **Purity:** pure
- **Signature:** `ValidateStructFields(data map[string]any, rules map[string]string) (bool, []string)`
- **Retorno:** (valid, errors)
- **Descripcion:** Valida campos de un map contra reglas declarativas tipo `"required,min=1,max=100,type=string"`. Pensado para validar metadata de entities en operations.db o resultados de queries sin definir structs Go.
- **Reglas soportadas:**
  - `required` — campo debe existir y no ser nil/""
  - `type=string|int|float|bool` — validar tipo Go subyacente
  - `min=N`, `max=N` — para numericos
  - `minlen=N`, `maxlen=N` — para strings
  - `oneof=a|b|c` — valor debe ser uno de los listados
  - `pattern=regex` — para strings
- **Deps:** `regexp`, `strconv`, `strings` (solo stdlib)
- **Tests:**
  - Campo required presente y ausente
  - Type validation (string como int falla)
  - Numeric ranges
  - String lengths
  - Oneof validation
  - Pattern matching
  - Multiples reglas combinadas
  - Map vacio con reglas required

### coerce_types

- **Dominio:** core
- **Lang:** Python
- **Purity:** pure
- **Signature:** `coerce_types(data: dict, schema: dict[str, str]) -> tuple[dict, list[str]]`
- **Retorno:** (coerced_data, warnings) — nuevo dict con tipos corregidos, warnings para coerciones lossy
- **Descripcion:** Convierte valores de un dict a los tipos esperados. Schema es `{"field": "int|float|str|bool|datetime|list[str]"}`. Util para normalizar datos que vienen como strings de CSV, JSON, o query params antes de insertarlos en operations.db.
- **Coerciones:**
  - str → int: `int(v)`, warning si tiene decimales
  - str → float: `float(v)`
  - str → bool: "true/1/yes" → True, "false/0/no" → False
  - str → datetime: ISO 8601 parse
  - str → list[str]: split por "," y strip
  - Valor ya del tipo correcto → pass through
  - Coercion imposible → mantener original + warning
- **Deps:** `datetime` (solo stdlib)
- **Tests:**
  - String "42" → int 42
  - String "3.14" → float 3.14
  - String "true" → bool True
  - String "2024-01-15T10:30:00Z" → datetime
  - Coercion fallida genera warning sin crash
  - Dict con mix de tipos ya correctos y strings
  - Campo ausente en schema → pass through sin tocar
