Skip to content

refactor(web): extract lib/streaming/ transport layer from domains/chat/#32598

Merged
ashleeradka merged 6 commits into
mainfrom
devin/1780080239-lum-2033-extract-streaming-domain
May 29, 2026
Merged

refactor(web): extract lib/streaming/ transport layer from domains/chat/#32598
ashleeradka merged 6 commits into
mainfrom
devin/1780080239-lum-2033-extract-streaming-domain

Conversation

@ashleeradka
Copy link
Copy Markdown
Contributor

@ashleeradka ashleeradka commented May 29, 2026

Closes LUM-2033

Prompt / plan

Phase 1 of a 2-phase plan to extract SSE transport infrastructure from domains/chat/. This PR creates lib/streaming/ as the home for transport-only code (SSE connection, event parsing, debug tracking) — zero domain knowledge.

Why lib/streaming/ not domains/streaming/? Streaming transport is shared infrastructure with side effects (SSE connections), not a business domain. Placing it in domains/ would require 15+ cross-domain allowlist entries for every chat file that imports from it. lib/ is defined in CONVENTIONS.md for "infrastructure with side effects" and lib/sync/ (EventSource state sync) is a direct precedent.

Changes

  1. Eliminate domains/chat/api/client.ts barrel file — 19-line re-export file deleted, 14 consumers updated to import directly from @/generated/api/client.gen and @/utils/api-errors
  2. Lift DisplayAttachment to @/types/attachment-types.ts — cross-domain type that was stuck in domains/chat/types/types.ts
  3. Move utils/diagnostics.tslib/diagnostics.ts — has side effects (sessionStorage I/O, Capacitor SDK import), belongs in lib/ per CONVENTIONS.md lib/ vs utils/ table
  4. Eliminate barrel re-exports in domains/chat/utils/diagnostics.ts — removed 7 aliased re-exports (recordDiagnostic as recordChatDiagnostic, etc.), updated all 11 consumers to import directly from @/lib/diagnostics with canonical names
  5. Move transport files to lib/streaming/:
    • domains/chat/api/stream.tslib/streaming/stream-transport.ts (renamed per CONVENTIONS.md)
    • domains/chat/api/event-parser.tslib/streaming/event-parser.ts
    • domains/chat/api/stream-debug.tslib/streaming/stream-debug.ts
    • All test files colocated alongside source
  6. Remove 15 cross-domain allowlist entrieslib/ imports don't require allowlisting
  7. Update CONVENTIONS.md and STYLE_GUIDE.md — architecture diagrams reflect lib/streaming/ and lib/diagnostics.ts, stale streaming domain references replaced
  8. Remove internal ticket references — replaced LUM-1431 and LUM-1538 references with context-appropriate descriptions (iOS WKWebView constraint, turn-sending wiring)

What stays in domains/chat/

Stream handlers (utils/stream-handlers/) remain in chat — they have heavy coupling to chat stores, utilities, and types. Phase 2 (LUM-2053) will decouple these via event bus subscribers.

Follow-up tickets created

  • LUM-2053 — Decentralize SSE stream event handlers into domain-scoped bus subscribers (Phase 2)
  • LUM-2055 — Split event-parser.ts (863 lines) into focused parsing modules
  • LUM-2056 — Split stream-transport.ts (488 lines) — extract watchdog and reconnect logic

Alternatives not taken

  • domains/streaming/ — Would require 15+ new cross-domain allowlist entries since every chat consumer would cross a domain boundary. lib/ eliminates this entirely.
  • Moving stream handlers now — Handlers have 15+ direct imports from chat stores/utils/types. Moving them without decoupling first would create more cross-domain violations than it fixes. Phase 2 uses dependency injection via StreamHandlerContext to decouple first.
  • Splitting event-parser (863L) and stream-transport (488L) now — Both exceed the ~300-line guideline but splitting mid-move adds risk. Ticketed as LUM-2055 and LUM-2056.

Safety

  • Zero logic changes — purely structural (file moves + import path updates + barrel elimination)
  • Lint and typecheck pass locally (0 new errors)
  • All cross-domain allowlist entries for streaming removed (net reduction)
  • No new dependencies introduced

References

Test plan

  • bun run lint — 0 errors
  • bunx tsc --noEmit — 0 type errors
  • Unit tests (165 tests across moved files + 20 event bus tests) — all pass
  • Vite dev server — zero module resolution errors
  • Browser — app loads, renders content, zero console errors
  • CI — 7/7 checks pass

