mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-11 08:47:33 +00:00
feat(concord): assign CORD-04 roles from the Members roster
`Account.grantConcordRole` had been implemented with zero callers, so role
grants were unreachable from the app while the changelog claimed they ship.
This adds the missing surface: a "Roles…" item beside "Make admin" opening a
multi-select over the roles the viewer may hand out.
Both rank rules are enforced by delegating to `AuthorityResolver` rather than
reimplementing them:
- assignable roles are `roles().filter { myRank < it.position }` — the fold
drops a grant whose granter does not strictly outrank every assigned role, so
offering one at or above our own position would publish an edition that every
client then silently discards;
- reachable members are `authority.canActOn(me, target, MANAGE_ROLES)`, which
already folds the whole rule (hold the bit, not banned, target isn't the
owner, strictly outrank) and makes self-promotion fall out for free.
Out-of-reach members show the item disabled *with a reason* instead of omitting
it, so there is no silently no-op control.
The grant REPLACES a member's role set rather than merging into it, so the
dialog preselects their current roles. That preselection is provably complete:
a member's rank is the lowest position they hold, and the dialog only opens
when we strictly outrank that rank, so every role they hold sits strictly below
us and is therefore rendered — no held role can be silently stripped.
`amy concord roles` also gained a `grants:` section reading the post-fixpoint
`authority.roleHolders()`. It previously printed role *definitions* but never
the *grants*, which made the fold outcome unverifiable from the CLI; a
rank-violating grant now shows up as visibly absent rather than as if it landed.
Device-verified on a test community (Admin/QA Lead/Helper/Greeter): the picker
hides roles above the viewer, disables on members who outrank them, preselects
correctly, and a saved grant survived the fold and a fresh relay drain read
back from a second client.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
97b861dd5e
commit
4e7242a295
@@ -59,6 +59,17 @@ object ConcordModCommands {
|
||||
state.roles.map { (id, r) ->
|
||||
mapOf("id" to id, "name" to r.name, "position" to r.position, "permissions" to r.permissions)
|
||||
},
|
||||
// The role-holder roster AFTER the authority fixpoint, so a grant that was
|
||||
// published but dropped on fold (granter didn't outrank the role or the member)
|
||||
// is visibly absent here rather than looking like it landed.
|
||||
"grants" to
|
||||
state.authority.roleHolders().sorted().map { member ->
|
||||
mapOf(
|
||||
"member" to member,
|
||||
"rank" to state.authority.rank(member),
|
||||
"roles" to state.authority.rolesFor(member).map { it.name },
|
||||
)
|
||||
},
|
||||
"banned" to ConcordModeration.currentBanned(editions, sc.communityId.hexToByteArray(), sc.owner).toList(),
|
||||
),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user