Sigildream Tech Blog

How a duel is born, second by second

A player presses «Enter the Arena». At the same instant, thousands of kilometres away, someone else does exactly the same. A few seconds later they are face to face in the same live duel. In those few seconds an invisible match is played out: deciding who faces whom so the challenge is balanced, and where in the world to run the clash.

What Sigilwake is. A turn-based combat role-playing game, in a black-and-white manga style, mobile-first, cross-platform (Web, Android, iOS, macOS, Windows), today in a validation phase. One-on-one duels: two fighters, four abilities each, cinematic animations, matches that can be played, followed live and rewatched as replays. The roster comprises 24 characters, all different from one another.
#GameAI   #GameBalance   #DevLog
From ticket to live match — the broker’s orbit A queue of matchmaking tickets on the left is drawn into a central pairing hub. The hub emits match tokens outward, paired to three regional combat servers labelled EU-WEST, US-EAST and APAC. Small bright pulses travel along the inbound and outbound paths, indicating the direction and low latency of the broker's hot path. TICKET · QUEUE BROKER · PAIRING COMBAT · REGIONS ticket · Varro μ 1502 φ 68 tier 3 · EU ticket · Nyx μ 1459 φ 72 tier 3 · EU ticket · Boreus μ 1611 φ 54 tier 4 · US pairing 12 MiB · 0.4% CPU signature EU arena warm · 200 ms EU region US arena warm · 210 ms US region Asia arena cold · ~5 s Asia region TAP → first turn 3–5 s · 7 systems · 3 signed hand-offs
Ticket → Broker → Combat allocation, one single request path. p50 ∼ 3.6 s

Act 1 · The four seconds

Three roles pass the baton to bring a player into the arena.

Behind that single tap on «Enter the Arena», three systems pass the baton like a relay. The first holds the queue: it collects the request to play and keeps it until it finds an opponent. The second is the pairing referee: it decides who faces whom so the challenge is balanced, and assigns an arena. The third lights up that arena — a dedicated server, in the corner of the world closest to both. They are separate roles for a good reason: this way each does one thing only, and when something slows down it is immediately clear which of the three to look at.

The main server

Who holds the queue

Holds the queue of those who want to play: it keeps every request until it finds an opponent. It checks the queue at a steady rhythm, with a maximum waiting time beyond which a fallback route kicks in.

The pairing service

The pairing referee

A dedicated service, called with a signed internal call for every proposed pair. It compares the value of the two players, prepares the single-use match keys and picks the nearest region. Steady-state footprint: 12 MiB of RAM and 0.4% of CPU across more than 2,800 pairs.

Geolocated micro-arenas

Who lights up the arena

Geolocated micro-instances light up a small arena in the region nearest the two players, host it and shut it down as soon as it ends. If one is already free, delivery is under a second; otherwise a new one is born in about 5 seconds.

Under the hood. They used to be a single block inside Nakama, our main server. Under strain — ten thousand players at once in the worst case — that block devoured memory and even slowed down other players logging in. We split it into three independent services, and the memory used dropped from 3.08 GiB to 1.59 GiB under the same load. Above, who they are and what they really cost.
a single Nakama block → three services · −1.5 GiB of RAM

Why separate them? The main server is excellent at tasks that are in no hurry: holding sessions, storing data, sending notifications. Acting as the pairing referee under heavy load, however, is not what it does best — and in our measurements it showed.

The stress test that convinced us to separate it tells of two advantages. The first is memory: from 3.08 GiB to 1.59 GiB, under the same workload. The second is the freedom to evolve the pairing rules independently, without waiting for updates to the main server.

A new rating rule, an extra defence against those who create a fresh account to beat beginners, another backup route to the match against the computer: that single service is updated and restarted in a few seconds. The main server, the database and the app on the phone remain untouched.

Act 1 · the flow, second by second

What happens behind the loading spinner.

