Split oversized modules and consolidate cascading CSS overrides #7
Labels
No labels
architecture
cleanup
dependencies
performance
priority: high
priority: medium
reliability
security
testing
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
solvreven/FPL#7
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Finding
Several files have become change hotspots with unrelated responsibilities:
frontend/app.js: 4,693 lines, roughly 272 top-level globals/functions, rendering and state for every surface.frontend/style.css: 2,544 lines, with repeated selectors whose later definitions silently win..pitchappears repeatedly across the file; band and bench selectors are also duplicated.backend/web/pipeline.py: 1,442 lines;build_players_index()alone spans 348 lines.backend/web/main.py: 1,351 lines, combining app lifecycle, cache state, presentation shaping, simulation helpers, persistence, and routes.CLAUDE.mdalready records that reading the first matching CSS rule led to incorrect conclusions because appended overrides hid the binding rule. This is therefore demonstrated maintenance risk, not a stylistic preference.Suggested direction
Acceptance criteria
This refactor needs a narrower first boundary so it can be completed and reviewed without mixing several unrelated migrations. Which slice should land first?
backend/web/pipeline.pystage extraction, orPlease also confirm whether ES modules and multiple browser-loaded JS files are acceptable, and whether this issue should be split into one issue per slice. The current acceptance criterion (“no core module remains a catch-all”) does not define a reviewable stopping point for a single change.
Agreed that the current acceptance criterion has no stopping point, and the request for a narrower first boundary is right. Answering the three questions, with line counts measured just now.
Which slice first:
backend/web/main.py, and specifically the ODDS AND MARKET endpoints.Not because it is the largest —
app.jsis — but because it is the only one of the four with a seam that is already load-bearing.props_load.py,nt_load.py,nt_market.pyandbackend/odds/exist and are separate; what sits inmain.pyis the thin HTTP layer over them, plus a lot that has drifted in. Extracting/api/market,/api/matchesand the props endpoints intobackend/web/routes/odds.pymoves ~400 lines against an interface that is already tested, and nothing else has to move with it.Explicitly NOT the CSS.
.pitchwas consolidated on 2026-08-27 (nine rules to one; 15 of 28 declarations never bound) and the result is gated bytests/web/test_css_characterization.py, which renders the live stylesheet against a frozen baseline and compares every element's full computed style across four tabs and twelve widths. That gate exists because the last consolidation nearly shipped a regression invisible at 1600px: the@media (max-width: 1180px)override sat 90 lines above where the merged rule landed, same specificity, so position decided. Further CSS consolidation is high-risk and low-value while the file is already gated; if it happens it should be last, not first.ES modules: yes, but not in this slice.
index.htmlloads four files with?v=NNNcache-busting, and that version is enforced bytests/web/test_asset_version.py(digest of all four assets; bumping one without the other fails). Moving to ES modules means either that guard grows to cover a module graph or it is replaced by a bundler — a separate decision with its own failure modes, and it should not ride along with a backend extraction. Splittingapp.jsis the second slice, not the first.Yes, split the issue — one per slice, with this as the tracking issue. Concretely:
main.py→routes/odds.py(this one; ~400 lines, existing tests cover the behaviour)main.py→routes/squad.py+routes/players.pypipeline.py→ stage extraction (build / project / warn)app.js→ ES modules, with the asset-version guard rebuilt firstA reviewable stopping point for each: the characterisation gate must be green with no re-baseline. For the backend slices that means the full suite passes unchanged; for the CSS slice it means
test_css_characterization.pypasses against the existing baseline. "Re-baseline deliberately when a design change is intended; never to make it pass" is already the rule in CLAUDE.md, and it is what turns "no core module remains a catch-all" into something a reviewer can check.Split into reviewable child issues, in order:
This issue remains the tracking issue. Each child has a no-rebaseline characterization gate.