LeanRoles tackles a problem almost nobody measures. WordPress keeps every role in one autoloaded option, with each role’s capabilities copied out in full, because core has no inheritance. On a membership or commerce site with dozens of roles that option is read, unserialized and held in memory by every PHP worker on every request — and those are exactly the sites whose traffic is mostly logged in, where page caching never gets a look in.
It measures — a read-only auditor
The auditor writes nothing. It takes the size of your role option with LENGTH() in the database rather than re-serializing it in PHP, times a real unserialize() after a warm-up pass, measures the resident footprint with the result kept alive, and works out what that costs across your concurrent workers. It identifies roles that grant no effective permission, roles nobody holds, roles with identical capability sets, and capabilities it cannot account for — while being explicit that «unrecognised» is not «orphaned», because custom code checks capabilities no scanner can see.
It offers the missing primitive — user tags
There is no way in WordPress to say «this user is a wholesale customer» without granting them permissions: there are only roles. That is why membership plugins keep inventing them. A LeanRoles tag is that alternative: it appears in $user->roles, answers current_user_can() and can be filtered on in WP_User_Query — and it is never written to the autoloaded option. Third-party code cannot tell the difference; the tag grants nothing and weighs nothing.
What it does not do
It does not convert roles into tags for you. It gives you three independent primitives —create a tag, assign it in bulk, delete a role with reassignment— which compose into a conversion done by hand, by someone who has read the audit and accepts the risk. Before deleting a role it tells you how many capabilities it grants and how many users hold it; it does not tell you which of them will notice. Take a backup and check for yourself.