v1.54.7
[1.54.7] — 2026-05-18
fix: W-001 — code/style assets + SPA shell served Cache-Control: no-store (deploy-hygiene).
🐛 Fixes
- The SPA loads
api.js/router.js/ every view via plain<script src>with no version query string, and there is no build step (no content hashing), so after a deploy a browser could keep serving a cached old bundle for hours → stale-cache 404s on query-string routes (observed live during the v1.29.2 regression; regression run W-001).server/index.mjsnow setsCache-Control: no-storeon.js/.mjs/.css/.htmlvia theexpress.staticsetHeadershook, and explicitly on the SPA-shell catch-all (which usessendFileand bypassessetHeaders), so the browser always revalidates the code that drives routing. Non-code static assets keepexpress.static's default caching. Security headers (CSP / nosniff / frame-deny / referrer-policy) are unchanged — verified by the existingsecurity-headerssuite (8 cases) running green alongside the new test.
🧪 Tests
test: tests/asset-cache-control.test.mjs— 4 cases (JS assetsno-store, CSSno-store, staticindex.htmlno-store, SPA catch-all deep-route shellno-store), booting the real app against an isolatedCAREER_OPS_ROOT. Plus a flaky-teardown fix intests/playwright-smoke.mjs(separatetest(e2e)commit): the auto-pipeline SSE smoke test now cancels the reader + aborts the fetch in afinallyand theafterhook force-closes lingering sockets, eliminating the post-teardown "Error: aborted" that reddened the v1.54.6 Playwright e2e job. 738 → 742.