trialdiff

R-CMD-check Codecov test coverage r-universe version r-universe status Lifecycle: experimental License: MIT

trialdiff is a clinical-trial data-cut change detection and downstream impact assessment framework for R, designed for the pharmaverse ecosystem.

Existing tools tell you that two datasets differ. trialdiff answers the clinical-programming question that follows:

What changed, what does the change represent, and which downstream analyses or outputs might be affected?

It does this in five transparent, composable layers:

Layer Function Purpose
Compare compare_cut() Added/removed/modified observations and schema changes
Classify classify_changes() Rule-based clinical change taxonomy
Trace define_lineage(), trace_dependencies(), lineage_from_metadata(), output_registry() Explicit data lineage graph
Assess assess_impact() Definitely / potentially / unlikely impact
Report report_diff() HTML, Quarto and machine-readable JSON

Everything is deterministic. There is no machine learning, and no statistical impact is ever claimed - analyses are flagged for review and rerun.

Installation

# From r-universe (includes Windows/macOS binaries)
install.packages(
  "trialdiff",
  repos = c(
    hirujan = "https://hirujan-r.r-universe.dev",
    CRAN = "https://cloud.r-project.org"
  )
)

# Or from GitHub
# install.packages("remotes")
remotes::install_github("Hirujan-R/trialdiff")

Quick start

library(trialdiff)

diff <- compare_cut(
  old = adsl_cut1,
  new = adsl_cut2,
  by = "USUBJID",
  dataset = "ADSL"
)

classified <- classify_changes(diff)

impact <- assess_impact(classified, adsl_adlb_lineage)

report_diff(diff, impact = impact, output = "report.html")

A treatment assignment change (TRT01P = "Placebo" -> "Drug A") is detected, classified as a treatment-assignment change, traced through ADSL.TRT01P -> ADLB.TRT01P -> lab summary -> MMRM -> efficacy table, and every downstream object is flagged for review with a rationale.

Why not just diffdf?

diffdf (and waldo) are excellent low-level comparison tools, and trialdiff deliberately does not reinvent them. trialdiff adds the layers that are specific to clinical programming:

It can even delegate the low-level comparison itself: compare_cut(..., backend = "diffdf") uses diffdf to detect differences and translates the result into the same tdiff object.

Design principles

Documentation

Project proposal

A full proposal covering the problem statement, ecosystem/gap analysis, novelty assessment, architecture, testing and roadmap is available in the project proposal.

Code of conduct

Please note that the trialdiff project is released with a Contributor Code of Conduct. By contributing you agree to abide by its terms.

License

MIT (c) Hirujan Rangaraj. No proprietary or real patient data is included; all example datasets are synthetic.