Repository navigation
fix: only move the current screen for wrapper events built as $screen - #930
Merged
Merged
Conversation
Contributor
posthog-android Compliance ReportDate: 2026-11-03T00:50:25.722127+00:00 ✅ All Tests Passed!232/232 tests passed Capture_V1 Tests✅ 105/105 tests passed View Details
Capture_Ai_V1 Tests✅ 110/110 tests passed View Details
Feature_Flags Tests✅ 17/17 tests passed View Details
|
ioannisj
approved these changes
Nov 3, 2026
ioannisj
left a comment
Contributor
There was a problem hiding this comment.
🤖 An AI agent wrote this on behalf of @ioannisj.
No findings. The builtAsScreen gate lines up with plain capture("$screen") on the native path, which doesn't move the current screen either (only screen() does), and the new test sits nicely next to the existing positive case.
5 of 7 tasks
turnipdabeets
added a commit
that referenced
this pull request
Nov 5, 2026
* feat!: disable the SDK when the project token is a personal API key A `phx_` token is a personal API key; capture rejects every request made with it. Setup now logs once and stays disabled, as for an empty token. Co-Authored-By: Claude Fable 5.1 <[email protected]> * feat!: send analytics events through capture v1 Analytics events now go to `POST /i/v1/analytics/events` with the project token in an `Authorization: Bearer` header, `PostHog-Sdk-Info`, `PostHog-Attempt`, `PostHog-Request-Id` and `PostHog-Request-Timestamp`. The body is `{created_at, batch}`; each event drops `$lib`/`$lib_version`, lifts string `$session_id`/`$window_id` to the root, and hoists the legacy `$process_person_profile`, `$cookieless_mode`, `$ignore_sent_at` and `$product_tour_id` properties into the new `PostHogEvent.options`. The queue reads the per-event results: `ok`, `warning` and `drop` leave the queue, only `retry` is kept and resent under the same request id and `created_at` with the next attempt number. A 2xx without readable results counts as delivered. 408 and 500/502/503/504 are retried; 429, 404 and other 4xx are terminal, as are redirects other than a same-origin 307/308 (followed at most 5 times with the same body and headers). Backoff doubles from 1 to 30 seconds with 25% jitter, and `Retry-After` is a floor capped at 30 seconds for every queue. Replay and logs keep their retry sets. Legacy cached events (`PostHogSendCachedEventsIntegration`) are sent through capture v1 too; the ones capture asks to retry are re-queued at the tail of the legacy file for the next launch. `PostHogConfig.maxRetries` is renamed `pushNotificationSubscriptionMaxRetries` since it only limits push-subscription retries. `PostHogApi.batch()` stays for posthog-server. Co-Authored-By: Claude Fable 5.1 <[email protected]> * chore(compliance): run the capture v1 suite against the adapter The adapter advertises `capture_v1` and `encoding_gzip`, tracks `/i/v1/analytics/events` requests with `retry_attempt` derived from `PostHog-Attempt`, maps `max_retries` to the renamed config field and runs with `personProfiles = ALWAYS`, since the harness never identifies. The workflow pins harness 1.20.0 and also runs for PRs that target the `chore/v4-*` and `feat/v4-*` branches. Co-Authored-By: Claude Fable 5.1 <[email protected]> * docs: changeset bullets and migration guide for capture v1 Co-Authored-By: Claude Fable 5.1 <[email protected]> * fix: resend a failed capture request as is, without client retries or logged bodies The queue now resends exactly the files of a request that failed or came back with events to retry, so the API keeps its request ID and `created_at` and bumps `PostHog-Attempt`. Before, the next request took the head of the queue, and any event queued since gave it a new ID at attempt 1. A 413 still halves the batch as a new request, and a file the queue drops in the meantime starts over. The capture client turns off OkHttp's `retryOnConnectionFailure`, which resent a request on a reused connection with a stale attempt number and timestamp. Debug logs for capture requests name the event count and the response status instead of printing the request and response bodies, which hold event content. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: stop OkHttp resending a capture 503 with Retry-After 0 OkHttp's follow-up layer resends a 503 carrying `Retry-After: 0` even with retryOnConnectionFailure off, repeating PostHog-Attempt and PostHog-Request-Timestamp outside the queue's backoff. A network interceptor on the capture client drops that header before the retry layer sees it; the queue waits the same with or without it. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: cap the capture v1 response read at 1 MiB A successful capture response was read whole into memory. Read at most 1 MiB and treat a larger or endless body as unreadable, which counts the batch as delivered like any other 2xx without readable results. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: keep the queue's retry jitter in milliseconds Rounding the jittered backoff to whole seconds removed the jitter from the 1 s and 2 s waits, so devices refused together retried together. The delay is now kept in milliseconds. Co-Authored-By: Claude Opus 5.5 <[email protected]> * test: send a 3.x event queued on disk through capture v1 Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs: list what a reverse proxy needs for capture v1 Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: cap the time spent reading capture v1 results A 2xx body that trickles bytes within the read timeout held the queue thread until it ended. Reading the results now has a 10 second deadline, after which the body counts as unreadable and the events as delivered, like an oversized body. Co-Authored-By: Claude Opus 5.5 <[email protected]> * feat!: add per-event capture options and one property precedence `capture`, `screen`, `identify`, `setPersonProperties`, `alias`, `group` and `captureException` take an `options` map that is copied onto the new `PostHogEvent.options`, so PostHog can be told how to process one event apart from its properties and `beforeSend` can edit it. Properties are merged in one order: SDK-set values, registered super properties, the caller's properties (with `$set`, `$set_once` and `$groups` as per-call values), then `beforeSend`. `$is_identified`, `$process_person_profile` and the replay debug properties are no longer re-applied after the caller's values. The SDK sets the `process_person_profile` option to `false` only when person processing is off, and only when neither a caller option nor a caller or registered `$process_person_profile` property already says so. It no longer writes a `$process_person_profile` property. Also: a blank `distinctId` argument on `capture` uses the current distinct id; a `$set` sent with `process_person_profile: false` neither stores nor matches the person-properties hash; an event returned by `beforeSend` keeps the uuid of the client capture it came from; the minimal `$feature_flag_called` allowlist keeps `$cookieless_mode`, `$ignore_sent_at` and `$product_tour_id`; the compliance adapter forwards `options` and advertises `event_options`. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01DRbQPidntd4hVufNpMT19L * test: cover capture options, property precedence and the personless option Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01DRbQPidntd4hVufNpMT19L * docs: describe capture options and property precedence for 4.0 Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01DRbQPidntd4hVufNpMT19L * fix: skip PostHog-reserved deep link query parameters A link opened with ?$process_person_profile=true copied that parameter into the Deep Link Opened properties, where capture v1 turns it into the process_person_profile option and enables person processing despite PersonProfiles.NEVER. Query parameters whose name starts with $ are now skipped. Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs: say the retry jitter keeps millisecond precision Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: keep the personless option when the legacy property is null A Java caller can pass a null `$process_person_profile`. It no longer counts as an override, so the SDK still sends `process_person_profile: false` when person processing is off. Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs: escape dollar-prefixed keys in the Kotlin migration examples Co-Authored-By: Claude Opus 5.5 <[email protected]> * feat: add captureAi on the capture v1 AI endpoint `captureAi` takes the same arguments as `capture`, goes through the same enrichment, precedence, personless default and `beforeSend`, and queues the event on its own disk queue, executor and retry identity for `POST /i/v1/ai/events`. It returns the event's uuid once it's handed to the queue, or null when the SDK is disabled or opted out or `beforeSend` dropped it. A name not starting with `$ai_` logs one debug line and is sent unchanged; `capture` never reroutes `$ai_*` events. The AI request client uses `captureAiTimeout` for its call, read and write timeouts and honors `captureAiCompression` through its own gzip interceptor instance. `PostHogQueue` becomes byte-aware through `EndpointSpec`: `maxBatchBytes` bounds a request window (check before append, an oversize record goes alone) and flushes as soon as that much is queued; `maxQueueBytes` is a FIFO disk cap on top of `maxQueueSize`, enforced on add and on load; `maxRecordBytes` drops a record over the limit when it's queued, logging only its name and size. The analytics spec gets a 5 MiB request cap; the AI spec gets 5 MiB requests, 50 MiB on disk and `captureAiMaxEventBytes` (at most 8 MiB) plus a 64 KiB envelope per event. New `PostHogConfig` knobs: `captureAiCompression`, `captureAiMaxQueueSize`, `captureAiTimeout` and `captureAiMaxEventBytes`; non-positive values use the defaults. `PostHogAndroid` stores the AI queue under `posthog-disk-ai-queue`. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01DRbQPidntd4hVufNpMT19L * test: cover captureAi, the AI lane and byte-aware batching SDK-level: routing by method, beforeSend and options, null returns, a terminal 404, the oversize drop (name and size only in the log), the non-`$ai_` debug line, flush and close draining the AI queue, compression per lane and the AI timeout. API-level: the AI endpoint's headers and body, separate retry identities per lane, and an AI queue keeping only the events asked to retry. Queue-level, on a synthetic record: byte-limited request windows, an oversize record sent alone, the flush at a request's worth of bytes, the per-record drop, the disk cap on add and on load, and the spec limits and config fallbacks. The Android setup test covers the AI storage prefix. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01DRbQPidntd4hVufNpMT19L * chore(compliance): run the capture v1 AI suite against the adapter Adds `POST /capture_ai`, which routes through `captureAi` and returns the uuid it sent, tracks `/i/v1/ai/events` requests next to the analytics ones and advertises `capture_ai_v1`. Also restores the capture v1 adapter changes (tracking by capture path, `PostHog-Attempt` as the retry count, `personProfiles = ALWAYS`, the renamed push retries field) that the options commit reverted. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01DRbQPidntd4hVufNpMT19L * docs: changeset bullets and migration guide for captureAi Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01DRbQPidntd4hVufNpMT19L * docs: list the AI endpoint in the migration guide's endpoint table Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: check the AI event size before queuing and return null when over The queue measured an AI event after `encryption`, so an encryption that grows the data dropped events PostHog would accept, and captureAi had already returned the uuid. captureAi now measures the serialized event before encryption and returns null when it's over the limit. The queue's per-record limit had no other user and is removed. Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs: describe the AI size limit and timeout as they behave The limit covers an AI event's properties up to 8 MiB, with 64 KiB for the rest of the serialized event, measured before encryption. captureAiTimeout is a timeout without network activity, not a call timeout. Co-Authored-By: Claude Opus 5.5 <[email protected]> * chore(compliance): report no uuid when captureAi doesn't queue the event Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: log each event capture v1 drops with the reason it gives Debug logs named only the drop count, so a misrouted_event or ai_event_too_big drop was invisible. Each dropped event is now logged with its name, uuid and the server's details, never its properties. Adds a test that an AI event with exactly 8 MiB of properties is sent. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: stop measuring an AI event once it passes the size limit captureAi checks the size on the caller's thread, so a huge prompt or base64 payload no longer costs a full serialization just to be dropped. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: log an unserializable property by key and type, not by value Properties can hold prompts and other user content. Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs: say the AI size check builds the full JSON tree before it stops counting * test: double bytes instead of Base64 in the AI encryption test java.util.Base64 isn't on API 23, so animalsnifferTest failed. Co-Authored-By: Claude Opus 5.5 <[email protected]> * test: make the unserializable Turn a plain class The data class hashCode calls Double.hashCode(double), which isn't on API 23. Co-Authored-By: Claude Opus 5.5 <[email protected]> * test: write encrypted test streams in blocks Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: retry capture v1 requests that get 404 or 429 (#897) * fix: retry capture v1 requests that get 404 or 429 A 404 usually means a misconfigured proxy and a 429 now only comes from an overloaded ingress, so keep the events queued and retry them with the usual backoff and Retry-After handling instead of dropping them. Matches PostHog/posthog-go#395. * fix: warn once when capture v1 returns 404 A 404 now keeps events queued, so nothing tells the app that the route is missing. Print one warning per client, even without debug, naming the URL and the path a reverse proxy or self-hosted instance must serve. * fix: leave host credentials and query out of the capture v1 404 warning Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: Claude Opus 5.5 <[email protected]> * docs: escape dollar signs in captureAi examples Co-Authored-By: Claude Opus 5.5 <[email protected]> * test: give the serializer privacy fixture a prompt-bearing toString Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: make captureAiMaxEventBytes limit the whole serialized event Match posthog-ios, posthog-python and the Flutter desktop lane: the value is the serialized event size, defaulting to 8 MiB + 64 KiB, instead of a properties size the SDK added 64 KiB to. A value over the ceiling now logs a warning when it is clamped. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: subtract a queued file's counted size when it's removed A file deleted from the cache dir reads as 0 bytes, so the queue kept counting it and evicted new AI events against bytes that were gone. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: read lenient false person-processing values before caching person properties Capture reads "false", 0 and similar strings as false, so a $set sent with them is personless and must not store the person-properties hash. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: send a fatal event even while a request waits to be retried The fatal flush resent only the retry set, so the crash report stayed on disk as the process exited. Co-Authored-By: Claude Opus 5.5 <[email protected]> * chore(compliance): count only delivered events when capture asks to retry some Co-Authored-By: Claude Opus 5.5 <[email protected]> * chore(compliance): run the 1.26.0 test harness against the adapter (#902) * chore(compliance): run the 1.25.0 test harness against the adapter Bump the harness from 1.20.0 (CI) and 0.10.0 (local docker-compose) to 1.25.0, and declare the 1.25 capabilities the SDK supports: generated_payloads, log_capture, property_layers and fail_open. Co-Authored-By: Claude Opus 5.5 <[email protected]> * chore(compliance): count the marker's serialized bytes when padding AI properties * chore(compliance): bump the test harness to 1.26.0 Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: Claude Opus 5.5 <[email protected]> * feat: let wrapper SDKs run their own beforeSend on the fully built event (#904) * chore(api): keep @PostHogInternal declarations out of the API dumps * feat: let wrapper SDKs build an event, run their own beforeSend, then send it * fix: start the replay debug window when the wrapper's event is queued * fix: defer wrapper build state changes and the replay debug claim to 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. * fix: keep wrapper builds state-free and send each built event once 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. * fix: tie a wrapper send to the build's setup, instance and identity 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. * fix: don't restore a wrapper screen name after a reset since the build * fix: add the replay debug bundle to wrapper AI events, like captureAi * fix: read replay debug state once per wrapper build The build's required replay keys and the deferred bundle came from two debugProperties() reads, so a replay transition between them could send $recording_status=buffering without its hold reason. Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: Claude Opus 5.5 <[email protected]> * fix: record the wrapper build's identity before enriching the event A reset() or identify() during the build left the event with the old distinct ID while the build recorded the new identity, so the send applied the old user's $set to the new user's flag properties. Co-Authored-By: Claude Opus 5.5 <[email protected]> * chore(compliance): read capture responses outside the adapter lock Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: drop the oldest AI events while too many wait to be written to disk (#901) * fix: drop an AI event while too many wait to be written to disk One executor both writes and sends AI events, so during a slow upload new multi-MiB events waited in memory with no limit. captureAi now returns null while captureAiMaxQueueSize events or 50 MiB are waiting, the same limits the disk queue keeps. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: drop the oldest waiting AI events instead of the new one While a slow upload holds the AI executor, captureAi now keeps the new event and drops the oldest events still waiting to be written once captureAiMaxQueueSize events or 50 MiB wait, the same as the disk queue already does. captureAi returns null again only for disabled, opted-out, beforeSend-dropped or oversized events. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: queue no more AI write tasks than events waiting to be written Dropping a waiting AI event no longer leaves its executor task behind for nothing: a dropped event's task writes a newer one instead, so the executor never holds more tasks than events are waiting. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: queue AI write tasks in the order their events were added --------- Co-authored-by: Claude Opus 5.5 <[email protected]> * docs: tell proxies that strip credentials to keep the project token Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs: say which capture drop logs need debug and what they print Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs: add 402, 404 warning, debug logs and AI queue details to the 4.0 guide Co-Authored-By: Claude Opus 5.5 <[email protected]> * chore: keep PostHogInternal APIs in the api dumps apiCheck is the only check that flags a changed internal signature that posthog-server or a wrapper SDK relies on. The dumps list them again, as on main. Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs: remove leftover conflict markers from the 4.0 guide * fix: keep the capture result when an event handler throws * fix: match capture v1 rules for empty names, drop logs, retry identity and typed values (#903) * fix: match the capture v1 rules for empty names, drop logs, retry identity and typed values * fix: merge a $groups map in properties into the groups set with group() * fix: log an empty-name drop once, without the generic dropped-event line * fix: clamp each duplicates_dropped count to the batch size * fix: keep the pending retry map off Java 8 Map methods missing on API 23 * fix: keep the personless option over a legacy property and drop a 2xx without results (#905) * fix: keep the personless option when a legacy person processing property is set A passed or registered `$process_person_profile` property no longer stops the SDK from setting `process_person_profile: false` when person processing is off. The send hoists the property only into an unset option, so an option set by any layer wins, as the capture spec requires. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: treat a 2xx without readable per-event results as a terminal failure A 2xx whose body can't be read as `{"results": {...}}` no longer counts the batch as delivered. It throws a PostHogApiError with that status, which the queue drops without retrying, and logs only the status and event count, as the capture spec requires. Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: Claude Opus 5.5 <[email protected]> * fix: warn about empty and personal API keys without debug and log rejected batches (#909) * fix: let a caller's $process_person_profile override the personless option Reverts the person-processing half of #905. A passed or registered `$process_person_profile` property again stops the SDK from adding `process_person_profile: false` when person processing is off, so the caller wins, as the client property precedence in sdk-specs `capture` (#143) requires. The send still hoists the property into the option. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: log drop reasons per batch and batch migrated legacy events by bytes - The capture v1 per-batch debug line names the endpoint and counts the dropped events by their `details` tag (opaque strings, never uuids or content), e.g. `ai_event_too_big: 1, misrouted_event: 1`. - Sending events cached by 2.x/3.x closes a batch before it would pass the 5 MiB capture v1 byte target, as the queue does, so a large migrated batch isn't lost to a 413. Order is kept and an event over the target ships alone. Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs: say the token warnings print without debug Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: name the records in the flush drop log Co-Authored-By: Claude Opus 5.5 <[email protected]> * test: cover the capture rules on the captureStateless path Also adds the posthog-server changeset for them. Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs: fold the server capture changes into the server changeset --------- Co-authored-by: Claude Opus 5.5 <[email protected]> * docs: keep PostHog keys when a proxy strips Authorization * fix: only move the current screen for wrapper events built as $screen (#930) * fix: keep a wrapper event sent for another distinct id out of the current user's person state (#928) * docs: review beforeSend hooks for the 4.0 event shape (#924) * docs: ask users to review beforeSend hooks for the 4.0 event shape * docs: cover replacing event.options in beforeSend Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: Claude Opus 5.5 <[email protected]> * feat!: report the device language as $locale and add $app_language (#927) * feat!: report the device language as $locale and add $app_language * fix: address the pre-PR review of $locale and $app_language * docs: correct the $locale migration notes * fix: read a registered $app_language without relying on merge order * fix: read locales and the locale config only on the worker thread Setup and capture no longer make Binder calls or parse the locale config, and supported locales changed at runtime with setOverrideLocaleConfig are picked up. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: leave out $app_language when several declared regions could match Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: stop reading a registered $app_language on every event Registered properties are merged later and win anyway. Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: guard LocaleList calls for the API 23 lint check Co-Authored-By: Claude Opus 5.5 <[email protected]> * fix: read the override locale config only when the locales change Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs: say when $app_language is left out with no match --------- Co-authored-by: Claude Opus 5.5 <[email protected]> * fix: keep events with non-string map keys and align capture v1 logs (#929) * fix: align capture v1 logs, request IDs and beforeSend handling * fix: copy arrays and cycles for beforeSend, and keep the hook failure log debug-only * fix: keep array types in the copy beforeSend hooks get * fix: keep sorted map lookups and copy primitive arrays for beforeSend * fix: read an HTTP-date Retry-After * fix: log the key type when a map key can't be serialized * docs: link the capture v1 upgrade guide and align the 4.0 guide with the backend guides (#934) * docs: link the capture v1 SDK upgrade guide Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs: add timestamps, UUID v7 and the person-only drop to the 4.0 guide * docs: align the 4.0 capture v1 guide with the backend SDK guides Claude-Session: https://claude.ai/code/session_019xLynws83apuXa9LfRy9Aq --------- Co-authored-by: Claude Opus 5.5 <[email protected]> * fix!: keep the 3.x PostHogEvent constructor and copy posthog-server is a minor release and its beforeSend gets PostHogEvent, so a new trailing constructor parameter broke Java callers and copy calls compiled against 3.x. options is now a property. When beforeSend returns a different event with null options, such as a copy, it keeps the options of the event the hook was given. Co-Authored-By: Claude Opus 5.5 <[email protected]> * docs: close the 4.0 guide gaps found in the release review - Remove the two internal TODO comments. - Say surveys-compose works with core 6.x and 7.0. - List RRStyle and the trimmed RRWireframe under internal APIs. - captureAi also returns null for an empty event name. - Note per-event product quota drops, the per-batch drop reasons and the removed per-event "queued" log line. - Self-hosting needs /i/v1/ai/events for captureAi. - A whitespace-only token disables the SDK too. - Describe the 3.x $set/$set_once/$groups replacement rule and the registered $set rule. - KDoc: the AI size drop logs the limit, not the event's size. Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: Claude Fable 5.1 <[email protected]>
6 of 16 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
💡 Motivation and Context
Flutter builds a plain
capture(eventName: r'$screen')under another name, because native appliesscreen()rules to$screenbuilds, and restores the real name before sending.sendBuiltEventForWrapperonly looked at the name at send, so withbeforeSendcallbacks set, a plain capture moved the current screen and later events got its$screen_name. Without callbacks it doesn't.Now the current screen only moves when the event was built and sent as
$screen. The event itself is still sent as before.Raised in review: PostHog/posthog-flutter#682 (comment)
💚 How did you test it?
Added a regression test to
PostHogWrapperEventTest. It failed before the fix and passes now../gradlew :posthog:test :posthog:apiCheck spotlessCheckpasses (JVM only, no device).📝 Checklist
No changeset:
sendBuiltEventForWrapperis unreleased, wrapper-only API on this branch.🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Written with Claude Code. A wrapper that renames a plain event to
$screenalso no longer moves the current screen; only posthog-flutter uses this API today. The screen check is separate from the distinct id fix in the sibling PR, and the two don't overlap.🤖 Generated with Claude Code