Skip to content

fix(privacy): gate cloud usage reporting to OpenWhispr-cloud transcriptions - #1679

Open
xpipko wants to merge 2 commits into
OpenWhispr:mainfrom
xpipko:fix/streaming-usage-privacy-gate
Open

fix(privacy): gate cloud usage reporting to OpenWhispr-cloud transcriptions#1679
xpipko wants to merge 2 commits into
OpenWhispr:mainfrom
xpipko:fix/streaming-usage-privacy-gate

Conversation

@xpipko

@xpipko xpipko commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

The problem

The streaming completion path reported usage to the OpenWhispr API for every
provider, and that call carries sendLogs — the transcript text itself.

For BYOK providers, custom endpoints, and self-hosted servers the user has
deliberately routed audio away from OpenWhispr's cloud. Shipping their
transcripts back defeats the point of choosing those providers.

The fix

Providers declare in the streaming registry whether their audio travels through
OpenWhispr Cloud, and the session records the answer at connect time from the
provider it selected and the mode it sent:

this.streamingSessionMetered =
  !!provider.cloudMetered && sessionOptions.mode === "openwhispr";

Completion reads that recorded decision instead of re-deriving routing from
settings, so a mid-dictation settings change can no longer decide where the
transcript goes.

mode is read back off the object buildStreamingSessionOptions() built rather
than re-derived, so the usage decision and the connect payload cannot disagree —
and if that builder ever changes how it resolves the mode, this follows
automatically.

The flag is opt-in. A backend added later stays silent until someone states
otherwise, so the failure mode of an oversight is a missing usage row rather
than a leaked transcript.

Provider Reports usage Why
deepgram yes OpenWhispr Cloud is the upstream
assemblyai yes OpenWhispr Cloud is the upstream
openai-realtime only in openwhispr mode runs both as Cloud's own upstream and, in BYOK, against the user's key
corti no streams over Corti's own WSS on the user's credentials
tinfoil-realtime no streams against the user's own Tinfoil key
local / self-hosted n/a never open a streaming session

Tests

test/helpers/audioManagerUsageGate.test.js drives production code rather than
restating it: each case sets a settings state and runs the real
resolveStreamingProviderName(), the real STREAMING_PROVIDERS registry via
getStreamingProvider(), and the real buildStreamingSessionOptions(), then
asserts which combinations may report usage. Six cases cover all five streaming
providers, including openai-realtime in both modes.

Confirmed it catches the regression it exists for: dropping cloudMetered from
openai-realtime fails the OpenWhispr-managed case.

It pins the gate's inputs, not the gate expression or its single consumer — both
sit inside startStreamingRecording past the mic and worklet setup, where there
is no seam to call. So it catches a backend added without a decision, or a BYOK
provider flipped to metered; it would not catch the guard itself being deleted.

npm run lint clean, full suite green (2089 tests).

xpipko added 2 commits August 22, 2026 09:18
…ptions

The streaming completion path reported usage to the OpenWhispr API for
every provider, and the call carries sendLogs -- the transcript text.
For BYOK providers, custom endpoints, and self-hosted servers the user
has deliberately routed audio away from OpenWhispr's cloud, so shipping
their transcripts back defeats the point.

Providers now declare in the streaming registry whether their audio
travels through OpenWhispr Cloud, and the session records the answer at
connect time from the provider it selected and the mode it sent.
Completion reads that instead of re-deriving routing from settings,
which also stops a mid-dictation settings change from deciding where the
transcript goes.

The flag is opt-in, so a provider added later stays silent until someone
states otherwise -- the failure mode of an oversight is a missing usage
row rather than a leaked transcript. Corti and Tinfoil stream on the
user's own credentials and declare nothing; local and self-hosted never
open a streaming session at all.
Drives the real resolveStreamingProviderName, STREAMING_PROVIDERS registry
and buildStreamingSessionOptions from a settings state, and asserts which
combinations may report usage. Adding a backend without declaring
cloudMetered, or flipping a BYOK provider to metered, fails here.

Verified it catches the regression: dropping cloudMetered from
openai-realtime fails the OpenWhispr-managed case.
@xpipko
xpipko force-pushed the fix/streaming-usage-privacy-gate branch from 0b65ddb to 1646762 Compare August 25, 2026 15:32
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