DGP Dossier: synth_qte1

1. Identity & Status

DGP ID synth_qte1
Version 1.6.0
Status experimental
Difficulty (4/5)
Stress Profile  overlap: moderatenoise: heavylinearity: lineareffect: heterogeneoustarget: both

2. What This DGP Stresses (Intent)

This DGP is conceptually hard rather than numerically hard: the treatment effect is sign-switching (+1 or -1) across the population. A mean-ATT estimator can look excellent (low bias/RMSE for the ATT) while completely missing that roughly half the population is harmed. The oracle QST curve is the “X-ray” that reveals the sign flip.

3. Identification Assumptions (Explicit)

  • Selection on observables holds.
  • Overlap is moderate.
  • SUTVA holds.

4. Mathematical Specification

Covariates: [ X ^5,X_j (0, 1^2) j = 1,,5 ]

Outcome (control): [ _0(X) = 1 + X_1 + 0.5 X_2 ]

Propensity: [ (p(X)) = 0.5 X_1 - 0.5 X_2 ]

Discontinuous effect: [ (X) = \[\begin{cases} +1, & X_1 > 0 \\ -1, & X_1 \le 0 \end{cases}\]

]

Noise: [ = 0.5,U,U t_4 ]

5. Oracle Truth Definition

  • True ATT is computed from structural_te among treated units.
  • True QST is computed on the oracle tau grid (cs_get_oracle_qst()).

6. Visual Diagnostics (n = 5000)

7. Empirical Validation

OLS (lm_att) passes the numerical benchmark (low ATT bias/RMSE), but fails the scientific benchmark: it reports only a mean ATT and provides no distributional view. The oracle QST curve shows that the treatment is positive in one half of the population and negative in the other.

Empirical validation (n=1000, seeds=1:10)
estimator_id mean_bias rmse
lm_att -0.008 0.056
oracle_att 0.000 0.000

8. Failure Mode Summary

  • Mean-ATT estimators can look excellent while masking that the treatment harms a large subpopulation (here, roughly those with (X_1 )).
  • Distributional diagnostics (QST) are mandatory in sign-switching regimes.

9. Implementation Reference

  • Generator: R/dgp-synth-qte1.R
  • Registry: cs_dgp_registry() entry for synth_qte1
  • Oracle truth: cs_get_oracle_qst("synth_qte1", version = "1.6.0")

10. Validation Checklist

11. Changelog

  • v1.3.0 dossier: Updated to emphasize conceptual blindness trap; removed TMLE narrative; added lm_att + oracle_att validation table.
  • v1.6.0: Implemented Common Random Numbers (CRN) for Oracle generation. This reduces Monte Carlo variance of the QST contrast; it does not eliminate empirical-quantile sampling uncertainty.

Appendix: Implementation

Source code for: dgp_synth_qte1_v160

function (n, seed = NULL, include_truth = TRUE, oracle_only = FALSE) 
{
    if (!is.null(seed)) {
        cs_set_rng(seed)
    }
    X1 <- stats::rnorm(n, mean = 0, sd = 1)
    X2 <- stats::rnorm(n, mean = 0, sd = 1)
    if (!isTRUE(oracle_only)) {
        X3 <- stats::rnorm(n, mean = 0, sd = 1)
        X4 <- stats::rnorm(n, mean = 0, sd = 1)
        X5 <- stats::rnorm(n, mean = 0, sd = 1)
    }
    mu0 <- 1 + X1 + 0.5 * X2
    tau <- ifelse(X1 > 0, 1, -1)
    p <- stats::plogis(0.5 * X1 - 0.5 * X2)
    w <- stats::rbinom(n, size = 1L, prob = p)
    eps0 <- 0.5 * stats::rt(n, df = 4)
    if (isTRUE(oracle_only)) {
        eps1 <- eps0
    }
    else {
        eps1 <- 0.5 * stats::rt(n, df = 4)
    }
    y0 <- mu0 + eps0
    y1 <- mu0 + tau + eps1
    if (isTRUE(oracle_only)) {
        return(list(df = tibble::tibble(w = w, y0 = y0, y1 = y1)))
    }
    y <- ifelse(w == 1L, y1, y0)
    true_att <- cs_true_att(structural_te = tau, w = w)
    true_qst <- if (isTRUE(include_truth)) 
        cs_get_oracle_qst("synth_qte1", version = "1.6.0")
    else NULL
    out <- list(df = tibble::tibble(y = y, w = w, y0 = y0, y1 = y1, 
        p = p, structural_te = tau, X1 = X1, X2 = X2, X3 = X3, 
        X4 = X4, X5 = X5), true_att = true_att, true_qst = true_qst, 
        meta = list(dgp_id = "synth_qte1", version = "1.6.0", 
            type = "synthetic", params = list(n = n, seed = seed), 
            structural_te = tau))
    cs_check_dgp_synthetic(out)
    out
}
<bytecode: 0x5592107cbf50>
<environment: namespace:CausalStress>