Repository navigation
ci: reconcile ambiguous release commits and resume partial publication - #316
Conversation
posthog-php-fork_curl Compliance ReportDate: 2026-11-11T13:40:52.007665+00:00
|
| Test | Status | Duration |
|---|---|---|
| Format Validation.Event Has Required Fields | ✅ | 38ms |
| Format Validation.Event Has Uuid | ✅ | 531ms |
| Format Validation.Event Has Lib Properties | ✅ | 532ms |
| Format Validation.Distinct Id Is String | ✅ | 533ms |
| Format Validation.Token Is Present | ✅ | 533ms |
| Format Validation.Custom Properties Preserved | ✅ | 532ms |
| Format Validation.Event Has Timestamp | ✅ | 531ms |
| Format Validation.Non Utc Event Timestamp Is Converted To Utc | ✅ | 533ms |
| Retry Behavior.Retries On 503 | ✅ | 5854ms |
| Retry Behavior.Does Not Retry On 400 | ✅ | 2538ms |
| Retry Behavior.Does Not Retry On 401 | ✅ | 2536ms |
| Retry Behavior.Respects Retry After Header | ❌ | 6350ms |
| Retry Behavior.Implements Backoff | ✅ | 16280ms |
| Retry Behavior.Retries On 500 | ✅ | 5649ms |
| Retry Behavior.Retries On 502 | ✅ | 5651ms |
| Retry Behavior.Retries On 504 | ✅ | 5649ms |
| Retry Behavior.Max Retries Respected | ✅ | 16280ms |
| Deduplication.Generates Unique Uuids | ✅ | 542ms |
| Deduplication.Preserves Uuid On Retry | ✅ | 5647ms |
| Deduplication.Preserves Uuid And Timestamp On Retry | ✅ | 10866ms |
| Deduplication.Preserves Uuid And Timestamp On Batch Retry | ✅ | 5650ms |
| Deduplication.No Duplicate Events In Batch | ✅ | 542ms |
| Deduplication.Different Events Have Different Uuids | ✅ | 534ms |
| Compression.Sends Gzip When Enabled | ✅ | 535ms |
| Batch Format.Uses Proper Batch Structure | ✅ | 532ms |
| Batch Format.Flush With No Events Sends Nothing | ✅ | 520ms |
| Batch Format.Multiple Events Batched Together | ✅ | 522ms |
| Error Handling.Does Not Retry On 403 | ✅ | 2535ms |
| Error Handling.Does Not Retry On 413 | ✅ | 2537ms |
| Error Handling.Retries On 408 | ✅ | 5650ms |
Failures
retry_behavior.respects_retry_after_header
Retry delay too short: 811ms < 2500ms
Feature_Flags Tests
✅ 17/17 tests passed
View Details
| Test | Status | Duration |
|---|---|---|
| Request Payload.Request With Person Properties Device Id | ✅ | 524ms |
| Request Payload.Flags Request Uses V2 Query Param | ✅ | 524ms |
| Request Payload.Flags Request Hits Flags Path Not Decide | ✅ | 523ms |
| Request Payload.Flags Request Omits Authorization Header | ✅ | 524ms |
| Request Payload.Token In Flags Body Matches Init | ✅ | 523ms |
| Request Payload.Groups Round Trip | ✅ | 524ms |
| Request Payload.Groups Default To Empty Object | ✅ | 523ms |
| Request Payload.Disable Geoip False Propagates As Geoip Disable False | ✅ | 523ms |
| Request Payload.Disable Geoip Omitted Defaults To False | ✅ | 524ms |
| Request Payload.Flag Keys To Evaluate Contains Only Requested Key | ✅ | 523ms |
| Request Lifecycle.No Flags Request On Init Alone | ✅ | 519ms |
| Request Lifecycle.No Flags Request On Normal Capture | ✅ | 517ms |
| Request Lifecycle.Two Flag Calls Produce Two Remote Requests | ✅ | 526ms |
| Request Lifecycle.Mock Response Value Is Returned To Caller | ✅ | 525ms |
| Retry Behavior.Retries Flags On 502 | ✅ | 625ms |
| Retry Behavior.Retries Flags On 504 | ✅ | 626ms |
| Side Effect Events.Get Feature Flag Captures Feature Flag Called Event | ✅ | 534ms |
posthog-php-lib_curl Compliance ReportDate: 2026-11-11T13:41:02.711789+00:00
|
| Test | Status | Duration |
|---|---|---|
| Format Validation.Event Has Required Fields | ✅ | 24ms |
| Format Validation.Event Has Uuid | ✅ | 521ms |
| Format Validation.Event Has Lib Properties | ✅ | 521ms |
| Format Validation.Distinct Id Is String | ✅ | 522ms |
| Format Validation.Token Is Present | ✅ | 522ms |
| Format Validation.Custom Properties Preserved | ✅ | 522ms |
| Format Validation.Event Has Timestamp | ✅ | 522ms |
| Format Validation.Non Utc Event Timestamp Is Converted To Utc | ✅ | 521ms |
| Retry Behavior.Retries On 503 | ✅ | 5831ms |
| Retry Behavior.Does Not Retry On 400 | ✅ | 2524ms |
| Retry Behavior.Does Not Retry On 401 | ✅ | 2524ms |
| Retry Behavior.Respects Retry After Header | ❌ | 6331ms |
| Retry Behavior.Implements Backoff | ✅ | 16244ms |
| Retry Behavior.Retries On 500 | ✅ | 5631ms |
| Retry Behavior.Retries On 502 | ✅ | 5626ms |
| Retry Behavior.Retries On 504 | ✅ | 5633ms |
| Retry Behavior.Max Retries Respected | ✅ | 17045ms |
| Deduplication.Generates Unique Uuids | ✅ | 228ms |
| Deduplication.Preserves Uuid On Retry | ✅ | 5629ms |
| Deduplication.Preserves Uuid And Timestamp On Retry | ✅ | 10837ms |
| Deduplication.Preserves Uuid And Timestamp On Batch Retry | ✅ | 5632ms |
| Deduplication.No Duplicate Events In Batch | ✅ | 526ms |
| Deduplication.Different Events Have Different Uuids | ✅ | 523ms |
| Compression.Sends Gzip When Enabled | ✅ | 522ms |
| Batch Format.Uses Proper Batch Structure | ✅ | 523ms |
| Batch Format.Flush With No Events Sends Nothing | ✅ | 518ms |
| Batch Format.Multiple Events Batched Together | ✅ | 510ms |
| Error Handling.Does Not Retry On 403 | ✅ | 2524ms |
| Error Handling.Does Not Retry On 413 | ✅ | 2524ms |
| Error Handling.Retries On 408 | ✅ | 5629ms |
Failures
retry_behavior.respects_retry_after_header
Retry delay too short: 803ms < 2500ms
Feature_Flags Tests
✅ 17/17 tests passed
View Details
| Test | Status | Duration |
|---|---|---|
| Request Payload.Request With Person Properties Device Id | ✅ | 522ms |
| Request Payload.Flags Request Uses V2 Query Param | ✅ | 520ms |
| Request Payload.Flags Request Hits Flags Path Not Decide | ✅ | 520ms |
| Request Payload.Flags Request Omits Authorization Header | ✅ | 520ms |
| Request Payload.Token In Flags Body Matches Init | ✅ | 520ms |
| Request Payload.Groups Round Trip | ✅ | 520ms |
| Request Payload.Groups Default To Empty Object | ✅ | 519ms |
| Request Payload.Disable Geoip False Propagates As Geoip Disable False | ✅ | 520ms |
| Request Payload.Disable Geoip Omitted Defaults To False | ✅ | 520ms |
| Request Payload.Flag Keys To Evaluate Contains Only Requested Key | ✅ | 520ms |
| Request Lifecycle.No Flags Request On Init Alone | ✅ | 516ms |
| Request Lifecycle.No Flags Request On Normal Capture | ✅ | 508ms |
| Request Lifecycle.Two Flag Calls Produce Two Remote Requests | ✅ | 522ms |
| Request Lifecycle.Mock Response Value Is Returned To Caller | ✅ | 521ms |
| Retry Behavior.Retries Flags On 502 | ✅ | 623ms |
| Retry Behavior.Retries Flags On 504 | ✅ | 622ms |
| Side Effect Events.Get Feature Flag Captures Feature Flag Called Event | ✅ | 521ms |
posthog-php-socket Compliance ReportDate: 2026-11-11T13:41:04.512087+00:00
|
| Test | Status | Duration |
|---|---|---|
| Format Validation.Event Has Required Fields | ✅ | 25ms |
| Format Validation.Event Has Uuid | ✅ | 520ms |
| Format Validation.Event Has Lib Properties | ✅ | 522ms |
| Format Validation.Distinct Id Is String | ✅ | 522ms |
| Format Validation.Token Is Present | ✅ | 522ms |
| Format Validation.Custom Properties Preserved | ✅ | 522ms |
| Format Validation.Event Has Timestamp | ✅ | 523ms |
| Format Validation.Non Utc Event Timestamp Is Converted To Utc | ✅ | 522ms |
| Retry Behavior.Retries On 503 | ✅ | 5830ms |
| Retry Behavior.Does Not Retry On 400 | ✅ | 2524ms |
| Retry Behavior.Does Not Retry On 401 | ✅ | 2524ms |
| Retry Behavior.Respects Retry After Header | ❌ | 6330ms |
| Retry Behavior.Implements Backoff | ✅ | 16245ms |
| Retry Behavior.Retries On 500 | ✅ | 5631ms |
| Retry Behavior.Retries On 502 | ✅ | 5630ms |
| Retry Behavior.Retries On 504 | ✅ | 5628ms |
| Retry Behavior.Max Retries Respected | ✅ | 16244ms |
| Deduplication.Generates Unique Uuids | ✅ | 528ms |
| Deduplication.Preserves Uuid On Retry | ✅ | 5630ms |
| Deduplication.Preserves Uuid And Timestamp On Retry | ✅ | 10836ms |
| Deduplication.Preserves Uuid And Timestamp On Batch Retry | ✅ | 5633ms |
| Deduplication.No Duplicate Events In Batch | ✅ | 526ms |
| Deduplication.Different Events Have Different Uuids | ✅ | 524ms |
| Compression.Sends Gzip When Enabled | ✅ | 522ms |
| Batch Format.Uses Proper Batch Structure | ✅ | 522ms |
| Batch Format.Flush With No Events Sends Nothing | ✅ | 519ms |
| Batch Format.Multiple Events Batched Together | ✅ | 511ms |
| Error Handling.Does Not Retry On 403 | ✅ | 2523ms |
| Error Handling.Does Not Retry On 413 | ✅ | 2523ms |
| Error Handling.Retries On 408 | ✅ | 5632ms |
Failures
retry_behavior.respects_retry_after_header
Retry delay too short: 802ms < 2500ms
Feature_Flags Tests
✅ 17/17 tests passed
View Details
| Test | Status | Duration |
|---|---|---|
| Request Payload.Request With Person Properties Device Id | ✅ | 522ms |
| Request Payload.Flags Request Uses V2 Query Param | ✅ | 520ms |
| Request Payload.Flags Request Hits Flags Path Not Decide | ✅ | 520ms |
| Request Payload.Flags Request Omits Authorization Header | ✅ | 520ms |
| Request Payload.Token In Flags Body Matches Init | ✅ | 520ms |
| Request Payload.Groups Round Trip | ✅ | 520ms |
| Request Payload.Groups Default To Empty Object | ✅ | 520ms |
| Request Payload.Disable Geoip False Propagates As Geoip Disable False | ✅ | 521ms |
| Request Payload.Disable Geoip Omitted Defaults To False | ✅ | 520ms |
| Request Payload.Flag Keys To Evaluate Contains Only Requested Key | ✅ | 520ms |
| Request Lifecycle.No Flags Request On Init Alone | ✅ | 517ms |
| Request Lifecycle.No Flags Request On Normal Capture | ✅ | 508ms |
| Request Lifecycle.Two Flag Calls Produce Two Remote Requests | ✅ | 523ms |
| Request Lifecycle.Mock Response Value Is Returned To Caller | ✅ | 521ms |
| Retry Behavior.Retries Flags On 502 | ✅ | 623ms |
| Retry Behavior.Retries Flags On 504 | ✅ | 622ms |
| Side Effect Events.Get Feature Flag Captures Feature Flag Called Event | ✅ | 523ms |
PR overviewNo security issues were found in this pull request. Reviews
|
marandaneto
left a comment
There was a problem hiding this comment.
Approved to unblock but left a few comments
| - '.changeset/*.md' | ||
| workflow_dispatch: | ||
| inputs: | ||
| resume_run_id: |
There was a problem hiding this comment.
I think we should use the version instead, wdyt
There was a problem hiding this comment.
🤖 An AI agent wrote this on behalf of @ioannisj.
Keeping the run id. The approved candidate only exists as an artifact of the failed run, so that's what the resume downloads, and the run URL is already in the failure Slack message and the RELEASING.md recipe.
A version would need an extra job that lists Release runs and pulls candidates until one matches, and it'd have to say which version too (PHP 4.23.1 or Laravel 0.4.1). I think we can add a resume_version input as a follow-up convenience.
| name: Resume publication | ||
| needs: resume-check | ||
| runs-on: ubuntu-latest | ||
| environment: Release |
There was a problem hiding this comment.
Does this require another approval?
Should we instead patch the release to allow rerunning the failed task, we do this for other sdks, i wonder why this one is a separate workflow
There was a problem hiding this comment.
🤖 An AI agent wrote this on behalf of @ioannisj.
Yes, one Release approval, the same gate the publish job already has. It's not a separate workflow either, resume-publication sits in the same release.yml and is only reached through the resume_run_id input.
Rerunning the failed job doesn't work here because the recheck at .github/workflows/release.yml:312 requires main to still equal the original source SHA, and the job's own version commit 82cd1d0 moved main, so a rerun fails before publishing anything. iOS gets away with gh run rerun --failed because the environment is only on version-bump and the publish steps are separate jobs. Here the two-repo publish is one job on purpose so PHP and Laravel land together.
Splitting it like iOS for example is a bigger refactor and gives up that atomicity, so I went with the smaller fix given the artifact expires on the 16th. Open to the split as a follow-up if it's worth it.
💡 Motivation and Context
Release run 43015053422 published PHP 4.23.1 and then stopped halfway through Laravel 0.4.1. GitHub applied the
createCommitOnBranchmutation for the distribution commit and answered with an HTTP 502, soscripts/commit_release.pytreated it as a failure and the job never reached the two Laravel releases. The commit itself is on posthog-laravel main, signed, and byte-identical to the approved archive.There was no way to finish it by hand. Rerunning the job fails the freshness check because main now carries the version bump commit, and the tag rulesets on both repos let only the releaser App create release tags.
Makes the workflow able to finish such a run on its own:
scripts/commit_release.pyreconciles after a failed mutation. It re-reads the destination branch and accepts the new head only if it is a GitHub-verified, single-parent child of the expected head whose diff is exactly the requested file changes. The mutation is never sent twice.release.ymlgets aresume_run_iddispatch input. A read-only job validates the resumed run and its candidate artifact, finds the shared version commit (source tree plusrelease.patch, App-signed) and reports which refs already exist. A job under the Release environment then completes only what is missing, check-then-create, with the same three App tokens and the same revoke-before-Composer order. Existing tags and releases are verified, never recreated or moved.scripts/check-release-refs.shgets a resume mode. The default mode is unchanged.Two things I left for follow-ups: the resume job repeats about a dozen steps of the release job and could share a composite action, and the reconciliation branch has no in-repo test yet.
💚 How did you test it?
python3 -m py_compileon both release scripts,actionlintwith shellcheck onrelease.yml,shellcheckon the three shell scripts.ghsuite against the real 0.4.1 candidate and real clones, 10 of 10 pass. A 502 with a matching landed head reuses it, in both distribution and source mode. A changed tree, an unchanged head, an unverified head, and a head that is not a child of the expected head all fail with the original error.scripts/find-version-commit.shreturns the real version commit 82cd1d0, the refs check reports core present and both Laravel refs missing, the Packagist wait pluscomposer install --no-devpass, and a fresh posthog-laravel clone takes the no-diff path and reuses 15105e02 without a mutation.gh workflow run release.yml --ref main -f resume_run_id=43015053422after this merges, before the candidate artifact expires on 2026-11-16.📝 Checklist
If releasing new changes
pnpm changeto generate a change intent file🤖 Agent context
DRI: @ioannisj
Autonomy: Human-driven (agent-assisted)