CityRP Documentation Repository

Inbuilt pass types are catalogue compositions

Last updated

Status: Accepted · 2026-10-04 · decided in #1264, on the custom passes map #733

Custom pass types are composed from a staff-curated catalogue of capabilities. The five inbuilt pass types predate it, and every behaviour they decide is an inline ply:Pass() == PASS_ORANGE-style comparison at its own call site. The map was charted on the assumption that the inbuilt five would keep those gates as a legacy layer beside the catalogue.

The decision

  • One backend. The inbuilt five are fixed compositions of catalogue capabilities, defined in code next to their existing definitions in cityrp.configuration["Passes"], and not editable per server or at runtime.
  • No gate names a pass type. Every pass-gated call site asks whether the player is granted a capability, through one resolver that combines across every pass held.
  • "Inbuilt" is a user-facing distinction only. The five keep their names, colours, badges, sort order and /pass give … orange; issuers cannot edit them. Nothing below the presentation layer treats them differently from a custom type.

Rejected alternative: a legacy layer of hardcoded gates

Keeping the inbuilt gates means every gate asks two questions: "holds ORANGE, or holds a custom pass granting X". That is the same fact written twice with nothing forcing the two halves to agree (AGENTS.md footgun #11), at every one of the 22 grant sites. The migration to set semantics rewrites each of those comparisons anyway, so pointing the rewrite at a capability rather than at PASS_ORANGE costs nothing extra, and the inbuilt five then become the reference definition of "full parity" in the same terms custom types are measured in.

Consequences

  • Changing what an inbuilt pass grants is a code change to its composition, not to the gates.
  • A behaviour no capability expresses cannot be gated by an inbuilt pass either; it has to be added to the catalogue first.