This guide is the ordinary CausalStress workflow. It uses exported functions and estimators shipped with the package. A run produces estimator outputs and a typed score surface; cs_collect_scores() is the canonical way to collect that surface. The older ATT- and QST-specific collectors remain compatibility projections.
Discover governed components
Suites are named collections, not a scientific endorsement of every member. Inspect the DGP status and estimator requirements before running a study.
suites <- cs_suite_registry()
suites[, c("suite_id", "description")]# A tibble: 5 × 2
suite_id description
<chr> <chr>
1 placebo All placebo (sharp-null) DGPs
2 heavytail Heavy-tail signal and placebo heavy-tail DGPs
3 signal Signal-focused DGPs (baseline, QTE heterogeneity, nonlinear heteros…
4 stress Stress-test DGPs (overlap and tilt stressors)
5 all All available synthetic DGPs
baseline <- cs_get_dgp("synth_baseline")
baseline[c("dgp_id", "version", "status", "type")]# A tibble: 1 × 4
dgp_id version status type
<chr> <chr> <chr> <chr>
1 synth_baseline 1.6.0 stable synthetic
lm_descriptor <- cs_get_estimator("lm_att")
lm_descriptor[c(
"estimator_id", "type", "oracle", "supports_qst", "version",
"source", "requires_pkgs"
)]$estimator_id
[1] "lm_att"
$type
[1] "gcomp"
$oracle
[1] FALSE
$supports_qst
[1] FALSE
$version
[1] "0.2.1"
$source
[1] "core"
$requires_pkgs
character(0)
Run once, then collect typed scores
cs_run_single() is the smallest ordinary entry point. The result keeps typed estimator outputs, canonical scores, compatibility projections (att and qst), bootstrap draws when requested, metadata, and provenance.
one_run <- cs_run_single(
dgp_id = "synth_baseline",
estimator_id = "lm_att",
n = 200,
seed = 17
)
names(one_run)[1] "outputs" "scores" "att" "qst" "boot_draws"
[6] "meta" "provenance"
one_scores <- cs_collect_scores(one_run)
one_scores |>
select(
estimand_target_id, metric_id, score_status,
estimate, truth, error, non_comparable_reason
)# A tibble: 1 × 7
estimand_target_id metric_id score_status estimate truth error
<chr> <chr> <chr> <dbl> <dbl> <dbl>
1 att point_error scored 1.04 1.09 -0.0480
# ℹ 1 more variable: non_comparable_reason <chr>
Each score row has an estimand_target_id. CausalStress compares an estimator output only with truth for that same target:
- ATT is the mean structural effect among treated units when that mean is a valid target for the DGP regime.
- ATE is the finite-sample mean structural effect over all generated units.
-
QST is a quantile-specific distributional contrast among treated units, indexed by
tau. - CATE is an explicitly staged target. Wave 1 records whether an estimator produced it, but does not yet score a CATE curve.
Targets are never silently cross-scored. A CATE estimate is not an ATT estimate, and an ATT estimate is not a QST estimate.
Request ATT and ATE explicitly
The built-in oracle is useful for testing benchmark truth plumbing. It is not an ordinary estimator: its descriptor permits the runner to grant governed structural_te through the Airlock.
oracle_run <- cs_run_single(
dgp_id = "synth_baseline",
estimator_id = "oracle_att",
n = 200,
seed = 17,
config = list(estimand_targets = c("att", "ate"))
)
cs_collect_scores(oracle_run) |>
select(estimand_target_id, metric_id, score_status, estimate, truth, error)# A tibble: 2 × 6
estimand_target_id metric_id score_status estimate truth error
<chr> <chr> <chr> <dbl> <dbl> <dbl>
1 att point_error scored 1.09 1.09 0
2 ate point_error scored 0.974 0.974 0
QST truth is defined on potential-outcome distributions. This direct DGP call is a truth-definition demonstration; do not pass y0, y1, p, or structural_te to an ordinary estimator.
truth_example <- dgp_synth_baseline(n = 300, seed = 19)
cs_true_qst(
y0 = truth_example$df$y0,
y1 = truth_example$df$y1,
w = truth_example$df$w,
tau = c(0.25, 0.50, 0.75)
)# A tibble: 3 × 2
tau value
<dbl> <dbl>
1 0.25 0.693
2 0.5 1.11
3 0.75 1.42
No dependency-free estimator shipped with CausalStress currently produces QST. The optional GenGC estimator does. Its example is deliberately opt-in so the ordinary article remains executable without optional estimator packages.
run_optional_qst <- requireNamespace("GenGC", quietly = TRUE) &&
identical(tolower(Sys.getenv("CAUSALSTRESS_RUN_OPTIONAL_DOCS")), "true")
if (!run_optional_qst) {
message(
"Optional QST example skipped. Install GenGC and set ",
"CAUSALSTRESS_RUN_OPTIONAL_DOCS=true to run it."
)
}Optional QST example skipped. Install GenGC and set CAUSALSTRESS_RUN_OPTIONAL_DOCS=true to run it.
qst_run <- cs_run_single(
dgp_id = "synth_qte1",
estimator_id = "gengc",
n = 300,
seed = 19,
status = "experimental",
tau = c(0.25, 0.50, 0.75),
config = list(estimand_targets = "qst")
)
cs_collect_scores(qst_run) |>
select(estimand_target_id, tau, metric_id, score_status, estimate, truth, error)Make staged targets visible
A mixed request can preserve executable ATT evidence while explicitly showing that CATE scoring is not implemented. The CATE row is evidence about the current contract; it is not an ATT result under another name.
staged <- cs_run_single(
dgp_id = "synth_baseline",
estimator_id = "lm_att",
n = 200,
seed = 23,
config = list(estimand_targets = c("att", "cate"))
)
cs_collect_scores(staged) |>
select(
estimand_target_id, metric_id, score_status,
estimate, non_comparable_reason
)# A tibble: 2 × 5
estimand_target_id metric_id score_status estimate non_comparable_reason
<chr> <chr> <chr> <dbl> <chr>
1 att point_error scored 1.25 <NA>
2 cate point_error non_comparable NA target_not_implemented
Repeat over seeds and summarize
Use cs_run_seeds() for one DGP-estimator pair and cs_run_grid() for ordinary cross-product work. Keep typed scores for target-aware analysis; use the summary helpers only where the target and moment regime make the aggregate meaningful.
runs <- cs_run_grid(
dgp_ids = "synth_baseline",
estimator_ids = c("lm_att", "ipw_att"),
n = 200,
seeds = 1:3,
show_progress = FALSE
)Running batch: synth_baseline x lm_att
Running batch: synth_baseline x ipw_att
typed_scores <- cs_collect_scores(runs)
typed_scores |>
count(estimator_id, estimand_target_id, score_status)# A tibble: 2 × 4
estimator_id estimand_target_id score_status n
<chr> <chr> <chr> <int>
1 ipw_att att scored 3
2 lm_att att scored 3
summary <- cs_summarise_runs(runs)
summary# A tibble: 2 × 14
dgp_id estimator_id n oracle supports_qst n_runs mean_true_att
<chr> <chr> <int> <lgl> <lgl> <int> <dbl>
1 synth_baseline ipw_att 200 FALSE FALSE 3 1.12
2 synth_baseline lm_att 200 FALSE FALSE 3 1.12
# ℹ 7 more variables: mean_est_att <dbl>, mean_error <dbl>, sd_error <dbl>,
# mean_abs_error <dbl>, max_abs_error <dbl>, mean_att_covered <dbl>,
# mean_att_ci_width <dbl>
cs_plot_att_error(runs)
Do not use mean-based ATT RMSE, coverage, or rankings for synth_heavytail. That DGP intentionally probes an estimand boundary under Cauchy-mixture noise: its governed structural contrast is a signal anchor, not a conventional mean potential-outcome ATT. Run ATT estimators there to study breakdown, but use QST for valid distributional comparisons rather than an ATT shootout.
Inspect provenance
Scientific identities live in the result metadata and score records; non-scientific execution details live in provenance.
cs_meta_flatten(one_run) |>
select(
dgp_id, dgp_version, estimator_id, estimator_version,
config_fingerprint, fit_fingerprint
)# A tibble: 1 × 6
dgp_id dgp_version estimator_id estimator_version config_fingerprint
<chr> <chr> <chr> <chr> <chr>
1 synth_baseline 1.6.0 lm_att 0.2.1 aadd190389820d49ea5…
# ℹ 1 more variable: fit_fingerprint <chr>
cs_provenance(one_run)[c("run_time_dgp", "run_time_est", "run_time_total")]$run_time_dgp
[1] 0.004334927
$run_time_est
[1] 0.00509572
$run_time_total
[1] 0.03819466
Persist completed runs and resume strictly
Persistence is opt-in. Without a board, results are returned but not stored. With a pins board, completed results are written as RDS-backed pins. Resume is also opt-in: skip_existing = TRUE reuses only schema-4 artifacts whose configuration fingerprint matches exactly. A missing/old schema or a mismatch fails closed. force = TRUE or skip_existing = FALSE recomputes instead.
board_path <- tempfile("causalstress-board-")
dir.create(board_path)
board <- pins::board_folder(board_path)
first_pass <- cs_run_seeds(
dgp_id = "synth_baseline",
estimator_id = "lm_att",
n = 150,
seeds = 1:2,
board = board,
show_progress = FALSE
)
resumed <- cs_run_seeds(
dgp_id = "synth_baseline",
estimator_id = "lm_att",
n = 150,
seeds = 1:3,
board = board,
skip_existing = TRUE,
show_progress = FALSE
)
resumed |>
select(seed, config_fingerprint)# A tibble: 3 × 2
seed config_fingerprint
<int> <chr>
1 1 d48750694cbdfa12bdb8665b5a46f19da64308ccfb13557906e8f5e9a0c2f853
2 2 348c3ae6dde770b0de1a4d7c8236830422a739d8ae5ae986a6de1d19dbed80ba
3 3 740daaf9a345bfd9aa6e6040a916eab98938ce92cddd84d953c33cfd09cf3aca
# A tibble: 3 × 4
dgp_id estimator_id n seed
<chr> <chr> <int> <int>
1 synth_baseline lm_att 150 1
2 synth_baseline lm_att 150 2
3 synth_baseline lm_att 150 3
Persistence protects completed artifacts, not an in-progress estimator call or an entire campaign transaction. Experimental parallel persistence additionally uses worker staging followed by controlled single-writer gathering.
Advanced planned batching
cs_plan_campaign() plus cs_run_batch() is the advanced lifecycle for explicit plans and batch artifacts. It is distinct from ordinary single, seed, and grid execution. cs_run_campaign() currently supports both a direct grid mode and a planned-batch mode; this guide does not redefine or deprecate either public contract.
plan <- cs_plan_campaign(
dgp_list = c("synth_baseline"),
estimator_list = c("lm_att", "ipw_att"),
n_seeds = 1:100,
batch_size = 20,
strategy_map = list(defaults = list(n = 1000))
)
batch_1 <- cs_run_batch(
plan = plan,
batch_id = 1,
staging_dir = "staging_batches"
)