In room version 12 the creator's power is implicit in m.room.create and the users map is empty. moho computes what this account may do from users alone, so in a room it created itself it believes it has power 0:
setMatrixPowerLevel → "you cannot give somebody a rank above your own (0)"
while the server accepts the same change from the same account without complaint. So moderation actions moho could perform are refused by moho before the server ever sees them — in exactly the rooms the account owns.
What it needs: read the creator from m.room.create (and, for v12+, treat the creator as above everybody), rather than defaulting to users_default when the users map has no entry. The same reading feeds the gates on the message and member menus, so those are wrong in the same rooms.
Found while testing Element interop: the room had been created by the account that could not, apparently, moderate it.
In room version 12 the creator's power is implicit in `m.room.create` and the `users` map is empty. moho computes what this account may do from `users` alone, so in a room it created itself it believes it has power 0:
```
setMatrixPowerLevel → "you cannot give somebody a rank above your own (0)"
```
while the server accepts the same change from the same account without complaint. So moderation actions moho *could* perform are refused by moho before the server ever sees them — in exactly the rooms the account owns.
**What it needs:** read the creator from `m.room.create` (and, for v12+, treat the creator as above everybody), rather than defaulting to `users_default` when the `users` map has no entry. The same reading feeds the gates on the message and member menus, so those are wrong in the same rooms.
Found while testing Element interop: the room had been created by the account that could not, apparently, moderate it.
Salastil
added the bug label 2026-09-06 22:46:57 -04:00
Power is read as the room actually grants it now: the creators named in m.room.create — its sender, plus version 12's additional_creators — outrank every number where the room version says they do.
Nothing changes for older rooms, deliberately. Before version 12 a creator is simply whoever holds 100 and can be demoted like anybody else, so an empty users map there really does mean the room has no admin left. Inventing an owner would be the same bug in the other direction.
Both shapes of the create event are read. A sync carries the whole event, sender included; asking the server for one piece of state returns the content alone, which has no sender — and the sender is exactly who made a v12 room. So the sync's copy is preferred and the fetch is the fallback. Getting this backwards is why the first attempt at the fix still failed.
Verified against the room that produced the bug (v12, created by @salastil:poa.st, empty users):
before setMatrixPowerLevel → "you cannot give somebody a rank above your own (0)"
after setMatrixPowerLevel → granted moderator, then took it back again
getMatrixRoomPermissions → canKick / canBan / canMute / canRedactOthers all true
Those permissions are what the message and member menus read, so the actions the owner was being denied are offered again. A profile in such a room now says "Owner" rather than printing a power level larger than any room could name.
441 tests pass, five of them new and covering the rule from both sides.
Finished — https://git.salastil.com/Salastil/nobilis/commit/f027f53 and https://git.salastil.com/Salastil/moho/commit/99e4858
Power is read as the room actually grants it now: the creators named in `m.room.create` — its sender, plus version 12's `additional_creators` — outrank every number where the room version says they do.
**Nothing changes for older rooms**, deliberately. Before version 12 a creator is simply whoever holds 100 and can be demoted like anybody else, so an empty `users` map there really does mean the room has no admin left. Inventing an owner would be the same bug in the other direction.
**Both shapes of the create event are read.** A sync carries the whole event, sender included; asking the server for one piece of state returns the *content* alone, which has no sender — and the sender is exactly who made a v12 room. So the sync's copy is preferred and the fetch is the fallback. Getting this backwards is why the first attempt at the fix still failed.
**Verified against the room that produced the bug** (v12, created by `@salastil:poa.st`, empty `users`):
```
before setMatrixPowerLevel → "you cannot give somebody a rank above your own (0)"
after setMatrixPowerLevel → granted moderator, then took it back again
getMatrixRoomPermissions → canKick / canBan / canMute / canRedactOthers all true
```
Those permissions are what the message and member menus read, so the actions the owner was being denied are offered again. A profile in such a room now says "Owner" rather than printing a power level larger than any room could name.
441 tests pass, five of them new and covering the rule from both sides.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
In room version 12 the creator's power is implicit in
m.room.createand theusersmap is empty. moho computes what this account may do fromusersalone, so in a room it created itself it believes it has power 0:while the server accepts the same change from the same account without complaint. So moderation actions moho could perform are refused by moho before the server ever sees them — in exactly the rooms the account owns.
What it needs: read the creator from
m.room.create(and, for v12+, treat the creator as above everybody), rather than defaulting tousers_defaultwhen theusersmap has no entry. The same reading feeds the gates on the message and member menus, so those are wrong in the same rooms.Found while testing Element interop: the room had been created by the account that could not, apparently, moderate it.
Finished — https://git.salastil.com/Salastil/nobilis/commit/f027f53 and https://git.salastil.com/Salastil/moho/commit/99e4858
Power is read as the room actually grants it now: the creators named in
m.room.create— its sender, plus version 12'sadditional_creators— outrank every number where the room version says they do.Nothing changes for older rooms, deliberately. Before version 12 a creator is simply whoever holds 100 and can be demoted like anybody else, so an empty
usersmap there really does mean the room has no admin left. Inventing an owner would be the same bug in the other direction.Both shapes of the create event are read. A sync carries the whole event, sender included; asking the server for one piece of state returns the content alone, which has no sender — and the sender is exactly who made a v12 room. So the sync's copy is preferred and the fetch is the fallback. Getting this backwards is why the first attempt at the fix still failed.
Verified against the room that produced the bug (v12, created by
@salastil:poa.st, emptyusers):Those permissions are what the message and member menus read, so the actions the owner was being denied are offered again. A profile in such a room now says "Owner" rather than printing a power level larger than any room could name.
441 tests pass, five of them new and covering the rule from both sides.