# Run The Validators CI Runs

> A green local build does not mean a green CI. Projects skip expensive validators (errorprone, RAT, forbidden-apis, license checks) on developer machines and enable them only in CI, where the same warning becomes a hard failure under -Werror. So "check passed locally" can be true while CI is red on the very file you just changed. Before claiming a change is done, find the project's opt-in flags for the validators its CI enables, and run with them. And when a validator does fire, fix the RULE across the whole diff — not the one line the reviewer pointed at. Use before saying "done", "green", or "ready for review". Trigger terms: check passed, build is green, CI is red but it works locally, errorprone, -Werror, lint failure, skipped on builds not running inside CI, warnings found.

- Skill: `serhiy-bzhezytskyy/run-the-validators-ci-runs` (Agent Skill)
- Install (CLI): `npx skillmds@latest add serhiy-bzhezytskyy/run-the-validators-ci-runs`
- Raw SKILL.md: https://api.skillmd.com/api/skills/serhiy-bzhezytskyy/run-the-validators-ci-runs/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: serhiy-bzhezytskyy (https://skillmd.com/u/serhiy-bzhezytskyy)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/serhiy-bzhezytskyy/run-the-validators-ci-runs

---


# Run the validators CI runs

## Purpose

Local builds are tuned for iteration speed, so projects disable the slow static
analysers and enable them only in CI. The failure mode is specific and expensive:
you run the project's own documented gate, it passes, you report "done" — and CI
fails on a warning your build never computed. The reviewer then sees a red PR they
already reviewed, which spends their attention on your build hygiene instead of your
change.

The second half matters as much as the first. When a linter does fire, the reviewer
usually quotes *one* instance. That instance is an example, not the requirement: the
**rule** is the requirement. Fixing only what was quoted leaves the same violation
elsewhere in your diff, and the next CI run finds it — costing a second round for
the same lesson.

## When to use

- Before saying "done", "green", "tests pass", or "ready for review".
- Immediately after a lint/static-analysis failure appears in CI.
- When CI is red and the local build is green — assume the validator gap first.

## When NOT to use

Not for the slow *test* suites — running every module's tests locally is often
impractical and CI exists for that. This is about **validators**: they are fast,
deterministic, and their absence locally is silent.

## The practice (checklist)

- [ ] Find the flags. Grep the build for validator toggles and read the CI workflow
      for what it actually enables:
      `grep -rn "validation\.\|skipIf\|onlyIf.*CI\|System.getenv(\"CI\")" build*.gradle* gradle/`
      and `cat .github/workflows/*.yml | grep -iE "gradlew|mvn|task"`.
- [ ] Run the gate **with** them, not just the bare gate. *Done when* the command
      you quote in your status includes the flags.
- [ ] Read the build's own output for skip notices. A line like
      `WARNING: errorprone disabled (skipped on builds not running inside CI
      environments, pass -Pvalidation.errorprone=true to enable)` is the project
      telling you your green is partial.
- [ ] When a validator fires, fix the **rule across the diff**, not the quoted line:
      `for f in $(git diff --name-only main...HEAD); do grep -n '<pattern>' "$f"; done`
      *Done when* the pattern returns nothing across every changed file.
- [ ] Re-run the flagged gate after the fix, before reporting.

Treat the flagged run as **mandatory before any "done"** — the whole point is that
its absence produces no error to notice.

## Rationalizations

| Shortcut | Why it fails |
|---|---|
| "`gradlew check` is the documented gate, and it passed." | It is documented *and* partial. The project disables validators locally by design; the documented command is not the CI command. |
| "CI will tell me." | It will — after the reviewer sees red on a PR they already reviewed. You spend their attention instead of 90 seconds of yours. |
| "I fixed the line they pointed at." | The linter quoted one instance of a rule. Other instances of the same rule are still in your diff; the next run finds them. |
| "It's only a warning." | CI commonly runs `-Werror`. There, a warning *is* a compile failure. |
| "The failure is unrelated / flaky." | Maybe — but check before saying so. "Known flaky" is the label most often applied to a real regression. |

## RECEIPT

**apache/solr PR #4640, 2026-08** — `./gradlew check -x test` passed locally while the PR
sat red. The build states the gap itself, verbatim from its own output:

> `WARNING: errorprone disabled (skipped on builds not running inside CI environments,
> pass -Pvalidation.errorprone=true to enable)`

Under CI's `-Werror` the skipped rule became a hard failure —
`error: warnings found and -Werror specified` → `compileTestJava FAILED` — taking
`gradle check`, `Run SolrJ Tests` and the Crave run red with it, on a
`[UnnecessarilyFullyQualified]` warning the local build never computed.

**The rule-vs-instance half, same PR.** The reviewer quoted one fully-qualified name. It
was fixed, the build recompiled clean *without* errorprone, and "clean" was reported —
while **four more instances of the same rule** in a second file were still failing. Only
`-Pvalidation.errorprone=true` surfaced them. A diff-wide grep for the pattern would have
found all five the first time.

## Lifecycle

- **Signals it worked:** CI's first run on a push is green; no reviewer ever sees a red
  check on a PR they have already reviewed.
- **What to log on a misfire:** the project, the validator, and the exact opt-in flag —
  each house names these differently, and the list is the asset. Record it in
  [`LEDGER.md`](../../LEDGER.md).
- **Death criterion:** obsolete for any project whose local default gate equals its CI
  gate; check the build output for a skip notice before assuming that.
- **Relates to:** sibling to obey-the-houses-own-tooling — that one is about *generating*
  artifacts with the house's tools, this one about *validating* with them. Both fail the
  same way: silently, with a green result.

