SaMD study lifecycle (research → holdout enrichment → pivotal)¶
What this chapter is¶
The recommended path for creating new healthy-vs-disease studies when you intend FDA-style SaMD evidence controls: real holdouts, locked hyperparameters before claims, and a small profile ladder.
This is not an FDA submission package. Architecture and profiles do not equal regulatory approval. See docs/regulatory/.
For a first binary or multi-stage walkthrough without the SaMD ladder, use Tutorial ch.16. For hyperparameter search mechanics, see ch.15 and packages/methylvalidation/docs/HYPERPARAMETER_SEARCH.md.
Mental model¶
| Layer | Owns | SaMD rule |
|---|---|---|
Study manifest project_*.json |
Cohorts, stages, validation_partitions, regulatory |
Who is train vs holdout; claim stage |
Profile samd_*.profile.json |
Iterations, BA gates, caps, holdout eval flags | How hard the science gates are |
| DomainProgram | Topology (MC → stability → freeze → model) | What runs |
| Site | Cluster caps (max DMPs/genes), genomes | Deployment bounds |
Never put tool knobs in the study manifest (step_config is rejected). Never move locked_test / pivotal_validation patients back into training.
flowchart LR
init["methyl-study-init"] --> research["samd_research"]
research -->|"lock HPs + require locked_test"| enrich["samd_holdout_enrichment"]
enrich -->|"freeze + open pivotal cohort"| pivotal["samd_pivotal"]
research -.-> search["hyperparam search + early-stop"]
SaMD study lifecycle
Three profiles¶
| Profile | Default regulatory.stage |
Holdouts | Hyperparameters |
|---|---|---|---|
samd_research |
expanded_development |
locked_test recommended |
Early-stop on; exploratory BA; fail_if_below_target: false; Tier A/B search OK |
samd_holdout_enrichment |
internal_validation |
Required non-empty locked_test; excluded from training |
Lock BA/caps/n_iterations from research; freeze readiness before model |
samd_pivotal |
pivotal_validation |
Required non-empty pivotal_validation (never used in research/enrichment training) |
Fully locked; hard BA fail; biological review required |
Existing mc_* profile names remain as deprecated aliases that fold into samd_research + a researchMode overlay (dmp_raw, dmp_fc, gene_enricher, gene_fc, dual_fc). Prefer pipelineProfile: samd_research with an explicit researchMode for research axes; keep the three-profile SaMD ladder (samd_research → samd_holdout_enrichment → samd_pivotal) for claim-bound studies—do not fold holdout/pivotal into research modes.
Clinical performance claims (allow_clinical_performance_claims: true) are code-blocked before pivotal_validation stage.
Step 0 — Scaffold a study¶
source .venv/bin/activate
methyl-study-init \
--study-id my-disease \
--name Healthy_vs_Disease \
--analyte buffy_coat \
--binary \
--output-root /work/projects
# or: --stages 3
Creates:
/work/projects/my-disease/
data/healthy.csv
data/disease.csv # or stage_1.csv …
configs/project_Healthy_vs_Disease.json
configs/README.md
Add --modality rnaseq for an RNA-Seq study (see ch.20); the default is methylation. Config overlays on an existing process are application packs — see the generic pattern in ch.24. Worked methylation instances: Alzheimer cfDNA (disease — staged Control -> MCI -> AD, cfDNA, neuro-core), Plant abiotic stress (trait — Arabidopsis Control vs Drought, plant_tissue, CG/CHG/CHH), and prostate cancer options (multi-path catalog).
Fill CSVs with sample IDs (patient-disjoint). Assign holdouts early:
- Put never-to-be-trained patients in
validation_partitions.locked_test. - Leave
pivotal_validationempty until the clinical-trial / pivotal cohort is opened. - Use
independence_keys(sample_id,patient_id, …) so the same patient cannot appear in train and holdout.
Validate before enrichment or pivotal runs:
methyl-study-validate-manifest \
--project /work/projects/my-disease/configs/project_Healthy_vs_Disease.json \
--profile samd_holdout_enrichment
Step 1 — Research (unknown hyperparameters)¶
- Set study
regulatory.stagetofeasibilityorexpanded_development. - Keep
allow_clinical_performance_claims: false. - Run MC stability with
samd_research:
Binary:
methyl-workflow-run \
--program workflow_engine/domain/fixtures/mc_stability.program.json \
--context-file workflow_engine/domain/profiles/samd_research.profile.json \
--context '{"projectPath":"/work/projects/my-disease/configs/project_Healthy_vs_Disease.json","pipelineProfile":"samd_research"}' \
--parallel-workers 1
Multi-stage:
methyl-workflow-run \
--program workflow_engine/domain/fixtures/mc_stability_staged.program.json \
--context-file workflow_engine/domain/profiles/samd_research.profile.json \
--context '{"projectPath":"/work/projects/my-disease/configs/project_Healthy_vs_Disease.json","pipelineProfile":"samd_research"}' \
--parallel-workers 1
- Discover knobs with early-stop and optional
methyl-hyperparam-search(Tier A/B only at this tier). - Record winning
n_iterations, FeatureCuts BA targets, and DMP/gene caps in a study-local overlay under/work(not in git), e.g./work/projects/my-disease/configs/overlay_locked_hps.json, for the next tier.
Step 2 — Holdout enrichment (add samples, real holdouts)¶
- Add new patients only to development cohort CSVs (or
development_trainlists). - Never move
locked_testsamples into training. Growlocked_testonly with new never-trained patients if needed. - Set
regulatory.stagetointernal_validation(thenmodel_freezeafter freeze readiness). - Apply locked HPs via
--context-fileoverlay +samd_holdout_enrichment. - Require non-empty
locked_test; run validate-manifest. - Run enrichment MC / lifecycle; pass
methyl-stability-freeze-readiness(go or go_with_risks) before model. - Run true holdout eval (WF3): profile sets
holdout_eval/holdout_partition: locked_test.
Partition promotion example¶
| Action | Train CSVs | locked_test |
pivotal_validation |
|---|---|---|---|
| After research | 40H + 40D | 10H + 10D reserved | empty |
| Add 10 patients | 45H + 45D (new only) | unchanged 10+10 | empty |
| Open pivotal | unchanged | unchanged | 20H + 20D new trial patients |
Step 3 — Pivotal / clinical trial¶
- Populate
validation_partitions.pivotal_validationwith trial patients disjoint from all prior train andlocked_testIDs. - Set
regulatory.stagetopivotal_validation. - Only then consider
allow_clinical_performance_claims: true(still requires human review of intended use). - Run with
samd_pivotal(holdout partition =pivotal_validation; early-stop off; hard BA fail). - Prefer full lifecycle program for freeze + model + post-model:
methyl-workflow-run \
--program workflow_engine/domain/fixtures/study_validation_lifecycle.program.json \
--context-file workflow_engine/domain/profiles/samd_pivotal.profile.json \
--context '{"projectPath":"/work/projects/my-disease/configs/project_Healthy_vs_Disease.json","pipelineProfile":"samd_pivotal"}' \
--parallel-workers 1
- Fill an evidence package in
docs/regulatory/validation-evidence-index.md(release SHA, profile, partitions, metrics paths). Submission topic map:docs/regulatory/samd-submission-scaffold.md(scaffold only — not FDA clearance).
Program pairing¶
| Tier | Binary DomainProgram | Staged DomainProgram |
|---|---|---|
| research / enrichment MC | buffy_healthy_vs_pca/.../mc_stability.program.json |
pca1_5_cg/.../mc_stability_staged.program.json |
| freeze + model + post-model | pca1_5_cg/.../study_validation_lifecycle.program.json |
same |
| Presets | scripts/workflow_presets.sh show samd_research_binary (etc.) |
samd_research_staged |
Admin CLI (distributed)¶
# After deploy_workflow_definitions.sh — start validation with SaMD profile in context
methyl-study-start validation-start request.json
Request context must include projectPath and pipelineProfile (samd_research | samd_holdout_enrichment | samd_pivotal). See Admin CLI.
Anti-patterns¶
- Using enrichment/pivotal profiles with empty required partitions
- Tuning BA/caps on pivotal data
- Claiming clinical performance before
pivotal_validationstage - Putting hyperparameters in
project_*.json - Reusing research random MC splits as if they were classical holdouts (see theory ch.12 WF2 vs WF3)