# VAPORA Validation Schemas

Nickel schemas for runtime validation of MCP tools and agent tasks.

## Directory Structure

```
schemas/
├── tools/              # MCP tool parameter validation
│   ├── kanban_create_task.ncl
│   ├── kanban_update_task.ncl
│   ├── assign_task_to_agent.ncl
│   ├── get_project_summary.ncl
│   └── get_agent_capabilities.ncl
│
└── agents/             # Agent task assignment validation
    └── task_assignment.ncl
```

## Schema Format

Nickel schemas define:

- **Field types** (String, Number, Bool, Array, Object)
- **Required/optional fields** (via `default` values)
- **Validation contracts** (NonEmpty, Email, UUID, Range, Pattern, etc.)
- **Documentation** (via `doc` annotations)

### Example

```nickel
{
  tool_name = "example_tool",

  parameters = {
    # Required field with contracts
    user_id
      | String
      | doc "User UUID"
      | std.string.NonEmpty
      | std.string.match "^[0-9a-f]{8}-[0-9a-f]{4}-...$",

    # Optional field with default
    priority
      | Number
      | doc "Priority score (0-100)"
      | std.number.between 0 100
      | default = 50,
  },
}
```

## Supported Contracts

| Contract | Description | Example |
|----------|-------------|---------|
| `std.string.NonEmpty` | String cannot be empty | Required text fields |
| `std.string.length.min N` | Minimum length | `min 3` for titles |
| `std.string.length.max N` | Maximum length | `max 200` for titles |
| `std.string.match PATTERN` | Regex validation | UUID format |
| `std.number.between A B` | Numeric range | `between 0 100` |
| `std.number.greater_than N` | Minimum value (exclusive) | `> -1` |
| `std.number.less_than N` | Maximum value (exclusive) | `< 1000` |
| `std.string.Email` | Email format | user@example.com |
| `std.string.Url` | URL format | https://... |
| `std.string.Uuid` | UUID format | xxxxxxxx-xxxx-... |
| `std.enum.TaggedUnion` | Enum validation | `[| 'low, 'high |]` |

## Usage

Schemas are loaded by `ValidationPipeline` at runtime:

```rust
use vapora_shared::validation::{SchemaRegistry, ValidationPipeline};

let registry = Arc::new(SchemaRegistry::new(PathBuf::from("schemas")));
let pipeline = ValidationPipeline::new(registry);

// Validate MCP tool input
let result = pipeline.validate("tools/kanban_create_task", &input).await?;

if !result.valid {
    return (StatusCode::BAD_REQUEST, Json(result.errors));
}
```

## Testing Schemas

Validate schema syntax:

```bash
nickel typecheck schemas/tools/kanban_create_task.ncl
```

Export schema as JSON:

```bash
nickel export schemas/tools/kanban_create_task.ncl
```

Query specific field:

```bash
nickel query --field parameters.title schemas/tools/kanban_create_task.ncl
```

## Adding New Schemas

1. Create `.ncl` file in appropriate directory
2. Define `tool_name` or `schema_name`
3. Define `parameters` or `fields` with types and contracts
4. Add `doc` annotations for documentation
5. Test with `nickel typecheck`
6. Restart services to reload schemas (or use hot-reload)

## Hot Reload

Invalidate cached schema without restart:

```rust
registry.invalidate("tools/kanban_create_task").await;
```

Invalidate all schemas:

```rust
registry.invalidate_all().await;
```
