Different regulatory authorities
weight the four R4SUB evidence pillars (quality, trace, risk, usability)
differently. The r4subprofile package encodes these
authority-specific requirements so that the SCI can be calibrated
accordingly.
submission_profile() returns a profile with
authority-specific pillar weights, decision bands, and required
indicators:
profile_summary() returns a tidy tibble summarising the
profile:
profile_summary(fda_nda)
#> ℹ Submission Profile: FDA NDA
#> Authority: U.S. Food and Drug Administration (United States)
#>
#> Pillar Weights:
#> quality 0.35
#> trace 0.25
#> risk 0.25
#> usability 0.15
#>
#> Decision Bands:
#> ready [85, 100]
#> minor_gaps [70, 84]
#> conditional [50, 69]
#> high_risk [0, 49]
#>
#> Required Indicators (15):
#> - Q-MISS-VAR
#> - Q-TYPE-MISMATCH
#> - Q-LABEL-LEN
#> - Q-DUP-RECORDS
#> - Q-FORMAT-ERR
#> - T-ORPHAN-VAR
#> - T-TRACE-LEVEL
#> - T-AMBIGUOUS-MAP
#> - T-DERIVATION-DOC
#> - R-HIGH-RPN
#> - R-OPEN-RISK
#> - R-MITIGATION-GAP
#> - U-DEFINE-COMPLETE
#> - U-REVIEWER-NOTE
#> - U-LABEL-QUALITY
#>
#> Required Asset Types: dataset, define, program, validation, spec
#> Minimum Coverage: 90%
#> Default Detectability: 3validate_against_profile() checks an evidence table
against the profile’s required indicators and asset types:
ev <- data.frame(
run_id = "run-001",
study_id = "STUDY01",
asset_type = c("dataset", "define", "program", "spec"),
asset_id = c("ADSL", "define.xml", "prod_adsl.R", "ADSL"),
source_name = "r4subcore",
source_version = "0.1.2",
indicator_id = c("Q-001", "Q-002", "R-001", "U-001"),
indicator_name = c("Quality Check", "Define Check",
"Program Validation", "Label Quality"),
indicator_domain = c("quality", "quality", "risk", "usability"),
severity = "info",
result = "pass",
metric_value = 1,
metric_unit = "score",
message = "Check passed",
location = c("ADSL", "define.xml", "prod_adsl.R", "ADSL"),
evidence_payload = "{}",
created_at = Sys.time(),
stringsAsFactors = FALSE
)
val <- validate_against_profile(ev, fda_nda)
val$is_compliant
#> [1] FALSE
val$coverage
#> [1] 0
val$missing_indicators
#> [1] "Q-MISS-VAR" "Q-TYPE-MISMATCH" "Q-LABEL-LEN"
#> [4] "Q-DUP-RECORDS" "Q-FORMAT-ERR" "T-ORPHAN-VAR"
#> [7] "T-TRACE-LEVEL" "T-AMBIGUOUS-MAP" "T-DERIVATION-DOC"
#> [10] "R-HIGH-RPN" "R-OPEN-RISK" "R-MITIGATION-GAP"
#> [13] "U-DEFINE-COMPLETE" "U-REVIEWER-NOTE" "U-LABEL-QUALITY"The details tibble shows per-requirement status:
Some authorities adjust requirements based on study phase. Pass
study_phase to reflect phase-specific requirements:
A profile answers “what does this authority require”. A rule pack
pins that to a named, dated version, so a score can be reproduced and
compared over time as guidance changes. rule_packs() lists
what is available:
library(r4subprofile)
rule_packs()
#> # A tibble: 2 × 5
#> id authority version effective_date n_indicators
#> <chr> <chr> <chr> <chr> <int>
#> 1 fda-2026.1 FDA 2026.1 2026-01-01 15
#> 2 ema-2026.1 EMA 2026.1 2026-01-01 15Select one by id. Each indicator carries a source field
for its authoritative citation:
pack <- rule_pack("fda-2026.1")
pack
#> ℹ Rule pack "fda-2026.1": FDA, version 2026.1, effective 2026-01-01
#> ℹ 15 indicators, 0 with a source citation
head(rule_pack_indicators(pack))
#> # A tibble: 6 × 2
#> indicator_id source
#> <chr> <chr>
#> 1 Q-DUP-RECORDS <NA>
#> 2 Q-FORMAT-ERR <NA>
#> 3 Q-LABEL-LEN <NA>
#> 4 Q-MISS-VAR <NA>
#> 5 Q-TYPE-MISMATCH <NA>
#> 6 R-HIGH-RPN <NA>The built-in packs ship with source set to
NA: the citations are left for entry from a controlled
regulatory reference list, rather than filled with unverified section
numbers. Supply them when you have them:
pack <- rule_pack(
"fda-2026.1",
sources = c("Q-MISS-VAR" = "FDA Study Data Technical Conformance Guide")
)
subset(rule_pack_indicators(pack), !is.na(source))
#> # A tibble: 1 × 2
#> indicator_id source
#> <chr> <chr>
#> 1 Q-MISS-VAR FDA Study Data Technical Conformance GuideRecord the pack on a scored result so the score can always be traced back to the exact ruleset and version that produced it: