Backfill ancestors so closure cannot remove access

FeatureInitializerService
Shipped
August 14, 2026 at 9:22 PM UTC
Author
Kamo
Commit
ffe66fb

MemberRightsAppliedService now denies any right whose parent chain is not granted. Every row written before the hierarchy existed knows nothing about ancestors, so a role holding MANAGE_SUBSCRIPTION_PLANS without ACCESS_COMMERCE — entirely normal until now — would lose it on the next recalculation. Across 13 live organizations that is an outage, not a migration. Brings all four levels (org roles, departments, job titles, member overrides) up to the invariant the write paths now maintain, using the same rule: a granted descendant pulls its ancestors up to GRANTED. Step 2 is the one that actually prevents the outage — it flips an explicitly DENIED ancestor to granted, because rows that exist survive step 1 untouched and closure would then revoke every descendant beneath them. Security model templates are deliberately NOT touched: a FORCE_NUKE on a parent is an administrator switching a subtree off on purpose, and closure honouring that is the feature. Step 3 is a GATE, not a log line: it re-checks the invariant and fails the run if any level still holds a granted descendant under a non-granted ancestor. A migration that reported success with a violation left behind would hand the problem to the resolver, where it surfaces as a member quietly losing a permission with nothing to explain it.

All changes

Like what you see shipping?

Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.

Start Free ForeverView Pricing