---
phase: 21-polish-integration
plan: 04
type: execute
wave: 2
depends_on: ["21-01", "21-02", "21-03"]
files_modified: [packages/web/src/routes/initiatives/index.tsx, packages/web/src/routes/initiatives/$id.tsx, packages/web/src/routes/inbox.tsx, packages/web/src/components/SpawnArchitectDropdown.tsx]
autonomous: true
---

<objective>
Wire SSE subscription error handling with reconnection feedback, and add toast notifications for subscription state changes.

Purpose: All three pages have `onError: () => {}` on their SSE subscriptions — errors are silently swallowed. When the backend is down, users get no feedback that live updates are paused. This plan adds graceful degradation so users know when real-time updates are working vs. falling back to manual refresh.
Output: Subscription error handling with user feedback on all three pages.
</objective>

<execution_context>
@~/.claude/get-shit-done/workflows/execute-plan.md
@~/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md

@packages/web/src/routes/initiatives/index.tsx
@packages/web/src/routes/initiatives/$id.tsx
@packages/web/src/routes/inbox.tsx
@packages/web/src/lib/trpc.ts

# Depends on 21-01 for toast system
@.planning/phases/21-polish-integration/21-01-PLAN.md
</context>

<tasks>

<task type="auto">
  <name>Task 1: Add subscription error handling with toast feedback on all pages</name>
  <files>packages/web/src/routes/initiatives/index.tsx, packages/web/src/routes/initiatives/$id.tsx, packages/web/src/routes/inbox.tsx</files>
  <action>
  1. Create a shared pattern (inline — not a separate file) for subscription error handling. In each page's subscription `onError` callback:
     - Call `toast.error('Live updates disconnected. Refresh to reconnect.', { id: 'sub-error', duration: Infinity })` — using a fixed toast ID prevents duplicates if multiple subscriptions fail simultaneously. `duration: Infinity` keeps it visible until dismissed.
     - The toast is intentionally sticky so the user knows live updates are broken.

  2. Apply to all subscription hooks:
     - `initiatives/index.tsx`: `trpc.onTaskUpdate.useSubscription` — replace `onError: () => {}` with the error toast.
     - `initiatives/$id.tsx`: Both `trpc.onTaskUpdate.useSubscription` and `trpc.onAgentUpdate.useSubscription` — replace both `onError: () => {}` with the error toast using the same toast ID (so only one shows).
     - `inbox.tsx`: `trpc.onAgentUpdate.useSubscription` — replace `onError: () => {}` with the error toast.

  3. Import `toast` from `sonner` in each file.

  Do NOT add complex reconnection logic. The tRPC SSE httpSubscriptionLink already handles reconnection automatically via EventSource retry. The toast just informs the user that something went wrong. When the connection re-establishes, `onData` will fire and queries will invalidate — the app self-heals.
  </action>
  <verify>
  - `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes
  - `npm run --workspace=packages/web build` succeeds
  - Grep confirms no remaining `onError: () => {}` in route files
  </verify>
  <done>All subscription error callbacks show user-facing feedback instead of silently swallowing. Same toast ID prevents duplicate error notifications.</done>
</task>

<task type="auto">
  <name>Task 2: Add error toast to SpawnArchitectDropdown inline mutation</name>
  <files>packages/web/src/components/SpawnArchitectDropdown.tsx</files>
  <action>
  NOTE: Plan 21-01 Task 2 already adds toasts to SpawnArchitectDropdown. This task is a verification step — confirm that 21-01 was applied correctly, and if the component still has any `console.error` calls without corresponding toast.error calls, fix them.

  If 21-01 was applied correctly, this is a no-op. Mark as done.

  If for any reason 21-01 didn't cover it, add `toast.error('Failed to spawn architect: ' + err.message)` in the mutation's onError and `toast.success('Architect spawned')` in onSuccess.
  </action>
  <verify>
  - `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes
  - Grep for `console.error` in SpawnArchitectDropdown.tsx returns no results
  </verify>
  <done>SpawnArchitectDropdown shows toast feedback for all outcomes.</done>
</task>

</tasks>

<verification>
Before declaring plan complete:
- [ ] `npx tsc --noEmit -p packages/web/tsconfig.app.json` passes
- [ ] `npm run --workspace=packages/web build` succeeds
- [ ] No `onError: () => {}` remaining in any route file
- [ ] No `console.error` without corresponding toast in component files
</verification>

<success_criteria>

- All tasks completed
- All verification checks pass
- Subscription errors show sticky toast notification
- Users know when live updates are disconnected
  </success_criteria>

<output>
After completion, create `.planning/phases/21-polish-integration/21-04-SUMMARY.md`
</output>
