# Initiatives List (v2)

### Route: `/initiatives`
### Source: `packages/web/src/routes/initiatives.tsx`

---

## v1 -> v2 Changes

| Aspect | v1 | v2 |
|--------|----|----|
| Card metadata | Name + status + progress only | Branch, projects, timestamp, active agent count, last activity summary |
| Sort | None | Dropdown: Recent Activity / Oldest / Name A-Z / Name Z-A / % Complete |
| Search | None | Client-side text filter on initiative name |
| Create dialog | Had Branch field | Branch removed (auto-generated on first execution dispatch) |
| Loading state | 3 skeleton cards | 5 skeleton cards with shimmer animation |
| Error state | None | AlertCircle + message + Retry button |
| Empty (filtered) | None | "No matching initiatives" + Clear filters link |
| Empty (zero) | Basic text + CTA | Centered EmptyState component |
| Card actions | View + Spawn dropdown + `...` menu | Same + enumerated `...` menu actions |
| Keyboard nav | None | Arrow keys navigate cards, Enter opens, `n` creates new |
| Multi-select | None | Checkbox select + batch action bar |
| View toggle | None | Card / compact list toggle for 20+ initiatives |

---

## Default State (with cards)

```
+=============================================================================+
| [CW]  [*Initiatives*]  Agents *3  Inbox (2)  Settings  [cmd-k]  [sun]  *  |
+=============================================================================+
|                                                                             |
|  Initiatives  (3)                                     [ + New Initiative ]  |
|                                                                             |
|  [search____________________]  [All v]  [Recent Activity v]                |
|                                                                             |
|  +-----------------------------------------------------------------------+  |
|  |  Auth System Overhaul                              [ACTIVE] [REVIEW]  |  |
|  |  [git] cw/auth-overhaul  [P] backend, frontend  . 2h ago             |  |
|  |  [▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░] 3/7 tasks    [*2 agents]          [...]   |  |
|  |  Agent completed "Implement auth middleware" 2h ago                    |  |
|  +-----------------------------------------------------------------------+  |
|                                                                             |
|  +-----------------------------------------------------------------------+  |
|  |  API Redesign                                        [DONE] [YOLO]   |  |
|  |  [git] cw/api-redesign  [P] backend  . 1d ago                        |  |
|  |  [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 12/12 tasks                     [...]   |  |
|  |  All tasks completed 1d ago                                           |  |
|  +-----------------------------------------------------------------------+  |
|                                                                             |
|  +-----------------------------------------------------------------------+  |
|  |  Mobile App Redesign                             [ACTIVE] [REVIEW]   |  |
|  |  [P] frontend  . 5m ago                                               |  |
|  |  [▓▓░░░░░░░░░░░░░░░░░░░░░] 1/5 tasks    [*1 agent]          [...]   |  |
|  |  Agent started "Design mobile nav" 5m ago                             |  |
|  +-----------------------------------------------------------------------+  |
|                                                                             |
+=============================================================================+
```

Note: Third card has no branch yet (auto-generated on first execution dispatch),
so `[git]` badge is absent. Only `[P]` project badges and timestamp shown.

Note: Total initiative count `(3)` shown next to heading for at-a-glance density.
Agent count badge `[*2 agents]` only appears when > 0 running agents on initiative.

## Card Anatomy

```
+-------------------------------------------------------------------------+
|  [checkbox]  Initiative Name                        [STATUS] [MODE]     |
|  [git] cw/<branch>  [P] project1, project2  . <relative-time>          |
|  [▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░░░░░] N/M tasks    [*K agents]          [...]   |
|  <last-activity-summary>                                                |
+-------------------------------------------------------------------------+
```

### Row 1: Title + badges
- `[checkbox]` — Hidden by default. Appears on hover or when any card is selected (batch mode).
- Initiative name — clickable, navigates to initiative detail.
- Status + mode badges right-aligned.

### Row 2: Metadata
- `[git] cw/<branch>` — GitBranch icon + branch name. Hidden if no branch yet.
- `[P] project1, project2` — Folder icon + comma-separated project names.
  Hidden if no projects linked.
- `. <relative-time>` — Dot separator + relative timestamp (e.g., "2h ago", "1d ago").
  Based on `updatedAt`.