For the player it is just a wait of a few seconds. Behind that spinner the three roles pass the baton along a precise relay: collect the player, find the opponent, light up the arena, hand each of them the key to enter it. The line below shows that relay second by second, with the time each step can take.

Under the hood. The player's app sends a single request; everything else happens on our servers. Seven systems coordinate along a path with three signed hand-offs — so no one can impersonate anyone else.

Matchmaking flow timeline — from client tap to first turn A horizontal seven-step timeline representing the wall-clock path from the tap on the player's client to the first frame of combat. Steps: 1 client tap (~40 ms), 2 ticket queue (wait up to 15 s), 3 proposed pair (~90 ms), 4 rating and identity check (~30 ms), 5 creation of the match keys (~2 ms), 6 server allocation (~200 ms warm), 7 client connection to combat (~120 ms). A moving pulse travels along the timeline indicating the direction of the request; a shaded queue-wait band highlights step 2 where most of the elapsed time accumulates. WALL-CLOCK · p50 target budget · not committed as an SLO END-TO-END target ≈ 3.6 s QUEUE WAIT 1 client tap app ~40 ms queued 2 ticket queue tick 1 s · 15 intervals 0 – 15 s until paired 3 proposed pair signature → broker ~90 ms matching 4 rating & identity store read ~30 ms single-use key 5 match keys one key per seat ~2 ms short-lived 6 server allocation warm pool ~200 ms cold: ~5 s 7 first turn app → combat ~120 ms key check main server pairing service geolocated micro-arenas + combat
The queue-wait band on step 2 is where most of the time accumulates — the other six steps put together stay well under a second when there are enough people in line.
1

Player tap

The player’s app

The app opens a connection to the main server.

~40 ms

If it goes wrong: it retries, waiting a little longer each time; the button stays locked while the request is in progress, to avoid double taps.

2

Waiting queue

The main server

The request enters the line.

0–15 s until paired

If it goes wrong: once the maximum waiting time passes, the same request is promoted to a match against the AI.

3

Proposed pair

The main server

A signed internal call to the pairing service.

~90 ms

If it goes wrong: if the service does not answer, the path falls back on its own to a backup route, with no errors for the player.

4

Rating & identity

Pairing service

Rating computation and exclusive assignment of the match.

~30 ms

If it goes wrong: if the store is slow, it falls back to the backup route; if the match turns out to be already assigned, the pair is re-proposed.

5

Match key

Pairing service

A signed key for each player.

~2 ms

If it goes wrong: the keys are valid for a few minutes and are consumed on the first entry into the arena; a second attempt with the same key is rejected.

6

Allocation

Geolocated micro-arenas

An arena lights up in the nearest region — or the local twin in development.

~200 ms warm · ~5 s cold

If it goes wrong: if a region is struggling, the allocation moves elsewhere without our code stepping in.

7

Entering the arena

Player’s app → combat server

The app enters the arena with its match key.

~120 ms

If it goes wrong: the reconnection protocol covers server changes — see the chapter on combat.

Act 2 · Balanced opponents, not random

How much a player is worth — and how sure we are of it.

A random opponent is a coin toss: boring for the strong, punishing for the beginner. That is why pairing is not random. Before placing two people opposite each other the system asks two questions: how good each is, and how sure we are of it. A freshly registered player and a veteran returning after a month may have the same rating on paper, but we know far less about the first — and treating them as if we knew just as much would produce lopsided matches. Measuring our uncertainty too is what turns pairing into a real challenge rather than a roll of the dice.

Under the hood. A naive rating system keeps a single number per player: how good they are. Ours keeps three: how much we think they are worth (μ), how much uncertainty there is around that value (φ) and how volatile that value is over time (σ). All three matter, for instance, when pitting a veteran who has not played for a month against a second account with which a strong player hides among beginners, perhaps in the middle of a winning streak. On top of these three numbers our system adds four in-house corrections, each closing one of the four ways in which, in competitive turn-based games, people try to game the rating.

