Four deterministic conformance checks over a CDISC SDTM delivery — structural completeness, cross-field consistency, visit & date coherence, and controlled terminology. No model, no API key, no per-run cost.
Download v0.1.0 (tar.gz) SHA-256
A finding has to be reproducible to be usable as regulatory evidence. The same delivery plus the same controlled-terminology release always produces the same findings, so a reviewer can re-run a check and get the same answer. That is the property a language model cannot offer, and it is why these are plain R scripts rather than agents.
| Check | Sees | Blocking findings |
|---|---|---|
structural | delivery completeness, readability, encoding | missing DM, missing expected domain, unreadable file |
consistency | who — values individually legal but mutually contradictory | contradicted USUBJID composition, orphan USUBJID, duplicate DM subject |
temporal | when — contradictory dates, disagreeing visit identifiers | start after end, death before reference start, one VISITNUM with two VISIT labels |
terminology | CDISC controlled terminology | non-extensible codelist violation |
The scopes are deliberately separate, and each split was forced by evidence rather than design taste. Running terminology alone over a set of deliberately corrupted sample deliveries scored two of them identically to a clean one; adding the structural check still scored a third one identically. Each gap was a real blind spot in the checks that existed, not a bug in them.
| Codelist | Example | Verdict |
|---|---|---|
| Non-extensible | DM.SEX = "X" against Sex (C66731) |
Blocking — a sponsor cannot extend this list, so the value is simply wrong |
| Extensible | LB.LBTESTCD = "BUN" against Laboratory Test Code |
Review item — a legitimate sponsor extension |
Flagging extensible extensions would make every real study fail; ignoring non-extensible violations would miss the ones that matter.
tar xzf sdtm-check-0.1.0.tar.gz
cd sdtm-check-0.1.0
chmod +x bin/sdtm-check scripts/*.R
./bin/sdtm-check /path/to/sdtm --expect DM,AE,EX,LB,VS
./bin/sdtm-check /path/to/sdtm --strict # exit 1 if anything blocks (CI gating)
./bin/sdtm-check --selftest # run the 20 bundled checks
It runs all four checks, writes one JSON report each, and prints a consolidated summary:
CHECK FINDINGS BLOCKING DETAIL
structural 0 0 structural-findings.json
consistency 1 1 consistency-findings.json
temporal 0 0 temporal-findings.json
terminology 4 1 ct-findings.json
2 blocking finding(s) — a reviewer must adjudicate before the delivery is accepted:
[sdtm_consistency] orphan_usubjid domain=AE usubjid=ORPHAN-99
[cdisc_ct_conformance] ct_nonconformant domain=DM variable=SEX value=X
All four scripts exit 0 whenever the check itself completed, even with blocking findings present.
A blocking finding is a successful result — the check did its job, and a human decides what
it means. Pass --strict, or read .blocking_count from the JSON, when you
want a non-zero exit for CI.
--demo. The bundled --demo mode generates a
delivery with known defects from a sample study that ships with the development tree, not with this
tarball. Outside that tree it will report that the sample is missing. Point the tool at your own
SDTM directory instead.
The distribution includes clincoder-ct-check.wd.json, a workflow definition that runs
the four checks as deterministic script steps followed by a human review gate, on
Mediforce. Each step is attributed in the audit
trail as executed by a script; the review gate records the reviewer's verdict, the reason the
transition was taken, and their verbatim comment.
upload-sdtm (human)
→ structural-check (script)
→ consistency-check (script)
→ temporal-check (script)
→ ct-conformance (script)
→ review-findings (human)
→ done
container/Dockerfile and scripts/build-image.sh build the step image.
p21bridge supplies. Pin it per study
if a submission requires a specific release.VISITNUM and VISIT.