Skip to content

Add Scout lifecycle and filter maintenance APIs - #466

Open
binaryfire wants to merge 13 commits into
0.4from
feature/scout-lifecycle-filter-maintenance
Open

Add Scout lifecycle and filter maintenance APIs#466
binaryfire wants to merge 13 commits into
0.4from
feature/scout-lifecycle-filter-maintenance

Conversation

@binaryfire

@binaryfire binaryfire commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

This PR adds first-class Scout lifecycle hooks and completion-aware filter maintenance for the external search engines.

Scout previously had no common boundary for an application to adjust a Builder, final document, or final index settings after Scout had assembled its own data but before the engine performed I/O. Raw engine filters and Builder constraints could also replace one another, and deleting documents by a filter required direct SDK calls with different completion behavior for every engine.

What changed

  • Add boot-time callbacks for Builder preparation, final searchable documents, final index settings, and model-wide flush guards. Each callback uses one replacement-based static slot and is reset by Scout::flushState().
  • Prepare Builders once at each outer terminal operation. Builder construction and configuration remain side-effect free, and pagination does not prepare twice.
  • Add an optional DeletesByFilter engine capability. Algolia, Meilisearch, and Typesense implement it using their existing filter compilers and target-selection rules.
  • Require filtered deletion to reject empty filters, treat a missing target as an already-complete deletion, and return only when the driver reports completion.
  • Preserve both application-provided raw filters and Builder constraints. Each engine composes them with explicit grouping using its native filter syntax.
  • Pass final external-engine documents and settings through the new lifecycle boundaries after Scout metadata and engine metadata have been assembled.
  • Add an optional force argument to Searchable::removeAllFromSearch(). Existing calls remain guarded by default; the explicit scout:flush command opts into the forced path.
  • Make Meilisearch credential signing use an explicit parent-key identifier and secret locally instead of discovering keys over the network.
  • Harden the shared external-service test helpers so Algolia cleanup requires a published terminal result and Meilisearch task waits only observe indexes owned by the current test worker.
  • Give the standalone PHPStan types analysis its own repository-local cache.

Compatibility and runtime behavior

The existing Laravel Scout search APIs and call shapes remain unchanged. The removeAllFromSearch force argument is additive and defaults to the previous behavior.

Normal searches add one callback null check at the terminal boundary and local string composition when both filter sources are present. Indexing and settings updates add one callback null check at their existing assembly boundary. No callback registry, retained per-request map, engine wrapper, cache, lock, or extra network lookup is introduced.

Testing

The change includes unit and feature coverage for callback registration, replacement and cleanup; every Builder terminal; command flush behavior; settings preparation; filter composition; filtered-deletion targets and failure paths; and explicit Meilisearch credential signing.

The Algolia, Meilisearch, and Typesense integration suites exercise composed searches and filtered deletion against the real services. The full formatter, static-analysis, parallel test, Testbench, and dogfood gates pass.

The Scout guide and package README document the new public behavior and the actionable differences from Laravel Scout.

Summary by CodeRabbit

  • New Features

    • Added lifecycle callbacks for customizing searches, indexed documents, index settings, and model flushing.
    • Added filtered deletion across Algolia, Meilisearch, and Typesense, including index/collection targeting and safe handling of missing targets.
    • Search filters now combine application filters with builder filters consistently.
    • Meilisearch tenant tokens now use explicit credentials and local signing.
    • Added optional forced flushing through the Scout command.
  • Bug Fixes

    • Improved search-task cleanup validation and isolated Meilisearch task monitoring.
  • Documentation

    • Documented lifecycle callbacks, filtered deletion, filter composition, and tenant-token changes.

Add replacement-based, boot-time callbacks for builder preparation, searchable documents, index settings, and model-wide flush guards.

Keep callback state bounded to four nullable slots, reset it through Scout::flushState(), and share constants between Scout's job defaults and their reset path. Cover unset behavior, complete callback arguments, replacement semantics, and state cleanup.
Resolve and prepare the selected engine at each outer Builder terminal while leaving Builder construction and configuration side-effect free.

Keep pagination preparation single-shot by retaining raw engine resolution in the internal total-count path. Cover result terminals, pagination terminals, ordering, and the no-work construction boundary.
Run the Scout model-flush callback against the resolved engine before deleting an entire model index. Add an optional force argument without changing the default call shape.

