mirror of
https://github.com/nesquena/hermes-webui.git
synced 2026-05-25 19:20:16 +00:00
2856ee6637
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 <ai-ag2026@users.noreply.github.com>
66 lines
3.3 KiB
Python
66 lines
3.3 KiB
Python
from pathlib import Path
|
|
|
|
REPO = Path(__file__).resolve().parents[1]
|
|
ROUTES_SRC = (REPO / "api" / "routes.py").read_text(encoding="utf-8")
|
|
SESSIONS_SRC = (REPO / "static" / "sessions.js").read_text(encoding="utf-8")
|
|
SW_SRC = (REPO / "static" / "sw.js").read_text(encoding="utf-8")
|
|
|
|
|
|
def test_stale_stream_cleanup_helper_exists():
|
|
assert "def _clear_stale_stream_state(session)" in ROUTES_SRC
|
|
assert "stream_id in STREAMS" in ROUTES_SRC
|
|
assert "session.active_stream_id = None" in ROUTES_SRC
|
|
assert "session.pending_user_message = None" in ROUTES_SRC
|
|
assert "session.pending_attachments = []" in ROUTES_SRC
|
|
assert "session.pending_started_at = None" in ROUTES_SRC
|
|
assert "session.save()" in ROUTES_SRC
|
|
|
|
|
|
def test_session_load_clears_stale_stream_before_response():
|
|
load_pos = ROUTES_SRC.index("s = get_session(sid, metadata_only=(not load_messages))")
|
|
cleanup_pos = ROUTES_SRC.index("_clear_stale_stream_state(s)", load_pos)
|
|
response_pos = ROUTES_SRC.index('"active_stream_id": getattr(s, "active_stream_id", None)', cleanup_pos)
|
|
assert load_pos < cleanup_pos < response_pos
|
|
|
|
|
|
def test_chat_start_clears_stale_pending_state_not_only_active_id():
|
|
stale_comment_pos = ROUTES_SRC.index("# Stale stream id from a previous run; clear and continue.")
|
|
cleanup_pos = ROUTES_SRC.index("_clear_stale_stream_state(s)", stale_comment_pos)
|
|
stream_id_pos = ROUTES_SRC.index("stream_id = uuid.uuid4().hex", cleanup_pos)
|
|
assert stale_comment_pos < cleanup_pos < stream_id_pos
|
|
|
|
|
|
def test_frontend_drops_inflight_cache_when_server_session_is_idle():
|
|
marker = "If the server says the session is idle, discard any browser-side inflight"
|
|
marker_pos = SESSIONS_SRC.index(marker)
|
|
window = SESSIONS_SRC[marker_pos:marker_pos + 500]
|
|
assert "if(!activeStreamId&&INFLIGHT[sid])" in window
|
|
assert "delete INFLIGHT[sid]" in window
|
|
assert "clearInflightState" in window
|
|
assert "S.busy=false" in window
|
|
|
|
|
|
def test_service_worker_cache_bumped_for_frontend_fix_delivery():
|
|
"""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."
|
|
)
|