How two players’ ratings change over time A rating drift chart. The x axis is the number of matches played from 0 to 40. The y axis is the mu rating of the rating system from 1300 to 1700. Two players are traced: player A starting from 1500 in gold, and player B, a returning veteran, starting from 1620 in violet. A shaded rating deviation (phi) band wraps each line to show the uncertainty. Four numbered inflection points annotate the four adjustments of our rating system: 1 per-character win-rate normalisation at match 8, 2 per-tier anti-smurf gate applied at match 14, 3 losing-streak damping that kicks in around match 22, and 4 RD decay floor for inactivity reached at match 32. A dashed baseline at mu 1500 marks the global median of the rating. 1700 1600 1500 1400 1300 0 5 10 15 20 25 30 35 40 MATCHES PLAYED rating (μ) 1 normalise char WR 2 anti-smurf gate 3 loss damping 4 RD floor player A · new account · φ narrowing player B · returning veteran · wide φ → floor baseline μ = 1500
Two players, forty matches, the four corrections of our rating system. Player A's uncertainty band narrows as the system grows more confident of their worth; player B's stays wide until the inactivity time stops it at a minimum value. Each correction is a numbered point on the curve.

1. The character does not count twice

The 24 characters do not all win with the same ease: some, in the current stage of the game, are stronger and others weaker. The rating accounts for this starting advantage or disadvantage, so that whoever picks a weaker character in the current stage is not penalised twice. The comparison between characters is redone from time to time, in the background; while playing, the already-computed value is fetched in an instant, without slowing the match.

2. The strong disguised as beginners

If a much stronger player continually faces people far weaker than themselves, they gain far less rating from their wins and lose far more from their losses. On top of that, accounts less than an hour old are kept in a separate line, so a wave of such profiles does not touch those who play fairly.

3. Losses in a row do not sink the rating

Several losses in a row raise our uncertainty (φ): it means we are no longer so sure of what that player is really worth. This cushions the losses that follow and avoids a runaway collapse. It is the least one can do not to drive people away: without it, one bad evening would turn into a 200-point drop to claw back over weeks.

4. The return after a long absence

If a player stays away for a long time, our confidence in their worth loosens, but only up to a certain limit — so a veteran returning after a month does not immediately find themselves up against one of the very best on their first Sunday back.

Act 2 · the knobs that keep the queue moving

How long to wait before widening the search.

Finding a balanced opponent costs time: the longer the search stays narrow, the better the pairing — but no one wants to stare forever at a spinning wheel. All the tuning in this part lives inside this tension: wait long enough to find the right person, widen the search before the wait becomes an annoyance, and keep the queue flowing even when thousands of requests arrive at the same instant.

Under the hood. Governing that rhythm is a handful of numbers on our main server — how often to check the queue, how long to keep a request alive, how many to hold at once. The default settings were simply too conservative for the worst case, tens of thousands of players queued at the same moment. The values below are the ones that keep the queue moving instead of piling up delay.

How often to check the queue

1 second

More often weighs too heavily on compute; less often overshoots the 3–5 s promised to players.

How long to keep a request alive

~15 seconds

Beyond this threshold it switches to a match against the AI: the balance point between waiting and seeming stuck.

How many requests to hold at once

20,000

Twice the 10,000-player scenario, headroom for the «all at once» peak.

How many internal workers to keep ready

from 32 to 64

The factory setting jammed within a second under 10,000 players; these values held up in every stress test.

Act 2 · the referee, opened up

The pairing referee, and the two promises it never breaks.

The piece that really decides who faces whom is a small service of its own: the referee. For every proposed pair it works out whether the clash will be balanced, assigns an arena and hands each player the key to enter it. It is fast and cheap to keep running, and in this part it is opened up piece by piece.

Under the hood. It is a small dedicated service, with a handful of functions and a state model pared to the bone. Beneath the surface, the «two promises» are two technical guarantees: that a match's identity can be spent only once, and that winner and loser stay bound to exactly the two paired players. Here are the service's surface and the two invariants.

