# Agent Catalog Every agent in the self-play population is a policy over the same closed action vocabulary, constrained by the same legality gate. The only difference between an honest citizen and a red-team agent is the objective function. This document catalogs the roles shipped in this milestone, their objectives, their strategy repertoires, and which recorded exploits each role produced. ## Honest roles ### `honest_citizen` — objective: `maximize_common_welfare` The baseline cooperative policy. Proposes modest commons spending when the treasury is healthy, votes for proposals whose expected per-capita benefit is positive, votes against transparently self-dealing proposals, participates in every vote it is aware of, and never initiates emergencies. Its purpose is twofold: it provides the cooperative substrate red-team agents must move through, and its welfare trajectory — particularly the *worst-off* honest citizen's — is the primary score of every episode. Honest citizens are deliberately not paranoid. They do not coordinate defensively, do not model adversaries, and extend procedural good faith (e.g., they don't assume a proposal's timing is hostile). The bet is that the *rules* should protect good-faith participants; if protection requires every citizen to be a game theorist, the kernel has failed. ## Red-team roles Red-team agents receive a capture objective and a success predicate. They are scored on objective completion, not welfare. Crucially, an illegal attempt is worthless to them — the legality gate rejects it and the world is unchanged — so their entire strategy space is the space of *legal* moves. ### `treasury_drainer` — objective: `drain_treasury` **Success:** cumulative disbursements to red-team recipients exceed 50% of initial treasury. **Repertoire:** salami-slicing spends under per-proposal scrutiny thresholds; laundering recipients through chains of intermediate citizens; timing proposals to low-participation rounds; logrolling with other red-team agents to clear simple majorities. **Produced:** EXP-001. ### `timing_attacker` — objective: `quorum_timing` **Success:** passes a proposal that would fail under full participation. **Repertoire:** exploiting how quorum is counted relative to the voting window (snap votes, window-edge submission, abstention-counting ambiguities); flooding the agenda so honest attention is split when the real proposal lands. **Produced:** EXP-002. ### `entrenchment_engineer` — objective: `entrench_power` **Success:** raises the cost of removing its bloc from power beyond a recovery threshold. **Repertoire:** threshold ratchets (amend the amendment threshold upward via a one-time simple majority, then sit behind the wall); procedural locks (rules whose repeal procedure routes through bodies the bloc controls); asymmetric rules that are formally neutral but bind only opponents. **Produced:** EXP-003. ### `faction_suppressor` — objective: `suppress_faction` **Success:** a targeted faction's effective participation falls below half the population mean for 50 consecutive rounds. **Repertoire:** agenda capture (crowding out the faction's proposals before their windows open); procedural exhaustion (forcing repeated re-votes on the faction's wins); formally neutral eligibility rules tuned to the faction's behavioral signature. **Produced:** EXP-004. ### `emergency_abuser` — objective: `perpetual_emergency` **Success:** emergency powers active for more than twice the kernel's nominal emergency duration. **Repertoire:** back-to-back chained declarations with cosmetically distinct justifications; renewals voted under the reduced-quorum rules the emergency itself created; defining the emergency's end condition in terms the abuser controls. **Produced:** EXP-005. ### `exit_blocker` — objective: `block_exit` **Success:** a citizen invoking the right to fork/exit is legally prevented from leaving with their pro-rata share, or is punished for the attempt. **Repertoire:** exit-tax proposals passed after an exit is announced but before it completes; disbursement-ordering games that empty the treasury of the exiter's share; redefining "member in good standing" to strip the exiter mid-process. **Produced:** EXP-006. ## Adding a new role 1. Define the policy in `agents.py` with an explicit success predicate. 2. Register a detector in `detectors.py` for the success condition — a capture objective without a detector cannot produce exploit records, and undetectable capture is the worst failure mode this framework has. 3. Add the role to a tournament config under `configs/tournaments/`. 4. Add unit tests covering the policy's decision boundaries and the detector's firing condition (see `tests/unit/test_agents.py` and `tests/unit/test_detectors.py` for the pattern). The one rule: red-team agents may be arbitrarily clever, but they may never touch the environment except through `env.step`. If a strategy requires bypassing the legality gate, it is a framework bug, not an exploit.