feat(canvas): A2ATopologyOverlay → ACTIVITY_LOGGED subscriber (#61 stage 2) #71
Loading…
Reference in New Issue
Block a user
No description provided.
Delete Branch "feat/canvas-topology-overlay-ws-subscribe"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Stage 2 of #61.
A2ATopologyOverlayno longer polls/workspaces/:id/activity?type=delegationon a 60s interval; it bootstraps once on mount (and on visible-ID-set change) and subscribes toACTIVITY_LOGGEDvia the existinguseSocketEventbus for live updates.Stage 1 (CommunicationOverlay) is PR #69 and uses the same shape.
What this PR changes
buildA2AEdgesThe 2026-05-04 render-loop fix (visibleIdsKey-keyed Zustand selector) is preserved — peer-discovery / status-flip writes still don't trigger a wasteful re-bootstrap.
SSOT decision
Same as Stage 1:
useSocketEventis the single subscription primitive. The aggregation logic lives in the existingbuildA2AEdgespure function — bootstrap and WS-push paths both feed it identical row shapes (ActivityEntry).Race-aware bootstrap
WS arrivals during the bootstrap fetch are preserved by id-dedup-with-fetched-first ordering:
[...fetchedRows, ...bufferRef.current]then dedup. No row is double-counted; no row is lost when a WS push lands between the fetch start and resume.Tests
canvas/src/components/__tests__/A2ATopologyOverlay.test.tsx— 33 tests, all PASS:buildA2AEdgespurity preserved, component visibility/visibleIdsKey/error-swallow behaviour preserved)buildA2AEdgesmethod filter)Full canvas suite: 1395 passing, 0 failing.
pnpm tsc --noEmitclean.Mutation tests
Security check
ChatTab,AgentCommsPanel, and (post-PR #69)CommunicationOverlayalready trust. The handler treats every payload field as optional/coercible.Versioning + backwards compat
/workspaces/:id/activitystill used for bootstrap)Hostile self-review — three weakest spots
buildA2AEdgesaggregates to at most N² edges.useSocketEvent's ref-based pattern means the bus subscription stays stable across renders, but the handler closure re-capturesbootstrapeach render. Side effect: fine — handler just callsrecomputeAndPush, which is idempotent.delegate_resultrows arriving over WS are silently dropped. Acceptable: the existingbuildA2AEdgesalready filters them at aggregation time (avoids double-counting). Pre-filtering at the WS handler keeps the bus path and bootstrap path consistent.Rollout / rollback
git revertthe merge — overlay falls back to the 60s polling shape.Out of scope (still tracked under #61)
ActivityTab(5s × 1 active workspace — separate PR; depends on this Stage's WS-buffer pattern)🤖 Generated with Claude Code
Cross-persona review (devops-engineer ↔ claude-ceo-assistant author): five-axes pass per SOP. Tests: full local suite green at each stage; mutation tests caught targeted regressions. Security: no auth/data/access changes. Approved.