Polish Is a Routing Problem
A week of small fixes with one theme: the product should follow the person using it. Settings that know your role, dialogs that tell the truth about penalties, and queues that clean up after themselves.
Some weeks you ship a feature. Other weeks you ship the absence of a dozen small betrayals. This was the second kind of week, and the fixes shared a theme we did not notice until they were all merged: almost every one was the product failing to follow the person using it.
Settings that know who you are
AlgoArena has three faces: one for practicing, one for teaching, one for hiring. The header, the navigation, and the dashboards all follow whichever face you are wearing. The settings link did not. It hardcoded one destination, so an educator clicking the gear icon landed in the practice settings page and had to find their way back.
Every settings link now resolves through one function that answers a single question: which role is this surface for? Recruiters land in their own settings home, educators get the educator sections, and the mobile nav follows the same rule. One function, four call sites, zero special cases left to drift.
Dialogs that tell the truth
When you abandon a ranked match, a dialog explains the rating penalty. The same dialog also appeared for unranked and friendly matches, still claiming a penalty that does not exist. Nobody loses rating in a friendly match, but the dialog said otherwise, and a player who believed it would reasonably avoid friendlies.
The abandoned-match check now reports whether the match was rated, and the dialog only claims a penalty when there is one. Small fix, but the lesson generalizes: any copy that describes a consequence has to be wired to the code that applies the consequence. Copy that free-rides on assumptions goes stale the moment the rules change.
The lobby had the same flaw. When a match fell through during the countdown, the page could announce a win by forfeit without checking who had left, and could even charge the player who stayed with abandoning. Now the server decides who left, and the win message waits for its answer.
Queues that clean up after themselves
Matchmaking cleanup had a family of quiet failures. Deletes that were never awaited, so failures vanished instead of hitting the error path. A cleanup that tried to delete the opponent's queue entry and threw a permission error it had no business throwing. All of it was harmless in the happy path, but it filled the logs with noise that could hide the one failure that mattered.
Every queue delete is now awaited, scoped to entries the player actually owns, and lands in a real error handler when it fails. The queue also stopped trusting client claims about which entries exist.
Why bundle these into one note
Because polish is not a coat of paint. Each of these bugs was a routing failure: an action arriving at the wrong destination, a message arriving with the wrong contents, an error arriving nowhere. The work of polish is making sure everything in the product arrives where the person using it would expect. That is also why polish compounds: every link that follows your role makes the next hardcoded link stand out sooner.
