Part of #980 (v1.0 M1). Closes #854 when it lands.
Reordering fit to (X, y, treatment, …) is necessary but not sufficient for #854. Pipeline.fit(X, y) passes exactly two things; treatment is a third required array with nowhere to ride. After the flip a CausalML learner still can't be a Pipeline step without an adapter — the reordering just removes the first obstacle.
The mechanism sklearn provides is metadata routing: fit(X, y, **fit_params) with set_fit_request(treatment=True), so a caller writes pipe.fit(X, y, treatment=treatment) and the router delivers treatment to the step that asked for it.
Prerequisite
#985, the signature flip. Until then Pipeline's positional y binds to treatment, so an end-to-end test cannot be written. #985 is unblocked and targets v1.0 (Jun 2027).
Scope for the first pass
- Meta-learners only — they are the classes users most want inside a Pipeline.
- Integration tests and documentation before any custom
MetadataRouter. BaseLearner subclasses BaseEstimator and the fit signatures declare treatment and p explicitly, so set_fit_request should be generated automatically; confirm that against sklearn.utils.metadata_routing before writing any routing code.
- Cover an S-learner pipeline plus one propensity-consuming learner.
- Cover both paths: routing enabled via
sklearn.set_config(enable_metadata_routing=True), and the prefixed routing-disabled form.
- Row-preserving transformers only. Resampling has to move
X, y, treatment and p together and belongs in its own design.
Out of scope for the first pass: whether p should route into a learner's wrapped estimator, rather than being consumed by the learner itself.
Why it's separate
The argument order is a breaking change on a deadline (v1.0 API freeze); routing is additive and can land any time after. Coupling them would put a design-heavy feature on the critical path of a mechanical rename.
Acceptance
Part of #980 (v1.0 M1). Closes #854 when it lands.
Reordering
fitto(X, y, treatment, …)is necessary but not sufficient for #854.Pipeline.fit(X, y)passes exactly two things;treatmentis a third required array with nowhere to ride. After the flip a CausalML learner still can't be a Pipeline step without an adapter — the reordering just removes the first obstacle.The mechanism sklearn provides is metadata routing:
fit(X, y, **fit_params)withset_fit_request(treatment=True), so a caller writespipe.fit(X, y, treatment=treatment)and the router deliverstreatmentto the step that asked for it.Prerequisite
#985, the signature flip. Until then
Pipeline's positionalybinds totreatment, so an end-to-end test cannot be written. #985 is unblocked and targets v1.0 (Jun 2027).Scope for the first pass
MetadataRouter.BaseLearnersubclassesBaseEstimatorand thefitsignatures declaretreatmentandpexplicitly, soset_fit_requestshould be generated automatically; confirm that againstsklearn.utils.metadata_routingbefore writing any routing code.sklearn.set_config(enable_metadata_routing=True), and the prefixed routing-disabled form.X,y,treatmentandptogether and belongs in its own design.Out of scope for the first pass: whether
pshould route into a learner's wrapped estimator, rather than being consumed by the learner itself.Why it's separate
The argument order is a breaking change on a deadline (v1.0 API freeze); routing is additive and can land any time after. Coupling them would put a design-heavy feature on the critical path of a mechanical rename.
Acceptance
Pipelinefinal step withtreatmentrouted, no adapter class.