Skip to content
aitrainer.work - AI Training Jobs Platform
Live Code Review & Debugging Interviews
0%
T3: Live Code Review & Debugging Interviews
T3 Technical
⏱️ 1.5 hours 🎯 Intermediate

Live Code Review & Debugging Interviews

Prepare for live, screen-share coding interviews where you debug real code out loud with an interviewer. Learn the narration habits and debugging loop that make the difference between a silent correct fix and a scored one.

Test Your Knowledge
Before you read anything: make a call

Two candidates are given the same broken function in a live interview and asked to find the bug.

Candidate A’s transcript:

[40 seconds of silence, typing, scrolling] “Okay, found it. Line 4 has an off-by-one error. Fixed.”

Candidate B’s transcript:

“Let me first confirm it’s actually broken. I’ll run it with a small example… okay, it returns 4 when I expected 5. Let me narrow this down. The function loops with range(1, n), so my hypothesis is it’s not checking the last value in the range. Let me test that specifically… yeah, if I pass a case where the missing number is the largest one, it fails. If the missing number is smaller, it works. That confirms the loop bound is the issue. Fixing it to range(1, n + 1), and re-running the original failing case to make sure that’s actually the fix.”

Both candidates land on the same correct fix in roughly the same amount of time. Which one scores higher in a live debugging interview?

See the answer

Candidate B, and it isn’t close.

The interviewer isn’t just checking whether the final code is correct. They’re evaluating engineering judgment and debugging approach, and those are only observable through what you say while you work. Candidate A’s silent 40 seconds could have been careful reasoning or a lucky guess. The interviewer has no way to tell, and no way to grade it. Candidate B’s narration makes the entire process visible: reproduce the failure, form a specific hypothesis, test that hypothesis before trusting it, apply the fix, then verify against the original failure.

This is the single biggest adjustment strong solo coders need to make for this format. Debugging alone, you don’t narrate. You just think and fix. In a live interview, an un-narrated correct answer often scores about the same as a narrated wrong one, because the thing being measured is process, not just outcome.


Why live debugging interviews exist

Several platforms gate access to coding annotation work behind a live, camera-on, screen-share interview. Mercor is one example, not the only one. The format is usually a short conversation about your background, then two or three debugging exercises solved out loud in real time, all inside a fixed window of roughly 20–30 minutes.

That’s a deliberate design choice, not an arbitrary hurdle. A written test already measures whether you can produce correct code. What it can’t measure is how you get there. Do you jump to conclusions or verify them? Can you explain a fix clearly enough that another engineer could review it? Do you stay coherent when you’re stuck? Those are exactly the qualities a training-data annotator needs, since the actual job is reasoning about someone else’s code (often an AI’s) and explaining, in words another person can follow, what’s wrong with it and why.

If you’ve only ever debugged alone, this format will feel unnatural at first. The skill this module teaches isn’t debugging. You already have that from T1. It’s narrating a debugging process you’d normally do silently, without slowing yourself down so much that you run out of time.


The narration habit

The single highest-leverage adjustment: say your hypothesis before you test it, not after.

“I think the bug is in the loop bound, let me check” is worth more than a correct fix announced with no lead-up, because it gives the interviewer a hypothesis to evaluate in real time, right or wrong. If you’re wrong, saying so out loud and adjusting is also a positive signal. It shows you don’t cling to a bad theory once evidence contradicts it.

Practical phrases that do this work:

  • “My first guess is X, because Y. Let me confirm before I change anything.”
  • “That’s not it. This ran and the output was still wrong, so I’m ruling that out.”
  • “I want to check one assumption before I go further: does this only fail on the second call, or every call?”

Avoid narrating after you’ve already silently solved it in your head. “So the bug is X” with no lead-up sounds like Candidate A above, even if you genuinely did think it through internally. The interviewer can only grade what’s said, not what’s assumed.


The live-debug loop

A repeatable structure to fall back on when you’re under pressure and can’t rely on the problem happening to be familiar:

  1. Reproduce: get a concrete example that actually fails, before you touch anything. Don’t debug from a description of a bug. Debug from an observed one.
  2. Isolate: narrow to the smallest input or condition that still triggers it. Does it fail on every call, or only the second? On every input, or only edge cases?
  3. Hypothesize: say, specifically, what you think is wrong and why, before testing it.
  4. Verify: check the hypothesis against evidence before changing code. A wrong hypothesis stated and corrected out loud is fine. A wrong hypothesis acted on silently wastes the interview’s remaining time.
  5. Fix: make the smallest change that addresses the verified cause.
  6. Re-check: confirm the fix resolves the original failing case, and briefly consider whether it could break anything else.

This loop is slower than jumping straight to a fix. That’s the point. The slowness is where the narration lives, and the narration is what’s being graded.


Pacing across a fixed window

With three exercises in roughly 20–30 minutes, spending too long on the first one is the most common way candidates run out of time. A partial, well-reasoned attempt on all three exercises generally reads better than a perfect solution to only one.

If you’re stuck:

  • Say so, specifically: “I’ve ruled out X and Y, I’m currently checking Z.”
  • Propose a next concrete step out loud, even if you’re not sure it’ll work: “I don’t have a strong hypothesis yet, so I’m going to add a print statement to see the actual value at this point.”
  • If you’re well past a reasonable amount of time on one exercise, say you’d like to note where you are and move on, rather than silently running the clock down.

Going silent while stuck is worse than being visibly, narratedly stuck. Silence gives the interviewer nothing. Stuck-but-reasoning-out-loud is still a signal of engineering judgment.

Some platforms run an AI interviewer instead of a human (micro1’s “Zara” is one example) that listens for active speech to know a thought is still in progress. A long silent pause can read as “finished” and get interrupted, or as dead air with nothing to grade. If you need a few seconds to actually think, say so instead of going quiet. “Give me a second, I’m reviewing the logic on line 14” keeps the mic active and signals you’re still working, not stuck or done.


Screen-share and interview mechanics

A few habits that have nothing to do with coding skill but affect how the session comes across:

  • Talk while you scroll or search, not before or after. “Let me search for where this function is called” said while you do it, not silently followed by an explanation afterward.
  • If you’re rereading a block of code to understand it, say what you’re looking for: “I’m checking whether this variable gets reassigned anywhere else.”
  • Don’t apologize repeatedly for being stuck. Note it once, matter-of-factly, and keep working.
  • Some platforms run automated gaze or attention tracking to flag candidates who might be reading answers off a second screen. A long silent stretch spent staring away from the screen while you think can look the same as that to an automated check. Keep narrating and looking roughly toward your own screen while you think, not just while you type, so a normal thinking pause doesn’t get misread as looking something up elsewhere.

The background discussion

Interviews in this format usually open with a short conversation about your background before the coding portion. That’s not filler. It’s a lower-stakes version of the same thing being tested later: can you explain something specific and real (in this case, your own past work) clearly, without vague generalities. Treat it with the same standard you’d apply to narrating a hypothesis: be specific, cite an actual example, and don’t pad with generic claims that could apply to anyone.


Skills Lab: Live Debug Walkthrough

Three practice exercises. Each gives you a broken function and a failing example. Before opening the reveal, try to talk yourself through the live-debug loop out loud (reproduce, isolate, hypothesize, verify, fix, re-check) the way you would in an actual interview. The reveal shows a full narrated walkthrough, not just the answer, so you can compare your process, not just your fix.

Try It 1: The boundary bug
def find_missing_number(nums, n):
    """nums contains every integer from 1 to n except one. Return the missing one."""
    for i in range(1, n):
        if i not in nums:
            return i
    return -1

Failing example: find_missing_number([1, 2, 3, 4], 5) should return 5, but returns -1.

Other examples work fine: find_missing_number([2, 3, 4, 5], 5) correctly returns 1.

Talk through it out loud before opening the reveal: what’s your hypothesis, and how would you confirm it?

See narrated walkthrough

“Okay, reproducing first. find_missing_number([1, 2, 3, 4], 5) returns -1 instead of 5. I’m told other cases work, so let me confirm that: find_missing_number([2, 3, 4, 5], 5), that one’s fine, returns 1. So this isn’t broken on every input, only some. That’s useful. It’s probably a boundary issue, not a fundamentally wrong approach.

Looking at the loop: for i in range(1, n). With n = 5, that’s range(1, 5), which gives 1, 2, 3, 4. It never checks 5 at all. My hypothesis is the range is missing its upper bound: it should be range(1, n + 1) to actually include n.

Let me verify that hypothesis makes sense with the working case too. When the missing number is 1, the loop starts at 1 and finds it immediately, so the bug never gets triggered. That’s consistent with why some inputs ‘work’ by coincidence, not because the function is actually correct.

Fixing it: range(1, n + 1). Re-running the original failing case, now returns 5, correct. And re-checking the previously-working case, still returns 1. Good.”

The bug: range(1, n) excludes n itself, so the function can never detect that n is the missing number. It only fails when the missing number happens to be the largest one in the range, which is why some test inputs looked fine.

Try It 2: The shared-state bug
def add_item(item, bucket=[]):
    bucket.append(item)
    return bucket

Failing example:

