Monday, 9:14 a.m. A pull request lands with the label generated. Four hundred lines, a new endpoint, and a test suite that passes. The reviewer opens it, reads the first function, and feels the familiar squeeze: the code is plausible, the tests are green, and nothing looks wrong. That is the moment the job changed.
For years, the hard part of software work was writing code. The bottleneck has moved. AI assistants now produce a large share of new code on many teams, and the human role has shifted to review: reading, questioning, and verifying code that arrived faster than anyone can inspect it. The strange part is that almost nobody trains for this. Teams run onboarding for new languages and frameworks, but not for the act of reviewing generated code.
A workshop cannot replace experience. It can compress the first painful months into ninety minutes. This article lays out a repeatable session: four exercises, a worked example students can rerun, and a tiny lab that runs on free infrastructure.
The lab
The lab needs two things: a place to run tests and a way to generate sample pull requests. MonkeyCode's free model access and free server option cover both, which keeps the cost at zero for a small group. Disclosure: This article was prepared as part of MonkeyCode's product outreach. The point of the workshop is not the tooling; the same exercises work with any model endpoint and any machine with Python.
MonkeyCode is an open-source project, and its free tier includes a 10-million-token allowance plus a free server instance. Quotas change, so check the project docs before planning a large session. For a team of ten, the allowance is more than enough.
The workshop repo contains three sample pull requests. Each is a single function with a planted defect. Nobody is told where the defects are.
The agenda
0:00–0:10 — Setup. Students clone the repo, install pytest, and confirm the lab server responds. The whole group works in the same preloaded environment, so there is no "works on my machine" drift.
0:10–0:30 — Exercise 1: Review by checklist. Students read the first pull request and mark a five-item checklist. Most people find zero defects on the first pass. That is the lesson: unaided review of generated code is mostly pattern matching, and patterns miss edge cases.
0:30–0:50 — Exercise 2: Write the failing test. Students stop guessing and start asserting. They write one test that should pass if the code is correct. The test fails. The review now has evidence instead of opinions.
0:50–1:10 — Exercise 3: Cross-grade the reviews. Pairs swap checklists and grade each other against the planted defect list. Review quality turns out to be measurable, not a matter of taste.
1:10–1:20 — Debrief. The facilitator reveals the defects and asks which checklist items caught them. Usually one item does all the work.
1:20–1:30 — Wrap-up. Students take the checklist back to real reviews. The session ends with a concrete artifact, not a vague resolution.
The worked example
The first sample pull request is a function that merges overlapping intervals:
# sample_prs/pr_01/merge_intervals.py
def merge_intervals(intervals):
intervals.sort(key=lambda x: x[0])
merged = []
for start, end in intervals:
if merged and start <= merged[-1][1]:
merged[-1][1] = end
else:
merged.append([start, end])
return merged
The code looks clean. The checklist makes it less comfortable:
[ ] Empty input, None, single element
[ ] Mutation of caller data
[ ] Contained intervals, e.g. (1,4) and (2,3)
[ ] Return type matches the documented contract
[ ] Error behavior on malformed input
Item two is the trap. The function sorts intervals in place, which mutates the caller's list. Item three catches the real bug: for [(1, 4), (2, 3)], the code returns [[1, 3]] instead of [[1, 4]], because it overwrites the end instead of taking the maximum. A generated test suite often misses both, because the happy path looks fine.
Students write the failing tests:
# tests/test_merge_intervals.py
from sample_prs.pr_01.merge_intervals import merge_intervals
def test_contained_interval_keeps_outer_end():
assert merge_intervals([(1, 4), (2, 3)]) == [[1, 4]]
def test_input_list_is_not_mutated():
data = [(2, 3), (1, 4)]
merge_intervals(data)
assert data == [(2, 3), (1, 4)]
And run them:
pytest tests/test_merge_intervals.py -q
Two failures, two discovered defects, about ten minutes of work. The fix is small:
def merge_intervals(intervals):
ordered = sorted(intervals, key=lambda x: x[0])
merged = []
for start, end in ordered:
if merged and start <= merged[-1][1]:
merged[-1][1] = max(merged[-1][1], end)
else:
merged.append([start, end])
return merged
The lesson is not that the model wrote bad code. The lesson is that the model wrote plausible code, and plausibility is exactly what a reviewer must distrust.
Who should not use this
Teams that do not review AI-generated code yet. If every pull request is still handwritten, the exercises will feel abstract. The format also assumes a facilitator who knows the planted defects; without one, the debrief turns into guesswork. And the free tier is sized for small groups — a hundred students hammering the same endpoint will hit rate limits, which is a valuable lesson in itself, but not the intended one.
The takeaway
The reviewer role is new, but it is trainable. Ninety minutes and a handful of planted bugs will not make anyone an expert; they will make the next generated pull request feel less like a magic trick and more like a puzzle. The workshop repo runs on a free server with free model access, and the checklist alone is worth taking back to the team.
Top comments (0)