feat: send $release_id from POSTHOG_RELEASE_ID on every event - #247
Conversation
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
The PR appears safe to merge; the previous test-isolation issue is resolved and no new actionable failures remain. Reviews (2) · Last reviewed commit: "test: clear the facade client after each..." |
posthog-php-fork_curl Compliance ReportDate: 2026-09-23T10:36:29.371196+00:00
|
| Test | Status | Duration |
|---|---|---|
| Format Validation.Event Has Required Fields | ✅ | 29ms |
| Format Validation.Event Has Uuid | ✅ | 524ms |
| Format Validation.Event Has Lib Properties | ✅ | 525ms |
| Format Validation.Distinct Id Is String | ✅ | 525ms |
| Format Validation.Token Is Present | ✅ | 526ms |
| Format Validation.Custom Properties Preserved | ✅ | 526ms |
| Format Validation.Event Has Timestamp | ✅ | 525ms |
| Format Validation.Non Utc Event Timestamp Is Converted To Utc | ✅ | 525ms |
| Retry Behavior.Retries On 503 | ❌ | 5528ms |
| Retry Behavior.Does Not Retry On 400 | ✅ | 2529ms |
| Retry Behavior.Does Not Retry On 401 | ✅ | 2529ms |
| Retry Behavior.Respects Retry After Header | ❌ | 5528ms |
| Retry Behavior.Implements Backoff | ❌ | 15544ms |
| Retry Behavior.Retries On 500 | ❌ | 5531ms |
| Retry Behavior.Retries On 502 | ❌ | 5531ms |
| Retry Behavior.Retries On 504 | ❌ | 5531ms |
| Retry Behavior.Max Retries Respected | ❌ | 15529ms |
| Deduplication.Generates Unique Uuids | ✅ | 46ms |
| Deduplication.Preserves Uuid On Retry | ❌ | 5532ms |
| Deduplication.Preserves Uuid And Timestamp On Retry | ❌ | 10535ms |
| Deduplication.Preserves Uuid And Timestamp On Batch Retry | ❌ | 5535ms |
| Deduplication.No Duplicate Events In Batch | ✅ | 534ms |
| Deduplication.Different Events Have Different Uuids | ✅ | 528ms |
| Compression.Sends Gzip When Enabled | ✅ | 636ms |
| Batch Format.Uses Proper Batch Structure | ✅ | 525ms |
| Batch Format.Flush With No Events Sends Nothing | ✅ | 516ms |
| Batch Format.Multiple Events Batched Together | ✅ | 518ms |
| Error Handling.Does Not Retry On 403 | ✅ | 2530ms |
| Error Handling.Does Not Retry On 413 | ✅ | 2528ms |
| Error Handling.Retries On 408 | ❌ | 5532ms |
Failures
retry_behavior.retries_on_503
Expected at least 3 requests, got 1
retry_behavior.respects_retry_after_header
Expected at least 2 requests, got 1
retry_behavior.implements_backoff
Expected at least 3 requests, got 1
retry_behavior.retries_on_500
Expected at least 2 requests, got 1
retry_behavior.retries_on_502
Expected at least 2 requests, got 1
retry_behavior.retries_on_504
Expected at least 2 requests, got 1
retry_behavior.max_retries_respected
Expected 4 requests, got 1
deduplication.preserves_uuid_on_retry
Need at least 2 requests to check retry
deduplication.preserves_uuid_and_timestamp_on_retry
Expected at least 3 requests, got 1
deduplication.preserves_uuid_and_timestamp_on_batch_retry
Expected at least 2 requests, got 1
error_handling.retries_on_408
Expected at least 2 requests, got 1
Feature_Flags Tests
✅ 17/17 tests passed
View Details
| Test | Status | Duration |
|---|---|---|
| Request Payload.Request With Person Properties Device Id | ✅ | 521ms |
| Request Payload.Flags Request Uses V2 Query Param | ✅ | 519ms |
| Request Payload.Flags Request Hits Flags Path Not Decide | ✅ | 519ms |
| Request Payload.Flags Request Omits Authorization Header | ✅ | 519ms |
| Request Payload.Token In Flags Body Matches Init | ✅ | 519ms |
| Request Payload.Groups Round Trip | ✅ | 518ms |
| Request Payload.Groups Default To Empty Object | ✅ | 519ms |
| Request Payload.Disable Geoip False Propagates As Geoip Disable False | ✅ | 518ms |
| Request Payload.Disable Geoip Omitted Defaults To False | ✅ | 519ms |
| Request Payload.Flag Keys To Evaluate Contains Only Requested Key | ✅ | 519ms |
| Request Lifecycle.No Flags Request On Init Alone | ✅ | 515ms |
| Request Lifecycle.No Flags Request On Normal Capture | ✅ | 513ms |
| Request Lifecycle.Two Flag Calls Produce Two Remote Requests | ✅ | 522ms |
| Request Lifecycle.Mock Response Value Is Returned To Caller | ✅ | 520ms |
| Retry Behavior.Retries Flags On 502 | ✅ | 622ms |
| Retry Behavior.Retries Flags On 504 | ✅ | 621ms |
| Side Effect Events.Get Feature Flag Captures Feature Flag Called Event | ✅ | 527ms |
posthog-php-lib_curl Compliance ReportDate: 2026-09-23T10:36:37.499377+00:00 ✅ All Tests Passed!47/47 tests passed Capture Tests✅ 30/30 tests passed View Details
Feature_Flags Tests✅ 17/17 tests passed View Details
|
posthog-php-socket Compliance ReportDate: 2026-09-23T10:36:34.522210+00:00
|
| Test | Status | Duration |
|---|---|---|
| Format Validation.Event Has Required Fields | ✅ | 22ms |
| Format Validation.Event Has Uuid | ✅ | 517ms |
| Format Validation.Event Has Lib Properties | ✅ | 517ms |
| Format Validation.Distinct Id Is String | ✅ | 519ms |
| Format Validation.Token Is Present | ✅ | 517ms |
| Format Validation.Custom Properties Preserved | ✅ | 518ms |
| Format Validation.Event Has Timestamp | ✅ | 517ms |
| Format Validation.Non Utc Event Timestamp Is Converted To Utc | ✅ | 518ms |
| Retry Behavior.Retries On 503 | ❌ | 9225ms |
| Retry Behavior.Does Not Retry On 400 | ✅ | 2522ms |
| Retry Behavior.Does Not Retry On 401 | ✅ | 2519ms |
| Retry Behavior.Respects Retry After Header | ❌ | 9229ms |
| Retry Behavior.Implements Backoff | ❌ | 19226ms |
| Retry Behavior.Retries On 500 | ❌ | 8745ms |
| Retry Behavior.Retries On 502 | ❌ | 9231ms |
| Retry Behavior.Retries On 504 | ❌ | 9230ms |
| Retry Behavior.Max Retries Respected | ❌ | 19237ms |
| Deduplication.Generates Unique Uuids | ✅ | 31ms |
| Deduplication.Preserves Uuid On Retry | ❌ | 9227ms |
| Deduplication.Preserves Uuid And Timestamp On Retry | ❌ | 14228ms |
| Deduplication.Preserves Uuid And Timestamp On Batch Retry | ❌ | 8737ms |
| Deduplication.No Duplicate Events In Batch | ✅ | 30ms |
| Deduplication.Different Events Have Different Uuids | ✅ | 519ms |
| Compression.Sends Gzip When Enabled | ✅ | 518ms |
| Batch Format.Uses Proper Batch Structure | ✅ | 519ms |
| Batch Format.Flush With No Events Sends Nothing | ✅ | 514ms |
| Batch Format.Multiple Events Batched Together | ✅ | 510ms |
| Error Handling.Does Not Retry On 403 | ✅ | 2519ms |
| Error Handling.Does Not Retry On 413 | ✅ | 2521ms |
| Error Handling.Retries On 408 | ❌ | 5523ms |
Failures
retry_behavior.retries_on_503
Expected at least 3 requests, got 1
retry_behavior.respects_retry_after_header
Expected at least 2 requests, got 1
retry_behavior.implements_backoff
Expected at least 3 requests, got 1
retry_behavior.retries_on_500
Expected at least 2 requests, got 1
retry_behavior.retries_on_502
Expected at least 2 requests, got 1
retry_behavior.retries_on_504
Expected at least 2 requests, got 1
retry_behavior.max_retries_respected
Expected 4 requests, got 1
deduplication.preserves_uuid_on_retry
Need at least 2 requests to check retry
deduplication.preserves_uuid_and_timestamp_on_retry
Expected at least 3 requests, got 1
deduplication.preserves_uuid_and_timestamp_on_batch_retry
Expected at least 2 requests, got 1
error_handling.retries_on_408
Expected at least 2 requests, got 1
Feature_Flags Tests
✅ 17/17 tests passed
View Details
| Test | Status | Duration |
|---|---|---|
| Request Payload.Request With Person Properties Device Id | ✅ | 518ms |
| Request Payload.Flags Request Uses V2 Query Param | ✅ | 516ms |
| Request Payload.Flags Request Hits Flags Path Not Decide | ✅ | 516ms |
| Request Payload.Flags Request Omits Authorization Header | ✅ | 517ms |
| Request Payload.Token In Flags Body Matches Init | ✅ | 515ms |
| Request Payload.Groups Round Trip | ✅ | 516ms |
| Request Payload.Groups Default To Empty Object | ✅ | 516ms |
| Request Payload.Disable Geoip False Propagates As Geoip Disable False | ✅ | 516ms |
| Request Payload.Disable Geoip Omitted Defaults To False | ✅ | 516ms |
| Request Payload.Flag Keys To Evaluate Contains Only Requested Key | ✅ | 515ms |
| Request Lifecycle.No Flags Request On Init Alone | ✅ | 511ms |
| Request Lifecycle.No Flags Request On Normal Capture | ✅ | 508ms |
| Request Lifecycle.Two Flag Calls Produce Two Remote Requests | ✅ | 518ms |
| Request Lifecycle.Mock Response Value Is Returned To Caller | ✅ | 516ms |
| Retry Behavior.Retries Flags On 502 | ✅ | 617ms |
| Retry Behavior.Retries Flags On 504 | ✅ | 617ms |
| Side Effect Events.Get Feature Flag Captures Feature Flag Called Event | ✅ | 519ms |
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

