Files
learn-tte/AGENTS.md
T
2026-06-08 10:15:36 -07:00

146 lines
7.5 KiB
Markdown

# Target Trial Emulation Learning Project
This project is for learning how to code and understand target trial emulation in R.
The main teaching example is an ICU septic shock study:
> Among ICU patients with suspected septic shock at ICU admission, what is the effect of initiating vasopressors early versus not initiating vasopressors early on 28-day mortality?
## How To Work With The User
- Teach by showing small code chunks that the user can type in manually.
- Explain each meaningful line of code before moving on.
- Add generous learner-focused comments, especially around R functions, function arguments, return values, and unfamiliar package functions.
- Include many small examples and REPL-style checkpoints with code, expected output, and interpretation.
- Keep report-style Quarto notebooks focused on rendered tables and interpretation unless the user asks for REPL-style checkpoints there.
- Teach the base R mechanics when a concept is new, then prefer readable tidyverse-style code for routine analysis.
- Make the smallest correct change when editing project files.
- Keep scripts and notebooks numbered so the learning sequence is obvious.
- Avoid over-abstraction early; build reusable primitives only after the concept is clear.
- When adding reusable code, explain what future project need it supports.
- When using external dependencies, prefer wrapping them behind project functions so the user learns stable primitives.
## Code Style
- Use the native pipe `|>`, not `%>%`
- snake_case for all names
- Prefer explicit, teaching-oriented comments over terse production-style code while this remains a learning project.
- For reusable functions, include comments describing purpose, arguments, return value, and at least one example call.
- Prefer `vapply` over `sapply`; explicit return types
- Use `cli::cli_*` for messages, not `message()`/`cat()`
- Prefer cleaner imports with grouped startup message suppression, for example `suppressPackageStartupMessages({ library(readr); library(dplyr) })`.
- Prefer `dplyr` verbs for data manipulation when external dependencies are allowed.
- Prefer `skimr` for quick data summaries.
- Prefer `gt` and `gtsummary` for clear analytic tables in notebooks and reports.
- Style with `styler::style_pkg()` before commits
## Don'ts
- Don't modify `renv.lock` by hand
- Don't `setwd()` — rely on the project root (`here::here()`)
- Don't introduce new dependencies beyond the approved stack without asking
## Stack
- R 4.4 managed by rig
- renv for dependency management; lockfile is source of truth
- targets for pipeline orchestration
- tidyverse, especially `dplyr`, for routine data manipulation
- ggplot2 for exploratory plots and visual diagnostics
- data.table for performance-oriented data manipulation when needed
- skimr for quick data summaries
- gt for presentation tables
- gtsummary for descriptive and model summary tables
- Quarto for reports
## Dependency Preference
- The first scripts may remain base R to teach the underlying mechanics.
- Going forward, use `dplyr`, `tidyverse`, `skimr`, `gt`, and `gtsummary` where they make the code clearer.
- Keep base R explanations available when they help the user understand what the package code is doing.
- Do not add packages outside the approved stack without asking first.
## Workflow Roles
- Put reusable logic in `R/` functions.
- Put reusable smoke checks or command-line workflows in `scripts/`.
- Put polished displays, interpretation, exploratory visualization, and rendered result tables in Quarto notebooks.
- Avoid CSV intermediates when functions can be called directly and reproducibly.
- Use `run_all.sh` as the lightweight end-to-end runner until the project is ready for `targets`.
- Keep rendered notebook reports in `outputs/reports/`.
## Learning Roadmap
- [x] Choose ICU teaching scenario: early vasopressor strategy in septic shock.
- [x] Simulate a simple ICU observational cohort.
- [x] Define the target trial protocol explicitly.
- [x] Estimate a naive observational association.
- [x] Show why naive comparison can be biased.
- [x] Align time zero and eligibility criteria.
- [x] Introduce treatment assignment windows.
- [x] Add censoring logic.
- [x] Add inverse probability weighting from first principles.
- [x] Refactor repeated logic into reusable project functions.
- [ ] Re-implement selected steps with external dependencies.
- [ ] Build wrapper functions around external dependency workflows.
- [ ] Add a targets pipeline.
- [x] Add initial Quarto report for reproducible analysis.
## Initial Target Trial Protocol
Clinical question:
Among ICU patients with suspected septic shock at ICU admission, what is the effect of starting vasopressors within 2 hours compared with not starting vasopressors within 2 hours on 28-day mortality?
Eligibility criteria:
- ICU admission.
- Suspected sepsis.
- Hypotension at baseline.
- Elevated lactate at baseline.
Time zero:
- ICU admission.
Treatment strategies:
- Early vasopressor strategy: start vasopressors within 2 hours of ICU admission.
- No early vasopressor strategy: do not start vasopressors within 2 hours of ICU admission.
Outcome:
- Death within 28 days.
Baseline confounders in the first simulated dataset:
- Age.
- Sex.
- SOFA score.
- Lactate.
- Mean arterial pressure.
Initial estimand:
- Risk difference in 28-day mortality.
- Risk ratio for 28-day mortality.
## File Sequence
- `run_all.sh`: run the key scripts and render all current notebooks.
- `scripts/01_simulate_icu_data.R`: simulate an ICU cohort in memory and print a quick `skimr` summary.
- `R/simulate_icu_cohort.R`: first reusable simulation primitive.
- `R/estimate_naive_vasopressor_mortality_effect.R`: shared naive mortality-effect primitive used by notebook workflows.
- `R/estimate_standardized_vasopressor_mortality_effect.R`: shared outcome-regression standardization primitive.
- `R/estimate_iptw_vasopressor_mortality_effect.R`: shared inverse-probability-of-treatment weighting primitive with unstabilized weights, propensity model diagnostics, weighted baseline balance, and weighted effect estimates.
- `notebooks/01_target_trial_basics.qmd`: report-style walkthrough of the target trial protocol and initial results.
- `notebooks/02_explore_simulated_data.qmd`: exploratory visual diagnostics for the simulated cohort.
- `notebooks/03_why_naive_analysis_is_biased.qmd`: explanation of confounding by indication and first standardized mortality-effect estimate.
- `notebooks/04_inverse_probability_weighting.qmd`: IPTW from first principles, weight diagnostics, baseline balance table, weighted effect estimates, and a three-way comparison of naive, standardized, and IPTW results.
- `R/simulate_icu_cohort_longitudinal.R`: longitudinal simulation primitive with time-varying covariates, treatment timing, and censoring events at sparse time points.
- `R/clone_trial_arms.R`: cloning function that duplicates each eligible patient into two trial arms at time zero and applies censoring rules at the 2-hour mark.
- `R/estimate_iptw_and_ipcw_effect.R`: combined IPTW + IPCW weighting primitive for per-protocol effect estimation in the cloned dataset.
- `notebooks/05_treatment_assignment_windows.qmd`: treatment assignment windows, grace periods, cloning mechanics, and censoring rules.
- `notebooks/06_censoring_and_ipcw.qmd`: inverse probability of censoring weighting, combined weight diagnostics, and comparison with cross-sectional IPTW.
- `notebooks/07_full_emulation_pipeline.qmd`: end-to-end target trial emulation pipeline with four-way comparison of naive, standardized, cross-sectional IPTW, and longitudinal IPTW + IPCW methods.