Complete Request Lifecycle ========================= This page follows one command from invocation to generated artifacts: .. code-block:: bash habit cv -c config/machine_learning/config_machine_learning_kfold_demo.yaml The command loads an ML configuration, runs K-fold cross-validation, and generates models, metrics, and plots. Seven stages ------------ .. mermaid:: flowchart TD S1["1. CLI entry
habit/cli.py"] --> S2["2. Command layer
commands/cmd_ml.py"] S2 --> S3["3. Load and validate
MLConfig.from_file()"] S3 --> S4["4. Core API
run_kfold_from_config()"] S4 --> S5["5. Assemble
MLConfigurator"] S5 --> S6["6. Execute
KFoldWorkflow -> KFoldRunner"] S6 --> S7["7. Report
models, metrics, plots"] Stage 1: CLI entry ------------------ The ``cv`` command declares its configuration option and uses a lazy import: .. code-block:: python @cli.command("cv") @config_option() def cv(config): """Run K-fold cross-validation for model evaluation.""" from habit.commands.cmd_ml import run_kfold run_kfold(config) The function-level import keeps ``habit --help`` fast and avoids loading optional dependencies for unrelated commands. Stage 2: command layer ---------------------- The command layer loads configuration, creates output directories, configures logging, delegates to the core API, and converts failures into clean CLI errors. It contains no domain algorithm. Stage 3: loading and validation ------------------------------ ``load_config_or_exit(MLConfig, path)`` reads the file, resolves paths relative to the configuration file, and validates it with Pydantic. Invalid fields and types fail before computation starts. Step parameters are checked through ``ParamSchemaRegistry``. Stage 4: core API ----------------- ``run_kfold_from_config()`` is the boundary shared by CLI and Python callers: .. code-block:: python def run_kfold_from_config(config, *, logger=None, output_dir=None): if config.run_mode != "train": raise ValueError("K-fold cross-validation requires run_mode='train'.") configurator = MLConfigurator(config=config, logger=logger, output_dir=output_dir) workflow = configurator.create_kfold_workflow() return workflow.run() The important sequence is **Configurator assembly followed by Orchestrator execution**. Stage 5: assembly ----------------- ``MLConfigurator`` translates the validated configuration into a ``KFoldWorkflow`` and resolves models, selectors, evaluators, and reporting services through registries. The configurator assembles objects but does not run the workflow. Stage 6: execution ------------------ ``KFoldWorkflow`` orchestrates the run, while ``KFoldRunner`` performs each fold: .. mermaid:: flowchart TD WF["KFoldWorkflow"] --> PLAN["WorkflowPlan
frozen config"] PLAN --> RUN["KFoldRunner"] RUN --> DM["DataManager
load and split"] DM --> PB["PipelineBuilder
selector -> scaler -> model"] PB --> FIT["fit on train fold
evaluate validation fold"] FIT --> RES["KFoldRunResult"] The complete sklearn Pipeline is fitted only on training folds, preventing data leakage. Stage 7: artifacts ------------------ The structured result is passed to reporting and visualization. Models, metrics, and plots are written to the configured output directory. Plot text is English by project convention. The same lifecycle applies to preprocessing, habitat segmentation, and model training; only the schema, configurator, workflow, and runner change.