docs(20): complete plan 20-01 SSE streaming summary and state update

This commit is contained in:
Lukas May
2026-02-04 22:18:11 +01:00
parent 42154d60d4
commit 8cfdfe987b
2 changed files with 136 additions and 8 deletions

View File

@@ -9,19 +9,19 @@ See: .planning/PROJECT.md (updated 2026-02-04)
## Current Position
Phase: 19 of 21 (Agent Inbox) - COMPLETE
Plan: 4 of 4 in current phase
Status: Phase 19 complete
Last activity: 2026-02-04 - Completed 19-04-PLAN.md (Inbox Page Assembly)
Phase: 20 of 21 (Real-Time Subscriptions) - IN PROGRESS
Plan: 1 of 2 in current phase
Status: Completed 20-01 (SSE Streaming & Subscription Procedures)
Last activity: 2026-02-04 - Completed 20-01-PLAN.md (SSE backend)
Progress: █████████░ 98%
Progress: █████████░ 99%
## Performance Metrics
**Velocity:**
- Total plans completed: 70
- Total plans completed: 71
- Average duration: 3 min
- Total execution time: 197 min
- Total execution time: 201 min
**By Phase (v1.0):**
@@ -225,6 +225,10 @@ Recent decisions affecting current work:
- 19-04: Detail panel inline in page file (not a separate component) — page-specific layout
- 19-04: useUtils() for query invalidation on mutation success (same pattern as initiative detail)
- 19-04: Serialize agent/message data to string dates for InboxList props (wire format consistency)
- 20-01: Queue + deferred promise pattern for bridging push (EventBus) to pull (async generator)
- 20-01: tracked() wrapper on each event for client-side reconnection via lastEventId
- 20-01: Fallback AbortSignal (new AbortController().signal) when opts.signal is undefined
- 20-01: Vite proxy works for SSE without changes (http-proxy streams chunked responses by default)
### Pending Todos
@@ -247,5 +251,5 @@ None.
## Session Continuity
Last session: 2026-02-04
Stopped at: Completed 19-04 (Inbox Page Assembly) — Phase 19 complete
Stopped at: Completed 20-01 (SSE Streaming & Subscription Procedures)
Resume file: None

View File

@@ -0,0 +1,124 @@
---
phase: 20-real-time-subscriptions
plan: 01
subsystem: api
tags: [trpc, sse, subscriptions, async-generators, streaming, event-bus]
requires:
- phase: 01.1-hexagonal-events
provides: EventBus port interface and EventEmitterBus adapter
- phase: 16-frontend-scaffold
provides: tRPC HTTP adapter and Vite proxy configuration
provides:
- SSE streaming support in tRPC HTTP adapter
- Three subscription procedures (onEvent, onAgentUpdate, onTaskUpdate)
- EventBus-to-async-generator bridge (eventBusIterable helper)
- SubscriptionEvent type in shared package for frontend consumption
affects: [20-02-frontend-subscriptions, 21-frontend-polish]
tech-stack:
added: []
patterns: [queue-based async generator for event bridge, tracked SSE for reconnection]
key-files:
created:
- src/trpc/subscriptions.ts
modified:
- src/server/trpc-adapter.ts
- src/trpc/router.ts
- packages/shared/src/types.ts
- packages/shared/src/index.ts
key-decisions:
- "Queue + deferred promise pattern for bridging push (EventBus) to pull (async generator)"
- "tracked() wrapper on each event for client-side reconnection via lastEventId"
- "Fallback AbortSignal when opts.signal is undefined (AbortController().signal)"
- "Vite proxy works for SSE without changes (http-proxy streams by default)"
patterns-established:
- "eventBusIterable: Reusable async generator factory for any subset of EventBus events"
- "Subscription procedure pattern: input with optional lastEventId, yield* from eventBusIterable"
duration: 4min
completed: 2026-02-04
---
# Plan 20-01: SSE Streaming & Subscription Procedures Summary
**tRPC SSE streaming via async generators bridging EventBus domain events to three subscription endpoints**
## Performance
- **Duration:** 4 min
- **Started:** 2026-02-04
- **Completed:** 2026-02-04
- **Tasks:** 2
- **Files modified:** 5
## Accomplishments
- Fixed tRPC HTTP adapter to stream ReadableStream responses instead of buffering (required for SSE)
- Created subscriptions module with queue-based async generator bridging EventBus to tRPC subscriptions
- Added onEvent, onAgentUpdate, and onTaskUpdate subscription procedures to the router
- Exported SubscriptionEvent type from shared package for frontend consumption
## Task Commits
Each task was committed atomically:
1. **Task 1: Fix HTTP adapter for SSE streaming and add subscription procedures** - `e5d8dbb` (feat)
2. **Task 2: Update shared types and verify SSE integration** - `42154d6` (feat)
## Files Created/Modified
- `src/trpc/subscriptions.ts` - EventBus-to-async-generator bridge with tracked SSE events
- `src/server/trpc-adapter.ts` - Stream ReadableStream responses instead of buffering
- `src/trpc/router.ts` - Three subscription procedures (onEvent, onAgentUpdate, onTaskUpdate)
- `packages/shared/src/types.ts` - SubscriptionEvent interface for frontend
- `packages/shared/src/index.ts` - Re-export SubscriptionEvent
## Decisions Made
- 20-01: Queue + deferred promise pattern for bridging push (EventBus) to pull (async generator)
- 20-01: tracked() wrapper on each event for client-side reconnection via lastEventId
- 20-01: Fallback AbortSignal (new AbortController().signal) when opts.signal is undefined
- 20-01: Vite proxy works for SSE without changes (http-proxy streams chunked responses by default)
## Deviations from Plan
### Auto-fixed Issues
**1. [Rule 3 - Blocking] TrackedEnvelope type annotation**
- **Found during:** Task 1 (subscriptions module)
- **Issue:** `ReturnType<typeof tracked<string, SubscriptionEventData>>` is invalid TS — generic type inference on `typeof` of a generic function doesn't work
- **Fix:** Import `TrackedEnvelope` type directly from `@trpc/server` and use `TrackedEnvelope<SubscriptionEventData>` as return type
- **Files modified:** src/trpc/subscriptions.ts
- **Verification:** `npm run build` succeeds
- **Committed in:** e5d8dbb (Task 1 commit)
**2. [Rule 3 - Blocking] opts.signal potentially undefined**
- **Found during:** Task 1 (subscription procedures)
- **Issue:** `opts.signal` has type `AbortSignal | undefined` in tRPC subscription context, but eventBusIterable requires `AbortSignal`
- **Fix:** Fallback to `new AbortController().signal` when opts.signal is undefined
- **Files modified:** src/trpc/router.ts
- **Verification:** `npm run build` succeeds
- **Committed in:** e5d8dbb (Task 1 commit)
---
**Total deviations:** 2 auto-fixed (2 blocking)
**Impact on plan:** Both auto-fixes necessary for type safety. No scope creep.
## Issues Encountered
None
## User Setup Required
None - no external service configuration required.
## Next Phase Readiness
- Backend SSE streaming ready for frontend consumption
- Plan 20-02 can add httpSubscriptionLink to the tRPC client and wire subscription hooks
- All existing queries/mutations verified working (452 tests pass)
---
*Phase: 20-real-time-subscriptions*
*Completed: 2026-02-04*