Skip to content

fix(webapp): never resolve realtime streams v2 without S2 configured - #4564

Open
matt-aitken wants to merge 3 commits into
mainfrom
fix/streams-version-guard
Open

fix(webapp): never resolve realtime streams v2 without S2 configured#4564
matt-aitken wants to merge 3 commits into
mainfrom
fix/streams-version-guard

Conversation

@matt-aitken

@matt-aitken matt-aitken commented Aug 11, 2026

Copy link
Copy Markdown
Member

Summary

determineRealtimeStreamsVersion treated its two paths differently. An explicit v2 from the caller was checked against the S2 configuration before being honoured, but when the caller expressed no preference the function returned REALTIME_STREAMS_DEFAULT_VERSION verbatim, with no check at all.

So a deployment that set the default to v2 without configuring S2 stamped its runs v2. Nothing failed at trigger time. Every later read or write against those runs' streams then threw Realtime streams v2 is required for this run but S2 configuration is missing, and because the version is fixed on the run at creation, it threw for the life of the run.

Fix

Both paths now resolve through one check, in a pure function that takes the configuration rather than reading env:

const requested = streamVersion ?? config.defaultVersion;
if (requested !== "v2") return "v1";

const hasCredentials = Boolean(config.accessToken) || config.skipAccessTokens;
return hasCredentials && Boolean(config.basin) ? "v2" : "v1";

An unsatisfiable v2 degrades to v1, which is a working backend, rather than producing a run whose streams cannot be used.

The basin requirement

resolveStreamBasin resolves run, session and organization basins ahead of the global setting, so a deployment that provisions a basin per organization can serve v2 with no global basin at all. Gating purely on the global setting would degrade every run there to v1.

determineRealtimeStreamsVersion therefore takes an optional organization basin, and callers that hold one pass authentication.environment.organization.streamBasinName:

basin: organizationBasinName ?? env.REALTIME_STREAMS_S2_BASIN,

This is deliberately the resolved basin and not the REALTIME_STREAMS_PER_ORG_BASINS_ENABLED flag. The flag says the feature is on, not that a given organization has been provisioned, and provisioning happens out of band. Keying off the flag would stamp v2 on runs for unprovisioned organizations, recreating the failure this PR removes.

This does widen behaviour for explicit v2 requests, which previously required the global basin: a provisioned organization on a per-org deployment now resolves v2 where it used to get v1. That is intentional, and it makes the two paths agree.

No behaviour change for a deployment that leaves REALTIME_STREAMS_DEFAULT_VERSION unset or set to v1 and configures a global basin.

Unit tests cover the resolution matrix, including organization-basin-only and credential-only configurations.

The default-version branch returned `REALTIME_STREAMS_DEFAULT_VERSION` verbatim
while the explicit branch checked that a basin and credentials were present. A
deployment that set the default to v2 without configuring S2 therefore stamped
runs v2, and every read and write against those runs' streams threw for the
life of the run.

Both paths now go through the same check, and an unsatisfiable v2 degrades to
v1, which is a working backend.
@changeset-bot

changeset-bot Bot commented Aug 11, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 6780a97

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The webapp now resolves the requested or configured realtime streams version through validated configuration. It selects v2 only when credentials and a global or per-organization basin are available. Otherwise, it selects v1. Task, batch, and replay flows now pass organization basin settings during version resolution. Tests cover deployment configurations, defaults, explicit versions, missing credentials or basins, and unrecognized versions. A changelog entry documents the fix.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the main fix: preventing realtime streams v2 resolution without S2 configuration.
Description check ✅ Passed The description clearly explains the defect, fix, basin behavior, compatibility impact, and unit-test coverage.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/streams-version-guard

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

devin-ai-integration[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

Gating v2 on the global basin alone would have degraded every run to v1 on a
deployment that provisions a basin per organization and sets no global one,
even though S2 is fully working there. `resolveStreamBasin` already resolves
run, session and organization basins ahead of the global setting, so either
source now satisfies the basin requirement.

Splits the pure resolver out from the env lookup so the version matrix can be
tested without reaching for `env.server`.
devin-ai-integration[bot]

This comment was marked as resolved.

Treating `REALTIME_STREAMS_PER_ORG_BASINS_ENABLED` as proof of a basin was
wrong. The flag says the feature is on, not that an organization has been
provisioned, and provisioning happens out of band. An unprovisioned
organization on a deployment with no global basin would still have been stamped
v2 and thrown on every stream operation, which is the failure this is meant to
prevent.

Callers that hold the organization now pass its `streamBasinName`, mirroring
the organization step of `resolveStreamBasin`. A provisioned organization
resolves v2 with no global basin configured; an unprovisioned one degrades to
v1.
@matt-aitken
matt-aitken enabled auto-merge (squash) August 11, 2026 10:48
@matt-aitken
matt-aitken disabled auto-merge August 11, 2026 10:48
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.

3 participants