fix: prevent plan canvas connection starvation

This commit is contained in:
haelyra
2026-08-27 21:24:03 -04:00
parent bb4adc6462
commit 61652b74ff
6 changed files with 197 additions and 222 deletions
+60 -13
View File
@@ -13,6 +13,9 @@ opening a second Plan Canvas in one agent chat.
disable or stall the page.
2. As a reviewer opening a plan with Mermaid diagrams, I want the Canvas page to
finish loading even when the Mermaid CDN is slow or unavailable.
3. As a reviewer with several Canvas tabs still open, I want the next Canvas to
receive and render its document instead of waiting forever for a browser
connection slot.
## Task report
@@ -43,6 +46,36 @@ opening a second Plan Canvas in one agent chat.
failures.
- GREEN checkpoint: `7fc31254 fix: keep mermaid from blocking canvas load`.
### Stop open canvases from exhausting the browser connection pool
- RED: the normal Chrome profile showed an `Untitled` blank tab with its load
indicator running indefinitely. `lsof -nP -iTCP:4517` showed exactly six
established connections from Chrome's network service to Plan Canvas. Each
older Canvas tab owned one permanent `EventSource`, exhausting Chromium's
six-connection HTTP/1 pool before the next document request could receive a
byte.
- RED: the focused integration test failed because `/client.js` still created
`EventSource`, `/api/session/:key/state` did not exist, `/events/:key` held
its response open, and health still advertised protocol 2.
- GREEN: protocol 3 replaces per-tab EventSource streams with one-second,
finite state requests carrying chat, presence, session status, and artifact
revision. Polls are sequential and abort after five seconds, so they cannot
pile up. Legacy `/events/:key` now returns HTTP 204, the status that tells an
existing EventSource client not to reconnect after the server upgrade.
- GREEN: `node tests/scripts/plan-canvas.test.js` produced 31 passes and 0
failures, including preservation of the active-browser idle lifecycle.
Focused ESLint and `git diff --check` passed.
- BROWSER: nine Canvas tabs were opened in one Chrome automation profile on an
isolated protocol-3 server. Every tab reached `document.readyState =
complete`, exposed its expected plan heading through the iframe accessibility
tree, and reported zero EventSource resources. Two shared keep-alive sockets
served the nine tabs at the observation point.
- DESKTOP: the normal Chrome profile kept the original blank protocol-2 tab
visible while three protocol-3 canvases on the isolated port rendered the
Sandbox Execution Fabric, Feature Fleet, and ECC 2 to ECC 3 plans. A captured
desktop-window image showed all three rendered tabs and live `agent listening`
presence.
## Test specification
| # | What is guaranteed | Test target | Type | Result |
@@ -52,30 +85,44 @@ opening a second Plan Canvas in one agent chat.
| 3 | Mermaid remote enhancement starts only after document load | `a plan containing mermaid serves the themed Mermaid loader` | Integration | PASS |
| 4 | Open, browser load, await, feedback, reply, approval, reopen, end, and stop still work together | `tests/integration/plan-canvas-e2e.test.js` | End to end | PASS |
| 5 | The large ECC 2 to ECC 3 master plan bootstraps under blocked local storage | Headless Chrome DOM and screenshot check against `/canvas/24af75d4c4fe` | Browser | PASS |
| 6 | The browser client never reserves one permanent HTTP connection per open Canvas | `browser client uses finite polling instead of one permanent connection per canvas` | Integration | PASS |
| 7 | Old EventSource clients stop reconnecting after upgrading the server | `legacy EventSource endpoint retires without reconnecting` | Integration | PASS |
| 8 | Browser polling carries chat, presence, end state, and artifact revision | Browser-state integration cases in `tests/scripts/plan-canvas.test.js` | Integration | PASS |
| 9 | More than Chromium's six HTTP/1 connection slots can coexist without blocking a new Canvas | Nine-tab Chrome DOM, accessibility-tree, resource-timing, and screenshot run | Browser | PASS |
| 10 | An actively viewed Canvas keeps the shared server alive through finite polls | `finite browser polls keep an actively viewed canvas server alive` | Integration | PASS |
## Coverage and full-suite evidence
`npm run coverage` passed all 3,993 discovered tests with these project totals:
`npm run coverage` passed all 3,996 discovered tests with these project totals:
- Statements: 88.98%
- Branches: 80.66%
- Functions: 94.32%
- Branches: 80.65%
- Functions: 94.34%
- Lines: 88.98%
The `scripts/lib/plan-canvas` group reached 98.38% statements, 88.2% branches,
98.64% functions, and 98.38% lines. Focused ESLint checks passed for every
The `scripts/lib/plan-canvas` group reached 98.53% statements, 87.82% branches,
100% functions, and 98.53% lines. Focused ESLint checks passed for every
modified JavaScript test and production file.
## Browser evidence and known gaps
The live shared server was initially process `15351`, started from the older
`ecc-tiered-sandbox` worktree, and served an unguarded `localStorage` client even
when invoked from current main. The patched CLI replaced it with the isolated
worktree server and restored persisted sessions. Two real plan sessions then
opened successfully. Headless Chrome with local storage disabled completed the
large master-plan DOM load in about two seconds and produced a rendered Canvas
screenshot.
when invoked from current main. The first patch replaced it with the isolated
worktree server and restored persisted sessions. That did not establish the
reported bug was fixed: HTTP 200 responses and a fresh-profile screenshot did
not exercise the saturated normal browser profile.
Chrome was exercised directly on macOS. Safari and Firefox were not run. The
fix relies only on standard health JSON, dynamic `import()`, and the standard
window `load` event.
The corrected investigation captured the real blank tab, its six live browser
connections, and the exact release-preview session behind it. The final browser
run used an isolated protocol-3 server on port 4518 so other agents could not
replace the executable under test. It rendered the actual in-progress Sandbox
Execution Fabric from the tiered-sandbox worktree, plus Feature Fleet and the
ECC 2 to ECC 3 master plan, in the normal desktop Chrome profile. Active agent
listeners remained attached to all three.
Chrome was exercised directly on macOS through both the user's normal profile
and a browser-automation profile. Safari and Firefox were not run. The
connection-pool fix relies on ordinary finite `fetch` requests, `AbortController`,
HTTP 204 EventSource retirement behavior, and file metadata for live-reload
revision checks.