The pairing arbiter and the two promises it never breaks At the top a proposed pair — two players — enters a central node, the arbiter, which checks whether the clash is fair, assigns an arena and hands each of them a key. Below, two panels show the two promises. The first: a match's identity goes from open to spent in a single step, and every repeated attempt bounces away, rejected. The second: only the two paired players enter the arena, while a stranger is turned away. ACT 2 · THE ARBITER two promises · never broken PROPOSED PAIR THE ARBITER ARENA · KEYS player A seeking a match player B seeking a match arbiter fairness · arena · keys arena assigned one key per player key A key B THE TWO PROMISES THE ARBITER NEVER BREAKS 1 A match's identity is spent only once open identity free a single step spent re-propose · reuse a key · recovery after a crash bounces — rejected no coins, no rating 2 Winner and loser tied to the two paired players ARENA same match admitted player A A player B B stranger ? no one slips into their place
The arbiter checks fairness, assigns the arena and hands out the keys — without ever breaking the two promises. one match, one identity, two players

What the service does

Its surface is a handful of internal functions, not exposed to the public: the health checks for monitoring, the pairings requested by the main server, the matches against the AI and the rating update at the end of a match. They are all calls between our services, each one signed and verified.

Two promises the service never breaks

  1. A match's identity is spent only once, across the whole platform. Every match has a unique identity that goes from «open» to «consumed» in a single indivisible operation. Every subsequent attempt — re-proposing the pair, reusing a key, a recovery cycle after a crash — is rejected instantly: no coin touched, no rating written, no session opened.
  2. Winner and loser stay tied to the two paired players. Whoever shows up at the arena must be one of the two originally paired for that match, and the same check applies to every rating update. No one else can slip into their place.

A single step to pair and assign

The two operations — finding the pair and lighting them an arena — have been merged into a single step, to halve the time and never leave a match half-done: either everything happens, or nothing does.

The response delivers everything needed to enter the arena: where the fight happens, a single-use match key for each player, and a few numbers on the quality of the pairing (how close the two ratings are).

Act 3 · Cheat-proof

How a service proves it really is itself.

A phone is a screen, not a referee. It cannot be taken at its word when it declares a rating, claims a victory or states who it is. This is where the whole structure of this section begins: every message carries a signature, every match hands out single-use keys, and every result is re-verified on our servers before a single coin or ranking position moves. It starts with the signature — the way in which, even between our own servers, one proves it really is itself and not an impostor, like a wax seal that no one else can reproduce.

Under the hood. Every internal call to the pairing service is a signed request: the signature travels together with the message, and whoever receives it checks that it is authentic before heeding a single word. Here is the idea, without the recipe.

The signed handshake — a message no impostor can forge Two nodes side by side: on the left the combat server, on the right our server. A message, drawn as an envelope, travels along a dashed connector from left to right; halfway along a seal appears on the envelope, that is, the signature. On arrival the receiver shows a tick to indicate that the signature has been verified. Lower down an impostor message, drawn in a faint tone and a different colour, tries to approach but is rejected with a cross before reaching the receiver. ACT 3 · THE SIGNATURE no impostor can forge it combat server generates and signs the message our server verifies the signature before trusting message signature whoever sees it cannot remake it verified impostor rejected
The combat server places a signature on the message; our server checks it on arrival and trusts it only if it matches. A message without a valid signature — an impostor — is rejected before being believed.

In practice, every internal message carries with it a cryptographic signature that certifies both its sender and its content together: if even a single character of the message changes, the signature no longer matches and the request is rejected. The signature is valid for a very short time and cannot be reused, so not even someone who managed to intercept it could replay it.

Act 3 · the match key

The single-use key that opens the right door for the right two players.

Once the pair is found, each of the two players receives a key — not just any key, but one that opens exactly one door, once only, and that demagnetises itself after a few minutes. It is the same idea as a hotel keycard: only the right guest enters the right room, and once the stay is over it is good for nothing. This way the two paired opponents — and no one else — end up in the same arena, and that key cannot be reused to sneak in a second time.

