Author: José Mauricio Gómez Julián
Date: 2026-07-06

# Theoretical Addendum – Block 8.5.A:

### The T-learner AMM-side Causal Bridge: Canonization and Implementation

#### José Mauricio Gómez Julián

#### 2026-07-06

# 1. Purpose and position in the package

This vignette canonizes the T-learner AMM-side causal bridge introduced in Sub-phase 8.5.A. It is the operative continuation of `vignette("v08_cate_ite_positioning")`: where v08 places AMM relative to the CATE/ITE literature (Proposition 8A: AMM is a predictive object, CATE is a counterfactual object), this addendum specifies the one explicit construction that turns a pair of independent AMM fits into a CATE estimator. The construction follows the T-learner of Kuenzel et al. (2019), specialized to the AMM-side.

The exported entry point is the function `gdpar_causal_bridge(fit_treat, fit_ctrl, newdata, ...)`. The function is not an argument of `gdpar()`; it is a separate function that consumes two `gdpar_fit` objects already produced by `gdpar()`. This API choice preserves the strict separation between AMM as a generic predictive framework and CATE as a causal-identification overlay (Proposition 8A); it also keeps the bridge decoupled from the inference machinery so that S-learner, X-learner, doubly-robust and double-machine-learning extensions can be added in later sub-phases without disturbing the AMM core.

What this addendum is. A formal definition of the T-learner AMM-side, the identification assumptions it inherits from v02 plus the residual no-confounding assumption that it introduces, the posterior-difference estimator and its credible bounds, and the structural compatibility contract the bridge enforces between the two fits. The minimum reproducible example of §8 exercises the whole API; the limitations and open questions of §9 and §10 anchor the deferred extensions in Block 9.

What this addendum is not. It is not a tutorial on causal inference (Imbens-Rubin 2015 remains the canonical reference); it is not a comparator with external meta-learners (Sub-phase 8.5.B); it is not a guide to specifying AMM models (v00, v01, vop01-vop05 cover that).

# 2. Notation inherited from v08 (rapid reference)

For full statements see `vignette("v08_cate_ite_positioning")` §2 and Appendix A. The minimal table needed here:

Symbol | Meaning
--- | ---
\(T_i \in \{0, 1\}\) | Treatment indicator
\((Y_i(0), Y_i(1))\) | Potential outcomes (Rubin 1974)
\(Y_i = T_i Y_i(1) + (1 - T_i) Y_i(0)\) | Observed outcome under (CONS)
\(\mu_t(x) = \mathbb{E}[Y(t) \mid X = x]\) | Conditional potential-outcome means
\(\tau(x) = \mu_1(x) - \mu_0(x)\) | CATE function
\(e(x) = \Pr(T = 1 \mid X = x)\) | Propensity score
\(\theta_i^{(t)} = \theta_{\text{ref}}^{(t)} + \Delta^{(t)}(x_i, \theta_{\text{ref}}^{(t)})\) | AMM parameter under arm \(t \in \{0, 1\}\)
\((\text{IGN})\) | Ignorability: \((Y(0), Y(1)) \perp T \mid X\)
\((\text{OVL})\) | Overlap: \(0 < e(x) < 1\) for \(\mu\)-a.e. \(x\)
\((\text{CONS})\) | Consistency / SUTVA

The superscript \((t)\) on AMM objects refers to the arm under which the fit was produced (treatment arm \(t = 1\), control arm \(t = 0\)). The T-learner fits one AMM model per arm independently; the per-arm parameters \(\theta_i^{(t)}\) are different objects of estimation, and there is no parameter shared between the two fits.

# 3. Definition: the T-learner AMM-side

> Definition 8.5.A-1 (T-learner AMM-side). Let \(\mathcal{D}_1 = \{(x_i, y_i) : T_i = 1\}\) and \(\mathcal{D}_0 = \{(x_i, y_i) : T_i = 0\}\) be the treatment and control sub-samples. Fix one AMM specification \(\mathcal{A}\) (formula, family with link \(g\), anchor, AMM level, modulating basis) and use it for both arms. The T-learner AMM-side bridge is:

