Appendix C — One page: a SAP in a regulated R environment
Status: [Y] my synthesis of common practice, not a standard. Company SOPs override everything here. Nothing below is a quoted regulatory requirement.
| Topic | Practice | In this repo |
|---|---|---|
| Environment | Pin R and every package version (renv.lock), same container image for the whole study, no upgrades after SAP lock |
renv.lock |
| Package validation | Risk-based: base/recommended R, widely used CRAN packages with their own test suites, and own functions (full tests). Document intended use and a risk rating per package | cross-checks of package vs hand code in every chapter |
| Own functions | Written to a specification, unit-tested (testthat), tests re-run on every change |
tests/testthat/ (54+ tests) |
| Double programming | Primary endpoints independently programmed by a second person from raw data with a different code path; automated comparison with a tolerance | SAP §12 (agreed to < 1e-10) |
| Independent review | Code review of everything else; reviewer different from author | – |
| Script QC checklist | See below | – |
| Audit trail | Everything in git; signed tags at SAP lock, data lock and final analysis; file hashes of data and cut-off files; outputs only produced by scripts, never edited by hand | SAP §13 (md5) |
| Reproducibility | Fixed seeds, sessionInfo() logged with each run, no interactive state |
seeds set in all chunks |
| Versioning and deviations | SAP versioned; post-lock changes via a documented amendment; deviation log | SAP header |
| Data standards | Raw → ADaM-style analysis datasets → TFLs; raw data read-only | mock_sap/data/ |
| SOP references | Programming, QC, data management, change control, archiving: cite the SOP numbers in the SAP | placeholders |
Script QC checklist (example)
Worked example of why double programming pays
While building the mock SAP, the independent re-derivation disagreed with the lead code: the shared helper classified a value equal to the upper cut-off as positive (>=), while the SAP convention (and the public FDA convention) is positive if >. Rounded assay values sit exactly on the cut-off, so the two programmes differed. The helper was fixed and a boundary unit test added.