Preflight Checks Prevent Push-then-Fix Cycles

Running the same lint, format, and test checks locally before pushing catches failures that would otherwise require a push-fix-push cycle through CI. The cost of a local preflight is seconds; the cost of a CI round-trip is minutes plus noise (failed build notifications, red badges, extra commits). A...

Tags

Preflight Checks Prevent Push-then-Fix Cycles

The Lesson

Running the same lint, format, and test checks locally before pushing catches failures that would otherwise require a push-fix-push cycle through CI. The cost of a local preflight is seconds; the cost of a CI round-trip is minutes plus noise (failed build notifications, red badges, extra commits). A preflight gate between commit and push eliminates the most common CI failure patterns.

Context

A project with Python (ruff for lint/format, pytest for tests) and Node.js (Astro build) had CI workflows that ran ruff check, ruff format --check, pytest, and npm run build. After completing the implementation and committing the XSS fix, a push was prepared. The push workflow included a preflight step that ran the same checks CI would run, locally, before authorizing the push.

What Happened

  1. The XSS fix was committed and the push workflow began. Before pushing, the preflight skill ran 7 gates: Python lint, Python format, Node lint, Python tests, Node tests, CI script existence, and build smoke test.
  2. Gate 1b (Python format) failed: ruff format --check reported 2 files would be reformatted — backend/app/adapters/vector/chromadb.py and backend/app/rag/generator.py.
  3. These files had been written during Phase 5 and never reformatted. They passed ruff check (lint) but not ruff format --check (formatting). The CI workflow ran both, so this would have been a CI failure.
  4. The fix was immediate: ruff format on the two files, commit the formatting fix, re-run preflight. All 7 gates passed on the second run.
  5. Without the preflight gate, the sequence would have been: push → CI fails on format check → read CI logs → run format locally → commit fix → push again. Two pushes, two CI runs, one wasted round-trip.
  6. The preflight completed in under 5 seconds. A CI round-trip on this project takes approximately 50 seconds (build job) plus GitHub Actions queue time.

Key Insights

Examples

Preflight output showing failure:

Gate 1: Python lint/format ........... FAIL
  Would reformat: backend/app/adapters/vector/chromadb.py
  Would reformat: backend/app/rag/generator.py
  2 files would be reformatted, 25 files already formatted

Result: FAIL (1 failure, 0 warnings)

Preflight output after fix:

Gate 1: Python lint/format ........... PASS
Gate 3: Python tests ................. PASS (39 passed)
Gate 7: Build smoke test ............. PASS

Result: PASS (0 failures, 0 warnings)

Applicability

This applies to any project with CI checks that can be run locally. It's most valuable when CI is slow (queue times, large test suites) or when the team has a pattern of "fix CI" commits. It does NOT replace CI — CI runs in a clean environment and catches environment-specific issues (missing dependencies, OS differences). Preflight catches the 80% of CI failures that are purely local mistakes.

Related Lessons

Related Lessons