# Schema Rules and Validation

## What the Schema Enforces

The event-driven workflow schema enforces **strict rules** to ensure your YAML perfectly describes system connections.

### 1. Events Must Be Defined Before Use

**Rule**: You cannot emit or consume an event that doesn't exist.

**Valid:**
```yaml
events:
  payment_selected:
    description: User selects payment method
    payload:
      method: string

components:
  checkout:
    emits:
      - payment_selected  # ✓ Valid - event is defined
```

**Invalid:**
```yaml
components:
  checkout:
    emits:
      - payment_processed  # ✗ Error - event not defined in 'events' section
```

**Error Message:**
```
Component 'checkout' emits undefined event 'payment_processed'.
Event must be defined in 'events' section.
```

### 2. Components Must Be Defined Before Reference

**Rule**: Workflows and stack must reference components that exist.

**Valid:**
```yaml
components:
  checkout:
    description: Payment processing
    emits: []

workflows:
  customer_checkout:
    steps:
      - component: checkout  # ✓ Valid - component exists
```

**Invalid:**
```yaml
workflows:
  customer_checkout:
    steps:
      - component: payment  # ✗ Error - component 'payment' not defined
```

**Error Message:**
```
Workflow 'customer_checkout' step references undefined component 'payment'.
Component must be defined in 'components' section.
```

### 3. Actors Must Be Defined Before Use

**Rule**: Workflows must reference actors that exist.

**Valid:**
```yaml
actors:
  customer:
    type: human
    description: End user

workflows:
  checkout:
    actor: customer  # ✓ Valid - actor exists
```

**Invalid:**
```yaml
workflows:
  checkout:
    actor: admin  # ✗ Error - actor 'admin' not defined
```

**Error Message:**
```
Workflow 'checkout' references undefined actor 'admin'.
Actor must be defined in 'actors' section.
```

### 4. Event Flow Must Be Complete

**Rule**: Events emitted should be consumed, and events consumed should be emitted.

**Warning (Emitted but Never Consumed):**
```yaml
events:
  order_cancelled:
    description: Order was cancelled
    payload:
      order_id: string

components:
  order_management:
    emits:
      - order_cancelled  # ⚠ Warning - no component consumes this
```

**Warning Message:**
```
Event 'order_cancelled' is emitted but never consumed by any component.
This may indicate a missing consumer.
```

**Warning (Consumed but Never Emitted):**
```yaml
components:
  analytics:
    consumes:
      - user_registered  # ⚠ Warning - no component emits this
```

**Warning Message:**
```
Event 'user_registered' is consumed but never emitted by any component.
This may indicate a missing emitter.
```

### 5. Stack Must Map to Defined Components

**Rule**: Stack services must implement components that exist.

**Valid:**
```yaml
components:
  checkout:
    description: Payment processing
    emits: [payment_selected]

stack:
  checkout:  # ✓ Valid - maps to defined component
    services:
      stripe:
        type: payment_processor
```

**Invalid:**
```yaml
stack:
  payment:  # ✗ Error - component 'payment' not defined
    services:
      stripe:
        type: payment_processor
```

**Error Message:**
```
Stack defines services for undefined component 'payment'.
Component must be defined in 'components' section.
```

### 6. Event Payloads Must Have Types

**Rule**: Event payload fields must specify a type.

**Valid:**
```yaml
events:
  payment_selected:
    description: Payment method selected
    payload:
      method: string
      amount: number
      currency: string
```

**Invalid:**
```yaml
events:
  payment_selected:
    description: Payment method selected
    payload:
      method: unknown_type  # ✗ Error - must be string, number, boolean, array, or object
```

## What This Guarantees

### Guarantee 1: No Broken References

The schema **prevents** you from creating YAML that references things that don't exist:
- Can't emit undefined events
- Can't consume undefined events
- Can't use undefined components
- Can't use undefined actors

### Guarantee 2: Complete Event Flow

The schema **warns** you when event flow is incomplete:
- Events emitted but never consumed (potential waste)
- Events consumed but never emitted (will never trigger)

This ensures you understand **exactly** how events flow through your system.

### Guarantee 3: Type Safety

The schema **enforces** type safety:
- Event payloads have well-defined types
- No ambiguity about data structure
- Generated code can use strong typing

### Guarantee 4: Clear Connections

The schema **documents** all connections:

**When you look at a component:**
```yaml
components:
  checkout:
    emits:
      - payment_selected
      - order_created
    consumes:
      - cart_viewed
```

**You immediately know:**
- What events it sends to other components
- What events it receives from other components
- Its exact role in the event flow

### Guarantee 5: Validation at Definition Time

