Skip to content

feat: add opt-in Laravel autocapture - #284

Draft
marandaneto wants to merge 14 commits into
feat/laravel-package-runtimefrom
feat/laravel-autocapture
Draft

marandaneto wants to merge 14 commits into
feat/laravel-package-runtimefrom
feat/laravel-autocapture

Conversation

@marandaneto

@marandaneto marandaneto commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

💡 Motivation and Context

Stacked on the Laravel runtime PR #283. This adds optional server-side collection without changing the PHP SDK's capture pipeline.

The package can collect request summaries, a separate server pageview mode, auth lifecycle events, explicitly mapped domain events, allowlisted model changes after commit, and job/command/scheduler outcomes. Every category defaults off. Model and domain data is explicitly selected. HTTP metadata uses route templates, not concrete parameters or query strings. Automatic events preserve identity, session and groups without copying arbitrary context properties.

The optional Blade conditional reuses native flag snapshots and exposure behavior. Collector events use ordinary laravel_* names, not UI $autocapture. The canonical autocapture spec is client-only. The public server schemas and limits are documented in AUTOCAPTURE.md.

Background schedules record launch, not cross-process completion or missed-schedule monitoring. Model collection is not a durable outbox. Browser pageviews must not be enabled alongside equivalent server pageviews.

💚 How did you test it?

  • 17 collector tests cover safe defaults, credential/URL filtering, identity/session correlation, publication of config, per-category exclusions, sampling, exact event/model allowlists, nested transactions and rollbacks, duplicate terminal events, failure preservation and flag exposure deduplication.
  • Integrated runtime plus collectors: 81 tests, 515 assertions on Laravel 13.
  • Full-stack Laravel 12 and 13 tests also pass through the temporary-source test helper in the final tooling PR.
  • PSR-12, syntax checks and git diff --check pass.
  • The URL privacy test constructs synthetic credentials at runtime to avoid a secret scanner treating a literal credential-bearing test URL as an unknown live credential. The credential-removal assertion remains in place. No real credential was used.
  • Initial isolated review reports no actionable findings. It caught explicit fail() jobs being labeled successful; a real sync-job regression failed before the fix and now passes.

📝 Checklist

  • All commits are signed.
  • 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

  • Recorded a Laravel-only initial release intent in .laravel-changes/.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Implemented with Pi, PHP/Composer, Git and GitHub CLI. Collectors were developed in an isolated worktree and integrated with the runtime lifecycle fixes using signed merge commits. Tests use framework events, SQLite transactions and mocked SDK traffic, not a live PostHog project. This is original integration code. Human review is required before merge.

Reviewed commit: 0e3243ee46def0be86f153169bc24d31876936d4. Reviewed base: 3b2ad5a8904fe7baa5d3e849dbce41bb3509d00a. Initial isolated review has no actionable findings.

Stack

Merge bottom-up:

  1. feat: add PHP framework integration primitives #282: PHP framework support
  2. feat: add the Laravel runtime package #283: Laravel runtime
  3. feat: add opt-in Laravel autocapture #284: Optional server autocapture
  4. feat: integrate PostHog feature flags with Laravel Pennant #285: Read-only Pennant integration
  5. feat: add a runnable Laravel SDK example #286: Runnable Laravel example
  6. ci: release the Laravel package independently #287: Independent CI and publishing

Laravel source lives in this repository but its Composer package is released separately. Publish core ^4.20 first. The distribution repository, protected release environment and Packagist setup remain administrator prerequisites. No release has been published.

Review feedback follow-up

Current head: 8ffd0ad16ce8368a8687b7f2411e661b24f28ac6.

Model events use connection-correct transaction records, aggregate 1,000-event/1 MiB encoded admission limits, bounded batch callbacks, and immutable snapshots. Rollback, PDO-reset/disconnect, reentrant commit callbacks and Laravel 12 same-PDO commit-time retries are covered. Scheduler outcomes omit overlap-lock acquisition skips using weak, once-per-task execution markers supported since Laravel 12.0.

Runtime plus collectors: 81 tests / 515 assertions. Final clean-source Laravel 12/13 stack (PHP 8.5 locally): 106 package tests / 664 assertions and 29 example tests / 163 assertions per version. New real schedule:run cases and observable transaction/callback admission checks failed before their fixes. Independent review caught the commit-time retry capacity edge; its Laravel 12 regression failed before and passed after correction.

All three collector review concerns addressed. No public budget configuration or new skipped outcome was added; delivery remains best-effort, not a durable outbox.

Core human-review integration

Signed merges integrate #282 commit 858c204: non-throwing instance group validation (static facade validation unchanged), explicit typed exception source independent of mechanism/handled, provenance protection and scope ownership docs. The core suite passes 2,532 tests / 11,366 assertions. Final committed-source Laravel 12/13 matrices remain green at 106 package tests / 664 assertions and 29 example tests / 163 assertions each. The core delta received a clean isolated review; no automatic Laravel hook-source inference was added.

Before the first Laravel release: server SDK registration

posthog-laravel is not yet registered on PostHog server master for PHP usage attribution, Python/Rust feature-flag library classification/parser, or SDK health frontend/backend registries. A separate backend registration/alias PR must land before the Laravel package ships, following the approach in PostHog/posthog#93911. Event ingestion itself is not rejected just because this library identifier is unclassified. SDK health/version handling must respect Laravel's independent package version, not compare 0.1.x against PHP core 4.x. No backend PR, repository or release was created by this SDK follow-up; this remains an explicit pre-release prerequisite alongside core ^4.20 publication and distribution/Packagist setup.

@posthog posthog Bot 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.

PostHog Review · Standard · reviewed 0e3243e: 3 Should fix.

This is the only automatic review while this pull request is a draft. Comment @posthog review to review new changes sooner. Otherwise, a review of the new changes runs when you mark it ready for review.

See this review and its findings in PostHog Review. Comment @posthog review --deep for a Deep review. A Deep review takes longer and looks deeper than a Standard review.

@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

posthog-php-fork_curl Compliance Report

Date: 2026-10-29T16:11:16.645514+00:00
Duration: 116195ms

⚠️ Some Tests Failed

46/47 tests passed, 1 failed


Capture Tests

⚠️ 29/30 tests passed, 1 failed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 30ms
Format Validation.Event Has Uuid ✅ 525ms
Format Validation.Event Has Lib Properties ✅ 527ms
Format Validation.Distinct Id Is String ✅ 527ms
Format Validation.Token Is Present ✅ 527ms
Format Validation.Custom Properties Preserved ✅ 527ms
Format Validation.Event Has Timestamp ✅ 526ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 529ms
Retry Behavior.Retries On 503 ✅ 5849ms
Retry Behavior.Does Not Retry On 400 ✅ 2530ms
Retry Behavior.Does Not Retry On 401 ✅ 2529ms
Retry Behavior.Respects Retry After Header ❌ 6341ms
Retry Behavior.Implements Backoff ✅ 16272ms
Retry Behavior.Retries On 500 ✅ 5643ms
Retry Behavior.Retries On 502 ✅ 5642ms
Retry Behavior.Retries On 504 ✅ 5642ms
Retry Behavior.Max Retries Respected ✅ 16272ms
Deduplication.Generates Unique Uuids ✅ 536ms
Deduplication.Preserves Uuid On Retry ✅ 5643ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10857ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5644ms
Deduplication.No Duplicate Events In Batch ✅ 531ms
Deduplication.Different Events Have Different Uuids ✅ 530ms
Compression.Sends Gzip When Enabled ✅ 534ms
Batch Format.Uses Proper Batch Structure ✅ 526ms
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 ✅ 5643ms

Failures

retry_behavior.respects_retry_after_header

Retry delay too short: 810ms < 2500ms

Feature_Flags Tests

✅ 17/17 tests passed

View Details
Test Status Duration
Request Payload.Request With Person Properties Device Id ✅ 519ms
Request Payload.Flags Request Uses V2 Query Param ✅ 520ms
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 ✅ 519ms
Request Payload.Groups Default To Empty Object ✅ 519ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 519ms
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 ✅ 515ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 514ms
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 ✅ 621ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 529ms

@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

posthog-php-lib_curl Compliance Report

Date: 2026-10-29T16:11:06.594859+00:00
Duration: 116329ms

⚠️ Some Tests Failed

46/47 tests passed, 1 failed


Capture Tests

