Metadata not routed to transformers in pipeline during cross validation.

### Describe the bug

When using a pipeline with transformers in combination with cross validation, it seems that metadata is not correctly routed to the transformers during prediction. I would expect, that if `set_transform_request` is set, that this is honored when calling predict on the pipeline.

**Edit:** At least according to the code this is a known limitation. Although I couldn't find an issue tracking the progress on this.
https://github.com/scikit-learn/scikit-learn/blob/9028b518e7a906a806a1dc8994f2714cc980c941/sklearn/model_selection/_validation.py#L362C1-L367C14

### Steps/Code to Reproduce

```python
import sklearn
from sklearn.pipeline import Pipeline
from sklearn.linear_model import LinearRegression
from sklearn.datasets import make_regression
from sklearn.base import TransformerMixin, _MetadataRequester
from sklearn.model_selection import cross_validate

print(sklearn.__version__)

sklearn.set_config(enable_metadata_routing=True)


class DummyTransfomerWithMetadata(TransformerMixin, _MetadataRequester):

    def fit(self, X, y=None, metadata=None):
        return self

    def transform(self, X, y=None, metadata=None):
        print(f"Received {metadata=}")
        return X

    # We need to explicitly implement fit_transform,
    # otherwise transform will not receive metadata during fit
    def fit_transform(self, X, y=None, metadata=None):
        return self.transform(X, y, metadata)


X, y = make_regression()

transformer = DummyTransfomerWithMetadata()
transformer.set_fit_request(metadata=True)
transformer.set_transform_request(metadata=True)


pipe = Pipeline([
    ("transformer", transformer),
    ("clf", LinearRegression())
])


print(f"--- Cross validation ---")
cross_validate(
    pipe, X, y, params={"metadata": "Some metadata"}, cv=2
)
```

### Expected Results

```
1.7.0
--- Cross validation ---
Received metadata='Some metadata'   # Fit 
Received metadata='Some metadata'   # Predict
Received metadata='Some metadata'
Received metadata='Some metadata'
```

### Actual Results

```
1.7.0
--- Cross validation ---
Received metadata='Some metadata'
Received metadata=None
Received metadata='Some metadata'
Received metadata=None
```

### Versions

```shell
System:
    python: 3.12.9 (main, Feb 12 2025, 14:50:50) [Clang 19.1.6 ]
executable: /home/max/.cache/uv/archive-v0/unVsgMut5oyZJu14JLk-G/bin/python
   machine: Linux-6.1.138-1-MANJARO-x86_64-with-glibc2.41

Python dependencies:
      sklearn: 1.7.0
          pip: None
   setuptools: None
        numpy: 2.3.1
        scipy: 1.16.0
       Cython: None
       pandas: None
   matplotlib: None
       joblib: 1.5.1
threadpoolctl: 3.6.0

Built with OpenMP: True

threadpoolctl info:
       user_api: blas
   internal_api: openblas
    num_threads: 12
         prefix: libscipy_openblas
       filepath: /home/max/.cache/uv/archive-v0/unVsgMut5oyZJu14JLk-G/lib/python3.12/site-packages/numpy.libs/libscipy_openblas64_-56d6093b.so
        version: 0.3.29
threading_layer: pthreads
   architecture: Haswell

       user_api: blas
   internal_api: openblas
    num_threads: 12
         prefix: libscipy_openblas
       filepath: /home/max/.cache/uv/archive-v0/unVsgMut5oyZJu14JLk-G/lib/python3.12/site-packages/scipy.libs/libscipy_openblas-68440149.so
        version: 0.3.28
threading_layer: pthreads
   architecture: Haswell

       user_api: openmp
   internal_api: openmp
    num_threads: 12
         prefix: libgomp
       filepath: /home/max/.cache/uv/archive-v0/unVsgMut5oyZJu14JLk-G/lib/python3.12/site-packages/scikit_learn.libs/libgomp-a34b3233.so.1.0.0
        version: None
```

COMMENT:
I have looked at this and my understanding is that `cross_validate` cannot route metadata to any `predict` method (yet), because it only indirectly calls `estimator.predict()` via a scorer. And the scorer then can be several different objects, which makes it complicated to implement.

Here's another reproducible that doesn't use a `Pipeline`.

```py
import sklearn
from sklearn.datasets import make_regression
from sklearn.base import RegressorMixin, BaseEstimator
from sklearn.model_selection import cross_validate

import numpy as np

sklearn.set_config(enable_metadata_routing=True)

class CustomRegressor(RegressorMixin, BaseEstimator):

    def fit(self, X, y=None, metadata=None):
        print(f"Received {metadata=} in fit")
        return self

    def predict(self, X, y=None, metadata=None):
        print(f"Received {metadata=} in predict")
        return np.zeros(shape=(len(X),))

    # commenting out to use the default scorer, in which case `CustomRegressor.predict()` is passed into `r2_score()`
    # def score(self, X, y, metadata=None):
    #     print(f"Received {metadata=} in score")
    #     return 1

X, y = make_regression()

estimator = CustomRegressor()
estimator.set_fit_request(metadata=True)
estimator.set_predict_request(metadata=True)
# estimator.set_score_request(metadata=True)
print(f"--- Cross validation with estimator ---")
cross_validate(
    estimator, X, y, params={"metadata": "Some metadata"}, cv=2
)
```

output:
```
Received metadata='Some metadata' in fit
Received metadata=None in predict
Received metadata='Some metadata' in fit
Received metadata=None in predict
```

I haven't deeply looked into #31654, but my impression is that it fix part of this issue (on the scoring side) and then what is left is to fix the issue on the `cross_validate` (and other splitters) side by implementing a routing to predict methods.

@sirzechs66 Thanks for trying this and sharing your accessment.
It's right that in cross-validation, each fold is processed separately, and that during each fold it calls the pipeline's `fit` and `predict` while going through all the steps that might come before (also possibly `transform` if a transformer is part of a pipeline). The problem here is that in cross validation the routing to `predict` isn't implemented yet (metadata routing is still work in progress) and that therefore, a call to a pipeline's `predict` method also doesn't trigger metadata routing to any of the the previous steps (neither `transform`).
That part of the code is mixing several concepts and it is better to get used to them slowly.

Labels: Bug, Metadata Routing