# Agencio Predict - Triggers & External Actions

## Overview

The Triggers & Actions system is the automation backbone of Agencio Predict.
It lets users (and the system itself) define rules that fire when prediction
events hit certain conditions, then execute external actions automatically.

**Think IFTTT/Zapier but for prediction intelligence.**

"When probability crosses 70%, pause my ad spend and alert the team on Slack."

---

## Concepts

```
┌────────────────┐     ┌────────────────┐     ┌────────────────┐
│    TRIGGER     │────▶│   EVALUATOR    │────▶│    ACTION      │
│  (Condition)   │     │  (Rule Engine) │     │  (Execution)   │
└────────────────┘     └────────────────┘     └────────────────┘
                              │
                              ▼
                       ┌────────────────┐
                       │  ACTION LOG    │
                       │  (Audit Trail) │
                       └────────────────┘
```

- **Trigger**: A predefined condition on a prediction event (e.g., probability > 0.8)
- **Action**: What happens when the trigger fires (e.g., send Slack message, call webhook)
- **Rule**: A trigger + one or more actions, created by a user
- **Evaluation**: Runs on every signal ingest / snapshot update
- **Cooldown**: Prevents the same rule from firing repeatedly in quick succession

---

## Built-in Trigger Types

### Probability Triggers

| Trigger ID | Description | Parameters |
|-----------|-------------|------------|
| `prob_crosses_above` | Probability crosses above a threshold | `threshold: number` |
| `prob_crosses_below` | Probability crosses below a threshold | `threshold: number` |
| `prob_enters_range` | Probability enters a range | `min: number, max: number` |
| `prob_exits_range` | Probability leaves a range | `min: number, max: number` |
| `prob_shift` | Probability shifts by X% in Y time | `delta: number, window_minutes: number` |

### Sentiment Triggers

| Trigger ID | Description | Parameters |
|-----------|-------------|------------|
| `sentiment_crosses_above` | Sentiment crosses above threshold | `threshold: number` |
| `sentiment_crosses_below` | Sentiment crosses below threshold | `threshold: number` |
| `sentiment_flip` | Sentiment flips sign (positive ↔ negative) | — |
| `sentiment_spike` | Sentiment changes rapidly | `delta: number, window_minutes: number` |

### Divergence Triggers

| Trigger ID | Description | Parameters |
|-----------|-------------|------------|
| `divergence_level` | Divergence reaches a level | `level: 'HIGH' \| 'EXTREME'` |
| `divergence_resolved` | Divergence drops back to LOW/NONE | — |

### Trust Triggers

| Trigger ID | Description | Parameters |
|-----------|-------------|------------|
| `trust_drops_below` | Trust score drops below threshold | `threshold: number` |
| `trust_flag_raised` | New trust flag is created | `severity_min: 'WARNING' \| 'ALERT' \| 'CRITICAL'` |
| `manipulation_risk` | Manipulation risk reaches level | `level: 'HIGH' \| 'CRITICAL'` |

### Volume Triggers

| Trigger ID | Description | Parameters |
|-----------|-------------|------------|
| `volume_spike` | Signal volume exceeds X in Y time | `count: number, window_minutes: number` |
| `volume_drought` | No new signals in X time | `window_minutes: number` |

### Event Lifecycle Triggers

| Trigger ID | Description | Parameters |
|-----------|-------------|------------|
| `event_resolved` | Event is resolved (YES/NO) | `outcome?: 'YES' \| 'NO' \| 'ANY'` |
| `event_created` | New event is created | `category?: string` |
| `resolution_approaching` | Resolution date within X days | `days_before: number` |
| `explanation_generated` | New AI explanation is created | `trigger_type?: string` |

### Marketing Triggers

| Trigger ID | Description | Parameters |
|-----------|-------------|------------|
| `campaign_predicted` | Campaign prediction completed | `min_success_prob?: number` |
| `variant_winner_changed` | Recommended variant switches | — |
| `campaign_outcome_recorded` | Actual outcome is logged | — |
| `prediction_accuracy_alert` | Prediction was significantly wrong | `error_threshold: number` |

### Composite Triggers

