Paraglobe
Migration testing for coding agents

Your agent writes the code. Paraglobe tests what happens.

Give your coding agent a production-shaped test environment to experiment on. Test database migrations at realistic scale, under modeled production load, before you open a pull request. Then the pull request’s check catches queries that got slower.

See a check in action Request a demo
A check in action

An agent catches its own migration.

The prompt: “add a column outcome to Call”. Claude Code chose on its own to check the migration with Paraglobe.

Claude Code › add a column outcome to Call
Round 1 · as writtencheck took about 8 min
🔴 Migration blocks requests
ALTER TABLE "Call" ADD COLUMN …
-- lock timeout 5 s
19 of 20requests stalled 1 s or more9.7 slongest stall15database sessions queued behind the lockfailsthe deploy itself
After the failed deploy, Prisma would refuse every later deploy.
Round 2 · the safer form Paraglobe offeredcheck took about 4½ min
🟢 Migration clean

The agent took the safer form from the first result and checked it again on a fresh copy.

0 of ~600requests failed1.7 slock wait

Measured on a voice-agent platform we run in production as our own test customer (TypeScript, Prisma, Postgres behind a pooler). Run four times unprompted, with the same result each time. About 8 minutes for the first check, 4½ for the second.

On the pull request

A migration that blocked writes.

Our own migration, run on Mattermost v11.11.0: an index on 20 million posts, measured as written and in its safer form.

Migration check Mattermost · 20,000,163 posts · 12 GB table · measured
FAIL · BLOCKS WRITEStotal run 8m 25s
Add index on posts (userid, createat)
The index built without errors. While it built, writes to posts were blocked for about 28 s, and posting p99 reached about 28 s against a 30 s request timeout.
Requests waiting on posts · schematicoriginalrevised
700
0 s
start
writes blocked~28 s
recover
Affected operationsas written
Posting a messagep99 ~28 s
Reading a channelslowed
Original vs. revised change
OriginalRevised
Writes blocked~28 snever
Waiting, peak700
Posting p99~28 s~390 ms
Reading a channelslowedslowed
🟡 WARNINGRevised: no writes blocked; posting slowed to ~390 ms for 38 s.
CREATE INDEX CONCURRENTLY IF NOT EXISTS idx_posts_user_id_create_at ON posts(userid, createat);
Conditions
Synthetic data: 20M posts across 3,022 channelsMattermost v11.11.010 requests/s across 4 request typesNot compared with a real deployment
Inspect the evidence, workload and safer alternative→
The problem

Your tests pass. Production is different.

Staging is small and nobody is using it. In production, a change that succeeds at the database can still take the application down: the lock it holds backs up the connection pool, requests time out, and queues and workers fall behind. Each component works. Together, under load, they fail.

Same migration · CREATE INDEX on posts
Application
70 requests waiting · posting p99 ~28 s
Database driver
waiting on the database
Connection pool
held by waiting writes
Database
CREATE INDEX · ok · writes to posts blocked ~28 s
Channel reads
slowed
Request timeout
30 s · posting p99 ~28 s
Background jobs
writes to posts wait
The database reports success. The application around it is failing.Illustrative · numbers from the experiment above
How it works

Write. Test. Fix. Keep going.

  1. 01agentWriteYour agent writes a migration and sends it to Paraglobe.
  2. 02ParaglobeTestAn isolated copy of your whole system (app, pooler, database) runs it against a workload shaped like your production traffic.
  3. 03ParaglobeMeasureParaglobe returns what it measured: blocked requests, lock waits, failed deploys, and a safer form when there is one.
  4. 04agentReviseYour agent revises the change and tests again on a fresh copy.
↻ 04 → 01 · repeat until the result is cleanthen open the pull request
The product

The answer belongs on the pull request.

Each Check answers the questions you’d ask before deploying, with the evidence one click away. The verdict comes first; the detail is there when you need it.

Paraglobe Check · Add index on postsillustrative layout · numbers from the Mattermost run BLOCKS
›What changed?One migration: an index on posts (userid, createat).1 migration
CREATE INDEX IF NOT EXISTS
idx_posts_user_id_create_at ON posts(userid, createat);
›What was tested?The migration beside the CONCURRENTLY version, on synthetic data: 20,000,163 posts (12 GB) across 3,022 channels, Mattermost v11.11.0, 10 requests/s across 4 request types.2 runs
›What failed or degraded?Writes to posts blocked about 28 s; 70 requests waiting at peak; posting p99 about 28 s, against a 30 s request timeout.fail
›What was affected?Posting waited for the index build. Reading a channel slowed too.writes, reads
›What evidence supports it?Lock waits and request latency measured during the run.measured
writes blocked ~28 s
requests waiting 70 at peak
posting p99 ~28 s (timeout 30 s)
total run 8m 25s
›Does an alternative behave better?Better, not clean. With CONCURRENTLY no writes were blocked, but posting slowed to ~390 ms for 38 s.🟡 warning
CREATE INDEX CONCURRENTLY IF NOT EXISTS
idx_posts_user_id_create_at ON posts(userid, createat);
-- writes blocked: never · requests waiting: 0
-- build ~38 s · posting p99 ~390 ms during the build
›What wasn’t compared?Nothing was compared with a real deployment. The data was synthetic.limitation
Fidelity

An experiment is only useful if you can trust it.

We score our predictions against production. We record what matched and what didn’t, misses included, and share it with teams evaluating Paraglobe. We run a production system of our own and predict what each change will do before it ships, then score the prediction against what actually happened.

  1. 01beforePredictBefore a change ships, we write down what we expect production to do.
  2. 02afterCompareAfter it deploys, we compare the prediction with what production actually did.
  3. 03recordRecordWe record what matched and what didn’t, misses included, and share it with teams evaluating Paraglobe.
Engineering proof

Built for the failures ordinary tests miss.

Internal experiment · add a column and backfill it in one transactionBLOCKS
Conditions
Database1 TB test database, shaped like a messaging app
Trafficproduction-shaped request mix
Changeadd a column and backfill it in one transaction
Limit30 minutes
Observed impact
99%of requests failed30 minstopped at the limit~4 daysbackfill at measured rate8 sto recover
Investigation

ALTER TABLE … ADD COLUMN took an ACCESS EXCLUSIVE lock on messages and held it until COMMIT. Every request touching the table queued behind the backfill. At the measured rate it would have taken about 4 days.

As written· locks messages for the whole backfillillustrative SQL
1BEGIN;
2ALTER TABLE messages ADD COLUMN sentiment smallint;
3UPDATE messages SET sentiment = score(body); -- every row
4ALTER TABLE messages
5 ALTER COLUMN sentiment SET NOT NULL;
6COMMIT;
Safer alternative· no lock held across the backfillillustrative SQL
1-- 1. the column on its own
2ALTER TABLE messages ADD COLUMN sentiment smallint;
3-- 2. backfill in committed batches
4UPDATE messages SET sentiment = score(body)
5 WHERE id > $1 AND id <= $2;
6COMMIT; -- repeat until done
7-- 3. the constraint, without locking
8ALTER TABLE messages ADD CONSTRAINT sentiment_nn
9 CHECK (sentiment IS NOT NULL) NOT VALID;
10ALTER TABLE messages VALIDATE CONSTRAINT sentiment_nn;
Privacy

No rows leave your database.

You run one read-only command that collects your schema and rounded statistics; you read exactly what it collected before sending it. We generate the test data from that.

Find out what your next change would do.

We’re working with engineering teams to bring production-calibrated verification into their development workflow.

Request a technical evaluation hello@paraglobe.dev