"""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)." )