⚠️ 29/30 tests passed, 1 failed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 21ms
Format Validation.Event Has Uuid ✅ 518ms
Format Validation.Event Has Lib Properties ✅ 519ms
Format Validation.Distinct Id Is String ✅ 518ms
Format Validation.Token Is Present ✅ 519ms
Format Validation.Custom Properties Preserved ✅ 518ms
Format Validation.Event Has Timestamp ✅ 518ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 520ms
Retry Behavior.Retries On 503 ✅ 5823ms
Retry Behavior.Does Not Retry On 400 ✅ 2522ms
Retry Behavior.Does Not Retry On 401 ✅ 2522ms
Retry Behavior.Respects Retry After Header ❌ 6328ms
Retry Behavior.Implements Backoff ✅ 16241ms
Retry Behavior.Retries On 500 ✅ 5629ms
Retry Behavior.Retries On 502 ✅ 5630ms
Retry Behavior.Retries On 504 ✅ 5642ms
Retry Behavior.Max Retries Respected ✅ 17041ms
Deduplication.Generates Unique Uuids ✅ 224ms
Deduplication.Preserves Uuid On Retry ✅ 5628ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10832ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5632ms
Deduplication.No Duplicate Events In Batch ✅ 524ms
Deduplication.Different Events Have Different Uuids ✅ 521ms
Compression.Sends Gzip When Enabled ✅ 520ms
Batch Format.Uses Proper Batch Structure ✅ 520ms
Batch Format.Flush With No Events Sends Nothing ✅ 516ms
Batch Format.Multiple Events Batched Together ✅ 509ms
Error Handling.Does Not Retry On 403 ✅ 2522ms
Error Handling.Does Not Retry On 413 ✅ 2522ms
Error Handling.Retries On 408 ✅ 5630ms

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 ✅ 517ms
Request Payload.Flags Request Uses V2 Query Param ✅ 555ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 515ms
Request Payload.Flags Request Omits Authorization Header ✅ 517ms
Request Payload.Token In Flags Body Matches Init ✅ 530ms
Request Payload.Groups Round Trip ✅ 516ms
Request Payload.Groups Default To Empty Object ✅ 517ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 518ms
Request Payload.Disable Geoip Omitted Defaults To False ✅ 517ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 517ms
Request Lifecycle.No Flags Request On Init Alone ✅ 514ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 508ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 520ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 519ms
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 Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

posthog-php-socket Compliance Report

Date: 2026-10-29T16:10:46.250558+00:00
Duration: 116260ms

⚠️ Some Tests Failed

46/47 tests passed, 1 failed


Capture Tests

⚠️ 29/30 tests passed, 1 failed

View Details
Test Status Duration
Format Validation.Event Has Required Fields ✅ 31ms
Format Validation.Event Has Uuid ✅ 523ms
Format Validation.Event Has Lib Properties ✅ 529ms
Format Validation.Distinct Id Is String ✅ 527ms
Format Validation.Token Is Present ✅ 529ms
Format Validation.Custom Properties Preserved ✅ 526ms
Format Validation.Event Has Timestamp ✅ 525ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 527ms
Retry Behavior.Retries On 503 ✅ 5835ms
Retry Behavior.Does Not Retry On 400 ✅ 2528ms
Retry Behavior.Does Not Retry On 401 ✅ 2528ms
Retry Behavior.Respects Retry After Header ❌ 6338ms
Retry Behavior.Implements Backoff ✅ 16252ms
Retry Behavior.Retries On 500 ✅ 5637ms
Retry Behavior.Retries On 502 ✅ 5632ms
Retry Behavior.Retries On 504 ✅ 5635ms
Retry Behavior.Max Retries Respected ✅ 16246ms
Deduplication.Generates Unique Uuids ✅ 539ms
Deduplication.Preserves Uuid On Retry ✅ 5636ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10842ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5639ms
Deduplication.No Duplicate Events In Batch ✅ 532ms
Deduplication.Different Events Have Different Uuids ✅ 527ms
Compression.Sends Gzip When Enabled ✅ 527ms
Batch Format.Uses Proper Batch Structure ✅ 525ms
Batch Format.Flush With No Events Sends Nothing ✅ 521ms
Batch Format.Multiple Events Batched Together ✅ 514ms
Error Handling.Does Not Retry On 403 ✅ 2529ms
Error Handling.Does Not Retry On 413 ✅ 2529ms
Error Handling.Retries On 408 ✅ 5633ms

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 ✅ 525ms
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 ✅ 525ms
Request Payload.Groups Round Trip ✅ 524ms
Request Payload.Groups Default To Empty Object ✅ 522ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 525ms
Request Payload.Disable Geoip Omitted Defaults To False ✅ 522ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 523ms
Request Lifecycle.No Flags Request On Init Alone ✅ 518ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 510ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 528ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 528ms
Retry Behavior.Retries Flags On 502 ✅ 627ms
Retry Behavior.Retries Flags On 504 ✅ 627ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 527ms

This branch has not been deployed

No deployments
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