.skills/discourse-acl-authoring/references/testing-and-review.md
Use this reference when adding specs or reviewing ACL-backed features.
For target models:
AclTarget.mandatory_acl if the target defines one.anonymous_can_read? or can_write? that wrap permission_acl..with_acl_permission and .with_any_acl_permissions when index/list actions depend on the shared scopes.For Guardian methods:
granular_anonymous_and_logged_in_groups_permissions behavior when relevant.For services using AccessControlListManager:
acl persists mandatory ACLs.acl: [] persists mandatory ACLs or fails closed when no mandatory ACL exists.acl: [] replaces existing ACLs with mandatory ACLs.banned_acl fail the has_no_banned_acl policy.permission_acl cache.For cleanup behavior:
:cleanup_acls_for_deleted.Jobs::CleanupAclsForDeleted removes the group id from ACL rows.:cleanup_acls_for_deleted.Jobs::CleanupAclsForDeleted removes the user id from ACL rows.For lookup objects:
Acl::Target#permission_group_ids returns [] for missing permissions and a defensive copy for present permissions.Acl::Target#group_ids_with_any_permission replaces the older multi_permission_group_ids name.Acl::Target#permission_user_ids and #user_ids_with_any_permission return [] for missing permissions and defensive array copies for present permissions.Acl::User#target_ids_with_permission and #target_ids_with_any_permissions return defensive array copies.For migration specs:
For DAccessControl consumers:
site.access_control.mandatory_acl[targetKey] appears and is locked.site.access_control.banned_acl[targetKey] removes matching permission options for the matching grantee.onChange writes updated ACL arrays into parent state.Use .skills/discourse-writing-js-tests for QUnit patterns.
Ask these questions during code review:
AccessControlListManager?@aclTarget string match the target's acl_target_key?Target.with_acl_permission, Target.with_any_acl_permissions, guardian.target_ids_with_acl_permission, or target_ids_with_any_acl_permissions instead of ad hoc SQL?DiscoursePluginRegistry.register_acl_target_class?anonymous_users, logged_in_users, or everyone can appear in ACLs?AccessControlListManager currently assumes caller-side authorization.allowed_user_ids, but shared UI authoring is not complete.DAccessControl remains group-first and does not provide complete user ACL editing yet.DAccessControl injects mandatory rows for display but does not notify the parent on render.DAccessControl filters banned permission options for UX, but hidden options are not authorization. The manager policy is the enforcement point.mandatory_values.flattened_list skips stale group IDs, stale user IDs, and unknown target classes, so a missing row can disappear from serialized ACL output while cleanup or validation catches up.