# Review Database Migrations in Elixir Pull Requests

An agent reviews your Ecto migration diff against sandbox Postgres, identifying lock risks, destructive statements and safer rollout sequences.

[Run this on Rush](https://cloud.getrush.ai/run/review-database-migrations/elixir/), in a Project that has your repository.

## What the agent does

The agent reads the pull request before running a database command. In an Elixir application like [hexpm/hexpm](https://github.com/hexpm/hexpm), `mix.exs` declares `elixir: "~> 1.20"` and a test alias that creates the database, loads its structure and migrates before ExUnit runs. The lockfile resolves Ecto to `3.14.2`. Those details matter because this repository does not expect every historical migration to replay into an empty database. The review compares the proposed migrations with the base branch and identifies which versions are genuinely new, rather than treating the whole migration directory as the proposed change.

It prepares a disposable Postgres database using the repository's setup. [The test configuration](https://github.com/hexpm/hexpm/blob/HEAD/config/test.exs#L88-L95) names `hexpm_test` and the SQL sandbox pool; [CI](https://github.com/hexpm/hexpm/blob/HEAD/.github/workflows/main.yml#L88-L102) uses Postgres 18. The agent installs the locked dependencies with `mix deps.get`, prepares the base structure in the test environment, and applies the new migration separately with its SQL output recorded. It checks rollback only on that disposable database and states when a down operation cannot recover the original data. No production database credentials belong in this request.

The review distinguishes reversibility from operational safety. [The existing releases index migration](https://github.com/hexpm/hexpm/blob/HEAD/priv/repo/migrations/20260814120200_index_releases_by_semver_sort_key.exs#L4-L15) declares `@disable_ddl_transaction true`, disables the migration lock and uses `CREATE INDEX CONCURRENTLY`. That is useful context when a new migration adds an ordinary index on a busy table. The agent also examines column narrowing, data deletion, foreign-key validation and nullability changes. A statement that succeeds against an empty table still needs an assessment of the lock it acquires and the work it performs against populated tables.

For each actionable finding, it names the changed file, statement, affected table and concrete failure scenario. A proposed rewrite might separate schema expansion, a resumable backfill, constraint validation and later cleanup. The request asks for comments on the existing pull request, not a replacement migration or another implementation branch. It also asks the agent to run `mix test` where the environment permits, and to separate that result from the migration experiment. A successful ExUnit run is supporting evidence, not a measurement of production lock duration.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "Review the Ecto migrations added by the open pull request for the checked-out branch; ask for the PR URL if it is ambiguous. Read mix.exs, mix.lock, the database configuration and CI first. Prepare a fresh disposable Postgres from the base branch's supported structure/setup, then apply only the proposed migrations and record their SQL. Check table rewrites, lock acquisition, dropped or narrowed data, constraint validation and rollback limitations. Run the relevant tests and mix test when possible. Comment on the existing PR with file and changed-line references, evidence and a safer rollout sequence. Distinguish observed sandbox results from production-size risks. Do not edit migrations, open another PR, connect to production or claim unrun checks passed.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

The result is a review on the existing pull request and a written summary of the database checks. Each comment explains why a particular statement is risky and what sequence avoids the problem. The summary identifies the base revision, migration versions, database version, commands and any failed setup step. Where commenting is unavailable, the answer contains the proposed comments without claiming they were published.

Before merging, a maintainer checks the proposed sequence against actual table sizes, deployment overlap and the application's read and write paths. A rollback that recreates a column does not restore its deleted contents. The sandbox transcript preserves the commands and output, while the reviewer supplies the production context that a fresh database cannot establish. No completed Rush run or measured locking result is asserted by this example.

## Run it on every migration pull request

Have your GitHub webhook handler select pull requests that change `priv/repo/migrations`, then send one API request per head revision. Replace the example resource with the pull request URL so Rush checks out its branch, and include the base and head revisions in the input. Use an `Idempotency-Key` for retries of that same request, and a new key for a changed revision. A completion webhook lets your service retrieve the review summary without keeping an event stream open.

## Why run it on Rush?

Migration review benefits from a database that can be changed and rolled back without touching a developer's working dataset. Rush gives the agent its own sandbox for that experiment, including the failed commands that explain a refusal or a rollback limitation. The work stays focused on the pull request instead of competing with a laptop's existing Postgres instance and half-applied migrations.

Separate migration reviews can run independently, subject to your key's concurrency limit. Their results remain attributable to the source revisions and command output, so the team can compare a revised migration with the earlier review. Read the session result and transcript through the API rather than accepting an unsupported statement that the deployment is safe.

## Frequently asked questions

### Does a successful sandbox migration prove it will not block production?

No, a fresh database does not reproduce production row counts or concurrent traffic. The review combines observed SQL with a statement-level explanation of locking and flags the production measurements still needed.

### Will the agent rewrite my migration?

This request explicitly asks for review comments only. You can approve a proposed sequence in a later, separate instruction if you want an implementation.

### Can it review raw SQL inside an Ecto migration?

Yes, the review includes statements passed to `execute`, not just Ecto's table and index helpers. The concurrent-index migration in the example repository is a concrete reason to inspect both forms.

### What happens when the database setup cannot run?

The requested summary names the failed command and keeps static findings separate from execution evidence. It must not describe an unapplied migration or an untested rollback as verified.
