Skip to content

refactor: wave 4 — TanStack Query API layer + convert worst fetch hotspot#52

Merged
ty13r merged 1 commit intomainfrom
refactor/wave-4-frontend-api-layer
Apr 19, 2026
Merged

refactor: wave 4 — TanStack Query API layer + convert worst fetch hotspot#52
ty13r merged 1 commit intomainfrom
refactor/wave-4-frontend-api-layer

Conversation

@ty13r
Copy link
Copy Markdown
Owner

@ty13r ty13r commented Apr 19, 2026

Summary

Wave 4 of the clean-code overhaul — establishes the frontend API layer called for in docs/clean-code.md §8 ("Server state via TanStack Query. No raw fetch() in components. Ever.").

New infrastructure

  • src/api/client.ts — typed fetch wrapper with ApiError (status + FastAPI detail surfacing), JSON / text / blob variants, consistent Content-Type handling.
  • src/api/hooks/runs.ts — typed React Query hooks for the /api/runs/* endpoint family: useRun, useRunReport, useRunDimensions, useRunLineage, useRunSkillMd, useFamilyVariants, useBenchFamily. Keyed consistently (["run", id, ...]) so cache dedup and invalidation work out of the box.
  • src/main.tsxQueryClientProvider with SKLD-tuned defaults (retry=1, no refetch-on-window-focus, staleTime=30s). WebSockets remain the real-time source of truth.

Exemplar conversion: AtomicRunDetail.tsx

The worst fetch hotspot in the codebase, per the Wave 0 exploration. Every data-fetching useEffect replaced with a hook call:

Before After
LOC 738 625
useEffect 7 0
useState 9 1 (activeTab)
raw fetch() 6 0

Manual loading/error/retry state removed. Component now only owns UI state.

Deferred

The other 18 components with raw fetch() calls are not converted in this PR on purpose. Each is already queued for Wave 5 (frontend hotspot decomposition), where components will be opened and decomposed anyway. Bulk-converting here would create churn we'd immediately redo in Wave 5.

The pattern is established — api/hooks/ grows per endpoint family; components import from @/api/hooks/....

Test plan

  • cd frontend && npm run lint — clean
  • cd frontend && npm run format:check — clean
  • cd frontend && npm run build — passes
  • cd frontend && npm run test — 35/35 pass
  • Backend untouched — still green

Manual verification

Open the app, navigate to any run detail page with evolution_mode: "atomic" (the seed runs qualify), confirm:

  • Network tab shows one request per endpoint (no duplicates from the old multi-effect pattern)
  • Loading/error states render (if backend is stopped mid-load)
  • Re-navigating to the same run uses the cache (no request)

🤖 Generated with Claude Code

Adds a proper API layer so no component has to call fetch() directly
and no data-fetching useEffect has to be hand-rolled. See
docs/clean-code.md §8.

New infrastructure
------------------
- src/api/client.ts: typed fetch wrapper (ApiError with status + detail,
  JSON / text / blob variants, FastAPI `detail` surfacing).

- src/api/hooks/runs.ts: typed React Query hooks for the run-detail
  endpoint family — useRun, useRunReport, useRunDimensions,
  useRunLineage, useRunSkillMd, useFamilyVariants, useBenchFamily.
  Every hook keyed consistently (["run", id, ...]) so cache dedup and
  invalidation work cleanly.

- src/main.tsx: QueryClientProvider with SKLD-tuned defaults —
  retry=1, refetchOnWindowFocus=false, staleTime=30s. We don't need
  aggressive background refetch because WebSockets are the real-time
  source of truth.

Exemplar conversion
-------------------
AtomicRunDetail.tsx — the worst fetch-hotspot in the codebase.

  Before: 738 LOC, 7 useEffect, 9 useState, 6 raw fetch() calls.
  After:  625 LOC, 0 useEffect, 1 useState, 0 raw fetch calls.

All data-fetching replaced with hook calls. Manual loading/error/retry
state removed. Component now only owns UI state (the active tab).

Other 18 components with raw fetch() calls are deferred — the pattern
is established and each can be converted as part of Wave 5 (frontend
hotspot decomposition) when each component is already being opened.

QA
--
  frontend lint            - clean
  frontend format:check    - clean
  frontend build           - passes
  frontend vitest          - 35/35 pass
  backend untouched        - still green

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ty13r ty13r merged commit 22d03a8 into main Apr 19, 2026
2 checks passed
@ty13r ty13r deleted the refactor/wave-4-frontend-api-layer branch April 19, 2026 18:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant