A round of testing with real users always turns up more problems than you can fix before the next preview. That is what it is for. The hard part is what you do with the list.
After 30+ years in technical UX, the mistake I see most is not a bad fix. It is fixing in the wrong order. Ten quick changes go out, the list gets shorter and it feels like progress. Meanwhile the one problem that stops people finishing the main task waits another round.
This gets harder after a Claude prototype. While you were prototyping, you fixed whatever you noticed the moment you noticed it, and nothing else depended on it. With real users and a real codebase, findings arrive faster than you can fix them, and changing everything at once breaks things you already fixed. That is not a sign anything has gone wrong. It is what building with real users feels like.
In my process this is the Iterate step. Findings from testing every preview with real users become the next round of changes, worst problems first.
Sort every finding by what it does to people
I put each finding into one of four levels, from worst to mildest.
- It blocks a task. Someone could not finish a core flow. They could not save, could not find the next step or gave up.
- It causes errors or loses data. The wrong record was saved, a form lost its contents when a session expired, a total was wrong. These can be worse than blockers, because people often don't notice until later.
- It confuses people. They hesitated, took a wrong path and recovered, or asked what something meant.
- It annoys them. Extra clicks, slow screens, awkward wording. Real problems, but people get through.
Write each finding as what happened, not as the fix you have in mind: which task, how many testers hit it and what they did. "Testers looked for the export under Settings" is a finding. "Move the export button" is a decision for later.
Weigh it against how often it happens
Severity alone is not enough. It also matters how often people meet a problem.
Jakob Nielsen's severity ratings combine three things: how often a problem occurs, how hard it is to overcome and whether it keeps coming back. That last one is easy to forget: a step people get past once is different from one they trip over every time.
So for each finding I ask two questions. How many testers hit it? And how often does that task happen in real work?
A confusing step in something people do all day can outrank a blocker in a screen used once a year, if that blocker has a safe workaround. A blocker or a data problem in a core flow goes to the top regardless.
Don't turn this into a spreadsheet of decimals. You are ranking, not calculating. The output is one ordered list, and the top of it is the next round.
Review every preview against the spec
Each round of fixes goes out as a new preview. Review it against the ranked list and the spec's acceptance criteria, not against memory.
Three questions for every preview:
- Did each fix solve the finding it was meant to solve?
- Does each core flow still meet its acceptance criteria?
- Did anything that worked before stop working?
Leave feedback where the problem is. If you deploy on Vercel, Comments let your team leave feedback directly on a preview deployment, attached to the part of the page it is about. Whatever the tool, tie feedback to a specific preview, so nobody argues later about which version they saw. There is more on that setup in previews, environments and rollback.
A fix is not done until a user gets through. The worst problems from this round go back in front of testers in the next one.
Hold new features until the round is done
Testing produces ideas, from users and from you. Write them all on a parking list, and don't build them this round.
With coding agents, a new feature can take an afternoon, which makes this tempting. But every feature adds screens, states and permissions to test, and it changes the product in the middle of the round. You can no longer tell whether the fixes worked.
The exception is when a finding shows the spec missed something essential, like a step the core flow cannot work without. That is a spec change. Make it on purpose, write it down and update the spec, so it stays the source of truth.
Keep a short decision log
Every round produces decisions: what you fixed, how, what you chose not to fix and why. Three rounds later, nobody remembers why the button moved.
A decision log doesn't need to be fancy. One entry per decision:
- the date
- the decision
- the finding or evidence behind it
- the options you rejected
- who decided
The log is also what the next person reads, whether that is your first engineer or a coding agent. When a decision changes what the product does, update the spec as well.
Know when a round is done
The list will never be empty. If you wait for that, you never ship. A round is done when:
- every blocker and data problem from this round is fixed and retested;
- the confusing steps in core flows are fixed, or there is a logged decision to leave them;
- the annoyances are ranked and parked for a later round;
- the preview meets the spec's acceptance criteria for every core flow;
- the latest test turned up nothing new in the top two levels.
Then you run the next round, or ship and let the same loop continue with real use, which I cover in launch starts the loop.
The short version
- Rank findings by what they do to people (blocks a task, causes errors or lost data, confuses, annoys) and how often they happen.
- Fix from the top of the list, not the easy end.
- Review every preview against the ranked list and the spec.
- Park new feature ideas until the round is done.
- Log each decision, including what you chose not to fix.
- Call the round done when the top two levels are clear.
