Skip to content

fix(voice-input): keep Meta realtime dictation on HTTP/1.1 WebSockets - #1710

Merged
donjor merged 1 commit into
hyprwsfrom
t3/fix-voice-transcription-error
Oct 11, 2026
Merged

donjor merged 1 commit into
hyprwsfrom
t3/fix-voice-transcription-error

Conversation

@donjor-agent

@donjor-agent donjor-agent Bot commented Oct 11, 2026

Copy link
Copy Markdown

🤖 claude/anthropic claude-opus-5-5 (medium)

Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release t3 runtime.
That runtime is a Node 26 SEA: undici 8 defaults allowH2 on, so the global WebSocket negotiates RFC 8441 WebSocket over HTTP/2 with api.meta.ai.
undici 8.10.2 then fails Meta's valid h2 response because Sec-WebSocket-Accept is missing (close 1006); the undici fix, nodejs/undici#5774, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

Change

The realtime route provides NodeSocket.layerWebSocketConstructorWS in place of the global constructor.
The ws package is already bundled and stays on HTTP/1.1.

-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);

Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

Verification

  • Maintainer dictated successfully against a Node 26 dev server with this fix.
  • Node 26 dev server: /api/fork/voice-input/realtime upgraded 101, and Meta acknowledged the session.
  • Direct Meta probe: 2s of PCM plus endStream returned a final transcript and closed 1000.
  • vp test run apps/server/src/voice-input: 45/45 passed.
  • vp run typecheck (apps/server): exit 0.
  • vp run fork:ci: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
@donjor
donjor merged commit a0867ed into hyprws Oct 11, 2026
@donjor
donjor deleted the t3/fix-voice-transcription-error branch October 11, 2026 05:15
donjor added a commit that referenced this pull request Oct 12, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 12, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 13, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 15, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 15, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 16, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 16, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 19, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 19, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 19, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 20, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 20, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 20, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 20, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 20, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 21, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 21, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 21, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 21, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 21, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 22, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 22, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 23, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Oct 29, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Oct 29, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Oct 30, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Oct 30, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Oct 30, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Oct 31, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Nov 6, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 6, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 6, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 6, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 6, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 6, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 6, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 7, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 7, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 7, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 8, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 8, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 9, 2026
…#1710)

## Problem

Desktop dictation fails with "Could not prepare voice transcription." on the release `t3` runtime.
That runtime is a Node 26 SEA: undici 8 defaults `allowH2` on, so the global `WebSocket` negotiates RFC 8441 WebSocket over HTTP/2 with `api.meta.ai`.
undici 8.10.2 then fails Meta's valid h2 response because `Sec-WebSocket-Accept` is missing (close 1006); the undici fix, `nodejs/undici#5774`, closed unmerged.

Dev and packaged-desktop backends run Electron's Node 24 (undici 7, HTTP/1.1), so they never reproduced it.

## Change

The realtime route provides `NodeSocket.layerWebSocketConstructorWS` in place of the global constructor.
The `ws` package is already bundled and stays on HTTP/1.1.

```diff
-        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor), Effect.ignoreCause);
+          // `ws` stays on HTTP/1.1. Node 26's undici negotiates WebSocket over HTTP/2 with Meta, then
+          // fails the valid RFC 8441 response for lacking Sec-WebSocket-Accept.
+        ).pipe(Effect.provide(NodeSocket.layerWebSocketConstructorWS), Effect.ignoreCause);
```

## Scope and approval

Maintainer reported the regression, tested the fix live in T3 Code, and authorized this PR and merge.
One-line transport swap inside the fork voice-input route.

## Verification

- [x] Maintainer dictated successfully against a Node 26 dev server with this fix.
- [x] Node 26 dev server: `/api/fork/voice-input/realtime` upgraded 101, and Meta acknowledged the session.
- [x] Direct Meta probe: 2s of PCM plus `endStream` returned a final transcript and closed 1000.
- [x] `vp test run apps/server/src/voice-input`: 45/45 passed.
- [x] `vp run typecheck` (apps/server): exit 0.
- [x] `vp run fork:ci`: exit 0.

Follow-up, not in this PR: the client maps every realtime failure, including Meta's own error message, to the generic "Could not prepare" text.

Claude Opus 5.5 via Claude Code in T3 Code.

## Fork trailers