Link to Devin session: https://app.devin.ai/sessions/4370103ab5e547ae8696d39b423f7103
Requested by: @ashleeradka

…s/chat/

- Create domains/streaming/ with stream-transport.ts, event-parser.ts,
  and stream-debug.ts (+ colocated tests)
- Eliminate domains/chat/api/client.ts barrel file — all 14 consumers
  now import directly from @/generated/api/client.gen and @/lib/api-errors
- Lift DisplayAttachment to @/types/attachment-types.ts (cross-domain type)
- Extract generic diagnostic recording to utils/diagnostics.ts; chat-domain
  diagnostics.ts retains only message-specific summary functions
- Update cross-domain allowlist for chat → streaming dependency direction
- Zero logic changes — purely structural

Closes LUM-2033

Co-Authored-By: ashlee@vellum.ai <ashlee@vellum.ai>
@devin-ai-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@linear
Copy link
Copy Markdown

linear Bot commented May 29, 2026

LUM-2033

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dc22985a70

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread apps/web/src/hooks/use-event-bus-init.ts Outdated
…tion

- Update mock.module path in use-event-bus-init.test.tsx to match
  new @/domains/streaming/stream-transport location
- Add event-parser.test.ts to cross-domain allowlist (inline type
  imports reference chat domain types)

Co-Authored-By: ashlee@vellum.ai <ashlee@vellum.ai>
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

View 2 additional findings in Devin Review.

Open in Devin Review

Comment thread apps/web/.cross-domain-allowlist.json
vex-assistant-bot[bot]
vex-assistant-bot Bot previously approved these changes May 29, 2026
Copy link
Copy Markdown
Contributor

@vex-assistant-bot vex-assistant-bot Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE — reviewed at 4b277e79

Value: Engineers and agents contributing to streaming behavior now have a clear, findable home (domains/streaming/) that doesn't require them to understand or navigate chat domain internals — this sharpens the codebase map for everyone.

What this does: Phase 1 of 2 — moves the SSE transport layer (stream.ts → stream-transport.ts, event-parser.ts, stream-debug.ts) out of domains/chat/api/ and into the new domains/streaming/ domain. Pulls generic diagnostics infrastructure to utils/diagnostics.ts, lifts DisplayAttachment to shared types, and deletes the domains/chat/api/client.ts barrel (19 lines of re-exports → 14 direct import sites). Stream handlers stay in chat for Phase 2.

Full analysis

Architecture

The boundary is correct. domains/chat/ had two distinct reasons to change: (1) chat UX/business logic — messages, composer, transcript rendering; (2) SSE infrastructure — reconnect logic, event schema parsing, stream lifecycle. This PR cleanly severs the second into its own domain. The rename stream.ts → stream-transport.ts per naming conventions is a nice touch.

File-by-file

domains/streaming/stream-transport.ts — Import rewire from the domains/chat/api/client barrel to direct client.gen + lib/api-errors imports is correct. The recordChatDiagnostic → recordDiagnostic rename aligns with the generalization. No logic changes visible.

domains/streaming/event-parser.ts — Single import path update (DisplayAttachment from shared types). Clean.

domains/streaming/stream-debug.ts — Doc comment update reflects the new module path. Minimal.

utils/diagnostics.ts (new) — The split between generic infrastructure (recordDiagnostic, resolvePlatformTag, getDiagnosticsEvents, buildDiagnosticsSnapshot) landing here vs. chat-specific summary functions (summarizeDisplayMessage, summarizeRuntimeMessage) staying in domains/chat/utils/diagnostics.ts is the right call. The share-feedback-modal.tsx import update confirms cross-domain usage made utils/ the correct home.

One small flag: bucketMessagesAdded and roleCounts are now in the generic utils file but feel chat-domain adjacent. They're typed generically enough that it's not a problem — just noting they may be better long-term candidates for domains/chat/utils/diagnostics.ts. Not blocking.

summarizeAssistantEvent operating on AssistantEvent (from shared @/types/event-types) is genuinely generic and belongs here.

types/attachment-types.ts (new) — Clean lift. DisplayAttachment was stuck in domains/chat/types/types.ts despite being consumed by the event parser. Now that event-parser lives in streaming, it can't import from chat — this resolves the backward dependency correctly. JSDoc is clear on the two population paths (SSE live vs. history reload).

