Skip to content

Trust Tier Model

Kurt edited this page Jul 17, 2026 · 3 revisions

Trust Tier Model

Audience: Builder Status: ✅ Ready

How TelosMUD grants elevated powers. A trust tier is an ordinal rung on a content-defined ladder, carried on the account, verified into a session at login, and turned into a small set of capability flags by the world. This page covers the world side — the ladder, how a verified tier becomes flags, the reserved-flag denylist, the rank-comparison rules, and what happens to elevation across a cross-shard walk. The account side — where tiers are stored and changed — is in First Admin Setup; the staff verbs the flags unlock are in Builder Commands.

The ladder is content-defined

A tier is { name, rank, flags }: a rank integer (higher = more trusted) and the set of capability flags that tier grants. The full ladder is content — a pack can define trust_tiers (see Pack Entity Reference) — and the engine ships a default ladder if a pack declares none:

Tier Rank Grants
player 0 (none)
builder 20 holylight, builder
admin 40 holylight, builder, admin

The 10/30 gaps are deliberate room for a pack to insert its own rungs between the defaults. A world uses the pack's ladder if it declared one, otherwise the shared default.

Rank resolution is fail-safe. An empty, "player", unknown, or drifted tier name resolves to rank 0 — garbage or a stale tier name can never read as elevation. An empty-named rung is dropped when the ladder is built, so "" can never resolve to a defined rung.

From verified tier to capability flags

The world never decides your tier; it reads it off a signature-checked session assertion and applies it. The path on a fresh login:

  1. The world verifies the gate's signed session assertion offline against the account service's public key. Your loginTier is set only from a signature-checked claim — on a dev/unverified path it's empty (baseline).
  2. That tier travels into the session (s.tier).
  3. At the login room, after your persisted flags load, applyTierFlags reconciles your reserved flags: it sets each capability flag your tier grants and clears every other reserved flag.

That reconcile-on-every-login is the whole mechanism by which both promotion and demotion take effect — a since-revoked stale flag is cleared on your next login, and a new grant is set. There is no live re-tiering in the world; a promote/demote (account/edge-side) lands the next time you log in. Those gate verbs are themselves staff-only and invisible to a mortal — typing one returns a plain Huh? with no refusal and no account-service call, gated by a manage_tiers visibility bit on the session assertion while the account service stays authoritative (see Accounts & Auth Internals).

Reserved flags and the four-part denylist

Four flags are reserved: holylight, builder, admin, wizinvis. Being reserved buys four protections, so a capability can only ever come from the trust ladder — never from content, a save file, or a forged snapshot:

  1. Content can't set them. A pack's set_flag / clear_flag ops refuse reserved flags — a pack can't grant itself see-all or admin.
  2. They're never persisted. The character dump omits them.
  3. They're not restored from a snapshot. State/handoff restore skips reserved flags, so a forged state or handoff snapshot can't inject a capability.
  4. Only login and the staff toggles write them. applyTierFlags (at login) is their only login-time writer; the holylight/wizinvis toggles are the only others.

Reserved ≠ capability (why wizinvis isn't grantable)

The reserved set and the capability set differ by exactly one flag: wizinvis. wizinvis is reserved (content-unsettable, un-persisted, cleared at login) but not tier-grantable — it's a staff toggle, not something a tier confers. applyTierFlags filters grants through the capability set, which is derived as "reserved minus wizinvis." The important consequence: a future reserved flag defaults to non-capability, i.e. fails closed — a new reserved flag can't accidentally become tier-grantable.

For contrast, perception flags like detect_invis / sense_hidden / hidden are deliberately plain gameplay flags, not reserved — they affect perception only, never harm or authorization, so content is free to use them.

Rank-comparison rules

Rank drives several checks:

  • Command-use gate. To run a staff verb, your rank must be ≥ the verb's MinRank (rankStaff = 1, i.e. "any positive rank is staff"). Below that, the verb reads as unknown (see Builder Commands).
  • stat target gate. stat refuses a target whose rank exceeds yours; equal (yourself) is always allowed, and mobs/items/rooms are baseline rank 0, so always inspectable. You can't peek at someone more trusted than you.
  • wizinvis concealment. A wizinvis staffer is hidden from a viewer of strictly lower rank (resolved via the target's zone ladder). Equal-or-higher ranks see them; a holylight viewer sees everyone (checked first). A mortal's baseline 0 conceals from no one.
  • holylight on cap. Only a tier that grants holylight may enable the toggle.
  • debug live re-check. Delivery re-verifies your rank per line, so a mid-session demote stops zone-internal echoes before you even relog.

Elevation across a cross-shard walk

Current behavior: an admin or builder keeps their elevation when they walk between shards. The account tier rides the signed handoff snapshot (the tier is bound into the snapshot's signing input), and at the destination the session adopts that tier and re-derives its reserved flags via applyTierFlags when the pending session activates — before the arrival "look." So holylight/builder/admin carry across the boundary. Two caveats:

  • wizinvis clears on arrival. Because wizinvis is a session concealment and never tier-grantable, applyTierFlags clears it at the destination — a wizinvis staffer arrives visible and triggers the normal "$n arrives." This is a documented, intended one-time presence flicker across a shard boundary, not a bug.
  • Elevation survives only on a signed path. A keyless dev/test shard that skips signature verification does not carry a trustworthy tier and fails closed to baseline. (Such deployments are single-shard and never hand off, so this is not a live-fleet concern.)

The flags themselves are not carried in the snapshot (protection #3 above) — the destination re-derives them from the carried, signed tier. Carrying the tier and re-deriving the flags is what keeps this both consistent and forgery-proof.

The direction

The current model is a small reserved-flag capability set keyed off an ordinal ladder. The intended direction is a fully content-defined, per-command permission model — where a pack can express which tier (or capability) each command requires, rather than the engine's fixed rankStaff gate. A reserved builder-admin subsection here will document that once it lands.

Related: First Admin Setup (granting/revoking, the audit trail), Builder Commands (the verbs these flags unlock), Accounts & Auth Internals (the signed assertion / auth boundary).

Clone this wiki locally