carlos / platform Public

Static routes send no Cache-Control or ETag — returning visitors get stale pages, and mixed stale HTML/CSS breaks the render Issue open

Migrated from github.com/carlosframework/platform issue #234, opened 2026-08-19. GitHub issues are closed for this repo; see AGENTS.md, "Work is tracked on amadan, not GitHub".

Still outstanding: Static routes send no Cache-Control or ETag, so returning visitors get stale pages and mixed asset versions.

---

What

Static routes serve only Last-Modified. No Cache-Control, no ETag.

$ curl -sI https://carlosframework.com/
last-modified: Wed, 19 Aug 2026 13:20:59 GMT
x-carlos-version: 89a5864

$ curl -sI https://carlosframework.com/site.css
last-modified: Wed, 19 Aug 2026 13:20:59 GMT
x-carlos-version: 89a5864

With no Cache-Control, browsers apply heuristic caching — commonly ~10% of the elapsed time since Last-Modified. For a page that had not changed in weeks, that is days of staleness for a returning visitor.

Why it matters more than "stale content"

Assets expire independently. Observed on carlosframework.com within minutes of the redesign deploy (afe6833 → 89a5864), in a real browser:

  1. One view served the entire old page — old markup, old stylesheet. Looked like the deploy never happened.
  2. Another served the new HTML against the old cached site.css. That is the damaging one: the page rendered with the retired serif, and the new inline-SVG wordmark — which the new stylesheet sizes and strokes — rendered as a row of giant black shapes across the top of the page.

So the failure mode is not "a visitor sees yesterday's copy". It is "a visitor sees a broken page", and neither the operator nor X-Carlos-Version shows it, because the server is serving the right bytes.

This also silently undercuts the "convergence is seconds" story: a promote reaches the edge in ~2s and then waits days in the visitor's browser.

Suggested shape

Content-addressed releases make this easy to get right:

  • HTML (and anything without a fingerprint): Cache-Control: no-cache — revalidate every time. Cheap, because an ETag/If-None-Match pair makes the common case a 304.
  • Fingerprinted assets, if/when static ships them: Cache-Control: public, max-age=31536000, immutable.
  • Emit a strong ETag for every static object. The release is content-addressed already, so the digest is in hand — this is close to free.

A sensible default of no-cache + ETag for all static objects would fix the reported breakage on its own, and a per-app or per-route override could come later if anyone needs long max-age.

Workaround in place meanwhile

carlosframework/website now (a) gives every inline SVG width/height/fill/stroke as presentation attributes so a stale stylesheet degrades to a sane outline rather than a black blob, and (b) links the stylesheet as site.css?v=<sha>, bumped at deploy. Both are documented in that repo's CLAUDE.md as workarounds for this issue. Neither helps a visitor whose HTML is stale — only the server can fix that case.