getting-started.Rmdreviewerguider populates the mechanical sections of a
Study Data or Analysis Data Reviewer’s Guide directly from dataset
metadata, validation findings and a programs directory – leaving only
the genuinely narrative sections to be written by hand.
Generated mechanically: the dataset inventory, the validation-findings table, the programs-submitted list, and the assembly of the document itself.
Left to you, deliberately: every narrative section (study background,
rationale for non-standard decisions), and every sponsor explanation of
a finding. Findings with no explanation are only
flagged (needs_explanation = TRUE); the
package never writes an explanation for you. The generated content is a
draft from your metadata – read it before it ships.
Two values are guessed rather than known, and both are disclosed
where you can see them: key variables when the study supplies no
declared keys (the key_source column says
"heuristic"), and program descriptions, which are the
header comment rather than an analysis of the code. Both limits are
spelled out in the sections below and in ?section_datasets
/ ?section_programs.
library(reviewerguider)
guide <- guide_spec(
"CDISCPILOT01",
type = "sdrg",
sponsor = "Acme Pharma",
protocol_title = "A Study of Drug X",
standards_version = "SDTMIG 3.4"
)
guide
#>
#> ── CDISCPILOT01 reviewer's guide (SDRG) ────────────────────────────────────────
#> ℹ Sponsor: Acme Pharma
#> ℹ 0 section(s)section_datasets() builds the inventory from a named
list of data frames (or an already-assembled metadata table):
adsl <- read.csv(system.file("extdata", "adsl.csv", package = "reviewerguider"))
adae <- read.csv(system.file("extdata", "adae.csv", package = "reviewerguider"))
section_datasets(list(adsl = adsl, adae = adae))
#> # A tibble: 2 × 8
#> dataset label class key_variables key_source records variables size
#> <chr> <chr> <chr> <chr> <chr> <int> <int> <chr>
#> 1 adsl NA data.frame STUDYID, USUBJID,… heuristic 6 7 2.7 …
#> 2 adae NA data.frame STUDYID, USUBJID,… heuristic 6 5 2.4 …With no metadata, key_variables is a
name-pattern guess and key_source says so.
Where the study declares its keys – a metacore object from
metacore::define_to_metacore(), or any data frame with
dataset, variable and key_seq
columns – pass it and the declared keys are used instead:
keys <- read.csv(system.file("extdata", "dataset_keys.csv", package = "reviewerguider"))
head(keys)
#> dataset variable key_seq
#> 1 ADSL USUBJID 1
#> 2 ADAE USUBJID 1
#> 3 ADAE AETERM 2
#> 4 ADAE ASTDT 3
#> 5 ADAE AESEQ 4
#> 6 ADLBC USUBJID 1
section_datasets(list(adsl = adsl, adae = adae), metadata = keys)
#> # A tibble: 2 × 8
#> dataset label class key_variables key_source records variables size
#> <chr> <chr> <chr> <chr> <chr> <int> <int> <chr>
#> 1 adsl NA data.frame USUBJID declared 6 7 2.7 …
#> 2 adae NA data.frame USUBJID, AETERM, … declared 6 5 2.4 …The declared keys (from the real CDISCPILOT01 ADaM define.xml)
disagree with the guess for both datasets – which is the point of never
letting a guide guess silently. Read key_source before the
table goes into a guide.
section_findings() takes a plain data frame in the
Pinnacle 21 report column schema – Dataset,
Variable, Rule ID, Message,
Records affected, Severity – so any tool that
emits those columns works, and no validator package is imported. Names
are matched case- and separator-insensitively, and a missing required
column is an error naming it.
It pairs each finding with its sponsor explanation (keyed by rule ID, or by message text) and flags the ones still missing one – that gap is exactly what gets a submission questioned. An unexplained finding is only flagged, never filled in:
findings <- read.csv(system.file("extdata", "findings.csv", package = "reviewerguider"))
explanations <- read.csv(system.file("extdata", "explanations.csv", package = "reviewerguider"))
section_findings(findings, explanations)
#> ! 3 finding(s) have no sponsor explanation and are flagged.
#> # A tibble: 6 × 8
#> dataset variable rule_id message records_affected severity explanation
#> <chr> <chr> <chr> <chr> <int> <chr> <chr>
#> 1 LB (LBHE) LBTEST, LBSTR… SD0029 Missin… 1000 Warning NA
#> 2 AE AEENDTC SD0021 Missin… 472 Warning Adverse ev…
#> 3 LB (LBHE) LBORRES, LBTE… SD0026 Missin… 293 Warning Original u…
#> 4 LB (LBUR) LBORRES, LBTE… SD0026 Missin… 25 Warning Original u…
#> 5 DM ARMCD, ACTARM… SD2236 ACTARM… 12 Warning NA
#> 6 QS (QSCO) QSSTRESC, QSB… SD1131 Missin… 7 Warning NA
#> # ℹ 1 more variable: needs_explanation <lgl>section_programs() inventories a directory of submission
programs, pulling each program’s leading comment block as its
description:
progs <- system.file("extdata", "programs", package = "reviewerguider")
section_programs(progs)
#> # A tibble: 2 × 5
#> file path size modified description
#> <chr> <chr> <chr> <dttm> <chr>
#> 1 adsl.R adsl.R 231 B 2026-08-03 02:29:55 Program: adsl.R Purpose: Derive t…
#> 2 t_dm.sas t_dm.sas 211 B 2026-08-03 02:29:55 Program: t_dm.sas Purpose: Produc…description is the header comment (#,
* or /* */) found in the first 60 lines,
collapsed to one line and truncated at 300 characters – not a parse of
the code. A header sitting below a licence banner or an
options/library block gives NA,
and a stale header is reported verbatim. Overwrite the column if you
need better.
guide <- add_section(guide, "Dataset Inventory",
section_datasets(list(adsl = adsl, adae = adae), metadata = keys),
type = "datasets")
guide <- add_section(guide, "Validation Findings", section_findings(findings, explanations),
type = "findings")
#> ! 3 finding(s) have no sponsor explanation and are flagged.
guide <- add_section(guide, "Programs Submitted", section_programs(progs), type = "programs")
guide <- add_narrative(
guide, "Introduction",
"This SDRG accompanies the CDISCPILOT01 SDTM submission and describes the datasets, conformance findings, and programs delivered."
)
guide
#>
#> ── CDISCPILOT01 reviewer's guide (SDRG) ────────────────────────────────────────
#> ℹ Sponsor: Acme Pharma
#> ℹ 4 section(s)
#> ✔ [datasets] Dataset Inventory - 2 row(s)
#> ✔ [findings] Validation Findings - 6 row(s)
#> ✔ [programs] Programs Submitted - 2 row(s)
#> ✔ [narrative] Introduction - 128 char(s)
out <- tempfile(fileext = ".html")
render_guide(guide, out, format = "html")
#> ✔ Rendered sdrg guide to /tmp/RtmpIp0faG/filebf430149fe575.html
file.exists(out)
#> [1] TRUErender_guide() starts from the sdrg/adrg section
skeleton shipped in inst/templates and needs
rmarkdown plus pandoc – no network access or credentials
required. rmarkdown is a Suggests, so if it is
not installed you get
The package "rmarkdown" is required to render a guide file.
before any file is written; every other function in the package works
without it, since the sections are ordinary tibbles.