Check Clinical Trial Data Against 'CDISC' Open Rules

Finds conformance problems in clinical trial data without leaving R, using the openly published 'CORE' conformance rules: the 'CORE' 1.0 rules maintained by Verisian for 'SDTM', and the 'CDISC' Open Rules for 'SEND', 'TIG' and 'USDM'. Check a single dataset while you are still writing the code that builds it, or a whole study folder once it exists, and get the findings back as a tidy data frame pointing at the exact row and variable. Reads transport ('XPT'), 'SAS', comma-separated and 'Dataset-JSON' files, plus 'Define-XML' when present, and 'USDM' study-design documents. Covers rules for the 'SDTM', 'SEND', 'TIG' and 'USDM' standards. The rules are bundled inside the package, so nothing is downloaded and your data never leaves your machine: no internet, no API key, no account. When a rule cannot be checked - because it needs a dataset you did not supply, for instance - it is reported as skipped with the reason, never counted as a pass. Meant as a quick first pass before a qualified validation system, never as a replacement for one. An independent project: not affiliated with or endorsed by 'CDISC' or Verisian, and not a 'CORE'-certified conformance engine.


coreval

CRAN status R-CMD-check License: MIT Lifecycle: stable

Find out what's wrong with your SDTM, SEND or USDM data before you send it anywhere.

You've just written the code that builds a dataset. Normally you'd export it, upload it to a validation tool, wait, and then work out which line of your code caused each problem. coreval does the checking straight away, in R, on your own machine. It tells you in plain words what's wrong, which rows, and what the values were.

It runs CDISC's published conformance rules (CORE): CORE 1.0's rules for SDTM, and CDISC's own for SEND, TIG and USDM. You'll still run your qualified tool before you submit. You'll just arrive with far less for it to find.

Try it

install.packages("coreval")
library(coreval)

dm <- data.frame(
  STUDYID = "STUDY1",
  DOMAIN  = "DM",
  USUBJID = c("STUDY1-001", "STUDY1-002", "STUDY1-003"),
  RFSTDTC = c("2024-01-15", "2024-13-01", "2024-02-03"),  # month 13
  AGE     = c(34, 51, 47),
  AGEU    = c("YEARS", "YEARS", "")                       # age with no unit
)

result <- check_dataset(dm, standard = "SDTMIG", version = "3.4")
print(result, n = 2)   # describe the first two problems; typing `result` shows ten

You get a report like this:

── coreval — DM ────────────────────────────────────────────────────────────────

4 problems across 2 records  (143 checks ran)

  wrong value         2   the data breaks the rule - start here
  missing required    1   the standard requires it
  missing optional    1   often legitimate: not collected, screen failure, ...

[wrong value]
AGEU must be populated when AGE is populated.
  1 record · AGE, AGEU
    row 3  STUDY1-003  AGE = "47", AGEU = (empty)
    CORE-000189  · also CG0665

[wrong value]
Value must be a valid ISO 8601 datetime or interval.
  1 record · RFSTDTC
    row 2  STUDY1-002  RFSTDTC = "2024-13-01"
    CORE-002121  · also CG0011

  ... and 2 more here. See result$findings for all of them.

────────────────────────────────────────────────────────────────────────────────
69 checks could not run.
  28 need other datasets (AE, CE, DD, DS, EX, RELREC, ...)
     → run check_study() on the whole folder to cover these
  22 ask what the whole study contains
  13 need a define.xml
     → put it in the study folder (reading it needs the xml2 package)
  2 need to know the controlled terminology version
     → pass ct_package = "sdtmct-..." (see list_ct_packages()), or for a study fill TSVCDREF and TSVCDVER in TS
  2 compare variable labels, and the data has none
     → give the variables labels: a data frame made in R has none until they are added
  2 for other reasons, see result$skipped

Scoped to SDTMIG: 109 rules written for other standards, or other versions of this one, were not run.

Fix what you can, then run this again.
To track the rest:  write_findings(result, "issues.xlsx")

Both planted mistakes are found. Definite errors come first, and each one shows the row, the subject (and the --SEQ, in a dataset that has one) and the value. The rule number is at the end, with the same rule's number in CDISC's Conformance Rules or the FDA Business Rules after "also". The bottom part tells you what it couldn't check and how to fix that.

Everyday use

Three functions cover almost everything.

While you write code, check the data frame you just built, or a single .xpt, .sas7bdat or .csv file:

result <- check_dataset(ae, standard = "SDTMIG", version = "3.4")

When the study exists as files, check the whole folder. This is the only way to run the rules that compare datasets with each other, such as an adverse event date against the subject's dates in DM. A define.xml in the folder is used automatically.

result <- check_study("path/to/sdtm", standard = "SDTMIG", version = "3.4")

To share with your team, save an Excel workbook. It lists the problems, the records behind them, what couldn't be checked and every rule's result, with empty Status and Notes columns for tracking what's being fixed.

write_findings(result, "issues.xlsx")

What the tags mean

Tag Means What to do
wrong value the data holds a value that breaks the rule, like a month of 13 fix it first
missing required something the standard requires is missing or blank fix it
missing optional something expected is missing often fine for your study: check it applies

To see only the definite errors: filter_findings(result, triage = "wrong value").