Mark the explicit scout:flush command as forced while keeping scout:import --fresh on the guarded default path. Cover callback ordering and both command behaviors.
Invoke the Scout settings lifecycle after application and soft-delete settings are assembled and after the physical index name is known.

Support both model-backed and raw named settings entries, including callbacks that turn an empty configured entry into concrete settings. Cover command inputs, ordering, nullable model context, and the final index target.
Introduce the optional DeletesByFilter engine capability and implement it for Algolia with prepared builders, explicit write-target selection, empty-filter refusal, missing-index handling, and verified task completion.

Preserve caller-authored filters when Builder constraints are present by composing both expressions with explicit precedence. Run final documents through Scout's lifecycle boundary and cover search, pagination, callbacks, deletion failures, and the real service path.
Compose application filters with Builder constraints across string and array filter forms, prepare final documents, and add completion-aware filtered deletion with bounded polling and precise missing-index handling.

Replace network key discovery in token generation with explicit parent-key identity and local signing so credentials cannot mix identifiers and secrets. Cover option precedence, filter shapes, task failures, timeouts, target selection, and real-service signing and deletion.
Compose raw Typesense filter_by expressions with Builder constraints while retaining their precedence, and pass final indexed documents and lazy-created schemas through Scout lifecycle preparation.

Implement synchronous filtered deletion with prepared builders, explicit write-target selection, empty-filter refusal, and missing-collection handling. Cover search callbacks, schema authority, target selection, failure paths, and the real service behavior.
Require Algolia index deletion waits to return a published terminal task so swallowed polling failures cannot let setup or teardown race unfinished cleanup.

Limit Meilisearch's shared pending-task waiter to indexes owned by the current test prefix, preventing parallel workers from adopting each other's tasks. Add deterministic coverage for incomplete Algolia results and prefix-isolated Meilisearch waits.
Give the standalone types analysis its own repository-local cache directory, matching the main PHPStan configuration's local-cache policy.

This prevents cached paths from deleted worktrees from leaking into types-only analysis and keeps the two configurations from sharing incompatible result state.
Describe the lifecycle registration points, Builder preparation timing, document and settings callbacks, model-flush guards, and the optional filtered-deletion capability.

Document raw-filter composition, completion guarantees, explicit Meilisearch token credentials, and forced command flushes. Keep the package README limited to concise, actionable differences from Laravel Scout.
Capture the completed lifecycle, filter-composition, filtered-deletion, explicit token-signing, and external-service verification contracts in a focused design record.

Update the prior Scout and framework lifecycle plans to reflect truthful Algolia completion checks and per-worker Meilisearch task ownership.
@coderabbitai

coderabbitai Bot commented Aug 2, 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: 6 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

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: 89456e81-3018-4d58-bcfb-f666418cb1b1

📥 Commits

Reviewing files that changed from the base of the PR and between a48c815 and 75f4535.

📒 Files selected for processing (5)
  • src/boost/docs/scout.md
  • src/foundation/src/Testing/Concerns/InteractsWithAlgolia.php
  • tests/Foundation/Testing/Concerns/ExternalServiceOptInTest.php
  • tests/Integration/Scout/Meilisearch/MeilisearchCommandsIntegrationTest.php
  • tests/Integration/Scout/Meilisearch/MeilisearchEngineIntegrationTest.php
📝 Walkthrough

Walkthrough

Changes

Scout lifecycle and filter maintenance