Under the hood. The keys are two signed tokens, one per seat, valid for a few minutes and with no renewal. What makes them secure, rather than a mere formality, is the way they are «consumed»: the first time one of the two enters the arena, the key is marked as spent in a single indivisible operation, and every subsequent attempt is rejected. Here is the idea.

The single-use key — one door, once only A diagram with a match core at centre-left that emits two match keys, one for each player. The gold key travels toward player A's arena door, the violet one toward player B's door. When a key enters its door, the door lights up green and opens. Each key opens the door once only: on a second attempt the same key comes up already used and expired, greyed out and crossed. Two moving pulses show the direction of emission; the rest of the diagram stays readable even with animations disabled. ACT 3 · THE MATCH KEY single-use · one door, once match key the match emits one key per player player A ARENA open player B ARENA open 2nd attempt 2nd attempt already used key expired already used key expired player A key player B key door open key used / expired
Every match hands out a single-use key per player: it opens the door to its own arena once only, then expires. Re-presenting the same key opens nothing more — it comes up already used.

Every key says the essentials and nothing more: who its owner is, which match it is valid for and with which character. The distinction between the two seats, and the opponent's identity, do not live inside the key. When a player shows up at the arena, the combat server verifies the signature and then «spends» the key in a single indivisible operation: from that moment it is spent, and anyone who re-presents the same key is rejected. It is exactly what prevents replaying the same match twice to double the reward.

Act 3 · the result, and the holes we closed

How a finished match becomes reward, ranking and training data — without anyone being able to falsify it.

Once a match is over, the players cannot be taken at their word on the result: the verdict is reconstructed and re-verified on our servers before a single coin changes hands or a ranking position shifts. Only then does the same result become three things at once — the reward for the winner, the ranking update and a row of data with which we train the artificial intelligence that will one day play like a champion.

Under the hood. When a match ends, the combat server does not create the rewards itself: it never touches either the wallet or the ranking. It signs the verdict and sends it, with two separate signed messages, to the two services that have the authority to make it effective — one credits the coins and updates the ranking, the other updates the ratings. Each redoes its own checks before moving anything.

Only if all these checks pass — together with the positive outcome of a further layer of security, which stays confidential and serves to verify the flow of messages — is the result made effective.

Result reconciliation — from combat to the main server and the pairing A three-node reconciliation flow. On the left, a combat container ends a match and emits two signed messages in parallel: one toward our main server, on the upper branch, which assigns the rewards and updates the rankings, and one toward the pairing referee, on the lower branch, which securely updates the players' rating. Both paths converge on a shared, persistent match record. Along each path, an icon indicates that the hand-off is signed and verified on our servers. COMBAT · match finished MAIN SERVER · rewards + ranking PAIRING · updates rating DATABASE · durable record combat-server match end · authoritative signs 2 envelopes signature signed message 4 GATE validity checks anti-replay check main server signed verdict coins + ranking once only per match 3 GATE outcome checks single-use key pairing updates rating updates rating batched · Phase B database rating + wallet append only batched updates SECURITY CHECKS ON THIS PATH outcome verified single-use key size limits anti-replay protected access rate limits
The combat server signs two messages in parallel — one toward the service that credits the coins, one toward the one that updates the ratings. Each branch has its own checks, and combat never touches wallet or ranking directly.

From the combat server to the rest of the platform

The end-of-match verdict travels as a signed message, and whoever receives it does not trust it on faith: it checks that the signature is authentic, that it comes from an authorised combat server, that it is recent and that it has not been seen before. Only if all these checks pass is the result made effective.

Act 4 · Combat runs close to the players

Micro-arenas born next to the two players, anywhere in the world.

A clash does not run in a single large compute centre on the other side of the planet: it runs in a small self-standing arena, born in the region nearest the two players, hosting the match and vanishing as soon as it ends. It is an advanced system of geolocated combat micro-instances — many small independent arenas that appear where they are needed, when they are needed. This way the duel is responsive and fair wherever the challengers are, in Milan as in Tokyo.