💡 Motivation and Context
A PHP app cannot link its error tracking issues to a release.
posthog-cliinjects the release id into JavaScript bundles, and PHP has no bundle. This is the PHP counterpart of posthog-python#975; PostHog/posthog#104420 shows the deploy side.POSTHOG_RELEASE_ID(the id thatposthog-cli release resolveprints) and sends it as$release_idon every event.$exceptionevents the server resolves the release by a direct id lookup.getenv(), likePOSTHOG_API_KEYandPOSTHOG_HOST. The value is trimmed, and a blank value counts as unset.Client::message(), whichcapture(),captureException(),identify(),alias()andgroupIdentify()all pass through.raw()skipsmessage()and stays untouched.$release_idin the event properties or in the request context wins over the env var.before_sendstill sees and can remove it.$release_idis added to the minimal$feature_flag_calledallowlist, so minimized flag events carry it too. This differs from Python, which leaves minimal flag events without it.Note
PHP-FPM clears the environment of its workers by default (
clear_env = yes). A deployment must pass the variable through, withclear_env = noor anenv[POSTHOG_RELEASE_ID] = $POSTHOG_RELEASE_IDpool entry. The changeset says this.💚 How did you test it?
test/ReleaseIdTest.php, parameterized over every event path (capture,$exception,$identify,$create_alias,$groupidentify, full and minimal$feature_flag_called), over the env values (set, padded, empty, whitespace only, unset), and over the explicit-value sources (event property, request context).$feature_flag_calledcase fails.main.phpcswithphpcs.xml: the new test file is clean, and the warnings on the changed library files are the same as onmain.composer api:checkreports the snapshot is up to date.posthog-cli release resolve, one handled exception, and one plain event. Both events carried$release_id, and the server resolvedphp-release-env@1.0.0from it. Not tested against production.The issue page resolves the release that the CLI created:
The event JSON, filtered to
release, shows the$release_idthat the SDK sent and the$exception_releasethat the server resolved from it (same id):📝 Checklist
If releasing new changes
pnpm changeto generate a change intent file🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Written with Claude Code (Claude Opus 5.5), directed by the PR assignee.
$feature_flag_calledallowlist was widened instead of copying Python's exclusion. Reviewers may prefer Python's behavior; the fix is dropping one allowlist entry and one test case..changesetformat, not withpnpm change.🤖 Generated with Claude Code