Bug Description
Clicking the "➕ New Session" button on a connected codespace group (green dot) does nothing — no new session is created, no error is shown to the user.
Root Cause
Three independent bugs combine to create this silent failure:
1. Fire-and-forget async lambda (silent exception swallowing)
The @onclick handler in SessionSidebar.razor uses a void-returning lambda that calls an async Task method:
@onclick="() => { openGroupMenuId = null; QuickCreateSessionForCodespace(gId); }"
In Blazor, @onclick with a void delegate (Action) does NOT await the returned Task. When QuickCreateSessionForCodespace hits its first await (calling CreateSessionAsync), it yields — and Blazor has no reference to the Task. Any exception thrown during the async portion is silently swallowed as an unobserved Task exception. The UI never re-renders after the async work completes or fails.
2. Error message displayed in wrong UI section
QuickCreateSessionForCodespace correctly catches exceptions and stores them in createError, but this variable is only rendered in the CreateSessionForm component at the top of the sidebar — not in the codespace section where the user actually clicked. Even with Bug 1 fixed, the error would appear in a completely different part of the UI.
3. Health check does not detect dead remote copilot process
The codespace health check verifies:
- SSH tunnel process is alive (
tunnel.IsAlive) ✅
- CopilotClient exists in dictionary (
_codespaceClients.ContainsKey) ✅
But it never checks whether the remote copilot process is still listening on the tunnel port. An SSH tunnel can stay alive long after the remote copilot --headless process dies (e.g., codespace went to sleep and came back, copilot was killed manually). The green "connected" dot persists, the "New Session" button appears, but every CreateSessionAsync call fails because the HTTP request through the tunnel gets connection-refused.
Expected Behavior
- Clicking "New Session" on a connected codespace group should either create the session or show an error in the codespace section
- The health check should detect when the remote copilot dies behind a live tunnel and transition to reconnecting state
- Error messages from codespace operations should be visible to the user
Fix
- Async lambda: Change to
async () => { ... await QuickCreateSessionForCodespace(gId); } so Blazor properly awaits the Task and re-renders
- Error display: Show
createError in the codespace group section (below sessions)
- TCP probe: Add a TCP connection probe in the health check — when tunnel is alive and client exists, verify the remote port is actually reachable before marking the group as healthy
Affected Files
PolyPilot/Components/Layout/SessionSidebar.razor — void lambda, error display
PolyPilot/Components/Layout/SessionSidebar.razor.css — error styling
PolyPilot/Services/CopilotService.Codespace.cs — health check TCP probe
Related
Bug Description
Clicking the "➕ New Session" button on a connected codespace group (green dot) does nothing — no new session is created, no error is shown to the user.
Root Cause
Three independent bugs combine to create this silent failure:
1. Fire-and-forget async lambda (silent exception swallowing)
The
@onclickhandler inSessionSidebar.razoruses a void-returning lambda that calls anasync Taskmethod:In Blazor,
@onclickwith a void delegate (Action) does NOT await the returnedTask. WhenQuickCreateSessionForCodespacehits its firstawait(callingCreateSessionAsync), it yields — and Blazor has no reference to the Task. Any exception thrown during the async portion is silently swallowed as an unobserved Task exception. The UI never re-renders after the async work completes or fails.2. Error message displayed in wrong UI section
QuickCreateSessionForCodespacecorrectly catches exceptions and stores them increateError, but this variable is only rendered in theCreateSessionFormcomponent at the top of the sidebar — not in the codespace section where the user actually clicked. Even with Bug 1 fixed, the error would appear in a completely different part of the UI.3. Health check does not detect dead remote copilot process
The codespace health check verifies:
tunnel.IsAlive) ✅_codespaceClients.ContainsKey) ✅But it never checks whether the remote copilot process is still listening on the tunnel port. An SSH tunnel can stay alive long after the remote
copilot --headlessprocess dies (e.g., codespace went to sleep and came back, copilot was killed manually). The green "connected" dot persists, the "New Session" button appears, but everyCreateSessionAsynccall fails because the HTTP request through the tunnel gets connection-refused.Expected Behavior
Fix
async () => { ... await QuickCreateSessionForCodespace(gId); }so Blazor properly awaits the Task and re-renderscreateErrorin the codespace group section (below sessions)Affected Files
PolyPilot/Components/Layout/SessionSidebar.razor— void lambda, error displayPolyPilot/Components/Layout/SessionSidebar.razor.css— error stylingPolyPilot/Services/CopilotService.Codespace.cs— health check TCP probeRelated