deploy · tutorial · vps
node --check + Lint: The Gate Every Push Passes
Thirty seconds that prevent midnight pages: syntax check plus zero-warning lint plus smoke curls on every push. The gate setup inside.

The push that passed everything and broke prod
Friday, 6pm. My agent finished the feature: lint clean (it said), tests green (it said), deployed. Saturday morning: checkout 500s on every coupon order. The "lint" it ran was against cached results. The "tests" were the ones it wrote to match its code. Nothing independent ever touched that push.
Saturday morning debugging with coffee going cold, re-running the checks that should have run Friday — and finding the null dereference in ninety seconds flat. The bug was trivial. The missing gate was the whole incident.
Node check lint gate exists because claims are cheap and pushes are expensive: thirty seconds of independent verification stands between "done" and disaster, every single time.
Claimed-green vs gate-green pushes
| Push | Verification | Saturday result |
|---|---|---|
| Agent claims green | Transcript says so | 500s, cold coffee |
| Suite green (agent tests) | Tests match code | Same blind spots, green |
| Gate green (this post) | Independent checks + curls | Quiet weekend |
| CI green (same gate) | Machine re-runs all | Merge-proof confidence |
Three things that Saturday teaches:
- Agents report, gates verify. "Lint clean" in a transcript is a claim about the past;
npm run lintexiting 0 in CI is a fact about the present. Claims decay (code changed after the claim); facts are timestamped. Trust facts with timestamps, especially on Fridays. - Cached results lie fluently. Stale lint caches, skipped test files, watch-mode partial runs — a dozen ways "green" describes last week's code. Fresh processes (
node --checkper touched file, full lint, live curls) cost thirty seconds and describe this week's. Cache is for speed; gates are for truth. - Curls catch what suites structurally miss. The coupon 500 needed a real payload through a live route — no unit test constructed it, because the agent wrote tests to match its assumptions. Three smoke curls (happy, unhappy, health) with real-shaped bodies prove what suites assume. Reality checks beat self-assessments, always.
The done-but-500 post told the war story. This one installs the machinery.
Node check lint gate setup
Thirty seconds, three layers: syntax, standards, smoke — run everywhere pushes originate.
Step 1 — Syntax-check every touched file.
# pre-push hook: only what changed, fresh processes, no cache
for f in $(git diff --cached --name-only | grep '\.js$'); do
node --check "$f" || exit 1
done
# 5 seconds, catches: typos, bracket drift, half-pasted agent outputPer-file node --check is the cheapest possible verification — milliseconds per file, zero config, no excuses. It catches the exact class agents produce most (syntactically plausible fragments) before anything heavier runs. Fast gates run always; slow gates get skipped. Speed is a gate feature, not a luxury.
Step 2 — Lint at zero warnings, no exceptions.
npm run lint # MUST exit 0: zero errors AND zero warnings
# warnings are errors wearing patience — today's ignored warning is tomorrow's incident lineZero-warning policy (not zero-error) is the load-bearing choice: warnings mark code the author already suspects, and suspects reoffend. My Saturday bug sat three lines below an ignored exhaustive-deps warning — related in hindsight, invisible in foresight. Warnings tolerated are standards declined. Decline nothing.
Step 3 — Smoke-curl the changed paths live.
curl -s -X POST localhost:3000/api/order -d '{"coupon":"X",...}' # happy
curl -s -X POST localhost:3000/api/order -d '{"coupon":null}' # unhappy
curl -s localhost:3000/api/health # neighborhood
# all 200s (or designed codes) → push approved. Anything else → fix first.Happy proves the feature, unhappy proves the edges, health proves the neighborhood — three curls, twenty seconds, the incident class of my Saturday eliminated structurally. CI re-runs all three per push (machines don't get tired on Fridays); humans run them pre-push (judgment before automation). Both, always, in that order of trust.
That's the loop — pushes proven before they leave.
The gate ledger since that Saturday
| Pushes (3 months) | Pre-gate era | Gate era |
|---|---|---|
| Saturday incidents | 4 (all "green" pushes) | 0 |
| Gate catches pre-push | — (nothing) | 11 (typos, guards, nulls) |
| Avg gate runtime | 0s (skipped) | ~30s |
| CI red rate | Rare (nothing checked) | Healthy (catches drift) |
| Weekend coffee temperature | Cold | Hot |
Here's what it costs: thirty seconds per push plus the discipline of never --no-verify — roughly an hour monthly across active development. Priced against four ruined Saturdays: the gate costs coffee stays hot, weekends stay weekends, and pushes carry proof instead of promises. Skipped gates feel fast the way skipping seatbelts feels free — until exactly once.
FAQ
Is node check lint gate enough without a full test suite?
It's the floor, not the ceiling: gate (syntax + standards + smoke) catches the incident class, suites catch regressions, adversary tests catch meaning. Solo stacks run gate always, suites per push, adversary cases per PR — layered by cost and value. Gate-only beats suite-only (reality over self-assessment), but layered beats either. Floor first, then furnish.
How do I stop myself from --no-verify on rushed Fridays?
Remove the option: pre-push hooks can't be skipped without deliberate sabotage (--no-verify leaves evidence in reflog habits), and CI re-runs the gate regardless — bypassing locally only delays the red to merge. Design the path of least resistance as the gated path (fast hooks, clear output). Discipline supported by defaults beats discipline versus defaults, every Friday.
Should agents run the gate or should I?
Both, sequentially: agents run it pre-handoff (their transcript pastes output), you (or CI) re-run on receipt. Agent-run catches their typos fast; independent re-run catches their optimism. Never accept pasted green as proof — re-running thirty seconds of commands costs less than reading the transcript's claims. Trust, then verify, then merge.
What belongs in CI versus pre-push hooks?
Speed decides: sub-10s checks (node --check, lint, smoke curls) run both places (instant local feedback, enforced remote truth). Minutes-long suites run CI-only (no local tax). Secrets scanning runs both (leaks can't wait for merge). Fast everywhere, slow centrally, secrets always. The split optimizes for developer patience and repository safety simultaneously.
How do monorepos or large apps keep the gate fast?
Scope to changed files (diff-based checks, affected-package tests) with full runs nightly — per-push cost stays ~30s regardless of repo size. Nightly full runs catch cross-cutting drift the scoped gate structurally misses. Fast per-push plus thorough nightly is the only scaling shape that holds: developers pay seconds, the repo pays nights.
When is skipping the gate actually justified?
Almost never — and "almost" covers active production fires where the gate itself runs slower than the fix deploys (seconds matter, verification follows immediately after). Even then: gate right after landing, before leaving the incident. Skipping is borrowing against the next incident at loan-shark rates. Borrow only mid-fire, repay within the hour.
Keep reading
- Agent Said Done. Checkout 500s. (The 10-Second Check) — the Saturday this gate prevents
- git push production deploy: Skip the 9-Minute CI Queue — the hook this gate lives in
- Mobile AI Guardrails: Couch Fixes That Can't Break Prod — the gate at phone scale
+ all the boring stuff (analytics, auth, SQLite ↔ Supabase, full marketplace, webhooks)
Command from your phone.
Built so autonomous AI agents build what you want without breaking what's already paying you.
- Built-in analytics — cookie-free mode, $0 forever, no PostHog bill
- SQLite ↔ Supabase: one setting, same field names
- Full digital marketplace & feedback boards included
- 3 payment rails: Stripe, LemonSqueezy & Dodo Payments
- Agent fences: lint gate, read-only data access, auto-rollback
- Ship from your phone via SSH & WireGuard/Tailscale in under a minute
$199
Get BoringPushOne-time payment · Lifetime updates · Unlimited projects.
Keep reading


