---
title: "Case study: data-cut review on public ADaM data"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Case study: data-cut review on public ADaM data}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
has_pva <- requireNamespace("pharmaverseadam", quietly = TRUE)
```

This case study runs the full `trialdiff` pipeline on the public
`pharmaverseadam` datasets: two data cuts are compared, changes are classified,
lineage is generated from metadata and an output registry, downstream impact is
assessed, and a review report is produced. No proprietary data is used.

```{r, eval = has_pva}
library(trialdiff)
```

## The two data cuts

We use `ADSL` and a subset of `ADLB` (three laboratory parameters) and build a
later cut that introduces the kinds of changes seen in practice: two new
subjects, a treatment-assignment correction, a corrected laboratory value and a
value that becomes missing.

```{r, eval = has_pva}
params <- c("ALT", "AST", "CREAT")
adsl_full <- pharmaverseadam::adsl
adlb_full <- subset(pharmaverseadam::adlb, PARAMCD %in% params)

subjects <- unique(as.character(adsl_full$USUBJID))
new_subjects <- tail(subjects, 2)

adsl_cut1 <- adsl_full[!adsl_full$USUBJID %in% new_subjects, ]
adlb_cut1 <- adlb_full[!adlb_full$USUBJID %in% new_subjects, ]
adsl_cut2 <- adsl_full
adlb_cut2 <- adlb_full

trt_subject <- adsl_cut2$USUBJID[which(adsl_cut2$TRT01P == "Placebo")[1]]
for (v in c("TRT01P", "TRT01A")) {
  adsl_cut2[[v]][adsl_cut2$USUBJID == trt_subject] <- "Xanomeline Low Dose"
}
for (v in c("TRT01P", "TRTP")) {
  adlb_cut2[[v]][adlb_cut2$USUBJID == trt_subject] <- "Xanomeline Low Dose"
}

i <- which(adlb_cut2$USUBJID == trt_subject & adlb_cut2$PARAMCD == "ALT" &
             adlb_cut2$AVISIT == "Week 4")[1]
adlb_cut2$AVAL[i] <- adlb_cut2$AVAL[i] + 7
adlb_cut2$CHG[i] <- adlb_cut2$AVAL[i] - adlb_cut2$BASE[i]

j <- which(adlb_cut2$PARAMCD == "AST" & adlb_cut2$AVISIT == "Week 2")[1]
adlb_cut2$AVAL[j] <- NA_real_
adlb_cut2$CHG[j] <- NA_real_

c(adsl = nrow(adsl_cut2) - nrow(adsl_cut1), adlb = nrow(adlb_cut2) - nrow(adlb_cut1))
```

## Lineage from metadata plus a registry

The data and derived-variable portion of the lineage comes from a small metadata
specification (the same shape as a `metacore` object). Analyses and outputs are
declared with `output_registry()` and grafted on with `overrides`.

```{r, eval = has_pva}
metadata <- list(
  ds_spec = data.frame(
    dataset = c("ADSL", "ADLB"),
    label = c("Subject-Level Analysis", "Laboratory Analysis")
  ),
  ds_vars = data.frame(
    dataset = c("ADSL", "ADSL", "ADSL", "ADLB", "ADLB", "ADLB", "ADLB", "ADLB"),
    variable = c("USUBJID", "TRT01P", "SAFFL", "USUBJID", "PARAMCD",
                 "TRT01P", "AVAL", "CHG")
  ),
  value_spec = data.frame(
    dataset = c("ADSL", "ADLB", "ADLB", "ADLB", "ADLB"),
    variable = c("TRT01P", "TRT01P", "AVAL", "BASE", "CHG"),
    derivation_id = c("MT.ADSL.TRT01P", "MT.ADLB.TRT01P", "MT.ADLB.AVAL",
                      "MT.ADLB.BASE", "MT.ADLB.CHG"),
    where = c(NA, NA, "PARAMCD == 'ALT'", NA, NA)
  ),
  derivations = data.frame(
    derivation_id = c("MT.ADSL.TRT01P", "MT.ADLB.TRT01P", "MT.ADLB.AVAL",
                      "MT.ADLB.BASE", "MT.ADLB.CHG"),
    derivation = c("DM.ARM", "ADSL.TRT01P", "LB.LBSTRESN", "ADLB.AVAL",
                   "AVAL - BASE")
  )
)

registry <- output_registry(
  td_output("Lab_Summary_By_Treatment",
            depends_on = c("ADLB.TRT01P", "ADLB.AVAL"),
            type = "analysis", relationship = "summarises"),
  td_output("MMRM", depends_on = c("ADLB.AVAL", "ADLB.CHG")),
  td_output("Table_14_2_1", depends_on = "Lab_Summary_By_Treatment",
            type = "output"),
  td_output("Table_14_2_2", depends_on = "MMRM", type = "output")
)

lineage <- lineage_from_metadata(metadata, overrides = registry)
lineage
```

The generated graph reaches from the raw source through derived variables to
analyses and TLFs, and every edge keeps its provenance:

```{r, eval = has_pva}
lineage_provenance(lineage)[, c("from", "to", "relationship", "source")]
```

## Compare and classify

```{r, eval = has_pva}
adsl_diff <- compare_cut(adsl_cut1, adsl_cut2, by = "USUBJID",
                         dataset = "ADSL") |>
  classify_changes()
adlb_diff <- compare_cut(adlb_cut1, adlb_cut2,
                         by = c("USUBJID", "PARAMCD", "AVISIT"),
                         dataset = "ADLB") |>
  classify_changes()

knitr::kable(table(adsl_diff$register$category_label),
             col.names = c("Category", "ADSL"))
knitr::kable(table(adlb_diff$register$category_label),
             col.names = c("Category", "ADLB"))
```

## Assess downstream impact

```{r, eval = has_pva}
adlb_impact <- assess_impact(adlb_diff, lineage)
adlb_impact$impacts[, c("node", "node_type", "level", "depth", "requires_rerun")]
```

A treatment-assignment change flows to `ADLB.TRT01P`, the by-treatment summary
and the MMRM, and every analysis or output is flagged for review or rerun. No
statistical impact is claimed.

## Review report

```{r, eval = has_pva}
report <- report_diff(adsl_diff,
                      impact = assess_impact(adsl_diff, lineage),
                      output = "list")
report$data$review_items
```

Writing `report_diff(..., output = "cut-review.html")` produces a self-contained
HTML report, and `as_json()` produces machine-readable output for automated QC
pipelines.

## What this demonstrates

* Deterministic comparison of two real data cuts, with clinical classification.
* Lineage generated from metadata, extended with an analysis/output registry.
* Transparent impact assessment that reaches TLFs and never claims statistical
  significance.
* A single workflow: `compare_cut()` -> `classify_changes()` ->
  `lineage_from_metadata()` + `output_registry()` -> `assess_impact()` ->
  `report_diff()`.

## Limitations

* The metadata above is a compact illustration; a real study would load it from
  Define-XML with `metacore::define_to_metacore()`.
* Analysis/output dependencies are not described by data metadata and must be
  supplied by the study team (here, via `output_registry()`).
* Impact is a review signal. Confirming whether a summary or model result
  actually changes requires rerunning it.
