KRONECTOR β Implementation Plan (v2 β Corrected)
Tagline: Every sector. Every timeline. Predicted. Domain: F1 Race Intelligence β self-improving multi-agent AI system
Month 1, Week 1 β Data Pipelines (CURRENT FOCUS)
Deliverables
data/build_driver_map.pyβ Generatedrivers_map.json(run once at init)data/fastf1_pipeline.pyβ Fetch telemetry + session data for 2018β2024 (includesfetch_lap_data)data/jolpica_pipeline.pyβ Backfill race results, grid, pit stops, standings for 2014β2017data/__init__.pyβ Merge logic combining both sources on(season, round, driver_id)- Project scaffolding β all
__init__.pyfiles,.env,requirements.txt,.gitignore
Execution Order
- Run
build_driver_map.pyβ generatesdrivers_map.json - Run
jolpica_pipeline.pyfor 2014β2017 β Jolpica backfill - Run
fastf1_pipeline.pyfor 2023 only β verify schema - Run merge logic β verify unified 2023 dataset
- Scale
fastf1_pipeline.pyto 2018β2024 - Run full merge β final unified 2014β2024 dataset
- Run
pytest tests/test_data_pipelines.py -v
[NEW] Project Scaffolding
kronector/
βββ agents/__init__.py
βββ ml/__init__.py
βββ data/
β βββ __init__.py (merge logic)
β βββ fastf1_pipeline.py
β βββ jolpica_pipeline.py (renamed from ergast)
β βββ build_driver_map.py
βββ api/__init__.py
βββ ui/
βββ mlflow_config/
βββ tests/
βββ cache/fastf1/ (gitignored)
βββ drivers_map.json (generated by build_driver_map.py)
βββ requirements.txt
βββ .env
βββ .gitignore
βββ README.md
[NEW] build_driver_map.py
Purpose: One-time init script β maps FastF1 3-letter abbreviations to Jolpica slugs.
- Pull FastF1 driver list for 2014β2024 via
fastf1.get_event_schedule()+ session drivers - Pull Jolpica driver list via
/api/f1/drivers.json - Match on
full_nameβ derive Jolpica slug - Output:
drivers_map.jsonat project root
Rule: FastF1 abbreviation (VER) = master driver_id throughout entire system. Jolpica slug only for Jolpica API calls.
[NEW] fastf1_pipeline.py
Purpose: Fetch telemetry + session data from FastF1 for 2018β2024.
| Function | Description |
|---|---|
enable_cache(cache_dir) |
Configure FastF1 cache directory |
fetch_race_results(season, round_num) |
Race finishing order, grid positions |
fetch_qualifying(season, round_num) |
Qualifying sector times + missing data guard |
fetch_practice(season, round_num) |
FP2/FP3 average lap times |
fetch_tire_data(season, round_num) |
Tire compounds, stint lengths, fresh/used |
fetch_pit_stops(season, round_num) |
Pit stop count + team_pit_speed computed inline |
fetch_weather(season, round_num) |
Track temp, rainfall from session weather |
fetch_lap_data(season, round_num) |
NEW β Lap-by-lap data with track_status for safety car |
build_season_dataframe(season) |
Orchestrate all fetchers for a full season |
build_full_dataset(start, end) |
Build complete FastF1 dataset |
Correction 2 β fetch_lap_data: Returns (season, round, driver_id, lap_number, track_status). track_status == '4' = safety car, '6' = VSC. Used in merge to compute safety_car_probability.
Correction 3 β team_pit_speed: Computed inside fetch_pit_stops() as mean pit duration per team per race. Returned as column, no separate function.
Correction 8 β Sector time guard:
if session.laps['Sector1Time'].isna().mean() > 0.5:
logger.warning(f"Season {season} R{round_num}: >50% sector times missing.")
No dropping, no imputing. Imputation deferred to feature_engineering.py (Week 2).
No championship_standing from FastF1 β comes from Jolpica only (Correction 1).
[NEW] jolpica_pipeline.py
Purpose: Backfill 2014β2017 data + championship standings for ALL years.
Base URL: https://api.jolpi.ca/ergast/f1
| Function | Description |
|---|---|
jolpica_get(url, retries, base_delay) |
Request wrapper with exponential backoff |
fetch_race_results(season, round_num) |
Results + grid from Jolpica JSON API |
fetch_pit_stops(season, round_num) |
Pit stop count per driver |
fetch_driver_standings(season, round_num) |
Championship standings β sole source for all years |
fetch_circuit_info(season, round_num) |
Circuit metadata (circuitId, locality) |
build_season_dataframe(season) |
Orchestrate fetchers for full season |
build_jolpica_dataset(start, end) |
Build complete backfill dataset |
Correction 5 β Rate limiting:
def jolpica_get(url, retries=3, base_delay=0.2):
for attempt in range(retries):
try:
response = requests.get(url, timeout=10)
response.raise_for_status()
time.sleep(base_delay)
return response.json()
except requests.exceptions.RequestException as e:
wait = base_delay * (2 ** attempt)
time.sleep(wait)
return None
Correction 1: championship_standing fetched here only, joined onto FastF1 rows in merge step.
[NEW] Merge Logic β data/init.py
- Align column schemas (union of all columns)
pd.concat([jolpica_df, fastf1_df])- Sort by
(season, round, grid_position) - Add
regulation_era: 2014β2021 βhybrid_era, 2022β2024 βground_effect_era - Add
track_typefrom circuit mapping - Compute
driver_form_last3(rolling avg finish, last 3 races) - Compute
safety_car_probabilityfromfetch_lap_dataoutput:- Group by
circuit_id, count laps wheretrack_status == '4'/ total laps
- Group by
- Join
championship_standingfrom Jolpica onto all rows - Add
win_probabilitytarget (1 iffinish_position == 1, else 0) - Validate
telemetry_availableflag integrity
Driver ID mapping: All Jolpica slugs converted to FastF1 abbreviations via DRIVER_MAP.
Verification Target (2023 First β Correction 7)
- 22 races Γ ~20 drivers = ~440 rows
- Spot-check sector times vs official F1 results
telemetry_available = Truefor all FastF1 rowstelemetry_available = Falsefor all Jolpica rows- Merged dataset sorted by
(season, round, grid_position)
Month 1, Week 2β4 (Unchanged)
| Week | Deliverable |
|---|---|
| W2 | feature_engineering.py β era normalization, encoding, TimeSeriesSplit, imputation of missing sector times |
| W3 | train.py + predict.py β LightGBM + SHAP TreeExplainer + MLflow logging |
| W4 | main.py β FastAPI /predict/f1 endpoint, all agents as plain Python functions |
Month 2 β Agent Refactor + Drift + Auto-Retrain (Unchanged)
Month 3 β UI + Deploy + Polish (Unchanged)
.env Template (Updated)
GROQ_API_KEY=
MLFLOW_TRACKING_URI=
CHROMA_PERSIST_DIR=./chroma
JOLPICA_BASE_URL=https://api.jolpi.ca/ergast/f1
FASTF1_CACHE_DIR=./cache/fastf1