### Row 3: Progress + agents
- Progress bar with `N/M tasks` label.
- `[*K agents]` — Running agent count (green dot + count). Hidden when 0.
- `[...]` — More actions menu, right-aligned.

### Row 4: Last activity
- Single-line activity summary in `text-muted-foreground text-sm`.
- Format: `"<Actor> <verb> "<target>" <relative-time>"`.
- Examples: `Agent completed "Implement auth middleware" 2h ago`,
  `You approved task "Deploy to staging" 10m ago`,
  `All tasks completed 1d ago`,
  `Agent started "Design mobile nav" 5m ago`.
- Source: derived from most recent agent event or task status change on the initiative.
  Priority order: agent error > agent question (waiting) > task completed > agent spawned > task created.
  Falls back to `"Created <relative-time>"` if no events exist yet.
- Truncated with ellipsis if text overflows.

### Card hover / focus states
- **Hover**: `bg-muted/50` background transition (`transition-colors duration-150`),
  `border-border/80` border brightens subtly. Checkbox fades in on Row 1 (see Multi-Select).
  Cursor: `cursor-pointer`.
- **Keyboard focus** (via `j`/`k` or Tab): `ring-2 ring-primary ring-offset-2 ring-offset-background`.
  No background change — the ring is the only focus indicator, keeping it distinct from hover.
- **Active/pressed**: `bg-muted/70` on `mousedown`, releases on `mouseup`.
- **Selected** (checkbox checked): `ring-2 ring-primary bg-primary/5` persistent highlight.
  The ring distinguishes selected from focused — both can coexist (focused + selected).
- **Disabled**: N/A — cards are never disabled. Archived initiatives are visually dimmed
  (`opacity-60`) but still interactive.

### Status badge colors
- `[ACTIVE]` — green
- `[DONE]` — grey
- `[ARCHIVED]` — dim grey

### Mode badge colors
- `[YOLO]` — yellow/amber
- `[REVIEW]` — blue

### Progress bar
- Segmented fill: each segment represents one task. Completed segments are filled,
  in-progress segments pulse, pending segments are grey track.
- Segment gap: 2px between segments (rendered via `gap-0.5` on a flex container,
  each segment is a `div` with `flex: 1`). Minimum segment width: 4px.
- Color: indigo (`--primary`) fill for completed segments when initiative is in progress,
  green (`--status-success-fg`) fill for all segments when 100% complete.
- In-progress segments: `--primary` at 50% opacity with `animate-pulse` (1.5s ease-in-out).
  This is the only animation on the card — intentionally subtle, draws the eye to where
  work is actively happening.
- `pending_approval` segments: amber (`--status-warning-fg`) static fill — distinct from
  in-progress (pulsing) and completed (solid).
- Grey track (`--muted`) for pending/not-started segments.
- At > 20 tasks, segments merge into a continuous bar (segments too narrow to distinguish).
  The bar becomes three colored sections: completed (solid), in-progress (pulsing), pending (grey).
- The `N/M tasks` label is always visible regardless of bar width.
- Tooltip on hover shows breakdown: "3 completed, 1 in progress, 1 pending approval, 2 pending".
- Zero tasks edge case: show "No tasks yet" in `text-muted-foreground text-xs` instead of
  an empty bar. This happens for freshly created initiatives before planning runs.

### More menu `[...]`

Opened via click on `[...]` button or `.` keyboard shortcut on focused card.
Uses shadcn `<DropdownMenu>`. Closed on `Escape`, click outside, or item selection.

```
  [...]
  +------------------------+
  |  View            Enter |   ← navigate to initiative detail
  |  ---------------------- |
  |  Discuss...            |   ← spawn discuss agent (opens dialog)
  |  Plan...               |   ← spawn plan agent (opens dialog)
  |  Refine...             |   ← spawn refine agent (opens dialog)
  |  ---------------------- |
  |  Duplicate             |   ← clone initiative (name, projects, phases — no tasks/agents)
  |  Archive           a   |   ← sets status to archived; window.confirm, Shift+click bypasses
  |  ---------------------- |
  |  Delete            d   |   ← destructive red text; window.confirm, Shift+click bypasses
  +------------------------+
```

Right-side hints (`Enter`, `a`, `d`) are keyboard shortcut annotations in
`text-muted-foreground text-xs`. They match the global keyboard bindings —
these are not menu-local shortcuts, they work without opening the menu.

