Skip to content

fix(cloud): keep retained stream config and pick supported defaults for new streams - #1460

Merged
Aaron ("AJ") Steers (aaronsteers) merged 6 commits into
release-candidate/v1from
devin/1794330332-cloud-syncmode-fix
Nov 12, 2026
Merged

Aaron ("AJ") Steers (aaronsteers) merged 6 commits into
release-candidate/v1from
devin/1794330332-cloud-syncmode-fix

Conversation

@aaronsteers

@aaronsteers Aaron ("AJ") Steers (aaronsteers) commented Nov 10, 2026 •

Copy link
Copy Markdown
Member

Overview

👉 TL;DR: Changing which streams a connection syncs no longer resets the streams that stay selected, and newly selected streams get the best sync mode they support instead of always using full refresh with overwrite. If a stream's existing settings can't be read in full, the change is refused, so nothing is lost.

Specifically, CloudConnection.set_selected_streams (MCP set_connection_selected_streams) resends each retained stream's existing StreamConfiguration, and api_util.build_stream_configurations picks new-stream defaults from getStreamProperties. Fixes #1459.

Changes

  • set_selected_streams re-reads the connection (force_refresh=True) and keeps every retained stream's config as-is: sync mode, cursor, primary key, namespace variants, mappers and selected fields. An empty selectedFields: [] from the GET is left out of the request, because the API rejects it with "No fields selected".
  • If a stream's mappers can't be decoded, get_connection normally falls back to lenient decoding, which drops them. set_selected_streams reads the connection with allow_mapper_loss=False, so in that case it raises AirbyteCloudError ("Stream mappers could not be read safely. Nothing was changed.") instead of PATCHing a config without mappers. Other callers keep the lenient default.
  • Streams without a config (newly selected streams, and every stream in create_connection / CloudWorkspace.deploy_connection) get the first mode in the stream's syncModes whose requirements are met:
    1. incremental_deduped_history: cursor and source-defined primary key
    2. incremental_append: cursor
    3. full_refresh_overwrite_deduped: source-defined primary key
    4. full_refresh_overwrite: if supported, or if syncModes is unknown
    5. full_refresh_append: for append-only destinations
  • The cursor is sent only for incremental modes, and the primary key only for deduped modes. A stream that supports none of these modes is sent with only its name and namespace, so the API picks the mode, and a warning names the stream.
  • Stream properties come from get_source_stream_properties(source_id, destination_id=..., ignore_cache=False), so syncModes already covers only modes both the source and the destination support. If the lookup fails, a warning is logged and new streams are sent by name only; the call still succeeds.
  • The docstrings of set_selected_streams, set_connection_selected_streams and create_connection describe this behavior. No MCP tool arguments changed.

Review Spotlight

Reviewers with limited time, please review first:

Risks

  • Selection changes now fail, rather than silently dropping mappers, on connections whose mappers the SDK can't decode (for example field-filtering). Those connections need the Cloud UI for selection changes until the SDK models can decode those mappers.

  • A retained stream name keeps exactly the namespace variants it already has. A newly discovered namespace for a name that is already selected is not added automatically.

  • Defaults come from the cached catalog (ignore_cache=False), so a stream that hasn't been discovered yet falls back to a name-only config.

Test plan

  • tests/unit_tests (2503 passed), ruff check, ruff format --check, pyrefly. The tests cover each default tier, a missing cursor or primary key, unsupported modes, the lookup-failure fallback, connection creation, empty and non-empty selectedFields, the append-only fallback, the refusal on undecodable mappers (_connection_with_field_filtering_mapper), and retained-config preservation; the preservation test fails if the fix is reverted.
  • Live in the Devin sandbox workspace, on 9a1a33a (before the mapper guard and append-only fallback) (Faker → dev-null), through the real MCP tool functions:
    • create_connection saved incremental_deduped_history with cursor and primary key.
    • After one stream was changed to incremental_append, set_connection_selected_streams (drop one stream, add one) kept that stream byte-for-byte identical, and the added stream got incremental_deduped_history.
    • On release-candidate/v1, the same steps reset the retained stream to full_refresh_overwrite.
  • Cloud MCP eval comparison: 122/130 passed vs 121/130 on base (run).

Link to Devin session: https://app.devin.ai/sessions/4b418db908da45af9e266acb39a59688
Link to Bot: https://app.devin.ai/org/airbytehq/bots/9b3f0480dd6148c9aba17702f8349056
Open in Devin Desktop: https://app.devin.ai/desktop/session/4b418db908da45af9e266acb39a59688?variant=devin

Important

Auto-merge enabled.

This PR is set to merge automatically when all requirements are met.

@devin-ai-integration

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

@github-actions

Copy link
Copy Markdown

👋 Greetings, Airbyte Team Member!

Here are some helpful tips and reminders for your convenience.

💡 Show Tips and Tricks

Testing This PyAirbyte Version

You can test this version of PyAirbyte using the following:

# Run PyAirbyte CLI from this branch:
uvx --from 'git+https://github.com/airbytehq/PyAirbyte.git@devin/1794330332-cloud-syncmode-fix' pyairbyte --help

# Install PyAirbyte from this branch for development:
pip install 'git+https://github.com/airbytehq/PyAirbyte.git@devin/1794330332-cloud-syncmode-fix'

PR Slash Commands

