Skip to content

fix: omit null custom event property members - #241

Draft
marandaneto wants to merge 3 commits into
mainfrom
fix/null-property-serialization-sqq3ojkm
Draft

fix: omit null custom event property members#241
marandaneto wants to merge 3 commits into
mainfrom
fix/null-property-serialization-sqq3ojkm

Conversation

@marandaneto

@marandaneto marandaneto commented Sep 9, 2026

Copy link
Copy Markdown
Member

💡 Motivation and Context

Custom event properties currently keep null object members in outgoing batches and saved events. This implements the null-property policy from sdk-specs #60 at the PHP event serialization boundary.

The serializer removes null custom-property members recursively after PHP resolves JsonSerializable values. It keeps array positions, empty objects, non-null values, caller data, and event-scoped exception and feature-flag metadata. File persistence, restored NDJSON, and CLI properties use the same object-preserving decoder, including NUL-prefixed keys. send.php accepts an optional host without changing its default. The public API snapshot adds only the two internal helpers. No dependencies or existing public signatures change.

💚 How did you test it?

Fresh checks on PHP 8.5.10 at 8883f6e64677fa72600d1064f7b3b388bdb2a836:

  • 22 focused serialization and numeric-loopback tests passed with 1,271 assertions. These exercise immediate and queued plain/gzip batches, actual File persistence, historical NDJSON, real sender and CLI subprocesses, hooks, generated null flag metadata, NUL keys, empty objects, array slots, caller preservation, and encode/decode failures. SDK requests use fake keys, mocked HTTP or guarded numeric loopback. The default-host negative control is denied before transport.
  • Seven selected queue controls passed with 25 assertions. Six selected flag privacy controls passed with 15 assertions. Existing SDK/PHPUnit deprecations remain.
  • Both actual mocked event/flags snapshot tests passed with 11 assertions. Initial CI on PHP 8.2-8.5 found two stale expected null custom members in the event snapshot. The same failure was reproduced locally before removing only those two expectations. The null inputs and the unrelated flags request snapshot remain unchanged.
  • Affected PHP_CodeSniffer and 12 syntax checks passed. The public API snapshot is current, and every prior symbol/signature is unchanged.
  • Required isolated committed-head autoreview against current origin/main completed with TruffleHog clean and no findings.

Final SHA-bound CI: all 21 checks passed on 8883f6e64677fa72600d1064f7b3b388bdb2a836, including hosted PHPUnit on PHP 8.2, 8.3, 8.4, and 8.5. No failed or pending checks remained at the final poll.

This is a draft for human review, not release or universal conformance approval. The unsafe original full suite, ForkCurl gzip/background paths, minimum PHP runtime matrix, and performance checks were not run locally. Synchronous uncompressed ForkCurl was tested only through the guarded loopback fixture. Earlier audit runs had external file/ingestion/temp safety incidents whose prior state remains unknown. This continuation did not repeat or clean up those incidents. Shared compliance-harness gaps remain separate and passing CI does not establish complete null-policy conformance.

📝 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

A posthog-php: patch intent was written manually in the existing .changeset format. No package manager, installation, lifecycle script, version bump, or release command was run.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Pi implemented and validated this change using Git, PHP/PHPUnit, PHP_CodeSniffer, the API checker, GitHub CLI, and the installed isolated autoreview helper. The human DRI is @marandaneto. No shareable session link is available.

The work keeps normalization at the existing event serialization boundary instead of adding caller-side filtering or a blanket metadata exemption. Native PHP encoding remains authoritative for custom serializers and rejection of invalid inputs. Human review is required. This draft must not be auto-merged or released by the agent.

@marandaneto marandaneto self-assigned this Sep 9, 2026
@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

posthog-php Compliance Report

Date: 2026-09-09 11:01:37 UTC
Duration: 95342ms

✅ All Tests Passed!

46/46 tests passed


Capture Tests

29/29 tests passed

View Details
Test Status Duration
Format Validation.Event Has Required Fields 13ms
Format Validation.Event Has Uuid 6ms
Format Validation.Event Has Lib Properties 7ms
Format Validation.Distinct Id Is String 6ms
Format Validation.Token Is Present 6ms
Format Validation.Custom Properties Preserved 7ms
Format Validation.Event Has Timestamp 6ms
Retry Behavior.Retries On 503 5316ms
Retry Behavior.Does Not Retry On 400 2010ms
Retry Behavior.Does Not Retry On 401 2009ms
Retry Behavior.Respects Retry After Header 8015ms
Retry Behavior.Implements Backoff 15728ms
Retry Behavior.Retries On 500 5115ms
Retry Behavior.Retries On 502 5115ms
Retry Behavior.Retries On 504 5115ms
Retry Behavior.Max Retries Respected 16530ms
Deduplication.Generates Unique Uuids 12ms
Deduplication.Preserves Uuid On Retry 5114ms
Deduplication.Preserves Uuid And Timestamp On Retry 10314ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry 5117ms
Deduplication.No Duplicate Events In Batch 12ms
Deduplication.Different Events Have Different Uuids 8ms
Compression.Sends Gzip When Enabled 6ms
Batch Format.Uses Proper Batch Structure 6ms
Batch Format.Flush With No Events Sends Nothing 4ms
Batch Format.Multiple Events Batched Together 10ms
Error Handling.Does Not Retry On 403 2008ms
Error Handling.Does Not Retry On 413 2010ms
Error Handling.Retries On 408 5115ms

Feature_Flags Tests

17/17 tests passed

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

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.

1 participant