Fork-Domain: voice-input
Fork-Tier: bugfix
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Nov 9, 2026
Squashes:

- 26171fbd8fa feat(server): scaffold external voice dictation (#1672) (#1672)
- da9e3d289f0 feat(server): transcribe recordings with Meta Muse (#1673) (#1673)
- c7b4f781cf5 feat(desktop): record dictation into editable chat drafts (#1675) (#1675)
- 9d5dcb319c9 fix(desktop): keep dictation transcribing across thread switches (#1684) (#1684)
- 7782b1f05b3 feat(desktop): stream live Meta dictation into the composer (#1686) (#1686)
- 80071d08816 fix(voice-input): keep Meta realtime dictation on HTTP/1.1 WebSockets (#1710) (#1710)
- 7edffba3c2b feat(voice-input): live dictation preview for any OpenAI Realtime endpoint (#1775) (#1775)
- 2283697771d fix(voice-input): use InlineButton for processing error dismissal (#1800) (#1800)
- 54c87d908a2 fix(voice-input): one base URL derives dictation upload and live paths (#1881) (#1881)
- bd64d598282 feat(voice-input): send per-project speech terms to the dictation service (#1882) (#1882)

Fork-Domain: voice-input
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 9, 2026
Squashes:

- 26171fbd8fa feat(server): scaffold external voice dictation (#1672) (#1672)
- da9e3d289f0 feat(server): transcribe recordings with Meta Muse (#1673) (#1673)
- c7b4f781cf5 feat(desktop): record dictation into editable chat drafts (#1675) (#1675)
- 9d5dcb319c9 fix(desktop): keep dictation transcribing across thread switches (#1684) (#1684)
- 7782b1f05b3 feat(desktop): stream live Meta dictation into the composer (#1686) (#1686)
- 80071d08816 fix(voice-input): keep Meta realtime dictation on HTTP/1.1 WebSockets (#1710) (#1710)
- 7edffba3c2b feat(voice-input): live dictation preview for any OpenAI Realtime endpoint (#1775) (#1775)
- 2283697771d fix(voice-input): use InlineButton for processing error dismissal (#1800) (#1800)
- 54c87d908a2 fix(voice-input): one base URL derives dictation upload and live paths (#1881) (#1881)
- bd64d598282 feat(voice-input): send per-project speech terms to the dictation service (#1882) (#1882)

Fork-Domain: voice-input
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 9, 2026
Squashes:

- 26171fbd8fa feat(server): scaffold external voice dictation (#1672) (#1672)
- da9e3d289f0 feat(server): transcribe recordings with Meta Muse (#1673) (#1673)
- c7b4f781cf5 feat(desktop): record dictation into editable chat drafts (#1675) (#1675)
- 9d5dcb319c9 fix(desktop): keep dictation transcribing across thread switches (#1684) (#1684)
- 7782b1f05b3 feat(desktop): stream live Meta dictation into the composer (#1686) (#1686)
- 80071d08816 fix(voice-input): keep Meta realtime dictation on HTTP/1.1 WebSockets (#1710) (#1710)
- 7edffba3c2b feat(voice-input): live dictation preview for any OpenAI Realtime endpoint (#1775) (#1775)
- 2283697771d fix(voice-input): use InlineButton for processing error dismissal (#1800) (#1800)
- 54c87d908a2 fix(voice-input): one base URL derives dictation upload and live paths (#1881) (#1881)
- bd64d598282 feat(voice-input): send per-project speech terms to the dictation service (#1882) (#1882)

Fork-Domain: voice-input
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 9, 2026
Squashes:

- 26171fbd8fa feat(server): scaffold external voice dictation (#1672) (#1672)
- da9e3d289f0 feat(server): transcribe recordings with Meta Muse (#1673) (#1673)
- c7b4f781cf5 feat(desktop): record dictation into editable chat drafts (#1675) (#1675)
- 9d5dcb319c9 fix(desktop): keep dictation transcribing across thread switches (#1684) (#1684)
- 7782b1f05b3 feat(desktop): stream live Meta dictation into the composer (#1686) (#1686)
- 80071d08816 fix(voice-input): keep Meta realtime dictation on HTTP/1.1 WebSockets (#1710) (#1710)
- 7edffba3c2b feat(voice-input): live dictation preview for any OpenAI Realtime endpoint (#1775) (#1775)
- 2283697771d fix(voice-input): use InlineButton for processing error dismissal (#1800) (#1800)
- 54c87d908a2 fix(voice-input): one base URL derives dictation upload and live paths (#1881) (#1881)
- bd64d598282 feat(voice-input): send per-project speech terms to the dictation service (#1882) (#1882)

Fork-Domain: voice-input
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 9, 2026
Squashes:

- 26171fbd8fa feat(server): scaffold external voice dictation (#1672) (#1672)
- da9e3d289f0 feat(server): transcribe recordings with Meta Muse (#1673) (#1673)
- c7b4f781cf5 feat(desktop): record dictation into editable chat drafts (#1675) (#1675)
- 9d5dcb319c9 fix(desktop): keep dictation transcribing across thread switches (#1684) (#1684)
- 7782b1f05b3 feat(desktop): stream live Meta dictation into the composer (#1686) (#1686)
- 80071d08816 fix(voice-input): keep Meta realtime dictation on HTTP/1.1 WebSockets (#1710) (#1710)
- 7edffba3c2b feat(voice-input): live dictation preview for any OpenAI Realtime endpoint (#1775) (#1775)
- 2283697771d fix(voice-input): use InlineButton for processing error dismissal (#1800) (#1800)
- 54c87d908a2 fix(voice-input): one base URL derives dictation upload and live paths (#1881) (#1881)
- bd64d598282 feat(voice-input): send per-project speech terms to the dictation service (#1882) (#1882)

Fork-Domain: voice-input
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 10, 2026
Squashes:

- 26171fbd8fa feat(server): scaffold external voice dictation (#1672) (#1672)
- da9e3d289f0 feat(server): transcribe recordings with Meta Muse (#1673) (#1673)
- c7b4f781cf5 feat(desktop): record dictation into editable chat drafts (#1675) (#1675)
- 9d5dcb319c9 fix(desktop): keep dictation transcribing across thread switches (#1684) (#1684)
- 7782b1f05b3 feat(desktop): stream live Meta dictation into the composer (#1686) (#1686)
- 80071d08816 fix(voice-input): keep Meta realtime dictation on HTTP/1.1 WebSockets (#1710) (#1710)
- 7edffba3c2b feat(voice-input): live dictation preview for any OpenAI Realtime endpoint (#1775) (#1775)
- 2283697771d fix(voice-input): use InlineButton for processing error dismissal (#1800) (#1800)
- 54c87d908a2 fix(voice-input): one base URL derives dictation upload and live paths (#1881) (#1881)
- bd64d598282 feat(voice-input): send per-project speech terms to the dictation service (#1882) (#1882)

Fork-Domain: voice-input
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 10, 2026
Squashes:

- 26171fbd8fa feat(server): scaffold external voice dictation (#1672) (#1672)
- da9e3d289f0 feat(server): transcribe recordings with Meta Muse (#1673) (#1673)
- c7b4f781cf5 feat(desktop): record dictation into editable chat drafts (#1675) (#1675)
- 9d5dcb319c9 fix(desktop): keep dictation transcribing across thread switches (#1684) (#1684)
- 7782b1f05b3 feat(desktop): stream live Meta dictation into the composer (#1686) (#1686)
- 80071d08816 fix(voice-input): keep Meta realtime dictation on HTTP/1.1 WebSockets (#1710) (#1710)
- 7edffba3c2b feat(voice-input): live dictation preview for any OpenAI Realtime endpoint (#1775) (#1775)
- 2283697771d fix(voice-input): use InlineButton for processing error dismissal (#1800) (#1800)
- 54c87d908a2 fix(voice-input): one base URL derives dictation upload and live paths (#1881) (#1881)
- bd64d598282 feat(voice-input): send per-project speech terms to the dictation service (#1882) (#1882)

Fork-Domain: voice-input
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 10, 2026
Squashes:

- 26171fbd8fa feat(server): scaffold external voice dictation (#1672) (#1672)
- da9e3d289f0 feat(server): transcribe recordings with Meta Muse (#1673) (#1673)
- c7b4f781cf5 feat(desktop): record dictation into editable chat drafts (#1675) (#1675)
- 9d5dcb319c9 fix(desktop): keep dictation transcribing across thread switches (#1684) (#1684)
- 7782b1f05b3 feat(desktop): stream live Meta dictation into the composer (#1686) (#1686)
- 80071d08816 fix(voice-input): keep Meta realtime dictation on HTTP/1.1 WebSockets (#1710) (#1710)
- 7edffba3c2b feat(voice-input): live dictation preview for any OpenAI Realtime endpoint (#1775) (#1775)
- 2283697771d fix(voice-input): use InlineButton for processing error dismissal (#1800) (#1800)
- 54c87d908a2 fix(voice-input): one base URL derives dictation upload and live paths (#1881) (#1881)
- bd64d598282 feat(voice-input): send per-project speech terms to the dictation service (#1882) (#1882)

Fork-Domain: voice-input
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 10, 2026
Squashes:

- 26171fbd8fa feat(server): scaffold external voice dictation (#1672) (#1672)
- da9e3d289f0 feat(server): transcribe recordings with Meta Muse (#1673) (#1673)
- c7b4f781cf5 feat(desktop): record dictation into editable chat drafts (#1675) (#1675)
- 9d5dcb319c9 fix(desktop): keep dictation transcribing across thread switches (#1684) (#1684)
- 7782b1f05b3 feat(desktop): stream live Meta dictation into the composer (#1686) (#1686)
- 80071d08816 fix(voice-input): keep Meta realtime dictation on HTTP/1.1 WebSockets (#1710) (#1710)
- 7edffba3c2b feat(voice-input): live dictation preview for any OpenAI Realtime endpoint (#1775) (#1775)
- 2283697771d fix(voice-input): use InlineButton for processing error dismissal (#1800) (#1800)
- 54c87d908a2 fix(voice-input): one base URL derives dictation upload and live paths (#1881) (#1881)
- bd64d598282 feat(voice-input): send per-project speech terms to the dictation service (#1882) (#1882)

Fork-Domain: voice-input
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 10, 2026
Squashes:

- 26171fbd8fa feat(server): scaffold external voice dictation (#1672) (#1672)
- da9e3d289f0 feat(server): transcribe recordings with Meta Muse (#1673) (#1673)
- c7b4f781cf5 feat(desktop): record dictation into editable chat drafts (#1675) (#1675)
- 9d5dcb319c9 fix(desktop): keep dictation transcribing across thread switches (#1684) (#1684)
- 7782b1f05b3 feat(desktop): stream live Meta dictation into the composer (#1686) (#1686)
- 80071d08816 fix(voice-input): keep Meta realtime dictation on HTTP/1.1 WebSockets (#1710) (#1710)
- 7edffba3c2b feat(voice-input): live dictation preview for any OpenAI Realtime endpoint (#1775) (#1775)
- 2283697771d fix(voice-input): use InlineButton for processing error dismissal (#1800) (#1800)
- 54c87d908a2 fix(voice-input): one base URL derives dictation upload and live paths (#1881) (#1881)
- bd64d598282 feat(voice-input): send per-project speech terms to the dictation service (#1882) (#1882)

Fork-Domain: voice-input
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
Co-authored-by: donjor <[email protected]>
rsi-software-agent Bot pushed a commit that referenced this pull request Nov 11, 2026
Squashes:

- 26171fbd8fa feat(server): scaffold external voice dictation (#1672) (#1672)
- da9e3d289f0 feat(server): transcribe recordings with Meta Muse (#1673) (#1673)
- c7b4f781cf5 feat(desktop): record dictation into editable chat drafts (#1675) (#1675)
- 9d5dcb319c9 fix(desktop): keep dictation transcribing across thread switches (#1684) (#1684)
- 7782b1f05b3 feat(desktop): stream live Meta dictation into the composer (#1686) (#1686)
- 80071d08816 fix(voice-input): keep Meta realtime dictation on HTTP/1.1 WebSockets (#1710) (#1710)
- 7edffba3c2b feat(voice-input): live dictation preview for any OpenAI Realtime endpoint (#1775) (#1775)
- 2283697771d fix(voice-input): use InlineButton for processing error dismissal (#1800) (#1800)
- 54c87d908a2 fix(voice-input): one base URL derives dictation upload and live paths (#1881) (#1881)
- bd64d598282 feat(voice-input): send per-project speech terms to the dictation service (#1882) (#1882)

Fork-Domain: voice-input
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
Co-authored-by: donjor <[email protected]>
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