| Trigger ID | Description | Parameters |
|-----------|-------------|------------|
| `all_of` | All sub-triggers must be true | `triggers: TriggerDef[]` |
| `any_of` | Any sub-trigger must be true | `triggers: TriggerDef[]` |
| `sequence` | Triggers fire in order within time window | `triggers: TriggerDef[], window_minutes: number` |

---

## Built-in Action Types

### Notifications

| Action ID | Description | Config |
|----------|-------------|--------|
| `notify_email` | Send email notification | `to: string[], template?: string` |
| `notify_slack` | Post to Slack channel | `webhook_url: string, channel?: string` |
| `notify_discord` | Post to Discord channel | `webhook_url: string` |
| `notify_teams` | Post to MS Teams | `webhook_url: string` |
| `notify_push` | Push notification (mobile/browser) | `user_ids: string[]` |
| `notify_sms` | Send SMS (Twilio) | `phone_numbers: string[]` |
| `notify_in_app` | In-app notification | `user_ids: string[], priority: string` |

### Webhooks

| Action ID | Description | Config |
|----------|-------------|--------|
| `webhook` | Generic HTTP webhook | `url: string, method: string, headers?: object, body_template?: string` |
| `webhook_graphql` | GraphQL mutation | `url: string, mutation: string, variables_template?: object` |

### Agencio Platform Actions

| Action ID | Description | Config |
|----------|-------------|--------|
| `agencio_pause_campaign` | Pause an Agencio campaign | `campaign_id: string` |
| `agencio_resume_campaign` | Resume a paused campaign | `campaign_id: string` |
| `agencio_adjust_budget` | Adjust campaign budget | `campaign_id: string, adjustment: string` |
| `agencio_swap_variant` | Switch active A/B variant | `campaign_id: string, variant: string` |
| `agencio_trigger_repredict` | Re-run campaign prediction | `campaign_id: string` |
| `agencio_create_alert` | Create alert in Agencio dashboard | `message: string, severity: string` |

### External Platform Actions

| Action ID | Description | Config |
|----------|-------------|--------|
| `google_ads_pause` | Pause Google Ads campaign | `account_id: string, campaign_id: string` |
| `google_ads_adjust_bid` | Adjust bid strategy | `account_id: string, campaign_id: string, adjustment: object` |
| `meta_ads_pause` | Pause Meta/Facebook ads | `account_id: string, campaign_id: string` |
| `meta_ads_adjust_budget` | Adjust Meta ad budget | `account_id: string, campaign_id: string, budget: number` |
| `tiktok_ads_pause` | Pause TikTok campaign | `advertiser_id: string, campaign_id: string` |
| `zapier_trigger` | Fire a Zapier webhook | `zap_webhook_url: string` |
| `make_trigger` | Fire a Make (Integromat) scenario | `webhook_url: string` |
| `n8n_trigger` | Fire an n8n workflow | `webhook_url: string` |

### Data Actions

| Action ID | Description | Config |
|----------|-------------|--------|
| `snapshot_report` | Generate and store a point-in-time report | `format: 'json' \| 'pdf' \| 'csv'` |
| `export_signals` | Export signals data | `destination: 'email' \| 's3' \| 'webhook', format: string` |
| `log_to_sheet` | Append row to Google Sheet | `sheet_id: string, tab: string` |
| `log_to_airtable` | Create record in Airtable | `base_id: string, table: string` |

### AI Actions

| Action ID | Description | Config |
|----------|-------------|--------|
| `generate_explanation` | Force AI explanation generation | — |
| `generate_report` | Generate AI summary report | `scope: 'event' \| 'category' \| 'global'` |
| `recompute_trust` | Force trust score recalculation | — |
| `generate_recommendation` | AI-generated action recommendation | `context: string` |

---

## Template Variables

Actions can use template variables that get replaced at execution time.

