Skip to content

test(ui): ban_removal_set_terminates_on_a_cycle hangs instead of failing (3 orphans burned 8 days of CPU on nova) #583

Description

@sanity

ban_removal_set_terminates_on_a_cycle (ui/src/components/members.rs) is designed to hang rather than fail if the cycle guard regresses:

(Test hangs rather than fails if this regresses, which is still a loud CI signal.)

It is not a loud signal in practice. On nova I found three orphaned copies of the river_ui test binary running this exact test, each burning ~96% of a core for 8 days (PPID 1 — their cargo parents had long since exited):

    PID     ELAPSED CMD
3530769  8-07:08:40 .../worktrees/feat-impersonation/target/debug/deps/river_ui-<hash> ban_removal_set_terminates_on_a_cycle
4010245  8-06:08:48 .../worktrees/feat-impersonation/target/debug/deps/river_ui-<hash> ban_removal_set_terminates_on_a_cycle
4091413  8-05:57:10 .../worktrees/feat-impersonation/target/debug/deps/river_ui-<hash> ban_removal_set_terminates_on_a_cycle

I killed them (they were 3/16 cores of permanent load on the dev box). The binaries were built from the feat-impersonation worktree, so I have not confirmed whether ban_removal_set on main also fails to terminate — the branch's version may be the one that regressed. Either way there are two problems:

  1. A hang is a bad failure mode for this assertion. In CI it burns the job's full timeout; locally it leaves an orphan spinning indefinitely with no output. Neither is loud. Prefer making non-termination detectable: give ban_removal_set an explicit visited-set (or an iteration cap of members.len()) and assert the walk completes and returns the expected set. A test that can only signal by never finishing cannot distinguish "regressed" from "still running".
  2. Something apparently did hang, at least on that branch — worth confirming whether the cycle guard on main is intact.

Suggested fix: add the visited guard to ban_removal_set itself (the UI mirror walks half-applied or hostile state, so it cannot rely on verify having rejected circular invite chains), and keep the test as a normal terminating assertion.

[AI-assisted - Claude]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions