Reviewing GitHub pull requests for scope, not just code quality
How engineering leads at fixed-fee agencies can add a scope check to pull request review: what to look for, a PR template that surfaces drift, and how to escalate without blocking delivery.
Key takeaways
- The pull request is the last cheap moment to catch unpriced work before it ships.
- Add one question to your PR template: which SOW deliverable does this change serve?
- Scope review should flag, not block. Merge decisions stay with engineering; pricing decisions go to the PM.
On this page (7 sections)
The pull request is the last checkpoint
By the time a feature reaches a pull request, someone has already decided to build it. That makes the PR a late place to catch scope creep, but it is often the only place where every change passes through a structured review. Slack requests are informal, tickets are sometimes skipped, but code still has to be reviewed and merged.
Most agencies already review PRs carefully for correctness, security and style. Very few review them for scope. The reviewer sees that a new endpoint is well written; nobody asks whether the client is paying for it.
What scope drift looks like in a diff
Scope drift in code has recognisable shapes. These are the signals our divergence engine weighs most heavily when it reads a PR against the SOW, and they are easy for a human reviewer to spot too.
- New external dependencies: a payments SDK, a maps library or an analytics client that does not appear in the SOW's integration list.
- New routes, screens or endpoints that do not map to a listed deliverable.
- New user roles or permission levels. Role logic is a classic source of hidden effort because it touches every screen.
- Schema migrations adding fields the SOW did not mention, especially for reporting.
- Branch names or commit messages that quote a client ("per Sarah's request", "quick add for launch").
- PRs that are much larger than the linked ticket's estimate, which often means the ticket grew in a conversation nobody recorded.
None of these is proof of out-of-scope work. Plenty of new dependencies are implementation details. But each one is a moment to ask the question, and the cost of asking is a few seconds.
A PR template that surfaces drift
The cheapest change you can make is to add a scope section to your pull request template. It takes a developer ten seconds to fill in and gives the reviewer something to check against.
## Scope. SOW deliverable this serves (section number): ____. Linked ticket: ____. Does this PR add anything the ticket did not describe? (yes/no, and what). Was any part of this requested directly by the client outside a ticket? (yes/no, link to message).
The last question is the important one. Developers usually know when work came from a side conversation. They rarely volunteer it, because there has never been a place to say so without sounding like they are complaining about the client. A neutral template field gives them that place.
Flag, don't block
A scope check that blocks merges will be bypassed within a week. Engineering teams are measured on delivery, and a PR stuck waiting for a commercial decision is a missed sprint goal. The goal is to separate two decisions that usually get merged together.
| Decision | Owner | Timing |
|---|---|---|
| Is the code correct and safe to merge? | Engineering reviewer | Normal review cycle |
| Is this work in the SOW? | PM, with SOW reference | Within one business day of the flag |
| Should it be priced, absorbed or deferred? | PM and account lead | Before the next client touchpoint |
In practice this means a reviewer who spots drift adds a label (we use scope-check) and mentions the PM, then carries on reviewing the code. The PR can merge to a feature branch while the PM works out the commercial side. If the decision is to defer, the branch waits. If it is to price, the PM raises a change order with the PR linked as evidence.
Making it stick across teams
- Start with one project where scope is already a known problem, so the team sees the value immediately.
- Share results back to engineers. When a flagged PR turns into a signed change order, say so in the team channel. Developers rarely hear that their work was billed.
- Review scope-check labels in the sprint retro. Patterns tell you which SOW sections are too vague.
- Keep the template short. Every field you add lowers the completion rate.
The cultural shift matters as much as the process. Developers at fixed-fee agencies often carry the cost of unpriced scope personally, through late nights before launch. Showing them that flagging drift protects their time, not just the agency's margin, is what turns the template from a chore into a habit.
A worked example
On a fixed-fee marketplace build, a developer opens a PR titled "Add seller payout dashboard". The linked ticket describes a simple payout history table. The diff adds a new reporting route, a charting library, two database columns for payout forecasts and a CSV export. The PR template's last field says the forecast idea came from a client call.
The reviewer approves the table, labels the PR scope-check and tags the PM. The PM finds that SOW section 5.3 lists payout history but excludes forecasting and exports. Within a day the client has two options: forecasting and export as a change order of about 26 hours, or the history table alone this sprint with forecasting in phase two. The client picks the change order. Nobody argued, and the work was paid for before it shipped.
Where automation fits
Manual PR scope review works well on a handful of projects. It gets harder across twenty repositories, each with its own SOW. TWINJAM's GitHub connector reads PR titles, descriptions, changed paths and dependency manifests with read-only access, compares them to the parsed SOW for that project, and posts a private note to the PM when a PR looks like it adds uncontracted work. It never comments on the PR itself or blocks a merge.
Whether you automate it or not, the principle is the same: the people closest to the code see scope drift first. Give them a low-friction way to say so, and route that signal to the person who can do something commercial about it.
Rohan Kulkarni
Product Manager, Divergence Engine, TWINJAM
Rohan owns how TWINJAM reads Jira, Linear and GitHub. Before that he was an engineering manager at a fixed-fee mobile agency.
Newsletter
The Profitable Agency
Weekly teardowns of agency contract terms, margin protection and delivery operations. One email every Thursday, no fluff.
Read by delivery leads and agency founders. Unsubscribe in one click.