Actions are context-aware:
- `Archive` only shown for `active` / `done` initiatives. `Unarchive` shown for `archived`.
- `Discuss/Plan/Refine` hidden for `archived` initiatives.
- `Delete` always shown, always destructive-colored (`text-destructive`).
- `Duplicate` hidden for `archived` initiatives (duplicating dead work is a mistake).
- When all agent actions are hidden (archived), the second separator is also hidden
  to avoid double separators.

---

## Search + Filter + Sort Controls

```
  [search____________________]  [All v]  [Recent Activity v]
```

### Responsive layout

```
>= 768px:   [search_______________]  [All v]  [Recent Activity v]

< 768px:    [search_______________________________________]
            [All v]  [Recent Activity v]
```

At mobile widths, the filter row wraps to two lines: search takes full width on
the first line, dropdowns share the second line. Search is always first because
it is the most-used control.

### Search input
- Placeholder: "Search initiatives..."
- Client-side filter on `initiative.name` (case-insensitive substring match)
- Debounced 150ms
- Clear button `[x]` appears when non-empty
- Keyboard shortcut: `/` focuses the search input (standard convention)

### Status filter dropdown `[All v]`

```
  [  All        v]
  +---------------+
  |  All          |
  |  Active       |
  |  Completed    |
  |  Archived     |
  +---------------+
```

### Sort dropdown `[Recent Activity v]`

```
  [  Recent Activity  v]
  +----------------------+
  |  Recent Activity     |   ← updatedAt DESC (default) — most recently touched first
  |  Oldest              |   ← createdAt ASC
  |  Name A-Z            |   ← name ASC
  |  Name Z-A            |   ← name DESC
  |  % Complete          |   ← (completed tasks / total tasks) DESC, then updatedAt DESC
  +----------------------+
```

"Recent Activity" replaces "Newest" — the label should describe the sort semantics,
not the age of the record. The default sort puts the initiative you most recently
interacted with at the top, which is the correct default for a workspace tool.

"% Complete" is unambiguous: it is `completed / total` as a percentage, with ties
broken by recent activity. An initiative at 3/7 (42.8%) sorts below 5/10 (50%).

---

## Loading State (5 skeleton cards with shimmer)

```
+=============================================================================+
|                                                                             |
|  Initiatives                                          [ + New Initiative ]  |
|                                                                             |
|  [search____________________]  [All v]  [Recent Activity v]                         |
|                                                                             |
|  +-----------------------------------------------------------------------+  |
|  | ░░░░░░░░░░░░░░░░░░░                              ░░░░░░  ░░░░░░░░   |  |
|  | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░  . ░░░░░                       |  |
|  | ░░░░░░░░░░░░░░                                                        |  |
|  | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                              |  |
|  +-----------------------------------------------------------------------+  |
|  +-----------------------------------------------------------------------+  |
|  | ░░░░░░░░░░░░░░░░░░░                              ░░░░░░  ░░░░░░░░   |  |
|  | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░  . ░░░░░                       |  |
|  | ░░░░░░░░░░░░░░                                                        |  |
|  | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                              |  |
|  +-----------------------------------------------------------------------+  |
|  +-----------------------------------------------------------------------+  |
|  | ░░░░░░░░░░░░░░░░░░░                              ░░░░░░  ░░░░░░░░   |  |
|  | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░  . ░░░░░                       |  |
|  | ░░░░░░░░░░░░░░                                                        |  |
|  | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                              |  |
|  +-----------------------------------------------------------------------+  |
|  +-----------------------------------------------------------------------+  |
|  | ░░░░░░░░░░░░░░░░░░░                              ░░░░░░  ░░░░░░░░   |  |
|  | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░  . ░░░░░                       |  |
|  | ░░░░░░░░░░░░░░                                                        |  |
|  | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                              |  |
|  +-----------------------------------------------------------------------+  |
|  +-----------------------------------------------------------------------+  |
|  | ░░░░░░░░░░░░░░░░░░░                              ░░░░░░  ░░░░░░░░   |  |
|  | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░  . ░░░░░                       |  |
|  | ░░░░░░░░░░░░░░                                                        |  |
|  | ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░                              |  |
|  +-----------------------------------------------------------------------+  |
|                                                                             |
+=============================================================================+
```

