Expand description
Concord role graph (GROUP_PROTOCOL.md).
The MVP exposes a single auto-generated “Admin” role, but this is the FULL graph:
roles are data (not a hardcoded is_admin flag), enforcement is capability-based
(effective-permission bits + position), and the engine reads an arbitrary set of
roles + grants. Mod roles, per-channel mods, and custom roles later are just more
Role records flowing through the same code — additive, no enforcement changes.
WIRE MODEL (per-entity): roles and grants do NOT live in the GroupRoot, and they
are NOT one consolidated blob. Each role is its own addressable RoleMetadata event
(vsk=1, d-tag = role_id) and each member’s grants are their own Grant event
(vsk=3, d-tag = an opaque per-member locator). So two managers editing different
roles or different members never clobber each other — only same-coordinate edits
converge (authority-first). CommunityRoles here is the in-memory AGGREGATION a
client builds from those fetched per-entity events, not an on-wire document.
Structs§
- Community
Roles - The role graph a client AGGREGATES from the fetched per-entity events (RoleMetadata + per-member Grant). Not an on-wire document — the enforcement engine queries this.
- Member
Grant - One member’s role grants (vsk=3) — its own addressable event so granting Alice
never clobbers Bob’s grants.
memberis the grantee’s pubkey, lowercase hex (same form as the banlist), androle_idsare the roles they hold (a member can have several). - Permissions
- Management/moderation permission bits. Access (read/post a channel) is NOT here — that is key possession (the two-mechanism split). Bit positions are part of the wire format and are FROZEN: append a reserved bit, never renumber or reuse one.
- Role
- A role: its own addressable RoleMetadata event (vsk=1). Fully general; the MVP
auto-creates exactly one (
Role::admin).
Enums§
- Role
Scope - Discord’s “any channel” vs “this channel”. Server-scope acts everywhere; channel-scope is rejected against any other channel.