# Whiteboard System Audit — 2026-05-26

## Executive Summary

The whiteboard system is **substantially complete**. Two gaps were identified and fixed in this run: (C) no whiteboard skill for agents, and (E) no in-UI test runner.

---

## Gap Matrix

### Panel Component
| Item | Status | Notes |
|------|--------|-------|
| Present | ✅ | `ui/src/ui/views/canvas-overlay.ts` |
| Functional | ✅ | Draggable/resizable floating overlay |
| Wired to backend | ✅ | Uses `mountMcpCanvas()` — same singleton as dedicated page |
| Click-to-expand | ✅ | Opens `#whiteboard` tab navigation |

### Dedicated UI Page (`/whiteboard` tab)
| Item | Status | Notes |
|------|--------|-------|
| Route registered | ✅ | `ui/src/ui/navigation.ts` line 116; Tab in "Media" group |
| Renders | ✅ | `renderMcpCanvasOnly()` in `ui/src/ui/views/whiteboard.ts` |
| Excalidraw mounted | ✅ | `mountMcpCanvas()` mounts React Excalidraw via `queueMicrotask` on container |
| Full-screen | ✅ | `.mcp-canvas-mount` has `flex:1; width:100%; height:100%` |
| Save/load wired | ✅ | `saveMcpCanvasToBoard()` / `loadBoardToMcpCanvas()` in controller |
| Templates | ✅ | 5 built-in templates (blank, flowchart, mindmap, wireframe, kanban) |
| Canvas Agent panel | ✅ | Right-side chat panel connected to `canvas` agent via `sessions.spawn` |

### Per-Agent-Type Integration
| Agent | Excalidraw tools accessible? | Notes |
|-------|------------------------------|-------|
| `main` | ✅ | Full MCP proxy → `mcp__infinibot__excalidraw_*` tools available |
| `coder` | ✅ | Same — all agents share the InfiniBot MCP server registry |
| `canvas` | ✅ | Primary intended agent; Canvas Agent panel spawns this |
| `voice` | ✅ | Same MCP proxy access |

All excalidraw tool calls flow: Agent → `mcp__infinibot__excalidraw_*` → `extensions/mcp-excalidraw` → `canvas.update` gateway broadcast → `app-gateway.ts` bridge → `excalidraw-update` DOM event → React canvas `updateScene()`.

### Skill Registration
| Agent | Whiteboard skill | Notes |
|-------|-----------------|-------|
| `main` | ❌ → **FIXED** | `skills/whiteboard/SKILL.md` created |
| `coder` | ❌ → **FIXED** | Same skill is discoverable by all agents |
| `canvas` | ❌ → **FIXED** | Primary beneficiary — guides diagram creation |
| `voice` | ❌ → **FIXED** | Same skill |

The existing `skills/canvas/SKILL.md` documents the **node-canvas** (HTML on iOS/Mac/Android), not Excalidraw. A dedicated `skills/whiteboard/SKILL.md` was missing.

### UI Test Status
| Item | Status | Notes |
|------|--------|-------|
| Existing whiteboard tests | ❌ | None |
| Test framework | ✅ | Vitest 4.0.18 + @vitest/browser-playwright in `ui/` |
| "Run tests" button | ❌ → **FIXED** | Added to whiteboard toolbar |
| In-page test results | ❌ → **FIXED** | Test panel renders below toolbar |

---

## Fixed In This Run

### C. Whiteboard Skill
- **Created**: `skills/whiteboard/SKILL.md`
- Documents all 18 excalidraw MCP tools
- Includes element type reference, coordinate system, and usage examples
- Covers agent↔whiteboard event flow

### E. In-UI Test Runner
- **Modified**: `ui/src/ui/views/whiteboard.ts`
- Added "🧪 Tests" button to the MCP canvas toolbar
- Added `renderTestPanel()` function with 5 test cases:
  1. Create element — push rectangle, verify `getMountedSceneElements()` finds it
  2. Update element — change strokeColor, verify property updated
  3. Delete element — push empty scene, verify element gone
  4. Query elements — push mixed types, verify rectangle + ellipse present
  5. Gateway roundtrip — `client.request("canvas.update")` → verify DOM event received
- Tests show pass/fail/running state inline with duration

---

## Architecture Reference

```
extensions/mcp-excalidraw/src/tools.ts   — 18 MCP tools (agent surface)
                ↓ calls
extensions/mcp-excalidraw/src/canvas-state.ts  — in-memory element store
                ↓ via
extensions/mcp-excalidraw/src/gateway-bridge.ts — gateway.request("canvas.update")
                ↓
src/gateway/server-methods/canvas.ts     — broadcast to all UI clients
                ↓
ui/src/ui/app-gateway.ts (lines 428–457) — translate to excalidraw-update DOM event
                ↓
ui/src/ui/views/whiteboard.ts            — React McpCanvasWrapper listens → updateScene()
```

Panel singleton: `mountMcpCanvas()` is a module-level singleton — only one React root at a time. Navigating between the overlay and the dedicated page re-mounts the canvas into the new container.
