The admin panel ships on Friday. On Monday, a support ticket lands: “I revoked our team's Billing access and one of our admins still exported an invoice.” The engineer pulls up the permissions form expecting a bug. There isn't one — not in the sense of a broken function. The code just treats every checkbox as independent, because the only shape the state has is a flat Set<string>.

The naive pattern looks fine in isolation. toggle(id) flips a single entry in the set. It works for a single consent toggle or a flat options list. Group the checkboxes under headings and three things break at once. Below is the form. Tick the “Billing” group and see what happens to the three permissions inside. Tick every permission by hand and see what happens to “Billing”. Finally toggle “Lock Billing” and try to tick a billing permission anyway.

Live form · flat Set<string>all empty
Admin
The flat version · shipped as-is
1
// The flat form every first-pass ships.
2
// Every checkbox independent; every disabled state independent.
3
function BrokenPermissionsForm({ permissions, disabledIds }) {
4
  const [checked, setChecked] = useState(new Set());
5
  const toggle = (id) => {
6
    const next = new Set(checked);
7
    next.has(id) ? next.delete(id) : next.add(id);
8
    setChecked(next);
9
  };
10
  return (
11
    <form>
12
      {permissions.map((perm) => (
13
        <label key={perm.id}>
14
          <input
15
            type="checkbox"
16
            disabled={disabledIds.has(perm.id)}
17
            checked={checked.has(perm.id)}
18
            onChange={() => toggle(perm.id)}
19
          />
20
          {perm.label}
21
        </label>
22
      ))}
23
    </form>
24
  );
25
}
26
27
// What breaks:
28
//   1. Ticking "Billing" does not cascade to billing-view/edit/export.
29
//   2. Ticking every billing-* leaf does not light "Billing" itself.
30
//   3. No "partial checked" — the parent is either boolean or absent.
31
//   4. disabling "Billing" leaves its children fully interactive —
32
//      users can still tick billing-export even though the org doesn't
33
//      have the feature. Form submission passes the server a tick for
34
//      a permission the plan does not include.
35
//   5. "Select all Billing" has to be hand-coded per group.
Step 1 / 3 · Probe: tick the group

Tick the “Billing” group in the form above. Watch the three billing permissions sitting below it. Before you peek — what do you expect?

probe
down
up
residue