Appearance
Agents
An agent is a member of the Department of Professional Standards with an account in the system. The authoritative record is the agents row, keyed by the agent's Discord user ID (discord_id is the primary key — it is known from the moment onboarding begins, unlike agent_id which does not exist until training completes).
The agent record
| Field | Purpose | Who sets it |
|---|---|---|
discord_id (PK) | Canonical identity | Bot at onboarding start |
name | Display name | Bot; admin correction |
status | active | inactive | onboarding | Bot (onboarding), admin (corrections) |
agent_rank | Rank (see below) | Director-gated admin only — the bot cannot set rank |
security_id, agreement_id | Onboarding identifiers (bot-generated) | Bot |
agent_id | DPS agent identifier (assigned after training) | Bot |
clearance_level | 1–5 | Bot (initial grant after training); Director-gated admin changes |
clearance_id | Clearance identifier (bot-generated) | Bot |
is_trainer | Training-eligibility flag | Admin (admin_agents) |
Roles and ranks
The rank hierarchy, lowest → highest (RANK_ORDER in authz.py):
text
Trial Agent → Probationary Agent → Agent → Senior Agent
→ Head Investigator → Lead Agent → Director → Department DirectorRank gates, checked against the live agents row on every request:
| Rank set | Grants |
|---|---|
Senior Agent + (SUPERVISOR_RANKS) | Supervisor reports, supervisor queue, audit visibility, trainer eligibility |
Head Investigator + (REASSIGN_RANKS) | Case reassignment |
Director / Department Director (DIRECTOR_RANKS) | Director-only admin capabilities (admin_reports, admin_schema, access management), rank/clearance changes |
Ranks are stored as agent_rank and validated against the fixed set; anything else is rejected by the database (INVALID_RANK).
Clearance
Clearance is an integer 1–5 mapping to capabilities via CLEARANCE_POLICY (see Permissions). It is separate from rank: an agent's clearance can be 5 while their rank is Lead Agent — Director-only capabilities additionally require Director rank, so a demotion revokes them immediately even if clearance_level is untouched.
Onboarding
Onboarding is driven by the bot, which generates every identifier itself through the /generate/* endpoints:
POST /agents/create(bot ormanage_agents) creates the row withdiscord_idand statusonboarding; everything else starts null.- As each phase completes, the bot PATCHes whitelisted fields onto the row (
PATCH /agents/<discord_id>/update):security_id/agreement_idafter Phase 2,agent_id/clearance_id/clearance_levelafter training. - The training-eligibility rule: only agents whose status is exactly
onboardingappear in the Training Center trainee selector; completing training transitions the status toactive.
There is no agents-equivalent timeline: onboarding step history lives on Discord, not in the API.
Permissions and gates
| Operation | Gate |
|---|---|
| List / view agents | view_agents (1) |
| Create agent (onboarding start) | manage_agents (5) or bot API key |
| Bot onboarding field updates | API key; restricted to the onboarding field whitelist; rank is not bot-settable (rejected with 400 — closes the static-key privilege-escalation path) |
| Agent record correction from the dashboard | admin_agents (4) + admin allowlist + required reason |
Change agent_rank / clearance_level | Director rank required (checked in the API and inside rpc_admin_agent_update against the live row) |
| Modify yourself | Blocked entirely (SELF_PROMOTION_BLOCKED, 403) — an admin can never edit their own record (prevents soft-locking yourself out of the site) |
| Modify agents above your rank | Blocked (RANK_MANAGE_REQUIRED / hierarchy guard) |
| Set rank above Head Investigator | Director only |
Administrative updates
Dashboard-side agent changes go through the audited admin path:
PATCH /agents/<discord_id>/update(browser session) →require_admin("admin_agents")→ reason required →rpc_admin_agent_update.PATCH /admin/agents/<discord_id>→ the admin Agents tab → same RPC.
rpc_admin_agent_update (migrations 028 + 034) is the single authoritative mutation for agent records:
- Field whitelist:
name,status,agent_rank,security_id,agreement_id,agent_id,clearance_level,clearance_id,is_trainer. - Validation: status ∈ {active, inactive, onboarding}; rank ∈ the fixed set; clearance 1–5; non-empty name/status/rank.
- Guards: clearance changes are Director-only and never on yourself; rank changes are never on yourself; Director-rank targets are Director-only; other targets follow
admin_requester_can_manage_rank(up to Head Investigator for active admins with clearance ≥ 4). - Writes the before/after
admin_audit_logrow (actionagent.update) and the canonicalagent.updatedevent.
The bot's onboarding updates flow through the same RPC via rpc_agent_set_onboarding_fields, which uses a reserved system-actor lane (system:botghost-onboarding) that skips only the human self-edit/Director clearance guard — rank is filtered out of the allowed fields entirely, and every write is audited under the system identity (api-key / BotGhost (API key)).
What an agent is NOT allowed to modify
- Own record — never (self-modification guard, enforced in the DB).
- Own rank or clearance — covered by the same guard.
- Rank via the bot key — the bot cannot set
agent_rankthrough any path. - Clearance via the bot key above 1–5 — bounded and validated; initial grants only, and only for onboarding agents.
- Anyone above their own rank — hierarchy guard in the API and the RPC.
- Non-whitelisted fields — anything outside the whitelist is
FIELD_NOT_ALLOWED(400).
Restrictions against unauthorized privilege escalation
The escalation surface is deliberately closed:
- The former direct bot rank write is gone; rank changes require a Director via the dashboard, and the RPC re-checks Director rank from the live agents table.
- Clearance changes require Director rank (not just clearance 5) and can never target the requester.
- The admin allowlist (
admin_users) is required on top of clearance, and access management (grant/revoke/remove) is Director-only with a required reason and audit row. - Directors cannot be removed from System Administration (
DIRECTOR_PROTECTED). - All of these checks exist in
authz.pyand inside the RPCs, so a route bug cannot bypass the database authority.