Skip to content

feat: add the Laravel runtime package - #283

Open
marandaneto wants to merge 26 commits into
mainfrom
feat/laravel-package-runtime
Open

marandaneto wants to merge 26 commits into
mainfrom
feat/laravel-package-runtime

Conversation

@marandaneto

@marandaneto marandaneto commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

💡 Motivation and Context

Add the independently versioned posthog/posthog-laravel package under packages/laravel. It depends on the already-published PHP SDK ^4.20. Core framework support landed in #282 and was released in 4.20.0. This branch now includes current main, so the PR no longer repeats those core implementation changes.

Composer discovery registers scoped services, a facade and an injectable core client. The package adds lazy SDK construction, authenticated/header analytics context, safe route metadata, bounded queue propagation, Laravel exception reporting, request-scoped flag snapshots, an optional Laravel Cache definition provider, diagnostics and a test fake.

Public API boundary

The supported surface is the manager/facade, documented Context APIs, the IsolatesCommandContext trait, test fake, service provider registration and the Laravel cache adapter. Framework-only classes are marked @internal and are final where appropriate. Public framework callback methods are not supported customer extension points.

The manager declares supported client conveniences explicitly instead of forwarding arbitrary methods through __call(). These include the five legacy flag getters, loadFlags() and contextFromHeaders(). Legacy getters inherit current context groups when no nonempty groups argument is supplied, consistently with evaluateFlags(). Explicit nonempty groups override the ambient groups. Other lower-level operations remain available through client(). The new api/laravel-public-api.json snapshot tracks the Laravel API separately from core and excludes internal classes and members. CI checks both snapshots and runs the Laravel tests.

Lifecycles and exceptions

HTTP context remains active through kernel termination and after-response callbacks. Queue and sequential Octane boundaries flush and clean context. Console integration decorates the application's existing kernel and restores nested kernel calls in finally.

Direct child-command call(), callSilent() and callSilently() isolation is opt-in: apply PostHog\Laravel\Concerns\IsolatesCommandContext to the calling command or the application's base command. Uninstrumented callers, including closure commands, still need kernel-level Artisan::call() or an explicit context scope. There is no global command interception, vendor patching or reflection-based wrapping.

Automatic exception reporting reuses captureException() inside a fresh saved-context scope. It preserves the original identity, groups and boundary metadata without a second reportException() API. Automatic reports of the same exception object are deduplicated. Laravel retains ownership of PHP handlers and exception-reporting policy.

Known hooks supply stable $exception_source values: laravel.middleware, laravel.queue_job, laravel.console_lifecycle and laravel.octane_worker_error. The registered reportable callback supplies laravel.reportable when no earlier source was remembered. Sources are not inferred from stack frames. Ordinary manual captures and direct reporter calls with no known hook omit the source. Later boundaries do not overwrite an earlier known source.

Safety and compatibility

Missing credentials and explicit disablement prevent SDK network paths. Defaults exclude raw URLs, query strings, bodies, cookies, email, visitor IP and implicit profile synchronization. GeoIP defaults off. PostHog tracing headers and queue metadata are untrusted analytics context, never authentication or authorization evidence.

Custom HTTP kernels without Laravel's lifecycle callback API cannot provide automatic after-response correlation. Overlapping shared-container Swoole coroutines are not supported. Do not retain scoped services in application singletons or prewarm them in Octane.

Capture, identify, alias, groups, exception metadata, feature-flag evaluation and tracing-header contracts reuse the PHP SDK. The core's pre-existing wire behavior outside the integration changes is not changed by this PR.

Core distribution boundary

The root .gitattributes excludes packages/laravel/ from core Composer archives. Laravel source remains available in Git and is not registered by the core autoloader. An archive regression test confirms the exclusion while retaining the core manifest, runtime and root license. The test failed before the attribute was added and passes afterward.

Source-copy tools must use a full Git checkout rather than a whole-repository git archive, which now excludes Laravel. The helper in the later tooling PR #287 needs that adjustment before it lands. Core release versioning remains scoped to the root package.