A clean report isn't always clean data

A short report can mean your data is fine, or that many rules couldn't run. coreval never lets those look the same. Every result lists what it skipped and why, in plain words: a dataset you didn't supply, no define.xml, no Controlled Terminology version. If nothing applies, it stops with an error rather than printing a clean report, and if every check had to be skipped, it says that no check ran.

So before you celebrate, look at result$skipped.

Common questions

Which terminology version does it use? The one your study declares, in TS (TSVCDVER, with TSVCDREF = CDISC) or in the define.xml. If neither says, the terminology rules are skipped until you tell it, for example ct_package = "sdtmct-2026-03-27". list_ct_packages() lists every release. It never guesses.

What does a rule check? list_rules(id = "CORE-000189") gives its description, the guidance it comes from and its Conformance Rules numbers.

Does my data leave my computer? No. There's no internet access, account or API key. The rules and terminology are bundled in the package.

Can I make my program stop when a dataset has errors? Yes, see "Stop my program when a dataset has errors" in vignette("coreval").

Is it a replacement for Pinnacle 21 or CDISC's engine? No. It's the quick check you run while working. Use a qualified tool for the submission.

Install

install.packages("coreval")

The development version, with changes not yet on CRAN, is on GitHub:

# install.packages("pak")
pak::pak("hrach-gevorgyan/coreval")

It needs R 4.1 or newer. A few optional packages switch on more, and coreval tells you when something was skipped because one is missing:

install.packages(c("xml2", "writexl", "jsonlite", "QuickJSR"))

xml2 reads define.xml, writexl saves to Excel, jsonlite reads Dataset-JSON and USDM study files, and QuickJSR runs USDM's JSONata rules.

What it covers

  • The published rules, which list_rules() lists: CORE 1.0's for SDTMIG 3.2 to 3.4 and the FDA Business Rules, maintained by Verisian in core-contributor, and CDISC's rules for SEND, TIG and USDM from cdisc-open-rules. Retired rules are included but run only if you ask.
  • Files: XPT, SAS datasets, CSV, Dataset-JSON, Define-XML, and USDM study files with usdm = TRUE.
  • Controlled Terminology: every release CDISC's engine carries, from 2014 on, bundled.

Both rule sets ship worked examples, and coreval is tested against every one. More than nine in ten rules give exactly the expected answer; docs/COVERAGE.md explains each of the rest.

Not yet:

  • ADaM. CDISC publishes expected results for one ADaM rule only, so there's no way to show the rest would be right.
  • Medical dictionaries. It can't check terms against your licensed MedDRA or WHODrug.

How it compares

coreval is an independent implementation of the same rules that CDISC's engine and Verisian's CORE 1.0 engine run. On CDISC's complete pilot study it agreed with Verisian's engine on almost every rule, and each difference has a traced cause. It runs inside R, offline, and in a fraction of the time and memory. The engines are the official reference and can check medical dictionaries. docs/COMPARISON.md goes through it all.

Learn more

  • Getting started: vignette("coreval"). Four steps, then answers to common tasks: only the real errors, choosing your standard, terminology, big studies.
  • How it works: vignette("technical"). The full reference: which files are read, which rules run and why, every skip reason, every column of a result.
  • Help for each function: ?check_dataset, ?check_study, ?write_findings, ?filter_findings, ?list_rules, ?list_ct_packages, ?read_study.
  • The evidence: docs/ has a real study checked by coreval and the reference engine, rule coverage, speed benchmarks and design decisions.

Please read this

coreval is an independent, personal open-source project. It is not a CDISC product, not endorsed by CDISC, and not a certified CORE engine. It is not validated software. A clean result doesn't mean a submission will be accepted, and it doesn't replace your organisation's own validation.

Found a wrong or missing result? That's the most useful thing you can report. Open an issue, ideally with a small dataset that shows it. Please read the Code of Conduct first.

License

The package code is MIT. The bundled rules and standards data come from three MIT-licensed repositories: CDISC's cdisc-open-rules and cdisc-rules-engine, and Verisian's core-contributor, which holds the CORE 1.0 SDTM rules. Two other bundled pieces carry their own permissive licences: the W3C's XHTML schemas, used to check narrative text in USDM files, and IBM's JSONata, used to run some USDM rules. Every bundled file, where it came from and its licence are listed in inst/COPYRIGHTS.

CDISC, CORE, SDTM, SEND, ADaM, Define-XML and TIG are trademarks of the Clinical Data Interchange Standards Consortium, used here only to name the standards this package reads.

Reference manual

It appears you don't have a PDF plugin for this browser. You can click here to download the reference manual.

install.packages("coreval")

0.4.0 by Hrach Gevorgyan, 12 hours ago


https://hrach-gevorgyan.github.io/coreval/, https://github.com/hrach-gevorgyan/coreval


Report a bug at https://github.com/hrach-gevorgyan/coreval/issues


Browse source code at https://github.com/cran/coreval


Authors: Hrach Gevorgyan [aut, cre, cph]


Documentation:   PDF Manual  


MIT + file LICENSE license


Imports data.table, haven

Suggests jsonlite, knitr, QuickJSR, rmarkdown, testthat, writexl, xml2


See at CRAN