Skip to content

fix(source-stripe): break same-second event cursor ties in favor of update events - #84355

Open
devin-ai-integration[bot] wants to merge 7 commits into
masterfrom
devin/1786635477-stripe-event-cursor-tiebreak
Open

fix(source-stripe): break same-second event cursor ties in favor of update events#84355
devin-ai-integration[bot] wants to merge 7 commits into
masterfrom
devin/1786635477-stripe-event-cursor-tiebreak

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Requested by Maddie Kashyap (Maddie Kashyap (@maddiekashyapAB)) via /ai-fix on the oncall issue.

Resolves https://github.com/airbytehq/oncall/issues/13191:

What

On incremental syncs, source-stripe reconstructs entity records from /v1/events and derives the record cursor (updated) from the event's created timestamp, which has 1-second granularity (cursor_granularity: PT1S). When a *.created and a *.updated event for the same object fall in the same second, both records carry the same cursor value, so the destination's dedup falls through to its secondary key: ORDER BY <cursor> DESC, _airbyte_extracted_at DESC. Stripe pages /v1/events newest-first, so the older .created payload is emitted last, gets the larger _airbyte_extracted_at, and wins — the destination keeps the creation-time payload and any field first set by the update event (in the reported case, metadata) reads as empty.

A user reported this on subscriptions, with both event payloads for the same subscription in the same second as evidence: the customer.subscription.updated event carried the full metadata, the customer.subscription.created event carried {}, and the empty one landed in the warehouse. The mechanism applies to every events-based stream in this connector, not just subscriptions.

How

Creation events now derive a cursor one second earlier than their event timestamp, so an update event in the same second sorts strictly higher and wins dedup deterministically — independent of emission order and _airbyte_extracted_at.

Applied at the three places that derive a cursor from an event payload:

# definitions.events_based_stream -> data.object.updated  (covers all ~25 events-based entity streams)
value: "{{ (record.get('updated', record.get('created', now_utc().timestamp())) | int) - (1 if record.get('type', '').endswith('.created') else 0) }}"

# streams.invoice_line_items.incremental_stream    -> invoice_updated
# streams.subscription_items.incremental_stream    -> subscription_updated
#   same conditional term, with the event at record['original_record']

The entity_stream / entity_restricted_stream / full_refresh_stream transformations are deliberately untouched: those read real entity objects (no type field, no collision).

Declarative-First Evaluation

Declarative only — a one-line Jinja change to the existing AddFields transformations. No custom Python component was added or needed; components.py still does not exist for this connector.

Review guide

  1. airbyte-integrations/connectors/source-stripe/manifest.yaml — the three cursor expressions.
  2. unit_tests/integration/test_external_account_cards.py — the two new mock-server tests.
  3. metadata.yaml / docs/integrations/sources/stripe.md — version bump and changelog.

Test Coverage