> 1. Fit \(\widehat{\theta}^{(1)} = \texttt{gdpar}(\mathcal{D}_1, \mathcal{A})\).
> 2. Fit \(\widehat{\theta}^{(0)} = \texttt{gdpar}(\mathcal{D}_0, \mathcal{A})\).
> 3. For every \(x \in \mathcal{X}_{\text{new}}\), define the per-arm response-scale prediction \(\widehat\mu_t(x) = g^{-1}\!\left( \widehat\theta^{(t)}(x) \right)\) on the inverse link of each arm’s predicted individual parameter.
> 4. The bridge estimator of the CATE at \(x\) is \[\widehat\tau(x) \;=\; \widehat\mu_1(x) - \widehat\mu_0(x).\]

The definition makes three architectural commitments explicit:

1. Structural symmetry between arms. The two arms share the same AMM specification \(\mathcal{A}\). The bridge does not entertain asymmetric specifications (treatment with one AMM level, control with another); such asymmetry would break the comparability of the two arms’ predictive objects on which the T-learner depends. `gdpar_causal_bridge` enforces this with structural compatibility checks (see §5 and the function’s `@details`).

2. No parameter sharing. Unlike the S-learner (which fits one model on the pooled data with \(T\) as a covariate) the T-learner fits two independent models. The joint posterior of \((\theta^{(0)}, \theta^{(1)})\) factorizes: \[p\!\left(\theta^{(0)}, \theta^{(1)} \mid \mathcal{D}_0 \cup \mathcal{D}_1\right) \;=\; p\!\left(\theta^{(0)} \mid \mathcal{D}_0\right)\, p\!\left(\theta^{(1)} \mid \mathcal{D}_1\right),\] a direct consequence of \(\mathcal{D}_0 \cap \mathcal{D}_1 = \emptyset\) and the independence of the two priors (gdpar uses the same prior distribution for both arms by default, but the random variables drawn from those distributions are independent across arms). This is the raison d’être of the per-draw difference of §6.

3. Response-scale CATE by default. Step (3) applies the inverse link before the difference, so \(\widehat\tau(x)\) is on the natural scale of the response (mean for Gaussian, rate for Poisson, success probability for Bernoulli, etc.). The package also exposes the linear-predictor scale (`type = "theta_i"`) for users who prefer to report differences on the link-transformed scale; the trade-off is that the linear-predictor difference is in units of the link, which are not always interpretable as treatment effects.

The bridge is agnostic to the AMM Path. Definition 8.5.A-1 is stated in terms of the fitted parameter \(\widehat\theta^{(t)}\) without reference to the path that produced it; Path 1 (Bayesian) is the only path implemented in 0.0.0.9001 (Sub-phase 8.5.A constrains the bridge to `path = "bayes"` and aborts otherwise). Paths 2 and 3 are mapped to the same construction in §10’s open questions.

# 4. Identification assumptions

The bridge inherits the AMM identifiability hypotheses of Block 1 (applied to each arm) and the gnoseological validity hypotheses of v02 (applied to each arm). On top of those, the T-learner requires the classical causal-identification hypotheses of v08 §2.1, restated here for self-containment, plus one additional structural assumption that is specific to the per-arm decomposition.

## 4.1. Inherited from v08

- (IGN) Ignorability: \((Y(0), Y(1)) \perp T \mid X\).
- (OVL) Overlap: \(0 < e(x) < 1\) for \(\mu\)-a.e. \(x\).
- (CONS) Consistency / SUTVA: \(Y_i = T_i Y_i(1) + (1 - T_i) Y_i(0)\).

Under (IGN)+(OVL)+(CONS), Imbens-Rubin (2015, Theorem 12.1) gives the identifying formula \(\mu_t(x) = \mathbb{E}[Y \mid X = x, T = t]\). The right-hand side is the per-arm conditional expectation that each AMM fit estimates: \(\widehat\mu_t(x) = g^{-1}(\widehat\theta^{(t)}(x))\). The identification of the CATE at \(x\) thus reduces to the identification of each arm’s per-arm conditional expectation, which is exactly the AMM identification problem of Block 1.

## 4.2. Residual no-confounding (T-learner-specific)

The T-learner additionally requires what we call (NCR) Residual no-confounding within each arm:

> (NCR). Within each arm \(t \in \{0, 1\}\), the AMM specification \(\mathcal{A}\) contains all covariates necessary to make the conditional expectation \(\mathbb{E}[Y \mid X = x, T = t]\) identifiable from the arm’s sub-sample. Equivalently, no unmeasured confounder of the outcome-treatment relationship is omitted from the AMM components \((a, b, W, x_{\text{vars}})\) at the level of each arm.

(NCR) is not a new substantive assumption beyond (IGN): if (IGN) holds at \(x\) and \(X\) is fully observed, the arm-specific conditional expectation is by definition identifiable. (NCR) merely makes the operational responsibility explicit: the user must include in the AMM specification all the covariates whose omission would create within-arm confounding. A common failure mode is to omit interactions with \(T\) that, under the pooled S-learner specification, would be absorbed by the treatment-indicator coefficient; the T-learner has no treatment indicator (each arm is fit separately), so omitted interactions contaminate the within-arm conditional expectation directly.

The bridge does not — and cannot — verify (IGN) or (NCR) from the data alone; they are causal assumptions and require domain knowledge or design (randomization, instrumental variables, regression discontinuities) to underwrite them. The bridge does verify the structural pre-conditions that make the T-learner construction well-defined: family, link, AMM level, anchor, covariate column structure (see §5).

## 4.3. What the bridge does not assume

- No homoscedasticity across arms. Each arm has its own posterior of \(\sigma_y\) (Gaussian), \(\phi\) (Negative Binomial), etc. The bridge does not assume that the two posteriors are equal.
- No common modulating block. Each arm has its own posterior of \(W_{\text{raw}}\), \(\sigma_W\). The bridge does not assume that the modulating block is the same in the two arms (treatment may amplify or dampen the modulation).
- No equal sample sizes. The bridge handles unbalanced sub-samples (different number of rows in \(\mathcal{D}_1\) and \(\mathcal{D}_0\)); the T-learner is known to suffer from regularization-induced bias in this setting (§9).

# 5. Estimation

The bridge is constructed by `gdpar_causal_bridge(fit_treat, fit_ctrl, newdata, type, level)`. The structural pre-conditions enforced at construction time are:

- Path: both fits have `path = "bayes"`.
- Non-hierarchical: both fits have `stan_data$use_groups == 0L`. The grouped regime of Block 6.5 introduces per-group anchors whose treatment under the T-learner difference is not defined in the canonical formulation; grouped bridges are queued for a future sub-phase (see §10).
- Family and link: both fits share `family$name` and `family$link`, and the per-slot family identifiers when \(K > 1\).
- Dim: both fits share `K` and `p`.
- AMM level and basis: both fits share `amm$level` (or per-slot levels when \(K > 1\)) and `amm$W$type` (polynomial or B-spline).
- Anchor: both fits share the anchor value within a relative tolerance of \(10^{-8}\). This is necessary because the anchor enters the modulating term as \(\theta_{\text{ref}}^k - \mathrm{anchor}^k\); a mismatch changes the meaning of \(\widehat\theta^{(t)}(x)\) and therefore of \(\widehat\tau(x)\).
- Covariate columns: both fits share the set of variables that appear in `a`, `b`, and `x_vars` (per coordinate / slot when multi-dimensional).

Any violation aborts with `gdpar_unsupported_feature_error`. The intent of the strict compatibility contract is to refuse meaningless bridges loudly rather than silently produce CATE estimates whose decomposition mixes incompatible AMM objects.

When the structural pre-conditions hold, the bridge calls `predict.gdpar_fit(fit_treat, newdata, type, summary = "draws")` and `predict.gdpar_fit(fit_ctrl, newdata, type, summary = "draws")`, aligns their draws (see §6), and computes the per-draw, per-observation difference:

\[\widehat{\tau}^{(s)}_i \;=\; \widehat{\mu}^{(s)}_{1}(x_i) \;-\; \widehat{\mu}^{(s)}_{0}(x_i), \qquad s = 1, \ldots, S, \ i = 1, \ldots, n_{\text{new}}.\]

The matrix \(\widehat{\tau} \in \mathbb{R}^{S \times n_{\text{new}}}\) is stored in the returned object as `cate_draws`. For multivariate (\(p > 1\)) or K-individual (\(K > 1\)) fits, `predict.gdpar_fit` returns a 3-array of shape \(S \times n \times \dim\); the bridge computes the elementwise difference and stores it as a 3-array of the same shape.

# 6. Inference: per-observation credible bounds and the ATE

The two fits are sampled from disjoint sub-samples and are therefore posteriori independent: the joint posterior of \((\theta^{(0)}, \theta^{(1)})\) factorizes (§3 (b)). Any draw \((\widehat{\theta}^{(0), s_0}, \widehat{\theta}^{(1), s_1})\) with \(s_0\) and \(s_1\) drawn independently from each marginal is a valid sample from the joint. The bridge implements this by pairing the \(s\)-th draw of one arm with the \(s\)-th draw of the other arm, which — under the Monte Carlo exchangeability of draws within a chain — is a uniformly distributed pairing. When the two fits have different numbers of draws \(S_t \ne S_c\), the bridge trims the longer arm to \(S = \min(S_t, S_c)\) and emits a `gdpar_diagnostic_warning`.

The per-observation posterior of the CATE at \(x_i\) is summarized by:

- The empirical mean \(\overline{\tau}_i = S^{-1} \sum_{s=1}^{S} \widehat{\tau}_i^{(s)}\), stored as `cate_mean`.
- The empirical \((\alpha/2, 1 - \alpha/2)\) quantiles with \(\alpha = 1 - \mathrm{level}\), stored as `cate_ci` (default \(\mathrm{level} = 0.95\)).

The summary uses empirical quantiles, not a normal-approximation interval, because the per-arm posteriors are not necessarily Gaussian (small-sample, non-Gaussian families) and the difference of two near-Gaussian distributions can have meaningfully heavy tails when the two marginals have different scales.

Marginal ATE. The bridge’s `summary()` method also reports the marginal average treatment effect (ATE) over the evaluation grid:

\[\widehat{\text{ATE}} \;=\; \frac{1}{n_{\text{new}}} \sum_{i = 1}^{n_{\text{new}}} \overline{\tau}_i.\]

The credible bounds of the ATE are computed by first averaging the per-draw CATE over the evaluation grid (giving an \(S\)-vector of per-draw ATEs) and then taking the empirical quantiles of that vector. This ordering preserves the posterior shape of the ATE; it is not equivalent to averaging the per-observation credible bounds. The latter would underestimate the width of the ATE interval by ignoring the cross-observation correlation introduced by parameter sharing within each arm.

# 7. Identifiability per arm

The bridge inherits the AMM identifiability machinery of Block 1 and the (C1)-(C6) static identifiability conditions of v01. Each arm is fitted by `gdpar()`, which runs the pre-flight identifiability check internally and populates the `identifiability_report` slot of the fit. The bridge records both reports as `id_check = list(treat = ..., ctrl = ...)` in the returned object; failures in either arm propagate as failures of the bridge construction (the upstream `gdpar()` call would have refused to fit if (C1)-(C6) were violated).

(C7) anti-aliasing of Block 6.5 (the grouped-anchor condition) is structurally moot in Sub-phase 8.5.A because the bridge aborts on hierarchical fits (§5, `use_groups == 0L` is required on both arms). The design contract is documented here for forward compatibility: when a future sub-phase extends the bridge to hierarchical fits, the canonical treatment will invoke `gdpar:::.check_group_aliasing_c7()` on each arm’s design separately, and a violation in either arm will abort the construction. The per-arm invocation, rather than a joint invocation, is necessary because the two arms have independent group-anchor columns (the per-group anchors \(\theta_{\text{ref}}^{(t)}[g]\) are independent across arms).

# 8. Minimum reproducible example

The example below is a CRAN-valid demonstration of the bridge on synthetic data. The treatment effect is heterogeneous in \(x_1\) (\(\tau(x) = 1 + 0.5 x_1\)); the example fits both arms, constructs the bridge on a coarse evaluation grid, and prints the bridge and its summary.

    library(gdpar)
    set.seed(20260524)
    n_per_arm <- 300L
    beta0 <- 0.2; beta1 <- 0.8
    tau0  <- 1.0; tau1  <- 0.5  # true CATE: tau(x) = tau0 + tau1 * x
    df_treat <- data.frame(
      x1 = rnorm(n_per_arm),
      y  = NA_real_
    )
    df_treat$y <- (beta0 + tau0) +
      (beta1 + tau1) * df_treat$x1 + rnorm(n_per_arm, sd = 0.4)
    df_ctrl <- data.frame(
      x1 = rnorm(n_per_arm),
      y  = NA_real_
    )
    df_ctrl$y <- beta0 + beta1 * df_ctrl$x1 + rnorm(n_per_arm, sd = 0.4)

    fit_treat <- gdpar(
      formula       = y ~ x1,
      family        = gdpar_family("gaussian"),
      amm           = amm_spec(a = ~ x1),
      data          = df_treat,
      chains        = 2L,
      iter_warmup   = 500L,
      iter_sampling = 500L,
      refresh       = 0L,
      verbose       = FALSE
    )
    fit_ctrl <- gdpar(
      formula       = y ~ x1,
      family        = gdpar_family("gaussian"),
      amm           = amm_spec(a = ~ x1),
      data          = df_ctrl,
      chains        = 2L,
      iter_warmup   = 500L,
      iter_sampling = 500L,
      refresh       = 0L,
      verbose       = FALSE
    )

    grid <- data.frame(x1 = seq(-2, 2, length.out = 21L))
    bridge <- gdpar_causal_bridge(fit_treat, fit_ctrl, newdata = grid)
    print(bridge)
    summary(bridge)

The expected output is a `gdpar_causal_bridge` object whose per-observation `cate_mean` traces the linear function \(1 + 0.5 \cdot x_1\) to within posterior credible bounds. The marginal ATE on the symmetric grid \([-2, 2]\) is close to \(1.0\) (the constant term of the heterogeneous CATE).

To re-evaluate the bridge on a fresh grid without re-running the compatibility checks, use `predict.gdpar_causal_bridge`:

    grid2 <- data.frame(x1 = seq(-1, 1, length.out = 11L))
    re <- predict(bridge, newdata = grid2)
    str(re, max.level = 1L)

# 9. Limitations of the T-learner

The T-learner is the most direct meta-learner from a structural standpoint (one arm equals one fit equals one model), but it is not universally optimal. The principal limitations are well-known (Kuenzel et al. 2019 §3.4):

1. Regularization-induced bias in unbalanced samples. When one arm is much larger than the other, the smaller arm’s posterior is more diffuse and the bridge’s CATE estimate inherits that diffusion asymmetrically. The T-learner has no mechanism to borrow strength across arms; the S-learner and X-learner do (the former by pooling in a single model, the latter by an explicit cross-arm correction). The diffusion is faithfully transmitted to the credible bounds, so the bridge does not understate uncertainty — but the point estimate may be biased toward the more diffuse arm’s prior.

2. No common feature representation. The two arms have independent AMM fits and therefore independent posterior estimates of the basis coefficients \(a\), \(c_b\), \(W_{\text{raw}}\). Any feature that is informative only in combination with treatment is not modeled as such (the treatment indicator is absent from each arm’s specification by construction); the two arms simply do not have a common feature space at the parameter level.

3. Sensitivity to mis-specification of the conditional mean. Like all conditional-mean estimators, the T-learner relies on the correct specification of \(\mu_t(x)\). AMM mitigates this via the explicit additive-multiplicative-modulated decomposition and the identifiability diagnostics of Block 2, but the underlying sensitivity remains: a mis-specified AMM in either arm produces a biased CATE.

Deferred alternatives. S-learner, X-learner, doubly-robust (DR), and double-machine-learning (DML) constructions are queued for Block 9. They will be added as separate functions (`gdpar_causal_s_learner`, `gdpar_causal_x_learner`, `gdpar_causal_dr`, etc.) following the same S3-friendly pattern as `gdpar_causal_bridge`, never as arguments of `gdpar()`; the principle of strict separation between AMM as predictive framework and CATE as causal overlay (§1) is preserved across all the deferred constructions.

# **10. Open questions (O*-CATE)**

The following questions are deferred to Block 9 sub-phases or to Sub-phase 8.5.B. Each is anchored to a specific Path or external dependency.

> (O1-CATE) Paths 2 and 3. Extension of the T-learner AMM-side to the varying-coefficient model (Path 2) and the amortized hypernetwork (Path 3). The construction of Definition 8.5.A-1 is path-agnostic at the level of the fitted parameter \(\widehat\theta^{(t)}(x)\), but the posterior of \(\theta\) in Paths 2 and 3 is structurally different (penalized-spline posterior in Path 2; amortized variational posterior in Path 3) and the credible bounds of §6 need adaptation. Queued for Block 9.

> (O2-CATE) Hierarchical bridges. Extension to fits with `use_groups == 1L`. The canonical treatment will invoke `.check_group_aliasing_c7()` per arm (§7) and decompose the CATE into a between-group and a within-group component. The decomposition is non-trivial because the per-group anchors \(\theta_{\text{ref}}^{(t)}[g]\) are correlated across observations within the same group but independent across arms.

> (O3-CATE) Comparator against external meta-learners. Sub-phase 8.5.B will add `gdpar_compare_meta_learners` as an opt-in benchmark against `grf`, `causalForest`, and EconML (via `reticulate`). The charter of 8.5.B is opened only after 8.5.A closes; the dependency on Python (EconML) is the principal architectural reason for the sub-division.

