# UI/UX Plan — Agent Console

**Status:** Draft for review
**Parent doc:** [Proposal_arch.md](Proposal_arch.md) §2 (L6 Agent Console), §12 item 4
**Scope:** Screens, navigation, and interaction patterns for the human-facing side of the agent system — grounded in this app's actual component library and conventions, not a new design language.

---

## 0. What this is built on (verified, not assumed)

A separate pass read the real code before designing anything, because this app's declared dependencies are misleading on their own:

- **PetalComponents is the real component library.** `use PetalComponents` is wired into `html_helpers/0` in `apps/platform_web/lib/platform_web.ex:94`, so every LiveView gets `<.slide_over>`, `<.input>`, `<.select>`, etc. for free. `salad_ui` is declared in `mix.exs` but a repo-wide grep found **zero usage** in `platform_web` — don't design against it.
- **Most page body content is raw HEEx + Tailwind**, with Petal used selectively for forms, badges, and the slide-over pattern. This plan follows that convention — Petal where it already does the job, plain markup otherwise.
- **AG Grid is a JS asset, not an Elixir dependency**, wired via `phx-hook`. Every existing list screen (terminals, transactions, settlements) uses the same contract: `phx-hook="<X>AgGridHook"`, `data-rows`, `data-cols`, `data-row-click-event`. New screens follow it exactly — see §2.
- **Navigation is provider-based, not hardcoded.** `PlatformWeb.SidebarComponent` renders `PlatformCore.Menu.Provider` modules composed by `apps/platform_web/lib/platform_web/menu/registry.ex`, ordered by a hardcoded `group_order/1` map (`"Dashboard" => 0, "Terminal Management" => 1, ... "System" => 8`). A new top-level section is a new Provider module + a new `group_order` entry — not a hand-edited template.
- **Permissions are dotted strings**, checked via `PlatformWeb.Authorization.can?/2`, format `"<domain>.<resource>.<action>"`, enforced per-route via `on_mount: [..., {PlatformWeb.UserAuth, {:require_permission, "..."}}]` in a `live_session` (router.ex). Most existing `live_session`s don't enforce a permission at mount — only `:settlement_admin` and `:merchant_portal` do. The Agent Console should follow their pattern, not the unenforced default, given what it exposes (§4).
- **The slide-over detail pattern already exists and should be reused as-is**, not reinvented: `apps/platform_web/lib/platform_web/live/terminal_live/index.html.heex:160` — `@selected_terminal` assign toggles a `<.slide_over origin="right" title={...}>`, addressable both by state (click a grid row) and by route (`live "/terminals/:serial_number", ..., :slide_over`), with internal tabs via `phx-click="set_tab"`.
- **The closest existing analog to an incident feed** is `apps/platform_web/lib/platform_web/live/alerts_live.ex` — query-param-driven tabs, a PubSub subscription (`TmsCore.TerminalManagement.subscribe_to_device_updates()`), and a 60-second poll (`Process.send_after(self(), :check_alerts, 60_000)`). The Incident Feed (§2) should follow this same shape — PubSub-pushed updates plus a poll fallback — rather than inventing a different refresh model.

---

## 1. Information architecture

New top-level nav group — call it **"Agentic AI"** (or "Intelligent Operations," matching [business-brief.md](business-brief.md)'s working name; Marketing's call) — inserted into `group_order/1` between "Risk Management" (4) and "Settlement" (5), or after "System" (8) if this should read as an operations layer rather than a peer domain. Recommend after "System" — it operates *across* the other domains, not alongside one of them.

```
/agents                              Agent Console home → redirects to /agents/incidents
/agents/incidents                    Incident Feed (default tab)
/agents/approvals                    Approval Queue
/agents/investigations               Investigation Console (A6, free-text + report history)
/agents/investigations/:id           A single Investigation Report, full detail
/agents/playbooks                    Playbook list + editor
/agents/policies                     Per-agent mode, provider routing, kill switch
/agents/audit                        Audit export
```