Layer / File(s) Summary
Lifecycle callbacks and flush wiring
src/scout/src/Scout.php, src/scout/src/Builder.php, src/scout/src/Searchable.php, src/scout/src/Console/..., tests/Scout/...
Scout adds boot-time callbacks for builder, document, index settings, and model-flush preparation. Builder terminals prepare engines once. Flush commands pass force: true.
Engine filter composition and deletion
src/scout/src/Contracts/..., src/scout/src/Engines/..., tests/Integration/Scout/..., tests/Scout/Unit/Engines/...
Algolia, Meilisearch, and Typesense compose application and builder filters and support filtered deletion. Meilisearch tenant tokens use explicit key identity and signing credentials.
External task cleanup validation
src/foundation/src/Testing/Concerns/..., tests/Foundation/Testing/Concerns/..., docs/plans/...
Algolia cleanup requires published deletion tasks. Meilisearch polling ignores tasks outside the current worker prefix.
Documentation and tooling updates
src/boost/docs/scout.md, src/scout/README.md, phpstan.types.neon.dist
Documentation covers the new lifecycle, filtering, deletion, tenant-token, and flush behavior. PHPStan uses .cache/phpstan-types as its temporary directory.

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

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.48% 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 changes: Scout lifecycle hooks and filter maintenance APIs.
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 feature/scout-lifecycle-filter-maintenance

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 2, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds boot-time Scout lifecycle callbacks and completion-aware filtered deletion for Algolia, Meilisearch, and Typesense.

  • Prepares builders at terminal execution and exposes final document, index-settings, and model-flush lifecycle boundaries.
  • Composes raw engine filters with Scout Builder constraints.
  • Adds engine-specific filtered deletion with target selection, empty-filter rejection, missing-target handling, and completion checks.
  • Changes Meilisearch tenant-token generation to use an explicit parent-key UID and secret.
  • Strengthens external-service test cleanup and adds focused unit and integration coverage.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
src/scout/src/Builder.php Routes search and pagination terminals through a single Builder-preparation boundary while preserving unprepared internal count resolution.
src/scout/src/Scout.php Adds replacement-based worker-lifetime callbacks for Builder, document, settings, and model-flush lifecycles with state cleanup.
src/scout/src/Engines/AlgoliaEngine.php Adds document preparation, grouped filter composition, and completion-aware filtered deletion.
src/scout/src/Engines/MeilisearchEngine.php Adds lifecycle preparation, array/string filter composition, bounded filtered-deletion waiting, and explicit local tenant-token signing.
src/scout/src/Engines/TypesenseEngine.php Adds lifecycle preparation, grouped filter composition, synchronous filtered deletion, and prepared lazy collection schemas.
src/scout/src/Searchable.php Adds the optional force argument and invokes the model-flush lifecycle guard before engine flushing.
src/foundation/src/Testing/Concerns/InteractsWithAlgolia.php Requires published terminal results for every scheduled Algolia cleanup task.
src/foundation/src/Testing/Concerns/InteractsWithMeilisearch.php Restricts pending-task waits to indexes owned by the current test-worker prefix.

Reviews (3): Last reviewed commit: "Await unscoped Meilisearch test index cr..." | 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: 5

🧹 Nitpick comments (3)
src/scout/src/Scout.php (2)

33-38: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider typed class constants for the job-class defaults.

DEFAULT_MAKE_SEARCHABLE_JOB and DEFAULT_REMOVE_FROM_SEARCH_JOB hold class-string values but declare no type. PHP 8.3+ supports typed class constants for scalar types, including string. Add the string type to catch accidental type mismatches at class-load time instead of at runtime.

♻️ Proposed typed constants
-    protected const DEFAULT_MAKE_SEARCHABLE_JOB = MakeSearchable::class;
+    protected const string DEFAULT_MAKE_SEARCHABLE_JOB = MakeSearchable::class;

-    protected const DEFAULT_REMOVE_FROM_SEARCH_JOB = RemoveFromSearch::class;
+    protected const string DEFAULT_REMOVE_FROM_SEARCH_JOB = RemoveFromSearch::class;

As per coding guidelines, src/**/*.php requires "Use modern PHP 8.4+, declare strict types in every file, and provide native types wherever permitted."

🤖 Prompt for 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.

In `@src/scout/src/Scout.php` around lines 33 - 38, Update the
DEFAULT_MAKE_SEARCHABLE_JOB and DEFAULT_REMOVE_FROM_SEARCH_JOB class constants
in Scout to explicitly declare the string type, preserving their existing
MakeSearchable::class and RemoveFromSearch::class values.

Source: Coding guidelines


111-114: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use first-class callable syntax for consistency with the rest of the file set.

Each *Using registration method converts the incoming callable with Closure::fromCallable($callback). Builder::query() in this same PR already uses the first-class callable syntax $callback(...) for the identical purpose. Both forms are functionally equivalent since PHP 8.1. Align the four Scout registration methods with the newer, terser syntax already used in this codebase.

♻️ Proposed change (repeat for all four methods)
-        static::$prepareBuilderCallback = Closure::fromCallable($callback);
+        static::$prepareBuilderCallback = $callback(...);

