library(CausalStress)
library(dplyr)
library(pins)
board_path <- tempfile("causalstress-history-")
dir.create(board_path)
board <- board_folder(board_path)CausalStress separates execution, optional persistence, typed scoring, and audit. A board is required only when results should be stored; without it, runners simply return their result objects.
Run and persist one seed
cs_run_single() returns typed outputs and scores, compatibility ATT/QST projections, optional bootstrap draws, metadata, and provenance. Bootstrap draws are present only when the estimator/runner produced them.
one_run <- cs_run_single(
dgp_id = "synth_baseline",
estimator_id = "lm_att",
n = 200,
seed = 123,
board = board
)
names(one_run)[1] "outputs" "scores" "att" "qst" "boot_draws"
[6] "meta" "provenance"
cs_collect_scores(one_run) |>
select(estimand_target_id, metric_id, score_status, estimate, truth, error)# A tibble: 1 × 6
estimand_target_id metric_id score_status estimate truth error
<chr> <chr> <chr> <dbl> <dbl> <dbl>
1 att point_error scored 1.07 1.07 0.00681
# A tibble: 1 × 5
dgp_id estimator_id seed est_att att_error
<chr> <chr> <int> <dbl> <dbl>
1 synth_baseline lm_att 123 1.07 0.00681
Only the completed result is persisted. The board does not make an in-progress estimator call recoverable.
Scale to an ordinary grid
This small grid uses the finite-moment baseline DGP, so the displayed mean ATT error summaries have their ordinary interpretation. Heavy-tail estimand-boundary runs should be executed and reported separately, not placed in a mean-based ATT RMSE, coverage, or ranking shootout.
runs <- cs_run_grid(
dgp_ids = "synth_baseline",
estimator_ids = c("lm_att", "ipw_att"),
n = 200,
seeds = 1:3,
board = board,
show_progress = FALSE
)Running batch: synth_baseline x lm_att
Running batch: synth_baseline x ipw_att
scorecard <- cs_summarise_runs(runs)
scorecard |>
select(
dgp_id, estimator_id, n_runs,
mean_error, mean_abs_error, sd_error
)# A tibble: 2 × 6
dgp_id estimator_id n_runs mean_error mean_abs_error sd_error
<chr> <chr> <int> <dbl> <dbl> <dbl>
1 synth_baseline ipw_att 3 -0.0318 0.137 0.202
2 synth_baseline lm_att 3 -0.0327 0.101 0.149
mean_error is signed mean deviation, mean_abs_error is mean absolute deviation, and sd_error is the standard deviation across the supplied runs. None of those columns is RMSE.
Resume matching completed work
Resume is explicit and strict. skip_existing = TRUE requires current schema-4 metadata and an exact configuration fingerprint before reading an existing pin. Here all requested records already exist, so the estimators are not rerun.
resumed <- cs_run_grid(
dgp_ids = "synth_baseline",
estimator_ids = c("lm_att", "ipw_att"),
n = 200,
seeds = 1:3,
board = board,
skip_existing = TRUE,
show_progress = FALSE
)Running batch: synth_baseline x lm_att
Running batch: synth_baseline x ipw_att
resumed |>
count(estimator_id)# A tibble: 2 × 2
estimator_id n
<chr> <int>
1 ipw_att 3
2 lm_att 3
Filesystem reads and validation still take time. A mismatch or historical schema fails closed; use force = TRUE only when recomputation and replacement are intentional.
Audit and reload persisted evidence
cs_audit() inventories pins and their recorded identities. It does not turn timestamps or runtime logs into scientific identity fields.
history <- cs_audit(board)
history |>
select(
dgp_id, estimator_id, estimator_version,
seed, fit_fingerprints, score_fingerprints, pin_name
) |>
head()# A tibble: 6 × 7
dgp_id estimator_id estimator_version seed fit_fingerprints
<chr> <chr> <chr> <int> <list>
1 synth_baseline ipw_att 0.2.1 1 <chr [1]>
2 synth_baseline ipw_att 0.2.1 2 <chr [1]>
3 synth_baseline ipw_att 0.2.1 3 <chr [1]>
4 synth_baseline lm_att 0.2.1 1 <chr [1]>
5 synth_baseline lm_att 0.2.1 123 <chr [1]>
6 synth_baseline lm_att 0.2.1 2 <chr [1]>
# ℹ 2 more variables: score_fingerprints <list>, pin_name <chr>
A pins board remains an ordinary persistence boundary, so a selected artifact can be loaded with pins and then inspected through CausalStress accessors.
target <- history |>
filter(
dgp_id == "synth_baseline",
estimator_id == "lm_att",
seed == 1
) |>
slice(1)
stored_result <- pin_read(board, target$pin_name)
cs_meta_flatten(stored_result) |>
select(dgp_id, estimator_id, seed, fit_fingerprint)# A tibble: 1 × 4
dgp_id estimator_id seed fit_fingerprint
<chr> <chr> <int> <chr>
1 synth_baseline lm_att 1 ce6d27d319adb1e646f5d1e1892188bd5a78eef5e96…
cs_provenance(stored_result)[c("run_time_dgp", "run_time_est", "run_time_total")]$run_time_dgp
[1] 0.003341913
$run_time_est
[1] 0.001786947
$run_time_total
[1] 0.02736688
For experimental parallel execution, workers stage completed RDS artifacts and the controlling process gathers them through a single-writer path. That is a different contract from serial board writes and does not make a whole campaign transactional.