Local two-browser reconnect evidence¶
PR #3769 extends the isolated two-API lane from #3765. The passing test tree
is c7f90b969ab560a59724b527684d7d776b9e2bee, committed as
752a42c30fd33ad5ae0a3a6b757834e0e3ab52c0. It includes #3765 head
93aaa11ac8632a19f0788f6cb78de47d96c4d8ee, including #3767's tested
fence fix and test-only coverage follow-up. The .NET build passed on the same
production source; the subsequent targeted browser run reused those binaries.
The local stack used database syrf_e2e, real RabbitMQ, a fixed allowlisted
test project, API 1 on localhost:13286, API 2 on localhost:13290, and
Angular on localhost:9406. The first Angular browser reached API 1 through
the Vite web proxy. A separate browser context changed only its fetched
runtime apiOrigin to API 2; CDP confirmed authenticated HTTP and real
/notifications WebSocket destinations. A seeded local E2ETest
administrator session was issued separately by each BFF host, because the
hosts' sessions are process scoped. The setup also seeded local reviewer and
standard roles. No personal or staging sign-in, token, or browser storage
state is committed.
From this PR's worktree, the exact checks were:
node e2e/scripts/test-chromium-netns.cjs
E2E_BROWSER_NETNS=1 bash e2e/run-local.sh --feat024-two-api --spec materialized-statistics-two-api
E2E_BROWSER_NETNS=1 bash e2e/run-local.sh --feat024-two-api --spec materialized-statistics-two-api --skip-build
pnpm --dir e2e exec tsc --noEmit
git diff --check
The first runner command fully built the .NET solution; its browser phase then
timed out on an initial page load. The final passing browser run used a
bounded initial-readiness wait and --skip-build to reuse that build after a
test-only parent merge. After the Stage Overview poll-bound fix, the targeted
rerun passed on those same binaries. Its final local log is
/tmp/syrf-pr3769-overview-reconnect-fix-run1.log; the full-build log is
/tmp/syrf-pr3769-two-browser-final-parent-run4.log. These uncommitted
machine-local logs include test-session diagnostics. Failure traces and
screenshots remain in the ignored e2e/test-results/ directory.
| Check | Passing observation |
|---|---|
| Materialized setup | Both API hosts reported effective Pages, ReviewerProgress, StageOverviewBundle, and SignalR flags. The initial Stage Overview browser bundle said readSource: Materialized; the administrator screening parity read said readSource: Materialized and inParity: true. The reviewer-progress response does not expose per-response provenance. |
| Two real browser hosts | The API 1 Stage Review browser, API 2 Stage Overview browser, and API 2 direct observer received the same new project revision 11 at 1354, 1357, and 1352 ms after the screening action. Stage Review and Stage Overview rendered the new counts at 2196 and 2138 ms. The views were 18,561 and 12,764 ms from navigation, before their first possible 30-second recovery poll. The test requires the event revision to exceed the watermark recorded immediately before the write. |
| Interrupted transport | Before the missed write, Playwright's context-scoped WebSocket route passed real frames unchanged to API 2. The harness remounted Stage Overview before interruption, required a new project-subscription acknowledgement, and recorded that page's new navigation and document identity. It then blocked new API 2 notification negotiations, closed the two real upstream notification transports, and required CDP to observe both corresponding browser socket closes. It marked only that browser context offline; the screening write committed through API 1. No application hub.stop, page reload during interruption or recovery, fake event, or shared-network rule was used. |
| Automatic Angular recovery | After returning online, both existing API 2 Stage Overview and Stage Review clients opened new real notification sockets and received a successful SubscribeToProject acknowledgement correlated by socket and invocation ID. Each made an authenticated API 2 catch-up read and rendered the third screened study. Overview read and render occurred 7992 and 8771 ms after its pre-interruption remount, before its own first possible recovery poll; its render was 2916 ms after returning online. Stage Review read and render occurred 13,562 and 14,250 ms after navigation, also before its first possible recovery poll; its render was 2934 ms after returning online. Both page URLs and document performance.timeOrigin values were unchanged across interruption and recovery, and the unsaved annotation textbox value remained intact. |
| Result | 4 Playwright cases passed (three seeded-role setup cases and one focused proof), 0 failed, in 1.4 minutes. Chromium namespace preflight, TypeScript, and whitespace checks passed. |
This proves two distinct local API hosts and automatic reconnection of an existing Angular client with a preserved draft. It does not establish deployed staging two-pod delivery, staging permissions, rollback, or a soak. Those remain separate acceptance gates using dedicated real staging test accounts. The local E2ETest auth endpoint must not be enabled on shared staging.