refactor: wave 4 — TanStack Query API layer + convert worst fetch hotspot#52
Merged
refactor: wave 4 — TanStack Query API layer + convert worst fetch hotspot#52
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 rawfetch()in components. Ever.").New infrastructure
src/api/client.ts— typed fetch wrapper withApiError(status + FastAPIdetailsurfacing), JSON / text / blob variants, consistentContent-Typehandling.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.tsx—QueryClientProviderwith 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
useEffectreplaced with a hook call:useEffectuseStatefetch()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— cleancd frontend && npm run format:check— cleancd frontend && npm run build— passescd frontend && npm run test— 35/35 passManual verification
Open the app, navigate to any run detail page with
evolution_mode: "atomic"(the seed runs qualify), confirm:🤖 Generated with Claude Code