# Numu — Agent ↔ Action Assignment Inversion — Implementation Report

**Branch:** `feature/managed-agents` (uncommitted)
**Goal:** Invert ownership of agent↔action assignment — the source of truth moves from **Action Details** to **AI Agents**. Add a dedicated **Action Agent Policies** matrix. Show only *assigned* agents in the Actions table. Redesign Approvals. **No schema changes** — all on the existing `agent_action_policies`.

---

## 1. Implementation summary

| # | Requirement | Status | How |
|---|---|---|---|
| 1 | Assign actions **from AI Agents** (Agent Details → Assigned Actions) | ✅ | New interactive manager on `agents/show`; add/remove/change-policy via AJAX |
| 2 | **Remove "Allowed Agents"** from Action Details (`/admin/labels/options/{id}`) | ✅ | Section replaced with a pointer to the matrix; `showOption` data removed |
| 3 | **🤖 Agents** icon in Actions table (View · Agents · Delete) → matrix | ✅ | Icon between View and Delete → `actions.matrix` |
| 3 | Dedicated **Action Agent Policies** matrix (actions × agents) | ✅ | New `actions/matrix` screen with per-cell policy dropdowns + search |
| 4 | Actions table Policy column shows **only assigned** agents (name + policy); `—` if none | ✅ | Driven by active policies grouped by action_key + agent-name map |
| 5 | Agent Details **Assigned Actions** table (add/remove/change/multi) | ✅ | Action · Policy · Enabled + picker, all multi-action |
| 6 | **Approvals** UI redesign | ✅ | Unified toolbar, dotted badges, empty state, responsive |
| 7 | UI/UX review of the 5 screens | ✅ | Consistent cards/badges/tables/spacing |
| — | Verification | ✅ | Renders + 14 agent tests + assign/unassign smoke |

---

## 2. Schema changes

**None.** The `agent_action_policies` table (already `agent_key × action_key × policy`, temporal via `effective_from`/`effective_to`) backs everything. Assigning = `setPolicy` (versioned), unassigning = close the active row (`effective_to`). Make workflows + slugs untouched.

---

## 3. Ownership model — before / after

```
BEFORE                                AFTER
Actions → Action Details              AI Agents → Agent Details
        → Allowed Agents                       → Assigned Actions   ← source of truth
                                      Actions  → 🤖 → Action Agent Policies (matrix)
                                      Actions table → shows ONLY assigned agents (read)
```

Three consistent views over the same data:
- **Agent Details → Assigned Actions** — per-agent (primary authoring surface).
- **Action Agent Policies matrix** — full grid (bulk, per cell), opened by the 🤖 icon.
- **Actions table → Policy column** — read display of assigned agents only.

---

## 4. API / route changes

| Route | Change |
|---|---|
| `admin.actions.policy` (POST) | **Unified** single-cell endpoint — `policy ∈ {always_allow, needs_approval, blocked, none}`; `none` unassigns; returns JSON for AJAX |
| `admin.actions.matrix` (GET) | **New** — Action Agent Policies matrix (`?tab=&action=`) |
| `admin.actions.agents` (POST) | **Removed** — superseded by the unified endpoint |
| `admin.agents.show` | now passes `assignedActions` + `availableActions` |

No MCP / external API changes.

---

## 5. UI changes

- **AI Agents → Agent Details:** new **Assigned Actions** card — picker (action + policy) to assign; per-row policy dropdown (colored) to change; ✕ to remove; Enabled column; live count; toast. Replaces the old read-only Policies list.
- **Actions table:** Policy column now lists **assigned agents only** as `Name + policy` pairs (`—` when none). New **🤖 Agents** icon (View · 🤖 · Delete) opens the matrix focused on that action.
- **Action Agent Policies (new):** actions (rows) × agents (columns) matrix; each cell a colored policy dropdown saving via AJAX; sticky action column + header; live **search**; Startup/Investor tabs; empty states.
- **Action Details (option page):** "Allowed Agents" removed; replaced by a one-line pointer to the matrix.
- **Approvals:** unified toolbar (status pills + date range in one card), summary count, dotted risk/status badges, polished table, friendly empty state, mobile-responsive (stacked rows with labels).

---

## 6. Verification report

| Check | Result |
|---|---|
| Agent Details renders + assigned/available split | ✅ `intake_triage` → assigned 2 (reject, move_to_review), available 12 |
| Assign via unified endpoint | ✅ `always_allow` persisted |
| Unassign (`policy=none`) | ✅ active policy closed (removed) |
| Actions index renders (both tabs) | ✅ startups + investors |
| Action Agent Policies matrix renders (both tabs) | ✅ startups 14×7 grid; investors empty-state |
| Policy column = assigned agents only | ✅ name + colored policy, `—` when none |
| Option page — Allowed Agents removed | ✅ no `actions.agents` / form in output |
| Approvals redesign renders (with filters) | ✅ date + status combined |
| No stale `actions.agents` references | ✅ none in app/resources/routes |
| Agent test suite | ✅ **14 passed** (29 assertions) |
| Make slugs / automations / policies model | ✅ unchanged |

---

## 7. Migration summary

**No migration.** The earlier `agents.agent_type` (prior task) remains the only Managed-Agents schema addition. This change is UI + one controller endpoint, on existing tables. Nothing to migrate or seed.

---

## 8. Files

**Created:** `resources/views/admin/actions/matrix.blade.php`, this report.
**Modified:** `app/Http/Controllers/Admin/Agents/ActionsController.php` (unified `update` + `matrix`, dropped `agents`), `app/Http/Controllers/Admin/Agents/AgentConsoleController.php` (`show` assigned/available), `app/Http/Controllers/Admin/LabelManagementController.php` (removed `allowedAgents` data), `resources/views/admin/agents/show.blade.php` (Assigned Actions manager), `resources/views/admin/actions/index.blade.php` (🤖 icon + assigned-only Policy column), `resources/views/admin/labels/option-edit.blade.php` (Allowed Agents → pointer), `resources/views/admin/approvals/index.blade.php` (redesign), `routes/web.php` (matrix route, dropped agents route), `lang/en/admin.php`, `lang/ar/admin.php`.