Skeleton cards mirror card anatomy: title line, metadata line, progress line,
activity line (4 rows matching real card height). Shimmer animation sweeps
left-to-right on a 1.5s loop via `@keyframes shimmer` with `background: linear-gradient(...)`.
Skeleton height must match real card height to prevent layout shift on data load.

Skeleton count reasoning: 5 cards fills a typical viewport (900px content area
at ~120px per card with gaps). Showing fewer risks the page feeling empty; showing
more risks painting below the fold for nothing. This is a minor detail — the shimmer
animation is what makes loading feel fast, not the count.

The search/filter bar renders immediately (not skeletonized) — the controls are static
and user-operable even while data loads. If the user starts typing a search during load,
the filter is applied as soon as data arrives. No race condition: the query returns all
initiatives and the client filters.

---

## Error State

```
+=============================================================================+
|                                                                             |
|  Initiatives                                          [ + New Initiative ]  |
|                                                                             |
|  +-----------------------------------------------------------------------+  |
|  |                                                                       |  |
|  |                         [AlertCircle]                                 |  |
|  |                    Failed to load initiatives                         |  |
|  |                                                                       |  |
|  |                          [ Retry ]                                    |  |
|  |                                                                       |  |
|  +-----------------------------------------------------------------------+  |
|                                                                             |
+=============================================================================+
```

Uses `<ErrorState>` component (see shared-components.md).
Retry calls `refetch()` on the tRPC query. Retry button shows a spinner while
the refetch is in-flight (disabled state, `opacity-50 pointer-events-none`).

Error message is the tRPC error message, not a generic string. Examples:
- "Failed to load initiatives" (generic fallback)
- "Database connection lost" (SQLite file locked)
- "Server unreachable" (network error)

The error state preserves the filter bar — if the user had filters set before
the error, they remain. This prevents the disorienting "my filters disappeared"
experience on transient errors.

---

## Empty State — No Initiatives

```
+=============================================================================+
|                                                                             |
|  Initiatives                                          [ + New Initiative ]  |
|                                                                             |
|  +-----------------------------------------------------------------------+  |
|  |                                                                       |  |
|  |                          [inbox]                                      |  |
|  |                    No initiatives yet                                 |  |
|  |              Create an initiative to get started.                     |  |
|  |                                                                       |  |
|  |                    [ + New Initiative ]                                |  |
|  |                                                                       |  |
|  +-----------------------------------------------------------------------+  |
|                                                                             |
+=============================================================================+
```

Uses `<EmptyState>` component (see shared-components.md).
CTA button opens the CreateInitiativeDialog.

---

## Empty State — No Filter Match

```
+=============================================================================+
|                                                                             |
|  Initiatives                                          [ + New Initiative ]  |
|                                                                             |
|  [auth_____________________]  [Active v]  [Recent Activity v]              |
|                                                                             |
|  +-----------------------------------------------------------------------+  |
|  |                                                                       |  |
|  |                    No matching initiatives                            |  |
|  |              Try a different search or filter.                        |  |
|  |                                                                       |  |
|  |                      [Clear filters]                                  |  |
|  |                                                                       |  |
|  +-----------------------------------------------------------------------+  |
|                                                                             |
+=============================================================================+
```

"Clear filters" is a text link (not a button). Resets search input to empty,
status filter to "All", sort to "Recent Activity".

---

## Keyboard Navigation

| Key | Action |
|-----|--------|
| `j` / `Arrow Down` | Move focus to next card |
| `k` / `Arrow Up` | Move focus to previous card |
| `Enter` | Open focused initiative |
| `x` | Toggle selection on focused card (batch mode) |
| `Shift+x` | Select range from last selected to focused card |
| `n` | Open Create Initiative dialog |
| `/` | Focus search input |
| `Escape` | Clear selection / blur search / close menu (priority order) |
| `.` | Open `[...]` menu on focused card |
| `d` | Quick-delete focused card (triggers confirm dialog) |
| `a` | Quick-archive focused card (triggers confirm dialog) |

Focus ring: `ring-2 ring-primary ring-offset-2` on the focused card.

