Architecture Decision Records
Last updated
May be stale
This page was last updated ago, on 4 October 2026. Check what it says against the code before relying on it.
One file per decision, numbered in the order they were taken: NNNN-<slug>.md. The number is the
ordering, so ADRs stay flat here rather than being foldered by topic — several ADRs about one system
are still several flat files. A superseded ADR is never deleted; the one that replaces it says so.
An ADR earns its place when all three are true: the decision is hard to reverse, it would surprise a
reader who only sees the code, and there was a real alternative that was rejected for specific
reasons. Everything else belongs in design docs (what a change would touch, in
what order) or in the topic docs under docs/ (how the gamemode behaves today).
| ADR | Decision |
|---|---|
| 0001 | What counts as a server session |
| 0002 | How integration test cases stay independent |
| 0003 | One hook per action |
| 0004 | Inbuilt pass types are catalogue compositions |
| 0005 | Jobs are saved by job key |
| Doc | Status | Date | Description |
|---|---|---|---|
| What counts as a server session | Accepted | 2026-09-03 | A session is one world-load lifetime, owned by cityrp.session, keyed by an internal autoincrement, and served fail-closed. |
| How integration test cases stay independent | Accepted | 2026-09-15 | Integration cases own their data and leave the seed alone, and the harness cleans up, drains and checks for leaks after them, rather than wrapping them in transactions or resetting the database. |
| One hook per action | Accepted | 2026-10-03 | A system exposes each action as a veto hook before it and a lifecycle hook after it, with different causes of the same outcome sharing one hook through a cause argument, rather than one changed hook with an action argument or one hook per route. |
| Inbuilt pass types are catalogue compositions | Accepted | 2026-10-04 | The five inbuilt pass types are fixed compositions of the same capability catalogue custom pass types draw from, so every pass gate queries a capability and none names a pass type; "inbuilt" survives only in what players and issuers see. |
| Jobs are saved by job key | Accepted | 2026-10-04 | Saved data and staff-entered configuration name a job by a fixed, never-reused job key set at registration, never by its index or its display name. |