Skip to content

riverctl: debug bans does not show whether a ban still enforces #472

Description

@sanity

Problem

riverctl debug bans <room> prints every ban with banned_user_id, banned_by_id and banned_at_secs, but gives no indication of whether the contract still enforces that ban.

Since deputy ban authority (#410), a ban can be present in state and completely inert. BansV1 computes enforcement separately from storage: MembersV1::check_banned_members only collects a ban's target (and their downstream subtree) when MembersV1::is_ban_authorized(ban.banned_by, ban.ban.banned_user, …) returns true at the time state is applied. That predicate is re-evaluated against current state, so a ban stops enforcing when any of these later become true:

  • the banner's deputy authority was revoked (their deputizer removed them from deputies);
  • the banner was pruned or left, so banner_is_member is false and the deputy-derived branches (steps 3 and 5) no longer grant;
  • the banner's deputizer left, so the banner is no longer a deputy of a genuine invite ancestor of the target;
  • the target has since deputized the banner, tripping the step-4 guardrail (and no absolute grant applies).

A moderator reading debug bans sees the ban listed and reasonably concludes the member is banned. They may well be back in the room.

Why it matters more now

#470 adds member deputized-by, so a moderator can now discover that nobody has deputized member X. What they still cannot see is the consequence: every ban X issued is dead. The two halves of the picture are split across commands, and only one of them exists.

Suggested fix

BansV1::ban_is_enforcing is already pub (common/src/room_state/ban.rs). Add an enforcing: bool to BanInfo in cli/src/commands/debug.rs, populate it from that predicate, and surface it in both the human and -f json branches. Mark the non-enforcing ones clearly in the human output, since that is the case a moderator needs to notice.

Worth considering alongside: a short reason for a non-enforcing ban (banner absent / authority revoked / guardrail), which is the information that makes it actionable.

Notes

Found while reviewing #470 (deputy-status read commands). Deliberately left out of that PR: it is ban status rather than deputy status, and it changes an existing command's output shape.

[AI-assisted - Claude]

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status
In Progress

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions