check_submission.RdRuns the checks that would otherwise cause a transport file to be rejected,
so the problems surface before the submission is written rather than after.
write_submission() calls this itself and refuses to write on any
"error" severity violation.
check_submission(data, spec, max_file_mb = 5000)A named list, one element per dataset, named to match
spec$datasets$dataset. Each element is a data frame, a list of data
frames (the parts of a split dataset), or a character vector of paths to
already-written .xpt files.
A submission_spec() object.
Per-file size ceiling in megabytes, used by the
file_size check. Defaults to 5000, the 5 GB per transport file ceiling
published by both FDA (Study Data Technical Conformance Guide) and PMDA.
submitpack does not track guidance revisions — set this yourself if the
guidance you are working to says something else. NULL skips the check.
A tibble of violations with columns dataset, variable,
check, severity ("error"/"warning") and message. Zero rows
means the submission is clean against the checks listed above — it does
not mean the submission is conformant.
Nineteen checks, in five groups. Each row of the returned tibble names the
check that produced it.
Names — dataset_name_length, variable_name_length (error): over 8
characters, which SAS v5 XPT cannot represent. dataset_name_chars,
variable_name_chars (error): anything outside ^[A-Za-z_][A-Za-z0-9_]*$
— a leading digit, a space, a hyphen, or a non-ASCII letter.
Labels — dataset_label_length (error): over 40 characters, the SAS v5
member label limit. variable_label_length (error): over 200 characters.
Note that a variable label is truncated to 40 bytes by the v5 NAMESTR
record itself, so 200 is the Define-XML limit, not the transport limit.
Character encoding — non_ascii_metadata, non_ascii_data (warning):
any byte above 0x7F in a label or in a character value. control_character
(error): any C0 control byte (0x01-0x1F) or DEL (0x7F) in a label or a
value, which corrupts the fixed-width record layout. Length checks count
bytes, not characters, because that is what the transport file stores:
a 3-character UTF-8 value can need 6 bytes.
Lengths and duplicates — length_too_short (error): the declared
length for a character variable is shorter than the longest value
actually observed, so writing it would silently truncate.
duplicate_dataset_name, duplicate_variable_name (error): in the spec
and in the real data frame's column names.
Splits — see the section below.
A dataset that exceeds the per-file size ceiling is submitted as numbered
parts, and the parts have to agree with each other: a variable that is
length 20 in lb1.xpt and length 30 in lb2.xpt is a finding, because the
reviewer cannot concatenate them without changing data. Pass the parts as a
list of data frames, or as paths to already-written .xpt files, and
check_submission() compares them:
split_variable_set (error): the parts do not carry the same variables.
split_variable_order (error): same variables, different order.
split_length_consistency (error): a variable's declared length differs
between parts.
split_label_consistency (error): a variable's label differs between
parts (compared on the first 40 bytes, which is all a v5 NAMESTR holds).
split_part_name_length (error): a part file name over 8 characters.
split_part_naming (warning): part names that are not
<dataset><n> — the convention agencies expect (lb1, lb2, ...). This
is a warning rather than an error because an 8-character dataset name
leaves no room for the suffix.
file_size (warning): the estimated size of a written part exceeds
max_file_mb, so it needs splitting (or splitting further).
When parts are supplied as data frames, the declared length comes from the
width attribute that xportr::xportr_length() sets, falling back to the
longest observed value. When they are supplied as file paths, it is read
out of the transport file's NAMESTR records, which is the real declared
length.
Everything else. In particular submitpack does not check controlled
terminology, codelist membership, Define-XML conformance or presence,
cross-dataset referential integrity (USUBJID in AE existing in DM),
required or expected variables for a domain, variable ordering against the
CDISC IG, date/time ISO 8601 formats, --SEQ uniqueness, value-level
metadata, SUPPQUAL structure, or any of the several hundred Pinnacle 21
rules. It is a transport-layer and split-layer gate, not a conformance
engine. Run Pinnacle 21 (or p21bridge) for conformance.
datasets <- data.frame(dataset = "DM", label = "Demographics", class = "SDTM")
variables <- data.frame(
dataset = "DM", variable = c("USUBJID", "VERYLONGVARNAME"),
label = c("Unique Subject Identifier", "ok"),
type = c("character", "character"), length = c(4, 8),
format = NA_character_, order = 1:2
)
spec <- new_submission_spec(datasets, variables)
dm <- data.frame(USUBJID = c("SUBJECT-001", "SUBJECT-002"), VERYLONGVARNAME = "x")
check_submission(list(DM = dm), spec)
#> # A tibble: 2 × 5
#> dataset variable check severity message
#> <chr> <chr> <chr> <chr> <chr>
#> 1 DM VERYLONGVARNAME variable_name_length error Variable 'VERYLONGVARNA…
#> 2 DM USUBJID length_too_short error Variable 'DM.USUBJID' d…
# Two parts of a split dataset that disagree on a variable's length
spec2 <- submission_spec(
data.frame(dataset = "LB", label = "Laboratory", class = "SDTM"),
data.frame(dataset = "LB", variable = "LBTESTCD", label = "Test Code",
type = "character", length = 8, format = NA_character_, order = 1)
)
p1 <- data.frame(LBTESTCD = "ALT")
p2 <- data.frame(LBTESTCD = "AST")
attr(p1$LBTESTCD, "width") <- 8
attr(p2$LBTESTCD, "width") <- 20
check_submission(list(LB = list(lb1 = p1, lb2 = p2)), spec2)
#> # A tibble: 1 × 5
#> dataset variable check severity message
#> <chr> <chr> <chr> <chr> <chr>
#> 1 LB LBTESTCD split_length_consistency error Variable 'LBTESTCD' is len…