The sensitivity level Γ¶
Offline pessimism assumes the observed transitions identify the causal effect. Under hidden
confounding they do not: the effect is only partially identified, in a sensitivity interval. Γ
is how wide a caller assumes that interval to be, and chc.sensitivity is
the one import that runs the whole line: calibrate Γ, turn it into a radius, control against the
radius, and check the result.
What Γ is¶
Γ >= 1 is the level of the marginal sensitivity model (MSM, Tan 2006): the odds of treatment
given the covariates and the unobserved confounder lie within a factor Γ of the odds given the
covariates alone. For an effect's bounds that is a bound on a density ratio (Dorn and Guo 2023):
the weight that turns the observed outcomes into the unobserved ones lies in [1/Γ, Γ]. The sharp
worst-case effect is then a CVaR mixture, and the gap over the point estimate inflates the
pessimism radius by (Γ-1)/(Γ+1)·(CVaR gap). At Γ = 1 the radius is zero, and the machinery
reduces to the ordinary, fully identified case.
Dorn and Guo's model is for a binary treatment. For a continuous lever the continuous MSM holds
the dose's density given the covariates and the unobserved within a factor Γ of its density
given the covariates alone (Jesson et al. 2022), and the same CVaR mixture is the sharp bound on
the mean outcome at one dose level (Frauen, Melnychuk and Feuerriegel 2023, Thm 1), not on a
slope. A contrast of two levels takes the upper bound at one less the lower bound at the other
(their Lemma 3). A radius spent on the control channel as radius·‖u‖ is a structural sensitivity
model of its own, not the MSM's bound.
Γ is the analyst's unfalsifiable input, and a single scalar aggregates over covariates. These
methods robustify pessimism; they do not test for confounding.
Two models, one symbol¶
Every Γ CHC takes or reports is the MSM's, and the report says so. Rosenbaum's Γ (2002), the
one matched-design analyses report, bounds a different ratio: the odds of treatment of any two
units with the same covariates. On the models compatible with the data the two nest (Zhao, Small
and Bhattacharya 2019, Prop. 7.1):
Rosenbaum(Γ) ⊆ MSM(Γ) ⊆ Rosenbaum(Γ²)
So compare a CHC number with a Rosenbaum-style one through the bracket, not as the same quantity:
- a plan CHC certifies up to
Γ*holds against every confounder Rosenbaum's model allows atΓ*, since each is one the MSM allows; - a study "insensitive to
Γ = 5" in Rosenbaum's sense covers the MSM only up to√5 ≈ 2.24.
Γ bounds only how far a confounder moves the treatment. How much bias it produces depends also
on how far it moves the outcome. Rosenbaum and Silber (2009) put the trade in closed form for
Rosenbaum's model: a Γ is a confounder that multiplies the odds of treatment by Λ and the odds
of a higher response by Δ, with Γ = (ΛΔ + 1)/(Λ + Δ), so Γ = 2 is Λ = 3 with Δ = 5. The
MSM has no such closed form, but the direction carries over, and the tests hold it on a binary
confounder: the Γ a known-null outcome needs is 1 when the confounder leaves the outcome alone,
rises with its pull on the outcome, and reaches the confounder's own MSM Γ when the outcome is
the confounder.
Calibrate it before spending it¶
Unfalsifiable is not the same as uncalibrated. Three functions price Γ against the data:
benchmark_gammaexpresses it in units of the confounding the observed covariates carry: dropping covariatejfrom the propensity produces exactly the pair of propensities the model bounds. It reports the exponentlog Γ / log Γ_strongest, because odds ratios compose multiplicatively — "an unobserved confounderktimes as strong as the strongest thing we did observe". Akfar below 1 is an assumption nobody should be impressed by; akfar above 1 is one the analyst has to defend. Two limits. It measures the treatment side only, so it is the ceiling above: read atquantile=1.0, a confounder as strong as covariatejin the treatment forces at mostΓ_j, and less if it moves the outcome less. And nothing formal ties an unobserved confounder to an observed covariate (Ding 2024, p. 242), so a benchmark sets a scale forΓ, not a bound on it.negative_control_gammainverts a known-null outcome for the smallestΓthat reconciles it. On an outcome whose true effect is zero, any nonzero estimate is confounding, so thatΓis a lower bound on the confounding actually present: assuming less is refuted by the data. It bounds the outcome of interest only when the control is U-comparable, confounded by the same unobserved causes (Lipsitch, Tchetgen Tchetgen and Cohen 2010): a control confounded by more overstates the outcome'sΓ, and one confounded by less understates it (Baitairian et al., arXiv 2510.16560). It returnsinfwhen noΓreconciles the null — the negative control has then refuted the model class instead of calibrating it.check_observational(experimental,chc.lift) reads a media-mix channel fitted to logged spend against the geo tests of it, and itsleast_gamma(cvar_gap)is the leastΓwhose identified set,1 ± (Γ-1)/(Γ+1)·cvar_gapin units of the lift the channel predicts, reaches the lift the tests read. It is the same kind of floor, from an experiment rather than a known null (De Bartolomeis et al. 2024 boundΓfrom below with a trial in the same way), and the sameinfwhen no level reconciles the two. It bounds the tested channel; read for a channel no test reached, it assumes the two are confounded alike.
The same question in variance shares¶
A channel fitted by adjustment has a second sensitivity model beside Γ, in Cinelli and Hazlett's
currency rather than odds. omitted_confounder_bound (experimental) bounds how far a confounder
the adjustment set left out could move a linear functional of the channel, such as one lever's
effect or the value of moving spend from one lever to another, by the bound of Chernozhukov,
Cinelli, Newey, Sharma and Syrgkanis (2022):
|bias| ≤ |ρ| · sqrt(cf_y · cf_d / (1 − cf_d)) · σ · ν
σ² is the rate's residual variance after the fit and ν² the second moment of the functional's
Riesz representer, both identified. cf_y and cf_d are the shares of the two the confounder
would explain, and they are the analyst's, as Γ is. robustness_value is the share, the same on
both sides, at which the bound reaches a null. A reallocation's value is linear in the channel, so
for one that is the confounding at which the move stops paying. robustness_value_ci is the same
for the confidence bound, and the point value is its design sensitivity, the value it reaches as
the log grows. On an OLS fit, chc.causal.sensitivity_analysis reports Cinelli and Hazlett's own
robustness value.
With one latent on a linear Gaussian plant the bound is attained, so at the latent's own shares it
sits on the truth (validation/omitted_confounder_bound.mac). Over 500 such worlds with drawn
loadings, half read by Euler and half by rk4 at steps up to 1.4, its confidence bounds covered the
reallocation's true value in 0.940 of them (Clopper–Pearson 0.915–0.959) at a nominal 0.95; at half
the shares in 0.216, and with none, the fit's own interval, in 0.138
(scripts/bench_omitted_confounder.py). DoubleML 0.11.4, fed the same cross-fitted predictions,
gives the same bounds to 3.8e-10 (scripts/doubleml_bound_reference.py).
The two models do not convert into each other: Γ bounds how far a confounder moves the odds of
treatment, the shares how much of two variances it explains. Where both apply, report both.
Where a move flips¶
A reallocation's value is linear in the channel, so each model gives its flip point in one call. In variance shares it is the move's robustness value:
move = np.zeros(fit.residual.channel.shape)
move[0, a, 0], move[0, b, 0] = -1.0, 1.0 # one unit of spend from lever a to lever b
bound = omitted_confounder_bound(fit, move, cf_y=0.1, cf_d=0.1)
bound.robustness_value # the shares at which the move's value could be zero
With null set to what a unit moved costs, it is the shares at which the move stops paying for
itself. In Γ, the identified set of the move's value, d̂ ± (Γ-1)/(Γ+1)·G for the analyst's gap
G, reaches zero at Γ = (G + |d̂|)/(G - |d̂|). That is barrier_gamma_star(abs(d_hat), G, 1.0),
the inversion a certificate makes, with the value's distance from zero as the radius the decision
can absorb. Past the flip the move's sign is not identified, and the robust criteria part:
minimax_action's worst cost is least at holding, while its criterion="regret" still moves, the
estimate's way, hedged. tests/test_reallocation_flip.py holds all three, the first against a grid
of Γ.
The flip reads the estimate as the value's centre. chc.regret.minimax_regret_move carries the
estimate's noise beside Γ (Montiel Olea, Qiu and Stoye, Review of Economic Studies 2026): while
k = (Γ-1)/(Γ+1)·G is at most √(π/2) standard errors the whole move on a positive estimate is
minimax regret; past it the rule makes a share of the move, and the worst regret is k/2. Its
full_move_gamma is the largest Γ at which the estimate still makes the whole move, at or past
the flip (ADR 0089).
Spend it on performance¶
The radius widens a pessimism radius (never optimistic, tight at Γ = 1, monotone). The
confounding bias then becomes a control-regret floor that is second order in the bias. Under an
asymmetric loss — undershoot costlier than overshoot, or the reverse — the minimax controller
shifts the gain to hedge the costlier error. It bounds the worst-case cost, wins beyond a
problem-dependent confounding threshold, and pays a bounded premium near zero confounding.
Or on safety¶
The same radius, spent on a constraint instead of the objective, is the barrier line of
certificates. There the question inverts: Γ* is the largest MSM level
under which the barrier stays certified. It is a model parameter, not a
measured amount of hidden confounding. The gap there is a share of the control channel, its
operator norm where the plan starts, so Γ* does not move with the units of the state or of the
levers. Once the radius swallows the control channel the
robust-optimal action is exactly zero: with the sign of the channel unidentified, acting cannot
improve the guarantee.
See it¶
- Tutorial 5 (robust control) — estimate, radius, minimax action, and the trade-off across a confounding sweep.
- The confounded-incentives case study — the same controller in closed loop on a confounded plant.