"""The cache-busting token in index.html must be bumped when CSS/JS changes.
Root cause of a real 2026-09-14 report ("this still looks the same",
"78 is still not up"). The Space serves /static/*.css with
`cache-control: public, max-age=31536000` — a full YEAR — and the HTML
references the assets with `?v=` query strings for cache busting.
The `20260912-paddle` token stayed static through four subsequent PRs
(#76, #77, #78, #79). Every browser that had loaded the app any time
after the Paddle release was serving the CSS/JS from cache regardless of
what shipped — no way to see the fixes without a manual hard refresh
that most users won't ever perform.
Two things pinned here:
1) EVERY versioned reference in index.html uses the SAME token — a
mixed set is the classic partial-refresh bug (new CSS against old
JS, or vice-versa, which reads on screen as broken selectors).
2) The token must not still be `20260912-paddle`, so this PR's bump
doesn't get quietly undone. Future PRs that change any static
asset get an obvious failing test to nudge them into bumping.
"""
import pathlib
import re
def _read(rel):
return pathlib.Path(rel).read_text(encoding="utf-8")
def _tokens_in_index():
html = _read("dee/static/index.html")
return sorted(set(re.findall(r"\.(?:css|js)\?v=([A-Za-z0-9_.-]+)", html)))
def test_index_html_uses_one_cache_busting_token_everywhere():
"""A mixed set is the classic 'new CSS against old JS' partial-refresh
bug. One token — everything invalidates together, or nothing does."""
tokens = _tokens_in_index()
assert tokens, "no ?v= cache-busting tokens in index.html — that would " \
"make every CSS/JS change invisible until manual reload"
assert len(tokens) == 1, (
"index.html carries multiple ?v= tokens: " + ", ".join(tokens) +
". They MUST match; a mix ships new CSS against old JS or vice-versa"
)
def test_the_cache_token_isnt_the_2026_09_12_stale_one():
"""A specific regression guard for THIS PR. The Paddle-release token
stayed static through #76-#79, so users never picked up any of those
fixes without manually clearing cache. Any future PR that changes a
static asset and forgets to bump the token gets a red test."""
tokens = _tokens_in_index()
assert tokens
assert tokens[0] != "20260912-paddle", (
"the cache token is the stale 2026-09-12 Paddle-release value. "
"Bump it — otherwise browsers keep serving month-old CSS and JS "
"against the current server (cache-control: max-age=31536000)."
)