Skip to content

Hotfix Soniox fallback keys for legacy cloud#3219

Merged
isaiahb merged 4 commits into
mainfrom
codex/soniox-fallback-hotfix
Jun 21, 2026
Merged

Hotfix Soniox fallback keys for legacy cloud#3219
isaiahb merged 4 commits into
mainfrom
codex/soniox-fallback-hotfix

Conversation

@isaiahb

@isaiahb isaiahb commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds Soniox fallback API keys for legacy Cloud v1 transcription and translation streams.

Why

The primary Soniox org/key hit its monthly spend ceiling, which made every new Soniox stream fail through the same exhausted credential. The old code only had provider-level retry/fallback; it did not rotate between multiple Soniox credentials.

What changed

  • Adds SONIOX_FALLBACK_API_KEYS as a comma-separated fallback list.
  • Shares one Soniox key-pool helper across transcription and translation.
  • Classifies Soniox auth, quota, rate-limit, concurrency, and transient failures with different cooldown behavior.
  • Keeps SONIOX_API_KEY as the preferred primary key while healthy.
  • Logs only safe key fingerprints, not raw API keys.
  • Documents the spike/spec in cloud/issues/108-soniox-fallback-api-keys/.

Validation

  • bun test cloud/packages/cloud/src/services/session/soniox/__tests__/SonioxKeyPool.test.ts
  • git diff --check
  • cd cloud && bun run build
  • cd cloud/packages/cloud && bun run build
  • Deployed commit 8e8ff2033941a236963a7aa12e577b8aa6881d66 to legacy cloud-debug on Azure Central US via porter-debug.yml.
  • Verified https://debugapi.mentra.glass/livez and /health return healthy.

Note

Medium Risk
Touches live STT/translation credential selection and retry behavior on a production hotfix path; misconfiguration or aggressive cooldowns could still exhaust all keys, though changes are scoped and tested at the pool layer.

Overview
Adds SONIOX_FALLBACK_API_KEYS (comma-separated) so legacy Cloud v1 can rotate across multiple Soniox credentials when the primary org/key is quota- or rate-limited.

Introduces a shared SonioxKeyPool: primary-first selection, round-robin fallbacks, per-key cooldowns (auth disables for the process; quota/rate/concurrency/transient use different durations), and SHA-256 fingerprints in logs instead of raw keys. Cooldown state is shared in-process between transcription and translation via getSharedSonioxKeyPool.

Transcription and translation Soniox providers now loop credentials on stream creation, record runtime failures on streams, and managers treat capacity errors and “no credentials available” as retryable so a new stream can pick another key.

Also bumps the default Soniox realtime model from stt-rt-v4 to stt-rt-v5 in config and stream setup. Spike/spec docs live under cloud/issues/108-soniox-fallback-api-keys/.

Reviewed by Cursor Bugbot for commit 9e0a49f. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Adds fallback Soniox API keys and a shared in‑process key pool so legacy Cloud v1 transcription and translation can rotate keys with smart cooldowns. Also defaults the Soniox model to stt-rt-v5 and tightens quota cooldown handling.

  • Bug Fixes

    • Introduced SONIOX_FALLBACK_API_KEYS and a shared key pool used by transcription and translation; cooldowns propagate across providers within the process.
    • Primary-first selection with round-robin fallbacks and per-failure cooldowns (auth disables; quota long; rate limit short; concurrency very short; transient short), with HTTP code awareness (401/402/429).
    • Providers try multiple credentials on stream creation; runtime errors record credential failures; successes do not clear active cooldowns; managers retry on capacity errors and when no credentials are temporarily available.
    • Default Soniox model is now stt-rt-v5 (SDK and WebSocket paths).
    • Log only SHA-256 key fingerprints.
  • Migration

    • Set SONIOX_FALLBACK_API_KEYS as a comma-separated list of Soniox keys in Cloud v1 environments. No other changes needed.

Written for commit e06781b. Summary will update on new commits.

Review in cubic

@isaiahb isaiahb requested a review from a team as a code owner June 21, 2026 01:51
@github-actions

Copy link
Copy Markdown
Contributor

📋 PR Review Helper

📱 Mobile App Build

Waiting for build...

🕶️ ASG Client Build

Waiting for build...


🔀 Test Locally

gh pr checkout 3219

@isaiahb isaiahb self-assigned this Jun 21, 2026

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8e8ff20339

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

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

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

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread cloud/packages/cloud/src/services/session/soniox/SonioxKeyPool.ts Outdated
Comment thread cloud/packages/cloud/src/services/session/soniox/SonioxKeyPool.ts
lower.includes("unauthorized")
) {
return { kind: "auth", cooldownMs: Number.POSITIVE_INFINITY, disabled: true };
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

403 errors not treated as auth

Low Severity

classifySonioxCredentialFailure disables credentials for HTTP 401 but not 403, so a Soniox error 403 is classified as transient with a short cooldown. That conflicts with transcription retry logic, which treats 403 as a non-retryable auth failure, and the key stays in rotation instead of being disabled for the process.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 08f06fd. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Leaving this open intentionally for follow-up. For the ASAP prod outage fix we are not broadening permanent disable behavior to 403; the production incident is the 402/budget quota path, which is fixed in e06781b.

@isaiahb

isaiahb commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

Related Soniox fallback PRs:

Current prod/main hotfix head: e06781b.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e06781b. Configure here.

this.config,
throw (
lastError ??
new Error(`No available Soniox credentials: ${JSON.stringify(this.keyPool.describeAvailability())}`)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Wrong error when keys cooling

Medium Severity

When stream creation stops because every remaining credential is on cooldown, the code still throws the last failure from an earlier key if one was tried. TranscriptionManager treats that as non-retryable for auth-style Soniox errors, so creation can give up even though fallback keys were never tried and would become available after their cooldown.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e06781b. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Leaving this open intentionally for follow-up. It is related to the broader last-error masking/retry semantics, but the ASAP prod hotfix is intentionally narrowed to the confirmed 402/budget quota outage path and shared fallback cooldown handling.

@isaiahb isaiahb merged commit 2370442 into main Jun 21, 2026
13 checks passed
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