Scroll-into-view: when `j`/`k` moves focus to a card partially or fully off-screen,
`scrollIntoView({ block: 'nearest', behavior: 'smooth' })` is called. This scrolls
the minimum distance needed — no jarring jumps to center.

Focus wraps: pressing `j` on the last card moves to the first.

Keyboard shortcuts are disabled when: any dialog is open, search input is focused,
or a dropdown is open. The `useHotkeys` hook should check `document.activeElement`
and bail if it is an input/textarea/select or inside a `[role="dialog"]`.

No keyboard shortcut hints are shown on the page itself. They are discoverable via
the command palette (`cmd-k`) which lists all available actions with their bindings.

---

## Multi-Select & Batch Operations

Checkbox appears on each card on hover, or on all cards when any card is selected.

### Batch action bar (appears when >= 1 card selected)

```
+=============================================================================+
|  [x] 3 selected          [ Archive ]  [ Delete ]            [Deselect all] |
+=============================================================================+
```

- Slides down from below the filter bar (above the card list), `animate-in slide-in-from-top`.
  Slides back up when selection is cleared (`animate-out slide-out-to-top`).
- `Archive` — sets all selected to `archived`. Confirms unless Shift held.
  Confirmation message: "Archive 3 initiatives?" (count is dynamic).
- `Delete` — destructive red (`text-destructive`). Confirms unless Shift held.
  Confirmation message: "Permanently delete 3 initiatives? This cannot be undone."
- `Deselect all` — text link (`text-muted-foreground underline`), clears selection.
- `[x]` checkbox is tri-state: unchecked (0 selected), indeterminate (some selected),
  checked (all visible selected). Clicking when indeterminate selects all visible.
- Selection count label: `"3 selected"` or `"3 of 12 selected"` when filtered
  (so the user knows they are only operating on visible items, not all initiatives).
- Selection state is cleared when filters change (prevents invisible-selection bugs).
- Bar has `bg-muted border-b` styling, `h-12` fixed height, `z-10` to layer above cards.
- Bar is sticky (`sticky top-0`) so it remains visible when scrolling through selected cards.

---

## Compact List View (toggle)

For workspaces with 20+ initiatives, a compact list view is more scannable than cards.

### Toggle control (right of filter bar)

```
  [search_______________]  [All v]  [Recent Activity v]   [card|list]
```

`[card|list]` — Two icon buttons (LayoutGrid / List lucide icons). Active state
uses `bg-muted`. Persisted to `localStorage` key `cw-initiatives-view`.

### Compact list wireframe

```
+=============================================================================+
|                                                                             |
|  Initiatives  (12)                                    [ + New Initiative ]  |
|                                                                             |
|  [search_______________]  [All v]  [Recent Activity v]       [card|*list*]  |
|                                                                             |
|  +-----------------------------------------------------------------------+  |
|  |  NAME                  STATUS  PROGRESS     AGENTS  ACTIVITY          |  |
|  |  -------------------------------------------------------------------  |  |
|  |  Auth System Overhaul  ACTIVE  3/7 (42%)    *2      2h ago            |  |
|  |  API Redesign          DONE    12/12 (100%)  —      1d ago            |  |
|  |  Mobile App Redesign   ACTIVE  1/5 (20%)    *1      5m ago            |  |
|  |  Logging Refactor      ACTIVE  0/3 (0%)      —      3d ago            |  |
|  +-----------------------------------------------------------------------+  |
|                                                                             |
+=============================================================================+
```

- Each row is clickable (navigates to initiative detail).
- Column headers are sortable by click (toggles ASC/DESC, synced with sort dropdown).
  Active sort column shows a chevron indicator (up/down). Click again to reverse.
- Rows are 40px height (`h-10`) for density. Text is `text-sm`.
- Hover: `bg-muted/50` row highlight (`transition-colors duration-100`).
- Focus: same `ring-2 ring-primary` as card view. `j`/`k` navigation works identically.
- Selection: checkbox column appears on left (always visible in list view — no hover reveal,
  because the row is too compact for hover-dependent UI). `x` to toggle, `Shift+x` for range.
- `[...]` menu: appears as the last column on each row (right-aligned, icon-only button).
  Same menu items as card view. This is better than right-click context menus because:
  (a) right-click is not discoverable, (b) it conflicts with browser dev tools context menu,
  (c) it has no mobile equivalent.
