# Plan Canvas loading hang TDD evidence ## Source No implementation plan was supplied. The journeys and guarantees below were derived from the reported intermittent localhost loading hang, especially when opening a second Plan Canvas in one agent chat. ## User journeys 1. As a reviewer opening plans from multiple ECC worktrees, I want every new Canvas to use the current server code so an older same-version process cannot 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 ### Replace a stale same-version detached server - RED: `node tests/integration/plan-canvas-e2e.test.js` produced 9 passes and 1 failure. The current CLI reused a fake legacy server that reported the same package version and sent the session-open request to it. - RED checkpoint: `5dc6d85c test: add reproducer for stale plan canvas server`. - GREEN: the health handshake now carries a protocol version and a SHA-256 fingerprint of every module loaded into the detached Canvas server. The CLI retires any process whose package, protocol, or runtime fingerprint differs. - GREEN: `node tests/integration/plan-canvas-e2e.test.js` produced 10 passes and 0 failures. - GREEN checkpoint: `7e0d115e fix: restart stale plan canvas servers`. ### Keep Mermaid enhancement from blocking page load - RED: `node tests/scripts/plan-canvas.test.js` produced 27 passes and 1 failure. The generated artifact loaded Mermaid with top-level `await`, which allowed an unresolved remote import to hold the document load event open. - RED checkpoint: `ca0d0415 test: reproduce mermaid page load stall`. - GREEN: the dynamic Mermaid import now starts from an async `load` listener. Browsers do not await that listener, so diagrams remain progressive enhancement and the raw Mermaid source remains available during a network stall. - GREEN: `node tests/scripts/plan-canvas.test.js` produced 28 passes and 0 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 | | --- | --- | --- | --- | --- | | 1 | A legacy server with the same package version is shut down before the current CLI opens a plan | `same-version legacy server is replaced before a canvas opens` | End to end | PASS | | 2 | Health exposes package, protocol, and exact Canvas runtime identity | `GET /health identifies the app and version` | Integration | PASS | | 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,996 discovered tests with these project totals: - Statements: 88.98% - Branches: 80.65% - Functions: 94.34% - Lines: 88.98% 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 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. 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.