From 2856ee66378fb0990ff48cb73d66db1cee3d8b7a Mon Sep 17 00:00:00 2001 From: Hermes Bot Date: Sun, 3 May 2026 16:21:42 +0000 Subject: [PATCH] =?UTF-8?q?fix(stage-279):=20absorb=20Opus=20MUST-FIX=20?= =?UTF-8?q?=E2=80=94=20sw.js=20conflict-marker=20resolution?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Opus advisor flagged that the conflict-marker resolution from PR #1525's merge had not actually landed — static/sw.js still contained the literal <<<<<<< HEAD / ======= / >>>>>>> pr-1525 markers, which made the file fail to parse as JavaScript even though the substring-based source-string tests still passed (the __WEBUI_VERSION__ token was present, just inside the conflict block). Concrete impact pre-fix when shipped: - Service worker install handler would throw on script load - SW would never reach activated state - Old SW (from v0.50.278) would keep controlling the page indefinitely - Frontend cache-bust pathway silently broken - The INFLIGHT[sid] clear in static/sessions.js (the frontend half of PR #1525's stale-stream cleanup) would never deliver to existing browsers because the new SW would never activate Fix: - Resolve sw.js conflict to keep CACHE_NAME = 'hermes-shell-__WEBUI_VERSION__' (the post-#1517 rename, with the manual -stale-stream-cleanup1 suffix dropped as redundant — natural version-token bump invalidates old caches). - Add tests/test_pwa_manifest_sw.py::test_sw_js_has_no_merge_conflict_markers regression guard that scans for <<<<<<<, =======, >>>>>>> in sw.js source. - Update tests/test_stale_stream_cleanup.py::test_service_worker_cache_ bumped_for_frontend_fix_delivery to assert the canonical version-token CACHE_NAME pattern instead of the (now-removed) -stale-stream-cleanup1 manual suffix. 3945 → 3946 tests passing (+1 from the new conflict-marker guard). This issue would have shipped a broken service worker if Opus hadn't caught it. The new test_sw_js_has_no_merge_conflict_markers test would have flagged it earlier in the pipeline. Caught-by: Opus advisor pass on stage-279 brief Co-authored-by: ai-ag2026 --- static/sw.js | 4 ---- tests/test_pwa_manifest_sw.py | 19 +++++++++++++++++++ tests/test_stale_stream_cleanup.py | 23 ++++++++++++++++++++++- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/static/sw.js b/static/sw.js index e4e7ac38..cb8e2071 100644 --- a/static/sw.js +++ b/static/sw.js @@ -7,11 +7,7 @@ // Cache version is injected by the server at request time (routes.py /sw.js handler). // Bumps automatically whenever the git commit changes — no manual edits needed. -<<<<<<< HEAD const CACHE_NAME = 'hermes-shell-__WEBUI_VERSION__'; -======= -const CACHE_NAME = 'hermes-shell-__CACHE_VERSION__-stale-stream-cleanup1'; ->>>>>>> pr-1525 // Static assets that form the app shell. // diff --git a/tests/test_pwa_manifest_sw.py b/tests/test_pwa_manifest_sw.py index c5e46982..730d4a9a 100644 --- a/tests/test_pwa_manifest_sw.py +++ b/tests/test_pwa_manifest_sw.py @@ -57,6 +57,25 @@ class TestServiceWorker: "handler at /sw.js to replace with WEBUI_VERSION at request time" ) + def test_sw_js_has_no_merge_conflict_markers(self): + """Regression guard for v0.50.279 stage build: a leftover git conflict + marker in static/sw.js made the file fail to parse as JavaScript even + though the substring-based source-string tests still passed (the + ``__WEBUI_VERSION__`` token was present, just inside the conflict block). + + A broken sw.js means the install handler throws on script load → SW + never reaches activated state → old SW keeps controlling the page → + every "old SW deletes other caches" guarantee is forfeited and frontend + cache-bust pathways silently break. Caught by Opus advisor pre-merge, + ship blocked. This test would have caught it too. + """ + src = SW.read_text(encoding="utf-8") + for marker in ("<<<<<<<", "=======\n", ">>>>>>>"): + assert marker not in src, ( + f"static/sw.js contains conflict marker {marker!r}; " + "the merge resolution did not actually land. Reject ship." + ) + def test_sw_bypasses_api_and_stream(self): src = SW.read_text(encoding="utf-8") assert "/api/" in src, "SW must bypass /api/* (no cached auth/session responses)" diff --git a/tests/test_stale_stream_cleanup.py b/tests/test_stale_stream_cleanup.py index c6070feb..fe117d01 100644 --- a/tests/test_stale_stream_cleanup.py +++ b/tests/test_stale_stream_cleanup.py @@ -41,4 +41,25 @@ def test_frontend_drops_inflight_cache_when_server_session_is_idle(): def test_service_worker_cache_bumped_for_frontend_fix_delivery(): - assert "stale-stream-cleanup1" in SW_SRC + """The SW CACHE_NAME must be keyed on the WEBUI_VERSION placeholder so + every release naturally invalidates the previous shell cache and delivers + the frontend half of the stale-stream cleanup fix to existing browsers. + + Originally pinned a manual `-stale-stream-cleanup1` suffix on + `CACHE_NAME` (PR #1525 author shipped that to force-bump existing + SWs). During the v0.50.279 stage build that suffix collided with the + independent #1517 placeholder rename (`__CACHE_VERSION__` → + `__WEBUI_VERSION__`), so the maintainer dropped the manual suffix in + favor of the canonical version-token path. The natural bump still + invalidates the old cache via `keys.filter((k) => k !== CACHE_NAME)` + in the activate handler — same delivery guarantee, less churn. + """ + # CACHE_NAME must include the WEBUI_VERSION placeholder so each release + # produces a different cache name. The activate handler then deletes any + # cache whose key != current CACHE_NAME, so the old shell is reaped on + # every upgrade and the new sessions.js (with the INFLIGHT[sid] clear) + # ships to existing browsers. + assert "CACHE_NAME = 'hermes-shell-__WEBUI_VERSION__'" in SW_SRC, ( + "SW CACHE_NAME must include __WEBUI_VERSION__ so each release " + "invalidates the previous cache and delivers frontend changes." + )