- STATUS column: uses the same badge components as card view but in `text-xs` size.
- AGENTS column: green dot + number when > 0, em-dash when 0.
- ACTIVITY column: relative time only (no activity summary — too dense for a table row).
  Full activity summary available on hover via a tooltip.

---

## Scale Behavior (50+ initiatives)

At high initiative counts, the page needs to stay responsive:

- **Card view**: No pagination. All cards render in a virtualized list (`@tanstack/react-virtual`)
  when count exceeds 30. The virtual window renders ~10 cards plus 5 overscan on each side.
  Scroll position is preserved on navigation back from initiative detail.
- **List view**: Same virtualization strategy. At 40px row height, 100 initiatives is only
  4000px — manageable without virtualization, but virtualize anyway for consistency.
- **Filter bar counts**: The `(N)` count next to "Initiatives" updates to reflect filtered
  count when filters are active: `Initiatives (5 of 47)`.
- **Search performance**: Client-side substring match is O(n) on initiative names. At 200
  initiatives this is ~0.1ms — no performance concern. If initiatives ever hit 1000+,
  move to server-side search (but that is not a v2 concern).
- **Auto-suggestion**: When the list exceeds 20 initiatives and the user is in card view,
  a one-time subtle hint appears below the view toggle: `"Tip: Switch to list view for faster scanning"`.
  Dismissable, stored in `localStorage` key `cw-list-view-hint-dismissed`.

---

## State Transitions

Transitions between loading, empty, error, and populated states should feel deliberate:

| From | To | Transition |
|------|----|-----------|
| Loading (skeletons) | Populated (cards) | Skeletons fade out (`opacity-0` 150ms), cards fade in (`opacity-100` 150ms). No layout jump — skeleton card dimensions match real card dimensions. |
| Loading | Empty (zero) | Skeletons fade out, empty state fades in. Container height stays stable (min-height matches 3 skeleton cards). |
| Loading | Error | Skeletons fade out, error state fades in centered. |
| Populated | Empty (filtered) | Cards slide out, empty-filter message fades in. Instant — no loading spinners for client-side filtering. |
| Error | Loading (retry) | Error fades out, skeletons fade in. Retry button shows spinner during refetch. |

Key principle: the container holding the card list has `min-h-[400px]` to prevent
the page from collapsing vertically during transitions. This avoids the jarring
"page jumping" effect when going from a tall state to a short empty state.

---

## Source

- `packages/web/src/routes/initiatives/index.tsx`
- `packages/web/src/components/InitiativeList.tsx`
- `packages/web/src/components/InitiativeCard.tsx`
- `packages/web/src/components/InitiativeCardCompact.tsx` (proposed — list view row)
- `packages/web/src/components/BatchActionBar.tsx` (proposed)
- `packages/web/src/components/EmptyState.tsx` (proposed)
- `packages/web/src/components/ErrorState.tsx` (proposed)

---

## Design Review Notes

Honest critique of the v2 spec. What was already good, what was weak, what was missing,
and what was added or changed during review.

### What the spec already got right

The v1-to-v2 delta table is excellent — it makes the design intent traceable. The card
anatomy with 4 rows is the right density for a mission-control tool. The segmented
progress bar, active agent count badge, and last-activity summary were all present
before this review. The sort options are well-chosen with clear semantics. The responsive
filter bar layout is properly specified. Credit where due: this spec was 80% there.

### 1. Card hover/focus/selected states were completely unspecified

The spec defined a focus ring in the keyboard nav section but said nothing about hover,
active (mousedown), or selected (checkbox checked) states. For a page where the primary
interaction is "scan cards and click one," this is a critical omission. A card with no
hover feedback feels dead. Added: hover (`bg-muted/50`), focus (`ring-2 ring-primary`),
active (`bg-muted/70`), selected (`ring-2 ring-primary bg-primary/5`), and the rule
that focus + selected can coexist visually.

### 2. Progress bar: good concept, missing edge cases

The segmented bar idea was solid. But the spec was silent on: `pending_approval` tasks
(a real status in this system — they need amber fill, not grey), zero-task initiatives
(shows an empty bar which looks broken), and the exact visual treatment of in-progress
segments (just saying "pulse" is not enough — added opacity and animation details).
The >20 task fallback was already there and is pragmatic.

