ForeSight now separates its package internals into a few stable layers so model growth does not keep dragging orchestration and validation concerns back into the same modules.
contracts
- Shared frame validation, parameter normalization, interval parsing, and capability checks.
- These modules are dependency-light and should not import
services, CLI code, or registry facades.
models/specs.py, models/factories.py, models/catalog/, models/registry.py
models/specs.pyownsModelSpecand related typing.models/factories.pyowns runtime object construction.models/catalog/owns model metadata shards only.models/registry.pyis the public facade that composes catalog shards and exposes lookup /make_*helpers.
services
services/forecasting.pyowns forecast workflow orchestration.services/evaluation.pyowns evaluation workflow orchestration.- Services may depend on
contracts,models.registry, metrics, splits, and existing algorithm modules.
facades
forecast.pyandeval_forecast.pyremain import-stable public entrypoints.- They should stay thin and delegate implementation to
services. - Temporary module-level compatibility shims are acceptable during migrations, but private helpers must not be part of the public export surface in
__all__. - New logic should not accumulate in these modules.
cli.py
- Owns parser construction, argument mapping, formatting, and exit behavior.
- Business rules should live in
servicesorcontracts, not in duplicated local helper functions.
contractsmust not importservices.base.pymust rebuild runtime state throughmodels.factories, not throughmodels.registry.cli.pyshould not redefine long-frame validators or covariate normalization helpers.servicesmay callmodels.registry, butmodels.registryshould not depend onservices.servicesmust not importforesight.forecast,foresight.eval_forecast, orforesight.cli.- Once dedicated
models/resolution.pyandmodels/runtime.pymodules exist,models.registryshould remain a facade and stop defining private helper families that belong in those modules.
Add new code based on ownership, not convenience:
- Put shared validation or normalization in
contracts. - Put workflow assembly in
services. - Put model metadata in
models/catalog/. - Put runtime constructor behavior in
models/factories.py. - Keep
forecast.py,eval_forecast.py, andmodels/registry.pyas facades unless compatibility explicitly requires a small wrapper.
All registered model metadata belongs in src/foresight/models/catalog/.
- Group related families into shard modules such as
classical.py,ml.py,stats.py,torch_local.py,torch_global.py,multivariate.py, andfoundation.py. catalog/__init__.pyis responsible for composing shards and rejecting key collisions.
Use this rule of thumb:
- If the module exists mainly because users import it directly, it is a facade.
- If the module exists mainly to hold the actual workflow or shared behavior, it is an implementation layer.
Today the main facades are:
foresight.forecastforesight.eval_forecastforesight.models.registry
The main implementation layers are:
foresight.contracts.*foresight.services.*foresight.models.catalog.*foresight.models.factories- algorithm modules under
foresight.models.*