One queue shape kept bothering me. Most players were clustered around a skill rating of 1500, while a few sat well above or below it. The center matched quickly. The edges waited.
For any one player near 1500, another 1500-point player was the obvious choice. But after enough search cycles, that sensible local decision became a queue-wide problem: new players kept arriving at the center, and the same people stayed at the edges.
This is why skill rating and matchmaking score stopped being synonyms for me. Over four years of working on target-selection and matchmaking systems, the score came to represent more dimensions: wait time, platform and hardware, latency, preferences, roles, party composition, and product-specific signals.
The direction I wanted was not one permanent formula. I wanted to change what the score represented without rebuilding the engine, test the product idea behind it, and see what players did after the match.
01 / THE QUEUE HAS EDGES
The easy match is not always the right next match.
The first temptation is to widen the search until somebody matches. I do not think waiting should make an impossible or plainly unacceptable match valid. I found it more useful to separate three kinds of rule.
| Policy layer | Examples | As waiting grows |
|---|---|---|
| Hard feasibility | Platform compatibility, maximum latency, required party shape. | Do not relax it. |
| Minimum quality | The product's lowest acceptable match quality. | Keep the floor intact. |
| Soft preference | Closer rating, preferred roles, ideal composition. | Widen the search or accept a weaker preference above the floor. |
My rule of thumb became simple: waiting may weaken a preference, but it should not erase validity or the quality floor. Within that floor, widening the search for an older request can help one player without sacrificing the whole group. How far to widen is a game decision, which is why I wanted it in configuration rather than buried in the engine.
I could still divide that wider pool into two teams with similar average skill. That solved the balance between teams, but it did not solve the skill gaps inside each team. Those gaps might change how the match felt and whether players returned. Widening was necessary; the work was finding a relaxation rule that did not destroy the quality we were trying to preserve.
02 / MORE THAN SKILL
The score had to represent more than rating.
A skill rating answers a narrow and useful question about competitive balance. It says nothing about whether two platforms can share a session, whether the network path is playable, whether a party is missing a role, or whether the players even want the same kind of game.
| Signal | Question | How it enters the policy |
|---|---|---|
| Skill rating | Is the competitive gap acceptable? | A quality floor, a widening band, or a soft preference. |
| Wait time | Who has already paid the largest delay? | Changes search width or the order in which candidates are considered. |
| Platform and hardware | Can these players share a session? | A hard compatibility rule or a product preference. |
| Latency and region | Will the game remain playable? | A hard maximum with softer choices inside it. |
| Preference and composition | Do modes, roles, parties, and expressed choices fit? | Feasibility rules plus tradeoffs that vary by game. |
| Behavioral signal | Does a product hypothesis predict a better experience? | A versioned experimental input with a defined fallback. |
A score can represent all of these dimensions, but that does not mean every term should cancel every other term. How many milliseconds of latency cancel out a missing role? How much waiting makes an unplayable connection acceptable? To me, neither trade makes sense. The policy has to keep its hard rules outside the trade before it scores the remaining choices.
This is what I mean by matchmaking scoring: not skill rating with a few bonuses, but a product-specific evaluation over several dimensions. I worked on making that formula customizable because each game valued those dimensions differently. Its job was to compare valid candidates, not to quietly redefine validity.
03 / WHAT COUNTS AS SUCCESS
Fairness was a signal, not the final objective.
The matching service naturally reports what it can see: parties formed, queue time, rating gaps. I used those numbers, but I stopped treating them as the final answer.
Even fairness was a proxy. A match that looked less fair by skill distribution could still be the better experience if it ended a punishing wait or preserved the composition players wanted. A perfectly balanced match that arrived too late could be a product failure. I did not want to decide that question from the skill distribution alone.
That leaves a claim worth testing: a less fair-looking match may produce better retention without crossing the game's hard limits. The useful questions come afterward. Did the players accept, start, finish, and return? If the evidence supported the trade, that could be the policy we kept.
I would still be careful with the conclusion. Seeing different post-match behavior after a policy change is not enough to say the matcher caused it. Matching can contribute to retention, but it does not own retention by itself. The feedback path is necessary; so is an experiment that can support the claim.
04 / FROM HYPOTHESIS TO POLICY
We needed a path from a product idea to the matcher.
Making the scoring formula customizable was only half the work. A product hypothesis still had to become data the matcher could use. I worked with game teams and data analysts to define the question, add logs when the existing data was not enough, and turn the result into attributes for the policy.
| Step | Work | Result |
|---|---|---|
| 1. State the hypothesis | Agree on a player segment, an expected outcome, and a guardrail. | A question that can be tested rather than a vague preference. |
| 2. Build the signal | Add the necessary logs and run them through ETL and the data warehouse. | A derived preference, persona, or behavioral attribute. |
| 3. Deliver the input | Materialize the value or send it as a custom attribute with the request. | A versioned contract between the caller and the matcher. |
| 4. Run the policy | Apply a configurable scoring formula, thresholds, and search limits to an experiment cohort. | A policy version that can be inspected and rolled back. |
| 5. Look at what followed | Compare post-match behavior and decide what to keep, change, or stop. | Evidence for the next hypothesis and policy version. |
Sometimes the value was derived in the warehouse and materialized for matching. Sometimes a game team sent it as a custom attribute with the request. In both cases, we needed to know what the value meant, which version produced it, and what to do when it was missing or stale.
05 / SEARCH WITHIN A BUDGET
We had to stop searching somewhere.
Once these dimensions interact, exhaustive search is not an option for a live service. We had to cap the search by time, candidate count, or exploration count. The result was the best match found inside that budget, not a global optimum.
That leaves a real optimization problem. Better candidate generation, pruning, ordering, and search heuristics can improve what the same budget finds. I still see room for research there; I do not think one algorithm settles it for every game and every population.
The boundary I prefer is straightforward. The game and product teams define what a good experience means. The caller sends valid, versioned attributes. Data systems build and evaluate the signals. The matching service validates those inputs, enforces the hard limits, searches within its budget, and returns an assignment. It should not invent the game's retention hypothesis.
If I were designing the next version today, I would optimize for that whole loop. I want to explain why a scoring policy changed, which part of the queue it helped or hurt, and what happened afterward. The score has to remain configurable, inspectable, and connected to that evidence.