# Fix Failing GitHub Actions Checks in a Laravel App

Yes. When a Laravel build fails, an agent reads the failed job's log, reruns php artisan test on the same PHP and database, fixes the cause and opens a PR.

[Run this on Rush](https://cloud.getrush.ai/run/fix-failing-ci/laravel/), in a Project that has your repository.

## What the agent does

The agent starts with the log of the job that failed. It receives the `workflow_run` event, runs `gh run view <run id> --log-failed`, and reads which matrix entry broke. In a Laravel app like monicahq/monica that matters, because `.github/workflows/tests.yml` does not list steps itself: it calls the reusable workflow `monicahq/workflows/.github/workflows/laravel.yml@v2` with `php-versions: "['8.3', '8.4']"` and `connections: "['sqlite', 'mysql', 'pgsql']"`, defaulting to PHP 8.3 on SQLite. A test that fails only on `pgsql` is a different problem from one that fails everywhere, so the agent names the PHP version and connection from the job name and quotes the PHPUnit failure, then opens the reusable workflow file to see the exact commands it runs.

Then it sets up the same PHP and database. `composer.json` requires PHP `^8.3`, `laravel/framework` `^12.0` and `phpunit/phpunit` `^11.0`, and the agent runs `composer install` from `composer.lock` on the PHP version the failing entry used. `phpunit.xml` sets `DB_CONNECTION=testing`, `QUEUE_CONNECTION=sync`, `CACHE_STORE=array`, `MAIL_MAILER=array` and `SCOUT_DRIVER=collection`, and `config/database.php` points the `testing` connection at `env('DB_TEST_DRIVER', 'sqlite')` with `database/database-test.sqlite` as the default file. For a SQLite failure the agent creates that file and runs the migrations against it; for MySQL or Postgres it starts that database and sets the `DB_TEST_*` variables the workflow sets.

It runs the failing test alone with `php artisan test --filter`, such as `php artisan test --filter=CreateContactTest`. Monica's domain tests sit beside the domain code: `app/Domains/Contact/ManageContact/Services/CreateContact.php` is covered by `tests/Unit/Domains/Contact/ManageContact/Services/CreateContactTest.php`, which uses `DatabaseTransactions` and helpers like `createUser`, `createVault` and `setPermissionInVault(..., Vault::PERMISSION_MANAGE, ...)`, and expects `NotEnoughPermissionException`, `ValidationException` or `ModelNotFoundException` for the wrong caller or input. The agent reads the service's validation rules and permission checks against the failing assertion and fixes the code the failing commit changed.

A query that works on SQLite and fails on Postgres, such as a case-sensitive `LIKE` or a string compared to an integer column, is fixed in the query, not by skipping the connection. After the fix the agent runs the full `php artisan test` on the failing connection and on the default SQLite, so the pull request does not move the failure to another matrix entry.

## Start it with one API call

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

```json
{
  "agent": "claude",
  "input": "The GitHub Actions workflow on this branch failed; the workflow_run event is at the end of this prompt. Read the failed job's log with gh run view <run id> --log-failed, name the PHP version and database connection of the failing matrix entry, and quote the PHPUnit failure. If the workflow calls a reusable workflow, read that file for the exact steps. Install with composer from the lockfile on the same PHP version, set up the same test database and migrate it, and reproduce the failure with php artisan test, filtered to the failing test first. Fix the cause in the application code (change a test only if the test is wrong, and say so; never skip a database connection), run the full php artisan test on the failing connection and on the default one until they pass, and open a pull request against the failing branch that quotes the error it fixed.\n\nEvent: <workflow_run payload>",
  "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

A pull request against the failing branch with the fix in the service, model, policy or controller the PHPUnit trace named. Its description quotes the failing test and assertion from the GitHub log, names the PHP version and connection, and lists every command the agent ran in its sandbox: the composer install, the migration, the filtered test and the full suite on each connection it tried. The workflow's full matrix reruns on the pull request, and the trajectory keeps each command with its output.

When the log shows a failure outside the code, such as a MySQL service that never became healthy, a Composer package that could not be downloaded, or a SonarCloud step failing on its token, the agent opens no pull request and its answer says what failed and where. That answer arrives on your webhook with the run.

A reviewer checks that permission checks such as `Vault::PERMISSION_MANAGE` were not loosened to make a test pass, that a query fix behaves the same on all three databases, and that any edited test was wrong rather than inconvenient.

## Run it on every failed Laravel test matrix

Send GitHub's `workflow_run` webhook to your server and, for each run that completes with `conclusion: failure`, send this request with the event in `input` and `https://github.com/<owner>/<repo>/tree/<head_branch>` as the resource. A matrix across PHP versions and databases produces one `workflow_run`, so one run handles every failing combination; exclude the agent's own branches so its fixes do not trigger it again.

Rush POSTs `run.completed` or `run.failed` to the webhook URL on your API key when the run finishes, with its answer and session URL, so your server can comment the pull request link on the contributor's pull request. Keep each `workflow_run.id` with the `execution_id` to drop redelivered events.

## Why run it on Rush?

A failure on one PHP version and one database is slow to chase on a laptop: you need that PHP, that database server, a migrated test database and a clean `vendor/` before the test even runs. The agent builds that in its own sandbox with its own clone, so your local PHP, your Valet or Sail setup and your current branch are untouched, and it starts as soon as the matrix goes red.

The fix comes with proof a reviewer can follow: the quoted PHPUnit failure, the trajectory with every Composer, migration and test command and its output, and the full matrix rerunning on the pull request. When several branches fail together, each one gets its own run in parallel, and a person merges each fix.

## Frequently asked questions

### Can it reproduce a failure that happens only on Postgres or MySQL?

Yes. It starts the database the failing matrix entry used and points the `testing` connection at it through the `DB_TEST_*` variables, then runs the same test. The pull request says which connections it ran the suite on.

### Does it work with Pest instead of PHPUnit?

Yes. `php artisan test` runs Pest suites too, and the agent filters to the failing test the same way. It writes any test changes in the style your suite already uses.

### Our workflow calls a reusable workflow in another repository. Can it read that?

It reads it when the file is public, as Monica's `monicahq/workflows` is, or when the Rush GitHub App can reach that repository. If it cannot read it, it works from the commands the job log shows and says so.

### Will it change my phpunit.xml or skip tests?

The prompt rules out skipping a connection or a test, and any change to `phpunit.xml` or the workflow shows in the diff for the reviewer. Its fixes go in application code unless a test is shown to be wrong.
