Tasks completed: 2/2
- Run full build verification (TypeScript, Vite, tests)
- Full integration smoke test (human-verified, approved)
SUMMARY: .planning/phases/21-polish-integration/21-06-SUMMARY.md
Add 21-05-SUMMARY.md documenting route-based code splitting results
(582 KB -> 454 KB main chunk + route-level chunks) and PlanTasksFetcher
useEffect fix. Update STATE.md to plan 5/6 with new decisions.
Replace the setState-during-render pattern in PlanTasksFetcher with a
useEffect hook. The onTasks callback was being called directly in the
render body when tasksQuery.isSuccess was true, which could cause
infinite re-render loops when the parent state update triggered a
re-render. Now data flows through useEffect with proper dependencies.
Enable autoCodeSplitting in TanStackRouterVite plugin to split the monolithic
582 KB bundle into route-level chunks. Main vendor chunk drops to 454 KB with
initiative detail (~13 KB), inbox (~13 KB), and dashboard (~65 KB) as separate
lazy-loaded chunks. Eliminates the Vite 500 KB chunk size warning.
- SpawnArchitectDropdown: toast.success on spawn, toast.error on failure
- ActionMenu: toast.success on archive, toast.error on failure
- CreateInitiativeDialog: toast.success on creation
- Inbox: toast.success/error for resumeAgent and respondToMessage mutations
- Replace all console.error-only mutation error handling with user-visible toasts
Replace plain "Loading initiative..." and "Loading phases..." text with
structured skeleton placeholders matching the page layout: header with
back arrow/title/badge, two-column grid with phase accordions and
sidebar panels.
- Hide inbox list on mobile when agent selected (drill-down pattern)
- Add "Back to list" button visible only on mobile (lg:hidden)
- Clicking back clears selection and returns to list view
- Create ErrorBoundary class component with recovery UI (reload button)
- Create Sonner Toaster wrapper (bottom-right, richColors)
- Wire ErrorBoundary around Outlet in root route to catch render errors
- Add Toaster as sibling to AppLayout in root route
- Update notFoundComponent with Back to Dashboard link button
- Remove disabled nav stubs (Agents, Tasks, Settings) from AppLayout
- Make TaskRow agent names clickable links to inbox page
- Add task ID link and "View in context" link in inbox detail panel
Create reusable Skeleton component with animate-pulse styling. Replace
plain "Loading..." text with structured skeleton placeholders matching
card layouts in InitiativeList and inbox page.
Phase 20 (Real-Time Subscriptions) is now complete. Both plans delivered:
- 20-01: SSE backend with subscription procedures
- 20-02: Frontend splitLink + subscription hooks on all 3 UI pages
Add useSubscription hooks to all three UI pages that invalidate React
Query caches on domain events:
- Dashboard: onTaskUpdate invalidates listInitiatives + listPhases
- Detail: onTaskUpdate invalidates phases/tasks/plans, onAgentUpdate
invalidates listAgents
- Inbox: onAgentUpdate invalidates listWaitingAgents + listMessages
Subscription failures are silent (onError: () => {}) so pages degrade
gracefully to manual refresh when the backend is not running.
Replace single httpBatchLink with splitLink that routes subscription
operations to httpSubscriptionLink (SSE) while keeping queries/mutations
on httpBatchLink. No new packages needed — both exports are part of
@trpc/client v11.
Add SubscriptionEvent interface for frontend consumption of SSE
subscription data in onData callbacks. Vite proxy confirmed compatible
with SSE streaming (http-proxy passes chunked responses by default).
AgentManager was never instantiated or passed to the CoordinationServer,
causing all agent-related tRPC procedures to throw "Agent manager not
available". Creates DrizzleAgentRepository, SimpleGitWorktreeManager,
and ClaudeAgentManager in startServer() and passes agentManager into
the server context deps.
listWaitingAgents, listAgents, and getAgentQuestions now return empty
results instead of throwing when agentManager is not wired into the
tRPC context. Mutation procedures (spawn, stop, resume) still throw.
Replaces stub inbox page with full implementation connecting InboxList
and QuestionForm components to tRPC backend. Two-column layout with
agent list on left and detail panel on right. Handles answer submission
via resumeAgent mutation, notification dismissal via respondToMessage,
and loading/error states following patterns from initiative detail page.
- Renders mixed question types from questions array
- Submit disabled until all questions answered
- onSubmit called with Record<string, string> mapping questionId to answer
InboxList joins agents with their latest messages, provides filter
(all/waiting/completed) and sort (newest/oldest) controls, renders
MessageCard instances, and shows empty state when no messages match.
- OptionGroup renders radio or checkbox based on multiSelect prop
- "Other" field auto-selects when user types into it
- FreeTextInput renders Input or Textarea based on multiline prop
- getAgentQuestions returns structured PendingQuestions from AgentManager
- listWaitingAgents filters agents to waiting_for_input status
- Updated JSDoc procedure list with both new procedures
MessageCard displays agent name with status, message preview (truncated
to 80 chars), relative timestamp, and response indicator (filled/empty
circle). Uses shadcn Card base with selected state highlighting.
Replace placeholder with full initiative detail page: tRPC data fetching
(getInitiative, listPhases, listPlans, listTasks), PhaseWithTasks helper
component pattern for stable hooks, two-column layout with phases on left
and progress/decisions on right, TaskDetailModal with selectedTask state,
queue actions for phases and tasks, loading/error states.
Tasks completed: 2/2
- InitiativeHeader with back button, name, status badge, dates
- ProgressPanel with progress bar and phase/task counts
SUMMARY: .planning/phases/18-initiative-detail/18-01-SUMMARY.md
Expandable/collapsible phase container with chevron toggle, phase
number + name header, task count (completed/total), StatusBadge,
phase-level DependencyIndicator, and TaskRow list when expanded.
Controlled dialog showing full task metadata, dependencies, dependents,
and action buttons (Queue Task / Stop Task) with proper enable/disable
logic based on task status and dependency completion.
Renders a single task row with Unicode tree connectors (├── / └──),
StatusBadge, inline agent name, and DependencyIndicator for blocked
tasks. Entire row is clickable with hover feedback.
Collapsible list of key decisions with expand/collapse per item and
show more/less toggle when exceeding maxVisible threshold. Renders
in a Card with empty-state placeholder.