# Agentic Football Dojo — Prediction CSV Schema (v1)

This is the **contract every team's agent must produce** for each prediction tranche
(a tranche = one tournament round). Upload one CSV per tranche through the registration /
re-submission form before that round's **Lock** deadline.

---

## File format

- **Encoding:** UTF-8
- **Delimiter:** comma (`,`)
- **Header row:** required, exact column names below (case-sensitive)
- **Rows:** exactly one row per match in the tranche you are predicting
- **File name suggestion:** `teamname_tranche.csv` (e.g. `redbot_group_stage.csv`)

## Columns

| Column | Type | Required | Description |
|---|---|---|---|
| `fixture_id` | integer | **yes** | **football-data.org match id** — the **authoritative join key** (e.g. Mexico vs South Africa = `537327`). We publish the list of `fixture_id`s for each tranche. Predictions whose `fixture_id` isn't in the open tranche are ignored. |
| `match_label` | string | no | Human-readable label, e.g. `Group A: Mexico vs Poland`. For your convenience only — **ignored on ingest**. |
| `predicted_home_goals` | integer ≥ 0 | **yes** | Predicted goals for the home team in 90' (regulation). |
| `predicted_away_goals` | integer ≥ 0 | **yes** | Predicted goals for the away team in 90' (regulation). |
| `predicted_winner` | `home` \| `away` | conditional | **Required only in knockout rounds when your predicted goals are equal** (i.e. you predict a draw that would go to a penalty shootout). Names the team you predict advances. Leave blank otherwise. |

## Scoring (how these map to points)

Per match, compared against the **final 90' result** ingested from football-data.org.
Points are **cumulative bonuses, max 5 per match**:

| Bonus | Condition | Points |
|---|---|---|
| Winner | correct outcome (home win / draw / away win) | **+2** |
| Home goals | exact `predicted_home_goals` | **+1** |
| Away goals | exact `predicted_away_goals` | **+1** |
| Goal difference | correct goal difference (home − away) | **+1** |

- A **perfect scoreline** scores all four = **5 pts**. Just the winner = 2. Winner + goal difference = 3. Wrong outcome with a lucky exact goal tally can still earn the goal bonuses.
- **Exact scoreline** is tracked as a flag (it earns no extra points) and is the **leaderboard tie-breaker**: equal Total Points → more exact scorelines ranks higher.
- **Knockout adaptation:** the goal bonuses always use the 90' result. For the **Winner** bonus, if the match is a draw at 90', you earn it only when `predicted_winner` matches the team that actually advances (extra time / penalties).

Total Points = sum across all scored matches. Leaderboard ranks by Total Points, then exact-score count.

## Validation rules (enforced by `ingest_predictions.py`)

A row is **rejected** (and reported back) if:
- `fixture_id` is missing, non-integer, or not in the currently open tranche.
- `predicted_home_goals` / `predicted_away_goals` is missing, non-integer, or negative.
- `predicted_winner` is present but not exactly `home` or `away`.
- a knockout-round row predicts a draw but `predicted_winner` is blank.
- duplicate `fixture_id` within the same file (last one wins, with a warning).

Valid rows from a file are always ingested even if some rows are rejected.

## Example

```csv
fixture_id,match_label,predicted_home_goals,predicted_away_goals,predicted_winner
537327,Group A: Mexico vs South Africa,2,1,
537328,Group F: South Korea vs Czechia,1,1,
537417,Round of 32: Winner Group A vs Runner-up Group B,2,2,home
```

See [`sample_predictions.csv`](../sample_predictions.csv) for a ready-to-edit template with **real WC 2026 match ids**.

## Optional: agent write-up (CoT)

Separate from the CSV, the registration form has an **optional** field where you can attach a
**Markdown file** explaining how you built and trained your agent and its chain-of-thought /
reasoning approach. It earns no points — it's for transparency and bragging rights, and we may
feature it on your team's dashboard snapshot. Totally optional.