💚 How did you test it?

  • PHP 8.5.10: core suite passes 2,534 tests / 11,379 assertions.
  • Laravel runtime suite passes 67 tests / 452 assertions on both Laravel 12 and 13. Clean dependency installs use the published PHP SDK 4.20.0.
  • Before/after regressions verify that automatic reports use captureException(), preserve context through failures, and attach known source metadata without leaking it into manual captures.
  • Before/after API tests verify that internal and future core methods are not exposed automatically. Supported flag methods preserve named arguments and restore core context. Five inherited-group cases and a real-core HTTP payload regression failed before the ambient-group fix and pass afterward.
  • Snapshot filtering tests verify that internal classes and members are excluded only for the Laravel snapshot. A deliberate stale-snapshot mutation is rejected by the checker. The core snapshot is unchanged.
  • Existing tests cover real HTTP termination, late callbacks, nested Artisan commands, queue failures, user-context isolation, Octane sandbox events, local definitions, disabled clients and fakes.
  • Scoped PHP_CodeSniffer, actionlint, Composer validation, both API snapshot checks and git diff --check pass.
  • The runtime/API closeout at d172504cf848badbb6d34936c61a2b0c0fd80066 received a clean isolated review after its ambient-group finding was reproduced and fixed in a separate signed commit. The archive closeout at 4837e6877a5847e1e3ae6ffae6642df282492c0b also received a clean isolated review.

📝 Checklist

  • All commits are signed.
  • Reviewed the submitted code and retained regression tests.
  • Updated documentation for the public API and exception provenance.
  • Added separate Laravel API snapshot checks and test execution to CI.
  • Removed the already-consumed core release intent.
  • Removed the Laravel initial-release intent for now. This PR does not publish a Laravel release.

🤖 Agent context

Autonomy: Human-driven (agent-assisted).

Implemented and validated with Pi, PHP/Composer, Git and GitHub CLI in the existing dedicated runtime worktree. The user requested the API naming changes, reporting consolidation, internal API restrictions, explicit forwarding, API snapshot coverage, shared-license symlink and removal of release intents. Human review is still required before merge.

Stack

Merge bottom-up:

  1. feat: add PHP framework integration primitives #282: PHP framework support. Merged and released in PHP 4.20.0.
  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. packages/laravel/LICENSE.md is a relative symlink to the repository's shared license. The later distribution tooling must materialize that file when exporting a standalone package.

Before the first Laravel release

posthog-laravel still needs server registration/aliases for PHP usage attribution, Python/Rust feature-flag library classification/parsing, and SDK health registries, following PostHog/posthog#93911. Its independent 0.1.x package version must not be compared against PHP core 4.x. Event ingestion is not rejected solely because the library identifier is unclassified.

The distribution repository, protected release environment and Packagist setup remain administrator prerequisites. Release intents and the standalone publisher belong with the release tooling, not this runtime PR. No Laravel release has been published.

@marandaneto marandaneto self-assigned this Oct 29, 2026
@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

posthog-php-fork_curl Compliance Report

Date: 2026-10-30T13:05:31.195709+00:00
Duration: 115991ms

⚠️ 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 ✅ 37ms
Format Validation.Event Has Uuid ✅ 529ms
Format Validation.Event Has Lib Properties ✅ 531ms
Format Validation.Distinct Id Is String ✅ 531ms
Format Validation.Token Is Present ✅ 531ms
Format Validation.Custom Properties Preserved ✅ 531ms
Format Validation.Event Has Timestamp ✅ 531ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 532ms
Retry Behavior.Retries On 503 ✅ 5852ms
Retry Behavior.Does Not Retry On 400 ✅ 2534ms
Retry Behavior.Does Not Retry On 401 ✅ 2536ms
Retry Behavior.Respects Retry After Header ❌ 6349ms
Retry Behavior.Implements Backoff ✅ 16275ms
Retry Behavior.Retries On 500 ✅ 5644ms
Retry Behavior.Retries On 502 ✅ 5647ms
Retry Behavior.Retries On 504 ✅ 5649ms
Retry Behavior.Max Retries Respected ✅ 16271ms
Deduplication.Generates Unique Uuids ✅ 43ms
Deduplication.Preserves Uuid On Retry ✅ 5642ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10863ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5647ms
Deduplication.No Duplicate Events In Batch ✅ 538ms
Deduplication.Different Events Have Different Uuids ✅ 532ms
Compression.Sends Gzip When Enabled ✅ 533ms
Batch Format.Uses Proper Batch Structure ✅ 531ms
Batch Format.Flush With No Events Sends Nothing ✅ 519ms
Batch Format.Multiple Events Batched Together ✅ 520ms
Error Handling.Does Not Retry On 403 ✅ 2532ms
Error Handling.Does Not Retry On 413 ✅ 2532ms
Error Handling.Retries On 408 ✅ 5646ms

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 ✅ 524ms
Request Payload.Flags Request Uses V2 Query Param ✅ 522ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 522ms
Request Payload.Flags Request Omits Authorization Header ✅ 523ms
Request Payload.Token In Flags Body Matches Init ✅ 523ms
Request Payload.Groups Round Trip ✅ 522ms
Request Payload.Groups Default To Empty Object ✅ 522ms
Request Payload.Disable Geoip False Propagates As Geoip Disable False ✅ 522ms
Request Payload.Disable Geoip Omitted Defaults To False ✅ 522ms
Request Payload.Flag Keys To Evaluate Contains Only Requested Key ✅ 522ms
Request Lifecycle.No Flags Request On Init Alone ✅ 520ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 516ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 528ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 523ms
Retry Behavior.Retries Flags On 502 ✅ 624ms
Retry Behavior.Retries Flags On 504 ✅ 626ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 532ms

@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 3b2ad5a: 7 Should fix. This pull request is large, so the review ran in 4 parts with less depth than usual.

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.

Comment thread packages/laravel/src/ConsoleKernel.php Resolved
Comment thread packages/laravel/src/PostHog.php Resolved
Comment thread packages/laravel/src/Context.php Resolved
Comment thread packages/laravel/src/PostHog.php Resolved
Comment thread packages/laravel/src/PostHog.php Resolved
Comment thread packages/laravel/src/PostHog.php Resolved
@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

posthog-php-socket Compliance Report

Date: 2026-10-30T13:05:39.054141+00:00
Duration: 115922ms

⚠️ 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 ✅ 24ms
Format Validation.Event Has Uuid ✅ 520ms
Format Validation.Event Has Lib Properties ✅ 521ms
Format Validation.Distinct Id Is String ✅ 522ms
Format Validation.Token Is Present ✅ 521ms
Format Validation.Custom Properties Preserved ✅ 522ms
Format Validation.Event Has Timestamp ✅ 521ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 521ms
Retry Behavior.Retries On 503 ✅ 5830ms
Retry Behavior.Does Not Retry On 400 ✅ 2523ms
Retry Behavior.Does Not Retry On 401 ✅ 2525ms
Retry Behavior.Respects Retry After Header ❌ 6327ms
Retry Behavior.Implements Backoff ✅ 16243ms
Retry Behavior.Retries On 500 ✅ 5633ms
Retry Behavior.Retries On 502 ✅ 5629ms
Retry Behavior.Retries On 504 ✅ 5631ms
Retry Behavior.Max Retries Respected ✅ 16244ms
Deduplication.Generates Unique Uuids ✅ 526ms
Deduplication.Preserves Uuid On Retry ✅ 5630ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10836ms
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 ✅ 521ms
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 ✅ 2523ms
Error Handling.Retries On 408 ✅ 5630ms

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 ✅ 521ms
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 ✅ 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 ✅ 519ms
Request Lifecycle.No Flags Request On Init Alone ✅ 516ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 507ms
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 ✅ 622ms
Retry Behavior.Retries Flags On 504 ✅ 622ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 521ms

@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

posthog-php-lib_curl Compliance Report

Date: 2026-10-30T13:05:10.923424+00:00
Duration: 116710ms

⚠️ 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 ✅ 29ms
Format Validation.Event Has Uuid ✅ 524ms
Format Validation.Event Has Lib Properties ✅ 524ms
Format Validation.Distinct Id Is String ✅ 525ms
Format Validation.Token Is Present ✅ 525ms
Format Validation.Custom Properties Preserved ✅ 524ms
Format Validation.Event Has Timestamp ✅ 525ms
Format Validation.Non Utc Event Timestamp Is Converted To Utc ✅ 524ms
Retry Behavior.Retries On 503 ✅ 5832ms
Retry Behavior.Does Not Retry On 400 ✅ 2529ms
Retry Behavior.Does Not Retry On 401 ✅ 2528ms
Retry Behavior.Respects Retry After Header ❌ 6333ms
Retry Behavior.Implements Backoff ✅ 16252ms
Retry Behavior.Retries On 500 ✅ 5636ms
Retry Behavior.Retries On 502 ✅ 5632ms
Retry Behavior.Retries On 504 ✅ 5640ms
Retry Behavior.Max Retries Respected ✅ 17049ms
Deduplication.Generates Unique Uuids ✅ 233ms
Deduplication.Preserves Uuid On Retry ✅ 5632ms
Deduplication.Preserves Uuid And Timestamp On Retry ✅ 10842ms
Deduplication.Preserves Uuid And Timestamp On Batch Retry ✅ 5637ms
Deduplication.No Duplicate Events In Batch ✅ 532ms
Deduplication.Different Events Have Different Uuids ✅ 527ms
Compression.Sends Gzip When Enabled ✅ 525ms
Batch Format.Uses Proper Batch Structure ✅ 525ms
Batch Format.Flush With No Events Sends Nothing ✅ 521ms
Batch Format.Multiple Events Batched Together ✅ 512ms
Error Handling.Does Not Retry On 403 ✅ 2528ms
Error Handling.Does Not Retry On 413 ✅ 2527ms
Error Handling.Retries On 408 ✅ 5633ms