domains/chat/utils/diagnostics.ts — 271 → ~20 lines. Correctly retains only chat-type summarizers.

.cross-domain-allowlist.json — 15+ new streaming entries. Devin flagged this against the "shrinks toward zero" guidance in CONVENTIONS.md (288-289). The PR description explains it well: these are documenting the legitimate chat → streaming consumer direction that exists today; Phase 2 removes them as stream handlers decouple via event bus. This is the right tradeoff for a 2-PR plan. The entries are principled, not convenient.

Bot findings at HEAD (4b277e79)

  • Codex P2 (mock path stale in use-event-bus-init.test.tsx) — ✅ fixed in this commit. @/domains/chat/api/stream@/domains/streaming/stream-transport. Verified.
  • Devin cross-domain allowlist flag — addressed in PR description with Phase 2 plan. Acceptable.
  • Devin empty review at HEAD — not a formal "No Issues Found," so second approval is still pending.

Merge gate

  • ✅ Architecture sound, conventions followed
  • ⚠️ Branch is dirty (merge conflict) — needs rebase against main before merge
  • ⚠️ CI incomplete — only Socket Security checks visible at HEAD; TypeScript/lint/tests need a clean run post-rebase
  • ⏳ Second approval still needed (Devin HEAD review was empty; needs @devin review this PR after rebase lands)

Vellum Constitution — Yours: streaming transport now has its own address in the codebase, so the assistant's infrastructure can evolve without the chat domain knowing it changed.

Co-Authored-By: ashlee@vellum.ai <ashlee@vellum.ai>
@devin-ai-integration devin-ai-integration Bot changed the title refactor(web): extract domains/streaming/ transport layer from domains/chat/ refactor(web): extract lib/streaming/ transport layer from domains/chat/ May 29, 2026
@devin-ai-integration
Copy link
Copy Markdown
Contributor

Test Results — LUM-2033

Ran Vite dev server locally against the PR branch and verified all moved files resolve correctly. All 5 tests passed.

Test Result
T1: Unit tests for moved files (165 tests across 3 files) ✅ Pass
T2: Event bus init test — mock path @/lib/streaming/stream-transport intercepts correctly (20 tests) ✅ Pass
T3: Vite dev server — zero Failed to resolve import errors ✅ Pass
T4: Browser — app loads, renders content, zero console module errors, no error boundary ✅ Pass
T5: Lint + typecheck — both exit 0 ✅ Pass
Evidence

T1 + T2: Unit tests

# Moved files (stream-debug, event-parser, stream-transport)
165 pass, 0 fail, 290 expect() calls — 3.44s

# Event bus init (mock path verification)
20 pass, 0 fail, 42 expect() calls — 2.64s

T3 + T4: Dev server + browser

  • Vite started cleanly, HTTP 200 on /assistant/
  • App redirected to /assistant/onboarding/welcome and rendered welcome page
  • Browser console: only [vite] connected. — zero module errors

T5: Static analysis

bun run lint → exit 0
bunx tsc --noEmit → exit 0

Devin session

@ashleeradka
Copy link
Copy Markdown
Contributor Author

@codex review

… update docs

- Move utils/diagnostics.ts → lib/diagnostics.ts (has side effects: sessionStorage I/O, Capacitor SDK)
- Remove barrel re-exports from domains/chat/utils/diagnostics.ts (7 aliased symbols)
- Update all 11 consumers to import directly from @/lib/diagnostics with canonical names
- Move diagnostics tests to colocate with lib/diagnostics.ts
- Update STYLE_GUIDE.md: streaming/ now shown under lib/ not domains/
- Update CONVENTIONS.md: replace stale streaming domain refs, clarify lib/streaming/ path
- Remove internal ticket references (LUM-1431, LUM-1538) from public repo code

Co-Authored-By: ashlee@vellum.ai <ashlee@vellum.ai>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8087e62ada

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread package.json Outdated
These were added during Playwright-based testing and should not be
committed — Playwright belongs in apps/web/package.json if needed.

Co-Authored-By: ashlee@vellum.ai <ashlee@vellum.ai>
@ashleeradka
Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@ashleeradka ashleeradka merged commit 0c60375 into main May 29, 2026
7 checks passed
@ashleeradka ashleeradka deleted the devin/1780080239-lum-2033-extract-streaming-domain branch May 29, 2026 21:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant