fix: address remaining bugbot review issues from PR #26

- SSE: separate service errors from enqueue errors so transient failures
  skip the poll instead of permanently killing the stream
- SSE: send single snapshot event per poll instead of N per-session
  activity events (matches SSESnapshotEvent type, constant traffic)
- Stats: only count reviewDecision === "pending" as needing review,
  not "none" (which is the unenriched default)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Prateek 2026-02-14 20:24:33 +05:30
parent 77c9411f9c
commit 52fc10f0eb
2 changed files with 17 additions and 14 deletions

View File

@ -56,22 +56,28 @@ export async function GET(): Promise<Response> {
// Poll for session state changes every 5 seconds
updates = setInterval(() => {
void (async () => {
let dashboardSessions;
try {
const { sessionManager } = await getServices();
const sessions = await sessionManager.list();
const dashboardSessions = sessions.map(sessionToDashboard);
dashboardSessions = sessions.map(sessionToDashboard);
} catch {
// Transient service error — skip this poll, retry on next interval
return;
}
for (const s of dashboardSessions) {
const event = {
type: "session.activity",
sessionId: s.id,
activity: s.activity,
try {
const event = {
type: "snapshot",
sessions: dashboardSessions.map((s) => ({
id: s.id,
status: s.status,
activity: s.activity,
attentionLevel: getAttentionLevel(s),
timestamp: new Date().toISOString(),
};
controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}\n\n`));
}
lastActivityAt: s.lastActivityAt,
})),
};
controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}\n\n`));
} catch {
// enqueue failure means the stream is closed — clean up both intervals
clearInterval(updates);

View File

@ -123,10 +123,7 @@ export function computeStats(sessions: DashboardSession[]): DashboardStats {
workingSessions: sessions.filter((s) => s.activity === "active").length,
openPRs: sessions.filter((s) => s.pr?.state === "open").length,
needsReview: sessions.filter(
(s) =>
s.pr &&
!s.pr.isDraft &&
(s.pr.reviewDecision === "pending" || s.pr.reviewDecision === "none"),
(s) => s.pr && !s.pr.isDraft && s.pr.reviewDecision === "pending",
).length,
};
}