L8 · The human layer
L8Go deeper5 min read

Being the quality voice in spec and design review

The cheapest bug is the one argued out of existence in a meeting. Getting into the room, asking the questions that surface unstated assumptions, and doing it without becoming the person who blocks everything.

A bug caught in a design review costs a comment. The same bug caught in code review costs a rewrite. Caught in staging it costs a release cycle, and caught in production it costs an incident, an apology, and a postmortem. Getting into the room before any code exists is still the cheapest place to do quality work, and most testers are not in that room by default.

Why the room matters more than the ticket

By the time a ticket reaches your queue, most of its assumptions are locked in. Someone decided what "done" means, what the edge cases are, and what happens when a third party call fails. If those decisions were made without a question that only a tester tends to ask, the ticket ships a gap that no amount of later testing will fully close, only find.

Spec and design review is where those assumptions are still soft. A sentence like "the user uploads a file" hides a dozen unstated decisions: file size limits, allowed types, what happens on a duplicate name, whether the upload can resume. Asking about them here changes a paragraph in a document. Asking about them after the feature ships changes a rollout plan.

The questions that actually earn a seat

Nobody gets invited to review meetings for pointing out typos. You earn the seat by asking questions that change the outcome of the meeting, not questions that make you look thorough. A short, repeatable set works better than a long checklist nobody remembers under time pressure:

  • What happens when this fails partway through, not just when it fails cleanly?
  • Who else consumes this data, and does this change break an assumption they rely on?
  • Is there an existing behavior this quietly changes, even if the ticket does not mention it?
  • What does "done" mean here in a way we could actually verify?

These are not gotcha questions. They surface unstated assumptions, and surfacing an assumption early is what good test strategy is built on: deciding where the risk actually sits before deciding how much effort to spend testing it.

A refund flow, and the question nobody had answered

A mid-size fintech team was building a partial refund feature. The spec described the happy path clearly: a support agent enters an amount, the system processes it, the customer sees a confirmation. In design review, the tester on the team asked what happens if two agents issue partial refunds on the same order within the same minute.

Nobody had an answer. The engineers assumed the ledger would reject a refund that exceeded the remaining balance. Nobody had checked that the ledger service enforced that at write time rather than at read time. That one question turned into a half day spike before a single line of feature code was written, and it was far cheaper than finding a double refunded order three weeks after launch.

The same tester asked what the support team would see if a refund partially succeeded, since the payment provider's API returned a status nobody had mapped to a UI state. That question reshaped a UI mock the day it was drawn instead of after a support ticket forced a hotfix. It is the same instinct that makes for bug reports that get fixed: naming the actual state a system can end up in, not just the state the spec assumed.

Not becoming the person who blocks everything

The failure mode on the other side of this is real, and it costs you the seat just as fast as saying nothing does. A tester who raises ten objections in every review, most of them low probability edge cases, trains the room to stop listening before the meeting ends. Writing acceptance criteria during refinement exists partly to force this discipline: name the risk, attach a rough likelihood and cost, and let the team decide whether it is worth addressing now or logging as a known gap.

The difference between a useful voice and a blocking one is usually framing. "This will break" stops a meeting and puts you on the defensive. "Here is what happens if this fails, and here is roughly how likely that is" gives the team something concrete to decide. That framing is what gets you invited back next sprint.

It also helps to pick your battles publicly. Raise the two or three questions that actually change the risk profile of the release, and let the smaller ones go into the ticket as a comment rather than a meeting agenda item. A reviewer who is right about everything but insists on saying all of it out loud is, in practice, hard to tell apart from a reviewer who is wrong.

Building the habit into the team's rhythm

This works best as a standing practice rather than a personal quirk. Teams that put a tester in refinement and design review as a default attendee, not an optional invite, catch these gaps consistently. The QA voice becomes part of how the team writes specs, not an audit layered on top of them afterward.

FAQ

Questions people ask

How do I get invited to design review if my team has never included QA?

Ask the engineering lead directly, framed around a specific past incident that a review question could have caught. A concrete example is harder to dismiss than a general request.

What if I ask a question and nobody has an answer?

Write it down as an open question in the ticket with an owner and a date, rather than letting the meeting move on. An unanswered question that is not tracked disappears by the next sprint.

How many questions is too many in one review?

If you are raising more than two or three substantial ones per ticket, you are probably including low risk edge cases. Save those as ticket comments instead of meeting time.

Does this replace writing test cases later?

No. It reduces how many gaps those test cases have to find, and it often changes what the test cases need to cover in the first place.