Under the hood. It is a distributed architecture that we build and run ourselves, on real production cloud infrastructure, with four concrete advantages.

  • Latency the arena lights up in the region nearest to both, so commands travel little and the clash responds instantly.
  • Resilience if a region has a problem, the clash is rerouted on its own to a nearby region — no match lost, no downtime.
  • Elastic adaptation capacity follows demand in real time across the world, thousands of arenas at the peaks and almost none in the quiet moments, without waste.
  • Integration the whole thing is woven deeply into the rest of the platform, not bolted on at the side — a real distributed system, not a slide.

The combat load is the most unpredictable part of our infrastructure: at peak hour the demand in Europe can be worth four times that of Asia in its quiet hours, within the same 24-hour span. A system of micro-arenas that light up and shut down on their own, region by region, follows this wave without keeping a peak-sized fleet running for nothing.

Global presence — ephemeral arenas close to the players An abstract map of the world with three generic regions: Americas, Europe, Asia. In each region a pair of players is flanked by an arena that lights up beside them, illustrated by a pulsing gold node; a short distance away a grey, switched-off node represents an arena already dismissed at the end of a match. At the bottom a band shows a small set of already-ready arenas. The bright pulses indicate the active arenas and the link with the players; every animation turns off under the reduced-motion setting. GLOBAL PRESENCE · the arena is born close to the players no owned datacentre Americas players nearby arena active dismissed Europe players nearby arena active dismissed Asia players nearby arena active dismissed WARM POOL arenas already ready, never off ready ready ready nearby arena dismissed ready players
Every arena is born in the region nearest the two players, hosts the clash and is dismissed once the match is over; a small set of arenas stays always ready to reduce the wait.

Why run it distributed

Close to the players. The arena lights up in the region nearest to both players, not in a single point of the globe: commands travel less distance and the duel stays responsive and fair even across different continents.

It does not stop. If a region runs into trouble, the clash is moved on its own to a nearby region, without anyone noticing and without losing the match in progress.

It grows and shrinks on its own. The number of arenas follows demand minute by minute across the world: thousands when everyone is playing, almost none in the empty hours, no capacity kept running for nothing.

Part of the system, not an accessory. It runs on real production cloud infrastructure and is woven deeply into the rest of the platform: the decision of who faces whom, the unfolding of the match and the final report always remain in our hands.

The life cycle of an arena, in a single breath

In each region a small group of arenas is kept on and ready; our system picks one and receives the address to send the two players to; the arena welcomes the challengers and hosts the match; once the match is over it signs the verdict, the rewards service credits the coins and updates the rankings, and the arena returns to the group of ready ones — the surplus ones shut down.

A local twin identical to production

In development the same micro-arena system runs in a local twin: it speaks exactly the same language and lights up combat arenas when the main server is too loaded. Running the same code in development and in production means scale problems surface on the laptop, not on a Sunday evening. This twin too was put through a security audit before being used, and is confined to the smallest possible footprint.

Act 4 · the numbers, measured in the field

What really holds up, measured with real data.

Every figure in this part comes from an empirical reading under load, not from an estimate. The goal is to state precisely what the stack holds up when pushed, and where it begins to crack — even when the answer is uncomfortable: only numbers anchored to load tests actually run, never a figure «in the millions» where the measurements say thousands.

Under the hood. Here are the measured limits, row by row — sustained load, worst case, gains after separating the pairing referee from the main server — with the source of every figure alongside and, where a number is a design goal rather than a measurement already taken, it is stated openly.

Every claim about capacity in this chapter is anchored to a load test recorded in our internal documents. The numbers below come from empirical readings under load, not from estimates.

1,000 simulated players at once, non-stop

Combat server ~60 MiB, main server ~3 GiB, all pairings between humans. Stable and already in use.

Baseline internal load test

