Align Permission denial terminology#436
Conversation
Use the framework-standard denied terminology in the permission package's about output. Update the command coverage alongside the provider so the public feature summary remains tested as one coherent change.
Rename Hypervel Permission's explicit negative assignment effect from forbidden to denied across the public extension API, pivot schema, relations, authorization checks, synchronization internals, and cache payloads. Keep Spatie-compatible APIs and behavior intact while exposing denyPermissionTo, hasDeniedPermission, hasDeniedPermissionViaRoles, syncPermissionEffects, and hasDeniedRolePermissions as coherent Hypervel additions. Treat both cached effect fields as required package-generated data instead of silently failing open when malformed payloads omit them. Cover real catalog and model-assignment cache round trips, preserve query counts and batched writes, and add a reflection guard proving the removed method names cannot return as compatibility aliases. Migrate the complete Permission test surface, including schemas, custom keys, events, guards, teams, partitions, coroutine isolation, UUID paths, query counts, and the renamed denied-permission behavior suite.
Describe explicit denied assignments using the same allow and deny vocabulary as Hypervel Auth. Document the new Hypervel extension APIs, the single-edge is_denied representation, effect flipping, and the distinction between effective allowed collections and explicit denied-edge inspection.
Update the Permission guide's navigation, schema examples, assignment APIs, synchronization examples, cache discussion, partition examples, and Spatie differences to use denied terminology consistently. Clarify that a denied assignment is an explicit edge effect, that it overrides allowed edges, and that revocation removes either effect without changing the package's broader authorization semantics.
Bring the original Spatie port plan forward to the package's final denied vocabulary so it no longer teaches stale APIs, pivot columns, cache fields, or test names. Retain the plan's historical design intent while describing the current single-edge effect model and settled Hypervel extension surface accurately.
Rename the single-state hardening plan and update its complete design record to use denied terminology for public APIs, internal helpers, pivot state, cache payloads, tests, and acceptance criteria. Preserve the original correctness and performance decisions while ensuring active design documentation presents only the current vocabulary.
Replace stale forbidden-effect symbols and prose throughout the Permission hardening and performance review plan. Keep its guard, cache-indexing, wildcard, event, and performance conclusions unchanged while making every code example and test reference match the live denied API.
Align the row-partitioning design with the denied permission API, is_denied pivot schema, synchronization vocabulary, cache aggregate, and current test names. Leave the partition architecture, query-count guarantees, lifecycle behavior, and ownership boundaries unchanged.
Record the authorization-vocabulary research, settled public API, schema and cache contracts, runtime invariants, file-by-file migration, testing strategy, exclusions, and acceptance criteria for the denied terminology change. Document the behavior-preserving and zero-overhead constraints, required cache fields, greenfield removal of legacy names, and the distinction between Permission effects and unrelated HTTP or ordinary-English uses.
📝 WalkthroughWalkthroughThe permission model and documentation are renamed from forbidden to denied. Pivot schemas, runtime checks, synchronization, cache serialization, public APIs, partition/team behavior, and tests now use ChangesPermission denial migration
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related PRs
🚥 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 SummaryThis PR is a clean, coherent terminology migration across the entire permission package — renaming the
Confidence Score: 3/5Not safe to merge without a column rename migration for existing installations; upgrading users will lose all explicitly-denied permission enforcement silently. The terminology rename itself is thorough and internally consistent across source, tests, and documentation. The blocking gap is the missing database migration: the initial creation migration was updated to use
Important Files Changed
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/permission/src/Traits/HasPermissions.php (1)
1760-1763: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUse an evidence-based union type instead of
mixed.Database driver implementations can return booleans as
bool,int,string, ornull. As per coding guidelines, use strict typing, modern PHP types, and evidence-based union types instead ofmixedwhen all valid types are known.♻️ Proposed refactor
/** * Normalize a permission assignment effect. */ - protected function permissionEffectIsDenied(mixed $value): bool + protected function permissionEffectIsDenied(bool|int|string|null $value): bool {🤖 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/permission/src/Traits/HasPermissions.php` around lines 1760 - 1763, Update the parameter type of permissionEffectIsDenied() from mixed to the evidence-based union bool|int|string|null, preserving the method’s existing behavior and return type.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.
Nitpick comments:
In `@src/permission/src/Traits/HasPermissions.php`:
- Around line 1760-1763: Update the parameter type of permissionEffectIsDenied()
from mixed to the evidence-based union bool|int|string|null, preserving the
method’s existing behavior and return type.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: a9511d8a-5830-4be8-9dd5-07d655382a41
📒 Files selected for processing (33)
docs/plans/2026-06-24-2406-permission-fresh-spatie-port.mddocs/plans/2026-07-02-permission-denied-single-state-hardening.mddocs/plans/2026-07-02-permission-review-hardening-and-performance.mddocs/plans/2026-07-13-permission-row-partitioning.mddocs/plans/2026-07-15-permission-denied-terminology.mdsrc/boost/docs/permission.mdsrc/permission/README.mdsrc/permission/database/migrations/2025_07_02_000000_create_permission_tables.phpsrc/permission/src/Models/Permission.phpsrc/permission/src/Models/Role.phpsrc/permission/src/PermissionRegistrar.phpsrc/permission/src/PermissionServiceProvider.phpsrc/permission/src/Traits/HasPermissions.phptests/Integration/Database/PermissionPartitionTest.phptests/Permission/CacheTest.phptests/Permission/Commands/CommandTest.phptests/Permission/CustomSchemaConfigTest.phptests/Permission/DeletionTest.phptests/Permission/DeniedPermissionTest.phptests/Permission/Events/EventTest.phptests/Permission/GateTest.phptests/Permission/Integration/PartitionQueryCountTest.phptests/Permission/Integration/PermissionRegistrarTest.phptests/Permission/PartitionAuthorizationTest.phptests/Permission/PartitionCoroutineIsolationTest.phptests/Permission/PartitionRelationsTest.phptests/Permission/PartitionTeamsTest.phptests/Permission/PartitionTestCase.phptests/Permission/PublicApiTest.phptests/Permission/SchemaConfigTest.phptests/Permission/TestCase.phptests/Permission/Traits/HasPermissionsTest.phptests/Permission/Traits/TeamHasPermissionsTest.php
|
@greptile-apps @coderabbitai Thanks for the review. I traced each finding through the release history, schema/query behavior, cache producers and hydrators, and PDO/Eloquent boundaries. No follow-up code change is needed.
The final branch remains unchanged. A fresh Permission suite run passes with 979 tests and 2,617 assertions, and the worktree is clean. |
|
Tip For best results, initiate chat on the files or code changes.
(੭ ˃̀ ᵥ ˂̀)੭ good to have this documented for future passes ✏️ Learnings added
|
|
All four justifications hold up against the implementation details. On the migration: zero released tags containing On cache compatibility: dead compatibility code for keys no released producer ever emitted is the right call to avoid. The fail-open argument is the stronger point here — On On docstring coverage: if the project convention is no restatement docblocks on test methods and production methods already carry Laravel-style docblocks, adding them to satisfy a metric serves no contract purpose. No follow-up changes needed. The implementation is consistent and the reasoning is sound. |
Summary
This PR aligns the Hypervel-specific explicit negative permission effect with the established authorization vocabulary of allow and deny.
is_forbiddentois_denied.For more details, see docs/plans/2026-07-15-permission-denied-terminology.md
Motivation
Hypervel Auth already uses allow and deny throughout Gate responses and authorization decisions. Permission previously paired an allowed synchronization input with forbidden assignment terminology, which made the public API and storage model less intuitive than the underlying behavior.
The permission edge has two effects: it either allows or explicitly denies an ability. Denied is the conventional and direct name for that state. It also makes the precedence rule clear: an explicit deny wins over a direct or role-granted allow.
This is a terminology migration, not a new authorization model. The existing single-row assignment representation, precedence behavior, cache architecture, invalidation rules, events, and query shapes remain intact.
Public API
The Hypervel extension now exposes:
denyPermissionTo(...$permissions)hasDeniedPermission($permission, $guardName = null)hasDeniedPermissionViaRoles($permission, $guardName = null)syncPermissionEffects(allowed: [...], denied: [...])PermissionRegistrar::hasDeniedRolePermissions()The Spatie-compatible surfaces remain unchanged, including
givePermissionTo(),revokePermissionTo(),syncPermissions(), role assignment APIs, relations, scopes, middleware, Gate integration, and events.The removed names are covered by reflection assertions so compatibility aliases cannot be reintroduced accidentally.
Schema and cache contract
Both effect-bearing pivots now use a boolean
is_deniedcolumn:model_has_permissionsrole_has_permissionsThe same name is used by relation pivots, model assignment cache entries, serialized role-permission edges, and hydrated catalog state. There is no translation layer between storage and runtime terminology.
The catalog
hasDeniedRolePermissionsfield and direct-assignmentis_deniedfield are required package-generated cache data. The previous fail-open fallbacks treated a missing effect as false; those fallbacks are removed so malformed payloads cannot silently suppress an explicit denial check.Regression coverage exercises both real cache paths:
Behavior and performance
Authorization semantics are unchanged:
The implementation adds no database query, cache operation, hot-path branch, or synchronization write. SQL uses the same predicates and joins with the renamed physical column. Permission synchronization retains its pivot-only state read, bulk detach and attach behavior, and at most two batched effect updates.
Event classes, payloads, dispatch timing, listener guards, cache identities, invalidation, guards, teams, generic row partitions, wildcard checks, coroutine memoization, and integer, UUID, and ULID key behavior are unchanged.
Documentation
The package README and Boost Permission guide now describe explicit denied assignments, effect flipping, precedence, synchronization, inspection, and revocation using one vocabulary. Active Permission design plans were updated so future implementation work does not learn stale symbols.
Historical
_archivecontent and unrelated HTTP 403 terminology remain untouched.Testing
composer fixpasses in full:Focused coverage also verifies direct and inherited denial, Gate behavior, wildcard checks, guards, teams, generic row partitions, coroutine isolation, custom keys and schemas, cache invalidation, query counts, synchronization batching, UUID database integration, events, and removed API names.
Summary by CodeRabbit
New Features
Breaking Changes
is_denied.Documentation