Joshua Shay Kricheli NeuroSymbolic AI
v2 v1

Release · v3.14.31

Stop building the site twice, and stop Netlify…

perf(ci): stop building the site twice, and stop Netlify building nothing

perf v3.14.31 August 18, 2026 Joshua Shay Kricheli 172552c

Details

Measured first, because the headline number was misleading. A pull request's
GitHub checks finish in **1m29s** wall clock, not seven minutes:
  Build site + TypeScript   0.9 min      Verify Python (uv)      0.3 min
  Links + analytics         1.4 min      Verify Supabase REST    0.1 min
The seven minutes is Netlify's deploy preview (~8 min on recent PRs). It is not
a required check, so it never blocked a merge — but it is what the PR page shows
pending, and it was doing a full build for changes that cannot alter the site.
## The site was being built twice
`links-and-analytics` looked like parallelism and was not: it rebuilt the same
tree the build job had just built — 41s in one job, 48s in the other, for one
artifact — and because it started from scratch it finished last and set the
wall-clock for the whole run. Its actual work is 24s (Chrome 14s, crawl 10s).
Folded into the build job, which now builds once and then checks what it built.
## Netlify: skip builds that cannot change the output
`ignore` now compares the commit range and skips when nothing outside
`.github/`, `.claude/`, `backend/supabase_db/`, `test/` and `*.md` changed. A
workflow or docs change was costing a full build: unshallowing 200 MB of
history, `bundle install`, `pnpm install`, then generating 925 change-log pages
to produce output identical to the last deploy.
Across the last 39 merges to `main`, **7 would now skip**. It stays deliberately
conservative — `package.json` and anything under `tools/` still trigger a build,
because both can change what Jekyll emits — and any case it cannot judge
(no cached ref) builds.
## Netlify: fetch the history without the blobs
The change log is a pure function of the whole history, so the shallow clone has
to be deepened — but `readHistory` only ever runs `git log` over commit
metadata, never reading a file at an old revision. `--filter=blob:none` fetches
the commits and trees and leaves ~200 MB of blobs behind, with the plain
`--unshallow` kept as the next fallback.
Flagged honestly: this one is NOT measured. The local `file://` transport
ignores partial-clone filters, so the size was identical in a local test; GitHub
supports them, and if the filter is ever refused the fallback makes it a no-op.
Branch protection updated in the same breath: `Links + analytics` is no longer a
check name, and a required check that never reports blocks a pull request
forever.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DAJJ63FFnLoD5XLpu6yJaG

Files changed (2)

.github/workflows/pr-validation.yml +9 −19
netlify.toml +21 −2