Failures

retry_behavior.respects_retry_after_header

Retry delay too short: 804ms < 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 ✅ 522ms
Request Payload.Flags Request Hits Flags Path Not Decide ✅ 525ms
Request Payload.Flags Request Omits Authorization Header ✅ 523ms
Request Payload.Token In Flags Body Matches Init ✅ 523ms
Request Payload.Groups Round Trip ✅ 524ms
Request Payload.Groups Default To Empty Object ✅ 522ms
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 ✅ 522ms
Request Lifecycle.No Flags Request On Init Alone ✅ 518ms
Request Lifecycle.No Flags Request On Normal Capture ✅ 509ms
Request Lifecycle.Two Flag Calls Produce Two Remote Requests ✅ 526ms
Request Lifecycle.Mock Response Value Is Returned To Caller ✅ 524ms
Retry Behavior.Retries Flags On 502 ✅ 624ms
Retry Behavior.Retries Flags On 504 ✅ 625ms
Side Effect Events.Get Feature Flag Captures Feature Flag Called Event ✅ 525ms

Base automatically changed from feat/php-framework-integration to main October 29, 2026 17:05
@marandaneto
marandaneto marked this pull request as ready for review October 30, 2026 12:13
@marandaneto
marandaneto requested a review from a team as a code owner October 30, 2026 12:13

@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 4837e68: 2 Should fix. This pull request is large, so the review ran in 4 parts with less depth than usual.

Comment thread packages/laravel/src/Context.php Resolved

@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 ca087b8: no findings. This pull request is large, so the review ran in 4 parts with less depth than usual.

@ioannisj ioannisj 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.

🤖 An AI agent wrote this on behalf of @ioannisj.

Nothing blocking from my side. The two I'd look at before the first Laravel release are the per-scope definitions refetch when flag_cache is off and the unguarded lazy client build in packages/laravel/src/PostHog.php, the rest are smaller and could be follow-ups.

&& trim((string) $this->app['config']->get('posthog.api_key')) !== '';
}

public function client(): Client

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.

🤖 An AI agent wrote this on behalf of @ioannisj.

[suggestion] client() builds the core client with no try/catch, and $this->client stays null when the build throws, so a mistyped posthog.sdk.consumer (undefined key, which Laravel turns into an ErrorException) or a provider that doesn't implement FlagDefinitionCacheProvider throws from the first capture() or flag read in the app, on every call, while posthog:doctor still reports healthy because it never builds the client.

Would it be worth catching here, logging once with the failing option, and falling back to the noop client? Or if fail-fast is the intent, validating the options at boot so it blows up at deploy time rather than per request. Either way doctor should probably build the client.

