Skip to content
TWINJAM

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.

RKRohan KulkarniProduct Manager, Divergence Engine, TWINJAM ·

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)
  1. 01The pull request is the last checkpoint
  2. 02What scope drift looks like in a diff
  3. 03A PR template that surfaces drift
  4. 04Flag, don't block
  5. 05Making it stick across teams
  6. 06A worked example
  7. 07Where automation fits

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.

.github/pull_request_template.mdClause

## 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.

Who decides what
DecisionOwnerTiming
Is the code correct and safe to merge?Engineering reviewerNormal review cycle
Is this work in the SOW?PM, with SOW referenceWithin one business day of the flag
Should it be priced, absorbed or deferred?PM and account leadBefore 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

  1. Start with one project where scope is already a known problem, so the team sees the value immediately.
  2. 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.
  3. Review scope-check labels in the sprint retro. Patterns tell you which SOW sections are too vague.
  4. 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.

RK

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.

All articles

Keep reading

Delivery operations5 min read

Assumption logs: the cheapest scope insurance an agency can buy

How to write, maintain and use an assumption log so that when a project's reality changes, the change order is already half written. Includes a log format and ten assumptions every SOW should state.

Rohan Kulkarni ·

Free SOW vulnerability audit

Drop in a PDF SOW. See the gaps in 60 seconds.

TWINJAM flags ambiguous deliverables, missing exclusion clauses, uncapped revisions and untestable assumptions, then scores the contract before your next client asks for “just one more thing”.

Run a free SOW audit

HFX-APP_SOW_v3.pdf

Halvorsen Freight · 26 pages

61

of 100

  • "Standard integrations" undefinedHigh
  • No revision cap on design deliverablesHigh
  • Browser support not listedMedium
  • Client content dates missingMedium
  • Change control in section 9Pass

Stop delivering free software features on fixed-fee contracts.

Upload a live project SOW. We will show you the out-of-scope Slack requests your team is building for free right now.