### 3. Sort semantics were already clean

"Recent Activity" and "% Complete" were already well-defined with tiebreakers. No
changes needed here. The original spec nailed this.

### 4. Batch operations: specified but the bar lacked detail

Multi-select was present but the batch action bar was a one-liner. Missing: tri-state
checkbox behavior, filtered-count awareness (`"3 of 12 selected"`), sticky positioning,
animation in/out, confirmation message wording, and the `Shift+x` range selection
keyboard shortcut. These are the details that separate "we thought about batch ops"
from "we can actually implement batch ops."

### 5. Compact list view: right-click context menu was a bad call

The original spec said "No `[...]` menu in list view — right-click context menu provides
the same actions." This is wrong for three reasons: (a) right-click is not discoverable
by any user who does not already know it exists, (b) it conflicts with browser developer
tools on right-click, (c) it does not work on mobile/touch. Changed to: `[...]` icon
button as the last column in every row. Consistent with card view, no discovery problem.

### 6. Keyboard nav: missing `.` for menu, `d`/`a` quick actions, `Shift+x` range

The original `j/k/Enter/x/n///Escape` set was a good start but missed: `.` to open the
`[...]` menu (standard in GitHub), `d` and `a` for quick-delete/archive (common in
email clients), and `Shift+x` for range selection. Also missing: scroll-into-view
behavior (if `j` moves focus off-screen, the card must scroll into view), and the
critical note about disabling shortcuts when dialogs/inputs are focused.

### 7. Skeleton cards had 3 rows, real cards have 4

The ASCII wireframe for skeleton cards showed 3 shimmer rows per card, but the real card
anatomy has 4 rows (title, metadata, progress, activity). This causes a layout shift
on data load — exactly the problem skeletons are supposed to prevent. Fixed: added a
4th shimmer row to each skeleton card.

### 8. No scale strategy beyond "list view"

The spec had card view and list view but no mention of what happens at 50+ or 100+
initiatives. Added: virtualization via `@tanstack/react-virtual` at 30+ items, scroll
position preservation on back-navigation, and a one-time hint nudging card-view users
toward list view when count exceeds 20.

### 9. Error state was too thin

"AlertCircle + message + Retry" is the skeleton of an error state, not a complete one.
Missing: retry button loading state, error message source (tRPC error vs. generic),
filter bar preservation during error. These are the details that determine whether a
transient SQLite lock causes user confusion or is handled gracefully.

### 10. Last activity event priority was unspecified

The spec said "derived from most recent agent event or task status change" but did not
define which events take priority. An agent error is more important than a task creation.
Added priority order: agent error > agent question (waiting) > task completed > agent
spawned > task created. This ensures the activity line surfaces the most actionable
information, not just the most recent timestamp.

### Open questions for implementation

1. **Last activity data source**: The `agent_log_chunks` table has raw JSONL but no
   structured events. The EventBus emits events but does not persist them. Two options:
   (a) derive from task `status` + `updatedAt` (cheap, less rich), or (b) add a
   lightweight `activity_log` table that captures the ~5 event types needed for
   activity summaries. Option (b) is cleaner but adds a migration and a new repository.
   Recommendation: option (a) for v2, option (b) for v2.1.

2. **Agent count query cost**: `listInitiatives` needs a LEFT JOIN on `agents` WHERE
   `status = 'running'` GROUP BY `initiativeId`. This is a single query, not N+1.
   The Drizzle ORM `with` clause or a raw subquery in the repository adapter handles
   this. Not optional — the agent count badge is the highest-value addition in this spec.

3. **Compact list view priority**: v2 can ship without it. Cards-only works for the
   typical 3-15 initiative range. But the toggle infrastructure (localStorage persistence,
   conditional render) should be stubbed even if the list component is not built yet,
   so adding it later is a 1-file change, not a refactor.

4. **Virtualization priority**: Not needed until someone actually has 30+ initiatives.
   Skip for v2, add when performance is measurably impacted. The hint to switch to list
   view is the cheap mitigation.

5. **`Shift+x` range selection complexity**: Range selection requires tracking "last
   selected index" which interacts with sort order changes. If sort changes while
   a range is partially selected, the range anchor becomes meaningless. Decision: clear
   the range anchor (but not the selection) on sort change. Document this behavior.
