From bb75707331627c581cccb7ba45d61a03bbd5b292 Mon Sep 17 00:00:00 2001 From: Michael Lam Date: Thu, 7 May 2026 10:23:32 -0700 Subject: [PATCH] fix: surface stale Kanban client recovery --- api/kanban_bridge.py | 12 +++ api/routes.py | 29 ++++++- .../1823/kanban-hard-refresh-diagnostic.png | Bin 0 -> 59883 bytes static/panels.js | 46 ++++++++++- tests/test_issue1823_kanban_not_found.py | 76 ++++++++++++++++++ tests/test_kanban_bridge.py | 16 ++++ 6 files changed, 172 insertions(+), 7 deletions(-) create mode 100644 docs/pr-media/1823/kanban-hard-refresh-diagnostic.png create mode 100644 tests/test_issue1823_kanban_not_found.py diff --git a/api/kanban_bridge.py b/api/kanban_bridge.py index 403f2710..d758d372 100644 --- a/api/kanban_bridge.py +++ b/api/kanban_bridge.py @@ -745,6 +745,18 @@ def _list_boards_payload(parsed): current = kb.get_current_board() except Exception: current = "default" + visible_slugs = {(_board_meta_dict(meta).get("slug")) for meta in boards} + default_slug = getattr(kb, "DEFAULT_BOARD", "default") + if current not in visible_slugs: + # The on-disk active-board pointer can outlive an archived/deleted board + # when another CLI/WebUI process removes it. Surface a valid current + # board instead of letting the frontend pin every subsequent request to + # a ghost slug and fail with an opaque 404. + try: + kb.clear_current_board() + except Exception: + pass + current = default_slug out = [] for raw_meta in boards: meta = _board_meta_dict(raw_meta) diff --git a/api/routes.py b/api/routes.py index e086587a..18d9c1a5 100644 --- a/api/routes.py +++ b/api/routes.py @@ -590,6 +590,19 @@ from api.agent_health import build_agent_health_payload from api.system_health import build_system_health_payload +def _kanban_unknown_endpoint(handler, parsed, method: str) -> bool: + """Return a Kanban-specific 404 for stale clients/obsolete endpoint shapes.""" + return bad( + handler, + ( + f"unknown Kanban endpoint: {method} {parsed.path}. " + "If this appeared after a WebUI update, your browser may be running " + "a stale cached bundle; use Hard refresh now, then reopen Kanban." + ), + status=404, + ) or True + + def _clear_stale_stream_state(session) -> bool: """Clear persisted streaming flags when the in-memory stream no longer exists. @@ -2616,7 +2629,9 @@ def handle_get(handler, parsed) -> bool: if parsed.path.startswith("/api/kanban/"): from api.kanban_bridge import handle_kanban_get - return handle_kanban_get(handler, parsed) + if handle_kanban_get(handler, parsed): + return True + return _kanban_unknown_endpoint(handler, parsed, "GET") if parsed.path == "/api/wiki/status": return _handle_llm_wiki_status(handler, parsed) if parsed.path == "/api/logs": @@ -3414,7 +3429,9 @@ def handle_post(handler, parsed) -> bool: if parsed.path.startswith("/api/kanban/"): from api.kanban_bridge import handle_kanban_post - return handle_kanban_post(handler, parsed, body) + if handle_kanban_post(handler, parsed, body): + return True + return _kanban_unknown_endpoint(handler, parsed, "POST") if parsed.path == "/api/dashboard/config": from api import dashboard_probe @@ -4590,7 +4607,9 @@ def handle_patch(handler, parsed) -> bool: if parsed.path.startswith("/api/kanban/"): from api.kanban_bridge import handle_kanban_patch - return handle_kanban_patch(handler, parsed, body) + if handle_kanban_patch(handler, parsed, body): + return True + return _kanban_unknown_endpoint(handler, parsed, "PATCH") return False @@ -4602,7 +4621,9 @@ def handle_delete(handler, parsed) -> bool: if parsed.path.startswith("/api/kanban/"): from api.kanban_bridge import handle_kanban_delete - return handle_kanban_delete(handler, parsed, body) + if handle_kanban_delete(handler, parsed, body): + return True + return _kanban_unknown_endpoint(handler, parsed, "DELETE") return False # ── GET route helpers ───────────────────────────────────────────────────────── diff --git a/docs/pr-media/1823/kanban-hard-refresh-diagnostic.png b/docs/pr-media/1823/kanban-hard-refresh-diagnostic.png new file mode 100644 index 0000000000000000000000000000000000000000..94546c3e9c0b2e3799bfb2766e0ca1a0309cb087 GIT binary patch literal 59883 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 literal 0 HcmV?d00001 diff --git a/static/panels.js b/static/panels.js index 9b056382..0add57b8 100644 --- a/static/panels.js +++ b/static/panels.js @@ -1189,11 +1189,49 @@ function _kanbanCard(task, status){ `; } +async function hardRefreshWebUIClient(){ + try { + if (navigator.serviceWorker) { + const regs = await navigator.serviceWorker.getRegistrations(); + await Promise.all(regs.map(r => r.unregister())); + } + } catch(_) {} + try { + if (window.caches) { + const keys = await caches.keys(); + await Promise.all(keys.map(k => caches.delete(k))); + } + } catch(_) {} + window.location.reload(); +} + +function _kanbanLooksLikeStaleClientError(err){ + const msg = String((err && err.message) || err || '').toLowerCase(); + return !!(err && err.status === 404 && ( + msg === 'not found' || + msg.includes('unknown kanban endpoint') || + msg.includes('stale cached bundle') + )); +} + +function _kanbanUnavailableHtml(err){ + const raw = String((err && err.message) || err || ''); + if (_kanbanLooksLikeStaleClientError(err)) { + return `

Kanban needs a hard refresh
The server rejected an obsolete Kanban endpoint. This usually means the browser or Mac app is still running a stale cached WebUI bundle after an update.
Original error: ${esc(raw || 'not found')}
`; + } + const msg = `${esc(t('kanban_unavailable'))}: ${esc(raw)}`; + return `
${msg}
`; +} + async function loadKanban(animate){ const board = $('kanbanBoard'); const list = $('kanbanList'); try { if (animate && board) board.innerHTML = `
${esc(t('loading'))}
`; + // Resolve the active board before board-scoped requests. If another CLI or + // tab archived the previous board, /boards can fall back to default instead + // of leaving config/board pinned to a ghost slug. + await loadKanbanBoards(); const config = await api('/api/kanban/config' + _kanbanBoardQuery()); let assignees = null; try { assignees = await api('/api/kanban/assignees' + _kanbanBoardQuery()); } catch(e) { assignees = null; } @@ -1230,9 +1268,9 @@ async function loadKanban(animate){ _kanbanStartPolling(); _kanbanRenderBoard(); } catch(e) { - const msg = `${esc(t('kanban_unavailable'))}: ${esc(e.message || e)}`; - if (board) board.innerHTML = `
${msg}
`; - if (list) list.innerHTML = `
${msg}
`; + const html = _kanbanUnavailableHtml(e); + if (board) board.innerHTML = html; + if (list) list.innerHTML = html; } } @@ -1687,6 +1725,8 @@ async function loadKanbanBoards(){ let active = serverCurrent; if (saved && boards.some(b => b.slug === saved)) { active = saved; + } else if (saved) { + _kanbanSetSavedBoard('default'); } _kanbanCurrentBoard = (active === 'default') ? null : active; // The switcher is visible whenever ≥1 non-default board exists OR the diff --git a/tests/test_issue1823_kanban_not_found.py b/tests/test_issue1823_kanban_not_found.py new file mode 100644 index 00000000..6899994b --- /dev/null +++ b/tests/test_issue1823_kanban_not_found.py @@ -0,0 +1,76 @@ +"""Regression coverage for #1823 Kanban stale-client/board-pointer failures.""" + +from __future__ import annotations + +import io +import json +from types import SimpleNamespace +from urllib.parse import urlparse + +from api import routes + +ROOT = __import__("pathlib").Path(__file__).resolve().parents[1] +PANELS = (ROOT / "static" / "panels.js").read_text(encoding="utf-8") +ROUTES = (ROOT / "api" / "routes.py").read_text(encoding="utf-8") + + +class _FakeHandler: + def __init__(self): + self.status = None + self.headers = {} + self.response_headers = [] + self.wfile = io.BytesIO() + + def send_response(self, status): + self.status = status + + def send_header(self, key, value): + self.response_headers.append((key, value)) + + def end_headers(self): + pass + + def body_json(self): + return json.loads(self.wfile.getvalue().decode("utf-8")) + + +def test_unknown_kanban_endpoint_get_returns_stale_client_diagnostic(): + """Obsolete/stale JS should not collapse to a bare `not found` 404.""" + handler = _FakeHandler() + handled = routes.handle_get(handler, urlparse("/api/kanban/obsolete-shape")) + + assert handled is True + assert handler.status == 404 + error = handler.body_json()["error"] + assert error != "not found" + assert "unknown Kanban endpoint: GET /api/kanban/obsolete-shape" in error + assert "stale cached bundle" in error + assert "Hard refresh now" in error + + +def test_unknown_kanban_endpoint_routes_are_wrapped_for_all_methods(): + assert 'return _kanban_unknown_endpoint(handler, parsed, "GET")' in ROUTES + assert 'return _kanban_unknown_endpoint(handler, parsed, "POST")' in ROUTES + assert 'return _kanban_unknown_endpoint(handler, parsed, "PATCH")' in ROUTES + assert 'return _kanban_unknown_endpoint(handler, parsed, "DELETE")' in ROUTES + + +def test_kanban_stale_client_error_renders_hard_refresh_escape_hatch(): + assert "function _kanbanLooksLikeStaleClientError(err)" in PANELS + assert "err.status === 404" in PANELS + assert "msg === 'not found'" in PANELS + assert "msg.includes('unknown kanban endpoint')" in PANELS + assert "Kanban needs a hard refresh" in PANELS + assert "Hard refresh now" in PANELS + assert "navigator.serviceWorker.getRegistrations()" in PANELS + assert "caches.keys()" in PANELS + assert "window.location.reload()" in PANELS + + +def test_kanban_load_resolves_board_before_board_scoped_requests(): + boards_pos = PANELS.find("await loadKanbanBoards();") + config_pos = PANELS.find("api('/api/kanban/config' + _kanbanBoardQuery())") + assert boards_pos != -1 + assert config_pos != -1 + assert boards_pos < config_pos + assert "_kanbanSetSavedBoard('default');" in PANELS diff --git a/tests/test_kanban_bridge.py b/tests/test_kanban_bridge.py index bbcae21d..3e99956d 100644 --- a/tests/test_kanban_bridge.py +++ b/tests/test_kanban_bridge.py @@ -389,6 +389,22 @@ def test_kanban_board_payload_exposes_read_only_board(monkeypatch): assert any(task["id"] == "t_1" and task["title"] == "Read-only board target" for task in all_tasks) +def test_board_pointer_drift_falls_back_to_default(monkeypatch): + bridge = _load_bridge(monkeypatch) + fake_kanban = sys.modules["hermes_cli.kanban_db"] + fake_kanban.boards = { + "default": {"slug": "default", "name": "Default board", "archived": False}, + "active": {"slug": "active", "name": "Active board", "archived": False}, + } + fake_kanban.set_current_board("ghost") + + data = bridge._list_boards_payload(_parsed(path="/api/kanban/boards")) + + assert data["current"] == "default" + assert fake_kanban.get_current_board() == "default" + assert any(board["slug"] == "default" and board["is_current"] for board in data["boards"]) + + def test_kanban_task_detail_payload_exposes_comments_events_links_and_runs(monkeypatch): bridge = _load_bridge(monkeypatch)