public function captureException(
Throwable|string $exception,
?string $distinctId = null,
array $properties = [],

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.

🤖 An AI agent wrote this on behalf of @ioannisj.

[suggestion] The third parameter here is $properties where core Client::captureException uses $additionalProperties, so captureException($e, additionalProperties: [...]) copied from core code throws Unknown named parameter on the manager and the facade. The README documents properties: so I take it that's deliberate, but testSupportedForwardersKeepTheCoreParameterSignatures skips captureException and evaluateFlags, so these two can drift from core unnoticed.

Rename to $additionalProperties before 0.1.0 freezes it, or keep properties and add both methods to the parity test with the rename allowlisted? Is there a reason not to match core?

private function leave(): void
{
try {
$this->app->make(PostHog::class)->flush();

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.

🤖 An AI agent wrote this on behalf of @ioannisj.

[suggestion] leave() flushes at every nesting depth (the finally in call() reaches it), so an Artisan::call() inside a controller sends the whole queue synchronously before the response goes out. I ran a route with one nested call against a flush-counting client and it flushed once inside the request. With QueueConsumer::flush() ignoring the retry cooldown and a 10 s default timeout, an ingestion outage holds the response for up to that per nested call.

Should nested calls skip the flush and leave events for the root boundary or HTTP termination, which already flush? Per-job and per-request flushing at scope end looks fine, it's only the nested console case.

if (!$explicitId && $resolver) {
try {
$id = ($this->app->make($resolver))($this->app);
} catch (Throwable) {

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.

🤖 An AI agent wrote this on behalf of @ioannisj.

[suggestion] The three catch (Throwable) {} blocks around the distinct_id resolver, the user lookup and the groups resolver swallow everything, so when a resolver throws (db down, bad binding) events go out without identity or groups and nothing says why, on every event until the scope resolves.

Worth one rate-limited error_log or logger line per resolver per scope with the class and message? Not via report() though, that would re-enter the reporter.

return ['handled' => false, 'mechanism' => 'runtime'];
}
}
return ['handled' => true, 'mechanism' => 'middleware'];

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.

🤖 An AI agent wrote this on behalf of @ioannisj.

[suggestion] The fallback here returns mechanism => 'middleware' whenever no boundary frame matched, and the reportable callback runs for every handler report(), so a manual report($e) from a job, command or scheduler task gets mechanism.type = middleware without any middleware being crossed. The exception-event-metadata spec has manual capture on generic unless a more specific category is known.

Should the fallback be generic, with middleware reserved for the HTTP pipeline frames? RuntimeTest only asserts handled on the manual path so it'd need one more assertion.

|| !empty($config['sdk']['flag_definition_cache_provider'])
|| ($config['flag_cache']['enabled'] ?? false);
$interval = max(1, (int) ($config['flag_cache']['refresh_interval'] ?? 30));
$refreshDue = $this->definitionsLoadedAt === null || time() - $this->definitionsLoadedAt >= $interval;

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.

🤖 An AI agent wrote this on behalf of @ioannisj.

[suggestion] $definitionsLoadedAt lives on the scoped manager, and the queue worker's forgetScopedInstances() plus Octane's per-request sandbox drop it together with the client, so with secret_key set and flag_cache.enabled at its default false every job or request that reads a flag does a blocking /flags/definitions GET (core shouldFetchFlagDefinitionsFromApi() returns true with no provider). I counted three fetches across three scopes inside one 30 s interval, so refresh_interval only throttles within a scope.

OctaneTest asserts separate clients per sandbox, so a singleton isn't it. Would it make sense to default the cache provider onto the process-local array store when a secret key is set and no provider is configured, so definitions live per worker? Or at least a doctor/README warning that a secret key without flag_cache refetches per request and job.

$request = $this->request;
$headerIdentity = $this->headerIdentity;
$resolved = $this->resolved;
$sessionId = $data['sessionId'] ?? $data['session_id'] ?? null;

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.

🤖 An AI agent wrote this on behalf of @ioannisj.

[nit] The new session_id read only feeds the $session_id property sync, the alias keys stay raw in the merged context, and data(), QueueContext::normalize() and the headerIdentity reset all look at distinctId/sessionId. So with(['session_id' => 'a', 'distinct_id' => 'b']) on a header-identified request gives the event session a with the header's distinct id, and a job dispatched inside forwards the header identity.

Either promote the aliases to canonical keys like core normalizeContextData() does, or drop the alias read so Context::with() consistently ignores snake_case (the README only documents aliases for the manager bridge). Which did you intend?

$this->lifecycle->begin($request);
try {
return $next($request);
} catch (Throwable $exception) {

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.

🤖 An AI agent wrote this on behalf of @ioannisj.

[nit] This catch never runs in a real request: Pipeline::carry() catches downstream throwables and Routing\Pipeline::handleException() reports and renders instead of rethrowing, so $next() returns a response. Your own /failure route test asserts laravel.reportable, and laravel.middleware is only produced by invoking the middleware directly, yet the README lists it as an emitted source (line 181).

Drop it from the README, or reword to say request failures report as laravel.reportable with mechanism middleware? The catch can stay as a safety net for custom pipelines.

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.

2 participants