You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- schedule_picklist.ps1: update event key to 2026gal, start date 2026-04-29
- tba.py: fix prior event selection to skip events with no COPR/OPR data;
add get_prior_event_oprs() for per-team prior DPR fallback
- frc2026_picklist_analysis.py: fix per-team EPA weight redistribution when
prior COPR missing; add blended foulPoints and dprs to picklist output;
fix Unicode arrow in print statement
- frc2026_picklist_runner.py: wire in prior_oprs_df; fix first_event_teams
to use teams_with_prior set instead of prior_coprs_df index
- .gitignore: exclude *.csv and *.txt local cache files
- CLAUDE.md: add initial codebase documentation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pre-commit hooks run both automatically on every commit.
33
+
34
+
## Architecture
35
+
36
+
This is a Python pipeline that pulls scouting data from multiple sources, blends them into team rankings, and publishes JSON to GitHub where a static webapp reads it.
37
+
38
+
**Entry point:**`src/scouting_analysis/frc2026_picklist_runner.py` → `main()` (registered as `run_picklist` CLI command in `pyproject.toml`)
39
+
40
+
### Data Sources
41
+
42
+
| Module | Source | What it provides |
43
+
|--------|--------|-----------------|
44
+
|`tba.py`| The Blue Alliance API | Team list, match schedule, match breakdowns, COPR, OPR |
45
+
|`sb.py`| Statbotics API | EPA (Expected Points Added) per phase per team |
46
+
|`sdb.py`|`api2.lanzersys.com` (4607 internal) | Raw scouting observations, pit data (hopper size) |
47
+
48
+
All fetched data is cached locally as CSV files and reused on subsequent runs. `--force` bypasses the cache.
49
+
50
+
### Core Scoring (frc2026_picklist_analysis.py)
51
+
52
+
`FRC2026PicklistAnalysis` blends data with **dynamic weights** that shift as the event progresses:
53
+
54
+
```
55
+
alpha = played_quals / total_quals # 0.0 → 1.0 through the event
-`webapp/latest_picklist.json` / `webapp/latest_planner.json` — what the webapp actively reads (`--post` flag)
70
+
71
+
GitHub Actions (`.github/workflows/notify_slack.yaml`) detects pushes to `webapp/latest_*.json` and sends a Slack notification.
72
+
73
+
### Webapp
74
+
75
+
Static HTML/CSS/JS in `webapp/` — no build step. `planner.html` and `picklist.html` fetch JSON from `raw.githubusercontent.com`. Changes to HTML deploy immediately on push.
76
+
77
+
## Environment
78
+
79
+
Requires a `.env` file (never committed) with:
80
+
```
81
+
X-TBA-Auth-Key=<TBA personal API key>
82
+
GITHUB_TOKEN=<GitHub PAT with repo write access>
83
+
WORKSPACE=<absolute path to project root>
84
+
PYTHONPYCACHEPREFIX=C:\Windows\Temp
85
+
```
86
+
87
+
## Key Implementation Details
88
+
89
+
**CSV parsing in `sdb.py`:** The internal scouting database returns malformed CSV (rows split across lines, extra commas in text fields). The parser explicitly handles both cases: stitching split rows together and truncating over-wide rows at the comments column.
**Prior event COPRs:** For teams with prior events, the runner fetches and averages their previous COPR values as a fallback when current-event data is sparse.
94
+
95
+
**GitHub push:** Uses the GitHub Contents API (requires fetching the existing file's SHA before updating).
96
+
97
+
**NaN sanitization:** All floats are sanitized before `json.dumps` because `NaN` is invalid JSON.
0 commit comments