sdtm clinicalprogramming sas relrec recist oncology RELREC That Reviewers Can Follow: Linking PR, TU, TR, and RS for RECIST 1.1 July 28, 2026 ClinPilot Insights A clean Pinnacle 21 report can still leave you with oncology data that nobody can reliably reconstruct. I’ve seen this more than once. `TU`, `TR`, and `RS` all pass their structural checks. Dates line up. Visits look sensible. Then somebody asks a basic review question: > Which lesion measurements supported this overall response, and which scan produced those measurements? That’s where the mapping starts to wobble. RECIST 1.1 data aren’t one flat assessment table. The submitted evidence is distributed across lesion identification, lesion results, response assessments and, when imaging procedure details are submitted, `PR`. If those records are connected only by visit and date, the package may look tidy while carrying an ambiguous lineage path. ## Four Domains, Four Different Jobs Keep the domain responsibilities separate before writing any relationship code. - `TU` identifies the tumor or lesion and assigns its role in the response assessment. A stable `TULNKID` is the lesion identity used to associate later measurements with that lesion. - `TR` holds the lesion-level measurements or assessments. `TRLNKID` matches the lesion identifier in `TULNKID`. - `RS` holds disease-response findings, including the overall response under the specified criterion and evaluator. - `PR` may hold details of the imaging procedure, such as CT, MRI, or medical photography. CDISC’s RECIST 1.1 supplement says `PR` isn’t mandatory for RECIST 1.1, but it may be used when scan data are represented. That last distinction gets missed. Don’t manufacture `PR` simply to make the package look complete. If procedure-level data were collected and submitted, link them. If not, don’t invent them. The core path looks like this: `PR procedure → TU lesion identification → TR lesion assessment → RS response` But the identifiers don’t all do the same thing. ## Use the Link Variables for Their Intended Grain The current RECIST 1.1 supplement describes these linking variables: - `TULNKID` and `TRLNKID` connect a lesion identified in `TU` to its assessments in `TR`. - `TRREFID` and `TUREFID` can point back to the image identifier represented in `PRREFID`. - `TRLNKGRP` groups the lesion-level `TR` records supporting a response assessment. - `RSLNKGRP` carries the corresponding group value in `RS`. So, for one subject at Week 8, you might have: - A chest CT in `PR` with `PRREFID = "IMG-W08-01"` - Two target lesions in `TU`, carrying `TULNKID = "T01"` and `"T02"` - Two Week 8 measurements in `TR`, carrying matching `TRLNKID` values - Both `TR` rows assigned `TRLNKGRP = "INV-W08"` - The investigator’s overall response in `RS`, assigned `RSLNKGRP = "INV-W08"` That group value should distinguish assessment context. Week alone may not be enough. If both investigator and independent central review are submitted, `"W08"` is a collision waiting to happen. Use an unambiguous convention such as `"INV-W08"` and `"BICR-W08"`. Boring identifiers are good identifiers. They’re easier to inspect at 6:30 on a Friday when the transfer has just changed again. ## Why Date Joins Fail A merge on `USUBJID`, `VISITNUM`, and assessment date often appears to work. Until it doesn’t. Common break points include: - Several procedures performed on the same date - Separate anatomical imaging regions - Investigator and central-reader assessments at the same nominal visit - Partial dates - Unscheduled scans - Assessments assembled from images obtained on different dates - Re-read or adjudicated results - Lesions split or merged between assessments Dates describe timing. They don’t establish identity. Sequence numbers aren’t a safe cross-domain key either. `PRSEQ`, `TUSEQ`, `TRSEQ`, and `RSSEQ` identify records within their own domains. Matching `TRSEQ = 7` to `RSSEQ = 7` has no standard meaning. It’s accidental numerology dressed up as traceability. ## Build the Relationships Upstream The usual mistake is creating `RELREC` after all four domains are final, then trying to infer relationships from whatever variables survived. Backwards. Create stable source identifiers before domain mapping: - A procedure or image identifier - A lesion identifier - An assessment-group identifier - An evaluator or reading-stream identifier - A criterion identifier when more than one response criterion is submitted Carry those keys through intermediate data. Drop them only after they have populated standard linking variables and the relationship records have been created. Here’s a stripped-down SAS pattern for linking `TU` to `TR` by lesion identifier and `TR` to `RS` by assessment group. ```sas data rel_tu_tr; length studyid $20 rdomain $8 usubjid $40 idvar $8 idvarval $200 reltype $8 relid $40; set sdtm.tu( keep=studyid usubjid tulnkid where=(not missing(tulnkid)) ); rdomain = "TU"; idvar = "TULNKID"; idvarval = tulnkid; reltype = "ONE"; relid = cats("TU-TR-", usubjid, "-", tulnkid); keep studyid rdomain usubjid idvar idvarval reltype relid; run; data rel_tr_tu; length studyid $20 rdomain $8 usubjid $40 idvar $8 idvarval $200 reltype $8 relid $40; set sdtm.tr( keep=studyid usubjid trlnkid where=(not missing(trlnkid)) ); rdomain = "TR"; idvar = "TRLNKID"; idvarval = trlnkid; reltype = "MANY"; relid = cats("TU-TR-", usubjid, "-", trlnkid); keep studyid rdomain usubjid idvar idvarval reltype relid; run; data rel_tr_rs; length studyid $20 rdomain $8 usubjid $40 idvar $8 idvarval $200 reltype $8 relid $40; set sdtm.tr( keep=studyid usubjid trlnkgrp where=(not missing(trlnkgrp)) ); rdomain = "TR"; idvar = "TRLNKGRP"; idvarval = trlnkgrp; reltype = "MANY"; relid = cats("TR-RS-", usubjid, "-", trlnkgrp); keep studyid rdomain usubjid idvar idvarval reltype relid; run; proc sort data=rel_tr_rs nodupkey; by studyid rdomain usubjid idvar idvarval reltype relid; run; data rel_rs_tr; length studyid $20 rdomain $8 usubjid $40 idvar $8 idvarval $200 reltype $8 relid $40; set sdtm.rs( keep=studyid usubjid rslnkgrp where=(not missing(rslnkgrp)) ); rdomain = "RS"; idvar = "RSLNKGRP"; idvarval = rslnkgrp; reltype = "ONE"; relid = cats("TR-RS-", usubjid, "-", rslnkgrp); keep studyid rdomain usubjid idvar idvarval reltype relid; run; data sdtm.relrec; set rel_tu_tr rel_tr_tu rel_tr_rs rel_rs_tr; run; proc sort data=sdtm.relrec nodupkey; by studyid relid rdomain usubjid idvar idvarval; run; ``` This is an implementation pattern, not a universal template. Relationship cardinality must match the actual data. For example, one lesion in `TU` commonly relates to many longitudinal results in `TR`, while one response record may relate to many supporting `TR` records. And check your selected SDTMIG version. Don’t copy a relationship layout from an old study without checking the model, the RECIST supplement, and your validator configuration. ## Link PR by Image Identity, Not by Hope When `PR` contains imaging procedures, `PRREFID` can identify the image or image set. The corresponding `TUREFID` and `TRREFID` values provide the cross-domain reference. A simple orphan check catches a lot of damage: ```sas proc sql; create table qc_trrefid_without_pr as select tr.studyid, tr.usubjid, tr.trseq, tr.trrefid from sdtm.tr as tr left join sdtm.pr as pr on tr.studyid = pr.studyid and tr.usubjid = pr.usubjid and tr.trrefid = pr.prrefid where not missing(tr.trrefid) and missing(pr.prrefid); quit; ``` Run the reverse check too. If a submitted `PRREFID` is supposed to support oncology assessments but never appears in `TUREFID` or `TRREFID`, investigate it. Some procedures may legitimately remain unlinked. That should be explainable from the collection design, not discovered during submission QC. ## Validate the Graph, Not Just the Rows Dataset checks are necessary. They aren’t enough. Treat the four domains and `RELREC` as a small graph, then test the edges. ```sas proc sql; create table qc_tr_without_tu as select tr.studyid, tr.usubjid, tr.trseq, tr.trlnkid from sdtm.tr as tr left join sdtm.tu as tu on tr.studyid = tu.studyid and tr.usubjid = tu.usubjid and tr.trlnkid = tu.tulnkid where not missing(tr.trlnkid) and missing(tu.tulnkid); create table qc_rs_without_tr as select rs.studyid, rs.usubjid, rs.rsseq, rs.rslnkgrp from sdtm.rs as rs left join sdtm.tr as tr on rs.studyid = tr.studyid and rs.usubjid = tr.usubjid and rs.rslnkgrp = tr.trlnkgrp where not missing(rs.rslnkgrp) group by rs.studyid, rs.usubjid, rs.rsseq, rs.rslnkgrp having count(tr.trseq) = 0; quit; ``` Your study-level checks should cover at least these failures: - A nonmissing `TRLNKID` with no matching `TULNKID` - A response-support group in `RS` with no matching `TR` records - A `TRREFID` or `TUREFID` with no matching `PRREFID`, when `PR` is used - A `RELREC` pointer whose `RDOMAIN`, `USUBJID`, `IDVAR`, and `IDVARVAL` don’t resolve to a submitted record - A `RELID` with only one side of the relationship - Duplicate lesion IDs within an evaluator stream - Group IDs reused across evaluators or criteria - Links inferred solely from date or sequence number That final one won’t necessarily throw a standard conformance message. It’ll just give reviewers a questionable evidence chain. Worse, it may feed an incorrect ADRS derivation without producing an obvious error. ## Don’t Make RELREC Carry Bad Modeling `RELREC` records relationships. It doesn’t repair weak source keys. If lesion identity changes every visit, `RELREC` can’t tell you that `"LIVER-1"` and `"HEPATIC-A"` were meant to be the same lesion. If evaluator context is missing, a shared assessment-group value may connect investigator measurements to a central-reader response. If split and merged lesions aren’t handled according to the chosen modeling convention, adding more relationship rows simply documents confusion. Fix those issues where the identifiers are assigned. Also document the conventions in Define-XML and the Study Data Reviewer’s Guide: - How lesion IDs are assigned and retained - How evaluator streams are distinguished - How assessment-group values are formed - Whether `PR` is present and what `PRREFID` identifies - How split, merged, re-read, or adjudicated lesions are represented - Any relationships that are intentionally absent A reviewer shouldn’t have to reverse-engineer `"G00037"` from four datasets and a prayer. ## The Practical Test Pick one subject with awkward data. Not the clean demo patient. Choose somebody with an unscheduled scan, more than one reader, a new lesion, or a changed lesion state. Start from the overall response in `RS` and walk backwards: - Find the supporting `TR` assessment group. - Identify each lesion through `TRLNKID`. - Resolve each lesion to `TU`. - Resolve the applicable image references to `PR`, if procedure data are submitted. - Confirm evaluator, criterion, and time point remain consistent across the path. If a programmer unfamiliar with the study can do that without guessing, the relationship design is working. If they need a spreadsheet of unwritten assumptions, it isn’t. Recommended Insights sdtm define-xml validation Stop Hand-Coding VLM: Compile CDISC Dataset Specializations into Study Metadata Compile CDISC Dataset Specializations into governed study VLM before test codes, units, origins, and codelists drift apart. Jul 28, 2026 Read More sdtm adam validation Retiring --BLFL Without Breaking Baseline: Rebuilding SDTM Findings for --LOBXFL Replace --BLFL with --LOBXFL in SDTM while keeping protocol baseline logic where it belongs: traceable and reproducible in ADaM. Jul 28, 2026 Read More
sdtm define-xml validation Stop Hand-Coding VLM: Compile CDISC Dataset Specializations into Study Metadata Compile CDISC Dataset Specializations into governed study VLM before test codes, units, origins, and codelists drift apart. Jul 28, 2026 Read More
sdtm adam validation Retiring --BLFL Without Breaking Baseline: Rebuilding SDTM Findings for --LOBXFL Replace --BLFL with --LOBXFL in SDTM while keeping protocol baseline logic where it belongs: traceable and reproducible in ADaM. Jul 28, 2026 Read More