Repository navigation
fix(cloud): keep retained stream config and pick supported defaults for new streams - #1460
Conversation
Co-Authored-By: AJ Steers <aj@airbyte.io>
|
I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".
|
👋 Greetings, Airbyte Team Member!Here are some helpful tips and reminders for your convenience. 💡 Show Tips and TricksTesting This PyAirbyte VersionYou 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 CommandsAirbyte Maintainers can execute the following slash commands on your PR:
📚 Show Repo GuidanceHelpful ResourcesCommunity SupportQuestions? Join the #pyairbyte channel in our Slack workspace. |
Code coverage overviewLanguages: Python Python / code-coverage/pytest-no-creds
View coverage of the 10 most impacted files.
Python / code-coverage/pytest-unit
Line coverage data for the release-candidate/v1 branch is not yet available. View coverage of the 10 most covered files.
ℹ️ Calculations represent line coverage. Results may change as calculations are updated. Updated |
Co-Authored-By: AJ Steers <aj@airbyte.io>
set_selected_streamsCo-Authored-By: AJ Steers <aj@airbyte.io>
Devin Review🟢 Devin Review found nothing to fix · View findings · Follow Devin's work |
Co-Authored-By: AJ Steers <aj@airbyte.io>
There was a problem hiding this comment.
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.
Co-Authored-By: AJ Steers <aj@airbyte.io>
There was a problem hiding this comment.
🟡 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
Co-Authored-By: AJ Steers <aj@airbyte.io>
95edda3
into
release-candidate/v1


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(MCPset_connection_selected_streams) resends each retained stream's existingStreamConfiguration, andapi_util.build_stream_configurationspicks new-stream defaults fromgetStreamProperties. Fixes #1459.Changes
set_selected_streamsre-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 emptyselectedFields: []from the GET is left out of the request, because the API rejects it with "No fields selected".get_connectionnormally falls back to lenient decoding, which drops them.set_selected_streamsreads the connection withallow_mapper_loss=False, so in that case it raisesAirbyteCloudError("Stream mappers could not be read safely. Nothing was changed.") instead of PATCHing a config without mappers. Other callers keep the lenient default.create_connection/CloudWorkspace.deploy_connection) get the first mode in the stream'ssyncModeswhose requirements are met:incremental_deduped_history: cursor and source-defined primary keyincremental_append: cursorfull_refresh_overwrite_deduped: source-defined primary keyfull_refresh_overwrite: if supported, or ifsyncModesis unknownfull_refresh_append: for append-only destinationsget_source_stream_properties(source_id, destination_id=..., ignore_cache=False), sosyncModesalready 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.set_selected_streams,set_connection_selected_streamsandcreate_connectiondescribe this behavior. No MCP tool arguments changed.Review Spotlight
Reviewers with limited time, please review first:
api_util.py#L2018-L2072:_default_stream_configuration, which picks the default modeapi_util.py#L2075-L2139:build_stream_configurations, which handles retained streams, new streams and the lookup fallbackconnections.py#L1459-L1495:set_selected_streamsRisks
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-emptyselectedFields, 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.9a1a33a(before the mapper guard and append-only fallback) (Faker → dev-null), through the real MCP tool functions:create_connectionsavedincremental_deduped_historywith cursor and primary key.incremental_append,set_connection_selected_streams(drop one stream, add one) kept that stream byte-for-byte identical, and the added stream gotincremental_deduped_history.release-candidate/v1, the same steps reset the retained stream tofull_refresh_overwrite.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.