Conversation
PackageExplorer was a 553-LOC god-component mixing file-list building,
tree rendering, file viewer, checklist rubric, and the master-detail
layout. Split along the obvious seams:
packageExplorer/types.ts shared VirtualFile + path helpers
packageExplorer/buildMeta.ts pure PACKAGE.md template builder
packageExplorer/buildFiles.ts pure partition into installable
+ metadata (fully unit-testable)
packageExplorer/FileTree.tsx collapsible directory widget
packageExplorer/GoldStandardChecklist.tsx
CLAUDE.md rubric comparison
PackageExplorer.tsx (197 LOC) orchestrator: master-detail layout,
ExplorerHeader + FileViewer
sub-components kept inline
Largest submodule is 132 LOC, under the 400-LOC TSX ceiling in
docs/clean-code.md §2.
Tests
-----
- packageExplorer/buildFiles.test.ts (5 tests) — pure tree-shaping logic:
SKILL.md first, supporting_files grouping, PACKAGE.md counts,
integration_report extraction, _meta/parents/*.md per winner.
- PackageExplorer.test.tsx (1 test, jsdom) — smoke test: renders with
fixture data, asserts installable + metadata counts + download link.
QA: frontend build, lint, format:check, 41 vitest tests (+6) all green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The "Start an Evolution Run" form was 561 LOC with 12 useState, 5 raw
fetch() calls (one useEffect + one submit branching to 3 endpoints),
and every layout concern inline. Decomposed along obvious seams:
specializationInput/types.ts SourceMode / EvolutionMode /
UploadResponse / SeedSummary
specializationInput/estimateCost.ts pure time+cost estimator
(calibrated from live runs)
specializationInput/startEvolution.ts pure API dispatcher — handles
all 3 source modes + 4
request shapes through one
typed signature
specializationInput/SourceModePicker Starting-Point radio grid
specializationInput/EvolutionModePicker Auto/Atomic/Classic radio
specializationInput/SeedPicker category-filter + seed grid
specializationInput/RunEstimateCard footer estimate + submit btn
api/hooks/seeds.ts typed useSeeds hook replacing
the raw /api/seeds fetch
SpecializationInput.tsx orchestrator — state + compose
Also inlined small ScratchBody / UploadBody / ForkBody /
GeneratedPackageBanner helpers in the main file; they're too
parent-coupled to merit their own module.
Tests
-----
- estimateCost.test.ts: 4 tests pinning the calibration points
(5x3 = 53min/$7.50; 2x1 = 9min/$2) and the hrs-vs-min rollover.
QA: frontend build, lint, format:check, 45 vitest tests (+4) all green.
Largest submodule is 96 LOC, under the 400-LOC TSX ceiling.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Homepage "How SKLD Works" section was 814 LOC with 12 inline SVG sub-components + the 12-entry STEPS config + the observer layout container. Split at the obvious seams: pipelineSteps/foundationVisuals.tsx (269) steps 1-6 SVG illustrations pipelineSteps/loopVisuals.tsx (335) steps 7-12 SVG illustrations pipelineSteps/steps.ts (119) Step type + STEPS data PipelineSteps.tsx (122) observer + scroll-reveal layout Biggest submodule is 335 LOC, under the 400-LOC TSX ceiling. QA: frontend build, lint, format:check, 45 vitest tests all green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The live-run arena was 541 LOC with 4 raw fetch() calls (including a
setInterval poller), 4 inline right-column cards, and the header
inlined. Converted to TanStack hooks + extracted sub-components.
Fetch -> hooks
--------------
- fetch("/api/runs/:id") -> useRun()
- fetch("/api/runs/:id/dimensions") -> useRunDimensions() with the new
`refetchInterval` option so React Query does the 5s poll (replaces
the hand-rolled setInterval + useEffect cleanup).
- fetch("/api/bench/summary") -> new useBenchSummary() hook
- fetch("/api/runs/:id/cancel") -> apiClient.post (POST action,
no caching needed)
Sub-components extracted
------------------------
evolutionArena/ArenaHeader (85) title + status + elapsed
+ budget + Cancel button
evolutionArena/CompositeScoring (54) 6-layer rubric card
evolutionArena/BaselineContext (53) raw-Sonnet baseline card
evolutionArena/PerDimensionPipeline (54) 5-step mini tracker
evolutionArena/CompletedDimensions (47) per-dim fitness list + avg
Inline CurrentChallenge + CompetitionPanel helpers kept in the main
file — they're too parent-coupled to merit their own modules.
Biggest submodule is 85 LOC, under the 400-LOC TSX ceiling.
QA: frontend build, lint, format:check, 45 vitest tests all 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
Decomposes the four remaining frontend hotspots called out in the Wave 6 PR. Each component above 400 LOC (
docs/clean-code.md§2 TSX ceiling) now has its rendering split into focused sub-components and its fetches converted to typed React Query hooks.PackageExplorer.tsxpackageExplorer/× 6 filesSpecializationInput.tsxspecializationInput/× 8 filesPipelineSteps.tsxpipelineSteps/× 3 filesEvolutionArena.tsxevolutionArena/× 5 filesPer-component highlights
PackageExplorer — tree-shaping logic (
buildFiles.ts), the file-tree widget, the checklist rubric, and the PACKAGE.md template each moved to their own module. Pure logic landed with 5 focused unit tests + one jsdom smoke test.SpecializationInput — the 5 raw
fetch()calls collapsed to one typed hook (useSeeds) + one pure dispatcher (startEvolution.ts) that handles all three source modes (scratch / upload / fork). Cost estimator extracted as a pure function with 4 calibration-point tests. SourceModePicker / EvolutionModePicker / SeedPicker / RunEstimateCard are now reusable.PipelineSteps — the 12 inline SVG mini-visualizations split into
foundationVisuals.tsx(steps 1-6) +loopVisuals.tsx(steps 7-12). Step metadata lives insteps.ts. Container is now 122 LOC of observer + layout.EvolutionArena — 4 raw fetch + 1 setInterval poller replaced with
useRun+useRunDimensions(refetchInterval)+ newuseBenchSummary. Right-column cards (ArenaHeader,CompositeScoring,BaselineContext,PerDimensionPipeline,CompletedDimensions) are their own files.New tests
packageExplorer/buildFiles.test.ts— 5 tests on the tree-shaping logicPackageExplorer.test.tsx— jsdom smoke testspecializationInput/estimateCost.test.ts— 4 calibration testsTest plan
cd frontend && npm run build— passescd frontend && npm run lint— cleancd frontend && npm run format:check— cleancd frontend && npm run test— 45 passed (up from 35)🤖 Generated with Claude Code