**Before** any code generation happens, the schema validates:
```bash
$ bang validate workflow.yaml

✗ Validation failed:
  - Component 'checkout' emits undefined event 'payment_processed'
  - Workflow 'admin_cancel' references undefined actor 'supervisor'
  - Stack component 'billing' not defined in components section
```

You catch errors **immediately**, not when trying to run generated code.

## How to Use the Schema

### 1. Define Events First

Start by defining all events in your system:
```yaml
events:
  user_registered:
    description: New user account created
    payload:
      user_id: string
      email: string

  order_placed:
    description: Customer placed an order
    payload:
      order_id: string
      total: number
```

### 2. Define Components with Event Dependencies

Then define components and declare what events they emit/consume:
```yaml
components:
  user_management:
    description: User account management
    emits:
      - user_registered
    consumes: []

  order_system:
    description: Order processing
    emits:
      - order_placed
    consumes:
      - user_registered  # Needs to know about users
```

### 3. Define Actors

Define who/what performs actions:
```yaml
actors:
  customer:
    type: human
    description: End user

  order_processor:
    type: system
    description: Background order processor
    schedule: "*/5 * * * *"
```

### 4. Define Workflows

Create workflows that tie it all together:
```yaml
workflows:
  customer_registration:
    actor: customer
    steps:
      - id: sign_up
        action: create_account
        component: user_management
        emits: user_registered
```

### 5. Map to Services

Finally, map abstract components to concrete services:
```yaml
stack:
  user_management:
    services:
      auth0:
        type: auth_provider
        config:
          domain: "{{ env.AUTH0_DOMAIN }}"
```

## Validation Examples

### Example 1: Valid Workflow

```yaml
events:
  payment_selected:
    description: Payment method chosen
    payload:
      method: string

actors:
  customer:
    type: human
    description: End user

components:
  checkout:
    emits:
      - payment_selected
    consumes: []

workflows:
  checkout_flow:
    actor: customer
    steps:
      - id: pay
        component: checkout
        emits: payment_selected

stack:
  checkout:
    services:
      stripe:
        type: payment_processor
```

**Result**: ✓ Valid - all references exist, event flow is complete

### Example 2: Missing Event Definition

```yaml
components:
  checkout:
    emits:
      - payment_completed  # ✗ Event not defined
```

**Result**: ✗ Error - Event 'payment_completed' must be defined in 'events' section

### Example 3: Orphaned Event

```yaml
events:
  rare_event:
    description: Rarely used event
    payload:
      data: string

# No component emits or consumes this event
```

**Result**: ⚠ Warning - Event 'rare_event' is never emitted or consumed

### Example 4: Stack Without Component

```yaml
stack:
  billing:  # ✗ Component 'billing' doesn't exist
    services:
      stripe:
        type: payment
```

**Result**: ✗ Error - Stack defines services for undefined component 'billing'

## Benefits of Strict Schema

### 1. Catch Errors Early

**Without Schema:**
```
Write YAML → Generate Code → Run Code → Runtime Error
(hours of debugging)
```

**With Schema:**
```
Write YAML → Validate → Error Found → Fix → Validate → Success
(seconds to fix)
```

### 2. Documentation is Built-In

The YAML **is** the documentation. When you look at:
```yaml
components:
  checkout:
    emits: [payment_selected, order_created]
    consumes: [cart_viewed]
```

You **immediately** understand the component's role in the system.

### 3. Refactoring is Safe

When you rename an event:
```yaml
events:
  payment_completed:  # Renamed from payment_selected
```

The schema validation will show you **every** place that needs updating:
```
✗ Component 'checkout' emits undefined event 'payment_selected'
✗ Component 'analytics' consumes undefined event 'payment_selected'
✗ Workflow 'checkout_flow' emits undefined event 'payment_selected'
```

### 4. AI Can Help More Effectively

With a strict schema, AI can:
- Suggest which events a component should consume
- Auto-complete valid event names
- Warn about missing event consumers
- Generate only valid YAML

### 5. Perfect System Description

The combination of:
- Events (what can happen)
- Components (what emits/consumes events)
- Workflows (step-by-step processes)
- Stack (concrete implementations)

**Perfectly describes** how your system connects and operates.

## Summary

The schema enforces these rules:

✓ **Events must be defined before use**
✓ **Components must be defined before reference**
✓ **Actors must be defined before use**
✓ **Event flow must be complete (emit → consume)**
✓ **Stack must map to defined components**
✓ **Event payloads must have types**

This ensures your YAML **perfectly describes** how parts of the system connect, with **no ambiguity** or **broken references**.