10,000 simulated players, worst case (all connected at the same instant)

The database and the pairing service jam instantly. The 23 April report records ~2,000 matches completed successfully with ~4,500 failed pairing attempts immediately retried; the steady-state split «8,000 queued + 2,000 started» cited in earlier drafts is a design estimate, not a measurement from that report.

Internal load report, 23-04-2026 (Phase A)

Partial Phase A′, 9 minutes, after the service split

Main server memory 1.59 GiB against 3.08 GiB at the start (−48%). Pairing service 12 MiB and 0.4% of CPU. More than 2,800 pairs. Zero signature errors.

Internal load report, 24-04-2026 (Phase A′)

Main server internal workers

From 32 to 64 ready workers. The factory setting jammed on the burst of matches against local instances during the 10,000-player peak.

Main server configuration, after the audit

Rating write rate

Direct writes, one at a time, today; the batched variant that holds much higher volumes is a goal for the next phase, not yet released.

Rating store

How we reach 10,000 in the test

The tool that simulates load on a single Mac tops out around 2,800 fake players, because of the machine's limits. To reach 10,000 without hitting that ceiling we keep a second machine, with a copy of the project, that pushes further fake players toward the Mac over the local network. That is how we really verified the «10,000-player» scenario: every 10,000 figure in the tables above comes from a test driven by that second machine.

Act 4 · when the queue stalls

What we do when something jams.

Sooner or later every system jams. What sets a mature service apart from a fragile one is not never failing: it is knowing in advance how it fails, and having, ready to hand, the move that gets it going again.

Under the hood. The thing that really matters is not the list of possible failures, but what happens when one shows up: in most cases the system rights itself on its own, and in no case does a failure leave a wrong rating behind.

Recovery and fail-safe — it gets moving again on its own and never writes a wrong rating Two lanes. At the top, the recovery lane: from a request, the main path towards a struggling region breaks off, marked with a cross; a green backup route lights up and resumes, still bringing the match to a start. Below, the verdict lane: the combat server can only sign and propose an outcome, which becomes real only after the services with authority re-check it. On a failure the verdict is discarded cleanly and nothing happens: the rating stays unchanged, never wrong. ACT 4 · WHEN THE QUEUE STALLS resilience by design 1 · IT GETS MOVING AGAIN ON ITS OWN request to play proposed pair main path region A struggling falls to the backup backup route nearby region match still starts not an error clash rerouted → nearby region empty search → match against the AI pair rejected → re-proposed 2 · A FAILURE NEVER WRITES A WRONG RATING combat server can only sign and propose signed verdict re-check services with authority all checks pass rating updated made effective, once only crash or lost message → verdict discarded, cleanly nothing happens rating unchanged, never wrong
If a piece gives way, the path falls back to a backup route and the match starts all the same; and a verdict counts only after the re-check — when in doubt, nothing happens. the worst outcome is a clean stop

It gets moving again on its own

Almost all the anticipated hiccups need no manual intervention. If a region or a piece runs into trouble, the path falls back on its own to a backup route and resumes: the clash is rerouted to a nearby region, a search that finds no one falls back to a match against the AI, a rejected pair is re-proposed. For the player, the result is a match that starts anyway, not an error.

A failure never writes a wrong rating

It is the most important guarantee of all. The server that hosts the clash has no power to touch ratings or coins: it can only sign a verdict and propose it. That verdict becomes real only after the services that hold the authority re-verify it on their own account. So, if a server goes down halfway through a match or a message is lost along the way, the effect is always «nothing happens», never «a wrong rating gets written»: even through failures, the rating stays consistent and reliable.

It is resilience by design: the worst outcome of a failure is a clean stop to pick up from, not a corrupted piece of data to fix by hand.

Golden rule. The matchmaking path is designed to fail safe: at every step, if something does not respond, it falls back to a backup route without ever blocking the player. That is why, when something seems broken, the first question is not «which piece went down?» but «why did the fallback route not kick in?».