Rebuilding the stylesheet produces a diff nothing can read #159

Closed
opened 2026-09-09 16:58:20 +00:00 by tiagoagueda · 1 comment
Owner

Observation

Any rebuild of the stylesheet produces a diff that cannot be read, reviewed, or in some
tools even printed. Reported from a terminal that stopped part way through it.

What exists

src/postulo/static/css/app.css is a build artefact that is committed, and Tailwind
writes it minified — one line of roughly a hundred kilobytes. Committing it is
deliberate and stated in docker/Dockerfile:

the compiled CSS is committed to the repository as well, but building it here means the
image is right even if somebody forgot to rebuild before committing

That decision is fine. What follows from it is not: because the file is a single line, every
npm run build:css produces a diff of exactly two lines — one removed, one added — each
about 100 kB wide. Git cannot show it usefully, a terminal wraps it into thousands of rows,
a review tool truncates it, and a pager can stall on it. git add -p is unusable. So is any
attempt to see what actually changed in the stylesheet, which is occasionally a real
question: a Tailwind upgrade silently changing a base rule is exactly the sort of thing a
diff should catch.

It is reproducible on demand: change any template class and rebuild.

What this asks for

A rebuild that does not produce an unreadable diff, without giving up the reason the file is
committed.

Worth being careful about

The smallest fix is .gitattributes, and it is honest. The file is generated; the
source of truth is assets/ and the templates. Marking it so tells every tool the truth:

src/postulo/static/css/app.css -diff linguist-generated=true

Git then reports "Binary files differ" instead of printing it, GitHub-style forges collapse
it, and git add -p skips it. Nothing about the build changes and the file still ships.
What it costs is the ability to read the diff at all — which is currently not available
anyway, so the trade is a real improvement rather than a loss.

Not minifying the committed copy is the other half, and it is worth weighing. Written
expanded, the file becomes a readable diff: a Tailwind upgrade that changes a base rule
shows as a handful of lines rather than as an opaque blob. It costs repository size and adds
a step, because what ships should still be minified — WhiteNoise already compresses what it
serves, so the minification may be redundant at that point. This is the one to think
about
: it is the difference between "the diff is hidden" and "the diff is useful", and the
project already treats a stylesheet as something a person should be able to reason about.

A hook that rebuilds it would make this worse. pre-commit regenerating the file on
every commit turns an occasional unreadable diff into one on every commit. Whatever is done
here should not add that.

Whatever is chosen has to keep the image correct. The Dockerfile's argument stands: the
image builds the stylesheet itself so that a forgotten rebuild cannot ship a stale one. Any
change that makes the committed copy optional must not make the image's copy optional.

And a test would notice a stale one. There is currently nothing that says the committed
stylesheet matches what the sources would produce. That is a separate small thing worth
having whichever way this goes, and it is what makes "the committed file is generated" safe
to assert.

Classification

Bug, in the sense the contributor experience is broken rather than the application. It costs
nothing to nobody using Postulo, and costs an unreadable diff to everybody working on it.

## Observation Any rebuild of the stylesheet produces a diff that cannot be read, reviewed, or in some tools even printed. Reported from a terminal that stopped part way through it. ## What exists `src/postulo/static/css/app.css` is a build artefact that is **committed**, and Tailwind writes it **minified** — one line of roughly a hundred kilobytes. Committing it is deliberate and stated in `docker/Dockerfile`: > the compiled CSS is committed to the repository as well, but building it here means the > image is right even if somebody forgot to rebuild before committing That decision is fine. What follows from it is not: because the file is a single line, every `npm run build:css` produces a diff of exactly two lines — one removed, one added — each about 100 kB wide. Git cannot show it usefully, a terminal wraps it into thousands of rows, a review tool truncates it, and a pager can stall on it. `git add -p` is unusable. So is any attempt to see *what actually changed* in the stylesheet, which is occasionally a real question: a Tailwind upgrade silently changing a base rule is exactly the sort of thing a diff should catch. It is reproducible on demand: change any template class and rebuild. ## What this asks for A rebuild that does not produce an unreadable diff, without giving up the reason the file is committed. ## Worth being careful about **The smallest fix is `.gitattributes`, and it is honest.** The file *is* generated; the source of truth is `assets/` and the templates. Marking it so tells every tool the truth: ``` src/postulo/static/css/app.css -diff linguist-generated=true ``` Git then reports "Binary files differ" instead of printing it, GitHub-style forges collapse it, and `git add -p` skips it. Nothing about the build changes and the file still ships. What it costs is the ability to read the diff at all — which is currently not available anyway, so the trade is a real improvement rather than a loss. **Not minifying the committed copy is the other half, and it is worth weighing.** Written expanded, the file becomes a readable diff: a Tailwind upgrade that changes a base rule shows as a handful of lines rather than as an opaque blob. It costs repository size and adds a step, because what ships should still be minified — WhiteNoise already compresses what it serves, so the minification may be redundant at that point. **This is the one to think about**: it is the difference between "the diff is hidden" and "the diff is useful", and the project already treats a stylesheet as something a person should be able to reason about. **A hook that rebuilds it would make this worse.** `pre-commit` regenerating the file on every commit turns an occasional unreadable diff into one on every commit. Whatever is done here should not add that. **Whatever is chosen has to keep the image correct.** The Dockerfile's argument stands: the image builds the stylesheet itself so that a forgotten rebuild cannot ship a stale one. Any change that makes the committed copy optional must not make the image's copy optional. **And a test would notice a stale one.** There is currently nothing that says the committed stylesheet matches what the sources would produce. That is a separate small thing worth having whichever way this goes, and it is what makes "the committed file is generated" safe to assert. ## Classification Bug, in the sense the contributor experience is broken rather than the application. It costs nothing to nobody using Postulo, and costs an unreadable diff to everybody working on it.
tiagoagueda added this to the 0.3.0 milestone 2026-09-09 16:58:20 +00:00
Author
Owner

The issue named the decision — hide the diff, or make it worth reading — and said which one
to think about. Made it useful.

The cost was measured, not argued. 76 kB minified is 10,225 bytes gzipped; 91 kB
expanded is 11,044. WhiteNoise compresses what it serves, so the entire value of
minification is 819 bytes of an 11 kB response, once, before the hashed filename is
cached forever. That is eight per cent of one response against a stylesheet nobody could
read a diff of.

-diff would have answered the wrong half. It is honest — the file is generated — but
the choice was never between a readable diff and a hidden one. It was between a hidden one
and an unreadable one, and the issue put the real question well: "a Tailwind upgrade
silently changing a base rule is exactly the sort of thing a diff should catch."
So
.gitattributes says linguist-generated=true and not -diff: a forge collapses it by
default, and anybody who wants to look still can. 2 lines became 3,029.

The four warnings

The image stays correct. It runs the same npm run build:css, so its copy and the
committed one are byte for byte the same file. The Dockerfile's argument is untouched and
now carries the reason for the flag that is missing.

No hook rebuilds it. None added, and the issue's warning is worth keeping: a pre-commit
that regenerated the file would turn an occasional diff into one on every commit.

A stale one is still caught. CI already rebuilds and runs git diff --exit-code on it —
with the real toolchain, which is stronger than anything a Python test could assert. It
needed no change.

And it stays readable. tests/test_static.py fails if app.css comes back as one line
or grows a line too wide to review — the guard against somebody restoring --minify for the
obvious-looking reason without the measurement.

Shipped in 29e2b7c on 0.3.0, with main kept level. Thanks for the report — the diff
that broke your terminal is in that commit, and it is the last one of its kind.

The issue named the decision — hide the diff, or make it worth reading — and said which one to think about. Made it useful. **The cost was measured, not argued.** 76 kB minified is **10,225 bytes** gzipped; 91 kB expanded is **11,044**. WhiteNoise compresses what it serves, so the entire value of minification is **819 bytes of an 11 kB response**, once, before the hashed filename is cached forever. That is eight per cent of one response against a stylesheet nobody could read a diff of. **`-diff` would have answered the wrong half.** It is honest — the file *is* generated — but the choice was never between a readable diff and a hidden one. It was between a hidden one and an unreadable one, and the issue put the real question well: *"a Tailwind upgrade silently changing a base rule is exactly the sort of thing a diff should catch."* So `.gitattributes` says `linguist-generated=true` and **not** `-diff`: a forge collapses it by default, and anybody who wants to look still can. 2 lines became 3,029. ## The four warnings **The image stays correct.** It runs the same `npm run build:css`, so its copy and the committed one are byte for byte the same file. The Dockerfile's argument is untouched and now carries the reason for the flag that is missing. **No hook rebuilds it.** None added, and the issue's warning is worth keeping: a `pre-commit` that regenerated the file would turn an occasional diff into one on every commit. **A stale one is still caught.** CI already rebuilds and runs `git diff --exit-code` on it — with the real toolchain, which is stronger than anything a Python test could assert. It needed no change. **And it stays readable.** `tests/test_static.py` fails if `app.css` comes back as one line or grows a line too wide to review — the guard against somebody restoring `--minify` for the obvious-looking reason without the measurement. Shipped in `29e2b7c` on `0.3.0`, with `main` kept level. Thanks for the report — the diff that broke your terminal is in that commit, and it is the last one of its kind.
Sign in to join this conversation.
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
Postulo/postulo#159
No description provided.