Skip to content

Complete Broadcasting correctness and SDK lifecycles - #469

Merged
binaryfire merged 13 commits into
0.4from
audit/broadcasting-correctness-parity
Aug 3, 2026
Merged

Complete Broadcasting correctness and SDK lifecycles#469
binaryfire merged 13 commits into
0.4from
audit/broadcasting-correctness-parity

Conversation

@binaryfire

@binaryfire binaryfire commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

This completes the Broadcasting package audit and brings its supported surface in line with current Laravel while retaining Hypervel's coroutine and custom-pool capabilities.

The change fixes Redis prefix ownership across standalone, Cluster, Lua, and authorization paths; resolves built-in SDK broadcasters directly; bounds Ably's worker-lifetime channel cache; makes Pusher JSONP an explicit opt-in; supports enum event names and single-string channels; and makes arbitrary-data JSON failures visible at transport boundaries.

It also removes superseded pool defaults, dead fallback code, false package dependencies, and stale documentation. The audit records and all carried cross-package revalidations are updated as complete.

For more details, see docs/plans/2026-08-03-1218-broadcasting-correctness-direct-sdk-lifecycles-and-current-parity.md.

Redis correctness

  • Resolve the selected Redis connection prefix through Redis's canonical configuration boundary.
  • Let native phpredis Cluster publication apply its own prefix exactly once.
  • Continue applying the prefix manually to Lua ARGV channel names, which phpredis does not transform.
  • Remove one leading physical prefix during authorization without altering later matching text.
  • Normalize the logical channel before selecting its configured guard.
  • Reject missing channel names before they reach strict string operations.

SDK ownership and lifecycle

  • Resolve built-in Pusher, Reverb, and Ably broadcasters directly and cache them on the manager.
  • Preserve the complete explicit custom-driver pooling API, including configuration transfer, forgetting, and pool-invalidating purge behavior.
  • Release ordinary Ably channel objects after successful and failed publication so dynamic names do not accumulate for the worker lifetime.
  • Retain explicitly encrypted Ably channels because their cached object owns the cipher configuration.
  • Keep SDK replacement methods available for boot-time configuration and tests, with clear worker-lifetime warnings.

Public behavior

  • Accept string-backed, integer-backed, and unit enum broadcast names.
  • Preserve enum identity at immediate, queued, unique, and wrapper-clone boundaries while continuing to isolate ordinary event objects.
  • Accept a single channel name from ShouldBroadcast::broadcastOn() in addition to channel objects and arrays.
  • Require an explicit jsonp connection option before returning executable Pusher JSONP responses.
  • Preserve current Laravel APIs, protected extension points, custom creator shapes, and concrete SDK access.

Failure handling and cleanup

  • Throw on invalid JSON in Redis, Ably, and Log broadcaster paths that encode arbitrary application data.
  • Construct only the selected ordinary or unique queued wrapper.
  • Remove the unreachable rescue fallback and redundant manager self-binding.
  • Correct the anonymous toOthers() assertion so it verifies socket propagation instead of assigning it.

Metadata and documentation

  • Declare the split package's actual Routing and PSR logging dependencies.
  • Keep Redis optional and lazily resolved by the Redis driver.
  • Remove stale direct Auth and Cache dependencies.
  • Document enum names, string channels, explicit JSONP, and opt-in custom broadcaster pooling.
  • Record the completed package audit and close the Events, Support, Redis, Contracts, and Queue revalidation entries.

Performance and compatibility

Built-in drivers no longer pay pool checkout or proxy overhead and remain manager-cached. Wrapper selection removes a discarded object, clone, and repeated metadata reads. Redis configuration is resolved once when constructing the driver. Authorization adds one leading-prefix comparison and slice. Ably adds one in-memory release after the existing network publication while preventing unbounded retained channel objects.

The change adds no request-time lock, registry, retry loop, coroutine-context lookup, serialization layer, or additional network round trip. No supported Laravel public API or protected extension point is removed.

Validation

  • Focused Broadcasting and Foundation regressions pass.
  • Package metadata validation passes.
  • The complete formatter, PHPStan, parallel component, Testbench, and package dogfood gates pass.
  • Final whitespace, stale-reference, caller/callee, coroutine-safety, retained-state, API, performance, and dead-code reviews are clean.

