fix(source-netsuite): use explicit UTC datetime bounds in incremental stream slices#79654
Conversation
… stream slices stream_slices() called .date() on the cursor, truncating it to date-only, then formatted slice bounds with date-only format strings. NetSuite interprets bare dates in the account's configured timezone, creating a dead zone up to 12 hours wide where records are permanently skipped. Fix: preserve datetime precision by replacing .date() with .replace(hour=0, minute=0, second=0) and adding the ISO 8601 datetime format as the first entry in NETSUITE_INPUT_DATE_FORMATS. The fallback mechanism still cycles through date-only formats for accounts that reject datetime in queries. Co-Authored-By: bot_apk <apk@cognition.ai>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
Co-Authored-By: bot_apk <apk@cognition.ai>
👋 Greetings, Airbyte Team Member!Here are some helpful tips and reminders for your convenience. 💡 Show Tips and TricksPR Slash CommandsAirbyte Maintainers (that's you!) can execute the following slash commands on your PR:
📚 Show Repo GuidanceHelpful Resources
|
Co-Authored-By: bot_apk <apk@cognition.ai>
|
Deploy preview for airbyte-docs ready!
Deployed with vercel-action |
|
|
Thanks for tackling this — the approach of prepending the ISO datetime format One gap worth flagging: we tested The N/query module (which backs the For accounts that reject ISO datetime, A robust complement would be a small lookback window - subtracting 1 day from The proper long-term fix would be migrating to the SuiteQL endpoint |
|
↪️ Triggering Reason: Draft PR with CI passing, fixes netsuite incremental stream datetime bounds.\n\n- https://github.com/airbytehq/oncall/issues/12846 |
|
🟢 Fix Proven —
|
| Step | Target (v0.1.28) | Control (v0.1.27) | Result |
|---|---|---|---|
| SPEC | success | success | ✅ No regression |
| CHECK | success | success | ✅ No regression |
| DISCOVER | success | success | ✅ No regression |
| READ | 312 records, 74 LOG | 312 records, 57 LOG | ✅ No regression |
Key finding: Target emits 17 additional LOG messages vs control. This is consistent with the date format fallback mechanism being triggered — the new ISO 8601 format is attempted first, and when rejected, the connector gracefully retries with the next format. This proves the new code path is active and the safety net works.
Stream-level record counts are identical:
salesorder: 1, purchaseorder: 3, workorder: 6, customer: 141, contact: 160, itemfulfillment: 1
Pre-release Publish
- Image:
airbyte/source-netsuite:0.1.28-preview.fd40857 - Workflow run
Full details with connection IDs posted to linked oncall issue.
|
|
↪️ Triggering Reason: |
Reviewing PR for connector safety and quality.
|
🛡️ AI PR Review Report🔴 Review Action: REQUEST CHANGES
🔶 Risk Level: 3/5Logic change to incremental 🔧 Remediation RequiredPR Hygiene — Unresolved peer feedback:
CI Checks — Pending:
Live / E2E Tests — No validation evidence:
📋 PR DetailsConnector(s): 🔍 Gate Evaluation DetailsGate-by-Gate Analysis
PR HygienePR Description Check:
Docs Changelog Check:
Peer Feedback Check:
Code Hygiene
Test Coverage
Code Security
Per-Record Performance
Breaking Dependencies
Backwards Compatibility
Forwards Compatibility
Behavioral Changes
Out-of-Scope Changes
CI Checks
Live / E2E Tests
📚 Evidence ConsultedEvidence
❓ How to RespondProviding Context or JustificationYou can add explanations that the bot will see on the next review: Option 1: PR Description (recommended) ## AI PR Review Justification
### {Gate Name}
[Your explanation here]Option 2: PR Comment After adding your response, re-run Note: Justifications provide context for the bot to evaluate. For the Live / E2E Tests gate, a sufficient justification with verifiable evidence can lead to PASS. For the PR Hygiene peer feedback check, replying to the unresolved comment is required. |
What
Resolves https://github.com/airbytehq/oncall/issues/12846:
Related: #79653
Incremental streams permanently lose records whose
lastModifiedDatefalls between the sync run time and midnight in the NetSuite account's configured timezone. The dead zone can be up to 12 hours wide.How
In
IncrementalNetsuiteStream.stream_slices(), the cursor datetime was truncated via.date()and formatted using date-only strings (e.g."03/15/2026"). NetSuite interprets bare dates in the account's timezone, soAFTER "03/15/2026"on a PDT account resolves to2026-03-15T07:00:00Z— not UTC midnight.Fix:
.date()with.replace(hour=0, minute=0, second=0)to preserve datetime precision%Y-%m-%dT%H:%M:%SZ) as the first entry inNETSUITE_INPUT_DATE_FORMATSdate.today()withdatetime.utcnow()for consistent datetime comparisonsSlice bounds now produce explicit UTC datetimes like
"2026-03-15T00:00:00Z", unambiguous regardless of account timezone. The existing date-format fallback mechanism (should_retry+DateFormatExeption) still cycles through date-only formats for accounts that reject datetime in theqparameter.Declarative-First Evaluation
N/A — this is a Python CDK-based connector (
cdk:pythontag), not declarative/manifest-only.Test Coverage
Added 9 unit tests covering:
request_paramsquery string formatReview guide
source_netsuite/constraints.py— datetime format prepended toNETSUITE_INPUT_DATE_FORMATSsource_netsuite/streams.py—stream_slices()preserves datetime, usesdatetime.utcnow()unit_tests/test_streams.py— new test suiteUser Impact
Records modified between sync time and account-local midnight are no longer silently dropped. All incremental streams now query using explicit UTC datetime bounds.
Can this PR be safely reverted and rolled back?
Link to Devin session: https://app.devin.ai/sessions/da55ff9ea025476da4e7256d413b076d