Skip to content
ManualMode guides

Verification playbook

AI code review checklist: verify generated code before it ships

Review AI-generated code with a runnable JavaScript async-filter example, failing cases, a corrected implementation, and a practical verification checklist.

Practice review

Review two synthetic patches in about 5 minutes.

No account. Review-only: it does not inspect your own code.

Try the review exercise

8 min read · Updated October 2026

Try this JavaScript review before reading the answer

A function must keep only records whose asynchronous check resolves to true, preserve their input order, and reject if any check fails. The input is a small, dense array that is not mutated during the check.

Would you approve this implementation? Predict which records it returns, then paste the example into a browser console or save it as review.mjs and run node review.mjs.

const records = [
  { id: "draft", ready: false },
  { id: "ready", ready: true },
];

async function canPublish(record) {
  return record.ready;
}

async function selectPublishable(records) {
  return records.filter(async (record) => {
    return await canPublish(record);
  });
}

console.log(await selectPublishable(records));

Before reading the answer, write down one input that distinguishes a correct implementation from this one.

Answer: the callback returns a Promise, not a decision

The example returns both records, including draft. The callback is asynchronous, so each call immediately returns a Promise. filter() checks whether that Promise object is truthy; it never waits for the boolean inside it. Adding await before the final array does not wait for the checks either.

Resolve the decisions first, then filter synchronously:

async function selectPublishable(records) {
  const decisions = await Promise.all(
    records.map((record) => canPublish(record)),
  );
  return records.filter((_, index) => decisions[index]);
}

Replace the original function with this one and run the example again. The result contains only the record with ID ready. Promise.all() preserves input order and rejects if a check rejects. It does not cancel the remaining checks.

This version starts all checks concurrently. It fits the small batch in the stated contract; a large batch or rate-limited service needs a separate concurrency policy.

Language references: Array.filter() and Promise.all().

Turn the contract into review evidence

  • Mixed decisions: one false and one true must keep only the true record. This exposes the original bug.
  • No matches: all false decisions must return an empty array.
  • Empty input: return an empty array without calling the checker.
  • Different completion order: resolve later records first and confirm the output still follows input order.
  • Failed check: reject the operation rather than quietly including an unchecked record.

The lesson applies to a patch written by a person or a coding agent: a plausible callback is not proof that an API awaits it. Test the contract at the call boundary.

Check the real repository boundary too. This toy example proves asynchronous filtering, not permission to publish. If the real canPublish checks record ownership, test a record belonging to another user and confirm that the caller rejects it. Compare the patch with the existing authorization path and test conventions before approving it. The testing guide shows how to turn those checks into merge evidence.

Want another review decision before signing up? Try the five-minute audit on a synthetic AI patch. It practices review; it does not inspect your own pull request.

Start with the contract, not the syntax

Generated code is often locally plausible and globally wrong. Write down what the function must accept, reject, preserve, and return before editing it.

  • Which inputs are valid but unusual?
  • Which values are intentionally empty, zero, false, or null?
  • Which caller assumptions must remain stable?

Run the original code once

Do not fix on sight. Run the current tests first so the failure becomes evidence, not a guess. Record the first failing case, expected value, and received value.

A strong review distinguishes the observed failure from the suspected cause.

Check the AI-era failure modes

  1. Truthiness: valid values such as 0, false, or an empty string are rejected.
  2. Async ownership: an older response overwrites newer state.
  3. Silent defaults: value || fallback replaces an explicit value.
  4. Partial validation: the happy path is checked while malformed or missing fields pass through.
  5. Scope expansion: the patch changes more behavior than the request required.

Prove the smallest safe correction

Add or identify a test that fails for the bug and passes after the correction. Then make the narrowest change that restores the stated contract without rewriting unrelated code.

Re-run the full public suite. A passing new test is useful only if existing behavior still passes.

Start with evidence

Calibrate with three Gym reps, then verify one real Project task.

3 Gym + 1 Project reps free. Create an account; no card or public review required.

Start free