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-flavored settings page and had to find their way back.
The fix is boring on purpose. 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. 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.
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 harmless in the happy path, all noise in the logs, all masking the one day it would matter.
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.
How to read this update
The important question is not only what shipped. It is what new evidence the product can now preserve. For engineering work, a useful release should make the next session easier to understand: what happened, why it mattered, and what someone can do with the result afterward.
That is the bar we use for field notes. A feature is stronger when it turns a hidden process into something reviewable: a timeline, a report, a map, a score explanation, a replay, or a teacher-facing control. The surface can stay simple, but the evidence behind it should get harder to hand-wave.
