Tasks & the task maker
The four v1 benchmarks, the cohort contract, and how to author your own task.
The four v1 tasks
Each task is a versioned Python module that specifies eligibility, prediction time, outcome, threshold, action direction, and evaluation protocol. Each task links to a potential clinical decision: goals-of-care conversations (mortality task), early rehabilitation and care-transition planning (discharge to LTACs), ventilator management (extubation failure), and discharge readiness assessment (ICU readmission).
| characteristic | Mortality task | Discharge to LTACs | Extubation failure | ICU readmission |
|---|---|---|---|---|
| Endpoint | Expired or hospice disposition | Disposition to LTACs | Reintubation within 24 h | Unplanned ICU return during the same hospitalization |
| Prediction time | Daily at 07:00 | Daily at 07:00 | 30 min before first confirmed extubation | End of first ICU stay |
| Reporting mode | Pooled landmarks | Pooled landmarks | Episodic | Episodic |
| Task threshold | 0.50 | 0.50 | 0.10 | 0.20 |
| High-risk alarm rule | Score ≥0.50 | Score ≥0.50 | Score ≥0.10 | Score ≥0.20 |
| Decision-curve action | Not calculated on maximum risk | Not calculated on maximum risk | Extubation, score <0.10 | Continued ICU care, score ≥0.20 |
Daily-task discrimination and calibration use pooled landmarks; alarm summaries use the maximum risk per hospitalization. Extubation decision curves evaluate action below the threshold, whereas high-risk alarms flag scores at or above it. LTACs denotes long-term acute care hospitals. The actions are evaluated retrospectively and are not clinical recommendations.
Label and eligibility rules
- Mortality task. The endpoint includes discharge disposition recorded as expired or hospice. A missing disposition, or one recorded as still admitted, is labelled negative.
- Daily tasks. Predictions occur at 07:00 during the first ICU stay. The evaluation covers hospitalizations still eligible for prediction at each of the first 30 prediction days.
- Extubation failure. The prediction occurs 30 minutes before the first confirmed extubation; reintubation is assessed during the 24 hours after extubation. Extubations followed by death within 24 hours, or without a complete 24-hour observation, are excluded unless reintubation occurs within that interval.
Task taxonomy
flair list-tasks| task | class | temporal | unit | thresh (dir) |
|---|---|---|---|---|
icu_daily_mortality | outcome | continuous | one-per-window | 0.50 (above) |
icu_daily_ltach | outcome | continuous | one-per-window | 0.50 (above) |
extubation_failure_24h | intervention | episode | one-per-stay | 0.10 (below) |
icu_readmission | outcome | episode | one-per-stay | 0.20 (above) |
The recommended report mode follows from the temporal pattern: episode →
episodic; continuous → continuous (pooled landmarks: the mortality
task and discharge to LTACs). See Building reports.
Loading a task → cohort
flair load-task icu_daily_mortality \
--clif-config clif_config.json \
--out cohort.parquet \
[--train-end YYYY-MM-DD] [--test-start YYYY-MM-DD]This runs the task's build() and writes cohort.parquet (one row
per prediction_id) plus cohort.table1.json (cohort characteristics,
auto-generated).
The cohort contract
| column | role |
|---|---|
hospitalization_id | raw hospitalization key |
hospitalization_join_id | stitched-hospitalization (stay-level) key |
prediction_dttm | when the prediction is made |
feature_cutoff_dttm | the last instant whose data may be used. Defaults to prediction_dttm; a task sets it earlier only if its prediction timestamp would itself leak the outcome |
<label_column> | the task label (e.g. label_mortality) |
split | train / test, assigned by hospitalization (see below) |
| demographics | age_at_admission, sex_category, race_category, ethnicity_category |
window_number | 1-based k-th prediction per stay (always 1 for one-per-stay) |
prediction_id | auditable per-row key |
prediction_id is
{hospitalization_join_id}-{hospitalization_id}-{patient_id}-{window_number}, so each
prediction traces to its stitched hospitalization, the specific hospitalization, the patient,
and the window. No shipped task sets feature_cutoff_dttm away from
prediction_dttm; extubation failure instead moves the prediction itself to 30
minutes before extubation. Reports carry a version identifier covering the task code, evaluation
policies, and the splitting procedure.
Train and test partitions
Hospitalizations, not patients, are assigned to training and test sets, at the grain of the
stitched hospitalization (hospitalization_join_id): one stitched hospitalization is
never split across the two, and a patient can contribute more than one hospitalization. Three
regimes, in priority order:
| given | site | assignment |
|---|---|---|
--train-end + --test-start | any | calendar cutoffs on each stitched hospitalization's earliest prediction time; rows between the two dates are dropped |
| neither | MIMIC-CLIF | MIMIC-IV dates are shifted, so a reproducible ordering assigns 75% of hospitalizations to training and 25% to testing |
| neither | any other | temporal: the oldest 75% for training and the newest 25% for testing |
Outside MIMIC-CLIF, rows predicted after a fixed data cutoff (31 December 2025) are dropped before any split. Performance is reported on test hospitalizations only.
time ≤ feature_cutoff_dttm and nothing after it. Every
build() respects this; any feature extraction you write must enforce it too (see
Feature engineering).
Authoring a new task (the "task maker")
A task is a single Python file dropped into
flair_benchmark/tasks/<name>.py that exposes a META dict and a
build() function. The catalog auto-discovers it - no registry edits.
META - required fields
The taxonomy triple (validated; reviewers read this before any code):
| field | allowed values |
|---|---|
task_class | outcome, deterioration, intervention, operational |
temporal_pattern | episode, fixed_horizon, continuous |
prediction_unit | one-per-stay, one-per-window |
For binary tasks, also required: clinical_threshold (a float in
(0, 1) and a multiple of 0.01, so it lands on the 99-point threshold
sweep) and clinical_direction ("above" or "below"). Also
validated: report_mode ("episodic" or "continuous") and,
for continuous tasks, landmark_horizon (a positive int; 30 daily landmarks for the
mortality task and discharge to LTACs). Plus descriptive fields: name, display_name,
task_type, label_column, positive_class,
clinical_action, windows, cohort docs, evaluation_metrics.
build() - signature & contract
def build(clif_config: str, train_end: str | None,
test_start: str | None) -> pl.DataFrame:
...
return finalize_cohort(df, OUTPUT_COLS, META)It must end with finalize_cohort(df, OUTPUT_COLS, META), which
selects your OUTPUT_COLS and stamps on window_number +
prediction_id (and feature_cutoff_dttm, defaulted to
prediction_dttm when absent). It does not drop rows whose
split came back null, so filter them after assign_split(...) as every
shipped task does.
Author decision checklist
- Cohort scope - all-comers ICU? hospital-wide? specific inclusion/exclusion?
- Label anchor - what clinical event defines the positive label?
- Prediction timing - one-per-stay (episode) or one-per-window (continuous)?
- Threshold + direction - at what risk do you act, and above or below?
prediction_dttm- when the prediction is made.feature_cutoff_dttm- does theprediction_dttmrow itself leak the outcome? If the anchor is the event (an extubation, a transfer, a procedure), set the cutoff strictly earlier; otherwise leave the default.
Acceptance
Researchers and ICU clinicians can propose new tasks for Benchmark Committee review. Each proposal specifies the clinical question, eligible hospitalizations, the information available at prediction, the outcome label, and the evaluation procedure.
A new task enters the federated suite after: reproducibility against MIMIC-CLIF, a clinician-led face-validity review, and site-governance acceptance at a minimum of two consortium sites.
Contribute a task via GitHub
Tasks ship through a pull request to the FLAIR repo. End-to-end, from a fork to a task that shows up on this leaderboard:
- Fork the repo.
The FLAIR library repository,
then branch (e.g.
task/<name>). - Add the task file. Drop
flair_benchmark/tasks/<name>.pywith aMETAdict and abuild()ending infinalize_cohort(df, OUTPUT_COLS, META)- see Authoring a new task above. The catalog auto-discovers it; no registry edits. - Validate locally. Reproduce against MIMIC-CLIF before opening the PR:
Check the generated
flair list-tasks # confirm your task is discovered flair load-task <name> \ --clif-config clif_config.json \ --out cohort.parquetcohort.table1.jsonfor sane cohort characteristics. - Mirror the task into the website catalog. In the website repo
(
flair_website, a separate pull request), add one entry todata/tasks.jsonso the task surfaces on the leaderboard and task pages - the catalog is hand-mirrored from the upstreamMETAdicts. Required fields:field notes idmust match the task file name / META.name; the leaderboard joins tasks ↔ scores on thisdisplay_namehuman title colorblue/purple/sage/terracotta(UI dot/pill)task_class,temporal_pattern,prediction_unitthe taxonomy triple (copy from META)task_typee.g. binaryclinical_threshold,clinical_directionfloat in (0,1) + above/below(binary tasks)clinical_actionthe act taken at threshold label_columne.g. label_mortalitysummaryone-line prose (prediction window + cohort) report_modeepisodic/continuous(see Building reports) - Regenerate the snapshot (website maintainers, once a site returns a
non-PHI result dump for the task): drop it under
runs_data/flair_export/<site>/<site>_baseline_non_phi_for_upload/<name>/and runpython scripts/build_data.pyto rebuilddata/leaderboard.json+data/reports/. Without a run, the task lists with no scores yet. - Open the pull request against the FLAIR library repository. CI plus a clinician-led face-validity review run on the PR.
- Acceptance follows the criteria above - reproducibility vs MIMIC-CLIF and site-governance acceptance at a minimum of two consortium sites.