# Schema System

> How Plexus activations expose self-describing JSON schemas.

## Overview

Schemas are generated automatically from your Rust types via `schemars`. Every activation exposes its schema at runtime, enabling dynamic discovery by clients like Synapse.

## PluginSchema

Each activation exposes a `PluginSchema` containing:
- `namespace`, `version`, `description`
- `methods: Vec<MethodSchema>` — each with name, description, params schema, returns schema, streaming flag
- `children: Option<Vec<ChildSummary>>` — for hub activations
- `self_hash`, `children_hash`, `hash` — content hashes for cache invalidation

```rust
pub struct PluginSchema {
    pub namespace: String,
    pub version: String,
    pub description: String,
    pub long_description: Option<String>,
    pub self_hash: String,
    pub children_hash: Option<String>,
    pub hash: String,
    pub methods: Vec<MethodSchema>,
    pub children: Option<Vec<ChildSummary>>,
}
```

### Leaf vs Hub

- **Leaf plugins** (`children: None`) — have methods only, created via `PluginSchema::leaf()`
- **Hub plugins** (`children: Some(...)`) — have methods and child summaries, created via `PluginSchema::hub()`

### Collision Validation

`PluginSchema` validates at construction time that there are no name collisions between methods, between children, or between methods and children. Panics on collision (system error).

## MethodSchema

```rust
pub struct MethodSchema {
    pub name: String,
    pub description: String,
    pub hash: String,                         // Content hash
    pub params: Option<schemars::Schema>,      // JSON Schema for params
    pub returns: Option<schemars::Schema>,     // JSON Schema for return type
    pub streaming: bool,                       // Multi-event or single result
    pub bidirectional: bool,                   // Server can request from client
    pub request_type: Option<schemars::Schema>, // Bidir request schema
    pub response_type: Option<schemars::Schema>, // Bidir response schema
}
```

### Builder Methods

```rust
MethodSchema::new(name, description, hash)
    .with_params(schema)                 // Add parameter JSON Schema
    .with_returns(schema)                // Add return type JSON Schema
    .with_streaming(true)                // Mark as streaming
    .with_bidirectional(true)            // Enable bidir communication
    .with_request_type(schema)           // Set bidir request schema
    .with_response_type(schema)          // Set bidir response schema
    .with_standard_bidirectional()       // Shorthand: bidir + StandardRequest/Response schemas
```

## Content Hashing

Three-level hashing for cache invalidation:

| Hash | Scope | Changes when... |
|------|-------|-----------------|
| `self_hash` | Methods only | Method signatures, names, or descriptions change |
| `children_hash` | Children only (hub) | Any child's hash changes (recursively) |
| `hash` | Composite | Either self_hash or children_hash changes |

```rust
// Clients can check just the composite hash for quick cache validation
if cached_hash != plugin_schema.hash {
    // Re-fetch schema
}
```

## ChildSummary

Shallow reference to a child plugin (for hub schemas):

```rust
pub struct ChildSummary {
    pub namespace: String,
    pub description: String,
    pub hash: String,  // Content hash for cache invalidation
}
```

Children are summaries, not full schemas. This enables lazy traversal — clients fetch child schemas individually via `{namespace}.schema`.

## Plugin ID

Deterministically generated from `namespace@major_version`:

```rust
uuid::Uuid::new_v5(&uuid::Uuid::NAMESPACE_OID, "echo@1".as_bytes())
```

This ensures handles survive minor/patch version upgrades (semver).

## Source Paths

| Component | Path |
|-----------|------|
| Schema types | `plexus-core/src/plexus/schema.rs` |
| Activation trait (default schema impl) | `plexus-core/src/plexus/plexus.rs` |
| Macro-generated schemas | `plexus-macros/src/codegen/method_enum.rs` |
