fix(ci): pin Tailwind scan scope so prose can't break the CSS drift check #4

Merged
crueber merged 1 commit from fix/pin-tailwind-scan-scope into main 2026-08-29 20:54:23 +00:00
Owner

What broke

After merging #3, CI failed on the new Verify compiled CSS is up to date step: a fresh tailwindcss build emitted an .invisible utility that the committed passage.css didn't contain. The drift check did its job — the committed CSS genuinely didn't match a fresh build.

Root cause

Tailwind v4's automatic source detection scans every non-ignored file in the repo — including markdown. My docs edit in ef1c991 added the word "invisible" to AGENTS.md ("this is invisible at compile time"); candidate extraction turned that prose word into a utility, and every future docs edit would risk the same. Editing docs without thinking to rebuild CSS is exactly the trap this step can't tolerate.

Fix

  • input.css: @import "tailwindcss" source(none); + explicit @source lines — only internal/web/templates/ and the two JS files are scanned. Prose can no longer generate CSS, in any file, ever.
  • Rebuilt passage.css: drops 11 prose-generated utilities (absolute, fixed, relative, transition, …). Verified none are used in any template (scripted intersection of template class attributes vs the dropped set).
  • AGENTS.md: documents the pinned scan scope and the rule to register new class-bearing files.

Verification

  • Build is deterministic (two consecutive builds byte-identical)
  • ./tools/build-css.sh && git diff --exit-code internal/web/static/passage.css passes — the exact CI step
  • go test -race ./internal/web green
## What broke After merging #3, CI failed on the new `Verify compiled CSS is up to date` step: a fresh `tailwindcss` build emitted an `.invisible` utility that the committed `passage.css` didn't contain. The drift check did its job — the committed CSS genuinely didn't match a fresh build. ## Root cause Tailwind v4's **automatic source detection scans every non-ignored file in the repo — including markdown**. My docs edit in ef1c991 added the word *"invisible"* to AGENTS.md ("this is invisible at compile time"); candidate extraction turned that prose word into a utility, and every future docs edit would risk the same. Editing docs without thinking to rebuild CSS is exactly the trap this step can't tolerate. ## Fix - `input.css`: `@import "tailwindcss" source(none);` + explicit `@source` lines — only `internal/web/templates/` and the two JS files are scanned. Prose can no longer generate CSS, in any file, ever. - Rebuilt `passage.css`: drops 11 prose-generated utilities (`absolute`, `fixed`, `relative`, `transition`, …). **Verified none are used in any template** (scripted intersection of template class attributes vs the dropped set). - AGENTS.md: documents the pinned scan scope and the rule to register new class-bearing files. ## Verification - Build is deterministic (two consecutive builds byte-identical) - `./tools/build-css.sh && git diff --exit-code internal/web/static/passage.css` passes — the exact CI step - `go test -race ./internal/web` green
Tailwind v4's automatic source detection scans every non-ignored file in
the repo, including markdown — a docs edit that used the word 'invisible'
made a fresh build emit an .invisible utility, so the committed
passage.css no longer matched and the CI drift step failed the build
after merge.

- input.css: @import "tailwindcss" source(none) + explicit @source for
  templates/ and the two JS files; rebuild passage.css (drops 11
  prose-generated utilities, none used in templates — verified)
- AGENTS.md: document the pinned scan scope and the rebuild-after-any-
  candidate-change rule
crueber deleted branch fix/pin-tailwind-scan-scope 2026-08-30 14:34:00 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
crueber/passage!4
No description provided.