From 2b19430b23e33e263a9f5e5506d900ab3891c4ca Mon Sep 17 00:00:00 2001 From: Egor Merkushev Date: Mon, 16 Feb 2026 12:32:37 +0300 Subject: [PATCH 1/6] Select task FU-P12-T2-1: Fix_stacking_click_listeners_in_updateLatencyTable --- SPECS/INPROGRESS/next.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/SPECS/INPROGRESS/next.md b/SPECS/INPROGRESS/next.md index c419fe90..d4e1bca8 100644 --- a/SPECS/INPROGRESS/next.md +++ b/SPECS/INPROGRESS/next.md @@ -1,6 +1,11 @@ -# No Active Task +# Active Task -The previously selected task has been archived. +## FU-P12-T2-1: Fix stacking click event listeners in `updateLatencyTable` + +- **Selected:** 2026-02-16 +- **Priority:** P3 +- **Depends on:** P12-T2 ✅ +- **Branch:** feature/FU-P12-T2-1-fix-stacking-click-listeners ## Recently Archived @@ -12,7 +17,6 @@ The previously selected task has been archived. ## Suggested Next Tasks -- FU-P12-T2-1: Fix stacking click event listeners in `updateLatencyTable` (P3, depends on P12-T2 ✅) - FU-P12-T1-1: Remove or document `MCPInitializeParams` in schemas (P3, depends on P12-T1 ✅) - FU-P12-T3-2: Add `error_code` column to audit CSV export (P3, depends on P12-T3 ✅) - FU-P12-T1-2: Add code comment clarifying stdin-only client capture in `on_request` (P3, depends on P12-T1 ✅) From 2acfc44eaabb73541f6152c31279a32c27e17181 Mon Sep 17 00:00:00 2001 From: Egor Merkushev Date: Mon, 16 Feb 2026 12:34:00 +0300 Subject: [PATCH 2/6] Plan task FU-P12-T2-1: Fix_stacking_click_listeners_in_updateLatencyTable --- ...g_click_listeners_in_updateLatencyTable.md | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 SPECS/INPROGRESS/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable.md diff --git a/SPECS/INPROGRESS/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable.md b/SPECS/INPROGRESS/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable.md new file mode 100644 index 00000000..4485ceb8 --- /dev/null +++ b/SPECS/INPROGRESS/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable.md @@ -0,0 +1,54 @@ +# PRD: FU-P12-T2-1 — Fix stacking click event listeners in `updateLatencyTable` + +**Status:** In Progress +**Priority:** P3 +**Depends on:** P12-T2 ✅ +**Date:** 2026-02-16 + +--- + +## Problem + +`updateLatencyTable(toolLatency)` is called on every polling cycle (~2 s) from +`handleMetricsUpdate`. Each invocation clears `tbody.innerHTML` and rebuilds rows, +but it also calls `tbody.addEventListener("click", handler)` unconditionally. Since +`tbody` is the same DOM node across calls (only its children are replaced), each +call stacks another identical click handler on it. After N refresh cycles, a single +button click fires the toggle logic N times, triggering N `fetchParamPatterns` +requests for the same row. + +## Root Cause + +```js +// dashboard.js:332 — inside updateLatencyTable, called every ~2 s +tbody.addEventListener("click", function (e) { … }); +``` + +The listener is registered inside the function that is called on every poll, with no +guard against re-registration. + +## Fix + +Move the click listener to `setupEventHandlers()`, which runs once at init. Attach +it to `el("latency-table")` (the stable `` element) instead of `tbody`, using +the same event-delegation pattern (`e.target.closest(".param-toggle-btn")`). Remove +the `tbody.addEventListener(...)` block from `updateLatencyTable`. + +## Deliverables + +- `src/mcpbridge_wrapper/webui/static/dashboard.js` — listener moved to + `setupEventHandlers`, removed from `updateLatencyTable`. + +## Acceptance Criteria + +- `updateLatencyTable` contains no `addEventListener` call. +- `setupEventHandlers` registers exactly one delegated click handler on + `el("latency-table")`. +- Toggle expand/collapse behaviour is unchanged after the fix. +- `fetchParamPatterns` is called exactly once per button click regardless of how + many times `updateLatencyTable` has been called before. +- All existing tests pass (`pytest`, `ruff check src/`). + +## Out of Scope + +- Changes to `fetchParamPatterns`, row rendering, or any other part of the dashboard. From 8fcdb0d2e05f2d0fc17e04898cdbb0d7ead97f76 Mon Sep 17 00:00:00 2001 From: Egor Merkushev Date: Mon, 16 Feb 2026 12:34:54 +0300 Subject: [PATCH 3/6] Implement FU-P12-T2-1: move latency table click listener to setupEventHandlers --- .../FU-P12-T2-1_Validation_Report.md | 41 +++++++++++++++++++ .../webui/static/dashboard.js | 40 +++++++++--------- 2 files changed, 61 insertions(+), 20 deletions(-) create mode 100644 SPECS/INPROGRESS/FU-P12-T2-1_Validation_Report.md diff --git a/SPECS/INPROGRESS/FU-P12-T2-1_Validation_Report.md b/SPECS/INPROGRESS/FU-P12-T2-1_Validation_Report.md new file mode 100644 index 00000000..4b891305 --- /dev/null +++ b/SPECS/INPROGRESS/FU-P12-T2-1_Validation_Report.md @@ -0,0 +1,41 @@ +# Validation Report: FU-P12-T2-1 + +**Task:** Fix stacking click event listeners in `updateLatencyTable` +**Date:** 2026-02-16 +**Verdict:** PASS + +--- + +## Change Summary + +Moved the delegated click handler for `.param-toggle-btn` out of +`updateLatencyTable` (which runs every ~2 s) into `setupEventHandlers` (which runs +once at init). The handler is now attached to `el("latency-table")` instead of +`tbody`, keeping the same event-delegation pattern. + +**File changed:** `src/mcpbridge_wrapper/webui/static/dashboard.js` +- Removed `tbody.addEventListener("click", …)` block from `updateLatencyTable` (lines 332-350 prior to fix) +- Added equivalent `el("latency-table").addEventListener("click", …)` in `setupEventHandlers` (lines 570-588) + +--- + +## Quality Gates + +| Gate | Result | +|------|--------| +| `pytest` | ✅ 465 passed, 5 skipped | +| `ruff check src/` | ✅ All checks passed | +| `pytest --cov` | ✅ 95.6% (≥ 90% required) | +| `mypy src/` | N/A — not configured | + +--- + +## Acceptance Criteria Verification + +| Criterion | Status | +|-----------|--------| +| `updateLatencyTable` contains no `addEventListener` call | ✅ | +| `setupEventHandlers` registers exactly one delegated click handler on `el("latency-table")` | ✅ | +| Toggle expand/collapse behaviour unchanged | ✅ (same handler logic) | +| `fetchParamPatterns` called exactly once per click regardless of prior refresh count | ✅ (single registered listener) | +| All existing tests pass | ✅ 465 passed | diff --git a/src/mcpbridge_wrapper/webui/static/dashboard.js b/src/mcpbridge_wrapper/webui/static/dashboard.js index b8328439..9d76d386 100644 --- a/src/mcpbridge_wrapper/webui/static/dashboard.js +++ b/src/mcpbridge_wrapper/webui/static/dashboard.js @@ -328,26 +328,6 @@ + "Loading\u2026"; tbody.appendChild(detailTr); }); - - tbody.addEventListener("click", function (e) { - var btn = e.target.closest(".param-toggle-btn"); - if (!btn) return; - var targetId = btn.getAttribute("data-target"); - var toolName = btn.getAttribute("data-tool"); - var detailRow = document.getElementById(targetId); - if (!detailRow) return; - var isOpen = detailRow.style.display !== "none"; - if (isOpen) { - detailRow.style.display = "none"; - btn.innerHTML = "▶"; - btn.setAttribute("aria-expanded", "false"); - } else { - detailRow.style.display = ""; - btn.innerHTML = "▼"; - btn.setAttribute("aria-expanded", "true"); - fetchParamPatterns(toolName, "patterns-" + targetId); - } - }); } function fetchParamPatterns(toolName, containerId) { @@ -585,6 +565,26 @@ auditPage = 0; loadAuditLogs(); }); + + el("latency-table").addEventListener("click", function (e) { + var btn = e.target.closest(".param-toggle-btn"); + if (!btn) return; + var targetId = btn.getAttribute("data-target"); + var toolName = btn.getAttribute("data-tool"); + var detailRow = document.getElementById(targetId); + if (!detailRow) return; + var isOpen = detailRow.style.display !== "none"; + if (isOpen) { + detailRow.style.display = "none"; + btn.innerHTML = "▶"; + btn.setAttribute("aria-expanded", "false"); + } else { + detailRow.style.display = ""; + btn.innerHTML = "▼"; + btn.setAttribute("aria-expanded", "true"); + fetchParamPatterns(toolName, "patterns-" + targetId); + } + }); } // --- Session Timeline --- From 2c8cbd20a989640002c2722d6e34fb130085df1a Mon Sep 17 00:00:00 2001 From: Egor Merkushev Date: Mon, 16 Feb 2026 12:36:07 +0300 Subject: [PATCH 4/6] Archive task FU-P12-T2-1: Fix_stacking_click_listeners_in_updateLatencyTable (PASS) --- ..._stacking_click_listeners_in_updateLatencyTable.md | 4 ++++ .../FU-P12-T2-1_Validation_Report.md | 0 SPECS/ARCHIVE/INDEX.md | 4 +++- SPECS/INPROGRESS/next.md | 11 +++-------- SPECS/Workplan.md | 2 +- 5 files changed, 11 insertions(+), 10 deletions(-) rename SPECS/{INPROGRESS => ARCHIVE/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable}/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable.md (97%) rename SPECS/{INPROGRESS => ARCHIVE/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable}/FU-P12-T2-1_Validation_Report.md (100%) diff --git a/SPECS/INPROGRESS/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable.md b/SPECS/ARCHIVE/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable.md similarity index 97% rename from SPECS/INPROGRESS/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable.md rename to SPECS/ARCHIVE/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable.md index 4485ceb8..8f9b7cd5 100644 --- a/SPECS/INPROGRESS/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable.md +++ b/SPECS/ARCHIVE/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable.md @@ -52,3 +52,7 @@ the `tbody.addEventListener(...)` block from `updateLatencyTable`. ## Out of Scope - Changes to `fetchParamPatterns`, row rendering, or any other part of the dashboard. + +--- +**Archived:** 2026-02-16 +**Verdict:** PASS diff --git a/SPECS/INPROGRESS/FU-P12-T2-1_Validation_Report.md b/SPECS/ARCHIVE/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable/FU-P12-T2-1_Validation_Report.md similarity index 100% rename from SPECS/INPROGRESS/FU-P12-T2-1_Validation_Report.md rename to SPECS/ARCHIVE/FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable/FU-P12-T2-1_Validation_Report.md diff --git a/SPECS/ARCHIVE/INDEX.md b/SPECS/ARCHIVE/INDEX.md index b5d824b7..ec89d229 100644 --- a/SPECS/ARCHIVE/INDEX.md +++ b/SPECS/ARCHIVE/INDEX.md @@ -1,6 +1,6 @@ # mcpbridge-wrapper Tasks Archive -**Last Updated:** 2026-02-16 (FU-P11-T1-1) +**Last Updated:** 2026-02-16 ## Archived Tasks @@ -101,6 +101,7 @@ | FU-P11-T2-1 | [FU-P11-T2-1_Push_Session_Data_via_WebSocket/](FU-P11-T2-1_Push_Session_Data_via_WebSocket/) | 2026-02-16 | PASS | | FU-P11-T2-2 | [FU-P11-T2-2_Add_limit_query_param_to_GET_api_sessions/](FU-P11-T2-2_Add_limit_query_param_to_GET_api_sessions/) | 2026-02-16 | PASS | | FU-P11-T1-1 | [FU-P11-T1-1_Refactor_FakeWebUIConfig_to_MagicMock/](FU-P11-T1-1_Refactor_FakeWebUIConfig_to_MagicMock/) | 2026-02-16 | PASS | +| FU-P12-T2-1 | [FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable/](FU-P12-T2-1_Fix_stacking_click_listeners_in_updateLatencyTable/) | 2026-02-16 | PASS | ## Historical Artifacts @@ -284,3 +285,4 @@ | 2026-02-16 | FU-P11-T2-2 | Archived REVIEW_FU-P11-T2-2_limit_query_param report | | 2026-02-16 | FU-P11-T1-1 | Archived Refactor_FakeWebUIConfig_to_MagicMock (PASS) | | 2026-02-16 | FU-P11-T1-1 | Archived REVIEW_FU-P11-T1-1_fake_webuiconfig_refactor report | +| 2026-02-16 | FU-P12-T2-1 | Archived Fix_stacking_click_listeners_in_updateLatencyTable (PASS) | diff --git a/SPECS/INPROGRESS/next.md b/SPECS/INPROGRESS/next.md index d4e1bca8..f1ba38c1 100644 --- a/SPECS/INPROGRESS/next.md +++ b/SPECS/INPROGRESS/next.md @@ -1,19 +1,14 @@ -# Active Task +# No Active Task -## FU-P12-T2-1: Fix stacking click event listeners in `updateLatencyTable` - -- **Selected:** 2026-02-16 -- **Priority:** P3 -- **Depends on:** P12-T2 ✅ -- **Branch:** feature/FU-P12-T2-1-fix-stacking-click-listeners +The previously selected task has been archived. ## Recently Archived +- 2026-02-16 — FU-P12-T2-1: Fix stacking click event listeners in `updateLatencyTable` (PASS) - 2026-02-16 — FU-P11-T1-1: Refactor `_FakeWebUIConfig` test stub to use `MagicMock(spec=WebUIConfig)` (PASS) - 2026-02-16 — FU-P11-T2-2: Add `limit` query param to `GET /api/sessions` (PASS) - 2026-02-16 — FU-P11-T2-1: Push session data via WebSocket (PASS) - 2026-02-16 — P12-T2: Add Tool Parameter Frequency Analysis (PASS) -- 2026-02-15 — P11-T4: Add Keyboard Shortcuts & Command Palette (PASS) ## Suggested Next Tasks diff --git a/SPECS/Workplan.md b/SPECS/Workplan.md index eb0052f9..283fd3df 100644 --- a/SPECS/Workplan.md +++ b/SPECS/Workplan.md @@ -1993,7 +1993,7 @@ Phase 9 Follow-up Backlog --- -#### FU-P12-T2-1: Fix stacking click event listeners in `updateLatencyTable` +#### ✅ FU-P12-T2-1: Fix stacking click event listeners in `updateLatencyTable` - **Description:** The `tbody.addEventListener("click", ...)` call inside `updateLatencyTable()` in `dashboard.js` is re-registered on every metrics refresh (every 1 second), causing listeners to accumulate. Move the click handler to a one-time setup function called once during dashboard initialization, or guard with a `data-listener-attached` sentinel attribute on the tbody element. - **Priority:** P3 - **Dependencies:** P12-T2 From d1c3474f4daac680d9c18b15ab60cc83ca9797a5 Mon Sep 17 00:00:00 2001 From: Egor Merkushev Date: Mon, 16 Feb 2026 12:36:39 +0300 Subject: [PATCH 5/6] Review FU-P12-T2-1: stacking_click_listeners --- ...EW_FU-P12-T2-1_stacking_click_listeners.md | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 SPECS/INPROGRESS/REVIEW_FU-P12-T2-1_stacking_click_listeners.md diff --git a/SPECS/INPROGRESS/REVIEW_FU-P12-T2-1_stacking_click_listeners.md b/SPECS/INPROGRESS/REVIEW_FU-P12-T2-1_stacking_click_listeners.md new file mode 100644 index 00000000..9a361ff4 --- /dev/null +++ b/SPECS/INPROGRESS/REVIEW_FU-P12-T2-1_stacking_click_listeners.md @@ -0,0 +1,53 @@ +## REVIEW REPORT — FU-P12-T2-1: Fix stacking click listeners in updateLatencyTable + +**Scope:** origin/main..HEAD +**Files:** 1 (dashboard.js) +**Date:** 2026-02-16 + +--- + +### Summary Verdict + +- [x] Approve + +--- + +### Critical Issues + +None. + +--- + +### Secondary Issues + +None. + +--- + +### Architectural Notes + +- The fix correctly moves the delegated click handler from `updateLatencyTable` + (called every ~2 s by the polling loop) into `setupEventHandlers` (called once at + `init()`), eliminating listener stacking entirely. +- Attaching to `el("latency-table")` (the stable `
` element) rather than + `tbody` (whose children are rebuilt on each poll) is the right approach: the table + element is present in the static HTML and survives all DOM rebuilds. +- Event delegation via `e.target.closest(".param-toggle-btn")` is preserved + unchanged, so the handler correctly targets dynamically created buttons regardless + of when they were inserted. +- The change is a pure refactor (no logic changes); the handler body is identical to + the original. + +--- + +### Tests + +- 465 tests pass; 5 skipped. Coverage 95.6% (requirement: ≥90%). +- No JS unit tests exist for dashboard.js — this is consistent with the existing + test suite which covers only the Python backend. No gap introduced. + +--- + +### Next Steps + +- No actionable issues found. FOLLOW-UP skipped. From 4cc70457b1f21a7ebf3091880b8214c017ef0b82 Mon Sep 17 00:00:00 2001 From: Egor Merkushev Date: Mon, 16 Feb 2026 12:37:07 +0300 Subject: [PATCH 6/6] Archive REVIEW_FU-P12-T2-1_stacking_click_listeners report --- SPECS/ARCHIVE/INDEX.md | 2 ++ .../_Historical}/REVIEW_FU-P12-T2-1_stacking_click_listeners.md | 0 2 files changed, 2 insertions(+) rename SPECS/{INPROGRESS => ARCHIVE/_Historical}/REVIEW_FU-P12-T2-1_stacking_click_listeners.md (100%) diff --git a/SPECS/ARCHIVE/INDEX.md b/SPECS/ARCHIVE/INDEX.md index ec89d229..083c88dc 100644 --- a/SPECS/ARCHIVE/INDEX.md +++ b/SPECS/ARCHIVE/INDEX.md @@ -166,6 +166,7 @@ | [REVIEW_P12-T2_param_frequency_analysis.md](P12-T2_Add_Tool_Parameter_Frequency_Analysis/REVIEW_P12-T2_param_frequency_analysis.md) | Review report for P12-T2 | | [REVIEW_FU-P11-T2-2_limit_query_param.md](_Historical/REVIEW_FU-P11-T2-2_limit_query_param.md) | Review report for FU-P11-T2-2 | | [REVIEW_FU-P11-T1-1_fake_webuiconfig_refactor.md](_Historical/REVIEW_FU-P11-T1-1_fake_webuiconfig_refactor.md) | Review report for FU-P11-T1-1 | +| [REVIEW_FU-P12-T2-1_stacking_click_listeners.md](_Historical/REVIEW_FU-P12-T2-1_stacking_click_listeners.md) | Review report for FU-P12-T2-1 | ## Archive Log @@ -286,3 +287,4 @@ | 2026-02-16 | FU-P11-T1-1 | Archived Refactor_FakeWebUIConfig_to_MagicMock (PASS) | | 2026-02-16 | FU-P11-T1-1 | Archived REVIEW_FU-P11-T1-1_fake_webuiconfig_refactor report | | 2026-02-16 | FU-P12-T2-1 | Archived Fix_stacking_click_listeners_in_updateLatencyTable (PASS) | +| 2026-02-16 | FU-P12-T2-1 | Archived REVIEW_FU-P12-T2-1_stacking_click_listeners report | diff --git a/SPECS/INPROGRESS/REVIEW_FU-P12-T2-1_stacking_click_listeners.md b/SPECS/ARCHIVE/_Historical/REVIEW_FU-P12-T2-1_stacking_click_listeners.md similarity index 100% rename from SPECS/INPROGRESS/REVIEW_FU-P12-T2-1_stacking_click_listeners.md rename to SPECS/ARCHIVE/_Historical/REVIEW_FU-P12-T2-1_stacking_click_listeners.md