Also applies to: 134-137, 161-164, 188-191

🤖 Prompt for 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.

In `@src/scout/src/Scout.php` around lines 111 - 114, Update all four Scout *Using
registration methods, including prepareBuilderUsing and the methods at the other
referenced locations, to assign the incoming callable via first-class callable
invocation syntax like $callback(...) instead of
Closure::fromCallable($callback), matching Builder::query() while preserving
their existing callback registration behavior.
src/scout/src/Engines/MeilisearchEngine.php (1)

38-43: 🚀 Performance & Scalability | 🔵 Trivial

Confirm the blocking wait budget for deleteByFilter.

FILTER_DELETE_TIMEOUT_IN_MS is 500_000, so waitForTask() can block the calling coroutine for up to 500 seconds. deleteByFilter() is reachable from request-serving code paths, not only from console commands. Consider making the timeout configurable, or document that callers must run filtered deletion from a queue or console context.

Also applies to: 429-434

🤖 Prompt for 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.

In `@src/scout/src/Engines/MeilisearchEngine.php` around lines 38 - 43, Review the
blocking wait in deleteByFilter and avoid hard-coding a 500-second request-path
delay: make FILTER_DELETE_TIMEOUT_IN_MS configurable through the existing engine
configuration mechanism, or explicitly document and enforce that deleteByFilter
callers run only in queue/console contexts. Preserve the
FILTER_DELETE_INTERVAL_IN_MS polling behavior and ensure the chosen timeout
policy applies to every deleteByFilter waitForTask call.
🤖 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 `@docs/plans/2026-08-02-1749-scout-lifecycle-and-filter-maintenance-apis.md`:
- Line 165: Update the validation sequence in the documented lifecycle plan to
include PHPStan for source changes and the full parallel test suite before
signoff, while preserving the existing changed-test, focused-suite, composer
fix, diff-check, and review gates. Also require running the Testbench suite
whenever Testbench changes are present.

In `@src/foundation/src/Testing/Concerns/InteractsWithAlgolia.php`:
- Around line 144-151: Update the deletion-task loop in the Algolia teardown
flow to record the first non-published result as a failure, continue calling
waitForTask for every scheduled task, and rethrow the recorded failure only
after the loop completes. Preserve the existing failure message and add a
regression covering two indices where the first task is incomplete, verifying
both tasks are awaited before failure is raised.

In `@tests/Integration/Scout/Meilisearch/MeilisearchEngineIntegrationTest.php`:
- Around line 60-70: Move the assertNotNull checks for $uid and $secret into the
try block that handles the Meilisearch key lifecycle, keeping key creation and
identifier extraction before it. Ensure cleanup via deleteKey($uid) still
executes when either assertion fails.

In `@tests/Scout/Unit/Engines/MeilisearchEngineTest.php`:
- Around line 124-138: Update the test cleanup flow to clear Scout lifecycle
callbacks and static state between tests: ensure
AfterEachTestSubscriber::flushStateAfterTest() invokes Scout::flushState(), or
register Scout::flushState() through AfterEachTestCleanup::flushUsing() after
the reset. Apply this to the cleanup mechanism covering
Scout::prepareSearchableDocumentUsing registrations so callbacks cannot leak
into later tests.

In `@tests/Scout/Unit/Engines/TypesenseEngineTest.php`:
- Around line 604-616: Update the Builder filter merge used by delete/search
parameter construction so the model-level filter_by from
typesenseSearchParameters() is preserved and combined with the option-supplied
filter_by, rather than overwritten. Ensure the resulting expression includes
both filters with correct grouping, and update affected deleteByFilter/search
parameter test expectations accordingly.

---

Nitpick comments:
In `@src/scout/src/Engines/MeilisearchEngine.php`:
- Around line 38-43: Review the blocking wait in deleteByFilter and avoid
hard-coding a 500-second request-path delay: make FILTER_DELETE_TIMEOUT_IN_MS
configurable through the existing engine configuration mechanism, or explicitly
document and enforce that deleteByFilter callers run only in queue/console
contexts. Preserve the FILTER_DELETE_INTERVAL_IN_MS polling behavior and ensure
the chosen timeout policy applies to every deleteByFilter waitForTask call.

