Change record status: 
Introduced in branch: 
1.0.x
Introduced in version: 
1.0.0-beta4
Description: 

Role revocation used to resolve which roles to remove by loading the subscription's plan at revocation time. If that lookup failed — the plan entity was deleted, its plan_id was renamed, or a cross-connector plan_id collision resolved to the wrong plan — no (or the wrong) roles were removed and the user kept paid access indefinitely (#3616929: Role revocation depends on a live plan lookup, so users can keep paid roles after expiry or cancellation).

Subscription entities now carry a granted_roles multi-value string base field. Whenever an active subscription is saved while its plan resolves, SubscriptionEntity::preSave() records the plan's role IDs there. Deactivation (updateUserRoles()), deletion (preDelete()), and the user-presave role re-sync all revoke from that snapshot; the live plan lookup remains only as a fallback for rows saved before the field existed.

New methods

  • SubscriptionEntity::getGrantedRoleIds(): array — the snapshotted role IDs (empty if nothing recorded yet).
  • SubscriptionEntity::getRevocableRoleIds(): array — the role IDs this subscription is responsible for: the snapshot, falling back to a live plan lookup.

SubscriptionEntity::addRoles() and removeRoles() now accept plain role ID strings as well as role field items.

Upgrade path

Update 10014 installs the field and backfills the snapshot for every ACTIVE subscription whose plan still resolves. Inactive subscriptions are not backfilled (re-saving one would re-run its revocation path) and keep the plan-lookup fallback they always had.

What you need to do

Nothing for typical sites: the change is internal to role handling. Custom code that granted extra roles by re-implementing the plan lookup should switch to getRevocableRoleIds(). Code that creates subscription entities programmatically needs no changes — the snapshot is recorded automatically on save.

Impacts: 
Module developers
Site templates, recipes and distribution developers