No description
  • Python 83%
  • JavaScript 9.6%
  • CSS 6.6%
  • HTML 0.5%
  • PowerShell 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
fpl-app eb9a7d6f48
All checks were successful
CI / syntax (push) Successful in 9s
CI / tests (push) Successful in 2m53s
CI / wheel (push) Successful in 30s
test: the absence test checks the analytic DEFCON minutes stay gone
It pinned the line inside pipeline._defcon_minutes, which went in 1376c77 with the second DEFCON it fed. Its requirement, that availability scales minutes and appearance together, stands on its other assertions (the simulator is handed the availability-scaled start and play chances); the pinned line is now asserted absent, as the test already asserts of the analytic appearance term. Found by the worktree suite.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NC5YiwXhE63nM2MrtACdkP
2026-10-20 17:19:50 +02:00
.claude fix: the kit's Stop hook is switched off in this repo 2026-09-12 23:10:32 +02:00
.forgejo/workflows ci: browser tests are a local suite, not a CI job 2026-09-18 23:46:38 +02:00
backend fix: the DEFCON column and the card read the simulator's DEFCON; the second computation goes 2026-10-20 16:43:34 +02:00
data data: the planner test's 2025/26 verdict 2026-10-09 10:51:01 +02:00
docs docs: the DEFCON column fixed (1376c77): CLAUDE.md's entry and the floodlit spec's phase-3 item say so 2026-10-20 16:47:26 +02:00
frontend fix: the DEFCON column and the card read the simulator's DEFCON; the second computation goes 2026-10-20 16:43:34 +02:00
scripts fix: the DEFCON column and the card read the simulator's DEFCON; the second computation goes 2026-10-20 16:43:34 +02:00
tests test: the absence test checks the analytic DEFCON minutes stay gone 2026-10-20 17:19:50 +02:00
wiki wiki: the DEFCON column reads the simulator's DEFCON; audit defect 7 struck; 3 stale pages re-verified 2026-10-20 16:47:26 +02:00
.gitignore build: the start challenger's models are ignored, as its spec says 2026-10-20 14:35:39 +02:00
build-to-gw1.md feat: wire backfill into the pipeline, foreign-league rates, captaincy 2026-07-26 16:28:03 +02:00
CLAUDE.md docs: the DEFCON column fixed (1376c77): CLAUDE.md's entry and the floodlit spec's phase-3 item say so 2026-10-20 16:47:26 +02:00
constraints.txt build: scikit-learn 1.9.1 for the start challenger (scripts only) 2026-10-20 10:40:51 +02:00
pyproject.toml build: scikit-learn 1.9.1 for the start challenger (scripts only) 2026-10-20 10:40:51 +02:00
README.md ci: browser tests are a local suite, not a CI job 2026-09-18 23:46:38 +02:00
run.bat feat: the goalscorer list is ordered by the book, not by us 2026-08-15 20:15:58 +02:00
run.ps1 fix: enforce the local-only trust boundary in the app, not the launcher (issue #2) 2026-08-24 19:04:40 +02:00

FPL squad optimiser

An evidence-conscious Fantasy Premier League projection and squad-planning app. It combines official FPL data, historical match and player data, simulations, availability estimates, optional market data, and FPL squad rules to produce a rolling six-gameweek view.

The application includes:

  • player and fixture projections;
  • best-XI, captain and vice-captain analysis;
  • squad building and automatic squad optimisation;
  • transfer, ownership and fixture views;
  • explicit provenance and refusal states for weak or missing inputs;
  • backtesting and calibration utilities;
  • point-in-time snapshots for auditable decisions.

The project is intended primarily as a local decision-support tool. It is not a hosted multi-user service, and its write/rebuild endpoints currently have no authentication.

Repository map

Path Purpose
backend/data/ Official FPL client, typed data models, SQLite store and sanity checks
backend/model/ Minutes, team strength, finishing, lineup and suspension models
backend/scoring/ FPL scoring, BPS and defensive-contribution rules
backend/simulator/ Match and fixture Monte Carlo simulation
backend/odds/ Odds ingestion, name matching and market comparison
backend/web/ Projection pipeline, optimiser, cache and FastAPI application
frontend/ Static HTML, CSS and JavaScript client
scripts/ Cache builds, data acquisition, diagnostics and backtests
tests/ Unit, integration, API and browser tests
data/ Committed inputs and evidence artifacts; generated local state is ignored
docs/ Designs, methodology notes and maintainer documentation

See Architecture, Development, and API reference for more detail. Contributors should read CLAUDE.md before changing model or data-flow code; it records the failure modes and invariants that shape this repository.

Quick start

Python 3.11 or newer is required. One command creates an environment and runs the suite from a clean checkout:

python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e ".[test]" -c constraints.txt

constraints.txt records the versions this suite has actually been run against. It is not a lockfile - it does not pin transitive dependencies - but it makes a failure attributable rather than a guess, given that pyproject.toml declares only lower bounds.

Build the projection cache, then start the app from the repository root:

python scripts/build_cache.py
python -m uvicorn backend.web.main:app --host 127.0.0.1 --port 8000

Open http://127.0.0.1:8000/. Keep the server on loopback: administrative routes can rebuild projections and write local state.

On Windows, use the included launcher:

run.bat
run.bat -Restart
run.bat -Port 8123

The server can start in cache-only mode if live dependencies cannot be loaded. In that state, read-only cached views remain available, while operations that need the complete dependency graph return 503.

Common workflows

Rebuild projections after model or source-data changes:

python scripts/build_cache.py

Verify that a change moved no projections (the golden master):

python scripts/golden_master.py

It exits 0 when every frozen field matches, 1 when something moved, and 2 when the cache predates the current code — in which case rebuild first, because a comparison against a stale cache proves nothing.

Refresh only live prices, ownership and availability while the server runs:

curl -X POST http://127.0.0.1:8000/api/refresh-live

Take an immutable point-in-time snapshot before a deadline:

python scripts/snapshot_pit.py

Ingest a finished gameweek so the model learns from the current season:

python scripts/fetch_current_season.py

Run the principal walk-forward evaluations:

python scripts/backtest_rps.py
python scripts/backtest_minutes.py

Run tests after installing the test dependencies:

python -m pytest

Browser tests use Playwright and are skipped when it is unavailable. CI does not install it, so these run locally only: run them before pushing a change to rendered frontend behavior, from the versions pinned in constraints.txt:

python -m pip install -e ".[test,browser]" -c constraints.txt
python -m playwright install chromium
python -m pytest tests/web

Generated local state

The application writes these ignored files:

  • data/cache/projections.json — projection cache;
  • data/fpl.db — SQLite store, rebuildable with scripts/import_archive.py;
  • data/squad.json — current squad selection;
  • data/overrides.json — explicit start-probability overrides;
  • data/pit/ — point-in-time snapshots.

data/golden/baseline.json is committed rather than ignored: it is the reference the golden master compares against, and it is only useful if it travels with the code it describes.

Projection artifacts carry build time and source-code provenance. Missing or invalid provenance is intentionally treated as an error rather than silently replaced with a plausible default.

Data sources

The official FPL API is the primary live source. The repository also contains historical archive data and optional pipelines for Transfermarkt, Understat, Solio and bookmaker player props. Some acquisition scripts may require external credentials, metered APIs or pre-registered run scopes. Read their help and the data-source rules in CLAUDE.md before running them.

Current maintenance notes

The repository review is tracked in Forgejo issues. Known improvement areas include clean-checkout dependency locking and CI, package discovery, persistence concurrency, API request models and module decomposition.

HTML interpolation (issue #1) is partially addressed: the frontend's esc() helper was a JavaScript-string escaper carrying an HTML escaper's name, and now escapes &, <, >, " and ' in a single pass. Remaining interpolation sites have not been audited.

This documentation describes the current implementation rather than implying those items are resolved.