```
{{ event.title }}              → "Iran escalation leads to oil > $100?"
{{ event.current_probability }} → 0.72
{{ event.previous_probability }} → 0.45
{{ event.probability_delta }}   → 0.27
{{ event.sentiment_score }}     → 0.41
{{ event.trust_score }}         → 0.58
{{ event.divergence }}          → "HIGH"
{{ event.confidence }}          → "MEDIUM"
{{ event.category }}            → "Geopolitics"
{{ event.url }}                 → "https://predict.agencio.com/event/iran-oil-spike"

{{ trigger.type }}              → "prob_crosses_above"
{{ trigger.fired_at }}          → "2026-03-24T10:35:00Z"
{{ trigger.description }}       → "Probability crossed above 70%"

{{ explanation.headline }}      → "Iran odds spike 27% after Reuters report"
{{ explanation.summary }}       → "Market probability jumped..."

{{ trust.overall_score }}       → 0.58
{{ trust.manipulation_risk }}   → "HIGH"
{{ trust.flag_type }}           → "INSIDER_TIMING"
{{ trust.flag_description }}    → "Large position opened 12 min before..."

{{ campaign.name }}             → "Gen Z sneaker drop"
{{ campaign.recommended }}      → "Variant B"
{{ campaign.success_prob }}     → 0.81

{{ user.name }}                 → "JJ"
{{ user.email }}                → "jj@agencio.com"
```

### Example: Slack Message Template

```json
{
  "action": "notify_slack",
  "config": {
    "webhook_url": "https://hooks.slack.com/services/...",
    "body_template": {
      "text": "🚨 *{{ event.title }}*\n\nProbability moved from {{ event.previous_probability | percent }} to {{ event.current_probability | percent }} ({{ trigger.description }})\n\nTrust Score: {{ event.trust_score | percent }}\n\n{{ explanation.headline }}\n\n<{{ event.url }}|View in Predict Terminal>"
    }
  }
}
```

---

## Rule Definition

A rule combines a trigger, actions, scope, and configuration.

```json
{
  "id": "uuid",
  "name": "Alert team when Iran odds spike",
  "description": "Notify Slack and pause related ad campaign when probability crosses 70%",
  "enabled": true,
  "created_by": "user-uuid",

  "scope": {
    "type": "event",
    "event_id": "event-uuid"
  },

  "trigger": {
    "type": "prob_crosses_above",
    "params": {
      "threshold": 0.70
    }
  },

  "actions": [
    {
      "type": "notify_slack",
      "config": {
        "webhook_url": "https://hooks.slack.com/services/...",
        "body_template": "🚨 {{ event.title }} crossed 70%: {{ explanation.headline }}"
      },
      "delay_seconds": 0
    },
    {
      "type": "agencio_pause_campaign",
      "config": {
        "campaign_id": "campaign-uuid"
      },
      "delay_seconds": 0
    },
    {
      "type": "notify_email",
      "config": {
        "to": ["cmo@company.com"],
        "template": "probability_alert"
      },
      "delay_seconds": 300
    }
  ],

  "cooldown_minutes": 60,
  "max_fires_per_day": 5,
  "active_hours": {
    "timezone": "America/New_York",
    "start": "08:00",
    "end": "22:00"
  },
  "expires_at": null
}
```

### Scope Types

| Scope | Description |
|-------|-------------|
| `event` | Triggers on a specific event |
| `category` | Triggers on any event in a category |
| `all` | Triggers on any event in the system |
| `campaign` | Triggers on a specific marketing campaign |
| `tag` | Triggers on any event with a specific tag |

### Composite Rule Example

```json
{
  "name": "High-confidence reversal with manipulation risk",
  "trigger": {
    "type": "all_of",
    "params": {
      "triggers": [
        {
          "type": "prob_shift",
          "params": { "delta": -0.15, "window_minutes": 120 }
        },
        {
          "type": "manipulation_risk",
          "params": { "level": "HIGH" }
        }
      ]
    }
  },
  "actions": [
    {
      "type": "notify_slack",
      "config": {
        "webhook_url": "...",
        "body_template": "⚠️ SUSPICIOUS REVERSAL: {{ event.title }} dropped {{ event.probability_delta | percent }} with HIGH manipulation risk. Trust: {{ trust.overall_score | percent }}. Flag: {{ trust.flag_description }}"
      }
    },
    {
      "type": "agencio_pause_campaign",
      "config": { "campaign_id": "{{ campaign.id }}" }
    },
    {
      "type": "generate_explanation",
      "config": {}
    }
  ]
}
```

---

## System-Level (Pre-built) Rules

These ship out of the box and run for all users. Users can disable them.