Two new mock-server tests in unit_tests/integration/test_external_account_cards.py (the existing mock harness covers external_account_cards' events path; it has no subscriptions fixture, and the expanded-record streams would need disproportionately larger fixtures):

  • test_given_created_and_updated_events_in_same_second_when_read_then_updated_event_wins_cursor_tie — a .created and an .updated event for the same object id in the same second; asserts the .created-derived record's cursor is exactly one lower. Fails on master (both records get the same cursor), passes with this change.
  • test_given_created_event_at_state_boundary_when_read_then_emit_record_without_regressing_state — guards the one real risk of decrementing a cursor: a .created event exactly at the state high-watermark second is still emitted, and the emitted state does not regress below the incoming state.

Full connector suite: poetry run pytest -x in unit_tests/206 passed.

Not verified: no live sync against a real Stripe account, so this is verified at the record/cursor level rather than end-to-end into a warehouse.

User Impact

Non-breaking. No schema, primary key, cursor field, state format, or spec change, and no records are excluded. The only observable difference is that the synthetic updated value on records derived from *.created events is one second lower than before; going forward, a same-second create/update pair keeps the update payload at the destination.

Rows already stale in a destination are not repaired by this change — they self-heal when Stripe next emits an event for that object, or immediately via a stream refresh (which reads the entity endpoint rather than /v1/events).

Two same-second collisions remain unaddressed, both out of scope here and not fixable by the same trick:

  • two *.updated events for one object in the same second (the older still wins);
  • a *.deleted event tying with an *.updated event (the update still wins, so is_deleted can be lost).

Can this PR be safely reverted and rolled back?

  • YES 💚
  • NO ❌

Devin session


Important

Autopilot Progressive Rollout Enabled

Autopilot progressive rollouts are enabled for one or more connector(s) modified in this PR. Check the box below if you need to bypass normal rollout safety processes and release to all users immediately upon merge:

  • Release immediately (bypasses automatic progressive rollout)

Note:

  • ⚠️ The above bypass option is for emergency/hotfix use only.
  • 🔗 You can monitor or manually advance a rollout at ops.internal.airbyte.ai.

Co-Authored-By: bot_apk <apk@cognition.ai>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@github-actions

Copy link
Copy Markdown
Contributor

👋 Greetings, Airbyte Team Member!

Here are some helpful tips and reminders for your convenience.

💡 Show Tips and Tricks

PR Slash Commands

Airbyte Maintainers (that's you!) can execute the following slash commands on your PR:

  • 🛠️ Quick Fixes
    • /format-fix - Fixes most formatting issues.
    • /bump-version - Bumps connector versions, scraping changelog description from the PR title.
      • Bump types: patch (default), minor, major, major_rc, rc, promote.
      • The rc type is a smart default: applies minor_rc if stable, or bumps the RC number if already RC.
      • The promote type strips the RC suffix to finalize a release.
      • Example: /bump-version type=rc or /bump-version type=minor
    • /bump-progressive-rollout-version - Alias for /bump-version type=rc. Bumps with an RC suffix and enables progressive rollout.
  • ❇️ AI Testing and Review (internal link: AI-SDLC Docs):
    • /ai-prove-fix - Runs prerelease readiness checks, including testing against customer connections.
    • /ai-canary-prerelease - Rolls out prerelease to 5-10 connections for canary testing.
    • /ai-review - AI-powered PR review for connector safety and quality gates.
  • 📝 AI Documentation:
    • /ai-docs-review - AI-powered documentation review for PRs with connector changes.
    • /ai-create-docs-pr - Creates a documentation PR for connector changes, stacked on the current PR.
  • 🚀 Connector Releases:
    • /publish-connectors-prerelease - Publishes pre-release connector builds (tagged as {version}-preview.{git-sha}) for all modified connectors in the PR.
    • /enable-autopilot-rollouts - Enables autopilot progressive rollouts for the modified connector(s) in the PR, remediating "autopilot rollouts not enabled for {connector-name}" auto-merge blockers. Sets defaultRolloutMode: autopilot and enableProgressiveRollout: true, preserving any existing autopilotConfig.
      • Optional args: connector=<CONNECTOR_NAME> (defaults to the modified connectors in the PR), strategy=fast|slow|default (defaults to fast).
      • Example: /enable-autopilot-rollouts or /enable-autopilot-rollouts connector=source-faker strategy=slow
  • ☕️ JVM connectors:
    • /update-connector-cdk-version connector=<CONNECTOR_NAME> - Updates the specified connector to the latest CDK version.
      Example: /update-connector-cdk-version connector=destination-bigquery
  • 🐍 Python connectors:
    • /poe connector source-example lock - Run the Poe lock task on the source-example connector, committing the results back to the branch.
    • /poe source example lock - Alias for /poe connector source-example lock.
    • /poe source example use-cdk-branch my/branch - Pin the source-example CDK reference to the branch name specified.
    • /poe source example use-cdk-latest - Update the source-example CDK dependency to the latest available version.
  • ⚙️ Admin commands:
    • /force-merge reason="<REASON>" - Force merges the PR using admin privileges, bypassing CI checks. Requires a reason.
      Example: /force-merge reason="CI is flaky, tests pass locally"
📚 Show Repo Guidance

Helpful Resources

📝 Edit this welcome message.

Co-Authored-By: bot_apk <apk@cognition.ai>
@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Deploy preview for airbyte-docs ready!

Project:airbyte-docs
Status: ✅  Deploy successful!
Preview URL:https://airbyte-docs-krw3oije5-airbyte-growth.vercel.app
Latest Commit:c22e552

Deployed with vercel-action

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

source-stripe Connector Test Results

211 tests   209 ✅  20m 40s ⏱️
  2 suites    2 💤
  2 files      0 ❌

Results for commit c22e552.

♻️ This comment has been updated with latest results.

@maddiekashyapAB

Maddie Kashyap (maddiekashyapAB) commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

/ai-prove-fix

AI Prove Fix Started

Running readiness checks and testing against customer connections.
View workflow run
🔍 AI Prove Fix session starting... Running readiness checks and testing against customer connections. View playbook

Devin AI session created successfully!

@airbyte-support-bot

Airbyte Support Bot (airbyte-support-bot) commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

🟢 Fix Proven

The 1-second cursor adjustment for *.created events is observable in a live warm incremental read, with no record loss and no state regression. One limitation is stated below.

Connector: source-stripe · PR: #84355 · Pre-release: airbyte/source-stripe:6.0.14-preview.4e0517d (publish run)
Comparison baseline (control): airbyte/source-stripe:6.0.11 — the version named in the originating support report. The only source-stripe change between 6.0.11 and this PR's base (6.0.13) is a declarative-manifest base image bump (7.23.77.24.0), so the baseline still carries the reported behavior and stays within major version 6.
Detailed results (customer data, internal): airbytehq/oncall#13191 — https://github.com/airbytehq/oncall/issues/13191#issuecomment-5283785989

Evidence summary

Attempt 1 — sandbox credentials, cold read (run): SPEC/CHECK/DISCOVER/READ all succeeded on both versions, 1,787 records on each side, no stream lower on target. The events stream read 0 records — with no incoming state the read hits entity endpoints, so the changed expressions never evaluate. Fix not exercised, escalated to a warm run. The comparison flagged 3 streams (bank_accounts, external_account_bank_accounts, invoice_items) with equal counts but differing records; a primary-key diff showed the only differing field is updated, always later in the target run — shared sandbox data mutating between the two sequential reads, not a target-side regression, and none of those streams' cursor expressions are touched by this PR.

Attempt 2 — warm/stateful read against an eligible existing connection (run, comparison mode, all streams, real incoming state): SPEC/CHECK/DISCOVER/READ succeeded on both versions (both processes exited 0). Incoming state confirmed the event-based path executed. Records: 23,668 control vs 23,713 target (+45); no stream lower on target, the extras being streams whose upstream data changed between the two sequential reads.

The designed behavior shows up directly in the cursor sequences for the three affected streams:

subscriptions        control: …9630, …9563, …9559, …9558
                     target:  …9630, …9563, …9559, …9557
subscription_items   control: …9630, …9563, …9559, …9558
                     target:  …9630, …9563, …9559, …9557
invoice_line_items   control: …9629, …9563, …9561, …9560, …9559
                     target:  …9629, …9563, …9561, …9560, …9558

In each stream exactly one cursor is 1 second lower on the target and every other cursor is byte-identical: the creation-event record moves earlier, so a same-second update payload can no longer tie with it and is the one that wins destination dedup.

State safety: final cursors are identical on both versions for all three affected streams, and across every stream the target never ended more than 1 second behind control (a single stream by exactly 1s). Worst case on upgrade is a 1-second re-read overlap; nothing is skipped.

Limitation

The regression harness flattens records, so the Stripe event envelope (and its type) is absent from the artifacts and no /v1/events request URL is logged. Attributing the shifted cursor specifically to *.created events therefore rests on the manifest diff plus this PR's integration tests, which assert cursor - 1 for *.created and an unchanged cursor for *.updated. No same-second create/update pair for a single object occurred inside the tested window, so the dedup outcome itself was not directly observed — it follows arithmetically from the observed 1-second separation.

Pre-flight checklist

Check Result
Breaking-change label / title / body indicators None
Schema changes (fields added/removed/renamed) None
Primary key changes None
Cursor field change / state migration needed None — field name and state format unchanged
Spec / config changes None
Streams removed None
Data scope reduced (records excluded) None — only the derived cursor value changes
Progressive rollout Enabled (autopilot, fast)
Reversible / downgrade-safe Yes — revert or pin to 6.0.13, no state incompatibility
Malicious code, obfuscation, credential/network abuse None found

Assessment: non-breaking and reversible. The one behavioral caveat — cursor values for *.created-derived records are 1s lower, so an upgraded sync may re-read at most 1 extra second — is confirmed harmless by the state comparison above.

Next steps

Ready to merge from a validation standpoint; the existing progressive rollout config (autopilot, fast) can carry 6.0.14 out. No live version pin was applied and no customer sync was triggered — the regression runs only read connection config/catalog/state.

Evidence plan used (posted before running the tests)

Proving evidence: (1) SPEC/CHECK/DISCOVER identical between target and control; (2) READ succeeds on both with no stream losing records on target; (3) on event-derived incremental reads, *.created-derived records carry a cursor exactly 1s lower on target while *.updated-derived records are identical; (4) where a same-second create/update pair exists, the update payload sorts last.

Disproving evidence: (1) the cursor tie persists on target; (2) target fails on a read path that succeeds on control; (3) target emits fewer records, or unexpected schema/catalog/state differences appear.

Anticipated limitation (confirmed in attempt 1): the events-based read path is only exercised on a warm, stateful incremental read; a cold read hits entity endpoints and leaves the changed expressions unevaluated, which is why the run was escalated to a stateful comparison against an existing connection.


Devin session

@airbyte-support-bot Airbyte Support Bot (airbyte-support-bot) added the hyd-prove Hydra: ai-prove-fix stage has run label Aug 13, 2026
@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Pre-release Connector Publish Started

Publishing pre-release build for connector source-stripe.
PR: #84355

Pre-release versions will be tagged as {version}-preview.4e0517d
and are available for version pinning via the scoped_configuration API.

View workflow run
Pre-release Publish: SUCCESS

Docker image (pre-release):
airbyte/source-stripe:6.0.14-preview.4e0517d

Docker Hub: https://hub.docker.com/layers/airbyte/source-stripe/6.0.14-preview.4e0517d

Registry JSON:

@maddiekashyapAB
Maddie Kashyap (maddiekashyapAB) marked this pull request as ready for review August 13, 2026 17:27
@airbyte-support-bot

Copy link
Copy Markdown
Contributor

↪️ Triggering /ai-review per Hands-Free AI Triage Project triage next step.

Reason: /ai-prove-fix returned 🟢 Fix Proven on this branch and there is no AI review marker yet — review is the next pipeline stage.

Devin session

@octavia-bot

octavia-bot Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

AI PR Review starting...

Reviewing PR for connector safety and quality.
View playbook

Devin AI session created successfully!

@airbyte-support-bot

Airbyte Support Bot (airbyte-support-bot) commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

🛡️ AI PR Review Report

🟢 Review Action: APPROVED

All 12 gates passed.

⚠️ Risk Level: 4/5

The cursor value emitted for *.created-derived records changes for every events-based stream (~25), a user-visible dedup/ordering change — deliberate and the point of the fix, but worth human awareness.


📋 PR Details

Connector(s): source-stripe
PR: #84355
HEAD SHA: e5b52530e12dea507b1b3e4ab4f4a4b2385c8b48
Session: https://app.devin.ai/sessions/7ac76ae19ef544bdbd02b5869dc05db1

🔍 Gate Evaluation Details

Gate-by-Gate Analysis

Gate Status Enforced? Details
PR Hygiene PASS Yes Description 5066 raw chars with What/How/Test Coverage/User Impact filled in; changelog row added to docs/integrations/sources/stripe.md for 6.0.14; no unresolved human review comments (0 inline comments; lazebnyi APPROVED at this SHA).
Code Hygiene PASS WARNING Source change (manifest.yaml) is accompanied by test changes in unit_tests/integration/test_external_account_cards.py; coverage evidence found.
Test Coverage PASS Yes Behavioral change (title fix(...), links airbytehq/oncall#13191) ships two new mock-server tests with real assertions on cursor values and state non-regression.
Code Security PASS Yes No changed file matches the auth/credential/secret path patterns; manifest.yaml hunks contain no authenticator/token/key keywords; the only metadata.yaml hunk is dockerImageTag: 6.0.13 → 6.0.14 (not dockerRepository, allowedHosts, or connectorBuildOptions).
Per-Record Performance PASS WARNING The added per-record work is a single record.get('type','').endswith('.created') string check inside existing AddFields transformations — negligible, no new objects, allocations, or I/O per record.
Breaking Dependencies PASS WARNING No dependency or build files touched (pyproject.toml, lockfile, gradle all unchanged); only the connector version tag moved.
Backwards Compatibility PASS Yes (enforced) No spec, schema, stream, primary-key, or cursor-field change (no spec*.json, schemas/*.json, or code type mapping in the diff), and no data-scope reduction — records emitted are identical in set and shape. See the cursor-value analysis below for why this is not a re-keying breaking change.
Forwards Compatibility PASS Warning (elevates Risk Level) Cursor semantics change but state format is unchanged (plain int epoch seconds), so rollback to 6.0.13 reads and writes the same state shape; test_given_created_event_at_state_boundary_when_read_then_emit_record_without_regressing_state proves a decremented cursor at the state boundary does not regress emitted state. No partition-router or partition_field change.
Behavioral Changes PASS Warning (elevates Risk Level) No operational keywords in functional hunks: no rate-limit, retry/backoff, timeout, or error_handler changes. The only limit match is with_limit(100) inside a new test fixture, which is not an operational change.
Out-of-Scope Changes PASS Skip All 5 changed files are in scope: airbyte-integrations/connectors/source-stripe/** (3) and docs/integrations/sources/stripe.md (1), plus the connector's AGENTS.md.
CI Checks PASS Yes Core checks green: Test source-stripe Connector ✅, Lint source-stripe Connector ✅, Connector CI Checks Summary ✅, Format Check ✅, Build and Verify Artifacts (source-stripe) ✅, Check Changelog Updated ✅; connector test results 209 passed / 2 skipped / 0 failed. No core check failed, cancelled, or pending.
Live / E2E Tests PASS Yes Validation is required (bug fix + sync-behavior change: incremental_sync cursor derivation). /ai-prove-fix posted 🟢 Fix Proven on this branch — the 1-second adjustment was observed in a live warm incremental read against pre-release airbyte/source-stripe:6.0.14-preview.4e0517d with no record loss and no state regression.

Cursor-value analysis (Backwards Compatibility)

The change alters the value written to the cursor field updated (and invoice_updated / subscription_updated) for records derived from *.created events, subtracting one second. The playbook treats a PK/cursor value change as breaking when it re-keys records so existing destination rows no longer match. That does not apply here:

  • Primary keys are unchanged (id and friends are untouched) — existing destination rows still match on the same key, so dedup/upsert targets the same rows.
  • The cursor field name, type, and state format are unchanged; the cursor only participates as the dedup ordering tiebreaker, which is exactly the bug being fixed.
  • No user action is required after upgrade (no re-sync, reconfiguration, or schema refresh), and no records are dropped from scope.

Worst case is that a *.created event landing exactly at the state high-watermark second is re-emitted once — a duplicate at append destinations, not data loss — and the new boundary test covers that path. So: PASS, with the user-visible ordering change reflected in Risk Level 4 rather than a breaking-change requirement.

Files that triggered gate evaluation

  • airbyte-integrations/connectors/source-stripe/manifest.yaml — three cursor expressions (definitions.events_based_streamdata.object.updated, invoice_line_itemsinvoice_updated, subscription_itemssubscription_updated). Drove Backwards/Forwards Compatibility and Live / E2E.
  • airbyte-integrations/connectors/source-stripe/unit_tests/integration/test_external_account_cards.py — two new def test_... functions with new assertions. Satisfied Test Coverage and Code Hygiene.
  • airbyte-integrations/connectors/source-stripe/metadata.yamldockerImageTag 6.0.13 → 6.0.14 only; no releases.breakingChanges entry, consistent with the non-breaking classification.
  • docs/integrations/sources/stripe.md — 6.0.14 changelog row. Satisfied PR Hygiene changelog check.
  • airbyte-integrations/connectors/source-stripe/AGENTS.md — documents the new same-second tie-break behavior for future maintainers.
📚 Evidence Consulted

Evidence

  • Changed files: 5 files (+71 / −4)
  • CI checks: 47 check-runs on e5b5253; core build/lint/test all success; source-stripe Pre-Release Checks, source-stripe Progressive Rollout Gate, Connector Active Progressive Rollout Checks Summary, Validate PR Title all success (and excluded from the CI Checks gate by policy); CodeQL neutral, JVM/Bulk-CDK jobs skipped (no JVM connector modified)
  • PR labels: connectors/source/stripe, hyd-fix, hyd-prove, hyd-review (applied by this run; also applied to the originating issue airbytehq/oncall#13191). No validation-override labels present or needed.
  • PR description: present (5066 chars)
  • /ai-prove-fix: 🟢 Fix Proven — fix(source-stripe): break same-second event cursor ties in favor of update events #84355 (comment) (detailed customer-data results in airbytehq/oncall#13191)
  • Existing bot reviews: none for this SHA (human APPROVE from lazebnyi at this SHA)

Devin session

@airbyte-support-bot

Copy link
Copy Markdown
Contributor

↪️ Triggering /ai-ready per Hands-Free AI Triage Project triage next step.

Reason: the /ai-review dispatched earlier today returned APPROVE at the current head e5b52530; merge state is CLEAN, GitHub review decision is APPROVED, no commits landed after the approval, no check is failing or pending, and no /ai-ready has run for this head — readiness is the next stage.


Devin session

@octavia-bot octavia-bot Bot added the hyd-ready Hydra: ready for human review or merge label Aug 14, 2026
@octavia-bot-hoard

octavia-bot-hoard Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Auto-merge evaluation: FAIL

Preconditions (all must pass)

Status Check Reasoning
No Breaking Changes Patch bump 6.0.13 -> 6.0.14 in metadata.yaml (no major/minor bump, no breakingChanges entry). Change is a Jinja expression tweak that decrements the derived cursor by 1s for *.created events. No schema, primary key, cursor field, state format, or spec changes; no streams or config options removed or renamed; no records excluded. Nothing requires downstream consumers to change code or config.
Ai Review Passed Comment id 5292951049 by airbyte-support-bot (2026-08-14) contains the marker '' with all 12 gates PASS, and that SHA matches the current PR head.
Airbyte Support Bot Assigned Airbyte Support Bot assignment confirms automated merge eligibility.
No Destination Changes No destination-related changes detected.

Change scope (at least one must pass)

❌ No matching change scope detected.

Devin session | Workflow run

@airbyte-support-bot

Copy link
Copy Markdown
Contributor

↪️ Triggering /ai-review per Hands-Free AI Triage Project triage next step.

Reason: the APPROVE marker is at e5b52530 but the head has since moved to 1edcf522, so the approval no longer describes this branch and cannot feed /ai-ready — the previous readiness run evaluated the old head. The connector test that was in flight has now finished, the PR is CLEAN with no failing or pending checks and a human APPROVED decision, so review is re-run at the current head.


Devin session

@octavia-bot

octavia-bot Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

AI PR Review starting...

Reviewing PR for connector safety and quality.
View playbook

Devin AI session created successfully!

@airbyte-support-bot

Airbyte Support Bot (airbyte-support-bot) commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

🛡️ AI PR Review Report

🟢 Review Action: APPROVED

All 12 gates passed.

⚠️ Risk Level: 4/5

The cursor value emitted for *.created-derived records changes for every events-based stream, a user-visible dedup/ordering change — deliberate and the point of the fix, but worth human awareness.


📋 PR Details

Connector(s): source-stripe
PR: #84355
HEAD SHA: 1edcf5228b4ad2a5f137a1c9e53794fcc24bbec1
Session: https://app.devin.ai/sessions/bac48be8158841dba7e157231e06556f

Re-run of /ai-review: the prior APPROVE marker was at e5b52530; the head has since advanced through two master merge commits (e5b52530, 1edcf522). git diff 4e0517d..1edcf522 -- airbyte-integrations/connectors/source-stripe/ is empty, so no connector content changed between the reviewed/validated commit and the current head.

🔍 Gate Evaluation Details

Gate-by-Gate Analysis

Gate Status Enforced? Details
PR Hygiene PASS Yes Description ~5.1k raw chars with What/How/Test Coverage/User Impact filled in; changelog row 6.0.14 added in docs/integrations/sources/stripe.md; no unresolved human review comments (one human APPROVED review by lazebnyi at the current head, zero inline comments).
Code Hygiene PASS WARNING Source change (manifest.yaml) accompanied by test change (unit_tests/integration/test_external_account_cards.py, +64 lines). Coverage evidence: Found.
Test Coverage PASS Yes Behavioral change (title fix(...), links airbytehq/oncall#13191). Two new def test_... functions with new assertions on cursor values and state non-regression.
Code Security PASS Yes No changed path matches auth/oauth/token/credential/secret/encrypt patterns. manifest.yaml diff hunks contain no authenticator/api_token/client_secret-class keywords; metadata.yaml diff is only dockerImageTag: 6.0.13 → 6.0.14 (no allowedHosts, connectorBuildOptions, or dockerRepository line changed).
Per-Record Performance PASS WARNING The change adds one str.endswith test and an integer subtraction inside an existing AddFields Jinja expression that already ran per record. No new object creation, network call, or loop.
Breaking Dependencies PASS WARNING No pyproject.toml, poetry.lock, build.gradle, or base-image change in the diff.
Backwards Compatibility PASS Yes (enforced) No spec*.json/spec*.yaml, schemas/*.json, stream, primary-key, or cursor-field change; no format/type change on any existing field. The cursor value on *.created-derived records shifts 1s earlier, which was evaluated against the PK/cursor re-keying rule: the dedup key (id) is unchanged, so existing destination rows still match, and the cursor is used only for ordering/tie-breaking. metadata.yaml is a patch bump (6.0.13 → 6.0.14) with no breaking-change semantics requiring a releases.breakingChanges entry.
Forwards Compatibility PASS Warning (elevates Risk Level) Diff touches a cursor-deriving AddFields transformation, so the gate's keywords match. State format and partition-router shape are unchanged, so state written by either version is readable by the other; test_given_created_event_at_state_boundary_when_read_then_emit_record_without_regressing_state proves a .created event at the state high-watermark is still emitted and the emitted state does not regress. Rollback re-emits the same records with a 1s-higher cursor — no state incompatibility.
Behavioral Changes PASS Yes → Warning (elevates Risk Level) No rate-limit, retry, backoff, timeout, error-handler, or resource-config change in the diff hunks. The only match against the keyword list is with_limit(100) in the new mock-server test request builder (test-only mock setup, not connector configuration).
Out-of-Scope Changes PASS Skip All 5 changed files are in scope: 4 under airbyte-integrations/connectors/source-stripe/, 1 under docs/integrations/sources/. No platform, CDK-core, CI-workflow, or infrastructure files.
CI Checks PASS Yes 39 passed / 0 failed / 0 pending at 1edcf522, including Test source-stripe Connector, Lint source-stripe Connector, Build and Verify Artifacts (source-stripe), Connector CI Checks Summary, Check Changelog Updated, Format Check. source-stripe connector test results: 211 tests, 209 ✅, 0 ❌.
Live / E2E Tests PASS Yes Validation is required (bug fix + sync-behavior change: incremental_sync/cursor/transformations). /ai-prove-fix posted 🟢 Fix Proven (comment 5283482563) on pre-release airbyte/source-stripe:6.0.14-preview.4e0517d, from a warm/stateful comparison read against an eligible existing connection with real incoming state: the 1-second adjustment is observable, with no record loss and no state regression. The connector directory is byte-identical between 4e0517d and the current head, so that conclusion still describes this branch.

Files changed (5): source-stripe/manifest.yaml (3 cursor expressions), source-stripe/metadata.yaml (version bump), source-stripe/AGENTS.md (behavior note), source-stripe/unit_tests/integration/test_external_account_cards.py (2 new tests), docs/integrations/sources/stripe.md (changelog row).

📚 Evidence Consulted

Evidence

  • Changed files: 5 files (git diff --merge-base origin/master)
  • CI checks: 39 passed, 0 failed, 0 pending, 10 skipped at 1edcf522
  • PR labels: connectors/source/stripe, hyd-review, hyd-fix, hyd-prove, hyd-ready — no validation-override labels relied on
  • PR description: present (~5.1k chars)
  • Existing bot reviews: prior APPROVE marker at e5b52530 (comment 5292951049); human APPROVED review by lazebnyi at the current head
  • /ai-prove-fix conclusion: 🟢 Fix Proven (comment 5283482563), detailed results in airbytehq/oncall#13191

@airbyte-support-bot

Copy link
Copy Markdown
Contributor

↪️ Triggering /ai-ready per Hands-Free AI Triage Project triage next step.

Reason: the re-run /ai-review returned APPROVE with all 12 gates PASS at the current head 1edcf522 (the connector directory is byte-identical to the prove-fix'n commit 4e0517d, and there is a human APPROVED review at this head). The PR is CLEAN, 39 checks pass with none failing or pending, and the earlier /ai-ready evaluated the now-stale head e5b52530.


Devin session

@octavia-bot-hoard

octavia-bot-hoard Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Auto-merge evaluation: FAIL

Preconditions (all must pass)

Status Check Reasoning
No Breaking Changes Patch version bump 6.0.13 -> 6.0.14 in metadata.yaml, no breakingChanges entry. The change is a Jinja expression tweak in manifest.yaml decrementing the derived cursor by 1s for *.created events. No schema, primary key, cursor field, state format, or spec changes; no streams or config options removed or renamed; no records excluded. Nothing requires downstream consumers to change code or config.
Ai Review Passed Comment id 5295002579 by airbyte-support-bot (2026-08-14T15:19:39Z) contains the marker '' with all 12 gates PASS, matching the current PR head 1edcf52.
Airbyte Support Bot Assigned Airbyte Support Bot assignment confirms automated merge eligibility.
No Destination Changes No destination-related changes detected.

Change scope (at least one must pass)

❌ No matching change scope detected.

Devin session | Workflow run

@airbyte-support-bot

Copy link
Copy Markdown
Contributor

💬 Readiness outcome for the record, per Hands-Free AI Triage Project: with the review refreshed at the current head, all four /ai-ready preconditions now pass — no breaking changes, AI review APPROVE at 1edcf522, support bot assigned, no destination changes — but the evaluation still returns FAIL on No matching change scope detected, so auto-merge was not enabled. Every automated stage on this PR is complete (/ai-prove-fix 🟢 Fix Proven, /ai-review APPROVE with 12/12 gates, CLEAN, human APPROVED, 39 checks green, none failing or pending); the only remaining step is a human merge. Escalated to the API connectors oncall.


Devin session

@airbyte-support-bot

Copy link
Copy Markdown
Contributor

↪️ Triggering /ai-review per Hands-Free AI Triage Project triage next step. Reason: the latest AI review marker (APPROVE) was recorded for head 1edcf522, but new commits landed afterwards and the current HEAD is 3a7b8322. A refreshed verdict on the exact current HEAD is required before /ai-ready can be re-evaluated. CI is green and the branch is clean with a human approval in place.

@octavia-bot

octavia-bot Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

AI PR Review starting...

Reviewing PR for connector safety and quality.
View playbook

Devin AI session created successfully!

@airbyte-support-bot

Airbyte Support Bot (airbyte-support-bot) commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

🛡️ AI PR Review Report

🟢 Review Action: APPROVED

All 12 gates passed.

⚠️ Risk Level: 4/5

The cursor value emitted for *.created-derived records changes for every events-based stream — a deliberate, user-visible dedup/ordering change, worth human awareness.


📋 PR Details

Connector(s): source-stripe
PR: #84355
HEAD SHA: 3a7b8322f14a861f2392f634dda8bb98501e7af3
Session: https://app.devin.ai/sessions/9be2bdf9c9a54221897394d64efe3730

Re-run of /ai-review: prior APPROVE markers were recorded at e5b52530 and 1edcf522; the head has since advanced to 3a7b8322, another master merge commit. git diff 1edcf522..3a7b8322 touches only .github/workflows/generate-connector-registries.yml and docs/integrations/sources/klaviyo.md (both inbound from master) — no source-stripe content changed since the reviewed and /ai-prove-fix-validated commit 4e0517d.

🔍 Gate Evaluation Details

Gate-by-Gate Analysis

Gate Status Enforced? Details
PR Hygiene PASS Yes Description is 5712 raw chars with What/How/Test Coverage/User Impact filled in; changelog row for 6.0.14 added to docs/integrations/sources/stripe.md; no unresolved human review comments (0 inline comments; lazebnyi APPROVED at the current head).
Code Hygiene PASS WARNING Source (manifest.yaml) changed and tests changed in the same PR (unit_tests/integration/test_external_account_cards.py, +64 lines) — coverage evidence Found.
Test Coverage PASS Yes Behavioral change (title fix(...), linked oncall issue). Two new mock-server tests with real assertions: test_given_created_and_updated_events_in_same_second_when_read_then_updated_event_wins_cursor_tie and test_given_created_event_at_state_boundary_when_read_then_emit_record_without_regressing_state.
Code Security PASS Yes No changed file matches auth/credential/secret path patterns. manifest.yaml diff hunks contain no security keywords (no authenticator, *_token, client_id/secret, api_key); the metadata.yaml hunk is only dockerImageTag: 6.0.13 → 6.0.14 (not dockerRepository/allowedHosts/connectorBuildOptions).
Per-Record Performance PASS WARNING The three changed expressions add one constant-time str.endswith per record inside existing AddFields transformations — no new allocation, no per-record I/O, no added complexity class.
Breaking Dependencies PASS WARNING No dependency files changed (pyproject.toml, poetry.lock, gradle files untouched); base image unchanged in this PR.
Backwards Compatibility PASS Yes (enforced) No spec file changed (no spec*.json/spec*.yaml, no spec section in manifest.yaml), so required is unchanged; no stream added/removed/renamed, no schema property or type/format change, no primary-key change (PK remains id), no state-format change, and no stream loses records. The cursor field (updated) is unchanged; the derived cursor value for *.created-sourced records is 1s lower. This is not the re-keying case the gate guards: destination dedup keys on the unchanged PK, so no existing row is re-keyed, and a 1s-lower cursor can at worst re-read one extra second (dedup'd), never skip records — /ai-prove-fix confirmed no record loss and no state regression on a warm live read. metadata.yaml is a patch bump with no breaking-change semantics requiring a releases.breakingChanges entry.
Forwards Compatibility PASS Warning (elevates Risk Level) Cursor-value expressions changed, so the gate's keywords are present — but state format, cursor field, and partition routing are all untouched (no partition_router/parent_stream_configs/state_migrations change), so rollback simply restores the prior +1s value with the same state shape. test_given_created_event_at_state_boundary_when_read_then_emit_record_without_regressing_state proves a .created event at the state high-watermark is still emitted and emitted state does not regress.
Behavioral Changes PASS Yes* (warning) Keyword scan over all +/- lines in the diff found no operational keywords (rate_limit, retry, backoff, Retry-After, timeout, sleep, page_size, error_handler, response_filters, http_codes, memory_*). The dedup-ordering effect of the change is documented in the PR description, the changelog row, and the connector's AGENTS.md.
Out-of-Scope Changes PASS Skip All 5 changed files are in scope: 4 under airbyte-integrations/connectors/source-stripe/ and 1 under docs/integrations/sources/.
CI Checks PASS Yes All core check-runs on 3a7b8322 are green, including Test source-stripe Connector, Lint source-stripe Connector, Build and Verify Artifacts (source-stripe), Connector CI Checks Summary, Format Check, Check Changelog Updated, and the docs checks. 0 failing, 0 pending.
Live / E2E Tests PASS Yes Validation is required (bug fix + sync-behavior change). /ai-prove-fix posted 🟢 Fix Proven (comment 5283482563) at 4e0517d — pre-release airbyte/source-stripe:6.0.14-preview.4e0517d, warm/stateful comparison read against an eligible existing connection vs. control 6.0.11, with the 1s cursor adjustment observable, no record loss and no state regression. The connector directory is byte-identical between 4e0517d and the current head, so that conclusion still describes this HEAD.

Changed files driving the evaluation

  • airbyte-integrations/connectors/source-stripe/manifest.yaml — three cursor expressions (definitions.events_based_streamdata.object.updated; invoice_line_itemsinvoice_updated; subscription_itemssubscription_updated) each gain - (1 if <event>.get('type','').endswith('.created') else 0).
  • airbyte-integrations/connectors/source-stripe/unit_tests/integration/test_external_account_cards.py — two new HttpMocker tests.
  • airbyte-integrations/connectors/source-stripe/metadata.yaml6.0.13 → 6.0.14.
  • airbyte-integrations/connectors/source-stripe/AGENTS.md — one documentation line recording the tie-break rule.
  • docs/integrations/sources/stripe.md6.0.14 changelog row linking this PR.
📚 Evidence Consulted

Evidence

  • Changed files: 5 files (git diff --merge-base origin/master), +71 / -4.
  • CI checks: 49 check-runs on 3a7b8322 — 38 success, 10 skipped, 1 neutral (CodeQL), 0 failed, 0 pending. Core connector checks (Test source-stripe Connector, Lint source-stripe Connector, Build and Verify Artifacts (source-stripe)) all success; source-stripe Pre-Release Checks and source-stripe Progressive Rollout Gate excluded from this gate by design and also green.
  • PR labels: connectors/source/stripe, hyd-review, hyd-fix, hyd-prove, hyd-ready. No validation-override labels relied on.
  • PR description: present (5712 chars).
  • Reviews: lazebnyi APPROVED at 3a7b8322. Prior bot markers: APPROVE at e5b52530 and at 1edcf522; no REQUEST CHANGES review has ever been submitted on this PR.
  • /ai-prove-fix: 🟢 Fix Proven (comment 5283482563), detailed customer-data results at airbytehq/oncall#13191.
  • Hydra stage label hyd-review applied to this PR and to the originating issue airbytehq/oncall#13191.

@airbyte-support-bot

Copy link
Copy Markdown
Contributor

↪️ Triggering /ai-ready per Hands-Free AI Triage Project triage next step. Reason: the refreshed /ai-review returned APPROVE for the exact current HEAD 3a7b8322, which was the only missing gate. The branch is clean, CI is green and a human approval is already in place, and no readiness evaluation has run against this HEAD.


Devin session

@octavia-bot-hoard

octavia-bot-hoard Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Auto-merge evaluation: FAIL

Preconditions (all must pass)

Status Check Reasoning
No Breaking Changes Patch version bump 6.0.13 -> 6.0.14 in metadata.yaml with no breakingChanges entry. The change is a Jinja expression tweak in manifest.yaml that decrements the derived cursor by 1s for *.created events. No schema, primary key, cursor field, state format, or spec changes; no streams or config options removed or renamed; no records excluded. Nothing requires downstream consumers to change code or config.
Ai Review Passed Comment id 5315549969 by airbyte-support-bot (2026-08-17T11:40:37Z) contains the marker '' with all 12 gates PASS, matching the current PR head 3a7b832.
Airbyte Support Bot Assigned Airbyte Support Bot assignment confirms automated merge eligibility.
No Destination Changes No destination-related changes detected.

Change scope (at least one must pass)

❌ No matching change scope detected.

Devin session | Workflow run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

connectors/source/stripe hyd-fix Hydra: ai-fix stage has run hyd-prove Hydra: ai-prove-fix stage has run hyd-ready Hydra: ready for human review or merge hyd-review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants