Skip to content

feat: let wrapper SDKs run their own beforeSend on the fully built event - #904

Open
turnipdabeets wants to merge 6 commits into
feat/v4-capture-v1from
feat/v4-wrapper-build-send
Open

turnipdabeets wants to merge 6 commits into
feat/v4-capture-v1from
feat/v4-wrapper-build-send

Conversation

@turnipdabeets

@turnipdabeets turnipdabeets commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

💡 Motivation and Context

posthog-flutter runs its Dart beforeSend before handing the event to this SDK. So on Android the Dart hook only sees the call's own properties: no SDK or registered properties, session, screen, uuid or timestamp. Anything it changes is overwritten when this SDK fills properties afterwards. Flutter desktop and native Android already run the hook on the full event.

This PR adds two internal methods so a wrapper can do the same on Android:

  1. buildEventForWrapper(...) builds the event the way capture/captureAi would: same checks, same property fill, a new uuid and timestamp. It doesn't run beforeSend and doesn't queue the event.
  2. The wrapper runs its own hook on that event.
  3. sendBuiltEventForWrapper(event, ai) runs the native beforeSend chain and queues the event on the analytics or AI lane, keeping its uuid and timestamp. It doesn't fill properties again.

capture now runs through the same pieces (prepare → beforeSend → enqueue). It behaves the same: the existing suite passes unchanged.

Both methods are @PostHogInternal and @suppressed in KDoc, with no-op defaults on PostHogInterface. To keep them out of the public API, the first commit adds @PostHogInternal to the binary-compatibility validator's nonPublicMarkers. That also drops every existing @PostHogInternal declaration from the .api dumps (about 900 lines). Those declarations are still public on the JVM, but apiCheck no longer guards them. That commit stands alone so it's easy to drop or discuss separately.

Notes:

  • Scope: capture, captureAi, screen and exceptions sent as $exception events. Building changes no SDK state, so a wrapper can drop the event: sendBuiltEventForWrapper caches a $screen event's $screen_name and updates the person properties used for flags, as screen() and capture do.
  • identify, alias and group aren't covered. They change state (distinct id, groups, flag reloads) around their capture call, so splitting them needs its own design.
  • Replay debug window: the build adds only the required debug keys. sendBuiltEventForWrapper claims the full bundle and starts the window when the event is queued, as capture does.
  • Surveys and replay event triggers see the event passed to sendBuiltEventForWrapper, which is after the wrapper's hook.

💚 How did you test it?

  • New PostHogWrapperEventTest:
    • build fills properties without running beforeSend or queueing
    • send keeps uuid and timestamp, doesn't fill again, and runs beforeSend
    • AI lane endpoint
    • null when beforeSend drops the event, when opted out, or on an opt-out between build and send
    • null when this instance didn't build the event, when setup() or close() ran since the build, or when it was already sent
  • A send applies person processing and flag person properties only while the SDK has the identity it was built for (a reset() counts even when reuseAnonymousId keeps the distinct id), and adds the replay debug values snapshotted at build.
    • $screen handling
  • ./gradlew spotlessApply apiCheck :posthog:test :posthog-android:testDebugUnitTest :posthog-server:test all pass.
  • I didn't test against a Flutter app; the Flutter side is a separate PR.

📝 Checklist

  • All commits are signed (see Commit signing)
  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran pnpm changeset to generate a changeset file

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

  • Written with Claude Code at Anna's direction, as the native half of running Flutter's beforeSend on the full event on iOS and Android.
  • I considered calling the Dart hook from the native beforeSend and rejected it: native hooks are synchronous and a method-channel reply is async, so it would deadlock on the main thread. That approach was also tried and dropped in posthog-flutter Allow configuring SDK HTTP client proxy settings #255.
  • A code-review pass before pushing found that the replay debug window was committed at build time. Fixed in the last commit.

🤖 Generated with Claude Code

@turnipdabeets turnipdabeets self-assigned this Oct 28, 2026
@turnipdabeets
turnipdabeets requested a review from a team as a code owner October 28, 2026 23:55

@posthog posthog 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.

PostHog Review · Standard · reviewed 5585bc1: 1 Should fix.

See this review and its findings in PostHog Review. Comment @posthog review --deep for a Deep review. A Deep review takes longer and looks deeper than a Standard review.

Comment thread posthog/src/main/java/com/posthog/PostHog.kt Outdated
@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

posthog-android Compliance Report

Date: 2026-10-29T01:38:50.549321+00:00
Duration: 449775ms

⚠️ Some Tests Failed

212/219 tests passed, 7 failed


Capture_V1 Tests

⚠️ 98/101 tests passed, 3 failed

View Details
Test Status Duration
Endpoint And Method.Targets V1 Endpoint ✅ 383ms
Endpoint And Method.Does Not Use Legacy Endpoints ✅ 39ms
Required Headers.Has Authorization Bearer Header ✅ 26ms
Required Headers.Has Content Type Json ✅ 25ms
Required Headers.Has Posthog Sdk Info Format ✅ 25ms
Required Headers.Has Posthog Attempt Header ✅ 27ms
Required Headers.Has Posthog Request Id ✅ 24ms
Required Headers.Has Posthog Request Timestamp ✅ 26ms
Required Headers.Has User Agent ✅ 25ms
Body Format.Body Has Created At And Batch ✅ 22ms
Body Format.No Api Key In Body ✅ 23ms
Body Format.No Sent At In Body ✅ 23ms
Event Format.Event Has Required Root Fields ✅ 21ms
Event Format.Event Uuid Is Valid ✅ 20ms
Event Format.Event Timestamp Is Rfc3339 ✅ 20ms
Event Format.Non Utc Event Timestamp Is Converted To Utc ✅ 25ms
Event Format.Distinct Id Is String ✅ 21ms
Event Format.Distinct Id At Root Not Properties ✅ 22ms
Event Format.Custom Properties Preserved ✅ 22ms
Event Format.Set Properties Preserved ✅ 24ms
Event Format.Set Once Properties Preserved ✅ 27ms
Event Format.Groups Properties Preserved ✅ 21ms
Event Format.Sdk Generates Uuid If Not Provided ✅ 28ms
Event Format.Event Has Required Root Fields Batch ✅ 30ms
Event Format.Event Uuid Is Valid Batch ✅ 27ms
Event Format.Event Timestamp Is Rfc3339 Batch ✅ 25ms
Event Format.Distinct Id Is String Batch ✅ 29ms
Event Format.Distinct Id At Root Not Properties Batch ✅ 27ms
Event Format.Custom Properties Preserved Batch ✅ 27ms
Event Format.Set Properties Preserved Batch ✅ 27ms
Event Format.Set Once Properties Preserved Batch ✅ 25ms
Event Format.Groups Properties Preserved Batch ✅ 26ms
Event Format.Sdk Generates Uuid If Not Provided Batch ✅ 41ms
Batch Behavior.Multiple Events In Single Batch ✅ 36ms
Batch Behavior.Batch Envelope Smoke ✅ 31ms
Batch Behavior.Flush With No Events Sends Nothing ✅ 16ms
Batch Behavior.Flush At Triggers Batch ✅ 1023ms
Batch Behavior.Created At Reflects Batch Creation Time ✅ 25ms
Deduplication.Generates Unique Uuids ✅ 45ms
Deduplication.Different Events Same Content Different Uuids ✅ 22ms
Deduplication.Preserves Uuid On Retry ✅ 7017ms
Deduplication.Preserves Timestamp On Retry ✅ 7014ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 7024ms
Deduplication.No Duplicate Events In Batch ✅ 34ms
Header Behavior On Retry.Attempt Header Starts At One ✅ 18ms
Header Behavior On Retry.Attempt Header Increments On Retry ✅ 12026ms
Header Behavior On Retry.Request Id Preserved On Retry ✅ 7017ms
Header Behavior On Retry.Different Requests Have Different Request Ids ✅ 2028ms
Header Behavior On Retry.Request Timestamp Changes On Retry ✅ 7018ms
Response Format Validation.Success Response Has Uuid Keyed Results ✅ 17ms
Response Format Validation.Success Response Has Ok For Each Event ✅ 22ms
Response Format Validation.Success No Retry After When All Ok ✅ 18ms
Response Format Validation.Success Retry After Present When Retry Events ✅ 2010ms
Response Format Validation.Success No Retry After When Drop Only ✅ 19ms
Response Format Validation.Response Echoes Request Id ✅ 16ms
Retry Behavior.Retries On 408 ✅ 7015ms
Retry Behavior.Retries On 500 ✅ 7017ms
Retry Behavior.Retries On 503 ✅ 7021ms
Retry Behavior.Retries On 504 ✅ 7015ms
Retry Behavior.Retryable Errors Have Retry After ✅ 4014ms
Retry Behavior.Respects Retry After On Retryable Error ✅ 10024ms
Retry Behavior.Does Not Retry On 400 ✅ 4020ms
Retry Behavior.Does Not Retry On 401 ✅ 4021ms
Retry Behavior.Does Not Retry On 402 ✅ 4019ms
Retry Behavior.Does Not Retry On 413 ✅ 4018ms
Retry Behavior.Does Not Retry On 415 ✅ 4018ms
Retry Behavior.Non Retryable Errors Have No Retry After ✅ 4018ms
Retry Behavior.Implements Backoff ✅ 17022ms
Retry Behavior.Max Retries Respected ❌ 17035ms
Partial Batch Handling.Handles 200 Full Success ✅ 2015ms
Partial Batch Handling.Handles 200 With All Ok ✅ 3026ms
Partial Batch Handling.Does Not Retry Dropped Events ✅ 3023ms
Partial Batch Handling.Does Not Retry Limited Events ✅ 3023ms
Partial Batch Handling.Prunes Ok Events On Partial Retry ✅ 7015ms
Partial Batch Handling.Prunes Dropped Events On Partial Retry ✅ 7017ms
Partial Batch Handling.Retries Only Retry Events From Partial ✅ 7014ms
Partial Batch Handling.Partial Retry Preserves Uuids ✅ 7017ms
Partial Batch Handling.Partial Retry Attempt Header Increments ✅ 7016ms
Partial Batch Handling.Partial Retry Request Id Preserved ✅ 7014ms
Partial Batch Handling.Respects Retry After On Partial ✅ 7022ms
Partial Batch Handling.Unknown Result Treated As Terminal ✅ 3021ms
Partial Batch Handling.Mixed Ok Drop Limited No Retry ✅ 3029ms
Compression.Sends Gzip Content Encoding ✅ 15ms
Compression.No Content Encoding When Disabled ✅ 13ms
Compression.Compressed Body Is Decompressible ✅ 13ms
Error Handling.Does Not Retry On Unknown 4Xx ✅ 4015ms
Event Options.Cookieless Mode Override ✅ 16ms
Event Options.Disable Skew Correction Override ✅ 13ms
Event Options.Process Person Profile Override ✅ 13ms
Event Options.Product Tour Id Override ✅ 17ms
Event Options.Unset Options Omitted ✅ 18ms
Event Options.Options Override In Batch ✅ 26ms
Event Options.Unknown Option Passes Through ✅ 17ms
Event Options.Option Value Is Not Converted ✅ 15ms
Event Options.Lenient Bool Option Values Are Not Converted ✅ 16ms
Event Options.Option Wins Over Legacy Property ✅ 19ms
Event Options.Legacy Property Fills Unset Option ✅ 16ms
Event Options.Null Option Falls Back To Legacy Property ✅ 15ms
Geoip And Historical Migration.Geoip Disable Injected Into Properties ❌ 15ms
Geoip And Historical Migration.Historical Migration Set In Body ❌ 19ms
Geoip And Historical Migration.Historical Migration Absent By Default ✅ 15ms

Failures

retry_behavior.max_retries_respected

Expected 4 requests, got 5

geoip_and_historical_migration.geoip_disable_injected_into_properties

Expected $geoip_disable='True', got 'None'. Available properties: ['$is_identified', '$recording_status', '$sdk_debug_pending_queue_size']

geoip_and_historical_migration.historical_migration_set_in_body

Body missing 'historical_migration' field. Body keys: ['created_at', 'batch']

Capture_Ai_V1 Tests

⚠️ 97/101 tests passed, 4 failed

View Details
Test Status Duration
Endpoint And Method.Targets V1 Endpoint ✅ 19ms
Endpoint And Method.Does Not Use Legacy Endpoints ✅ 17ms
Endpoint And Method.Capture Does Not Reroute Ai Named Events ✅ 15ms
Required Headers.Has Authorization Bearer Header ✅ 19ms
Required Headers.Has Content Type Json ✅ 17ms
Required Headers.Has Posthog Sdk Info Format ✅ 21ms
Required Headers.Has Posthog Attempt Header ✅ 18ms
Required Headers.Has Posthog Request Id ✅ 21ms
Required Headers.Has Posthog Request Timestamp ✅ 25ms
Required Headers.Has User Agent ✅ 24ms
Body Format.Body Has Created At And Batch ✅ 19ms
Body Format.No Api Key In Body ✅ 20ms
Body Format.No Sent At In Body ✅ 16ms
Event Format.Event Has Required Root Fields ✅ 15ms
Event Format.Event Uuid Is Valid ✅ 23ms
Event Format.Event Timestamp Is Rfc3339 ✅ 16ms
Event Format.Non Utc Event Timestamp Is Converted To Utc ✅ 14ms
Event Format.Distinct Id Is String ✅ 14ms
Event Format.Distinct Id At Root Not Properties ✅ 13ms
Event Format.Custom Properties Preserved ✅ 15ms
Event Format.Set Properties Preserved ✅ 20ms
Event Format.Set Once Properties Preserved ✅ 19ms
Event Format.Groups Properties Preserved ✅ 18ms
Event Format.Sdk Generates Uuid If Not Provided ✅ 18ms
Event Format.Capture Ai Keeps Supplied Uuid ❌ 11ms
Event Format.Event Has Required Root Fields Batch ❌ 22ms
Event Format.Event Uuid Is Valid Batch ✅ 24ms
Event Format.Event Timestamp Is Rfc3339 Batch ✅ 24ms
Event Format.Distinct Id Is String Batch ✅ 17ms
Event Format.Distinct Id At Root Not Properties Batch ✅ 19ms
Event Format.Custom Properties Preserved Batch ✅ 27ms
Event Format.Set Properties Preserved Batch ✅ 27ms
Event Format.Set Once Properties Preserved Batch ✅ 26ms
Event Format.Groups Properties Preserved Batch ✅ 24ms
Event Format.Sdk Generates Uuid If Not Provided Batch ✅ 21ms
Batch Behavior.Multiple Events In Single Batch ✅ 24ms
Batch Behavior.Batch Envelope Smoke ✅ 24ms
Batch Behavior.Flush At Triggers Batch ✅ 1017ms
Batch Behavior.Created At Reflects Batch Creation Time ✅ 14ms
Deduplication.Generates Unique Uuids ✅ 31ms
Deduplication.Different Events Same Content Different Uuids ✅ 17ms
Deduplication.Preserves Uuid On Retry ✅ 7011ms
Deduplication.Preserves Timestamp On Retry ✅ 7016ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 7016ms
Deduplication.No Duplicate Events In Batch ✅ 23ms
Header Behavior On Retry.Attempt Header Starts At One ✅ 13ms
Header Behavior On Retry.Attempt Header Increments On Retry ✅ 12022ms
Header Behavior On Retry.Request Id Preserved On Retry ✅ 7017ms
Header Behavior On Retry.Different Requests Have Different Request Ids ✅ 2024ms
Header Behavior On Retry.Request Timestamp Changes On Retry ✅ 7016ms
Response Format Validation.Success Response Has Uuid Keyed Results ✅ 14ms
Response Format Validation.Success Response Has Ok For Each Event ✅ 18ms
Response Format Validation.Success No Retry After When All Ok ✅ 16ms
Response Format Validation.Success Retry After Present When Retry Events ✅ 2009ms
Response Format Validation.Success No Retry After When Drop Only ✅ 17ms
Response Format Validation.Response Echoes Request Id ✅ 13ms
Retry Behavior.Retries On 408 ✅ 7013ms
Retry Behavior.Retries On 500 ✅ 7016ms
Retry Behavior.Retries On 503 ✅ 7022ms
Retry Behavior.Retries On 504 ✅ 7016ms
Retry Behavior.Retryable Errors Have Retry After ✅ 4011ms
Retry Behavior.Respects Retry After On Retryable Error ✅ 10019ms
Retry Behavior.Does Not Retry On 400 ✅ 4018ms
Retry Behavior.Does Not Retry On 401 ✅ 4018ms
Retry Behavior.Does Not Retry On 402 ✅ 4016ms
Retry Behavior.Does Not Retry On 413 ✅ 4019ms
Retry Behavior.Does Not Retry On 415 ✅ 4015ms
Retry Behavior.Non Retryable Errors Have No Retry After ✅ 4016ms
Retry Behavior.Implements Backoff ✅ 17030ms
Retry Behavior.Max Retries Respected ❌ 17030ms
Partial Batch Handling.Handles 200 Full Success ✅ 2015ms
Partial Batch Handling.Handles 200 With All Ok ✅ 3022ms
Partial Batch Handling.Does Not Retry Dropped Events ✅ 3021ms
Partial Batch Handling.Does Not Retry Limited Events ✅ 3018ms
Partial Batch Handling.Prunes Ok Events On Partial Retry ✅ 7015ms
Partial Batch Handling.Prunes Dropped Events On Partial Retry ✅ 7015ms
Partial Batch Handling.Retries Only Retry Events From Partial ✅ 7017ms
Partial Batch Handling.Partial Retry Preserves Uuids ✅ 7011ms
Partial Batch Handling.Partial Retry Attempt Header Increments ✅ 7011ms
Partial Batch Handling.Partial Retry Request Id Preserved ✅ 7014ms
Partial Batch Handling.Respects Retry After On Partial ✅ 7018ms
Partial Batch Handling.Unknown Result Treated As Terminal ✅ 3021ms
Partial Batch Handling.Mixed Ok Drop Limited No Retry ✅ 3024ms
Compression.Sends Gzip Content Encoding ✅ 14ms
Compression.No Content Encoding When Disabled ✅ 11ms
Compression.Compressed Body Is Decompressible ✅ 13ms
Error Handling.Does Not Retry On Unknown 4Xx ✅ 4016ms
Event Options.Cookieless Mode Override ✅ 14ms
Event Options.Disable Skew Correction Override ✅ 15ms
Event Options.Process Person Profile Override ✅ 15ms
Event Options.Product Tour Id Override ✅ 12ms
Event Options.Unset Options Omitted ✅ 14ms
Event Options.Options Override In Batch ✅ 18ms
Event Options.Unknown Option Passes Through ✅ 11ms
Event Options.Option Value Is Not Converted ✅ 13ms
Event Options.Lenient Bool Option Values Are Not Converted ✅ 15ms
Event Options.Option Wins Over Legacy Property ✅ 15ms
Event Options.Legacy Property Fills Unset Option ✅ 13ms
Event Options.Null Option Falls Back To Legacy Property ✅ 12ms
Geoip And Historical Migration.Geoip Disable Injected Into Properties ❌ 13ms
Geoip And Historical Migration.Historical Migration Absent By Default ✅ 14ms

Failures

event_format.capture_ai_keeps_supplied_uuid

Expected last action result '0198c0de-0000-7000-8000-000000000abc', got '01a1854b-e652-7e7e-b9be-9eaa6e5bf834'

event_format.event_has_required_root_fields_batch

Expected 1 requests, got 2

retry_behavior.max_retries_respected

Expected 4 requests, got 5

geoip_and_historical_migration.geoip_disable_injected_into_properties

Expected $geoip_disable='True', got 'None'. Available properties: ['$is_identified', '$recording_status', '$sdk_debug_session_start', '$sdk_debug_pending_queue_size']

Feature_Flags Tests

✅ 17/17 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 31ms
Request Payload.Flags Request Uses V2 Query Param ✅ 17ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 18ms
Request Payload.Flags Request Omits Authorization Header ✅ 16ms
Request Payload.Token In Flags Body Matches Init ✅ 16ms
Request Payload.Groups Round Trip ✅ 15ms
Request Payload.Groups Default To Empty Object ✅ 15ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 15ms
Request Payload.Disable Geoip Omitted Defaults To False ✅ 15ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 15ms
Request Lifecycle.No Flags Request On Init Alone ✅ 5ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 13ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 23ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 19ms
Retry Behavior.Retries Flags On 502 ✅ 319ms
Retry Behavior.Retries Flags On 504 ✅ 317ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 17ms

…send

A built event the wrapper drops no longer caches the screen name, updates the
person properties used for flags, or claims the replay debug bundle. The send
does all three, as capture does, so the window starts with the event that
carries the bundle.

@posthog posthog 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.

PostHog Review · Standard · reviewed 31a7119: 1 Must fix, 3 Should fix.

Comment thread posthog/src/main/java/com/posthog/PostHog.kt Outdated
Comment thread posthog/src/main/java/com/posthog/PostHog.kt Outdated
Comment thread posthog/src/main/java/com/posthog/PostHog.kt Outdated
Comment thread posthog/src/main/java/com/posthog/PostHog.kt Outdated
Build defers person processing to send and records the built name for replay
debug eligibility. Send adds only the throttled replay debug keys (API 23 safe,
keeps keys the wrapper's hook removed), skips flag person properties when the
user changed since the build, and ignores a second send of the same event.

@posthog posthog 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.

PostHog Review · Standard · reviewed e73e33b: 1 Should fix.

This is review round 3 on this pull request. When findings keep coming back in the same code, the approach is usually the problem. Before the next fix, check whether a different design would remove the whole class of findings.

Comment thread posthog/src/main/java/com/posthog/PostHog.kt Outdated
A send now drops an event this instance didn't build or built before setup()/close(), skips person processing and flag person properties after reset() (also when reuseAnonymousId keeps the distinct id), and adds the replay debug values snapshotted at build.

@posthog posthog 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.

PostHog Review · Standard · reviewed 887cae5: 2 Should fix.

This is review round 4 on this pull request. When findings keep coming back in the same code, the approach is usually the problem. Before the next fix, check whether a different design would remove the whole class of findings.

Comment on lines +1486 to +1487
if (!ai && event.event == PostHogEventName.SCREEN.event) {
(properties["\$screen_name"] as? String)?.trim()?.takeIf { it.isNotEmpty() }?.let { cacheScreenName(it) }

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.

P2 · Guard deferred screen caching against resets

Build a wrapper $screen event, call reset(), then send the event after the asynchronous hook completes. cacheScreenName restores the previous user's screen into the cleared context, so subsequent events and logs inherit that stale $screen_name. Apply the reset-generation guard to this deferred cache update while still delivering the original event.

built.uuid?.let { uuid ->
// Snapshotted now, so a new session during the round trip doesn't change them.
val deferredReplayDebug =
if (!ai && isReplayDebugEvent(event)) {

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.

P2 · Preserve replay debug enrichment on the wrapper AI lane

With an active session and no debug window, wrapper $ai_generation events omit $sdk_debug_session_start and the optional replay bundle because !ai disables deferred enrichment; native captureAi includes them. This breaks the replay-debug contract required by AGENTS.md:46. Remove the AI exclusions in both build and send enrichment.

This branch has not been deployed

No deployments
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.

1 participant