| Rule | Trigger | Action |
|------|---------|--------|
| Explanation on big move | `prob_shift` (delta > 0.10, window 240min) | `generate_explanation` |
| Trust recompute on volume spike | `volume_spike` (count > 50, window 30min) | `recompute_trust` |
| Alert on critical manipulation | `trust_flag_raised` (severity CRITICAL) | `notify_in_app` to event followers |
| Resolution reminder | `resolution_approaching` (7 days) | `notify_email` to event creator |
| Campaign repredict on market shift | `prob_shift` (delta > 0.15) + event linked to campaign | `agencio_trigger_repredict` |
| Calibration update on resolution | `event_resolved` (ANY) | Recompute calibration scores |

---

## Database Schema

### prediction_rules

```sql
CREATE TABLE prediction_rules (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL REFERENCES auth.users(id),

  -- Definition
  name TEXT NOT NULL,
  description TEXT,
  enabled BOOLEAN DEFAULT true,

  -- Scope
  scope_type TEXT NOT NULL CHECK (scope_type IN ('event', 'category', 'all', 'campaign', 'tag')),
  scope_id UUID,              -- event_id, category_id, campaign_id (NULL for 'all')
  scope_tag TEXT,              -- for tag scope

  -- Trigger
  trigger_type TEXT NOT NULL,
  trigger_params JSONB NOT NULL DEFAULT '{}',

  -- Actions (ordered array)
  actions JSONB NOT NULL DEFAULT '[]',
  -- Each action: { "type": "...", "config": {...}, "delay_seconds": 0 }

  -- Throttling
  cooldown_minutes INTEGER DEFAULT 60,
  max_fires_per_day INTEGER DEFAULT 10,
  active_hours JSONB,          -- { "timezone": "...", "start": "08:00", "end": "22:00" }

  -- Lifecycle
  is_system BOOLEAN DEFAULT false,  -- system-level pre-built rule
  expires_at TIMESTAMPTZ,
  last_fired_at TIMESTAMPTZ,
  fire_count INTEGER DEFAULT 0,

  created_at TIMESTAMPTZ DEFAULT now(),
  updated_at TIMESTAMPTZ DEFAULT now()
);

CREATE INDEX idx_rules_user ON prediction_rules(user_id);
CREATE INDEX idx_rules_scope ON prediction_rules(scope_type, scope_id);
CREATE INDEX idx_rules_enabled ON prediction_rules(enabled) WHERE enabled = true;
CREATE INDEX idx_rules_trigger ON prediction_rules(trigger_type);
```

### prediction_rule_executions

Audit log of every rule fire.

```sql
CREATE TABLE prediction_rule_executions (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  rule_id UUID NOT NULL REFERENCES prediction_rules(id) ON DELETE CASCADE,
  event_id UUID REFERENCES prediction_events(id),

  -- What triggered it
  trigger_snapshot JSONB NOT NULL,  -- state at time of trigger
  -- e.g., { "probability": 0.72, "previous": 0.45, "delta": 0.27 }

  -- Execution status
  status TEXT NOT NULL DEFAULT 'PENDING'
    CHECK (status IN ('PENDING', 'EXECUTING', 'COMPLETED', 'PARTIAL_FAILURE', 'FAILED', 'SKIPPED_COOLDOWN', 'SKIPPED_HOURS', 'SKIPPED_LIMIT')),

  -- Action results (one per action in the rule)
  action_results JSONB DEFAULT '[]',
  -- Each: { "action_type": "...", "status": "success|failed", "response": {...}, "error": "...", "executed_at": "..." }

  started_at TIMESTAMPTZ DEFAULT now(),
  completed_at TIMESTAMPTZ,
  error_message TEXT
);

CREATE INDEX idx_executions_rule ON prediction_rule_executions(rule_id);
CREATE INDEX idx_executions_event ON prediction_rule_executions(event_id);
CREATE INDEX idx_executions_status ON prediction_rule_executions(status);
CREATE INDEX idx_executions_started ON prediction_rule_executions(started_at DESC);
```

### prediction_action_connections

Stores user OAuth tokens / API keys for external platforms.

```sql
CREATE TABLE prediction_action_connections (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL REFERENCES auth.users(id),

  platform TEXT NOT NULL,
  -- 'slack', 'discord', 'google_ads', 'meta_ads', 'tiktok_ads',
  -- 'zapier', 'make', 'n8n', 'google_sheets', 'airtable', 'twilio'

  -- Credentials (encrypted at rest)
  credentials JSONB NOT NULL,    -- { "access_token": "...", "refresh_token": "...", ... }
  scopes TEXT[],                 -- OAuth scopes granted

  -- Status
  status TEXT DEFAULT 'ACTIVE' CHECK (status IN ('ACTIVE', 'EXPIRED', 'REVOKED', 'ERROR')),
  last_used_at TIMESTAMPTZ,
  expires_at TIMESTAMPTZ,
  error_message TEXT,

  created_at TIMESTAMPTZ DEFAULT now(),
  updated_at TIMESTAMPTZ DEFAULT now()
);

CREATE UNIQUE INDEX idx_connections_user_platform ON prediction_action_connections(user_id, platform);
```

---

## API Endpoints

### Rules CRUD

```
GET    /api/predict/v1/rules                    → list user's rules
GET    /api/predict/v1/rules/:id                → get rule detail
POST   /api/predict/v1/rules                    → create rule
PUT    /api/predict/v1/rules/:id                → update rule
DELETE /api/predict/v1/rules/:id                → delete rule
POST   /api/predict/v1/rules/:id/toggle         → enable/disable
POST   /api/predict/v1/rules/:id/test           → dry-run (simulate trigger)
```

### Rule Executions

```
GET    /api/predict/v1/rules/:id/executions     → execution history
GET    /api/predict/v1/executions               → all executions for user
GET    /api/predict/v1/executions/:id           → execution detail + action results
POST   /api/predict/v1/executions/:id/retry     → retry a failed execution
```

### Connections

```
GET    /api/predict/v1/connections               → list connected platforms
POST   /api/predict/v1/connections/:platform/auth → initiate OAuth flow
DELETE /api/predict/v1/connections/:platform      → disconnect platform
POST   /api/predict/v1/connections/:platform/test → test connection
```

### System Rules

```
GET    /api/predict/v1/rules/system              → list system-level rules
PUT    /api/predict/v1/rules/system/:id/override  → user override (enable/disable)
```

---

## Evaluation Engine

### How Triggers Are Evaluated

```
Signal Ingest / Snapshot Update
         │
         ▼
┌─────────────────────────────┐
│  1. Load active rules       │
│     matching this event's   │
│     scope (event, category, │
│     tag, all)               │
└──────────┬──────────────────┘
           │
           ▼
┌─────────────────────────────┐
│  2. For each rule:          │
│     - Evaluate trigger      │
│       condition against     │
│       current + previous    │
│       state                 │
│     - Check cooldown        │
│     - Check active hours    │
│     - Check daily limit     │
└──────────┬──────────────────┘
           │ (rules that pass)
           ▼
┌─────────────────────────────┐
│  3. For each fired rule:    │
│     - Create execution      │
│       record (PENDING)      │
│     - Queue actions         │
│     - Update last_fired_at  │
│     - Increment fire_count  │
└──────────┬──────────────────┘
           │
           ▼
┌─────────────────────────────┐
│  4. Action Executor:        │
│     - Execute each action   │
│       (respecting delay)    │
│     - Log result per action │
│     - Mark execution status │
│     - Retry on transient    │
│       failure (max 3x)      │
└─────────────────────────────┘
```

### State Tracking for "Crosses" Triggers

"Crosses above" means the value was below and is now above. We need previous state.

```sql
-- Stored on prediction_events
ALTER TABLE prediction_events ADD COLUMN previous_probability DECIMAL(5,4);
ALTER TABLE prediction_events ADD COLUMN previous_sentiment DECIMAL(5,4);
ALTER TABLE prediction_events ADD COLUMN previous_trust_score DECIMAL(5,4);
ALTER TABLE prediction_events ADD COLUMN previous_divergence TEXT;

-- Updated atomically on every snapshot:
UPDATE prediction_events SET
  previous_probability = current_probability,
  current_probability = NEW_VALUE,
  previous_sentiment = sentiment_score,
  sentiment_score = NEW_VALUE,
  -- etc.
WHERE id = EVENT_ID;
```

### Evaluation Pseudocode

```typescript
async function evaluateTriggers(eventId: string, previousState: EventState, newState: EventState) {
  // 1. Load applicable rules
  const rules = await loadActiveRules(eventId, newState.category_id, newState.tags);

  for (const rule of rules) {
    // 2. Check throttle
    if (isInCooldown(rule)) continue;
    if (isOutsideActiveHours(rule)) continue;
    if (hasExceededDailyLimit(rule)) continue;

    // 3. Evaluate trigger
    const fired = evaluateTrigger(rule.trigger_type, rule.trigger_params, previousState, newState);

    if (fired) {
      // 4. Create execution record
      const execution = await createExecution(rule, eventId, { previousState, newState });

      // 5. Queue actions
      for (const action of rule.actions) {
        if (action.delay_seconds > 0) {
          await scheduleAction(execution.id, action, action.delay_seconds);
        } else {
          await executeAction(execution.id, action, newState);
        }
      }

      // 6. Update rule metadata
      await updateRuleFireMetadata(rule.id);
    }
  }
}
```

---

## Frontend Components

### Rules Page (`/predict/rules`)

```
┌──────────────────────────────────────────────────────────┐
│  Triggers & Actions                    [+ Create Rule]   │
│                                                          │
│  ┌── Active Rules ─────────────────────────────────────┐ │
│  │                                                     │ │
│  │  ☑ Alert team when Iran odds spike         ⚡ 3/day │ │
│  │    prob_crosses_above(0.70) → Slack + Pause         │ │
│  │    Last fired: 2 hours ago                  [Edit]  │ │
│  │                                                     │ │
│  │  ☑ Manipulation warning on elections       ⚡ 0/day │ │
│  │    trust_flag_raised(CRITICAL) → Email + Slack      │ │
│  │    Never fired                              [Edit]  │ │
│  │                                                     │ │
│  │  ☐ Pause ads on market crash (disabled)    ⚡ 1/day │ │
│  │    prob_shift(-0.20, 60min) → Google Ads pause      │ │
│  │    Last fired: 5 days ago                   [Edit]  │ │
│  │                                                     │ │
│  └─────────────────────────────────────────────────────┘ │
│                                                          │
│  ┌── Recent Executions ────────────────────────────────┐ │
│  │                                                     │ │
│  │  ✅ Alert team when Iran odds spike  2h ago         │ │
│  │     → Slack: sent ✓  Pause campaign: sent ✓         │ │
│  │                                                     │ │
│  │  ✅ [System] Explanation on big move  4h ago        │ │
│  │     → generate_explanation: completed ✓             │ │
│  │                                                     │ │
│  │  ❌ Pause ads on market crash  5d ago               │ │
│  │     → Google Ads pause: FAILED (auth expired)       │ │
│  │                                           [Retry]   │ │
│  └─────────────────────────────────────────────────────┘ │
│                                                          │
│  ┌── Connected Platforms ──────────────────────────────┐ │
│  │  ✅ Slack          Connected     [Test] [Disconnect]│ │
│  │  ✅ Google Ads     Connected     [Test] [Disconnect]│ │
│  │  ⚠️ Meta Ads       Token expired [Reconnect]        │ │
│  │  ➕ Discord        [Connect]                        │ │
│  │  ➕ Zapier         [Connect]                        │ │
│  │  ➕ Google Sheets  [Connect]                        │ │
│  └─────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘
```

### Rule Builder (Modal / Page)

