Skip to content

docs(compliance): re-audit posthog-android capture rows for 4.0 - #186

Merged
turnipdabeets merged 18 commits into
mainfrom
docs/android-4-compliance
Nov 11, 2026
Merged

turnipdabeets merged 18 commits into
mainfrom
docs/android-4-compliance

Conversation

@turnipdabeets

@turnipdabeets turnipdabeets commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Important

Don't merge until posthog-android 4.0.0 is released. This scores code on the 4.0 integration branch, not a shipped version. Before merging:

Summary

posthog-android 4.0 (PostHog/posthog-android#871) moves analytics to capture v1 (/i/v1/analytics/events), adds captureAi on its own /i/v1/ai/events lane, and changes consent handling, remote config, the flag API, session replay and surveys. This PR re-audits 30 android rows at aaa23d39 against main 752f899 plus #146 at d387ab79 (which includes #147's text), treated as merged. The 30 are the five capture v1 rows and the 25 rows that 4.0 code or spec text merged since 2026-10-19 changes. The other 34 rows carry forward from 2026-10-19 (c5e788bd).

Row Before After Why
Application Lifecycle ✅ ✅ Installed, Updated, Opened and Backgrounded conform; un-prefixed version/build break only a SHOULD NOT (n31)
Before Send Hook ✅ ✅ Chain and fail-closed unchanged; options and the uuid survive a hook as capture allows (n3)
Capture ✅ ✅ Capture v1 wire, headers, per-event results, options hoisting, the $lib/$lib_version fill (posthog-android#956), "" left out of $active_feature_flags (#193) and null array elements kept (posthog-android#955) conform; the post-hook uuid and null-options restore are #146's two allowances (n24)
Capture AI ➖ ✅ #147 adds android 4.0 to Applicability; lane, routing, config, compression, size cap and 5 MiB batching conform (n25)
Capture Exception ✅ ✅ One coercer for handled and uncaught JVM exceptions; the native crash serializer keeps frames (#124) (n40)
Consent Gating 🟡 ✅ optOut() stops replay and integrations; deferred native crashes follow consent at crash time (n5)
Event Batcher 🟡 🟡 Byte-aware 5 MiB batching passes; the periodic flush still runs on java.util.Timer, not the injectable clock (n6)
Exception Event Metadata 🟡 🟡 Nested handled, no mechanism.source, no single-entry exception_id: 0, no $exception_source, caller override of reserved keys, missing empty value. synthetic: false is correct (n7)
Feature Flag Cache ✅ ✅ A malformed cached payload reads as null (#170) (n33)
Feature Flag Called Tracker 🟡 🟡 Minimal-event allowlist drops $os_name/$os_version and registered attribution keys; config version 2 (#162, #203) doesn't apply on /flags?v=2 (n8)
Get Feature Flag ✅ ✅ Matches the 4.0 android variant (n39)
Get Feature Flag Payload ✅ ✅ The getter is gone, as #170 allows (n38)
Get Feature Flag Result ✅ ✅ "" reads as disabled (#193); a malformed payload is null (n36)
Get Feature Flags ❌ 🟡 getAllFeatureFlags() is now the spec's android form, but returns null after a restart until the disk cache is loaded (n9)
Get Feature Flags And Payloads ❌ 🟡 Same form and same cold-start gap (n10)
HTTP Client ✅ ✅ Capture v1 transport conforms; separate compression/captureAiCompression and the redirect rule on a caller's httpClient are what #146 allows (n26)
Identify ✅ 🟡 Runs while opted out (#167), but updates the dedup hash for a $set it dropped, which the spec says it MUST NOT (n28)
Is Feature Enabled ✅ ✅ Caller default, known value wins, "" reads as false (n37)
Logs ✅ ✅ compression = NONE sends raw JSON (#81) (n35)
On Feature Flags 🟡 ✅ Runtime onFeatureFlags() with unsubscribe, late replay and stale-load suppression (#161) (n13)
Opt In 🟡 🟡 Replay restart and crash-time consent (#138, #199) conform; optOut() can't clear local data (@client scenario) (n14)
Reload Feature Flags ✅ ✅ Callback gets PostHogFeatureFlagsLoaded (n34)
Remote Config ✅ ✅ Replies after close() or from an earlier setup are dropped (posthog-android#953, #961) (n32)
Retry Queue ✅ ✅ Capture v1 status set, 1 s→30 s jittered backoff, Retry-After floor, retry-only resends, no OkHttp retries (n27)
Session Replay Debug Properties 🟡 ✅ Required/optional tiering, $-event gate and 30 s bundle window (n17)
Session Replay Privacy 🟡 ✅ Wireframe mode removed (#197); View and Compose unmask agree; FLAG_SECURE windows record black (#160) (n19)
Setup ✅ ✅ projectToken only; a blank or phx_ token disables the SDK with a warning (n29)
Shutdown ✅ ✅ close() flushes, stops queues and integrations, safe twice (n30)
Start Session Recording ❌ ✅ Replay isn't installed while opted out, so a start stays inactive (n20)
Surveys 🟡 🟡 Web-only exclusion and popup delay conform; submit and dismiss move the last-seen date (#102), and an unknown question type blocks later surveys (n22)

android moves from 37/16/5/6 to 42/15/2/5 (58%→66%), with 17 open gaps.

Not scored as gaps: unmet SHOULDs are noted in each row's note. For a durable client queue, #146 lets 404'd events stay queued with no attempt limit; the page records this with the other client allowances.

Out of scope but stale: Stop Session Recording (n21) carries forward from 2026-10-19. Its opt-out point predates 4.0's optOut() uninstalling replay, so the next full audit must re-verify it.

README: updated the android roll-up row, the out-of-cycle refresh paragraph, the non-Pass count (17), the android gap-inventory rows, and the Session Replay Debug Properties pattern paragraph.

Validation

🤖 Generated with Claude Code

@eli-r-ph

eli-r-ph commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

On the post-hook rule: yes, let's carve both out. Re-imposing the pre-hook uuid matches the fleet rule that a hook can't resend an SDK-generated uuid, and treating absent options as unchanged is fine as long as an empty map still clears them. I'll update #146.

On the redirect rule: yes. The same-origin 307/308 rule is a capture rule, not a transport preference, so applying it to a caller-supplied client is right. I'll say so in #146.

turnipdabeets and others added 5 commits November 10, 2026 12:35
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>
…c26b9b

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>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… for clients

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…st 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>
@turnipdabeets
turnipdabeets force-pushed the docs/android-4-compliance branch from a301122 to 4078fe3 Compare November 10, 2026 17:41
@turnipdabeets
turnipdabeets marked this pull request as ready for review November 10, 2026 18:44
@turnipdabeets
turnipdabeets requested a review from a team as a code owner November 10, 2026 18:44

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

The five-row re-audit and revised totals are consistent with the cited Android 4.0 implementation and pinned capture-v1 contract. The documented release-tag repinning and final-spec recheck remain prerequisites before merging.

AI-assisted review.

turnipdabeets and others added 6 commits November 10, 2026 16:19
…shutdown and lifecycle rows at 4.0

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… reload, flag-called tracker, before-send and logs rows at 4.0

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>
… at 4.0

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… roll-ups

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread compliance/posthog-android.md Outdated
@@ -79,64 +145,64 @@ complete implementation of that contract outside the browser.
| # | Contract | Status | Note |
|---|----------|--------|------|
| 1 | Alias | ❌ | [n1] |

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.

Alias is carried forward as ❌ for a missing distinct_id, but alias() on the 4.0 branch now sets props["distinct_id"] (posthog-android#819). Alias code changed after 2026-10-19, so by this page's own scope rule it should be re-scored, likely to ✅.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 06bd1ad — Alias ✅ at aaa23d39 (#819 is in it) and joins the 4.0 re-audit.

Comment thread compliance/posthog-android.md Outdated
|---|---|---|---|
| Application Lifecycle | ✅ | ✅ | Installed, Updated, Opened and Backgrounded carry the required properties; un-prefixed `version`/`build` break only a SHOULD NOT ([n31](#n31)) |
| Before Send Hook | ✅ | ✅ | Chain, drop and fail-closed unchanged; `options` and the uuid survive a hook as capture allows ([n3](#n3)) |
| Capture | ✅ | ✅ | Capture v1 wire, headers, per-event results, options, the `$lib`/`$lib_version` pair fill, session id lifting, timestamps and fail-open token all conform; the post-hook uuid and `null`-options restore are the two allowances #146 grants ([n24](#n24)) |

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.

#146 now requires migration guides to show a call option process_person_profile: true as the way to keep identifying under a registered false. The SDK behaves that way, but MIGRATION.md here has no such example until posthog-android#966 merges. Capture is 🟡 at this commit, or say it's met once #966 lands.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cfc72e1 — Capture 🟡 against 15501ca; clears when posthog-android#966 lands.

@turnipdabeets turnipdabeets Nov 11, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed in 1b64af2 — this audit tracks 4.0 and #966 targets it, so Capture stays ✅ with a note; we'll recheck when #966 merges.

Comment thread compliance/posthog-android.md Outdated
**Summary:** 37 ✅ · 16 🟡 · 5 ❌ · 6 ➖ · 0 ❓ (64 rows; previous audit 2026-08-10 at `8659a7b4` scored 31/16/9/3/0 on 59 rows)
**Audited commit:** `c5e788bd603d3bdda77ac4d213538b9db637299a` ([commit](https://github.com/PostHog/posthog-android/commit/c5e788bd603d3bdda77ac4d213538b9db637299a)) — audited on 2026-10-19. **30 rows re-audited against posthog-android 4.0** at `aaa23d39af4424978bd2439028282e47417490b8` ([commit](https://github.com/PostHog/posthog-android/commit/aaa23d39af4424978bd2439028282e47417490b8), head of the 4.0 integration PR [PostHog/posthog-android#871](https://github.com/PostHog/posthog-android/pull/871)) on 2026-11-10 — see [posthog-android 4.0](#posthog-android-40-re-audit-2026-11-05)
**Audited against sdk-specs commit:** `c72e367` (2026-10-19 rows); `752f899` plus the capture v1 text of [#146](https://github.com/PostHog/sdk-specs/pull/146) at `d387ab79`, which includes [#147](https://github.com/PostHog/sdk-specs/pull/147) (merged into #146's branch as `6a9ed0f`), for the 30 4.0 rows
**Summary:** 42 ✅ · 15 🟡 · 2 ❌ · 5 ➖ · 0 ❓ (64 rows; 2026-10-19 at `c5e788bd` scored 37/16/5/6/0; previous full audit 2026-08-10 at `8659a7b4` scored 31/16/9/3/0 on 59 rows)

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.

This page stays at 64 rows while main lists 69 and the iOS 4.0 page adds Experiment Exposure, AI Datasets, AI Scorers, Offline Evaluations and Emails. Could it add the same five rows (all ➖)?

@turnipdabeets turnipdabeets Nov 10, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 30a6492 — added the five rows as ➖; now 43/15/1/10 on 69 after 1b64af2.

turnipdabeets and others added 4 commits November 10, 2026 18:50
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>
…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>
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>
… 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>
turnipdabeets and others added 3 commits November 10, 2026 19:00
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>
@turnipdabeets
turnipdabeets merged commit dfeaa99 into main Nov 11, 2026
10 checks passed
@turnipdabeets
turnipdabeets deleted the docs/android-4-compliance branch November 11, 2026 01:47
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.

3 participants