In `@src/scout/src/Scout.php`:
- Around line 33-38: Update the DEFAULT_MAKE_SEARCHABLE_JOB and
DEFAULT_REMOVE_FROM_SEARCH_JOB class constants in Scout to explicitly declare
the string type, preserving their existing MakeSearchable::class and
RemoveFromSearch::class values.
- Around line 111-114: Update all four Scout *Using registration methods,
including prepareBuilderUsing and the methods at the other referenced locations,
to assign the incoming callable via first-class callable invocation syntax like
$callback(...) instead of Closure::fromCallable($callback), matching
Builder::query() while preserving their existing callback registration behavior.
🪄 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: f3d7a238-d19e-4673-8d52-15312bd74ce8

📥 Commits

Reviewing files that changed from the base of the PR and between d941c93 and a48c815.

📒 Files selected for processing (33)
  • docs/plans/2026-07-12-0915-framework-coroutine-state-lifecycle-audit-ledger.md
  • docs/plans/2026-08-02-1006-scout-current-parity-queue-and-search-lifecycles.md
  • docs/plans/2026-08-02-1749-scout-lifecycle-and-filter-maintenance-apis.md
  • phpstan.types.neon.dist
  • src/boost/docs/scout.md
  • src/foundation/src/Testing/Concerns/InteractsWithAlgolia.php
  • src/foundation/src/Testing/Concerns/InteractsWithMeilisearch.php
  • src/scout/README.md
  • src/scout/src/Builder.php
  • src/scout/src/Console/FlushCommand.php
  • src/scout/src/Console/IndexCommand.php
  • src/scout/src/Console/SyncIndexSettingsCommand.php
  • src/scout/src/Contracts/DeletesByFilter.php
  • src/scout/src/Engines/AlgoliaEngine.php
  • src/scout/src/Engines/MeilisearchEngine.php
  • src/scout/src/Engines/TypesenseEngine.php
  • src/scout/src/Scout.php
  • src/scout/src/Searchable.php
  • tests/Foundation/Testing/Concerns/ExternalServiceOptInTest.php
  • tests/Integration/Scout/Algolia/AlgoliaFilteringIntegrationTest.php
  • tests/Integration/Scout/Meilisearch/MeilisearchEngineIntegrationTest.php
  • tests/Integration/Scout/Meilisearch/MeilisearchFilteringIntegrationTest.php
  • tests/Integration/Scout/Typesense/TypesenseFilteringIntegrationTest.php
  • tests/Scout/Feature/SearchableModelTest.php
  • tests/Scout/Unit/BuilderTest.php
  • tests/Scout/Unit/Console/FlushCommandTest.php
  • tests/Scout/Unit/Console/ImportCommandTest.php
  • tests/Scout/Unit/Console/IndexCommandTest.php
  • tests/Scout/Unit/Console/SyncIndexSettingsCommandTest.php
  • tests/Scout/Unit/Engines/AlgoliaEngineTest.php
  • tests/Scout/Unit/Engines/MeilisearchEngineTest.php
  • tests/Scout/Unit/Engines/TypesenseEngineTest.php
  • tests/Scout/Unit/ScoutTest.php

Comment thread src/foundation/src/Testing/Concerns/InteractsWithAlgolia.php
Comment thread tests/Integration/Scout/Meilisearch/MeilisearchEngineIntegrationTest.php Outdated
Comment thread tests/Scout/Unit/Engines/MeilisearchEngineTest.php
Comment thread tests/Scout/Unit/Engines/TypesenseEngineTest.php
Wait for every already-scheduled Algolia index deletion when the SDK returns an incomplete normal result, then report the first incomplete task. Preserve immediate propagation for SDK failures so retry exhaustion is not multiplied across indexes.

Add two-index regressions for both completion boundaries, and ensure Meilisearch integration child keys are removed whenever either supported deletion identifier is available without masking nullable-response assertions.

Document the asynchronous deletion behavior, Meilisearch wait bound, and recommended execution context for long filtered deletions.
@binaryfire

Copy link
Copy Markdown
Collaborator Author

@coderabbitai Thanks for the review. Follow-up is pushed in 64221b6.

Changed:

  • Algolia cleanup now attempts every scheduled wait after an incomplete normal result and reports the first incomplete task afterward. SDK exceptions remain immediate.
  • Meilisearch integration key cleanup now survives nullable UID or key responses without masking the original assertion failure.
  • Scout documentation now explains the Algolia and Meilisearch asynchronous wait behavior, the Meilisearch bound, and where long deletions should run.

