has this ever happened to YOU?
you have merged some new PRs for tranquil and rebuilt it on your nixos system. these include some changes for the frontend account manager
you tried to re-login to the account manager to check things out but you just saw a blank page??
(clearing your cache will fix it, for reasons explained below)
curl -sI https://ao.oyster.cafe/app/dashboard
HTTP/2 200
accept-ranges: bytes
alt-svc: h3=":443"; ma=2592000
content-type: text/html
date: Wed, 07 Oct 2026 19:28:48 GMT
last-modified: Thu, 01 Jan 1970 00:00:01 GMT
via: 1.1 Caddy
content-length: 579
this is caused by something nix and others do to attain reproducible builds. instead of using mtime (modification time) with actual datetimestamps, it uses unix epoch, to make sure builds built at different real-world timestamps still have the same bytes for the package.
this results in the Last-Modified header showing an inaccurate timestamp. we also dont ship any Cache-Control header, so the timestamp alone gets used by browsers to determine how long to cache the page. they make the assumption that a webpage from ~56 years ago likely doesn't change very often and might decide to cache it for years.
when the underlying pages have changed, but the browser still thinks its cache is valid, the frontend can break!
two things can help fix this behavior:
- supplying
Cache-Control: no-cache, which asks clients to always check upstream for changes - supplying an ETag, allowing clients to compare its value with upstream instead of the
Last-Modifieddate
when a client checks upstream for changes, even under no-cache, it has an opportunity to be told 304: Not Modified and keep the local copy:
curl -sI -H 'If-Modified-Since: Thu, 01 Jan 1970 00:00:01 GMT' https://ao.oyster.cafe/app/dashboard
HTTP/2 304
alt-svc: h3=":443"; ma=2592000
date: Wed, 07 Oct 2026 20:14:19 GMT
via: 1.1 Caddy
by default it compares the unix epoch Last-Modified fields which never change and always 304s. we can instead have tranquil generate unique identifiers based on the content of the resource (SHA-256). we will have clients use these "entity tags" instead of the Last-Modified header
effectively, this makes sure that clients are always asking upstream if it's updated, and re-fetching when (and only when) it has changed
etagged routes:
- /
- /app/*
- /index.html
- /homepage.html
hashed assets provide public, max-age=31536000, immutable for 2xx/304 responses, as they are uniquely hashed by name already. 404s do not get cached
bonus: token responses and PAR now provide no-store and no-cache. clients were likely not caching these anyway but this puts us in compliance with RFC 6749 5.1 and mirrors the examples on RFC 9126 2.2
placing nginx/caddy/cloudflare in front of tranquil should be compatible with these tags. if for example using compression in caddy, the etag headers get the compression appended to them, like -gzip. I believe nginx and cloudflrae downgrades the etags to "weak validation" in this scenario.
two-thirds of this pr is just tests that enshrine this behavior in the new frontend.rs module