Repository navigation
Forecasting prereqs - #932
Open
Felipedino wants to merge 5 commits into
Open
Felipedino wants to merge 5 commits into
Felipedino wants to merge 5 commits into
Conversation
Felipedino
added this pull request to stack #936
October 24, 2026 20:49
ReversingTask moves to its own module so the prediction and explanation tests can use it too. It now names the splitters and the model those tests need, and SeriesOnlyTask stands in for forecasting without registering ForecastingTask: it offers only the temporal holdout splitter.
Run.split_indexes are positions in the dataset the task prepared, and a task may reorder it: forecasting sorts by date. Predicting on a partition selected those positions from the loaded dataset, so with a reordering task it predicted and saved other rows, without an error. The job now prepares the loaded rows with the columns training used (the raw refs when the session preprocesses) before selecting. Preparing keeps every column, value and type, which a test pins: with a task that does not reorder, a partition's saved prediction is the whole dataset's for its rows.
…epared PrepareExplanationDataUnit cut the loaded dataset with the run's indexes, handed the three parts to the task and cut the result again with the same indexes. The task merges a dict of parts back in alphabetical order of their names, test first, so every explainer got partitions holding rows of the others, with any task. A task that reorders, as forecasting does, read the loaded order on top of that. The unit now prepares the loaded rows first, with the columns training prepared with, and cuts once. A session that preprocesses supplies input_column_refs together with the artifacts path, so the task gets the raw refs, and each part is transformed after the cut as before. The pairing check moves to a module function in splitter_scope, shared with the partition units.
…tegy The session API validated a splits payload against its splitter's schema only. A run prepares with the unit the splitter's PARTITIONING picks and fits with the unit the strategy's KIND picks, so a holdout strategy with a fold splitter failed every run with a missing context key. A splitter the task does not offer ran without a word: a temporal holdout on a regression, or the default HoldoutSplitter, which shuffles, under a payload that named none. A registered name of another type reached the schema lookup as a 500. Strategies now declare SPLITTER_PARTITIONING, and the API resolves the splitter (the default included) and checks it against the splitters the task offers and the partitioning the strategy takes, on creation and on a change of task. The default stays for the sessions that rely on it; a task that does not offer it gets a 422 that says no splitter was named.
POST /run/ only checked that the model name was registered, of any type, so a regressor in a classification session, or a metric's name, was stored and failed or misbehaved inside the fit. The endpoint now asks the registry the question the wizard asks, after the download checks so their 409 stays. A change of task by PATCH asks it for every run the session has. A run whose model the new task does not offer refuses the change with a 422 that names the runs; they are neither deleted nor flagged. The relation lookup the three session checks share moves to api.utils.offered_components.
Felipedino
force-pushed
the
reconcile/forecasting-prereqs
branch
from
October 24, 2026 23:35
fc3398a to
f319e05
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First PR of the stack that ends with the forecasting redesign. It does not touch forecasting. It fixes general bugs that forecasting exposes, because forecasting is the only task that reorders rows and the only one whose splitters suit no other task.
Base:
developat88810b892(merge of #918).Why
Run.split_indexesare positions in the dataset as the task prepared it, since that is what training partitions. A task may reorder that dataset:ForecastingTasksorts it by date. Two consumers still indexed the loaded dataset. Separately, the session and run APIs did not check that the splitter and the model fit the task and the strategy.PredictJobselected a run's partition from the loaded rowsPrepareExplanationDataUnitcut the loaded rows and only then prepared themsplitter_namefalls back toHoldoutSplitter, which shufflesUnitContractError. A splitter the task does not offer ran without a word. A registered name that is not a splitter caused a 500POST /run/only checked that the model name was registered, with any typeChanges
PredictJob): when the prediction names a partition, the job prepares the loaded rows first and then selects them. It prepares with the columns training used: the raw refs if the session preprocesses,input_columnsotherwise.PrepareExplanationDataUnit):ModelJobdoes;input_column_refsfield, which comes together withpreprocessing_artifacts_pathor not at all.ExplainerJobpasses it;splitter_scope.persisted_preprocessing. The partition units keep calling it through the same method as before.POST/PATCH /model-session/):SPLITTER_PARTITIONING:"holdout","folds", orNonefor the full-dataset strategy;_validate_splitsresolves the splitter, including the default, and checks, in order: that the name is registered, that the task offers it, that itsPARTITIONINGis the one the strategy takes, and that its schema accepts the payload;POST /run/,PATCH /model-session/):Modelcomponents the task offers. This check runs after the download checks, so their 409 stays;api.utils.offered_components(registry, task, type)holds the relation lookup that the strategy, splitter, model and run checks share.ModelJobandnormalize_splits_payloadare unchanged. Validation lives in the API, and the job trusts it. This is the same approach clustering took for the strategy.Behavior changes
All of these are deliberate:
COMPATIBLE_COMPONENTS, as they already must declare their strategies. Relations are stored both ways, so a task can name splitters and models it does not own.PrepareExplanationDataUnitrejects an artifacts path that comes without refs, raisingJobError.Tests
Every new test was run against the unfixed code first and failed for the expected reason.
tests/back/api/row_order_tasks.py:ReversingTask, moved here from the preprocessing row-order test, andSeriesOnlyTask, which offers onlyTemporalHoldoutSplitter. With it, U7 is covered without registeringForecastingTask.test_predict_job_row_order.py: thetestandvalpartitions, each with and without session preprocessing.test_predict_job.pyandtest_predict_job_preprocessing.py: a prediction on a partition saves exactly what a whole-dataset prediction saves for those rows. That covers columns, declared types, the Arrow schema with its metadata, and values. These tests passed before and after the fix: they pin that preparing changes nothing but the row order.test_explanation_units.py:RegressionTask(U2b), with a reversing task (U2), and with a persisted preprocessor;test_session_splitter_validation.py: wrong partitioning, a splitter the task does not offer, a non-splitter name, the default under a task that does not offer it, and a change of task.test_run_model_validation.py: a model the task does not offer, a non-model name, and a change of task with an incompatible run.test_units_api.pynow pins the schema ofPrepareExplanationDataUnit.Verification
uv run --frozen --extra cpu pytest tests/ --deselect tests/back/test_main.py::test_app_front.test_model_job_cross_validation.py,test_model_job_orchestration.py,test_model_job_clustering_net.py,test_clustering_notebook_net.py) have no diff and pass.EXPECTED_UNITSat 37. No units were added.ruff checkandruff format --checkare clean on the touched files.Out of scope
GenerateLocalExplanationUnit._select_instancesprepares before indexing, but it transforms the whole dataset first, so a step that drops rows (NanRemover) shifts the indexes.ReportJobprepares with the post-converter input columns and does not apply the session preprocessor.POST /predict/does not check the partition againstpredictable_splits.{}), or a fold-shaped payload with no splitter name under a holdout strategy, still resolves toHoldoutSplitter.PATCH /model-session/{id}withdataset_idre-validates nothing. That was already the case before this PR.