Reviewed without changes:

  • composer fix already contains every validation gate named in the plan comment.
  • Scout state is already reset through AfterEachTestSubscriber::flushScoutState().
  • Typesense option precedence matches Laravel Scout, while prepared Builder constraints remain AND-composed.
  • Closure::fromCallable matches the local callback registrar convention.
  • Typing only the new Scout constants would be inconsistent with the package, and additional generated docstrings would not improve the public documentation.

The full repository gate and the configured Meilisearch integration suite are green.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

git show --stat --oneline --decorate --no-renames 64221b6cb
git diff 64221b6cb^ 64221b6cb -- \
  src/foundation/src/Testing/Concerns/InteractsWithAlgolia.php \
  src/foundation/src/Testing/Concerns/InteractsWithMeilisearch.php \
  src/boost/docs/scout.md \
  tests/Foundation/Testing/Concerns/ExternalServiceOptInTest.php

printf '\n--- Matching follow-up test and documentation references ---\n'
rg -n -C 3 \
  'waitForTask|published|incomplete|delete.*key|apiKey|tenant token|filtered deletion|asynchronous|timeout' \
  src/foundation/src/Testing/Concerns/InteractsWithAlgolia.php \
  src/foundation/src/Testing/Concerns/InteractsWithMeilisearch.php \
  src/boost/docs/scout.md \
  tests/Foundation/Testing/Concerns/ExternalServiceOptInTest.php || true

Length of output: 30935


🏁 Script executed:

#!/bin/bash
set -euo pipefail

git diff 64221b6cb^ 64221b6cb -- \
  tests/Integration/Scout/Meilisearch/MeilisearchEngineIntegrationTest.php

printf '\n--- Relevant Meilisearch integration cleanup context ---\n'
ast-grep outline tests/Integration/Scout/Meilisearch/MeilisearchEngineIntegrationTest.php --items all
rg -n -C 8 \
  'delete.*key|deleteKey|apiKey|uid|finally|tearDown|assert|expect' \
  tests/Integration/Scout/Meilisearch/MeilisearchEngineIntegrationTest.php

Length of output: 13922


@binaryfire Verified in 64221b6cb.

  • Algolia cleanup now waits for every scheduled task after an incomplete result. It reports the first incomplete task after the waits complete. SDK exceptions remain immediate.
  • The Meilisearch integration cleanup now handles nullable UID and key values without replacing the original assertion failure.
  • The Scout documentation states the asynchronous behavior, the 500-second Meilisearch bound, the five-second polling interval, and the recommended execution context for long deletions.

The reported review findings are addressed. 🐇


✏️ Learnings added
Learnt from: binaryfire
URL: https://github.com/hypervel/components/pull/466

Timestamp: 2026-08-02T21:11:40.920Z
Learning: In the Scout package, `AfterEachTestSubscriber::flushScoutState()` resets Scout state between tests. Do not request additional test-level state cleanup when this subscriber applies.

Learnt from: binaryfire
URL: https://github.com/hypervel/components/pull/466

Timestamp: 2026-08-02T21:11:40.920Z
Learning: For Scout Typesense searches, application option precedence follows Laravel Scout behavior. Prepared `Builder` constraints are then AND-composed with the selected application filter.

Learnt from: binaryfire
URL: https://github.com/hypervel/components/pull/466

Timestamp: 2026-08-02T21:11:40.920Z
Learning: In the Scout package, lifecycle callback registrars use `Closure::fromCallable`. This matches the local callback-registration convention.

Learnt from: binaryfire
URL: https://github.com/hypervel/components/pull/466

Timestamp: 2026-08-02T21:11:40.920Z
Learning: Scout lifecycle callback constants should follow existing package typing conventions. Typing only newly added constants is inconsistent with the package style.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

You are interacting with an AI system.

Capture and wait for the exact task returned when the scoped-deletion regression creates its deliberately unprefixed index. The shared task waiter correctly ignores indexes outside the current test prefix, so relying on it left the precondition vulnerable to Meilisearch asynchronous creation timing.

Keep the prefix-scoped waiter unchanged for parallel isolation and make the real-service command regression deterministic on slower CI workers.
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