The front half of the pattern.
DoWhy, EconML and CausalML each take a causal graph as an input. This builds one from business content and hands it over with the caveats attached — including the ones that come from our own mistakes.
If you already run an estimation stack, the missing piece is usually not an estimator. It is a defensible graph, and a record of who said each edge was there.
Where the graph comes from
There is more than one way to get a causal graph, and the difference between them is not quality. It is what the edges mean and whether anyone can say who put them there.
Recovered from data
Structure learners infer a graph from rows, and DoWhy's graphical-model module ships them. That is a legitimate way to get a graph when you have a sample and no account of the process — and for a question with abundant data it may be the right one.
A recovered edge is a statistical claim about the sample it came from. It carries no statement about the process, and no field in it records who believes the edge is there or on what grounds.
Elicited from content
This engine builds the graph from a description, a table, a file or a URL, and asks a person to confirm what it read. Every edge carries a source tag, and the tag survives into every answer computed from it.
An elicited edge is not measured and we do not present it as if it were. It is a claim about how the process works, held by someone, and the provenance row is what makes that visible later.
So the honest form of the claim is narrower than the one we first wrote down. It is not that nobody else can build a graph. It is that the graph here is elicited rather than learned, every edge records where it came from, and that difference survives the handoff — where a downstream estimator inherits our structure, and our misses along with it.
What lands in your hands
One route returns everything an estimation call needs, so the caller does not have to reconstruct the caveats from a diagram.
GET /v1/networks/wealth-retention/handoff?treatment=advisor_contact&outcome=attrition
- dot
- The graph as a DOT digraph, which is the form the libraries document. Deterministic: two calls against one revision are byte-identical, so a diff shows a real change rather than a reshuffle.
- identified · method
- Whether the question identifies at all, and by which route — backdoor, front-door, or none. none is a first-class answer here, not an error condition.
- adjustment_set · minimal_adjustment_set
- The full backdoor set and its minimal subset. A caller who adjusts for everything upstream is not wrong; a caller who adjusts for the minimal set gets the same estimate with less variance.
- roles
- Every variable classified against the treatment and outcome pair, with advice on whether to adjust for it. This is the part that earns its place, and it is set out in full below.
- reason
- Why the identification answer is what it is, in a sentence a reviewer can read without reading the graph. When the answer is no, this is the sentence that says what would have to change.
- snippet
- An illustrative call carrying the graph, the treatment, the outcome and the control set, so the only thing you add is your dataframe.
snippet is labeled inside the payload as not executed and not verified here, because this service does not depend on those libraries and therefore cannot run them. Shipping code that looks verified when it is not is the failure mode this product exists to avoid, so the label travels with the code rather than living in documentation somewhere else.
The control advice, which is the useful part
The most emphasised pitfall in the causal literature is adjusting for the wrong variable, and it is usually settled by argument. A graph settles it structurally, because the role of a variable is a property of its position rather than of anyone's opinion.
Confounder
requiredStructural definition
An ancestor of both the treatment and the outcome.
Omitting it leaves a backdoor path open, and the estimate absorbs the difference. This is the one omission that shows up as a wrong number rather than as a wider interval.
Mediator
do not controlStructural definition
Downstream of the treatment, upstream of the outcome.
It carries part of the effect. Adjusting for it reports the direct effect while appearing to report the total, which is the most consequential way to be wrong without noticing.
Collider
do not controlStructural definition
Downstream of both the treatment and the outcome.
Conditioning on a common effect creates an association between its causes. It can make the treatment and the outcome appear related when they are not, or hide a relationship that is there.
Cause of treatment only
optionalStructural definition
Upstream of the treatment, not of the outcome.
It cannot confound, because it does not touch the outcome. Including it can sharpen the estimate by explaining variance, and excluding it costs nothing but precision.
Cause of outcome only
optionalStructural definition
Upstream of the outcome, not of the treatment.
It cannot confound, because it does not touch the treatment. Including it is harmless and possibly useful, and is not required.
Effect of outcome
optionalStructural definition
Downstream of the outcome, not of the treatment.
Not on a backdoor path, so it cannot bias the estimate. Note the asymmetry with a collider: being downstream of the outcome alone is not the same as being downstream of both.
Other
optionalStructural definition
Neither an ancestor of the treatment nor of the outcome.
Nothing to gain and nothing to lose. Worth reading anyway, because this label is the one that inherits a miss in the graph — see the example.
A variable marked do-not-control used as a feature in a learned model is a mediator or a collider, and the model will report a biased effect without reporting a problem. The role table is what turns that from a fact about the literature into a decision this caller can see before they fit anything.
One measured example
The retention demo, asked for the effect of advisor contact on attrition.
GET /v1/networks/wealth-retention/handoff?treatment=advisor_contact&outcome=attrition
identified: true method: backdoor adjustment_set: [client_segment, volatility_tolerance] minimal_adjustment_set: [client_segment] advisor_contact treatment n/a attrition outcome n/a client_segment confounder required aum_change collider do_not_control volatility_tolerance other optional
The minimal set does real work
The backdoor set includes volatility_tolerance; the minimal set drops it, because in the recovered graph it does not lie on a backdoor path. A caller who adjusts only for client_segment gets the same estimate with less variance, and a caller who adjusts for everything upstream is not wrong — but they are paying for a variable they did not need.
The advice is only as right as the graph
volatility_tolerance is labeled other, meaning neither an ancestor of the treatment nor of the outcome. That is true of the graph we recovered. The graph we recovered also missed the volatility_tolerance → attrition edge at 1,500 rows — which is the 0.83 recall measured in the demo, arriving here in the advice rather than in a footnote.
This is the section that matters on this page, and it is the reason the handoff calls the graph the assumption rather than the result. A downstream estimator inherits our structure, including our misses. That is worth stating plainly on a page whose subject is handing work to another tool: we are not transferring a truth, we are transferring a model and a record of how confident we are in each part of it.
What we deliberately do not do
Four boundaries, each one a place where crossing it would make the product easier to sell and worse to rely on.
We do not estimate effects from data
A heterogeneous treatment effect is learned from observations, with sampling error and a confidence interval. What this engine computes is exact arithmetic on a stated model. Both are useful and they are not the same kind of claim.
What this does not establish: They must never be presented as the same number. If you need intervals that account for sampling, you need an estimator — and the handoff is how you get one rather than a blurred substitute for one.
We do not chase their feature lists
Competing on estimators means losing to the teams that do only that, on ground they have held for years, while abandoning the exactness that makes an answer here auditable in the first place.
What this does not establish: An estimator missing from this product is a decision, not a gap on a roadmap. Do not read its absence as something we intend to close.
We do not add a capability we can do exactly and cheaply
Refutation and subgroup effects on a discrete model are arithmetic on a model we already hold. They need no new dependency, no data, and no research-grade statistics.
What this does not establish: The rule cuts the other way too: when a library does something we cannot do exactly, the handoff is the answer and a bundled copy would be the wrong one. This is a test, not a preference.
We keep the boundary visible
An unidentified question and a graph with no valid adjustment set are first-class results here. The handoff carries them as answers rather than converting them into something a downstream tool can consume.
What this does not establish: When the graph does not identify the question, the payload says so instead of emitting a number shaped exactly like the ones that are identified. A consumer that ignores the field will not be warned twice.
Do we bundle the libraries in?
No — and the decisive argument is a measurement rather than a preference about dependencies.
DoWhy 0.14 caps scipy at ≤ 1.15.3. CausalML 0.17 floors it at ≥ 1.16.0. So the pattern usually recommended — define the graph in DoWhy, estimate with EconML, target with CausalML, all in one environment — is not installable as described.
The resolver would either fail outright or walk at least one library backwards to a release chosen by resolution order rather than by an operator, and the operator would be running an untested combination without being told. The rest of the cost is 44 direct requirements between them: solvers, a compiler toolchain, plotting stacks and gradient-boosting libraries, alongside packages listed as runtime requirements that are build tooling.
The deeper reason: it would put two kinds of number behind one field
Every cell in this product carries provenance — elicited, expert, fitted, or mixed — so a reader can tell a guess from a measurement. A doubly-robust estimate and an exact elimination result are epistemically different claims, and behind a single values field they become indistinguishable to anything downstream, because the field is what consumers read. If estimated numbers are ever exposed, they need their own response shape: estimator, version, sample size, interval, assumptions. That is a second product surface, not an internal function call.
Incorporate a library when it does something we cannot do exactly. Do not incorporate one when we can do it exactly and more cheaply ourselves.
Estimation from observational data qualifies. Refutation and subgroup effects on a discrete model do not — they are arithmetic on a model we already hold, and doing them here is what keeps every number in the product auditable in the same way. This section is a decision rule with a date attached, not a permanent position: it holds until one of the two premises stops being true.
DoWhy, EconML and CausalML are named because they are the tools a reader in this space already runs, and because the handoff is shaped for them. No partnership, affiliation or endorsement is implied in either direction, and none of the three is bundled with this service.
They need a graph. This builds one from business content and hands it over with the caveats attached — the half of the pattern no estimator covers.