Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
29183e2
MAESTRO: add AgentInbox types (InboxItem, sort/filter modes, status m…
Feb 15, 2026
94f99bf
MAESTRO: register AgentInbox modal in modal store (ModalId, action, s…
Feb 15, 2026
2122f98
MAESTRO: add Agent Inbox keyboard shortcut (Alt+Cmd+I) with zero-item…
Feb 15, 2026
87b2ef4
MAESTRO: register AgentInbox modal in AppModals with lazy import and …
Feb 15, 2026
1439217
MAESTRO: verify AgentInbox placeholder compilation and mark Phase 01 …
Feb 15, 2026
ee4e2fb
MAESTRO: add useAgentInbox data aggregation hook with null guards and…
Feb 15, 2026
5f34008
MAESTRO: build AgentInbox modal with react-window v2 virtualization a…
Feb 15, 2026
c184cbb
MAESTRO: refine InboxItemCard selection styling and add 14 dedicated …
Feb 15, 2026
85c3464
MAESTRO: implement Tab focus cycling in AgentInbox keyboard navigation
Feb 15, 2026
005a639
MAESTRO: fix requestAnimationFrame memory leak in AgentInbox and add …
Feb 15, 2026
bc2f307
MAESTRO: verify AgentInbox modal integration — lint, tests, and code …
Feb 15, 2026
270c141
MAESTRO: add context usage color-coded bar and null guards in AgentInbox
Feb 15, 2026
8bcd8f4
MAESTRO: add git branch badge styling with SF Mono font, icon prefix,…
Feb 15, 2026
50158c4
MAESTRO: implement smart summary generation with deterministic heuris…
Feb 15, 2026
2680229
MAESTRO: add edge case guards to formatRelativeTime — invalid timesta…
Feb 15, 2026
316978e
MAESTRO: verify Phase 03 — TSC, ESLint, and all 165 AgentInbox tests …
Feb 15, 2026
d2ca4ec
MAESTRO: align sort segmented control to Phase 04 spec — 4px padding,…
Feb 15, 2026
7580232
MAESTRO: add ARIA attributes to AgentInbox filter/sort segmented cont…
Feb 15, 2026
f1b97f4
MAESTRO: add filter-aware empty states to AgentInbox — CheckCircle ic…
Feb 15, 2026
d3c8eca
MAESTRO: apply visual polish to AgentInbox — 150ms fade-in, theme-com…
Feb 15, 2026
476bd26
MAESTRO: verify Phase 04 — full test suite passes clean (19,312 tests…
Feb 15, 2026
5756da3
MAESTRO: verify Phase 05 hook tests — 38 tests pass, all 16 spec item…
Feb 15, 2026
90eb9b7
MAESTRO: add Escape and focus-restoration tests to AgentInbox compone…
Feb 15, 2026
39ea883
MAESTRO: add 17 dedicated helper tests for AgentInbox — formatRelativ…
Feb 15, 2026
24f548f
MAESTRO: mark Phase 05 commit task complete — all Agent Inbox files a…
Feb 15, 2026
ce40db8
MAESTRO: verify Phase 06 naming compliance — all 6 checks pass clean
Feb 15, 2026
1490781
MAESTRO: verify Phase 06 accessibility compliance — all 9 ARIA/focus …
Feb 15, 2026
0ec9c8b
MAESTRO: verify Phase 06 visual specification compliance — all 8 chec…
Feb 15, 2026
99322d1
MAESTRO: verify Phase 06 critical fix compliance — all 5 checks pass …
Feb 15, 2026
0bf20ef
MAESTRO: verify Phase 06 zero-items guard — 5 test cases added, all 5…
Feb 15, 2026
d7713c3
MAESTRO: verify Phase 06 final gate — all 4 CI-equivalent checks pass…
Feb 15, 2026
c3a892c
MAESTRO: Phase 07a baseline coverage report — 60.09% overall, Agent I…
Feb 15, 2026
39d19bf
MAESTRO: Phase 07b gap discovery — 6 coverage gaps identified across …
Feb 15, 2026
9bff6e8
MAESTRO: Phase 07c gap evaluation — 6 gaps rated, 3 PENDING for auto-…
Feb 15, 2026
67bf151
MAESTRO: Phase 07d test 1 — findRowIndexForItem grouped-mode navigati…
Feb 15, 2026
3aeffc9
MAESTRO: Phase 07d test 2 — close button hover handlers (2 tests, 193…
Feb 15, 2026
24e0e80
MAESTRO: Phase 07d test 3 — setAgentInboxOpen modalStore tests (2 tes…
Feb 15, 2026
d0d73d1
MAESTRO: Phase 07d test 4 — final batch, no PENDING candidates remain…
Feb 15, 2026
e451778
MAESTRO: Phase 07e coverage gate — TARGET REACHED, pipeline exits (93…
Feb 15, 2026
30acc86
MAESTRO: Phase 08 task 1 — rewrite filter system to All / Unread / Read
Feb 15, 2026
d92ecca
MAESTRO: Phase 08 task 2 — increase card height to 100px, add row gap…
Feb 15, 2026
fee4e61
MAESTRO: Phase 08 task 3 — add agent icon badge to inbox cards
Feb 15, 2026
c3f152c
MAESTRO: Phase 08 task 4 — add tab name to inbox card display
Feb 15, 2026
b6b7858
MAESTRO: Phase 08 task 5 — full verification and lint gate passed (15…
Feb 15, 2026
5a1d367
MAESTRO: Phase 09 task 1 — thread setAgentInboxOpen from App.tsx thro…
Feb 15, 2026
ed8c968
MAESTRO: Phase 09 task 2 — add Unified Inbox menu entry to Left Bar h…
Feb 15, 2026
b42ea00
MAESTRO: Phase 09 task 3 — rename Agent Inbox to Unified Inbox across…
Feb 15, 2026
334804e
MAESTRO: Phase 09 task 4 — full verification and lint gate passed (20…
Feb 15, 2026
e701539
MAESTRO: Phase 10 task 1 — redesign Row 1 with agent icon + pencil ta…
Feb 15, 2026
92740be
MAESTRO: Phase 10 task 2 — redesign modal header into two-row layout
Feb 15, 2026
aa9521e
MAESTRO: Phase 10 task 3 — add group expand/collapse toggle with chev…
Feb 15, 2026
7a30e8f
MAESTRO: Phase 10 task 4 — full verification and lint gate passed (15…
Feb 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 43 additions & 44 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@
"react-diff-view": "^3.3.2",
"react-markdown": "^10.1.0",
"react-syntax-highlighter": "^16.1.0",
"react-window": "^2.2.7",
"reactflow": "^11.11.4",
"recharts": "^3.6.0",
"rehype-raw": "^7.0.0",
Expand Down
167 changes: 167 additions & 0 deletions playbooks/agent-inbox/LOOP_00001_COVERAGE_REPORT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
---
type: report
title: Agent Inbox — Baseline Test Coverage Report
created: 2026-02-15
tags:
- test-coverage
- agent-inbox
- phase-07a
related:
- "[[UNIFIED-INBOX-07a]]"
- "[[UNIFIED-INBOX-07b]]"
---

# Agent Inbox — Baseline Test Coverage Report

> **Measured:** 2026-02-15 | **Branch:** `feature/unified-inbox` | **Framework:** Vitest + V8

---

## Overall Line Coverage: 60.09%

| Metric | Covered | Total | Percentage |
|-------------|---------|--------|-----------|
| **Statements** | 35,138 | 59,286 | **59.26%** |
| **Branches** | 22,947 | 42,470 | **54.03%** |
| **Functions** | 7,314 | 12,645 | **57.84%** |
| **Lines** | 33,387 | 55,560 | **60.09%** |

- **Target:** 80%
- **Gap to Target:** ~20 percentage points
- **Test Suite:** 452 test files, 19,336 tests passing, 107 skipped, 0 failures

---

## Agent Inbox Feature — Coverage Breakdown

| File | Stmts | Branch | Funcs | Lines | Tests | Status |
|------|-------|--------|-------|-------|-------|--------|
| `AgentInbox.tsx` | 87.57% | 82.69% | 86.84% | 91.60% | 88 | Above target |
| `useAgentInbox.ts` | 98.68% | 95.65% | 100% | 98.38% | 38 | Excellent |
| `agent-inbox.ts` (types) | 100% | 100% | 100% | 100% | — | Complete |
| `agentInboxHelpers` (cross-file) | — | — | — | — | 17 | Pure functions |
| `modalStore.ts` (shared) | 69.45% | 51.27% | 40% | 70.22% | 66 | Below target |

**Agent Inbox Total Tests:** 143+ across 4 test files (88 + 38 + 17 in dedicated files)

### Key Observations

- `useAgentInbox.ts` is **near-perfect** at 98.38% line coverage — only line 25 (an early guard) uncovered.
- `AgentInbox.tsx` is **well-covered** at 91.60% lines — small gaps in lines 448-452 and 638-641.
- `modalStore.ts` is **below target** at 70.22% — Agent Inbox modal functions (lines 628-736) are partially uncovered. This is shared infrastructure, not Agent Inbox-specific.

---

## Coverage by Module (Selected Highlights)

### Well-Covered Modules (>80% lines)

| Module | Lines | Notes |
|--------|-------|-------|
| `shared/` | 92.66% | Shared utilities, formatters |
| `renderer/stores/` | 89.76% | State management stores |
| `web/components/` | 97.55% | Web UI components |
| `web/hooks/` | 97.79% | Web hooks |
| `web/utils/` | 99.54% | Web utilities |
| `renderer/hooks/batch/` | 84.57% | Batch processing hooks |
| `renderer/hooks/remote/` | 86.70% | SSH/remote hooks |

### Below-Target Modules (<80% lines)

| Module | Lines | Notes |
|--------|-------|-------|
| `renderer/hooks/session/` | 31.56% | Session management hooks (largest gap) |
| `renderer/hooks/props/` | 0% | Panel prop hooks (no tests at all) |
| `renderer/hooks/symphony/` | 43.44% | Symphony/contribution hooks |
| `renderer/hooks/keyboard/` | 63.19% | Keyboard handler (complex, large) |
| `renderer/hooks/input/` | 69.80% | Input processing hooks |
| `renderer/hooks/git/` | 69.88% | Git management hooks |
| `renderer/hooks/ui/` | 65.53% | UI utility hooks |
| `renderer/services/` | 65.69% | Services layer |
| `renderer/utils/` | 77.92% | Renderer utilities |
| `web/` (App) | 26.53% | Web app entry point |

---

## Lowest Coverage Files (Critical Gaps)

| File | Lines | Category |
|------|-------|----------|
| `hooks/session/useSessionUpdates.ts` | 1.04% | Session state management |
| `hooks/session/useRealtimeTracker.ts` | 3.94% | Session realtime tracking |
| `hooks/session/useSessionNavigation.ts` | 0% | Session navigation |
| `hooks/session/usePinnedSessions.ts` | 0% | Pinned sessions |
| `hooks/props/useMainPanelProps.ts` | 0% | Main panel props |
| `hooks/props/useRightPanelProps.ts` | 0% | Right panel props |
| `hooks/props/useSessionListProps.ts` | 0% | Session list props |
| `hooks/ui/useAppHandlers.ts` | 0% | App-level handlers |
| `hooks/ui/useThemeStyles.ts` | 0% | Theme style hook |
| `hooks/input/useInputSync.ts` | 0% | Input synchronization |
| `hooks/agent/useSendAndContinue.ts` | 0% | Agent send & continue |
| `hooks/symphony/useContribution.ts` | 0% | Symphony contributions |
| `hooks/symphony/useContributorStats.ts` | 0% | Contributor stats |
| `services/contextGroomer.ts` | 22.44% | Context grooming service |
| `utils/remarkSmartFormatTable.ts` | 5.55% | Table formatting utility |

---

## Existing Test Patterns

The project follows consistent patterns across all 452 test files:

1. **Testing Stack:** Vitest + @testing-library/react + jsdom
2. **Hook Testing:** `renderHook` with `act()` for state updates
3. **Component Testing:** `render` + `screen` queries + `fireEvent`
4. **Mock Strategy:** `vi.mock()` for modules, `vi.fn()` for functions
5. **Factory Functions:** `makeSession()`, `makeTab()`, etc. for test data creation
6. **Semantic Queries:** `getByRole`, `getByText`, `getAllByRole` preferred over test IDs
7. **Accessibility Testing:** ARIA attributes validated in dedicated test blocks
8. **Setup:** Global `setup.ts` with jsdom environment, tab-indented files

---

## Recommendations

### Quick Wins (High coverage gain, low effort)

These modules have partial coverage and could reach 80%+ with targeted tests:

| Target | Current | Effort | Notes |
|--------|---------|--------|-------|
| `modalStore.ts` Agent Inbox lines | 70% | Low | Add tests for inbox-related modal actions (lines 628-736) |
| `renderer/utils/` assorted | 78% | Low | Many files at 80-95%, a few at 0% pulling average down |
| `renderer/hooks/settings/` | 76% | Medium | Large file with many branches |
| `AgentInbox.tsx` remaining lines | 92% | Low | Just lines 448-452, 638-641 uncovered |

### Requires Setup (Medium effort, infrastructure needed)

| Target | Current | Effort | Blocker |
|--------|---------|--------|---------|
| `hooks/session/` cluster | 32% | High | Complex state management, needs extensive mocking |
| `hooks/keyboard/` handler | 63% | Medium | Large file (750+ lines), needs keyboard event simulation |
| `hooks/input/` processing | 70% | Medium | Complex input pipeline with debouncing |
| `services/contextGroomer.ts` | 22% | High | Requires IPC mocking for main process communication |

### Skip for Now (Low ROI or non-essential)

| Target | Reason |
|--------|--------|
| `hooks/props/*` (0%) | Pure prop-passing hooks, low logic density |
| `web/App.tsx` (27%) | Web app entry point, hard to unit test |
| `utils/confetti.ts` (0%) | Animation utility, visual-only |
| `utils/clipboard.ts` (0%) | Browser API wrapper, hard to test in jsdom |
| `utils/formatters.ts` (0%) | Renderer-side formatters may be redundant with shared/formatters |
| Type definition files (0%) | No executable code to test |

---

## Agent Inbox Specific — Next Steps

The Agent Inbox feature is in **strong shape** at 91-98% coverage for its core files. To reach 80% project-wide target, the effort should focus on:

1. **Close the `modalStore.ts` gap** — Add tests for the Agent Inbox modal state transitions (lines 628-736)
2. **Cover `AgentInbox.tsx` edge cases** — Lines 448-452 and 638-641 are small gaps
3. **Integration test** — A single test exercising the full pipeline (store → hook → component → user interaction)
4. **Performance test** — Verify rendering with 100+ inbox items doesn't regress

The broader project coverage gap (60% vs 80% target) is overwhelmingly in non-Agent-Inbox modules, particularly the session management and keyboard handling hooks.
191 changes: 191 additions & 0 deletions playbooks/agent-inbox/LOOP_00001_GAPS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
---
type: analysis
title: Agent Inbox — Test Coverage Gaps
created: 2026-02-15
tags:
- test-coverage
- agent-inbox
- phase-07b
related:
- "[[UNIFIED-INBOX-07a]]"
- "[[UNIFIED-INBOX-07b]]"
- "[[LOOP_00001_COVERAGE_REPORT]]"
---

# Agent Inbox — Test Coverage Gaps

> **Measured:** 2026-02-15 | **Branch:** `feature/unified-inbox` | **Source:** Phase 07a coverage report + manual code inspection

---

## Summary

The Agent Inbox feature is in **strong shape** (91–98% line coverage for core files). This document catalogs the remaining small gaps to close in Phase 07c/07d.

| File | Current Lines | Target | Gap Size |
|------|--------------|--------|----------|
| `AgentInbox.tsx` | 91.60% | 95%+ | ~8 lines |
| `useAgentInbox.ts` | 98.38% | 100% | 1 line |
| `modalStore.ts` (shared) | 70.22% | 80% | ~2 lines (Agent Inbox specific) |
| `agent-inbox.ts` (types) | 100% | 100% | None |

**Total new tests estimated:** 8–12 test cases

---

## Gap 1: `AgentInbox.tsx` — `findRowIndexForItem` fallback return

| Field | Value |
|-------|-------|
| **File** | `src/renderer/components/AgentInbox.tsx` |
| **Function** | `findRowIndexForItem` (lines 446–455) |
| **Uncovered Lines** | 448–452 |
| **Type** | Edge Case |
| **Current Coverage** | Partial — only called implicitly via `scrollToRow` effect |
| **Why It Matters** | The for-loop body (line 450 match check) and fallback `return 0` (line 452) are not directly tested. If the loop logic breaks, items won't scroll into view correctly. |
| **Description** | This callback maps an item index to a row index (accounting for group headers in grouped mode). The fallback `return 0` handles the case where no matching row is found — e.g., when selectedIndex is out of bounds or rows are empty. |
| **Suggested Test Approach** | **Unit test** — Extract `buildRows` (already module-scoped) and test `findRowIndexForItem` logic indirectly by: (1) rendering in grouped mode and navigating to verify scroll behavior, OR (2) testing `buildRows` directly and verifying row indices match expected positions. A simpler approach: test that selecting an item in grouped mode with headers produces correct `aria-activedescendant`. |

---

## Gap 2: `AgentInbox.tsx` — Close button hover handlers

| Field | Value |
|-------|-------|
| **File** | `src/renderer/components/AgentInbox.tsx` |
| **Function** | Close button `onMouseEnter`/`onMouseLeave` (lines 637–641) |
| **Uncovered Lines** | 638–641 |
| **Type** | Edge Case (Visual) |
| **Current Coverage** | 0% — no test fires mouseenter/mouseleave on close button |
| **Why It Matters** | Low risk — these are hover style handlers. However, they do modify `style.backgroundColor` imperatively, which could cause visual regressions if removed or broken. |
| **Description** | `onMouseEnter` sets the close button background to `${theme.colors.accent}20` (accent at 12.5% opacity). `onMouseLeave` resets it to `'transparent'`. |
| **Suggested Test Approach** | **Component test** — Fire `mouseEnter` and `mouseLeave` events on the close button (`screen.getByTitle('Close (Esc)')`) and assert `style.backgroundColor` changes. Low effort, 2 test cases. |

---

## Gap 3: `useAgentInbox.ts` — `matchesFilter` default branch

| Field | Value |
|-------|-------|
| **File** | `src/renderer/hooks/useAgentInbox.ts` |
| **Function** | `matchesFilter` (lines 12–27) |
| **Uncovered Lines** | 25 (`default: return false`) |
| **Type** | Edge Case (Defensive Guard) |
| **Current Coverage** | 0% for this specific line — all 3 valid filter modes are tested, but the `default` branch (unreachable with current types) is not |
| **Why It Matters** | Very low risk — TypeScript enforces `InboxFilterMode` is `'all' | 'needs_input' | 'ready'`, so this line is unreachable at compile time. It exists as a defensive guard. |
| **Description** | The `default` case returns `false` for any unrecognized filter mode. Since `InboxFilterMode` is a union type, this can only be reached via type casting (e.g., `'invalid' as InboxFilterMode`). |
| **Suggested Test Approach** | **Unit test** — Call `useAgentInbox` with an invalid filter mode cast via `as InboxFilterMode` and verify it returns an empty array. Alternatively, accept this as an intentional uncovered guard line (1 line = 0.02% impact). |

---

## Gap 4: `modalStore.ts` — `setAgentInboxOpen` action

| Field | Value |
|-------|-------|
| **File** | `src/renderer/stores/modalStore.ts` |
| **Function** | `setAgentInboxOpen` (lines 527–529) |
| **Uncovered Lines** | 528–529 (open/close branches) |
| **Type** | Unit |
| **Current Coverage** | 0% — no test in `modalStore.test.ts` covers the Agent Inbox modal action |
| **Why It Matters** | Medium risk — if the modal type string `'agentInbox'` is misspelled or the action is removed, the Inbox won't open/close. This is the bridge between the keyboard shortcut and the modal rendering. |
| **Description** | `setAgentInboxOpen(true)` calls `openModal('agentInbox')`, `setAgentInboxOpen(false)` calls `closeModal('agentInbox')`. These are thin wrappers around the generic modal store machinery. |
| **Suggested Test Approach** | **Unit test** — In `modalStore.test.ts`, add a test block: call `setAgentInboxOpen(true)`, assert `isOpen('agentInbox')` is true. Call `setAgentInboxOpen(false)`, assert it's false. 2 test cases, very low effort. |

---

## Gap 5: `AgentInbox.tsx` — Focus/blur outline handlers

| Field | Value |
|-------|-------|
| **File** | `src/renderer/components/AgentInbox.tsx` |
| **Function** | `onFocus`/`onBlur` handlers on InboxItemCardContent (lines 120–126) and SegmentedControl buttons (lines 285–291) |
| **Uncovered Lines** | Not in the 07a report as uncovered, but no test explicitly verifies focus ring behavior |
| **Type** | Edge Case (Accessibility) |
| **Current Coverage** | Partial — focus is tested for Tab cycling but not the visual outline style |
| **Why It Matters** | Medium risk for accessibility — focus rings are critical for keyboard users. If `outline` styling breaks, keyboard navigation becomes invisible. |
| **Description** | `onFocus` sets `outline: 2px solid ${theme.colors.accent}` with `-2px` offset. `onBlur` removes it. Applied to both item cards and segmented control buttons. |
| **Suggested Test Approach** | **Component test** — Focus an item card via `fireEvent.focus()` and check `style.outline`. Then blur and verify outline is removed. 2–3 test cases. |

---

## Gap 6: `AgentInbox.tsx` — `InboxRow` null guard for missing row

| Field | Value |
|-------|-------|
| **File** | `src/renderer/components/AgentInbox.tsx` |
| **Function** | `InboxRow` (lines 310–363) |
| **Uncovered Lines** | 323 (`if (!row) return null`) |
| **Type** | Edge Case (Defensive Guard) |
| **Current Coverage** | 0% for null guard — react-window always passes valid indices |
| **Why It Matters** | Very low risk — this guard protects against react-window passing an out-of-bounds index, which shouldn't happen in practice. |
| **Description** | If `rows[index]` is undefined (e.g., due to a race condition between rowCount and rows array), the component returns null instead of crashing. |
| **Suggested Test Approach** | Skip — this is a defensive guard that cannot be triggered through normal UI interaction. Testing it requires directly rendering `InboxRow` with an invalid index, which tests implementation details rather than behavior. Accept as intentional uncovered guard. |

---

## Untested Branches Summary

| Location | Branch Type | Tested Path | Untested Path |
|----------|-------------|-------------|---------------|
| `matchesFilter` switch | switch/default | `all`, `needs_input`, `ready` | `default` (unreachable) |
| `findRowIndexForItem` for-loop | loop exit | N/A (implicit via scroll) | Loop body + fallback return 0 |
| Close button hover | if/else (enter/leave) | Neither | Both `onMouseEnter` and `onMouseLeave` |
| `InboxRow` null guard | if/early-return | Normal row rendering | `!row` guard |
| `setAgentInboxOpen` | boolean branch | Neither | Both `true` and `false` |

---

## Untested Error Handling

| Location | Error Type | Status |
|----------|-----------|--------|
| `useAgentInbox` — undefined `aiTabs` | null guard (`?? []`) | **Tested** (line 93 of hook test) |
| `useAgentInbox` — undefined `logs` | null guard (`?? []`) | **Tested** (line 330 of hook test) |
| `useAgentInbox` — null log text | null guard (`?.text`) | **Tested** (line 549 of hook test) |
| `useAgentInbox` — empty session id | falsy guard (`!session.id`) | **Tested** (line 103 of hook test) |
| `deriveTimestamp` — invalid timestamp | fallback chain | **Tested** (line 610 of hook test) |
| `resolveStatusColor` — unknown color key | fallback (`?? textDim`) | **Not tested** — would need a session state not in `STATUS_COLORS` map |

---

## Untested Edge Cases

| Location | Edge Case | Priority |
|----------|-----------|----------|
| `AgentInbox.tsx` — context bar at exactly 0% | Width `0%` rendering | Low |
| `AgentInbox.tsx` — negative contextUsage | `Math.max(value, 0)` clamp | Low |
| `buildRows` — empty items array in grouped mode | Returns empty array | Low |
| `AgentInbox.tsx` — `selectedItemId` when selectedIndex > items.length | Returns `undefined` | Low |
| `AgentInbox.tsx` — `listHeight` on server (typeof window === 'undefined') | Returns 400 fallback | Low |

---

## Recommended Test Priority

### Must Have (High ROI, Low Effort)

1. **Gap 4: `setAgentInboxOpen` in modalStore** — 2 tests, ensures modal open/close works
2. **Gap 2: Close button hover** — 2 tests, covers the last uncovered lines in AgentInbox.tsx

### Nice to Have (Medium ROI)

3. **Gap 1: `findRowIndexForItem` fallback** — 1–2 tests, validates grouped mode scroll behavior
4. **Gap 5: Focus ring handlers** — 2–3 tests, accessibility assurance

### Skip (Low ROI)

5. **Gap 3: `matchesFilter` default** — Unreachable via TypeScript types
6. **Gap 6: `InboxRow` null guard** — Defensive guard, never triggered in practice

---

## Projected Coverage After Closing Gaps

| File | Current | After Gaps 1–4 | After All |
|------|---------|----------------|-----------|
| `AgentInbox.tsx` | 91.60% | ~95% | ~97% |
| `useAgentInbox.ts` | 98.38% | 98.38% | ~99.5% |
| `modalStore.ts` | 70.22% | ~71% | ~71% |
| **Agent Inbox Overall** | ~93% | ~95% | ~97% |

> Note: `modalStore.ts` coverage gains from Agent Inbox tests are minimal (~0.5%) since the file is 737 lines and Agent Inbox occupies only 3 lines. The broader modalStore coverage gap is a separate concern.
Loading