Skip to content

Cache the production compile's pages CSS on main - #8312

Merged
gianfrancopiana merged 1 commit into
mainfrom
gianfranco/main-pages-tailwind-cache
Oct 10, 2026
Merged

gianfrancopiana merged 1 commit into
mainfrom
gianfranco/main-pages-tailwind-cache

Conversation

@gianfrancopiana

Copy link
Copy Markdown
Member

What

On a main asset cache miss, the production compile unpacks the pages CSS from a cache instead of building it.

  • A new script, .buildkite/scripts/main_pages_tailwind_cache.sh, keys the pages CSS on its build script, its CSS input, lib/tasks/pages_tailwind.rake, the package files, docker/base and docker/web/compile_assets.sh.
  • The production path downloads the tarball and verifies its checksum, with the same helpers as the node_modules cache (Cache the production compile's node_modules on main #8311).
  • make build_production mounts the tarball into the compile container. docker/web/compile_assets.sh unpacks it and sets PAGES_TAILWIND_RESTORED, so pages_tailwind:build skips the Tailwind build.
  • After a build that the cache lacked, the container writes a new tarball of the four output files. Only a main build creates and uploads it.
  • comp-assets-* builds read the cache and never write it. Staging and preview builds mount nothing and build as before.
  • A [no-cache] commit builds the CSS and replaces the entry.
  • The cache directory is removed when the build exits, also after a failed compile.

Why

About half of main deploys miss the main asset cache and compile from scratch. On a miss, the pages Tailwind build takes 73–76 s, although its output never changes with app code: scripts/build_pages_tailwind.mjs builds a fixed class list, and its CSS input sets source(none). PR CI already caches the same files on the same inputs (#8298).

With the node_modules cache, this removes the two steps of a compile miss that do not depend on the change being deployed.

Before/After

This changes the production build only. Nothing changes for users.

  • Before: every compile on a cache miss builds the pages CSS (73–76 s).
  • After: a compile on a cache miss unpacks the cached pages CSS, unless its inputs changed.

Test results

  • bash .buildkite/scripts/main_asset_cache_compile_test.sh: 58 pass. New cases:

    • a verified hit is in place for make, and a tarball that fails its checksum is not used;
    • a main miss saves the tarball and its checksum, and a comp-assets-* miss saves nothing;
    • a [no-cache] commit builds the CSS and replaces the entry;
    • the cache directory is removed after the compile, also when the compile fails.
  • The same test runs the real make build_production and the real docker/web/compile_assets.sh against a stub docker, with a real tarball:

    • a mounted tarball is unpacked before assets:precompile, the restored flag skips the build, and nothing is written back;
    • a main build writes the four output files to pages_tailwind.tar.gz.new;
    • a comp-assets-* build creates no archive, and a failed archive write leaves no partial file.

    Each piece of the change, removed on its own, makes at least one case fail.

  • bundle exec rspec spec/lib/tasks/pages_tailwind_spec.rb: 2 pass. Without the skip in the rake task, the restored case fails.

  • bundle exec rubocop and shellcheck -S warning: no new offenses.

  • A real Buildkite production compile of this branch (build 25596, on a comp-assets-* branch, no deploy) passed in 6.2 min:

    • make build_production mounted both cache directories into the compile container;
    • with no tarball there, npm run build:pages-tailwind ran, in 75.9 s;
    • the image pushed as usual, with no tar, gzip, checksum, S3 or Rake error.

    That build cannot test a restore, because only main writes entries. The first main compile after the merge fills the cache, and the next miss restores it. Both log their result.


AI disclosure: Claude Opus 5.5.

The pages CSS is a fixed class list, so app code and views never change
it, yet every compile that missed the main asset cache rebuilt it, about
73 s. Main now saves the built files to S3, keyed on the build script,
its CSS input, the lockfile and the Node image. A compile with a verified
entry unpacks it and skips pages_tailwind:build.
@gianfrancopiana gianfrancopiana self-assigned this Oct 10, 2026
@greptile-apps

greptile-apps Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 5/5

[High impact] The PR appears safe to merge; no actionable issue was found.

Summary

This PR lets production asset builds reuse cached pages CSS instead of rebuilding it.

  • Production compiles reuse cached pages CSS when its inputs match.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Production asset cache miss] --> B{no-cache commit?}
  B -->|No| C{Pages CSS archive verifies?}
  B -->|Yes| E[Build pages CSS]
  C -->|Yes| D[Unpack CSS and skip pages build]
  C -->|No| E
  D --> F[Finish assets precompile]
  E --> F
  F --> G{Main built fresh CSS?}
  G -->|Yes| H[Save archive and checksum]
  G -->|No| I[Keep cache unchanged]
  H --> J[Remove local cache directories on exit]
  I --> J
Loading

Reviews (1) · Last reviewed commit: "Cache the production compile's pages CSS..." · Reviewed by Greptile

@gumclaw gumclaw added the run-all-specs Run the full Fast/Slow test suite on this PR instead of the trimmed Test Relevant set label Oct 10, 2026
@gumclaw

gumclaw commented Oct 10, 2026

Copy link
Copy Markdown
Contributor

bin/branch-specs escalated this diff (build/docker/cache scripts cannot be mapped to a spec subset), so the push run's Test Relevant step exits with "add the run-all-specs label"; added the label and re-ran the Tests run so it takes the full Fast/Slow suite.

gianfrancopiana added a commit that referenced this pull request Oct 10, 2026
## What

`bin/branch-specs` now maps a changed `lib/tasks/NAME.rake` to
`spec/lib/tasks/NAME_spec.rb` when that spec exists. The `lib/` name
mapping now matches `.rake` files and `.rb` files. A rake task without a
spec still escalates as a mapping gap.

## Why

The Test Relevant jobs use `bin/branch-specs` to select specs for a PR.
The `lib/` name mapping matched only `.rb` files, and content
attribution also matches only `.rb` files. A change to a rake task
therefore escalated to the full suite, even when the rake task has its
own spec.

#8312 shows this. The selector reported `lib/tasks/pages_tailwind.rake`
as a mapping gap, but the branch has a spec for that rake task. The
`Makefile` on that PR escalates correctly, and this change keeps that
behavior.

Rake task specs in this repo already use the `lib/tasks/NAME.rake` to
`spec/lib/tasks/NAME_spec.rb` layout. Examples are `taxonomy`,
`preview_qa`, and `db_schema_parity`.

## Before/After

This change affects CI test selection only. Users see no change.

- Before: a change to `lib/tasks/taxonomy.rake` escalates with "mapping
gap".
- After: the same change selects `spec/lib/tasks/taxonomy_spec.rb`.
- Before and after: a change to a rake task without a spec escalates
with "mapping gap".

## Test results

- `ruby spec/bin/branch_specs_test.rb`: 179 checks passed.
- Without the change to `bin/branch-specs`, the new case "rake task maps
to its spec/lib/tasks spec" fails with exit 3 (mapping gap).
- `bundle exec rubocop bin/branch-specs spec/bin/branch_specs_test.rb`:
no offenses.

---

AI disclosure: Claude Opus 5.5.

Co-authored-by: Gianfranco Piana <gianfrancopiana@users.noreply.github.com>
@gianfrancopiana
gianfrancopiana marked this pull request as ready for review October 10, 2026 18:03
@gianfrancopiana
gianfrancopiana merged commit ecdd0fe into main Oct 10, 2026
149 of 173 checks passed
@gianfrancopiana
gianfrancopiana deleted the gianfranco/main-pages-tailwind-cache branch October 10, 2026 18:03
gianfrancopiana added a commit that referenced this pull request Oct 10, 2026
## What

Add regression checks that the pages CSS cache tag changes when its
build script, CSS input, package lock, or rake task changes.

## Why

PR #8312 added the pages CSS cache. Its tests covered restore and save
behavior, but did not prove that representative build inputs invalidate
the cache key.

## Before/After

Before: cache-key input changes had no direct regression coverage.

After: the shell harness checks each representative input independently
and confirms unrelated changes keep the key stable.

## Test Results

- `bash .buildkite/scripts/main_asset_cache_compile_test.sh` — 63
passed, 0 failed
- Mutation controls — removing each tested input from the key produced
its intended failure
- `bin/test-confidence --strict` — no tests selected because the diff
only changes the shell harness
- Private Claude Sonnet 5.5 high-effort review — clean

## QA

No manual QA needed. This is test-only coverage for the existing cache
key.

---

Implemented with Claude Sonnet 5.5.

This branch was successfully deployed

1 active deployment
preview/gianfranco-main-pages-tai-4ca864 — 79eb9dc9 Deployed Oct 10, 2026 by gumroad-buildkite
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

run-all-specs Run the full Fast/Slow test suite on this PR instead of the trimmed Test Relevant set

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants