# Ranked Games, Rankings and Player Trust

> What a ranked match guarantees and what it does not: grades, disputes, consent takebacks, placement, ladders and seasons, Scores and Player Trust.

- Source: https://diceytable.com/docs/mods/concepts/ranked-games
- Last verified: 2026-10-04

A **ranked match** is one game of a fully scripted variant whose result counts. Each player has a **Score** per
ladder, shown on the game's **Rankings**. Scores are public, and so is each player's **Player Trust** tier, which
is how DiceyTable tells people who play fair from people who do not.

This page is for authors deciding whether to offer ranked play, and for anyone who wants to know what a ranked
result is worth. The script side is [Matches and Variants](https://diceytable.com/docs/scripting-api/matches); the manifest side is
[`variants[].ranking`](https://diceytable.com/docs/mods/manifest/reference#variants).

Two words, used precisely. The number is a **Score**. The feature is **Rankings**. "Rating" on DiceyTable means
the one-to-five-star review of a game, and nothing on this page.

## What makes a game rankable

A game is ranked **per variant**, and three things must all be true:

1. **The variant is Fully scripted.** Its manifest entry says
   [`rulesEnforced: true`](https://diceytable.com/docs/mods/manifest/reference#variants): the variant's script enforces the rules and
   decides the result. Ranking a game whose players move pieces by hand would rank whoever was best at arguing.
2. **The variant offers ranked play.** It has a `ranking` block, with `enabled` not `false`. Switching **Fully
   scripted** on in [the Variants dialog](https://diceytable.com/docs/editor/interface/topbar#the-variants-dialog) adds one with every
   setting at its default.
3. **A script attached to the variant calls `match.end(`.** A ranked match whose result nobody reports could
   never finish, so publishing refuses the variant without one
   ([`ranked-variant-no-match-end`](https://diceytable.com/docs/mods/scanner/what-gets-rejected#ranked-variant-no-match-end)).

Then, in the lobby, the room's owner switches **Ranked** on. The variant shows **Fully scripted** and **Ranked
available** badges so players know what they are choosing.

## Who can play ranked

Every human participant must be signed in, on an up-to-date client, without an AI agent attached, and not
trust-locked. When the owner presses Start with **Ranked** on, the server checks each of them and refuses the
Start, naming who and why, if any check fails. It also refuses when fewer than two sides are seated, when bots
are seated in a variant that does not rank them, and when the host is trust-locked (the host proposes results,
so a locked host cannot run a ranked match even as a spectator).

Two caps stop Scores being farmed:

- **5 ranked matches per pair of accounts per day, per ladder.** Two friends cannot play each other a hundred
  times to pump one Score.
- **20 ranked matches a day against bots only, per player, per ladder.**

The checks run again at the start of every match. A player who sat down after Start, or a lock that landed
since, makes **that match** unranked without ending the room's ranked play. The match still plays; it just does
not count, and players are told why.

## What is and is not guaranteed

Read this before you tell anyone that a ranked result is trustworthy. **Rankings are not cheat-proof.** The host's
browser runs the game, so a modified client can do things an honest one cannot, and DiceyTable's defence is to
make lying detectable and costly rather than impossible. This is the table we work from.

| Threat | Control | Residual risk |
|---|---|---|
| Host invents a win against another human | The other human's client attests. For kernel games it **replays** the moves and checks the kernel's result. A mismatch → **disputed**, and a dispute is recorded against both parties. With 3+ humans the majority result stands and the host is flagged as minority (weight 2.0). | A **two-human** dispute cannot be resolved automatically: the host's result stands, both parties get weight 1.0, and admins review. A repeat liar reaches the lock in ≤ 3 disputes. Win-trading collusion is limited by caps, not eliminated. |
| Host lies only to the server | The attestation hash covers ranks, roster and record hash → mismatch → dispute. | None beyond the above. |
| A player falsely disputes every loss | Every false dispute also costs the disputer weight 1.0 (two humans) or 2.0 (minority). They reach the lock as fast as a lying host. Admins can attribute fault. | A false disputer can cost an honest opponent up to 1.0 per two-human match before review. Mitigation: admins clear the victim's records. The public tier uses decayed points with a Caution threshold (1.5) above a single dispute. |
| Host aborts a match it is losing | Past the variant's `minSeconds`, with another human playing, the server treats [`match.abort`](https://diceytable.com/docs/scripting-api/matches#matchabort) as **the host resigning**. Only an early abort, or one with no other human playing, is void. A record that fails the host's own check or outgrows its limits ends as no contest and, with another human playing, is flagged for admin review. | A host can still fake a no-contest ending; review makes a host who does it repeatedly visible. |
| Loser closes the tab | Server-observed; forfeit after 90 s. | Honest disconnects are protected for trust (see below), but not for the match result (same as chess.com/BGA). |
| Host rewrites the table (undo/load) without consent | An honest client cannot: the UI requires a granted consent id. For kernel games, a modified host that rewinds without consent produces a record that peers' replays reject, because every takeback must cite a server-granted consent id. | For **non-kernel** games, a modified host client can rewrite the table undetectably. This is the general limit of `attested` grade, and it is documented. |
| Solo human vs bot (the host runs the bot) | Graded `self-hosted`; 20 per day per pool; records stored for later re-verification; takebacks refused. | A modified client can weaken its bot. Glicko-2 bounds the gain near the strongest bot's Score. |
| Non-kernel game | Graded `attested`. `ranking.requireKernel` opts out. | The host's script is the authority. |
| Agent plays | Server-attested `agentActive` → blocked at Start, voided mid-match. | As for chips and stats. |
| Alt-account farming | Signed-in accounts only; no duplicate seats; 5 matches per pair per 24 h per pool; minimum length. | Two real accounts playing genuine full games. Accepted. |
| A locked account keeps playing **ranked** | Server-side, at every point a match can become ranked: the ranked Start blocker `trust-locked` (409), the match-open re-check (a locked participant or a locked host makes the match unranked), and host migration during a live ranked match (a locked promoted host voids it). Casual play, public rooms included, is deliberately unaffected. | A connected session is not kicked; the lock bites at the next ranked qualification check. |
| A client floods the server with match messages | Every match message is rate-limited per connection on the server; over the limit it is dropped without being processed or stored. Consent requests have their own, tighter limit. | None for honest play, which stays well inside the limits. |
| Rules change under a ladder | The match records the mod's commit, the kernel id/version, the pool and the season. The author bumps `season`. | An author who does not bump it. |
| A rogue or mistaken admin | Admin access is checked on the server. Every admin change is audit-logged with before/after and a mandatory reason. The log is append-only. | A database superuser. Out of scope. |

## Grades

Every finalized ranked match carries a **grade**, shown beside its result. It says how the result was checked,
not who won.

| Grade | When | What it means |
|---|---|---|
| `kernel-verified` | The match has a move record (a kernel match), and at least one other human's client replayed it and agreed. | The strongest check: the moves were replayed with the game's own rules. |
| `attested` | Every other case with another human: no kernel, or nobody replayed. | Another human confirmed what they saw. |
| `self-hosted` | No other human took part (one person against bots). | Nobody but the host saw it. The record is kept so it can be re-verified later. |

A disputed match keeps its grade, with the dispute shown beside it. An author who wants every ranked result to be
`kernel-verified`-capable sets [`ranking.requireKernel`](https://diceytable.com/docs/mods/manifest/reference#variants).

## When players disagree

When a ranked match ends, every other human participant's client either **agrees** with the host's result,
**disagrees** (and reports the result it believes), or cannot verify. Silence and "cannot verify" are not votes.
Bots never vote.

- **Nobody disagrees.** The host's result is scored. This is nearly every match.
- **Somebody disagrees.** The match is **finalized and disputed**. It is still scored, never left hanging, and it
  goes to the admin queue.
  - If one result has a **strict majority of all votes**, the host's included, that result is scored. With three
    humans, two who agree outvote a host who does not.
  - Otherwise the **host's result** is scored. That covers the two-human case, one vote against one, and any split.

Every disputed match records a dispute against the host and against each player who disagreed, weighted by how
it went:

| Side | Weight |
|---|---|
| Lost to a strict majority (the minority) | 2.0 |
| No strict majority (two humans, or a split) | 1.0 each |
| On the winning majority | 0.25 |

Players who agreed get nothing recorded. Each party to a dispute sees "Disputed: result under review" on their
match and which result stands; only admins see what everyone reported. Admins can re-score or void a match and
clear dispute records that were not a player's fault.

Other endings are not disputes: any time an AI agent controls a participant **voids** the match, a match shorter
than the variant's minimum is **no contest**, and a match decided by forfeits finalizes at once with no result to
argue about.

## Takebacks need everyone to agree

During a live ranked match **nothing that rewrites the table is unilateral**, for the host or anyone else.

| Action | Who may ask | Who must agree | What happens |
|---|---|---|---|
| **Undo** (takeback) | Any human participant | Every other human participant, within 60 seconds | The match stays ranked. The host restores the previous checkpoint and the script is told ([`match.onTakeback`](https://diceytable.com/docs/scripting-api/matches#matchontakeback)). |
| **Load a save** (including **Load from File** and **Restore Autosave**), **Reset the table**, **Edit Mode** | The host | Every other human participant | The match ends **void** (unranked), then the action goes ahead. |
| Spawn from the library, delete, the scale tool, move a participant to another seat, add or remove a bot | Nobody | — | Blocked until the match ends. |

Dice, cards, flips and every move the game is actually played with stay open.

**The four-declines rule.** A request ends one of three ways:

- **Yes from everyone** — it happens.
- **An explicit No** from any player — it does not happen, and it is a **strike** against the player who asked.
- **No answer within 60 seconds** — it does not happen ("No answer, so the move stands"), and it is **not** a
  strike.

A player's fourth strike in a match ends their undo requests for the rest of it: "No more undo requests this
game". The host's load/reset/Edit Mode requests have a separate counter with the same rule. A request the server
turns down before anyone is asked (nothing to take back, another request already waiting) is not a strike.

Why it cannot be gamed: an opponent cannot use up your requests by ignoring them, because silence is never a
strike. And a player cannot get round the rule by spamming requests and letting them time out, because only one
request can be waiting at a time, so each unanswered one costs them a full minute, while the other player can end
any of them at once by saying No. Saying No never costs the person who says it anything.

Some limits worth knowing:

- **Against bots only, a takeback is refused**: "Undo needs another player to agree, and bots can't".
- **Up to 10 moves back**, one agreed step at a time, fewer on a very large table. The host publishes how far
  back it can go, so Undo is disabled once there is nothing left to restore.
- **A takeback the host cannot restore changes nothing.** After a host change (checkpoints live in the host's
  memory and do not move with it), or beyond the checkpoints the host holds, an agreed takeback leaves the table
  and the moves as they were and shows "Can't go back further on this table". The script is not told.
- **A variant can switch takebacks off** with [`ranking.takebacks`](https://diceytable.com/docs/mods/manifest/reference#variants),
  for games where a move cannot honestly be undone.

## Scores, placement, ladders and seasons

**Everyone starts at 1500**, bots included. Each bot has its own Score per difficulty, and earns and loses it
exactly as people do.

- **Two sides of one player each** (chess, backgammon, a duel) are scored with **Glicko-2**.
- **Three or more sides** are scored with **Weng-Lin**, which understands places and ties, so second of five is
  worth more than last. Both are shown on the same 1500 scale.

A Score is more certain the more a player plays; after a long break it becomes less certain again, so the first
games back move it further.

**Placement.** A new player is in placement for the variant's first
[`placementGames`](https://diceytable.com/docs/mods/manifest/reference#variants) ranked games (5 by default): their Score moves, but
they are hidden from Rankings and shown as "Placement 3/5". Rankings list established players only.

**Ladders (pools).** Variants that share a `ranking.pool` share one set of Scores. By default each variant is its
own ladder. Variants on one ladder must rank the same sides and seat the same player range.

**Seasons.** Bumping `ranking.season` starts a fresh ladder once you publish: everyone begins again at 1500 and
the old season stays readable. Do it when the rules change enough that old Scores stop meaning the same thing.

Every finished match is in the players' match history, which they can show to everyone, to friends, or to
nobody.

## Player Trust

Every account has a public **trust tier**, shown on profiles and on lobby member rows. It is a label, never a
number:

| Tier | Badge | When |
|---|---|---|
| **Locked** | Red lock | Ranked play is paused for this account while a review is pending. |
| **Caution** | Amber shield | Some recent ranked matches had problems: trust points of 1.5 or more, or a sustained pattern of abandoned matches. |
| **New** | Neutral | Fewer than 5 ranked matches so far. The default for everyone; it judges nothing. |
| **Trusted** | Green shield | A long record of clean ranked matches: at least 25, few points, and an account at least 30 days old. |
| **Good standing** | Subtle | Everyone else. |

The first tier that applies, reading down, is the one shown. The Locked tooltip never gives a reason.

**What moves it.** Trust points come from disputes (their weights above), from abandoned ranked matches (0.5) and
from an AI agent taking over mid-match (1.0). Every clean ranked match takes a little off (0.1). Points fade with
a half-life of 45 days, so recovery comes from playing fairly plus time. **Resigning and saying No to a takeback
never cost trust.**

**Honest disconnects are protected.** An abandon does not count when the server was restarting, when everybody in
the room dropped within the same few seconds, or when it is your first in a week. Even counted abandons never lock
an account.

**The lock.** An account whose dispute weights add up to **3.0 within any 30 days** (records an admin cleared do
not count) is locked automatically and goes to the admin queue. A lock lifts only by an admin's decision, never on
its own.

**A lock affects ranked play only.** A locked player can still create, join and host any room, public or
private, and play there unranked. They cannot take part in, or host, a ranked match. Your own trust page lists
every event that counts, in plain words, with the date it stops mattering.

## See also

- [Matches and Variants](https://diceytable.com/docs/scripting-api/matches) — writing the script.
- [Game variants](https://diceytable.com/docs/mods/manifest/variants) — `rulesEnforced` and `ranking` in the manifest.
- [The Variants dialog](https://diceytable.com/docs/editor/interface/topbar#the-variants-dialog) — Fully scripted and Ranked play in the editor.
- [Game bots](https://diceytable.com/docs/mods/concepts/bots) — bots that earn a Score of their own.
- [What gets rejected](https://diceytable.com/docs/mods/scanner/what-gets-rejected#ranked-variant-rules-4) — the four ranked-variant refusals.