```
┌──────────────────────────────────────────────────────────┐
│  Create Rule                                             │
│                                                          │
│  Name: [Alert team when Iran odds spike_________]        │
│                                                          │
│  ── WHEN (Trigger) ───────────────────────────────────── │
│                                                          │
│  Scope:  ○ Specific event  ○ Category  ○ Tag  ○ All     │
│  Event:  [Iran escalation → oil > $100?        ▼]       │
│                                                          │
│  Condition: [Probability crosses above         ▼]       │
│  Threshold: [0.70_____]                                  │
│                                                          │
│  [+ Add another condition (AND)]                         │
│                                                          │
│  ── THEN (Actions) ──────────────────────────────────── │
│                                                          │
│  Action 1: [Send Slack message               ▼]         │
│  Channel:  [#predictions________________________]        │
│  Message:  [🚨 {{ event.title }} crossed 70%    ]        │
│  Delay:    [Immediately                      ▼]         │
│                                                          │
│  Action 2: [Pause Agencio campaign           ▼]         │
│  Campaign: [Summer sneaker push              ▼]         │
│  Delay:    [Immediately                      ▼]         │
│                                                          │
│  Action 3: [Send email                       ▼]         │
│  To:       [cmo@company.com_____________________]        │
│  Delay:    [5 minutes                        ▼]         │
│                                                          │
│  [+ Add action]                                          │
│                                                          │
│  ── Settings ─────────────────────────────────────────── │
│                                                          │
│  Cooldown:    [60] minutes between fires                 │
│  Max/day:     [5] fires per day                          │
│  Active hours: [08:00] to [22:00] [America/New_York ▼]  │
│  Expires:      [Never                           ▼]      │
│                                                          │
│           [Cancel]  [Test Rule (Dry Run)]  [Save Rule]   │
└──────────────────────────────────────────────────────────┘
```

---

## Example Use Cases

### 1. Marketing: Auto-pause ads when geopolitical risk spikes
```
WHEN: "US-China trade war" probability crosses above 80%
THEN: Pause Google Ads campaigns targeting Chinese market
  AND: Notify marketing lead on Slack
  AND: Generate AI recommendation for adjusted strategy
```

### 2. Trading: Divergence alert
```
WHEN: Any event divergence reaches EXTREME
  AND: Trust score is above 0.6 (not manipulation)
THEN: Send Discord alert with event details
  AND: Log to Google Sheet for tracking
```

### 3. Campaign: Auto-optimise based on prediction
```
WHEN: Campaign variant winner changes (B was winning, now A is)
THEN: Swap active variant in Agencio
  AND: Notify team on Slack
  AND: Re-run prediction with latest signals
```

### 4. Compliance: Manipulation early warning
```
WHEN: Trust flag raised with severity CRITICAL
  AND: Event is in "Finance" category
THEN: Send email to compliance team
  AND: Generate full trust audit report
  AND: Pause any campaigns linked to this event
```

### 5. Content: Automated reporting
```
WHEN: Any event resolves (YES or NO)
THEN: Generate AI report on prediction accuracy
  AND: Append to Google Sheet (prediction log)
  AND: Send summary to newsletter list via webhook
```

### 6. Sequence: Escalation chain
```
WHEN: Probability shifts > 20% in 2 hours (first alert)
THEN: Send Slack notification

WHEN: Same event probability shifts > 30% in 4 hours (escalation)
  AND: Previous rule fired within 4 hours
THEN: Send SMS to CEO
  AND: Pause all campaigns in category
  AND: Generate emergency briefing
```

---

## Build Phase

This system fits into **Phase 3.5** (between Trust Layer and Marketing Engine):

### Phase 3.5 Tasks:
- [ ] Create `prediction_rules` table
- [ ] Create `prediction_rule_executions` table
- [ ] Create `prediction_action_connections` table
- [ ] Add `previous_*` columns to `prediction_events`
- [ ] Build trigger evaluation engine (runs on signal ingest)
- [ ] Build action executor (with retry logic)
- [ ] Implement core triggers: `prob_crosses_above/below`, `prob_shift`, `trust_flag_raised`
- [ ] Implement core actions: `webhook`, `notify_slack`, `notify_email`, `notify_in_app`
- [ ] Rules CRUD API
- [ ] Connections API + OAuth flow (Slack first)
- [ ] Rules page UI (`/predict/rules`)
- [ ] Rule builder modal
- [ ] Execution log UI
- [ ] System rules (explanation generation, trust recompute)
- [ ] Dry-run / test mode

### Phase 4+ additions:
- [ ] Agencio campaign actions (pause, resume, swap variant)
- [ ] Google Ads / Meta Ads integrations
- [ ] Composite triggers (all_of, any_of, sequence)
- [ ] Zapier / Make / n8n connectors
- [ ] Google Sheets / Airtable logging
