Back to BlogQuality & Testing

Our Offshore Team Ships Bugs: The QA Gates That Fix It

Rupak Amin

Founder & Lead Engineer, RAITHub

12 min read

An offshore team usually ships bugs because nothing stops a bug before release, not because of where the team sits. The fix is a set of gates: a written definition of done, required CI checks on every pull request, a test with every bug fix, an independent QA pass on staging, a release checklist with rollback, and a review of every bug that escapes.

If you would rather have the gates set up and run for you, see how RAITHub would test this below, or the QA as a service overview.

Why does my offshore team keep shipping bugs?

Almost always for process reasons that would cause the same result with a team down the hall. The usual causes:

  • Tickets without acceptance criteria. The developer builds what the ticket says, the ticket was vague, and the gap is discovered by a customer.
  • Developers test only their own work. The person who wrote the code checks the path they had in mind, not the paths users take.
  • No test is required to merge. Tests exist, or do not, but nothing blocks a pull request that breaks them.
  • No production-like staging. Code is checked on a laptop with different data, settings and services.
  • Slow feedback across time zones. A question asked at the end of one team's day is answered at the start of the other's, so developers guess instead of waiting.
  • Incentives to close tickets. If the team is measured on tickets closed, quality is whatever is left at the end of the sprint.

Faster coding makes this worse, not better. The 2025 DORA research on AI-assisted software development describes AI's primary role as "an amplifier, magnifying an organization's existing strengths and weaknesses" (DORA 2025 report). A team without gates that starts writing code faster will ship bugs faster.

What is a QA gate?

A QA gate is a check that must pass before work moves to the next stage, enforced by a tool or a named person rather than by good intentions. The six gates below catch different kinds of bug at different moments.

GateWhat it blocksWho owns itEffort to set up
1. Definition of doneWork that is "finished" but untested or unclearProduct owner and team leadAn hour to write, weeks to make habit
2. Required CI checksMerges that fail lint, types, unit or end-to-end testsThe repository settingsHours if CI exists
3. A test with every bug fixThe same bug returning laterReviewer of each pull requestNo setup; a review rule
4. Independent QA on stagingBugs on paths the developer did not think ofA tester who did not write the codeDays, if staging needs building
5. Release checklist and rollbackBroken releases with no way backRelease ownerA day to write and rehearse
6. Escape reviewThe same kind of bug escaping twiceTeam lead30 minutes per escaped bug

Gate 1: what should a definition of done include?

A short checklist that every ticket must meet before anyone calls it done. Put it in your pull request template so it appears on every change:

## Definition of done
- [ ] Acceptance criteria in the ticket are met, including the "must refuse" cases
- [ ] Unit or integration tests added for new rules
- [ ] Bug fixes include a test that failed before the fix
- [ ] Tested on staging with production-like data
- [ ] Works for every role that can reach this screen
- [ ] Error states show a clear message and reach error tracking
- [ ] No new console errors; migrations run cleanly from empty

The most important line is the first. Ask for acceptance criteria written as examples ("a manager can approve; a viewer sees the button disabled") before work starts. Most "offshore bugs" are specification gaps.

Gate 2: how do you make CI checks required on every pull request?

Run the checks on every pull request, then make them required in branch protection, so a red check physically blocks the merge. On GitHub, required status checks must succeed before changes can be merged to a protected branch (GitHub protected branches docs). A minimal workflow for a Node and TypeScript project:

name: pr-gates
on:
  pull_request:
    branches: [main]
jobs:
  checks:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm run lint
      - run: npx tsc --noEmit
      - run: npm test
      - run: npx playwright install --with-deps chromium
      - run: npx playwright test --project=chromium

Then, in the repository's branch protection rule for main, require the "checks" job to pass and require at least one approving review. Also turn off direct pushes to main, including for administrators, or the gate has a side door.

Keep the end-to-end layer small at first: the three to seven journeys that make money or hold data. A short, reliable suite that blocks merges is worth more than a long one people learn to ignore. For which journeys to choose, see regression testing on every deploy.

Gate 3: why must every bug fix ship with a test?

Because a bug without a test is a bug that can come back. The rule is simple: the pull request that fixes a bug includes a test that fails without the fix and passes with it. Reviewers reject fixes without one. Over a few months this builds a regression suite shaped exactly like your real failures, which is more useful than any coverage target. If releases are breaking right now, every release breaks something covers the first week of stopping the bleeding.

Gate 4: who should test before a release?

Someone who did not write the code. Developers are good at proving their code does what they intended; an independent tester is good at finding what nobody intended. That tester works on a staging environment with production-like settings and realistic seed data, against the acceptance criteria and with time for exploratory testing.

This is the gate offshore setups most often skip, because the vendor's developers "test their own work". If your vendor has no independent testers, add them, either in-house or as a service such as manual and exploratory testing. Time zones help here: work merged at the end of the developers' day can be tested before they start the next one, with results waiting in a written handoff.

Gate 5: what goes in a release checklist?

A short list run on every release: critical journeys pass on staging, migrations ran cleanly, feature flags are set as planned, monitoring is green, and the rollback is known. Rollback means more than redeploying old code: decide in advance what happens to database changes. The pre-launch QA checklist is a fuller version for a first launch.

Gate 6: what should you do when a bug still escapes?

Hold a short, blameless review for every bug a customer finds: which gate should have caught it, and why it did not. Then change one thing: a new acceptance criterion pattern, a new end-to-end journey, a staging data fix. Track three numbers per release: bugs found by customers, the share of releases that needed a hotfix or rollback (close to what DORA calls change failure rate, "the ratio of deployments that require immediate intervention following a deployment", in its DORA metrics guide), and tickets reopened after "done". If those numbers do not fall within two or three months, the gates are not being enforced.

How do you roll out QA gates without stalling the team?

One gate at a time, in this order: definition of done, required CI checks with the tests you already have, a test with every fix, independent QA, the release checklist, then escape reviews.

Do-it-yourself time estimate: 1 to 2 days to add required CI checks if you already have CI and some tests; 2 to 4 weeks to put all six gates in place alongside normal work, if someone on your side knows GitHub Actions or a similar CI tool. Main risk: flaky tests. If a gate fails at random, people learn to rerun or bypass it. Playwright, for example, labels a test that fails first and passes on retry as "flaky" (Playwright test retries docs); treat those as bugs to fix, using the approach in fixing flaky end-to-end tests.

Is the problem the team or the process?

Give the gates two or three months. If bugs still escape with the gates enforced, you have learned something about the team. If the vendor resists the gates, you have learned something sooner. Signs it is the team: the same kind of bug keeps escaping after reviews, tests are written to pass rather than to check, and nobody can explain how the code deploys. The wider costs of a cheap vendor are covered in the hidden cost of cheap offshore development, and running a remote team well in how to manage an offshore development team. If the codebase itself has become unsafe to change, a code rescue diagnostic comes before more testing.

Buy, build or hire?

RouteChoose this whenWatch out for
A tool or SaaS testing platformYour team will write the tests and only needs CI, device clouds or test runnersTools do not decide what to test or enforce review rules
Freelancers or crowdtestingYou need an independent pass on one releaseNo memory of the product between releases
An in-house QA hireYou can lead QA and want gates owned inside the companySlow to hire; one person cannot cover security, accessibility and mobile
A managed QAaaS teamYou want the gates set up and run independently of the developersMake sure tests live in your repository and CI

Why RAITHub for QA gates?

  • An offshore team that works this way itself. RAITHub is based in Dhaka, and its own builds run their test suites in CI. PropDesk runs 1,024 automated tests, and Sundor Skin runs 530+ and enforces row-level security on 146 PostgreSQL tables.
  • Independent of your developers. As a QA service, RAITHub tests work it did not write, which is the point of gate 4.
  • Gates in your systems. Workflows, tests and branch rules go into your repository, with IP assigned to you and an NDA as standard.
  • Specialist testing on top. Mobile testing on real devices, web application security testing and WCAG 2.2 accessibility audits when releases need them.

When don't you need RAITHub for this?

  • When your team can set up the six gates itself. The workflow above and an afternoon of branch settings are a good start.
  • When you want to manage testers yourself inside your vendor's team. That is staff augmentation, which RAITHub does not offer.
  • When the issue is a certified security attestation. RAITHub's security testing is application-level, not an accredited pentest.

How RAITHub would test this

  • Audit: read your repository, CI, branch rules and the last few escaped bugs, and name which gates are missing.
  • Gates: add the definition of done, required checks and the first end-to-end journeys in your CI, using your existing tools where they work.
  • Independent QA: a staging test pass on each release, with bug reports your developers can act on in their next working day.
  • Review: escape reviews and a regular report of customer-found bugs, hotfixes and reopened tickets.

Timeline: the gate setup is a fixed-scope audit with dates agreed before it starts; ongoing QA runs as a monthly plan. You receive: CI workflows, tests and branch rules in your repository, a written gate policy, handover documents, full IP and an NDA. Next step: a free 15-minute audit, then a written fixed quote. RAITHub publishes no rates. For automation details, see QA and test automation.

To get gates in place, request a one-off QA gate audit, or ask about ongoing QA.

Frequently asked questions

Why does my offshore development team ship so many bugs?

Usually because nothing blocks a bug before release: vague acceptance criteria, developers testing their own work, no required tests to merge and no production-like staging. Those are process gaps, and gates close them.

What is a quality gate in CI?

A check, such as lint, type-checking or tests, that must pass before a pull request can merge. It becomes a gate when branch protection makes it required, so a failure blocks the merge.

How long does it take to set up QA gates?

Required CI checks take 1 to 2 days if CI and some tests exist. All six gates take 2 to 4 weeks alongside normal work.

Should the offshore team test its own code?

Developers should write automated tests for their own code. A release still needs a check by someone who did not write it, because authors test the paths they had in mind.

How do I know if the problem is the team rather than the process?

Enforce the gates for two or three months. If the same kinds of bug keep escaping, or the vendor resists the gates, the problem is likely the team.

Can RAITHub act as an independent QA team for another vendor's code?

Yes. RAITHub can test code written by another team, as a monthly plan, a one-off audit or a dedicated team that RAITHub manages.

offshore team qualityQA gatesCI quality gatesdefinition of donebranch protectionregression testing

Ready to discuss your project?

Book a free 15-minute technical audit with our engineering team.