The Comparison Everyone Wants To Make
The tempting move is always the same: treated users did better, so the treatment worked. Ship it, screenshot the dashboard, present it Monday. That sentence is also exactly how confounding wins every time nobody checks the math.
orthoshift creates a population where treatment depends on covariates, outcomes depend on the same covariates, and the true average treatment effect is known in advance. That's the only honest way to grade an estimator: against the answer key, not against a vibe.
Orthogonal Residuals Do The Boring, Important Work
The estimator fits nuisance models for outcome and treatment, residualizes both, then estimates the treatment effect from what's left over. That orthogonal step is the entire trick, and it's less exciting than it sounds, which is exactly why it works.
I kept the linear algebra in the repo instead of hiding it behind an import. No scikit-learn, no hidden solver, no black box you have to trust on faith. Open the ridge routine and watch the estimate get built in front of you.
The Number
The true effect is 1.986. Naive difference in means reports 3.798, missing by 1.812, which is confounding lying to your face with a completely straight expression. Orthogonal DML reports 1.864, missing by only 0.122.
3 tests pass locally and on GitHub Actions across Python 3.9, 3.11, and 3.13.