> (O4-CATE) S-learner and X-learner AMM-side. Both meta-learners map naturally to the AMM pipeline: S-learner adds \(T\) as a covariate in a single AMM specification and reads the CATE from the contrast between \(T = 1\) and \(T = 0\); X-learner imputes counterfactual outcomes by cross-arm prediction and refits. Both are queued for Block 9. The functions will be `gdpar_causal_s_learner` and `gdpar_causal_x_learner`.

> (O5-CATE) Doubly-robust and double-machine-learning AMM-side. DR and DML add a propensity-score model that the T-learner does not require. The propensity-score model can be a separate `gdpar` fit on the binary outcome \(T_i\), or an external estimator passed via an argument. Queued for Block 9.

> (O6-CATE) Diagnostics for the bridge. A bridge-specific diagnostic battery (overlap plots, posterior-predictive checks per arm, ATE sensitivity to leave-one-out exclusion) would complement the existing per-fit diagnostics. The diagnostic module would consume a `gdpar_causal_bridge` object. Queued for Block 9.

# Appendix A. Notational correspondence with Kuenzel et al. (2019)

For readers familiar with the meta-learner literature, the following table maps Kuenzel et al.’s notation to the AMM-side construction of this addendum. Items marked “n/a” are concepts of Kuenzel et al. that have no direct AMM-side analog or that are deferred to a later sub-phase.

Kuenzel et al. (2019) | This addendum (gdpar)
--- | ---
Base learner \(M_t\) | `fit_treat` and `fit_ctrl` (a pair of `gdpar_fit` objects)
T-learner construction \(\widehat\tau_T(x) = M_1(x) - M_0(x)\) | `gdpar_causal_bridge(fit_treat, fit_ctrl, newdata)`
Plug-in CATE estimate | `bridge$cate_mean`
Bootstrap or asymptotic CI for CATE | Posterior credible bounds `bridge$cate_ci` (per-observation), `summary(bridge)$ate_ci` (marginal ATE)
Cross-arm imputation (X-learner) | n/a in 8.5.A; queued as (O4-CATE)
Propensity-score model | n/a in 8.5.A; queued as (O5-CATE) for DR/DML
Treatment indicator \(W_i\) (in their Section 2) | Determined extensionally by membership in `fit_treat$data` or `fit_ctrl$data`; the bridge does not see a treatment indicator

The correspondence is structural, not numerical: the per-arm point estimates of \(M_t(x)\) depend on the base learner used (Kuenzel et al. use random forests; this addendum uses AMM via gdpar); when the base learners coincide the two formulations agree on the CATE.

# Appendix B. Implementation notes for future external comparators (8.5.B preview)

The bridge is decoupled from any external meta-learner. The principal integration points for Sub-phase 8.5.B will be:

1. A common evaluation grid. External meta-learners consume the same `newdata` data frame as `gdpar_causal_bridge` and return a per-observation CATE estimate (typically a vector of length \(n_{\text{new}}\) with optional CIs). The 8.5.B comparator wraps each meta-learner in an adapter that returns a list with `cate_mean`, `cate_ci`, and a `method` tag.

2. No assumption on the comparator’s posterior. Most external meta-learners do not produce a posterior; their CIs are obtained by bootstrap or by asymptotic approximation. The 8.5.B comparator does not equate `cate_ci` across methods of different inferential origin; the comparator reports the discrepancy in `cate_mean` and in `cate_ci` separately, leaving the interpretation to the user.

3. No Python dependency in 8.5.A. The optional EconML integration requires `reticulate` and a working Python environment with EconML installed. The dependency is isolated in Sub-phase 8.5.B’s `Suggests` block and does not contaminate the core package `Depends` / `Imports`.

# References cited in this addendum

- Holland, P. W. (1986). Statistics and causal inference. Journal of the American Statistical Association, 81(396), 945-960.
- Imbens, G. W., and Rubin, D. B. (2015). Causal Inference for Statistics, Social, and Biomedical Sciences: An Introduction. Cambridge University Press.
- Kuenzel, S. R., Sekhon, J. S., Bickel, P. J., and Yu, B. (2019). Metalearners for estimating heterogeneous treatment effects using machine learning. Proceedings of the National Academy of Sciences, 116(10), 4156-4165.
- Rubin, D. B. (1974). Estimating causal effects of treatments in randomized and non-randomized studies. Journal of Educational Psychology, 66(5), 688-701.

End of Theoretical Addendum – Block 8.5.A.