Skip to content

feat: send $release_id from POSTHOG_RELEASE_ID on every event - #247

Merged
ablaszkiewicz merged 2 commits into
mainfrom
feat/release-id-env
Sep 24, 2026
Merged

ablaszkiewicz merged 2 commits into
mainfrom
feat/release-id-env

Conversation

@ablaszkiewicz

@ablaszkiewicz ablaszkiewicz commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

💡 Motivation and Context

A PHP app cannot link its error tracking issues to a release. posthog-cli injects 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.

  • The SDK now reads POSTHOG_RELEASE_ID (the id that posthog-cli release resolve prints) and sends it as $release_id on every event.
  • On $exception events the server resolves the release by a direct id lookup.
  • The client reads the variable once, in its constructor, with getenv(), like POSTHOG_API_KEY and POSTHOG_HOST. The value is trimmed, and a blank value counts as unset.
  • The property is set in Client::message(), which capture(), captureException(), identify(), alias() and groupIdentify() all pass through. raw() skips message() and stays untouched.
  • An explicit $release_id in the event properties or in the request context wins over the env var. before_send still sees and can remove it.
  • $release_id is added to the minimal $feature_flag_called allowlist, so minimized flag events carry it too. This differs from Python, which leaves minimal flag events without it.
  • No public API change: the constant and the field are private.

Note

PHP-FPM clears the environment of its workers by default (clear_env = yes). A deployment must pass the variable through, with clear_env = no or an env[POSTHOG_RELEASE_ID] = $POSTHOG_RELEASE_ID pool entry. The changeset says this.

💚 How did you test it?

  • 14 new tests in 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).
  • Without the change, 9 of the 14 fail. Without the allowlist entry, the minimal $feature_flag_called case fails.
  • Full suite on PHP 8.5: 696 tests pass. The warning and deprecation counts match main.
  • phpcs with phpcs.xml: the new test file is clean, and the warnings on the changed library files are the same as on main. composer api:check reports the snapshot is up to date.
  • End to end against a local PostHog stack: a Composer install built from this branch, a release from a locally built posthog-cli release resolve, one handled exception, and one plain event. Both events carried $release_id, and the server resolved php-release-env@1.0.0 from it. Not tested against production.

The issue page resolves the release that the CLI created:

php-release-issue

The event JSON, filtered to release, shows the $release_id that the SDK sent and the $exception_release that the server resolved from it (same id):

php-release-json

📝 Checklist

  • 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 change to 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.

  • The behavior follows posthog-python#975: env var over a CLI-written file, read once per client, explicit value wins.
  • The assignee asked for the id on all events, so the minimal $feature_flag_called allowlist 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.
  • The changeset file was written by hand in the .changeset format, not with pnpm change.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@ablaszkiewicz ablaszkiewicz self-assigned this Sep 23, 2026
@greptile-apps

greptile-apps Bot commented Sep 23, 2026

Copy link
Copy Markdown

Retrigger

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..."

Comment thread test/ReleaseIdTest.php
@github-actions

github-actions Bot commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

posthog-php-fork_curl Compliance Report

Date: 2026-09-23T10:36:29.371196+00:00
Duration: 112222ms

⚠️ Some Tests Failed

36/47 tests passed, 11 failed


Capture Tests

⚠️ 19/30 tests passed, 11 failed

View Details
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

@github-actions

github-actions Bot commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

posthog-php-lib_curl Compliance Report

Date: 2026-09-23T10:36:37.499377+00:00
Duration: 118467ms

✅ All Tests Passed!

47/47 tests passed


Capture Tests

30/30 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields 21ms
Format Validation.Event Has Uuid 520ms
Format Validation.Event Has Lib Properties 518ms
Format Validation.Distinct Id Is String 519ms
Format Validation.Token Is Present 517ms
Format Validation.Custom Properties Preserved 517ms
Format Validation.Event Has Timestamp 519ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc 518ms
Retry Behavior.Retries On 503 5824ms
Retry Behavior.Does Not Retry On 400 2523ms
Retry Behavior.Does Not Retry On 401 2521ms
Retry Behavior.Respects Retry After Header 8528ms
Retry Behavior.Implements Backoff 16242ms
Retry Behavior.Retries On 500 5628ms
Retry Behavior.Retries On 502 5628ms
Retry Behavior.Retries On 504 5627ms
Retry Behavior.Max Retries Respected 17030ms
Deduplication.Generates Unique Uuids 238ms
Deduplication.Preserves Uuid On Retry 5625ms
Deduplication.Preserves Uuid And Timestamp On Retry 10832ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry 5633ms
Deduplication.No Duplicate Events In Batch 523ms
Deduplication.Different Events Have Different Uuids 520ms
Compression.Sends Gzip When Enabled 519ms
Batch Format.Uses Proper Batch Structure 519ms
Batch Format.Flush With No Events Sends Nothing 515ms
Batch Format.Multiple Events Batched Together 511ms
Error Handling.Does Not Retry On 403 2520ms
Error Handling.Does Not Retry On 413 2523ms
Error Handling.Retries On 408 5623ms

Feature_Flags Tests

17/17 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id 523ms
Request Payload.Flags Request Uses V2 Query Param 515ms
Request Payload.Flags Request Hits Flags Path Not Decide 517ms
Request Payload.Flags Request Omits Authorization Header 516ms
Request Payload.Token In Flags Body Matches Init 517ms
Request Payload.Groups Round Trip 517ms
Request Payload.Groups Default To Empty Object 517ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False 517ms
Request Payload.Disable Geoip Omitted Defaults To False 516ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key 516ms
Request Lifecycle.No Flags Request On Init Alone 513ms
Request Lifecycle.No Flags Request On Normal Capture 509ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests 519ms
Request Lifecycle.Mock Response Value Is Returned To Caller 518ms
Retry Behavior.Retries Flags On 502 620ms
Retry Behavior.Retries Flags On 504 619ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event 520ms

@github-actions

github-actions Bot commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

posthog-php-socket Compliance Report

Date: 2026-09-23T10:36:34.522210+00:00
Duration: 147376ms

⚠️ Some Tests Failed

36/47 tests passed, 11 failed


Capture Tests

⚠️ 19/30 tests passed, 11 failed

View Details
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

@posthog

posthog Bot commented Sep 23, 2026

Copy link
Copy Markdown

🦔 PostHog Review reviewed this pull request

Nothing worth raising this time, so here's a calming picture instead:

Someone relaxing in a sunny garden

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@ablaszkiewicz
ablaszkiewicz merged commit 11c9b0d into main Sep 24, 2026
30 checks passed
@ablaszkiewicz
ablaszkiewicz deleted the feat/release-id-env branch September 24, 2026 10:27
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.

2 participants