Skip to content

CI cannot catch a WS events transport regression: the lane passes on silent HTTP fallback #3730

Description

@pranaygp

Found while diagnosing #3728. The WebSocket events transport silently fell back to HTTP for the entire life of every affected process, from #3493 (2026-08-19) until it was noticed by hand in durabench. Every CI lane stayed green throughout.

Three gaps, each independently sufficient to hide it:

1. e2e-vercel-ws-transport does not assert the transport

The lane exercises a run and checks the run's outcome. Events written over HTTP produce the same outcome as events written over WS, so the lane passes either way — it asserts that the feature is harmless, not that it is used.

Fix: assert which transport actually carried the events. postEventFrameOverWs already tags its span workflow.events.transport: 'ws' (see ws-transport-spans.test.ts), so there is something concrete to assert on.

2. No workbench warms the world in instrumentation.ts

workbench/nextjs-turbopack/instrumentation.ts only calls registerOTel. The failing shape needs register() to touch the world:

const { getWorld } = await import('workflow/runtime');
await getWorld();

That is what durabench's apps/workflow-host does, and it is why durabench saw this and CI did not. Worth adding to one workbench app so the deployed lane has the shape.

Note this is not required to duplicate the module — with no warm-up at all there are still two live copies (route + ssr) — but it is what makes the two World caches land in different copies deterministically.

3. resolveWsTransport misses silently

A miss returns null and the caller writes over HTTP with no breadcrumb. A single debug log naming the wsUrl and the registry size would have turned several investigations into one grep. Cheap, and useful well beyond this bug.

Why it matters beyond the one regression

#3728 adds a lint rule that prevents the cause (mutable module-scope state in a bundled world) from recurring. These three items are about the symptom being observable: the transport can also break for reasons that have nothing to do with module duplication — a proxy, an auth failure, a handshake regression — and today all of those are equally invisible.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingclaude-code-assistedws-transport-testRun the e2e-vercel-ws-transport lanes (WORKFLOW_EVENTS_TRANSPORT=ws) on this PR

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions