# Fix Failing GitHub Actions Checks in a Rails App

Yes. When your Rails build goes red, an agent reads the failed job's log, reruns the same RSpec, lint or Brakeman command, fixes the cause and opens a pull request.

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

## What the agent does

The agent reads the failure before it reads any code. From the `workflow_run` event it runs `gh run view <run id> --log-failed` and names the job that failed. That matters in a Rails repository like lobsters/lobsters, whose `.github/workflows/check.yml` has four jobs with different failure modes: `test` runs `bundle exec rspec`, `lint` runs `bundle exec standardrb`, `security` runs `bundle exec brakeman --ensure-ignore-notes`, and `database-consistency` loads the schema and runs the `database_consistency` gem against the models. A red `lint` job is a formatting diff, a red `security` job is usually a Brakeman warning whose ignore entry lacks a note, and only the `test` job needs a spec reproduced. The agent quotes the failing block and says which case it is.

Then it builds the same environment. `.ruby-version` pins Ruby 4.0.0 and the `Gemfile` resolves to Rails 8.1.3.1 and `rspec-rails` 8.0.2. The workflow installs `libvips` for `ruby-vips`, copies the test credentials with `cp .github/workflows/check/* config/`, installs `config/database.yml.sample` as `config/database.yml`, which puts the primary, cache, queue and `rack_attack` databases on SQLite files under `db/test`, and runs `./bin/rails db:schema:load db:migrate`. Every job sets `RUBYOPT` to `--yjit --enable-frozen-string-literal --debug-frozen-string-literal`, so a spec that passes locally but fails in CI is often a string mutated in place. `lib/tasks/build.rake` is the maintainers' local copy of those steps, and the agent reads it when a step is unclear.

With the environment in place it runs the exact failing command, narrowed first: `bundle exec rspec spec/requests/stories_spec.rb -e "returns previous discussions for an existing story"` for one example, with the same `RUBYOPT`, so the failure is on record before any change. It then reads the code the spec covers, such as `StoriesController#show`, which redirects merged stories, renders a 404 when the story may not be seen and canonicalizes the title path, or `CommentsController#create`, which answers 400 for a missing story, rejects a parent comment from another story, and skips a duplicate submission. It reads the commit that broke the job as well, because the fix belongs where that commit changed behavior.

The fix goes in the application code. A test is changed only when the test itself is wrong, and the pull request says so. Before pushing, the agent runs the whole `bundle exec rspec`, then `bundle exec standardrb` and `bundle exec brakeman --ensure-ignore-notes`, so a fix for the `test` job does not turn the `lint` or `security` job red in the next run. Each job has `timeout-minutes: 15`, and the agent notes when a spec it added is slow enough to matter.

## Start it with one API call

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

```json
{
  "agent": "codex",
  "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 job that failed (test, lint, security or database-consistency), and quote the failing example, standardrb offense or Brakeman warning. Use the Ruby in .ruby-version, install libvips, copy the test credentials from .github/workflows/check/ and config/database.yml.sample into config/ as the workflow does, run bin/rails db:schema:load db:migrate, and reproduce the failure with the same command and the workflow's RUBYOPT, narrowed to the failing spec first. Fix the cause in the application code (change a test only if the test is wrong, and say so), then run bundle exec rspec, bundle exec standardrb and bundle exec brakeman --ensure-ignore-notes until all three 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 `app/` and the job name and quoted failure in the description. For a `test` failure the description shows the single example failing and then passing, then the full `rspec` run; for a `lint` failure it shows the `standardrb` offense; for a `security` failure it shows the Brakeman warning and the note it added or the code it changed. Every command the agent ran in its sandbox is listed, and the session's trajectory keeps each with its output.

When the log shows a failure the sandbox cannot reproduce, such as a flaky example that passes on rerun, the agent says so, runs the example several times, and either fixes the order dependence it finds or reports that it found none rather than retrying CI blindly. When there is no code cause, it opens nothing and its answer explains what the log shows.

A reviewer checks that an edited spec was really wrong, that a Brakeman ignore entry carries a real note, that the change keeps the frozen string literal option happy, and that `config/` and the workflow are untouched.

## Run it on every failed Rails workflow run

Add an automation to the Project with this prompt and a `github` trigger on `workflow_run.failure`. Each failed run of the `CI` workflow then starts one run with the event under the prompt; the trigger fires only for work by owners, members and collaborators, so a fork's red build does not start one. Alternatively, send GitHub's `workflow_run` webhook to your own server and send this request yourself with `https://github.com/<owner>/<repo>/tree/<head_branch>` as the resource.

Exclude branches the agent opened so its own pull request's failure does not start a second run, keep each `workflow_run.id` with the returned `execution_id` to drop redeliveries, and use the `run.completed` webhook from Rush to post the pull request link on the contributor's pull request.

## Why run it on Rush?

A red Rails build with four jobs is tedious on a laptop: you scroll the log to find which job failed, install the right Ruby and `libvips`, copy credentials, load the schema, and only then rerun the spec with the flags CI used. The agent does that in its own sandbox from the workflow file, without touching your checkout or your local databases.

What it hands back is checkable: the quoted failure, the trajectory with every `rspec`, `standardrb` and `brakeman` run and its output, and the workflow rerunning on the pull request. Failures on several branches each get their own run at the same time, and nothing merges without a reviewer.

## Frequently asked questions

### Will it fix a lint failure by changing the standardrb config?

No. It runs `bundle exec standardrb --fix` on the offending files only where the fix is mechanical, and otherwise edits the code by hand. A change to `.standard.yml` would show in the diff and the prompt does not ask for one.

### Does it need MySQL?

Not in this repository: `config/database.yml.sample` puts every connection on SQLite under `db/test`, so `db:schema:load` runs in the sandbox with no server. A Rails app on MySQL or Postgres gets that server started the way its workflow's `services` block does.

### What about the database-consistency job?

It copies the same credentials and schema steps as the `test` job and then runs the `database_consistency` gem. The agent reproduces that command and fixes the model or migration it complains about, with the same rule that a check is silenced only with a stated reason.

### Will it touch the credentials in .github/workflows/check/?

No. It copies them into `config/` for the run, exactly as CI does, and the pull request never includes `config/credentials.yml.enc`, `config/master.key` or `config/database.yml`.
