Repository navigation
Conversation
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…o v2 sends it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d delta Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
6c6daa2 to
41b4023
Compare
…rors Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…arning result Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tions Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… retries, 413 halving, request identity, wrapper names, global options, empty options) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… disabled-client error always Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
turnipdabeets
left a comment
There was a problem hiding this comment.
A few more from checking the current text against the iOS, Android, Flutter and React Native plugin v1 branches.
[nit] Outside the diff: retry-queue (lines 19, 70, 94, 117), http-client and event-batcher still say Flutter has no Dart queue, transport or batcher of its own and delegates to native or posthog-js. That's no longer true for 6.0 on Windows and Linux.
…sonless default, wrappers, replay, group identify, Retry-After, timestamps and logs Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keep both new http-client requirements: capture v1 transport (this branch) and request body compression and opt-out (#81). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… options Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ype, without debug on servers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e v1 - A per-call disable_geoip is a per-event value; false is sent as false. - Capture's own 408/500/503/504 and 2xx-with-retry carry Retry-After: 1, so the timing scenario keeps only 404, 429 and 502. - A server SDK may requeue events whose last attempt got no HTTP response. - A 413 is terminal on server SDKs; client SDKs may halve. - List the client majors in http-client; state Flutter desktop's own queue. - Note that ingestion drops personless person-only events. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…52f899 and #146 d387ab7 Capture, Capture Exception and Capture AI move to Pass now that null-valued properties are omitted (posthog-ios#1047) and the SDK fills its own $lib pair after the caller's properties (posthog-ios#1050). On Feature Flags moves to Pass: loads in flight across reset() are dropped (posthog-ios#1048) and empty variants are left out of listener flags. HTTP Client is scored Pass on its merits, since #146 now leaves a lane with its own compression setting out of the whole-client opt-out. Surveys stays Partial only for the popup-delay eligibility re-check (SHOULD); posthog-ios#1049 fixed the rest. Opt In meets the new deferred-crash consent requirement (#199); the empty variant (#193), variant key rename (#203) and job-retry (#205) changes need no other status change. Line references move to e27cbe4cb. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Re-audits all 64 posthog-flutter rows at 6be9a1e9ee (the 6.0 release PR) against sdk-specs 8306698 plus #146 at 5c26b9b, treated as merged, and adds five ➖ rows. Mobile rows cite the posthog-ios 4.0 and posthog-android 4.0 audits. Tally 26/27/4/12 on 69 rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Re-audits the posthog-flutter rows at 82123e6 against sdk-specs 752f899 plus #146 at d387ab7, with native rows checked at posthog-ios e27cbe4cb and posthog-android aaa23d39. On Feature Flags moves to Pass: posthog-ios now drops a flag load in flight across reset(). Capture scores the $lib pair fill on every path, HTTP Client and Capture AI drop the settled compression note, Surveys keeps only posthog-android's last-seen date gap, Opt In records #199's deferred crash consent, and Get Feature Flags notes posthog-js reading an empty variant as enabled on web. Tally 27/26/4/12 on 69 rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dustinbyrne
left a comment
There was a problem hiding this comment.
Approved with non-blocking comments on token-rule scope, server retry-overlap coverage, and nullable optional-ID parsing. The prior artifact corrections are addressed. The declared public-v1-release prerequisite remains separate; this approval does not clear that gate.
AI-assisted review.
…with a call option A layered process_person_profile false also reaches $set and registered client layers. A call option true beats every layer; docs show it as the way to keep identifying, not a per-call legacy property. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on guide shows the identity call option #146 at 15501ca requires migration guides to show a per-call process_person_profile: true on identity calls; MIGRATION.md at e27cbe4cb lacks it until PostHog/posthog-ios#1053 merges. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#146 now requires migration guides to show a process_person_profile: true call option on identity calls under a registered false. The 6.0 guide only says those events get dropped; record the gap until posthog-flutter#718. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ter Register Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ity-call guide gap #146 at 15501ca requires migration guides to show a process_person_profile: true call option on identity calls. The 4.0 MIGRATION.md doesn't yet; PostHog/posthog-android#966 adds it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The identity-call migration-guide example #146 requires lands in 4.0 with PostHog/posthog-ios#1053, which targets the release branch. This audit tracks 4.0, so a pending release-branch PR is noted rather than scored as a gap. Reverts 85d4acd. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… 4.0 The identity-call migration-guide example #146 requires lands in 4.0 with PostHog/posthog-android#966, which targets the release branch. This audit tracks 4.0, so a pending release-branch PR is noted rather than scored as a gap. Undoes the Capture downgrade from cfc72e1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
…-plugin 3.0 (#201) * docs(compliance): re-audit posthog-react-native rows for react-native-plugin 3.0 Re-audits the nine rows that react-native-plugin 3.0's move to posthog-ios 4.0 and posthog-android 4.0 affects, at posthog-js 210bf35d8 with native behavior read at posthog-ios e27cbe4cb and posthog-android aaa23d39, against sdk-specs 752f899 plus #146 at d387ab7 treated as merged. Is Session Replay Active, Ingestion Controls and Privacy go to ✅; Debug Properties goes ❌→🟡; Opt In meets #138 and #199; Stop Session Recording stays 🟡 on posthog-android. Tally 32/25/2/5. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): keep RN ingestion controls partial for cached sample rate Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): score RN capture exception partial for null custom properties Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): score RN start session recording partial for event triggers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): record RN capture null-property gap in n5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): pin n5 null-property line refs to posthog-js 210bf35d8 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…reads - Null-valued properties: an SDK MAY omit them; one that keeps them sends JSON null. Omission scenarios are labeled and their acceptance features require the null_property_omission capability. - MCP acceptance asserts the process_person_profile option, not the legacy property. - Close add-capture-v1 task 3.4: the strict JSON body requirement covers non-finite numbers for capture v1. - Scope the client $lib pair fill and token fail-open to capture v1; use a key without a pair rule in the client precedence scenario; note that session_id and window_id may be null; update the proposal for the $lib reversal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* docs(compliance): re-audit posthog-android capture rows for 4.0 Re-score Capture, Capture AI, Event Batcher, HTTP Client and Retry Queue against posthog-android 4.0 (be3ed4b4) and the capture v1 text in #146 and #147. Capture AI now applies to android. Capture, Capture AI and HTTP Client move to partial on post-beforeSend uuid/options restore and a caller httpClient's redirect policy; Retry Queue stays a pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): re-check posthog-android 4.0 rows against #146 at 5c26b9b Re-checks the five capture v1 rows at posthog-android 8b63a135 and #146 at 5c26b9b, which includes #147. #146 now allows the post-hook uuid and options restore and the redirect rule on a caller's httpClient, so Capture and HTTP Client stay ✅ and Capture AI scores ✅. Android 4.0 now keeps $lib in properties (#942). Two #146 conflicts (compression opt-out scope and client $lib precedence) are recorded as open questions, not scored. Tally 38/16/5/5. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): score posthog-android 4.0 rows against #146 as merged Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): treat the #146 $lib precedence conflict as resolved for clients Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): re-check posthog-android 4.0 rows at aaa23d39 against main 752f899 and #146 d387ab7 Score Capture against the client $lib pair fill #146 now requires (posthog-android#956), the #193 empty-variant rule and kept null array elements (#955). Drop the settled compression and $lib conflict notes: #146 exempts a lane with its own compression setting from the opt-out. Update line numbers and the MIGRATION.md links, list the out-of-scope rows later 4.0 and spec changes leave stale, and add note anchors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): re-audit posthog-android consent, identify, setup, shutdown and lifecycle rows at 4.0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): re-audit posthog-android remote config, flag cache, reload, flag-called tracker, before-send and logs rows at 4.0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): re-audit posthog-android flag-read rows at 4.0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): re-audit posthog-android session replay rows at 4.0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): re-audit posthog-android surveys and exception rows at 4.0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): update posthog-android 4.0 totals, scope and README roll-ups Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): re-score posthog-android Alias at 4.0 alias() sets properties.distinct_id since PostHog/posthog-android#819, which is in aaa23d39, so the row moves from ❌ to ✅ and joins the 4.0 re-audit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): score posthog-android Capture partial for the identity-call guide gap #146 at 15501ca requires migration guides to show a process_person_profile: true call option on identity calls. The 4.0 MIGRATION.md doesn't yet; PostHog/posthog-android#966 adds it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): add the five newer contracts to posthog-android as N/A Experiment Exposure, AI Datasets, AI Scorers, Offline Evaluations and Emails join the matrix, matching main's 69 contracts and the iOS 4.0 page. All are N/A: android requests /flags?v=2 and the other four are server-only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): keep posthog-android Capture passing while tracking 4.0 The identity-call migration-guide example #146 requires lands in 4.0 with PostHog/posthog-android#966, which targets the release branch. This audit tracks 4.0, so a pending release-branch PR is noted rather than scored as a gap. Undoes the Capture downgrade from cfc72e1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): make the 69-contract README note SDK-neutral The same paragraph lands from both the iOS and Android 4.0 audits, so it merges cleanly in either order and stays true after both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): point posthog-android Identify remediation at #967 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* chore(compliance): audit posthog-flutter 6.0 Re-audits all 64 posthog-flutter rows at 6be9a1e9ee (the 6.0 release PR) against sdk-specs 8306698 plus #146 at 5c26b9b, treated as merged, and adds five ➖ rows. Mobile rows cite the posthog-ios 4.0 and posthog-android 4.0 audits. Tally 26/27/4/12 on 69 rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): re-audit posthog-flutter 6.0 at 82123e6 Re-audits the posthog-flutter rows at 82123e6 against sdk-specs 752f899 plus #146 at d387ab7, with native rows checked at posthog-ios e27cbe4cb and posthog-android aaa23d39. On Feature Flags moves to Pass: posthog-ios now drops a flag load in flight across reset(). Capture scores the $lib pair fill on every path, HTTP Client and Capture AI drop the settled compression note, Surveys keeps only posthog-android's last-seen date gap, Opt In records #199's deferred crash consent, and Get Feature Flags notes posthog-js reading an empty variant as enabled on web. Tally 27/26/4/12 on 69 rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): keep flutter flag payload and result partial for web Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): score flutter capture and capture AI partial for desktop session id Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): keep the flutter desktop debug-property gap in n28 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): note the web flag-event default in flutter n13 and n15 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): exclude web from the posthog-flutter $lib pair fill Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): score posthog-flutter Capture against #146 at 23c2478 #146 now requires migration guides to show a process_person_profile: true call option on identity calls under a registered false. The 6.0 guide only says those events get dropped; record the gap until posthog-flutter#718. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): cite #146's registered-options text in posthog-flutter Register Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): track the posthog-flutter migration-guide example for 6.0, not as a gap PostHog/posthog-flutter#718 targets the 6.0 release branch, which this audit tracks, so the identity-call example is noted rather than listed as a Capture gap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): restore the posthog-flutter bulk flag getter gaps row and give its 64-row score The ❌ rows for Get Feature Flags and Get Feature Flags And Payloads were removed when both moved to 🟡, without the 🟡 row iOS and Android add. The row also gives its shared 64-row score like the other 69-row lines. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* chore(compliance): audit posthog-ios 4.0 Re-audit all 64 posthog-ios rows at 3460e534a (4.0 release branch) against sdk-specs dd11a6b, add the five rows added to the README table since the last audit, and update the iOS roll-up and gap entries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(compliance): score posthog-ios HTTP Client partial compression = .none leaves captureAi requests gzipped through the separate captureAiCompression setting, so iOS 4.0 has no whole-client compression opt-out. Roll-up becomes 40/17/1/11 (58%), 18 gaps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): list iOS capture v1 retries as matching #146 Draft #146 already permits the client-SDK durable queue, unlimited attempts, 1-30 s backoff and multi-event 413 halving for iOS 4.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(compliance): score posthog-ios Session Replay Privacy partial SwiftUI's postHogMask() wins over an enclosing postHogNoMask(), the reverse of the spec's unmask-over-mask precedence. It over-masks rather than leaks. Roll-up becomes 39/18/1/11 (57%), 19 gaps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): re-check posthog-ios 4.0 at 1f91c5b2 against main and #146 Re-checks the iOS audit at 1f91c5b2 and sdk-specs 8306698. #1036 keeps $lib/$lib_version, which now matches #146. Opt In meets the #138 replay restart requirements. Surveys gains a #102 gap: setSurveySeen moves the last-seen date on submit and dismiss. HTTP Client goes back to ✅: its compression gap comes from conflicting http-client and capture-ai rules in #146, raised on that PR. Tally 40/17/1/11. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): score posthog-ios 4.0 capture v1 rows against #146 as merged Scores Capture, Capture AI, Before Send Hook, Event Batcher, HTTP Client and Retry Queue against #146 at 5c26b9b, treated as merged. The capture v1 wire, transport and retry policy conform. Capture AI applies to iOS 4.0 and is 🟡 for the same NSNull serialization gap as Capture; starting the AI queue at setup is what #146 asks of client SDKs. Tally 40/18/1/10. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): treat the #146 $lib precedence conflict as resolved for clients Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): re-check posthog-ios 4.0 at e27cbe4cb against main 752f899 and #146 d387ab7 Capture, Capture Exception and Capture AI move to Pass now that null-valued properties are omitted (posthog-ios#1047) and the SDK fills its own $lib pair after the caller's properties (posthog-ios#1050). On Feature Flags moves to Pass: loads in flight across reset() are dropped (posthog-ios#1048) and empty variants are left out of listener flags. HTTP Client is scored Pass on its merits, since #146 now leaves a lane with its own compression setting out of the whole-client opt-out. Surveys stays Partial only for the popup-delay eligibility re-check (SHOULD); posthog-ios#1049 fixed the rest. Opt In meets the new deferred-crash consent requirement (#199); the empty variant (#193), variant key rename (#203) and job-retry (#205) changes need no other status change. Line references move to e27cbe4cb. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): score posthog-ios Surveys as pass The popup-delay and wait-period SHALLs are met since posthog-ios#1049. The one unmet requirement is a SHOULD (re-check eligibility when the delay elapses), which is recorded but not scored. Totals become 45/13/1/10. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): score iOS Exception Steps partial on NSNull normalization Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): score posthog-ios Capture partial until the migration guide shows the identity call option #146 at 15501ca requires migration guides to show a per-call process_person_profile: true on identity calls; MIGRATION.md at e27cbe4cb lacks it until PostHog/posthog-ios#1053 merges. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): note the README's 69 contracts and the iOS row's 69-row basis Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): keep posthog-ios Capture passing while tracking 4.0 The identity-call migration-guide example #146 requires lands in 4.0 with PostHog/posthog-ios#1053, which targets the release branch. This audit tracks 4.0, so a pending release-branch PR is noted rather than scored as a gap. Reverts 85d4acd. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(compliance): make the 69-contract README note SDK-neutral The same paragraph lands from both the iOS and Android 4.0 audits, so it merges cleanly in either order and stays true after both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ostHog#5637) With POSTHOG_CAPTURE_MODE=v1, a 404 or 429 from capture now gets the same backoff, Retry-After handling and retry budget as 408 and 5xx, instead of failing the batch at once. Matches the capture v1 status classification in PostHog/sdk-specs#146 and posthog-python#1178.
SDK docs, migration guides and examples set the four settings through options. They may say once that legacy option properties still work, map each option to its property, and show a before-and-after migration example. posthog-ios and posthog-android have no public global options, so their docs may register a legacy option property for every event. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
posthog-kmp 0.11 is a capture v1 release too: it wraps posthog-android 4.0, posthog-ios 4.0 and the JVM core 7.0, so Android, JVM, iOS and macOS send to
The spec doesn't name posthog-kmp in these places yet:
Could you add posthog-kmp 0.11 (native on Android, JVM, iOS and macOS; legacy on JavaScript and Wasm) next to posthog-flutter 6.0 in each? |
…server SDKs A server SDK sets process_person_profile on $identify, $create_alias, $merge_dangerously, $groupidentify, $set and $set_once from the call alone: the call's option, else its legacy property moved into the option, else true unless the SDK generated the distinct id. Layers no longer turn these events personless, and before_send sees one value. Client SDKs keep the current rule. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…release posthog-python 8.0, posthog-go v2, posthog-rs 1.0 and posthog-node 6.0 ship capture v1 first; the client SDK majors follow in their own release. Name only those four where a requirement lists SDKs or versions, and keep the client SDK rules in general terms. The client SDK details move to a follow-up change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
||
| An SDK that delivers events through capture v1 SHALL treat an empty or whitespace-only caller `distinct_id` as missing. A missing id keeps the SDK's existing behavior: a generated personless id (UUIDv7, with `process_person_profile: false` set as an option) or a clear error returned to the caller. The SDK SHALL never send an event without a `distinct_id` key. | ||
|
|
||
| The SDK SHALL NOT shorten, hash or reject distinct ids by length or by placeholder value: capture v1 drops an event whose `distinct_id` is over 200 UTF-8 bytes (`distinct_id_too_large`) and accepts placeholder values such as `anonymous` without a person profile, and reports both in that event's `results` entry. A `$groupidentify` event's `distinct_id` SHALL be the caller's id when given, else the request-context id where the SDK has one, else `$<group type>_<group key>`, and never a random value. An `alias` call SHALL never take its target from the request context. A server SDK SHALL default identify-style events (`$identify`, `$create_alias`, `$merge_dangerously`, `$groupidentify`, `$set` and `$set_once`) to person processing when the call submits them, before any layer fills and before `before_send`: a non-`null` `process_person_profile` option on the call stands; otherwise a non-`null` `$process_person_profile` property on the call moves into the option and leaves the properties; otherwise the option is `true`, unless the SDK generated the event's distinct id, which keeps the personless `false`. A `null` option or property counts as unset. So global, context and registered layers do not set `process_person_profile` on an identify-style event whose distinct id the SDK did not generate; they reach it like any other event for every other property and option, and `$groupidentify` never takes the context session id. Once the option is set, the SDK SHALL remove any `$process_person_profile` property from the event before `before_send`, so the hook sees one value; the hook can still change the option and has the final say. The default applies to the event name the call submitted, so a hook that builds an identify-style event, or renames an event to one, sets the option itself, and SDK docs SHALL say so. When the final `process_person_profile` on `$identify`, `$create_alias`, `$merge_dangerously` or `$groupidentify` is `false`, capture still accepts it and reports it `ok`, but ingestion drops it (ingestion warning `invalid_event_when_process_person_profile_is_false`), so the identify, alias, merge or group update never takes effect; a `$set` or `$set_once` event is kept without its person update. SDK docs and migration guides SHALL describe this default, and SHALL tell apps that want an identify-style event personless to set `process_person_profile: false` on the call or in `before_send`, or to turn person processing off for the project. On a client SDK, global and registered layers still reach these events like any other event, and a `process_person_profile: true` call option, or one set in `before_send`, keeps them. Client SDKs have no request context: they send `$groupidentify` with the current distinct id, and with the session id like any other event. |
There was a problem hiding this comment.
[suggestion] Could we extend this rule to client SDKs too? posthog-ios#1067 and posthog-android#979 now ignore a registered $process_person_profile, and a wrapper-registered process_person_profile option, on the same six events. Flutter and KMP inherit that from native, and a posthog-flutter PR for the desktop (Dart) path is coming.
The reason is the same as on the server, and stronger: in 3.x the client SDKs overwrote a registered $process_person_profile with their own value, so a registered false never blocked identify. Without this, 4.0 would start dropping those calls for apps that register false.
How the client version differs from the server rule:
- It removes the registered value instead of setting
true. Ingestion treats the two the same, and the SDK's own personlessfalsefor an anonymous user still applies, which is the client counterpart of the generated-id exception. - A value passed on the call, or set in
before_send, still applies. person_profiles: neverstill skips these calls.
So we'd replace "On a client SDK, global and registered layers still reach these events like any other event" with something like: "A client SDK SHALL NOT apply a registered $process_person_profile property or registered process_person_profile option to an identify-style event; a value set on the call or in before_send still applies." We'd also tag the layered-personless scenarios below @client too, or add client scenarios for a registered false, a call false, a before_send false, and an ordinary-event control.
There was a problem hiding this comment.
[suggestion] The register spec needs the same exception: openspec/specs/register/spec.md says registered properties reach every later event (step 6), and that identify / alias / group include them too. For $process_person_profile, those two lines would need to exclude the six identity events, matching the capture rule above.
Problem
capture,retry-queue,http-clientandevent-batcherspecs still describe the legacy wire (/batch/,api_keyin the body,$libstamped into properties, global defaults overwriting the call,429retried, batches shrunk on413).v1branches, worked out during the ports.Changes
capturegains the capture v1 wire contract: the endpoint, the body envelope, strict field types, the required headers and which ones change on a retry, and the per-eventresultsmap withduplicates_dropped.capturegains per-eventoptions, the hoisting of the four legacy option properties afterbefore_send, and global and context options where an SDK has global and context properties. SDK docs and examples set these settings throughoptions.capturegains the server event-building order: the call wins, context and global values fill only unset keys, SDK values fill last,before_sendhas the final say. This folds in the flag-property rule from docs(capture): place server feature flag properties in the merge order #145.capturegains the rules capture v1 makes observable: blank distinct ids, the$groupidentifyfallback id, timestamps at millisecond precision or finer, per-event serialization,$lib/$lib_versionsent in properties and stored as sent, with thePostHog-Sdk-Infoheader only as a fallback, fail-open on a missing or personal API key.retry-queuegains the capture v1 status set (404/408/429/500/502/503/504 and network errors retried; 402/413 terminal), four attempts with 100 ms doubling waits and jitter,Retry-Afteras a clamped floor, and no HTTP-library retries. "429 retryable" and "shrink on 413" are marked legacy.http-clientgains bearer auth, the acceptedContent-Encodingvalues, and same-origin 307/308 redirects only.event-batchergains byte-aware check-before-append batching and the end of 413 batch shrinking.migration/yaml-parity-v1mirrors the harness capture v1 suite update (posthog-sdk-test-harness#92): 404, 429 and 502 retry scenarios, and thewarningresult in place oflimited, which capture never sends.capture-aigains the capture v1 AI lane (/i/v1/ai/events, lane isolation,misrouted_event, size rules and lane configuration), PostHog's AI wrappers always send through the AI method, andcapture-ai-v1.feature/capture-ai-v1-delivery.featureadd the v1 AI cases undercapture_ai_v1.capture_v0*harness features are untouched.Note
Three open PRs touch the same ground and need a decision before merge: #145 (folded in here), #140 (requires
nullfor non-finite numbers, while posthog-go v2 drops the event locally; this change records both as allowed), #81 (gzip by default, while the v1 server SDKs default to no compression).How did you test this code?
openspec validate add-capture-v1 --type change --strictpassed before archiving.openspec validate --specs --strict --no-interactiveafter archiving: 67 passed, 0 failed, the same totals asmain.master(rust/capture/src/v1/) and against the four SDKv1branches, including their open pre-release PRs. Sources are listed in the archiveddesign.md.SDK_V2_SPECSpointing at this branch: discovery ready with no missing bindings (160 migrated cases), and the retry and outcome features pass against the harness reference hosts. The harness case-count test needs 157 → 160 when the harness bumps its specs pin.@sdk:server; that needs an end-to-end run against a real adapter.🤖 Agent context
🤖 Generated with Claude Code