Add shared serializable class policy and harden model caches - #458
Conversation
Clarify approval for Laravel API differences and limit package README comparisons to user-facing behavior. Record the event wildcard and request-context rules that affect coroutine-safe framework work.
Prevent new entries while the guide awaits deletion and remove rare route-object guidance that does not belong in global application context.
Record semantic package config operations instead of their first evaluated result so fresh workers merge against freshly loaded configuration. Preserve mutation order, seal replay, and cover both package helpers and dotenv reload.
Combine configured and provider-contributed classes into one worker-lifetime allowlist while preserving unrestricted and deny-all modes. Normalize and deduplicate sources without autoloading, finalize once after boot, and reject late registration.
Preserve Laravel's scalar serializableClasses constructor API while allowing manager-built array and worker-array stores to use the shared live policy. Cover scalar compatibility, policy precedence, and serialized round trips.
Preserve Laravel's scalar serializableClasses constructor API while allowing manager-built database stores to use the shared live policy. Cover direct scalar construction and restricted object round trips.
Preserve Laravel's scalar serializableClasses constructor API while allowing manager-built file stores to use the shared live policy. Propagate both serialization inputs to lock stores and cover restricted round trips and subclass paths.
Route PHP-owned Redis deserialization through the shared live policy while preserving scalar direct construction, numeric fast paths, and native serializer bypass. Cover allowed and denied values at both the store and serialization-helper boundaries.
Preserve direct scalar allowlists while allowing manager-built storage stores to use the shared live policy. Derive physical paths with stable unseeded xxh128 over the prefixed key and pin the exact mapping in tests.
Give every manager-built PHP-serializing store the same worker-lifetime policy and expose boot-time class contributions through the cache facade. Keep Swoole's internal payloads outside the user-value policy and cover manager, direct-store, and interval paths.
Freeze contributed serializable classes after providers boot in console processes and after worker configuration reload on servers. Preserve the parameterless provider boot API and verify every worker and taskworker lifecycle.
Expose normalized stack repositories for recursive validation and report stable zero-based layer indexes even when configuration uses string keys. Keep tag composition and ordinary stack behavior unchanged.
Reject stores and Redis serializers that cannot safely preserve cached model objects, including unsupported leaves inside nested stacks. Inspect configured Redis options without opening a connection and return actionable feature and layer details.
Declare the cache and core packages used directly by Auth's model-cache validation and worker-start lifecycle integration. This keeps the subtree package installable without relying on monorepo-only dependency availability.
Replace Auth's shallow store whitelist with the shared recursive model-cache validator before provider state or listeners mutate. Preserve tag validation order and cover supported, rejected, and direct-construction paths.
Contribute enabled Eloquent provider models and stock Eloquent graph containers to the global class policy. Validate every configured cached provider after application boot or worker config reload without resolving guards or adding request-path work.
Exercise real serialized cache hits with automatic root-model contributions, explicit application classes, and denied nested relations. Pin zero-query hot reads and PHP's incomplete-class behavior for undeclared graph members.
Remove the manual user-model allowlist from tagged Auth caching so the integration suite proves provider contributions work through taggable stores. Retain cache-hit and invalidation coverage.
Round-trip cached Eloquent users through Redis with policy-owned serialization and each available type-preserving native serializer. Verify every accepted mode returns a concrete model without a second database query.
Declare the core package used directly by Sanctum's worker-start cache validation listener. This keeps the subtree package dependency graph complete outside the monorepo.
Use one typed constant for initial and flushed personal-access-token model state. This keeps worker and test resets aligned with the framework default.
Contribute the selected access-token model, Sanctum guard provider models, and stock Eloquent graph containers to the global policy. Validate the configured store at process startup while preserving the parameterless provider boot API.
Keep tokenable relations out of cached access-token snapshots, preserve other eager relations, and refresh audit timestamps from a clean clone. Let internal last-used writes evict only the token entry while application-visible updates and deletion still clear both caches.
Resolve and attach one tokenable instance for provider validation, callbacks, events, and withAccessToken instead of fetching a second object. Preserve the protected Laravel validation hook and zero-query hot authentication.
Run forget and flush against every configured leaf so stale lower-priority values cannot reappear. Preserve first-success behavior elsewhere, existing failure events and dedupe, and last-exception semantics when every store fails.
Describe the global false, array, and unrestricted policy modes at the configuration source. Clarify provider contributions, forged-payload safety, and native PhpRedis serializer bypass.
Document boot-time class contributions, nested application objects, denied-class behavior, native Redis serializer rules, and model-store validation. Explain failover invalidation behavior and the Session serializer boundary without exposing internal implementation details.
State which provider models and Eloquent containers Auth contributes automatically and which application-owned graph classes remain explicit. Document supported stores, Redis serializer rules, startup-only configuration, and cache staleness behavior.
Update application guidance for automatic user-model contributions, explicit nested graph classes, recursive store validation, and type-preserving Redis serializers. Clarify invalidation and maximum-staleness behavior without requiring manual root-model configuration.
Keep framework and Testbench defaults aligned while documenting storage support, recursive stack validation, shared-cache topology, and boot-only cache configuration. Replace the stale outer-stack caveat with the validated behavior.
Document automatic token and provider model contributions, explicit application graph classes, supported serializers and stores, and startup-only configuration. Clarify tokenable separation, invalidation, and staleness guarantees.
Explain automatic identity-model contributions, application-owned nested classes, recursive store validation, and Redis serializer requirements. Describe the cache shapes and invalidation rules that preserve zero-query hot authentication.
State that the configured token cache TTL is also the maximum time a cached tokenable identity may remain stale. Keep the existing last-used update interval guidance intact.
Bring the Queue lifecycle and parity audit, PostgreSQL schema correction, and migration publishing fixes into the cache policy branch before final verification.
📝 WalkthroughWalkthroughThis PR adds shared cache serialization policies, recursive model-cache store validation, auth and Sanctum cache integration, failover invalidation handling, replayable configuration mutations, and related documentation and test coverage. ChangesCache policy and store behavior
Auth and Sanctum
Configuration replay
Documentation and tests
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Sequence Diagram(s)sequenceDiagram
participant Application
participant AuthServiceProvider
participant CacheManager
participant ModelCacheStoreValidator
participant CacheStore
Application->>AuthServiceProvider: boot()
AuthServiceProvider->>CacheManager: register serializable model resolver
AuthServiceProvider->>CacheManager: resolve configured auth store
AuthServiceProvider->>ModelCacheStoreValidator: validate repository
CacheManager->>CacheStore: provide shared serialization policy
Application->>CacheManager: finalize policy at startup or worker start
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
Greptile SummaryAdds a shared worker-lifetime cache serialization policy and strengthens model-cache correctness.
Confidence Score: 5/5The PR appears safe to merge based on the eligible follow-up review scope. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| src/cache/src/SerializableClassPolicy.php | Introduces centralized, lazily resolved class restrictions for PHP cache deserialization. |
| src/cache/src/CacheManager.php | Owns the shared serialization policy and injects it into manager-created serializing stores. |
| src/cache/src/ModelCacheStoreValidator.php | Recursively validates whether configured cache stores can safely support cross-request model caching. |
| src/cache/src/FailoverStore.php | Changes destructive cache operations to attempt every failover backend rather than stopping after the first success. |
| src/auth/src/EloquentUserProvider.php | Integrates cached Eloquent users with store validation, serialization policy registration, and model-event invalidation. |
| src/sanctum/src/PersonalAccessToken.php | Separates token and tokenable cache payloads while refining update and deletion invalidation. |
| src/sanctum/src/SanctumServiceProvider.php | Registers Sanctum model classes with the shared policy and validates its model cache at process startup. |
| src/foundation/src/Configuration/ConfigMutationTracker.php | Records package configuration mutations so they can be replayed against freshly loaded worker configuration. |
Reviews (2): Last reviewed commit: "docs(cache): record serialized class pol..." | Re-trigger Greptile
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (9)
tests/Cache/SerializableClassPolicyTest.php (1)
110-141: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider covering
finalize()idempotency.
SerializableClassPolicy::finalize()early-returns when already finalized; a secondfinalize()call after the resolvers are cleared isn't exercised, so a regression there (e.g. re-resolving to an empty set) would go unnoticed.🤖 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 `@tests/Cache/SerializableClassPolicyTest.php` around lines 110 - 141, Extend testUnserializeRecomputesBeforeFinalizationAndFreezesAfterward to call SerializableClassPolicy::finalize() a second time after the first finalization, then verify the finalized policy remains frozen and resolverRuns is unchanged, covering idempotent finalization without re-resolving.tests/Cache/ModelCacheStoreValidatorTest.php (2)
282-298: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueTwo independent scenarios in one test method.
The "last option wins" behavior is asserted twice with opposite outcomes; splitting into two methods makes a failure self-describing and avoids the mixed
assertTrue(true)+expectExceptionflow.🤖 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 `@tests/Cache/ModelCacheStoreValidatorTest.php` around lines 282 - 298, Split testLastRecognizedRedisSerializerOptionWins into two focused test methods: one asserting validation succeeds when Redis::OPT_SERIALIZER is the last recognized option, and another asserting UnsupportedModelCacheStoreException when the case-variant serializer option is last. Remove the placeholder assertTrue(true) and keep each scenario’s setup and expectation isolated.
32-46: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider a named "did not throw" helper instead of
assertTrue(true).The placeholder assertions communicate intent poorly. A small private helper (e.g.
assertValidates(...)that callsvalidate()and then asserts) or a comment noting the assertion exists only to satisfy PHPUnit's risky-test detection would read better.Also applies to: 69-83, 145-188
🤖 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 `@tests/Cache/ModelCacheStoreValidatorTest.php` around lines 32 - 46, Replace the placeholder assertTrue(true) calls in testAcceptsSupportedStoresAndSubclasses and the other referenced validation tests with a named private helper such as assertValidates that invokes the validator and clearly communicates the expected no-throw outcome. Update each affected test to use the helper while preserving the existing store coverage and validation arguments.tests/Cache/CacheFileStoreTest.php (1)
151-172: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueReflection on private state makes this assertion brittle.
Asserting the lock store's internal
serializableClasses/serializableClassPolicyproperties couples the test to implementation details. A behavioral assertion (e.g. round-tripping an object through the lock store and checking it comes back as__PHP_Incomplete_Class) would survive refactors of the property names.🤖 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 `@tests/Cache/CacheFileStoreTest.php` around lines 151 - 172, Replace the ReflectionProperty-based assertions in testLockStoreRetainsBothSerializationPolicies with a behavioral round-trip through the lock store: persist and retrieve an object covered by the configured serialization policy, then assert it is returned as __PHP_Incomplete_Class. Remove the private-state inspection while preserving coverage that both serializableClasses and serializableClassPolicy are propagated to the lock store.tests/Integration/Cache/FailoverStoreTest.php (1)
437-463: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
failoverStore()andbuildFailoverRepository()largely overlap.Both construct a mocked
CacheManager+Dispatcherand aFailoverStoreover['primary', 'fallback'].buildFailoverRepository()could be expressed asnew Repository($this->failoverStore([...], $events))once the helper accepts real repositories too.♻️ Sketch
private function buildFailoverRepository(Repository $primary, Repository $fallback): Repository { - $cacheManager = m::mock(CacheManager::class); - $cacheManager->shouldReceive('store')->with('primary')->andReturn($primary); - $cacheManager->shouldReceive('store')->with('fallback')->andReturn($fallback); - $events = m::mock(Dispatcher::class); $events->shouldReceive('dispatch')->withAnyArgs()->andReturnNull(); + $events->shouldReceive('hasListeners')->withAnyArgs()->andReturn(false); - return new Repository(new FailoverStore($cacheManager, $events, ['primary', 'fallback'])); + return new Repository($this->failoverStore([ + 'primary' => $primary, + 'fallback' => $fallback, + ], $events)); }🤖 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 `@tests/Integration/Cache/FailoverStoreTest.php` around lines 437 - 463, Refactor the test helpers so buildFailoverRepository() delegates to failoverStore() instead of duplicating CacheManager, Dispatcher, and FailoverStore setup. Update failoverStore() to accept the real repository instances needed by buildFailoverRepository(), while preserving its existing named-repository behavior and event handling, then wrap the returned FailoverStore in Repository.tests/Auth/AuthEloquentUserProviderCacheTest.php (1)
52-55: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMock the concrete
ModelCacheStoreValidatorinstead of an anonymous mock.An untyped
m::mock()bound underModelCacheStoreValidator::classwon't catch signature drift invalidate()(arg count/types), unliketests/Auth/AuthManagerTest.phpwhich mocks the concrete class.♻️ Proposed change
- $this->storeValidator = m::mock(); + $this->storeValidator = m::mock(ModelCacheStoreValidator::class);🤖 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 `@tests/Auth/AuthEloquentUserProviderCacheTest.php` around lines 52 - 55, Update the test setup around storeValidator to mock the concrete ModelCacheStoreValidator class rather than using an untyped m::mock(), while preserving the existing default validate() expectation and container binding so validate() signature changes are detected.tests/Auth/AuthServiceProviderTest.php (1)
147-201: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueTest name promises taskworker-specific behavior that the listener doesn't distinguish.
AuthServiceProvider::boot()validates on everyAfterWorkerStart, so$server->taskworker = trueat Line 199 doesn't exercise any distinct branch — the assertion would pass identically withfalse. Either drop the flag from the name/setup, or add a second case asserting both worker types behave the same, so the test documents an actual contract.🤖 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 `@tests/Auth/AuthServiceProviderTest.php` around lines 147 - 201, Update testServerValidationUsesWorkerDependenciesAndRunsForTaskworkers to match the behavior it actually verifies: either remove the taskworker-specific name and $server->taskworker setup, or add explicit coverage showing the AfterWorkerStart listener behaves identically for taskworker and non-taskworker servers. Ensure the assertions distinguish both cases if retaining the taskworker contract.tests/Integration/Auth/EloquentUserProviderCacheTest.php (1)
488-495: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueByte-identical
countQueriesForTable()copied into three test classes. The shared root cause is the absence of a reusable query-log assertion helper; extract it into a trait (e.g.Fixtures/testing concern) and use it in all three.
tests/Integration/Auth/EloquentUserProviderCacheTest.php#L488-L495: remove the local helper and pull in the shared trait.tests/Integration/Auth/EloquentUserProviderRedisCacheTest.php#L185-L192: remove the local helper and pull in the shared trait.tests/Sanctum/GuardTest.php#L201-L208: remove the local helper and pull in the shared trait.🤖 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 `@tests/Integration/Auth/EloquentUserProviderCacheTest.php` around lines 488 - 495, Extract the duplicated countQueriesForTable() helper into a reusable testing trait, preserving its existing query-log filtering behavior. Remove the local helper and import/use the shared trait in tests/Integration/Auth/EloquentUserProviderCacheTest.php#L488-L495, tests/Integration/Auth/EloquentUserProviderRedisCacheTest.php#L185-L192, and tests/Sanctum/GuardTest.php#L201-L208.src/sanctum/src/SanctumServiceProvider.php (1)
42-43: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider method-injected
boot()params over manualmake()calls.Lines 42-43 resolve
CacheManagerandConfigRepositoryvia$this->app->make(...)insideboot(). Since Laravel-style containers auto-resolve type-hintedboot()parameters, injectingboot(CacheManager $cache, ConfigRepository $config)would align better with the coding guideline to inject contracts rather than construct/resolve framework services directly. This is a style improvement, not a defect, and would ripple into the mock-heavy test setup inSanctumServiceProviderTest.php.Based on coding guidelines: "Use dependency injection for newly written classes; inject contracts instead of using helpers, facades, or constructing framework services directly."
Also applies to: 90-135
🤖 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/sanctum/src/SanctumServiceProvider.php` around lines 42 - 43, Update SanctumServiceProvider::boot to accept CacheManager and ConfigRepository as type-hinted parameters, removing the corresponding app->make calls. Adjust SanctumServiceProviderTest.php mock setup and invocations as needed to supply these dependencies while preserving existing boot behavior.Source: Coding guidelines
🤖 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 `@src/cache/src/ModelCacheStoreValidator.php`:
- Around line 40-73: Update validateStore() to handle FailoverStore by resolving
and recursively validating each configured backing store, preserving the current
feature and layerPath context for nested locations. Place this branch before the
unsupported-store exception, and retain explicit rejection behavior for
ArrayStore and WorkerArrayStore when they are not safe for model caching.
In `@src/foundation/config/auth.php`:
- Around line 99-107: The store documentation in src/foundation/config/auth.php
lines 99-107 and src/testbench/hypervel/config/auth.php lines 25-33 conflates
standalone node-local stores with node-local stack tiers. Update both comment
blocks to state that standalone file/swoole deployments are single-instance
only, while stacks with a node-local upper tier can be eventually consistent,
explicitly including [file, redis] alongside the existing example.
In `@src/foundation/config/cache.php`:
- Around line 127-133: Update the serializable_classes=false documentation in
src/foundation/config/cache.php lines 127-133 to state that arbitrary classes
are blocked while explicit classes contributed through
allowSerializableClassesUsing() by framework, package, or application providers
remain permitted. Revise the opening false-mode explanation in
src/boost/docs/cache.md lines 85-117 to clarify that application classes can
also be allowed through resolver contributions, not only through the
configuration array.
In `@src/sanctum/src/SanctumServiceProvider.php`:
- Around line 42-88: Update the serializable-class resolver registered in
SanctumServiceProvider so it resolves the current ConfigRepository inside the
closure, rather than capturing the boot-time $config. Ensure the enabled flag,
auth.guards, providers, and model list are read from the worker-reloaded
configuration when the resolver executes, while preserving the existing
validation and returned class list.
In `@tests/Sanctum/GuardTest.php`:
- Around line 85-92: Update disableTokenCache() to write sanctum.cache.enabled
directly to false on the provided ApplicationContract, in addition to updating
tokenCacheEnabled as needed. Ensure the
#[DefineEnvironment('disableTokenCache')] callback disables caching regardless
of whether it runs before or after defineEnvironment().
---
Nitpick comments:
In `@src/sanctum/src/SanctumServiceProvider.php`:
- Around line 42-43: Update SanctumServiceProvider::boot to accept CacheManager
and ConfigRepository as type-hinted parameters, removing the corresponding
app->make calls. Adjust SanctumServiceProviderTest.php mock setup and
invocations as needed to supply these dependencies while preserving existing
boot behavior.
In `@tests/Auth/AuthEloquentUserProviderCacheTest.php`:
- Around line 52-55: Update the test setup around storeValidator to mock the
concrete ModelCacheStoreValidator class rather than using an untyped m::mock(),
while preserving the existing default validate() expectation and container
binding so validate() signature changes are detected.
In `@tests/Auth/AuthServiceProviderTest.php`:
- Around line 147-201: Update
testServerValidationUsesWorkerDependenciesAndRunsForTaskworkers to match the
behavior it actually verifies: either remove the taskworker-specific name and
$server->taskworker setup, or add explicit coverage showing the AfterWorkerStart
listener behaves identically for taskworker and non-taskworker servers. Ensure
the assertions distinguish both cases if retaining the taskworker contract.
In `@tests/Cache/CacheFileStoreTest.php`:
- Around line 151-172: Replace the ReflectionProperty-based assertions in
testLockStoreRetainsBothSerializationPolicies with a behavioral round-trip
through the lock store: persist and retrieve an object covered by the configured
serialization policy, then assert it is returned as __PHP_Incomplete_Class.
Remove the private-state inspection while preserving coverage that both
serializableClasses and serializableClassPolicy are propagated to the lock
store.
In `@tests/Cache/ModelCacheStoreValidatorTest.php`:
- Around line 282-298: Split testLastRecognizedRedisSerializerOptionWins into
two focused test methods: one asserting validation succeeds when
Redis::OPT_SERIALIZER is the last recognized option, and another asserting
UnsupportedModelCacheStoreException when the case-variant serializer option is
last. Remove the placeholder assertTrue(true) and keep each scenario’s setup and
expectation isolated.
- Around line 32-46: Replace the placeholder assertTrue(true) calls in
testAcceptsSupportedStoresAndSubclasses and the other referenced validation
tests with a named private helper such as assertValidates that invokes the
validator and clearly communicates the expected no-throw outcome. Update each
affected test to use the helper while preserving the existing store coverage and
validation arguments.
In `@tests/Cache/SerializableClassPolicyTest.php`:
- Around line 110-141: Extend
testUnserializeRecomputesBeforeFinalizationAndFreezesAfterward to call
SerializableClassPolicy::finalize() a second time after the first finalization,
then verify the finalized policy remains frozen and resolverRuns is unchanged,
covering idempotent finalization without re-resolving.
In `@tests/Integration/Auth/EloquentUserProviderCacheTest.php`:
- Around line 488-495: Extract the duplicated countQueriesForTable() helper into
a reusable testing trait, preserving its existing query-log filtering behavior.
Remove the local helper and import/use the shared trait in
tests/Integration/Auth/EloquentUserProviderCacheTest.php#L488-L495,
tests/Integration/Auth/EloquentUserProviderRedisCacheTest.php#L185-L192, and
tests/Sanctum/GuardTest.php#L201-L208.
In `@tests/Integration/Cache/FailoverStoreTest.php`:
- Around line 437-463: Refactor the test helpers so buildFailoverRepository()
delegates to failoverStore() instead of duplicating CacheManager, Dispatcher,
and FailoverStore setup. Update failoverStore() to accept the real repository
instances needed by buildFailoverRepository(), while preserving its existing
named-repository behavior and event handling, then wrap the returned
FailoverStore in Repository.
🪄 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: 3a869dc6-23b1-4bcb-9035-9f1cd76948af
📒 Files selected for processing (64)
AGENTS.mddocs/ai/differences-vs-laravel.mdsrc/auth/README.mdsrc/auth/composer.jsonsrc/auth/src/AuthServiceProvider.phpsrc/auth/src/EloquentUserProvider.phpsrc/boost/docs/authentication.mdsrc/boost/docs/cache.mdsrc/boost/docs/sanctum.mdsrc/cache/src/AbstractArrayStore.phpsrc/cache/src/ArrayStore.phpsrc/cache/src/CacheManager.phpsrc/cache/src/CacheServiceProvider.phpsrc/cache/src/DatabaseStore.phpsrc/cache/src/Exceptions/UnsupportedModelCacheStoreException.phpsrc/cache/src/FailoverStore.phpsrc/cache/src/FileStore.phpsrc/cache/src/ModelCacheStoreValidator.phpsrc/cache/src/Redis/Support/Serialization.phpsrc/cache/src/RedisStore.phpsrc/cache/src/SerializableClassPolicy.phpsrc/cache/src/StackStore.phpsrc/cache/src/StorageStore.phpsrc/cache/src/SwooleStore.phpsrc/foundation/config/auth.phpsrc/foundation/config/cache.phpsrc/foundation/src/Configuration/ConfigMutationTracker.phpsrc/sanctum/README.mdsrc/sanctum/composer.jsonsrc/sanctum/config/sanctum.phpsrc/sanctum/src/PersonalAccessToken.phpsrc/sanctum/src/Sanctum.phpsrc/sanctum/src/SanctumGuard.phpsrc/sanctum/src/SanctumServiceProvider.phpsrc/support/src/Facades/Cache.phpsrc/support/src/ServiceProvider.phpsrc/testbench/hypervel/config/auth.phptests/Auth/AuthEloquentUserProviderCacheTest.phptests/Auth/AuthManagerTest.phptests/Auth/AuthServiceProviderTest.phptests/Cache/CacheArrayStoreTest.phptests/Cache/CacheDatabaseStoreTest.phptests/Cache/CacheFileStoreTest.phptests/Cache/CacheManagerTest.phptests/Cache/CacheRedisStoreTest.phptests/Cache/CacheServiceProviderTest.phptests/Cache/CacheStackStoreTagsTest.phptests/Cache/CacheStorageStoreTest.phptests/Cache/CacheSwooleStoreIntervalTest.phptests/Cache/CacheSwooleStoreTest.phptests/Cache/CacheWorkerArrayStoreTest.phptests/Cache/ModelCacheStoreValidatorTest.phptests/Cache/Redis/Support/SerializationTest.phptests/Cache/SerializableClassPolicyTest.phptests/Foundation/Configuration/ConfigMutationTrackerTest.phptests/Foundation/Listeners/ReloadDotenvAndConfigTest.phptests/Integration/Auth/EloquentUserProviderCacheTagsTest.phptests/Integration/Auth/EloquentUserProviderCacheTest.phptests/Integration/Auth/EloquentUserProviderRedisCacheTest.phptests/Integration/Cache/FailoverStoreTest.phptests/Sanctum/GuardTest.phptests/Sanctum/PersonalAccessTokenCacheTest.phptests/Sanctum/SanctumServiceProviderTest.phptests/Support/SupportServiceProviderTest.php
Pin idempotent finalization and Redis serializer option precedence, and type the remaining validator test double.\n\nClarify provider contributions, node-local store guidance, and deliberate taskworker coverage without changing runtime behavior.
Document the final architecture, worker lifecycle, performance invariants, model cache rules, and verification coverage for serialized cache values.
|
@coderabbitai Thanks for the review. I checked all five inline findings and the main review nitpicks against the current source. Changed:
Kept as designed:
The inline replies contain the source-level reasoning for each finding. |
|
Tip For best results, initiate chat on the files or code changes.
I’ve noted the design context for future reviews. 🐇 ✏️ Learnings added
|
There was a problem hiding this comment.
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
`@docs/plans/2026-07-27-0615-cache-serializable-class-policy-and-model-cache-safety.md`:
- Around line 1708-1710: Correct the stale test-path references in
docs/plans/2026-07-27-0615-cache-serializable-class-policy-and-model-cache-safety.md:1708-1710
and :1868-1868 by replacing CacheStackStoreTest.php with
CacheStackStoreTagsTest.php, including the focused test command target.
🪄 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: ef558181-cdee-4d49-88a7-649f8ee3d011
📒 Files selected for processing (11)
docs/plans/2026-07-27-0615-cache-serializable-class-policy-and-model-cache-safety.mdsrc/boost/docs/cache.mdsrc/foundation/config/auth.phpsrc/foundation/config/cache.phpsrc/testbench/hypervel/config/auth.phptests/Auth/AuthEloquentUserProviderCacheTest.phptests/Auth/AuthServiceProviderTest.phptests/Cache/CacheServiceProviderTest.phptests/Cache/ModelCacheStoreValidatorTest.phptests/Cache/SerializableClassPolicyTest.phptests/Sanctum/SanctumServiceProviderTest.php
🚧 Files skipped from review as they are similar to previous changes (10)
- src/testbench/hypervel/config/auth.php
- src/foundation/config/cache.php
- src/foundation/config/auth.php
- tests/Auth/AuthEloquentUserProviderCacheTest.php
- src/boost/docs/cache.md
- tests/Auth/AuthServiceProviderTest.php
- tests/Cache/CacheServiceProviderTest.php
- tests/Sanctum/SanctumServiceProviderTest.php
- tests/Cache/SerializableClassPolicyTest.php
- tests/Cache/ModelCacheStoreValidatorTest.php
| Extend `tests/Cache/CacheStackStoreTest.php` with the regression that a | ||
| string-keyed layer configuration reports the correct zero-based layer index in | ||
| tag-composition errors. |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Correct the stale cache-stack test path.
The plan consistently names tests/Cache/CacheStackStoreTest.php, but the supplied stack uses tests/Cache/CacheStackStoreTagsTest.php.
docs/plans/2026-07-27-0615-cache-serializable-class-policy-and-model-cache-safety.md#L1708-L1710: targettests/Cache/CacheStackStoreTagsTest.php.docs/plans/2026-07-27-0615-cache-serializable-class-policy-and-model-cache-safety.md#L1868-L1868: run the focused command againsttests/Cache/CacheStackStoreTagsTest.php.
📍 Affects 1 file
docs/plans/2026-07-27-0615-cache-serializable-class-policy-and-model-cache-safety.md#L1708-L1710(this comment)docs/plans/2026-07-27-0615-cache-serializable-class-policy-and-model-cache-safety.md#L1868-L1868
🤖 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
`@docs/plans/2026-07-27-0615-cache-serializable-class-policy-and-model-cache-safety.md`
around lines 1708 - 1710, Correct the stale test-path references in
docs/plans/2026-07-27-0615-cache-serializable-class-policy-and-model-cache-safety.md:1708-1710
and :1868-1868 by replacing CacheStackStoreTest.php with
CacheStackStoreTagsTest.php, including the focused test command target.
Summary
Hypervel defaults
cache.serializable_classestofalse, but Auth and Sanctum cache Eloquent models without a way for their providers to contribute the framework-known classes those models require. Applications must repeat root model classes manually, nested model graphs can still deserialize incompletely, and a cache store created early can freeze the policy before later providers finish booting.This PR makes the serializable-class policy a worker-lifetime capability owned by
CacheManager. Packages contribute lazy class resolvers during boot, then the policy is finalized after configuration is ready for the process. Auth and Sanctum contribute the model classes they can derive from configuration. Application-owned relation models, morph targets, and custom Eloquent containers remain explicit declarations throughCache::allowSerializableClassesUsing().Design
SerializableClassPolicywith the existing config semantics:falsedenies classes, arrays allow explicit classes, andnullortrueremain unrestricted. Provider contributions are additive, normalized, and deduplicated.Auth and Sanctum
Auth automatically contributes enabled Eloquent provider models plus the stock Eloquent collection and pivot containers. Sanctum contributes its configured personal access token model and Eloquent models selected by Sanctum guards.
Sanctum token caching now uses one resolved tokenable instance throughout authentication. PAT cache entries never embed the tokenable relation, cache hits and misses expose the same live relation shape, and the internal
last_used_ataudit write invalidates only the PAT entry. Application-visible token updates and deletions still clear both token and tokenable entries.Configured Auth and Sanctum stores are validated at process startup. Directly constructed cached Auth providers also validate before enabling their cache.
Cache correctness
FailoverStore::forget()andflush()now attempt every configured leaf. First-success invalidation could leave a stale lower-priority value that later became visible during failover. Reads and writes retain their existing first-success behavior.Stack layers are normalized to a stable list for recursive validation and tag error reporting. Storage cache paths use
xxh128for their internal non-cryptographic key digest.Laravel compatibility
Laravel-compatible cache-store constructors, named arguments, protected scalar policy properties, and Sanctum extension points are preserved.
CacheManager::getSerializableClasses(array $config)is intentionally removed. Its per-store copied-array contract cannot represent the live global worker policy without keeping two competing policy systems. The supported extension point isCache::allowSerializableClassesUsing().Performance
The policy and model-store checks are resolved at process startup. Cache reads do not perform graph traversal, extra serialization, provider resolution, container lookup, or additional backend requests. Native Redis serializer paths continue to bypass PHP unserialization as before.
Validation
composer fix, including formatting, static analysis, the full parallel suite, Testbench package coverage, and dogfood coverageSummary by CodeRabbit