A super is an admin who can take a person out of the admin console. A shielded account keeps using the app exactly as before, while for every plain admin it simply is not there — not the username, not the spending, not the chats, and not the arithmetic that would otherwise give it away. Status: built. Written 2026-08-14.
Three tiers, but only two role values in the database:
| Tier | Stored as | Can |
|---|---|---|
| super | role='admin' + super_user=1 | everything an admin can, plus hide/reveal any account and grant the tier |
| admin | role='admin' | the whole console, minus whatever is shielded from them |
| tester | role='tester' | no console |
role string. The app checks role == "admin" in roughly 45 places. Adding a third value would have turned every one of those into a site where a super silently loses a power, and the failure would be quiet — a missing button, a 403 nobody expects. As a flag, a super is an admin by construction and the tier can only ever add. It also means the wire's role field keeps meaning "effective privilege", so no client gate had to change.The one contradiction that flag-plus-role allows is guarded: an account cannot be demoted to tester while it still holds the tier, because super_user=1 with role='tester' would be a user that is_super() accepts and all 45 admin checks refuse. The tier comes off first, as a separate act.
| Surface | What a plain admin gets |
|---|---|
| Users tab | the row is absent; the headcount drops with it |
| Overview | totals, online count, room counts and both top-spender boards exclude them |
| Usage & cost | by_user, by_room, by_model, by_day, by_function and all four total windows exclude them |
| Rooms tab | every room they are in is gone — not greyed, not owner-less, gone |
| Console peek | 404 — the same answer a room with no transcript gives |
| The peek button's real path ( /api/rooms/…/state·replay·members·stream) | 403. This is the widest read in the app: for a non-member it carries no history floor, so the raw replay would hand over unfloored history. The shield lands here, not only on /api/admin/*. |
| Invites | the name is out of used_by and the uses counter is reconciled, so no mismatch names the code they joined on |
| Seen | their pieces are dropped, not anonymised — a Seen carries the user's own verdict and free-text note |
| Role · caps · reset · sign-out · delete | 404, byte-identical to an unknown id. /logout needs no password, so without this an admin could walk ids and read existence off the status code. |
| Profile · avatar · DM · seating | the rank's bypass is withdrawn; the ordinary social check still runs (see §4) |
id and can infer that some account exists that they cannot see. They learn a count, never a name, a chat, or an amount. Closing this would need per-viewer id virtualisation, which breaks every action route that keys on the id — judged not worth it.What it does guarantee is the thing that was asked for: through the admin console, a plain admin can never read a shielded user's username, their spending, or a word of their chats.
The first super is minted out of band, on purpose. Only a super can grant the tier, so a console door for the first one would be exactly the reach the tier exists to deny. It is made by someone with shell access to the box and the database file — the same trust level as owning the server:
cd /opt/mad/Multi-Agent-Dialog
sudo -u mad MAD_DB_PATH=/var/lib/mad/app.db \
.venv/bin/python lib/make_super.py enovy
No restart is needed — the flag is read per request. After that, a super works the tier from Users → ⋮: Hide from admins / Show to admins, and Make super / Revoke super. Both re-confirm the super's own password, the way promoting to admin already does.
Two guards worth knowing: the last super cannot revoke itself (that would leave shielded accounts hidden with nobody able to reveal them — make_super.py can always re-grant with shell access, so the guard makes the step deliberate rather than the state unrecoverable), and a super is always shielded, whatever the column says. A tier a plain admin can see is a tier they know to go looking for.
| Seam | Where |
|---|---|
is_super(user) — the one tier predicate | lib/auth.py |
shielded_user_ids() — the only definition of «hidden» (folds in every super) | lib/db.py |
rooms_touching(uids) — the room half | lib/db.py |
_ev_clauses() — the one exclusion predicate for turn_events, by user OR room | lib/db.py |
_hidden_for(user) — built once per admin request | lib/run_room.py |
_admin_target(uid, me) — hidden reads as absent, for the five mutation routes | lib/run_room.py |
_admin_reach(user, uid) — replaces a bare role == "admin" in the social bypasses | lib/run_room.py |
| 33 checks, incl. the arithmetic and the probe oracles | lib/smoketest.py § super tier / the shield |
shielded_user_ids(). A second copy of the predicate is how one surface starts disagreeing with another — and here a disagreement is a leak.