# Contract — Agentic UI API v1.1 (Spec 030)

Extensão da API Spec 029. Base: `/api/v1/agents`.

**Auth:** igual 029 — JWT ops view (`get_current_user` + `_ops_view`).

---

## GET `/overview`

Resumo para status bar.

**Response 200:**

```json
{
  "tier": "t1",
  "ollama": true,
  "model": "qwen2.5:7b-instruct",
  "last_tick_at": "2026-06-20T06:32:02.723068+00:00",
  "last_tick_status": "degraded",
  "scenarios_total": 9,
  "scenarios_ok": 5,
  "incidents_open": {
    "critical": 0,
    "high": 2,
    "warn": 2,
    "info": 0
  },
  "worker_interval_sec": 600
}
```

---

## GET `/incidents`

Lista deduplicada para mission board.

**Query:**

| Param | Tipo | Default |
|-------|------|---------|
| `status` | `open` \| `ack` \| `all` | `open` |
| `severity` | string | — |
| `agent_id` | string | — |
| `limit` | int | 50 |

**Response 200:**

```json
{
  "incidents": [
    {
      "id": 1,
      "scenario_id": "vm123.finance.stack",
      "title": "FOSSBilling VM123 down",
      "severity": "high",
      "status": "open",
      "primary_agent": "sentinel",
      "agent_name": "Vigia",
      "occurrence_count": 12,
      "first_seen_at": "2026-06-19T23:45:16Z",
      "last_seen_at": "2026-06-20T06:32:02Z",
      "suggested_human_action": "Verificar docker compose VM123 finance stack",
      "thread_id": 47,
      "latest_finding_id": 253
    }
  ]
}
```

---

## GET `/incidents/{id}`

Detalhe + runs recentes do cenário.

**Response 200:**

```json
{
  "incident": { "...": "..." },
  "recent_runs": [
    {
      "run_id": 758,
      "status": "degraded",
      "started_at": "2026-06-20T06:25:34Z",
      "findings_count": 1
    }
  ],
  "thread_id": 47
}
```

---

## POST `/incidents/{id}/ack`

Ack incidente, mensagens inbox associadas, e finding latest.

**Response 200:**

```json
{
  "ok": true,
  "incident_id": 1,
  "thread_id": 47,
  "findings_acked": 1
}
```

**RBAC:** `super_admin`, `ops_lead`, `technician`, `agentic_operator`, `devops`, `security_analyst` (mesmo `_ops_view`).

---

## Alteração no tick (runner)

Pseudo-lógica em `notify_finding_to_operators`:

```
1. Upsert agent_incidents ON scenario_id
   - increment occurrence_count
   - update last_seen_at, latest_finding_id, severity (max)
2. Reutilizar thread_id do incidente se open
3. Post message apenas se severity escalou OU first_seen OR human_action mudou
```

Evita 140 threads para 4 cenários.

---

## Frontend consumption

```javascript
// agentic-ops v2 boot
const [overview, incidents] = await Promise.all([
  agentsApi('/overview'),
  agentsApi('/incidents?status=open'),
]);
```

Fallback UI-A (sem backend): agrupar `/findings?open_only=true` por `scenario_id` no JS até UI-B deploy.