Airbyte Maintainers can execute the following slash commands on your PR:

  • /fix-pr - Fixes most formatting and linting issues
  • /uv-lock - Updates uv.lock file
  • /test-pr - Runs tests with the updated PyAirbyte
  • /prerelease - Builds and publishes a prerelease version to PyPI
  • /evals - Runs the Cloud MCP evals that use the MCP tools this PR changed (/evals full=true runs the full suite)
📚 Show Repo Guidance

Helpful Resources

Community Support

Questions? Join the #pyairbyte channel in our Slack workspace.

📝 Edit this welcome message.

@github-code-quality

github-code-quality Bot commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

Code coverage overview

Languages: Python

Python / code-coverage/pytest-no-creds

release-candidate/v1 d9f652f devin/1794330332-clo... 0721270 +/-
65% 81% +16%
View coverage of the 10 most impacted files.
File release-candidate/v1 d9f652f devin/1794330332-clo... 0721270 +/-
airbyte/_util/api_util.py 36% 68% +32%
airbyte/mcp/cloud.py 52% 87% +35%
airbyte/cloud/connectors.py 34% 81% +47%
airbyte/cloud/connections.py 26% 76% +50%
airbyte/mcp/_datadog.py 0% 50% +50%
airbyte/mcp/_telemetry.py 0% 94% +94%
airbyte/cloud/c...lder/project.py 0% 94% +94%
airbyte/_direct...ctors/models.py 0% 95% +95%
airbyte/mcp/_sso_auth.py 0% 96% +96%
airbyte/cloud/models.py 0% 96% +96%

Python / code-coverage/pytest-unit

release-candidate/v1 devin/1794330332-clo... 0721270 +/-
— 78% —

Line coverage data for the release-candidate/v1 branch is not yet available.

View coverage of the 10 most covered files.
File release-candidate/v1 devin/1794330332-clo... 0721270 +/-
airbyte/mcp/_sso_auth.py — 96% —
airbyte/cloud/models.py — 96% —
airbyte/_direct...ctors/models.py — 95% —
airbyte/cloud/client.py — 91% —
airbyte/mcp/cloud.py — 87% —
airbyte/cloud/connectors.py — 81% —
airbyte/progress.py — 80% —
airbyte/cloud/connections.py — 76% —
airbyte/_util/api_util.py — 68% —
airbyte/shared/...ql_processor.py — 68% —

ℹ️ Calculations represent line coverage. Results may change as calculations are updated.


Updated November 12, 2026 15:44 UTC

Co-Authored-By: AJ Steers <aj@airbyte.io>
@devin-ai-integration devin-ai-integration Bot changed the title fix(cloud): preserve existing stream config in set_selected_streams fix(cloud): preserve stream config and choose supported defaults for new streams Nov 11, 2026
Co-Authored-By: AJ Steers <aj@airbyte.io>
@devin-ai-integration

devin-ai-integration Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Devin Review

🟢 Devin Review found nothing to fix · View findings · Follow Devin's work

Co-Authored-By: AJ Steers <aj@airbyte.io>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Devin Review found 1 finding. Devin automatically fixed it.

Fixed by Devin (1)
  • Unsupported overwrite mode blocks stream selection — Overwrite is now used only when it is supported or the modes are unknown; otherwise the stream is sent name-only so the API picks its default.

View findings in Devin Review · Follow Devin's work

Devin Review

Co-Authored-By: AJ Steers <aj@airbyte.io>
@devin-ai-integration devin-ai-integration Bot changed the title fix(cloud): preserve stream config and choose supported defaults for new streams fix(cloud): keep retained stream config and pick supported defaults for new streams Nov 12, 2026
@aaronsteers
Aaron ("AJ") Steers (aaronsteers) marked this pull request as ready for review November 12, 2026 15:18
Copilot AI balanced review requested due to automatic review settings November 12, 2026 15:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The replacement PATCH can silently discard existing stream mappers after lenient decoding, while missing sync-mode selection can request unsupported overwrite behavior for append-only destinations.

2 open issues
What changed in this PR

This PR addresses #1459 by preserving retained stream settings when changing a Cloud connection’s stream selection and choosing supported defaults for newly selected streams.

Changes:

  • Refresh connection settings before selection updates and reuse retained configurations, omitting empty field selections.
  • Choose new-stream defaults from source and destination capabilities, with a fallback when property lookup fails.
  • Document the behavior and add tests for preservation, default selection, and failure handling.
File Description
tests/​unit_tests/​test_cloud_connections.py Tests retained settings, empty field selections, and failed reads.
tests/​unit_tests/​test_cloud_api_util.py Tests default-mode selection, lookup fallback, and connection creation.
airbyte/​mcp/​cloud.py Documents stream configuration behavior in MCP tool docstrings.
airbyte/​cloud/​connections.py Refreshes and passes existing configurations into selection updates.
airbyte/​_util/​api_util.py Adds stream-property lookup, supported defaults, and retained-configuration handling.

Review effort: Balanced

Comment thread airbyte/cloud/connections.py Resolved
Comment thread airbyte/_util/api_util.py Resolved
@aaronsteers
Aaron ("AJ") Steers (aaronsteers) merged commit 95edda3 into release-candidate/v1 Nov 12, 2026
27 checks passed
@aaronsteers
Aaron ("AJ") Steers (aaronsteers) deleted the devin/1794330332-cloud-syncmode-fix branch November 12, 2026 15:44
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.

2 participants