Tests canvas/src/lib/hydrate.ts: hydrateCanvas() with exponential backoff retry.
Cases:
1. Success on first attempt → { error: null }
2. Viewport fetch failure is non-fatal → store still hydrates
3. Success after 1 retry → onRetrying(1) called once, result { error: null }
4. onRetrying called correctly on each failed attempt
5. All attempts fail → error message after MAX_RETRIES
6. onRetrying called MAX_RETRIES-1 times before final exhausted attempt
7. Total elapsed time ≈ sum of exponential delays (1s + 2s = 3s)
Each attempt makes 2 parallel api.get calls (workspaces + viewport); mocks
set up per parallel-call to avoid Promise.all consuming wrong mock slots.
Issue: #701
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>