Files
boss/docs/superpowers/plans/2026-04-10-sse-refresh-noise-reduction.md
2026-04-10 12:55:43 +08:00

7.0 KiB

SSE Refresh Noise Reduction Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Reduce unnecessary realtime reloads on scoped conversation folder pages without breaking global conversation refresh behavior.

Architecture: Keep server-side event names stable and narrow consumption at scoped clients. The shared Web realtime refresh utility accepts optional device scope, while the Android folder activity applies the same project-first, device-only fallback filter.

Tech Stack: Next.js App Router, TypeScript node:test, Android Java native activities, Server-Sent Events.


Task 1: Add Device Scope To Shared Web Refresh Filtering

Files:

  • Modify: src/lib/realtime-refresh.ts

  • Test: tests/realtime-refresh-utils.test.ts

  • Step 1: Write the failing tests

assert.equal(
  shouldRefreshRealtimeEvent({
    eventType: "conversation.updated",
    eventData: JSON.stringify({ deviceId: "mac-studio" }),
    projectIds: ["project-a", "project-b"],
    deviceId: "mac-studio",
  }),
  true,
);

assert.equal(
  shouldRefreshRealtimeEvent({
    eventType: "conversation.updated",
    eventData: JSON.stringify({ deviceId: "windows-box" }),
    projectIds: ["project-a", "project-b"],
    deviceId: "mac-studio",
  }),
  false,
);
  • Step 2: Run the focused test and verify the new device-scope test fails

Run: npx tsx --test tests/realtime-refresh-utils.test.ts

Expected: the new device-scope case fails before deviceId support exists in RealtimeRefreshScope.

  • Step 3: Add minimal device scope support
export interface RealtimeRefreshScope {
  projectId?: string;
  projectIds?: string[];
  deviceId?: string;
  deviceIds?: string[];
  conversationUpdatedNotes?: string[];
}

Then parse deviceId from the JSON payload and require scoped listeners to match at least one scoped project or device identifier before refreshing.

  • Step 4: Run the focused test and verify it passes

Run: npx tsx --test tests/realtime-refresh-utils.test.ts

Expected: all realtime refresh utility tests pass.

Task 2: Wire Web Folder Device Scope

Files:

  • Modify: src/components/app-runtime.tsx

  • Modify: src/app/conversations/folders/[folderKey]/page.tsx

  • Test: tests/project-scoped-realtime-refresh.test.ts

  • Step 1: Write the failing route wiring assertion

assert.match(
  folderPage,
  /deviceId=\{folder\.deviceId\}/,
  "expected folder page to scope device-only refreshes to the folder device",
);
  • Step 2: Run the route test and verify the assertion fails

Run: npx tsx --test tests/project-scoped-realtime-refresh.test.ts

Expected: the assertion fails until the folder page passes deviceId.

  • Step 3: Pass device scope through the runtime component
<RealtimeRefresh
  projectIds={folder.threads.map((thread) => thread.projectId)}
  deviceId={folder.deviceId}
  events={["conversation.updated", "project.messages.updated"]}
/>

Also pass deviceId and deviceIds from RealtimeRefresh into shouldRefreshRealtimeEvent.

  • Step 4: Run the route test and verify it passes

Run: npx tsx --test tests/project-scoped-realtime-refresh.test.ts

Expected: the folder route wiring test passes.

Task 3: Mirror Filtering In Android Folder Activity

Files:

  • Modify: android/app/src/main/java/com/hyzq/boss/ConversationFolderActivity.java

  • Test: tests/android-folder-realtime-refresh.test.ts

  • Step 1: Write the failing Android source assertion

assert.match(
  source,
  /String payloadDeviceId = event\.payload\.optString\("deviceId", ""\)\.trim\(\);/,
  "expected folder activity to inspect device-scoped realtime payloads",
);
  • Step 2: Run the Android static test and verify it fails

Run: npx tsx --test tests/android-folder-realtime-refresh.test.ts

Expected: the test fails until the folder activity reads deviceId.

  • Step 3: Add project-first and device-only filtering
String payloadProjectId = event.payload.optString("projectId", "").trim();
if (!payloadProjectId.isEmpty()) {
    return trackedProjectIds.contains(payloadProjectId)
            || (!targetProjectIds.isEmpty() && targetProjectIds.contains(payloadProjectId))
            || (targetProjectId != null && targetProjectId.equals(payloadProjectId));
}
String payloadDeviceId = event.payload.optString("deviceId", "").trim();
if (payloadDeviceId.isEmpty() || folderDeviceId == null || folderDeviceId.isEmpty()) {
    return false;
}
return payloadDeviceId.equals(folderDeviceId);
  • Step 4: Run the Android static test and verify it passes

Run: npx tsx --test tests/android-folder-realtime-refresh.test.ts

Expected: the Android folder realtime filtering test passes.

Task 4: Verify Integration

Files:

  • Verify: src/lib/realtime-refresh.ts

  • Verify: src/components/app-runtime.tsx

  • Verify: src/app/conversations/folders/[folderKey]/page.tsx

  • Verify: android/app/src/main/java/com/hyzq/boss/ConversationFolderActivity.java

  • Verify: scripts/deploy-server.sh

  • Step 1: Run focused realtime tests

Run: npx tsx --test tests/realtime-refresh-utils.test.ts tests/project-scoped-realtime-refresh.test.ts tests/android-folder-realtime-refresh.test.ts

Expected: all focused realtime tests pass.

  • Step 2: Run deployment script guard test

Run: npx tsx --test tests/deploy-server-script.test.ts

Expected: the deploy script tests pass and assert .project, .classpath, and .settings are excluded from rsync.

  • Step 3: Run broader realtime page tests

Run: npx tsx --test tests/realtime-refresh-utils.test.ts tests/project-scoped-realtime-refresh.test.ts tests/android-folder-realtime-refresh.test.ts tests/config-pages-realtime-refresh.test.ts tests/config-state-events.test.ts tests/settings-page-realtime-refresh.test.ts tests/settings-state-events.test.ts tests/status-pages-realtime-refresh.test.ts

Expected: all selected realtime and event contract tests pass.

  • Step 4: Run project gates

Run: npm run lint

Expected: lint exits 0.

Run: npm run build

Expected: production build exits 0.

  • Step 5: Stage only intended files
git add src/lib/realtime-refresh.ts src/components/app-runtime.tsx 'src/app/conversations/folders/[folderKey]/page.tsx' tests/realtime-refresh-utils.test.ts tests/project-scoped-realtime-refresh.test.ts tests/android-folder-realtime-refresh.test.ts android/app/src/main/java/com/hyzq/boss/ConversationFolderActivity.java scripts/deploy-server.sh tests/deploy-server-script.test.ts docs/superpowers/specs/2026-04-10-sse-refresh-noise-reduction-design.md docs/superpowers/plans/2026-04-10-sse-refresh-noise-reduction.md

Expected: generated IDE metadata under android/.project, android/.settings, android/app/.project, android/app/.settings, and android/app/.classpath remains untracked.