2026-04-25
Session 44: Phase 5c (cont.): drain TimeSeriesExperiment.finalize_model
Engineering log for session 44.
The fifth (and last user-facing) TS verb is fully native. After this session, every callable TS verb runs without touching legacy — create_model / predict_model / compare_models / tune_model / finalize_model all bypass self._legacy.<verb>. (assign_model doesn't exist for TS — it's an UnsupervisedExperiment-only verb.) The only legacy.* callsite remaining for TS is legacy.setup() inside _native_setup_timeseries itself.
ADDED — engine#
ADDED—TimeSeriesExperiment.finalize_modelinpackages/engine/pycaret/tasks/time_series.py. Refits on the fully(y_train + y_testfrom_fit_state["y"]) using the experiment's preprocess pipeline. Optional exogenousX_fullfrom_fit_state["X"]. Defaultsfit_kwargs["fh"]to the experiment'sfh. Returns aFinalizeResultwhosepipelineis a deployment-readyForecastingPipeline. Doesn't mutate the input — input pipeline keeps its train-only fit. Accepts both bare sktime forecasters andForecastingPipelineinstances; raisesTypeErrorfor anything else.
ADDED — tests#
ADDED—packages/engine/tests/test_session44_ts_finalize_model_drain.py— 7 new tests:- Drain-lock for
finalize_model. - Refits on the full
y(forecaster's_ylength matches_fit_state["y"]). - Bare forecaster path (auto-wires into preprocess).
predict_model(final.pipeline, fh=[1,2,3,4,5,6])after finalize produces 6-step forecasts.- Object without
.fit→TypeError. - End-to-end
create + tune + finalize + predictchain with all 5 legacy verbs poisoned. - Input pipeline isn't mutated by finalize (the original
res.pipelinekeeps its train-only fit).
- Drain-lock for
INTERNAL#
INTERNAL— Noassign_modelfor TS. PyCaret'sassign_modelis defined onUnsupervisedExperiment(clusters/anomaly labels back onto rows).TimeSeriesExperimentinherits fromSupervisedExperiment, notUnsupervisedExperiment, so the verb is genuinely absent — not a missed drain. Confirmed withgrep -n "def assign_model"across the TS module tree: zero hits.INTERNAL— Why phase 5d isn't in this session. Strippinglegacy.setup()from_native_setup_timeseriesrequires porting two pieces: (1) seasonality auto-detection via Fourier analysis (legacy'ssetup()derivesseasonality_present,primary_sp_to_use,strictly_positive,seasonality_typeand TS containers read all of those when constructed), and (2) sktime-nativetemporal_train_test_split+ExpandingWindowSplitterbuild. Substantive enough to be its own session.INTERNAL—finalize_modeldoesn't go throughcreate_model. Unliketune_model(which refits viacreate_modelto get standard CV metrics),finalize_modelis fundamentally a "refit on more data" operation — there's no holdout left to CV against. So we just callpipeline.fit(y=y_full, X=x_full)directly. Matches legacy semantics.INTERNAL—fhdefaulting in fit_kwargs. Some sktime forecasters (e.g. ARIMA with auto order) need to know the forecast horizon at fit-time. Defaulting to the experiment'sfhletspredict_modelwork post-finalize without the user having to re-specify it. Thetry/except TypeErrorretry handles forecasters that don't acceptfhin fit (e.g.NaiveForecaster).
Session 44 delta summary#
| Metric | Session 43 end | Session 44 end |
|---|---|---|
| TS verbs drained | 4 of 6 | 5 of 5 callable verbs (assign_model n/a) |
legacy.<verb> callsites for TS | 1 (finalize_model) | 0 |
| Engine tests (fast + slow) | 228 | 235 |