Robustness sweep over contextual assumptions (worst-case power and n_max)
Source:R/robust.R
ape_robust.RdPower computed from a single guess at the contextual inputs – baseline
rate, nuisance signal, covariate dependence – is fragile (Hancock &
Feng, 2026). ape_robust() re-runs the power analysis over a scenario
grid of those inputs and reports per-scenario power, the worst case, and
(optionally) n_max: the sample size that reaches the target power in
every scenario – the insurance-premium n.
Usage
ape_robust(
dgp,
n,
claim = c("minimum", "detect", "equivalence"),
sesoi = NULL,
alpha = 0.05,
conf = NULL,
nsim = 800,
seed = NULL,
vary,
pin = c("ape", "coefficients"),
mode = c("power", "mde"),
power = 0.8,
grid_points = 3,
nmax = TRUE,
nmax_power = 0.9,
se = c("model", "robust"),
direction = NULL,
separation = c("fail", "keep")
)Arguments
- dgp
- n
Total sample size of the simulated study.
- claim
"minimum"(default),"detect", or"equivalence".- sesoi
Smallest effect size of interest, in APE units. Required for
"minimum"and"equivalence"; optional for"detect"(if supplied, the outcome table is still broken out against it).- alpha
The claim's error rate (default 0.05): two-sided for
"detect", one-sided for"minimum", TOST for"equivalence". May also be a sample-size rule: a function ofnreturning the error rate to use at thatn, for examplefunction(n) alphaN::alphaN(n, BF = 3), the Bayes-factor calibration of Wulff and Taylor (2024) that lowers alpha asngrows. The searching functions evaluate the rule at every candidaten, soape_n()designs jointly over the pair (alpha(n), n); results store the rule and the level it produced.- conf
Optional override: the interval level used for the claim itself (
1 - alphafor detection,1 - 2 alphaotherwise). Supplyingconf = 0.95for a minimum-effect or equivalence claim reproduces the pre-1.8.0 behavior (one-sided error rate 2.5%).- nsim
Number of simulation replications.
- seed
Optional seed (the caller's RNG state is preserved).
- vary
Named list of scenario values for contextual inputs. Parametric route:
baseline,signal,correlation(scalar); empirical route:baseline,signal. A length-2 element is expanded togrid_pointsequally spaced values; longer vectors are used as-is. Scenarios are the full factorial grid.- pin
"ape"(re-invert per scenario) or"coefficients"(hold coefficients, let the implied effect drift). Ignored in MDE mode, which always re-solves.- mode
"power"(default) reports power at the pinned effect per scenario;"mde"reports the minimum detectable effect per scenario viaape_mde()– the worst case is then the MDE largest in magnitude, answering "what is the smallest effect this design finds even under the least favorable contextual assumptions?".- power
Target power for MDE mode (default 0.80; unused in power mode).
- grid_points
Grid size used to expand length-2
varyelements.- nmax
Run the n_max search (default TRUE; power mode only).
- nmax_power
Target power for the n_max search (default 0.90, the default of
ape_n()).- se
Standard errors for the exogenous cross-sectional routes:
"model"(default, expected-information ML) or"robust"(heteroskedasticity-robust HC0 sandwich, as in the sandwich package). Panel designs always use unit-clustered SEs and IV designs the stacked method-of-moments robust sandwich;seis ignored there.- direction
MDE mode only:
"positive"or"negative"search direction, as inape_mde(); default: the sign of the base DGP's pinned effect.- separation
How simulated studies with separation in an identifying cell are scored:
"fail"(default; counted as failed, as the field's reference analysis refuses them) or"keep"(retained with their degenerate Wald intervals). See the section 'Separation and sparse cells'.
Value
A powerape_robust object: scenarios (inputs, implied effect,
power, MCSE, share of simulated studies with separation), the worst
scenario, marginal mean power per input, and the n_max result
(nmax, the ape_n() result in the scenario that sets it;
nmax_scenario, that scenario's inputs; nmax_candidates, every
scenario searched with its answer).
Details
Two pinning modes (DESIGN.md section 3.3):
pin = "ape"(default): the inversion is re-run in every scenario, so the true effect stays at the planning value and only the precision channel varies. Scenarios where the target is infeasible are reported as such, not dropped silently.pin = "coefficients": the effect coefficients stay at their base-case values while the contextual calibration is redone; the implied true effect drifts and is reported per scenario. Claim-boundary guards are relaxed here on purpose – showing that a scenario collapses power is the point.
n_max. The insurance-premium n is the largest requirement across
scenarios. Power at the user's n cannot rank the scenarios for that
purpose – at a generous n every scenario's power is near 1 – so the
scenarios are ranked by a criterion that does not saturate: the
normal-approximation requirement implied by each scenario's simulated
standard error and its effect's distance from the claim boundary.
ape_n() then runs in the least favorable scenario and in any scenario
within 5% of it on that criterion (up to three), and n_max is the
largest confirmed answer. When the implied effect of a feasible
scenario sits on or beyond the claim boundary (possible with pin = "coefficients"), no n reaches the target there, and n_max is not
reported.
Examples
# \donttest{
d <- ape_dgp(focal = pa_var("treat", "binary", p = 0.5), baseline = 0.30)
d <- set_ape(d, target = 0.10)
ape_robust(d, n = 700, claim = "detect",
vary = list(baseline = c(0.20, 0.40)),
nsim = 300, seed = 1, nmax = FALSE)
#> powerape robustness sweep -- detect claim, APE, pin = ape
#> n = 700, nsim = 300 per scenario, 3 scenario(s) over: baseline
#> power range [0.773, 0.890]; worst scenario:
#> baseline implied_effect power mcse separated
#> 0.4 0.1 0.7733333 0.02417222 0
#> scenarios:
#> baseline implied_effect power mcse separated
#> 0.2 0.1 0.8900000 0.01806470 0
#> 0.3 0.1 0.8466667 0.02080242 0
#> 0.4 0.1 0.7733333 0.02417222 0
# }