Skip to content

Check

Definition

Check is a small frozen dataclass representing the outcome of a single preflight path-existence test. A collection of Check objects is passed to run_preflight(), which logs each result and raises SystemExit on the first critical failure. Check objects are produced by check_path_exists() and consumed exclusively by run_preflight().

Kind

Value object (@dataclass, four fields). Immutable by convention (no frozen=True in the dataclass decorator, but no mutation after construction occurs in the codebase).

Source of truth

run/preflight.py:20class Check.

@dataclass
class Check:
    """Result of a single preflight check."""

    name: str
    passed: bool
    message: str = ""
    critical: bool = False

Key attributes

Field Type Default Semantics
name str Human-readable identifier, typically "path_exists:<path>"
passed bool True if the check succeeded
message str "" Diagnostic detail; empty on success, "Path not found: <path>" on failure
critical bool False When True and passed=False, run_preflight() raises SystemExit

Lifecycle

  1. check_path_exists(path) (preflight.py:30) wraps AnyPath(str(path)).exists() (cloud-safe) and returns a Check with critical=True.
  2. Stage-specific functions (see below) build list[Check] by calling check_path_exists for each required path.
  3. run_preflight(checks) (preflight.py:42) iterates the list, logs at SUCCESS / WARNING / ERROR, and raises SystemExit on the first critical failure.

The five stage-specific check-sets

Each function in run/preflight.py returns a list[Check] tailored to one pipeline stage:

Function Stage What it checks
preflight_paths_for_features run_features All ResolvablePath inputs (stress parquet omitted when assembled from indices)
preflight_paths_for_hindcast run_hindcast / run_fit_production check_data_exists entries + fit.parquet + pred.parquet under features_dir
preflight_paths_for_forecast_features run_forecast_features Resolvable inputs + canonical hindcast pred.parquet
preflight_paths_for_forecast_predict run_forecast_predict Resolvable inputs + per-(season_year, init_date) forecast features parquet + detrender.pkl + feature_fill_values.parquet
preflight_paths_for_export run_export Resolvable inputs only

preflight_paths_for_forecast (preflight.py:183) is a convenience composer that returns the union of preflight_paths_for_forecast_features and preflight_paths_for_forecast_predict; it is not a sixth independent check-set.

preflight_paths_for_resolvable_inputs (preflight.py:77) is a shared helper called by several of the above; it mechanically walks _iter_resolvable_fields(config) so any new ResolvablePath field is automatically covered without a hand-maintained list.

Relationships

  • Produced by: check_path_exists (preflight.py:30)
  • Consumed by: run_preflight (preflight.py:42)
  • Assembled by: the five stage-specific functions above
  • Called from: cli.py entry points (e.g. run_features_cmd calls preflight_paths_for_features), delivery/export.py:run_export (calls run_preflight(preflight_paths_for_export(config)))

Package layering caveats

The Check entity itself is innocent of any layering violation. Two import-direction issues exist in the surrounding package:

  • delivery/export.py:39 imports preflight_paths_for_export and run_preflight from run/preflight.py. The run/ package is an orchestration-level module; Delivery should not depend on it directly. Correct home: migrate preflight_paths_for_export to lib/.
  • delivery/conversions.py:50 imports primary_calibration from stages/run_meta_models.py. Delivery should not depend on Stages. Correct home: lib/conformal/.

Both violations are non-breaking at runtime but contradict the single-direction import rule in DESIGN.md:49 and complicate isolated testing of the Delivery subsystem.

Open questions

  • All current checks are path-existence checks with critical=True. The critical=False / warning path is plumbed but never exercised. Non-critical checks (e.g. config-value sanity) could be added without changing the interface.