Runs 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)

Arguments

data

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.

spec

A submission_spec() object.

max_file_mb

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.

Value

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.

What is checked

Nineteen checks, in five groups. Each row of the returned tibble names the check that produced it.

Namesdataset_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.

Labelsdataset_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 encodingnon_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 duplicateslength_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.

Split datasets

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.

What is NOT checked

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.

Examples

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…