print(add_item("apple"))    # ["apple"]: looks correct
print(add_item("banana"))   # ["apple", "banana"]: should be ["banana"]

The second call is unrelated to the first, but its result includes leftover data. Talk through it before opening the reveal.

See narrated walkthrough

“Reproducing: first call add_item('apple') gives ['apple'], that looks right. Second call add_item('banana'), called completely independently, gives ['apple', 'banana']. I expected just ['banana']. So the first call is fine on its own, and the bug only shows up once a second call happens. That’s a strong hint this is a shared-state issue rather than a logic error in the function body itself.

Isolating: is this about the specific items, or would any second call show leftover state from any prior call? I’d test with different items again to confirm it’s not something specific to ‘apple’ and ‘banana’, and it isn’t. Any second call inherits the first call’s list.

Hypothesis: the default argument bucket=[] is the issue. Python evaluates default argument values once, when the function is defined, not fresh on every call. So if the default is a mutable object like a list, every call that doesn’t pass its own bucket is actually sharing and mutating the same list object.

Verifying: that matches exactly what I’m seeing. The second call’s ‘default’ bucket isn’t a fresh list, it’s the same list object the first call already appended to.

Fix: replace the mutable default with None and create a new list inside the function if none was passed:

def add_item(item, bucket=None):
    if bucket is None:
        bucket = []
    bucket.append(item)
    return bucket

Re-checking: add_item('apple') gives ['apple'], and add_item('banana') now correctly gives ['banana'] on its own.”

The bug: mutable default arguments in Python are evaluated once at function definition time and shared across every call that relies on the default, so state silently leaks between unrelated calls. It’s invisible on the first call, which is why it’s easy to miss without deliberately testing a second, independent call.

Try It 3: The wrong-assumption bug
_cache = {}

def get_price(product_id, currency):
    if product_id in _cache:
        return _cache[product_id]
    price = fetch_price_from_api(product_id, currency)  # imagine a real external call
    _cache[product_id] = price
    return price

Failing example:

get_price(42, "USD")   # fetches and caches, say, 19.99
get_price(42, "EUR")   # returns 19.99 again: wrong, should fetch the EUR price

Talk through it before opening the reveal.

See narrated walkthrough

“Reproducing: get_price(42, 'USD') returns 19.99. Then get_price(42, 'EUR') also returns 19.99. That’s suspicious. USD and EUR prices for the same product shouldn’t be identical in general, and I’d expect a fresh currency to trigger a fresh fetch.

Isolating: is it caching correctly for the same currency, at least? Calling get_price(42, 'USD') twice in a row, yes, second call returns the cached value instantly without hitting the fake API again, so the caching mechanism itself works. The problem is specifically what it’s caching by.

Hypothesis: the cache key is just product_id, but the function’s actual output depends on both product_id and currency. So a second call with a different currency but the same product_id is going to hit the cache and return a stale, wrong-currency result instead of fetching again.

Verifying: checking the code, yes, _cache[product_id] only ever keys on product_id. currency isn’t part of the key at all. That confirms it.

Fix: key the cache on both values:

def get_price(product_id, currency):
    key = (product_id, currency)
    if key in _cache:
        return _cache[key]
    price = fetch_price_from_api(product_id, currency)
    _cache[key] = price
    return price

Re-checking: get_price(42, 'USD') and get_price(42, 'EUR') now trigger independent fetches and cache independently, and repeat calls with the same pair still hit the cache.”

The bug: a cache key must capture every input that affects the output. Keying only on product_id while the result also depends on currency means the function silently returns a stale, wrong-currency result with no error anywhere. It’s the kind of bug that’s easy to miss because the function “works” on every single-currency test.


Quick Reference

  • The loop: reproduce with a concrete failing example, isolate to the smallest case that still fails, hypothesize out loud, verify before you fix, fix, then re-check against the original failure.
  • Narrate before you test, not after. A stated hypothesis, even a wrong one, is a signal the interviewer can grade. A silently-correct answer with no lead-up gives them nothing to evaluate but the final line.
  • Pace across the whole interview, not just one exercise. A visibly-reasoned partial attempt on all three exercises beats a perfect silent answer to only the first one.
  • Scope check: this module covers live, verbal debugging interviews. Written, asynchronous code review and PR-rating are a different skill, covered in T1 and T2. The three exercises above are original practice material, not any specific platform’s real interview questions.

Test Your Knowledge

Answer question 1 to preview. Sign in to complete all 8 questions.

Question 1 of 8

1. A candidate silently stares at broken code for 40 seconds, then says "found it" and types the correct fix. Why does this typically score lower than a slower, narrated fix?

easy

Was this worth your time?

Rate this module. It takes two seconds.