Implemented as one `PlatformWeb.AgentLive` module with tab-based routing (matching `alerts_live.ex`'s `?tab=` pattern) for the first five, plus two dedicated routes (`/agents/investigations/:id` for a permalink-able report, `/agents/audit` for export) where deep-linking or a distinct permission boundary matters more than tab convenience.

---

## 2. Screen specs

### 2.1 Incident Feed (`/agents/incidents`, default tab)

**Purpose:** the operational home screen — every open `agent_incident`, correlated (A7 already deduplicated 400 alerts into one row, per parent doc §3).

**Layout:** AG Grid, same contract as `terminal_live`:
```heex
<div id="incidentGrid"
     phx-hook="AgentIncidentAgGridHook"
     phx-update="ignore"
     data-rows={Jason.encode!(@incidents)}
     data-cols='[{"headerName":"Severity","field":"severity"},
                 {"headerName":"Domain","field":"domain"},
                 {"headerName":"Subject","field":"subject_ref"},
                 {"headerName":"Status","field":"status"},
                 {"headerName":"Opened","field":"opened_at"},
                 {"headerName":"Owning Agent","field":"owning_agent"}]'
     data-row-click-event="show_incident_detail"
     class="ag-theme-alpine w-full h-[600px] rounded-lg border border-gray-200">
</div>
```
Filter bar above the grid: severity, domain (fleet/config/rollout/settlement/risk/infra — matching A1–A8), status (open/resolved), owning agent. Live updates via a PubSub subscription to `agent_incidents` changes (new incident, status change) — same pattern as `alerts_live.ex`'s device-update subscription — plus a 30–60s poll fallback for anything the subscription misses.

Row click → opens the **Decision Card** slide-over (§2.2), not a full page navigation, exactly like clicking a terminal row today.

### 2.2 Decision Card (slide-over, opened from any incident/action row)

**Purpose:** the single most important screen in the whole feature — this is where an operator decides whether to trust the agent. Reuses `<.slide_over>` verbatim:

```heex
<%= if @selected_incident do %>
  <.slide_over origin="right" title={"Incident: #{@selected_incident.summary}"}>
    <!-- internal tabs, same phx-click="set_tab" pattern as terminal_live -->
  </.slide_over>
<% end %>
```

Internal tabs:
- **Summary** — one-paragraph plain-language explanation, confidence badge (LOW/MEDIUM/MEDIUM-HIGH/HIGH, matching the investigation doc's enum), fingerprint, correlated observation count.
- **Reasoning** — the model's stated hypothesis, in full, not truncated. This is the "never trust the summary" principle from the investigation design made visible in the UI, not just a backend property.
- **Evidence** — every cited evidence item, expandable to the raw tool result (matches investigation doc §5's mandatory citation rule — if the backend enforces "no uncited claims," the UI should make every claim clickable to its evidence, or the enforcement is invisible to the person who needs to trust it).
- **Proposed Actions** — ordered list, each showing risk tier (T1/T2/T3, plain-language: "Automatic," "Needs your approval," "Requires senior approval"), blast radius, reversibility. **Approve** / **Reject** buttons appear only on actions actually awaiting approval (T2/T3 in `:awaiting_approval` status) — T1 actions already executed show as a log line, not a decision point, so the operator isn't asked to approve something that already happened.
- **History** — for a recurring fingerprint, prior incidents and their outcomes (`agent_outcomes`), so "has this worked before" is visible without leaving the panel.

Approve/Reject dispatch `phx-click="approve_action"` / `"reject_action"` with the `action_id`, same event-naming convention as `terminal_live`'s `close_slide_over`/`set_tab`.

### 2.3 Approval Queue (`/agents/approvals`)

**Purpose:** a focused list of *only* what needs a human right now — everything else is noise for this screen. Same AG Grid contract, filtered to `agent_actions.status == "awaiting_approval"`, sorted by risk tier then age. Bulk-approve is deliberately **not** offered for T3 — every T3 approval is a single deliberate click on its own Decision Card, never a checkbox-and-batch action. T2 bulk-approve, if requested later, needs its own confirmation step naming every affected device/incident, not a silent count.

### 2.4 Investigation Console (`/agents/investigations`)

**Purpose:** A6's on-demand entry point (investigation doc §8). Not an AG Grid screen — this is closer to a search/chat interface.

- **Ask box** at the top — free-text question, plus structured scope pickers (subject type, time window) for when the question is precise rather than exploratory.
- **Live reasoning stream** while a query runs — hypotheses appear, then get struck through as evidence refutes them (investigation doc §4's hypothesis/discriminating-test loop, made visible). This is explicitly called out in the investigation design as *"what builds operator trust faster than any accuracy number"* — worth protecting in implementation, not cutting for scope.
- **Report view** (§5 format from the investigation doc) once complete: Finding → Evidence → Hypotheses Considered (supported/refuted/untested) → Suggested Actions (with risk tier, explicitly marked "you execute this, not the agent") → Limitations.
- **From-anywhere entry points**: an "Investigate" button on the Decision Card, on a terminal detail slide-over, and on an SLA-breach alert — pre-filling scope, per investigation doc §8.
- **Rate** — two-click useful/partly/wrong, plus optional free text. The investigation doc is explicit that anything more than two clicks won't get used; that constraint should survive into the actual button layout, not just the spec.
- **History** at `/agents/investigations` (list) and `/agents/investigations/:id` (permalink) — searchable past reports, with the doc's caching note honored: an identical scope within the last hour surfaces the cached prior report before spending tokens on a repeat.

### 2.5 Playbook Editor (`/agents/playbooks`)

**Purpose:** human-editable `agent_playbooks` (parent doc §5) — this is the literal UI for what D7 calls "skills." List view (name, domain, fingerprint pattern, success_rate, times_applied, is_active) + a markdown editor for content, preconditions, and recommended tools. New playbooks proposed by the nightly learning job (parent doc §7) land here in a **pending-review** state, visually distinct from human-authored ones, and require an explicit human "activate" action — never auto-activated, per the parent doc's explicit safeguard.

### 2.6 Agent Policies & Kill Switch (`/agents/policies`)

**Purpose:** the control panel, and the most permission-sensitive screen in the feature.

- Per-agent mode selector: `:shadow | :suggest | :auto_low_risk | :auto`, per environment.
- Per-agent/per-environment **provider routing** (D6): Anthropic / OpenAI / Ollama, surfaced plainly — this is also where a data-residency-driven Ollama mandate (§12 item 1) gets enforced operationally, not just in code.
- **Global kill switch** — one prominent, unmistakable control, separate from and more visually weighted than any per-agent toggle. Confirmation required (type-to-confirm or equivalent), not a bare click, given what it does.
- Confidence floors, blast-radius caps, rate limits — read-only display of current values in the first version; editable in a later phase once the numbers have real operating history behind them, not day-one.

### 2.7 Audit Export (`/agents/audit`)

**Purpose:** the compliance-facing screen — matches the existing "Export Reports" pattern already used elsewhere in the app (TMS RFP doc §2.2). Filterable by agent, date range, risk tier, outcome; exports `agent_decisions` + `agent_actions` to CSV. No dashboard chrome needed here — this screen exists for a regulator or an auditor, not day-to-day ops.

---

## 3. Permissions

Proposed dotted-permission strings, following the existing `"<domain>.<resource>.<action>"` convention (`authorization.ex`):

| Permission | Grants |
|---|---|
| `agents.console.view` | Base access to `/agents/*` — without it, the nav item doesn't render (`can_any?/2` in menu registry) |
| `agents.incidents.view` | Incident Feed + Decision Card (read) |
| `agents.actions.approve` | Approve/Reject buttons on T2/T3 actions |
| `agents.investigations.use` | Investigation Console — ask, view, rate |
| `agents.playbooks.manage` | Playbook Editor — create/edit/activate |
| `agents.policy.manage` | Policies screen, **including the kill switch** — recommend restricting this to a smaller set than general ops access, given the blast radius of a mistaken toggle |
| `agents.audit.export` | Audit export screen |

The Agent Console's `live_session` should enforce `agents.console.view` at `on_mount`, following the `:settlement_admin`/`:merchant_portal` pattern (router.ex) rather than the unenforced `:default` session — this is a system that takes actions on payment terminals; it shouldn't inherit the "authenticated is enough" default that most read-only pages use today.

---

## 4. What this deliberately does not do in v1

- **No mobile-optimized layout.** This app's existing screens (AG Grid-heavy, slide-over panels) are desktop-oriented; the Agent Console follows suit. Revisit only if ops actually need on-call mobile access.
- **No custom charting library.** Any trend visualization (e.g. A8's BEAM/jPOS metrics, once §1.7 lands) should reuse whatever charting the app already has (AG Charts, per the Cloud Layer RFP doc) rather than introducing a second one.
- **No real-time collaborative editing** on playbooks — last-write-wins with a version bump is sufficient for a human-edited, agent-consumed document; this isn't a shared document editor.

---

## 5. Build sequencing (maps to Proposal_arch.md §10)

| Phase | Screens |
|---|---|
| Phase 1 (A6 Investigation) | Investigation Console (§2.4) — the only screen this phase needs, since A2 doesn't exist yet to generate incidents |
| Phase 2 (A2 shadow → T1) | Incident Feed (§2.1) + Decision Card (§2.2), scoped to A2's incidents only at first — this is also the shadow-vs-`VersionComplianceChecker` comparison view called out in §10 |
| Phase 3 (fleet + orchestration + A8) | Approval Queue (§2.3), full Incident Feed across A1/A3/A7/A8, Policies screen (§2.6) — approval gating only matters once T2/T3 actions exist |
| Phase 4 (settlement + risk + learning) | Playbook Editor (§2.5) — the learning loop's review queue needs a UI once it's actually producing candidate playbooks |
| Ongoing | Audit Export (§2.7) — build whenever compliance needs it; not gated on any other screen |