Summary by CodeRabbit

  • New Features

    • Broadcasting events can now target a single channel name and use enum-based event names.
    • Built-in Pusher and Ably integrations use direct SDK connections by default, while custom drivers may opt into pooling.
    • Pusher JSONP can be explicitly enabled when needed.
  • Bug Fixes

    • Improved Redis channel prefix handling and authorization.
    • Broadcasting now reports JSON encoding failures instead of silently continuing.
    • Ably channel resources are reliably released after successful or failed broadcasts.
  • Documentation

    • Expanded broadcasting and connection-pooling guidance, including framework-specific behavior and lifecycle considerations.

Document that package and application TestState callbacks run after the test application has been destroyed and therefore cannot resolve container services.\n\nUse the framework subscriber for first-party optional packages, reserve registrars for process-local state that survives application teardown, and leave external resource cleanup with the corresponding integration-test traits.
Resolve Redis connection prefixes through the Redis-owned configuration boundary and separate native Cluster prefixing from Lua argument formatting. Authorization now removes exactly one leading physical prefix before logical channel normalization and guard selection.

Resolve built-in Pusher, Reverb, and Ably broadcasters directly while preserving the complete explicit custom-pool surface. Construct only the selected broadcast wrapper, remove the redundant manager self-binding, and use canonical container resolution without changing Laravel extension points.

Add counterfactual coverage for prefix precedence, Cluster and Lua publication, authorization normalization, direct SDK access, custom pool lifecycle behavior, enum dispatch boundaries, wrapper construction, and exact unique lock identities.
Release ordinary Ably channel objects after both successful and failed publication so dynamic channel names cannot accumulate for the worker lifetime. Retain explicitly encrypted channels because their cached object owns the cipher configuration required by later broadcasts.

Make presence JSON encoding failure-truthful and preserve the SDK's real one-message publish call behind one narrow annotation suppression for its contradictory duplicate method declarations.

Exercise the SDK's supported fake transport seam to prove release, failure cleanup, encrypted-channel retention, repeated-name boundedness, and invalid presence data without reflection or live network calls.
Gate Pusher JSONP decoding behind an explicit per-connection option instead of treating any request callback as permission to return executable JavaScript. Keep ordinary JSON as the default and preserve the existing two-argument broadcaster constructor through an optional parameter.

Ship explicit false defaults for Pusher and Reverb while retaining connection-array replacement semantics. Remove built-in SDK pool configuration now that those concurrency-safe clients are manager-cached directly.

Cover default JSON, configured JSONP, callback absence, connection defaults, and retained Reverb path configuration.
Normalize custom broadcast names through enum_value at the transport boundary so string-backed, integer-backed, and unit enum results reach the broadcaster as strings. Preserve enum identity at wrapper clone boundaries while ordinary event objects remain isolated by cloning.

Widen the ShouldBroadcast channel contract to its documented Laravel surface by accepting one Channel or string as well as arrays; the existing runtime normalization already supports each form.

Add coverage for every enum name and clone shape, single-string channels, ordinary clone isolation, and existing queue option behavior.
Narrow channel-handler normalization to the callable and class-string inputs the implementation supports, with a matching callable return contract. Remove contradictory docblock types rather than widening the runtime boundary.

Make Log broadcaster payload encoding throw on invalid user data instead of silently publishing an invalid representation. Preserve valid JSON formatting and all established authorization behavior.

Add focused invalid-payload coverage and complete native test method typing across the touched broadcaster tests.
Replace the assignment inside the toOthers dispatch assertion with a strict comparison so the test fails when the socket identifier is not propagated. This corrects a vacuous assertion without changing production behavior.

Complete native void return types in the touched integration test while preserving the existing anonymous-event coverage.
Declare the Routing and PSR logging dependencies used by the split package and remove stale direct Auth and Cache requirements whose behavior is owned through existing package boundaries. Keep Redis optional because it is resolved lazily only when that driver is selected.

Add a focused split-metadata regression covering required packages, optional SDK and Redis suggestions, provider discovery, and the absence of false dependencies so subtree releases remain self-contained.
Document enum broadcast names, single-string channels, and explicit JSONP opt-in at the public Broadcasting surface. Clarify that built-in SDK drivers resolve directly while pooling remains available only for drivers applications explicitly mark poolable.

Add concise package provenance and intentional Hypervel differences without duplicating the user guide. Remove the completed built-in pooling todo and stale documentation that implied automatic broadcaster pooling.
Record the verified Broadcasting findings, upstream and SDK evidence, ownership decisions, exact implementation boundaries, counterfactual test matrix, and final validation requirements.

Carry forward the audit's general anti-overengineering rules so post-compaction work retains the same standards without depending on the core plan. The design rejects speculative registries and compatibility machinery while requiring complete fixes at the owning boundary.
Mark Broadcasting complete in the package checklist and reset the active routing state. Close the Events, Support, Redis, Contracts, and Queue dependency revalidations at both their index and owning-ledger locations.

Add the final Broadcasting ledger entry with its inspected surface, accepted and rejected boundaries, implementation result, counterfactual versus guard coverage, performance profile, Laravel-facing compatibility, validation, and review status.

Record why the corrected Redis, built-in-pool, and anonymous-socket assertions are truthful test repairs rather than weakened expectations.
Drop the README note about worker-wide channel registration. Applications and packages register channel authorization during boot in both Laravel and Hypervel, so the underlying storage lifetime is not a practical public difference users need to account for.

Keep the method-level lifecycle warning for framework maintainers and retain only actionable public differences in the package README.
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@binaryfire, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 25 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c4655e98-e52a-413e-9b9b-c120e3c7008b

📥 Commits

Reviewing files that changed from the base of the PR and between d80e9e0 and e615af3.

📒 Files selected for processing (1)
  • tests/Broadcasting/PusherBroadcasterTest.php
📝 Walkthrough

Walkthrough

Broadcasting now supports enum names and string channels, corrects Redis prefix handling, disables JSONP by default, uses direct built-in SDK clients, releases ordinary Ably channels, throws JSON errors, updates dependencies and documentation, and adds focused regression coverage.

Changes

Broadcasting correctness

