caxton 0.1.4

A secure WebAssembly runtime for multi-agent systems
Documentation
# ADR-0020: Parse Don't Validate Paradigm

## Status
Accepted

## Context
The codebase previously validated values at usage sites, leading to:
- Repeated validation logic
- Possibility of forgetting validation
- Invalid states being possible throughout the system
- Runtime errors deep in the call stack

## Decision
Adopt the "Parse Don't Validate" paradigm:
1. Parse and validate data at system boundaries
2. Use types that make invalid states unrepresentable
3. Once parsed into a domain type, the value is guaranteed valid

### Implementation Strategy

#### Construction Patterns
```rust
// Types with validation - can fail
let name = AgentName::try_new(input)?; // Validates 1-255 chars

// Types without validation - always succeed
let id = AgentId::new(uuid); // UUID is always valid

// After construction, the value is guaranteed valid
process_agent(name); // No validation needed here
```

#### Validation Rules in Types
```rust
#[nutype(
    validate(len_char_min = 1, len_char_max = 255),
    derive(Debug, Clone, Serialize, Deserialize),
)]
pub struct AgentName(String);
// Invalid AgentName cannot exist after construction
```

## Consequences

### Positive
- **Guaranteed Validity**: Once constructed, values are always valid
- **Single Validation Point**: Validation happens once at construction
- **Compile-Time Safety**: Invalid states are impossible to represent
- **Simplified Logic**: Functions can assume inputs are valid
- **Error Locality**: Validation errors occur at system boundaries

### Negative
- **Construction Complexity**: Must handle potential construction failures
- **Type Proliferation**: Need many specific types instead of primitives
- **Learning Curve**: Developers must understand the paradigm

### Examples

#### Before (Validate)
```rust
fn process_memory(bytes: usize) -> Result<()> {
    if bytes > MAX_MEMORY {
        return Err("Invalid memory size");
    }
    // Use bytes...
}
```

#### After (Parse)
```rust
fn process_memory(bytes: MemoryBytes) -> Result<()> {
    // bytes is guaranteed valid, just use it
    allocate(bytes);
}
```

## References
- [Parse, Don't Validate - Alexis King]https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/
- ADR-0018: Domain Types with nutype
- [Making Invalid States Unrepresentable]https://yoric.github.io/post/rust-typestate/