forked from molecule-ai/molecule-core
Selector instability caused fetchAndUpdate to recreate on every Zustand nodes[] mutation (status flips, position drags, peer-discovery writes, heartbeats — typically ~5/sec). Each recreation invalidated the useEffect deps so the 60s polling fan-out fired on every update, hammering /workspaces/<id>/activity?type=delegation 5×N requests/sec until the edge rate-limit returned 429. User-reported via browser console showing infinite uE→ux→uE→ux render loop and 429s repeating across every visible workspace ID. Root cause: const nodes = useCanvasStore((s) => s.nodes); const visibleIds = useMemo(() => nodes.filter(...).map(...), [nodes]); // useMemo dep recreates on every store update, even when ID set unchanged Fix: select a STABLE STRING KEY (sorted CSV of visible IDs) from Zustand. The selector's shallow-equal short-circuit prevents re-renders when the actual visible-ID set is unchanged, so visibleIds reference stays stable, fetchAndUpdate keeps its identity, and the useEffect only re-fires when the visible-ID-set genuinely changes. Tests: - New regression test "does not re-fetch when nodes[] reference changes but visible IDs are the same" - Discipline-verified: pre-fix code emits 4 fetches (2 mount + 2 re-fetch storm), post-fix emits exactly 2 - Companion test "re-fetches when the visible ID set actually changes" pins the desired behavior so future "stabilization" doesn't suppress legitimate updates Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| e2e | ||
| public | ||
| src | ||
| .env.example | ||
| .gitignore | ||
| components.json | ||
| Dockerfile | ||
| next.config.ts | ||
| package-lock.json | ||
| package.json | ||
| playwright.config.ts | ||
| playwright.staging.config.ts | ||
| postcss.config.js | ||
| tsconfig.json | ||
| vitest.config.ts | ||