Layer / File(s) Summary
Event contracts and manager resolution
src/broadcasting/src/BroadcastEvent.php, src/broadcasting/src/BroadcastManager.php, src/contracts/src/Broadcasting/ShouldBroadcast.php, tests/Integration/Broadcasting/BroadcastManagerTest.php
Broadcast events normalize enum names, preserve enum instances during dispatch, accept string channels, resolve services through the container, and avoid default SDK pools.
Transport lifecycles and failure handling
src/broadcasting/src/Broadcasters/*, src/foundation/config/broadcasting.php, tests/Broadcasting/*
Redis prefix handling, JSON encoding, Pusher JSONP, and Ably channel release behavior were updated and tested.
Package metadata and documentation
src/broadcasting/composer.json, src/broadcasting/README.md, src/boost/docs/*, tests/Broadcasting/PackageMetadataTest.php
Dependencies, pool guidance, broadcasting differences, enum support, channel forms, and JSONP configuration were documented and validated.
Audit and supporting validation
docs/plans/*, AGENTS.md, tests/Broadcasting/BroadcasterTest.php, tests/Integration/Broadcasting/SendingBroadcastsViaAnonymousEventTest.php
Audit records, cleanup guidance, strict test signatures, channel assertions, and an anonymous-event socket assertion were updated.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant BroadcastManager
  participant Broadcaster
  participant SDK_or_Redis
  BroadcastManager->>Broadcaster: Resolve configured driver
  BroadcastManager->>Broadcaster: Dispatch event or authenticate channel
  Broadcaster->>SDK_or_Redis: Publish or encode transport payload
  SDK_or_Redis-->>Broadcaster: Return response or error
  Broadcaster-->>BroadcastManager: Return result or throw exception
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 17.22% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the PR's main focus on Broadcasting correctness and SDK lifecycle changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch audit/broadcasting-correctness-parity

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Aug 3, 2026

Copy link
Copy Markdown

Greptile Summary

The PR completes the Broadcasting package audit, aligning event and channel inputs with current Laravel behavior while revising Redis prefix handling and built-in SDK lifecycles.

  • Adds enum broadcast names and single-string channel support.
  • Corrects Redis publication and authorization prefix ownership.
  • Directly caches built-in SDK broadcasters and bounds ordinary Ably channel retention.
  • Makes transport-boundary JSON failures explicit and requires opt-in Pusher JSONP.
  • Updates package dependencies, configuration, documentation, and regression coverage.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
src/broadcasting/src/BroadcastManager.php Revises driver construction, queuing wrapper selection, SDK ownership, Redis prefix resolution, JSONP configuration, and explicit custom-driver pooling.
src/broadcasting/src/BroadcastEvent.php Normalizes enum event names, wraps single-string channels, and preserves enum identity while cloning ordinary events.
src/broadcasting/src/Broadcasters/RedisBroadcaster.php Separates native cluster prefixing from Lua channel prefixing and consistently removes only one leading prefix during authorization.
src/broadcasting/src/Broadcasters/AblyBroadcaster.php Throws on authentication JSON failures and releases ordinary channel objects after both successful and failed publication while retaining cipher-configured channels.
src/broadcasting/src/Broadcasters/PusherBroadcaster.php Makes executable JSONP authentication responses conditional on explicit connection configuration.
src/broadcasting/src/BroadcastServiceProvider.php Removes a redundant explicit manager singleton because the container auto-caches the unbound concrete manager.
src/contracts/src/Broadcasting/ShouldBroadcast.php Expands the public channel return contract to accept a single string.
src/foundation/config/broadcasting.php Disables JSONP by default and removes superseded built-in broadcaster pool defaults.
src/broadcasting/composer.json Replaces stale direct dependencies with the routing and PSR logging dependencies used by the package.

Reviews (2): Last reviewed commit: "test(broadcasting): assert the JSONP cal..." | Re-trigger Greptile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/Broadcasting/PusherBroadcasterTest.php`:
- Around line 303-306: Update the test around validAuthenticationResponse to
verify the JSONP wrapper content, asserting that the returned response body
starts with the myCallback callback rather than only checking its JsonResponse
type. Keep the existing response-type assertion if useful, but ensure the test
fails when the callback is ignored.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6b70525b-5250-415f-8301-85c96c9163ce

📥 Commits

Reviewing files that changed from the base of the PR and between 4d58887 and d80e9e0.

📒 Files selected for processing (29)
  • AGENTS.md
  • docs/plans/2026-07-12-0900-framework-coroutine-state-lifecycle-audit.md
  • docs/plans/2026-07-12-0915-framework-coroutine-state-lifecycle-audit-ledger.md
  • docs/plans/2026-08-03-1218-broadcasting-correctness-direct-sdk-lifecycles-and-current-parity.md
  • docs/todo.md
  • src/boost/docs/broadcasting.md
  • src/boost/docs/pools.md
  • src/broadcasting/README.md
  • src/broadcasting/composer.json
  • src/broadcasting/src/BroadcastEvent.php
  • src/broadcasting/src/BroadcastManager.php
  • src/broadcasting/src/BroadcastServiceProvider.php
  • src/broadcasting/src/Broadcasters/AblyBroadcaster.php
  • src/broadcasting/src/Broadcasters/Broadcaster.php
  • src/broadcasting/src/Broadcasters/LogBroadcaster.php
  • src/broadcasting/src/Broadcasters/PusherBroadcaster.php
  • src/broadcasting/src/Broadcasters/RedisBroadcaster.php
  • src/contracts/src/Broadcasting/ShouldBroadcast.php
  • src/foundation/config/broadcasting.php
  • tests/Broadcasting/AblyBroadcasterTest.php
  • tests/Broadcasting/BroadcastEventTest.php
  • tests/Broadcasting/BroadcasterTest.php
  • tests/Broadcasting/LogBroadcasterTest.php
  • tests/Broadcasting/PackageMetadataTest.php
  • tests/Broadcasting/PusherBroadcasterTest.php
  • tests/Broadcasting/RedisBroadcasterTest.php
  • tests/Foundation/FoundationConfigTest.php
  • tests/Integration/Broadcasting/BroadcastManagerTest.php
  • tests/Integration/Broadcasting/SendingBroadcastsViaAnonymousEventTest.php
💤 Files with no reviewable changes (2)
  • docs/todo.md
  • src/broadcasting/src/BroadcastServiceProvider.php

Comment thread tests/Broadcasting/PusherBroadcasterTest.php
Capture the explicitly enabled Pusher authorization response and assert that its content begins with Symfony's JSONP callback wrapper.

The previous class-only assertion also passed for an ordinary JSON response, so it could not detect removal of withCallback(). The new assertion proves the configured callback is applied without coupling the regression to the complete serialized payload.

The focused Pusher suite and the complete composer fix gate pass.
@binaryfire
binaryfire merged commit 333538b into 0.4 Aug 3, 2026
38 checks passed
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