Repository navigation
deploy: no-cache index.html/sw.js/version.json under /sundial/ (fixes #37) - #39
Merged
Merged
Conversation
The /sundial/ coexistence config served none of the cache-control rules data/nginx.conf carries, so the entry point, service worker and version probe fell back to heuristic browser caching. Tapping "update" just calls location.reload(), which on Firefox Android home-screen installs can be satisfied from the browser cache — reloading the old version (#37). Mirror data/nginx.conf's no-cache block, nested inside location /sundial/ so expires -1 applies while the block inherits the subpath's security add_header set (nginx drops inherited add_header only from a block that sets its own). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Static assertion (same style as csp.test.js) that data/nginx.conf and deploy/nginx-sundial.conf both no-cache index.html, sw.js and version.json, and that the deploy block stays nested under /sundial/ without its own add_header so the security headers keep being inherited. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Record in deploy/README.md and agents.md that nginx-sundial.conf now no-caches the three update-critical files, why it is nested, and that tests/unit/nginx-cache.test.js enforces it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The nesting check used textual ordering, so a no-cache block moved out to the server level (which would inherit no add_header and silently drop the security headers for the three files) still passed. Match braces to assert the block sits inside location /sundial/. Also guard data/nginx.conf's root no-cache block against setting its own add_header, the same regression class. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Locate the /sundial/ block with a whitespace-tolerant regex instead of an exact string, match NO_CACHE_BLOCK once (reuse .index + body) instead of twice, and note what the \. escaping in the matcher means. No behaviour change; the nesting mutation is still caught. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Fixes #37. The
/sundial/coexistence config (deploy/nginx-sundial.conf, the path added to the Android home screen) carried none of theCache-Control: no-cacherules thatdata/nginx.confships forindex.html,sw.jsandversion.json. Those files fell back to default nginx headers and heuristic browser caching, so the PWA "update" button'slocation.reload()could be satisfied from the browser's own cache on Firefox Android — reloading the old version.The fix mirrors
data/nginx.conf's no-cache block, nested insidelocation /sundial/soexpires -1applies while the block still inherits the subpath's securityadd_headerset (nginx drops inheritedadd_headeronly from a block that declares its own — the nested block declares onlyexpires).Verification
Beyond the suite, I ran a real
nginx:alpinewith this config over the repo files and confirmed viacurl -D-:/sundial/{index.html,sw.js,version.json}→Cache-Control: no-cacheand all four security headers (CSP, X-Frame-Options, nosniff, Referrer-Policy) present (inheritance works)./sundial/js/main.jsand other assets → no forced no-cache (unchanged), headers still present./sundial/and SPA fallback routes → resolve toindex.htmland inherit the no-cache rule.nginx -tpasses on bothdeploy/nginx-sundial.confanddata/nginx.conf.Full suite green locally: unit 89/89 (incl. 3 new), e2e 45/45,
check_i18n.pyclean.A new
tests/unit/nginx-cache.test.js(sibling-style tocsp.test.js) locks in: both confs no-cache the exact three files withexpires -1; neither no-cache block sets its ownadd_header; and the deploy block is brace-nested insidelocation /sundial/(not merely textually after it).Scope
Per the issue, cache-busted asset filenames are a deliberate out-of-scope follow-up and are not included.
Out-of-scope observations (pre-existing, NOT fixed here — flagged for a human)
While reviewing, two pre-existing gaps surfaced that affect PWA correctness under
/sundial/but are unrelated to this caching bug and were left untouched to keep scope tight:deploy/nginx-sundial.confis a partial mirror ofdata/nginx.conf— it lacks the two MIMEdefault_typeblocks (location = /manifest.webmanifest → application/manifest+json,location ~ \.mjs$ → application/javascript). The repo shipsmanifest.webmanifestand loadsvendor/lean-qr.mjsas an ES module, so under/sundial/these could be served asapplication/octet-stream(breaking the module load / QR view and the manifest type). Matters for PWA/QR under the subpath; a follow-up should add those two blocks.deploy/install-on-shard.shdoes not packsw.jsormanifest.webmanifest(it tarsindex.html version.json css js vendor assets). So on a shard the new/sundial/sw.jsno-cache rule is inert until the file is actually deployed, and PWA installability under/sundial/(manifest + service worker) is itself incomplete. TheDockerfile(root/core-release) does copy both, so the root path is unaffected.Both are worth a separate issue; neither blocks this fix (the two files that most matter for #37's reload —
index.htmlandversion.json— are packed and now no-cached).Review panel
Sequential adversarial subagents, each given only the diff + issue:
expireschange, block removal, andadd_header-in-block. Caught that the original nesting check used textual order, so a block moved to server level passed spuriously → fixed by asserting real brace containment (commitae68018), plus added the same no-add_headerguard fordata/nginx.conf(advisory finding Automated tests + CI (72 tests: unit + Playwright e2e) #2)./sundial/block, singleNO_CACHE_BLOCKmatch reused, escaping comment. Kept the exact-three-files regex (deliberate, per the test adversary) and the test split (nesting + add_header are one inheritance invariant).Lenses not run (triggers did not fire): Security (no auth/token/secret/input-parsing surface; the header-inheritance risk is covered by the adversarial lens, the live-nginx curl check, and the unit test), DB/migration, API-contract, UX.
🤖 Generated with Claude Code