Skip to content

Rollforward Workflow API Reference

Rollforward Workflow

Rollforward is the single object for all three rollforward surfaces: .run(mode="model") (in-memory), .run(mode="workflow", output_dir=...) (artifact-emitting), and .readiness(...). run(), run_rollforward_workflow(), and generate_rollforward_readiness_report() are convenience entry points over it. Run readiness checks first when working with a new dataset. The result types (RollforwardRunSummary, operational_status, etc.) are the canonical cross-surface summary contract.

Each result also has .summary()/.plot() (RollforwardResult, RollforwardWorkflowResult) matching vintage/survival/predictive. ReadinessRunResult is a deliberate partial exception: it already has a field named summary (the readiness scoring dict), so result.summary — no call — already serves that role there; it still has .plot().

cranalytics.rollforward

Unified public front door for the rollforward workflow.

Rollforward is the single object for all three rollforward surfaces, hiding the multi-module session / evaluation / reporting / result-translation chain behind a small interface:

  • .run(mode="model") -> in-memory :class:RollforwardResult
  • .run(mode="workflow") -> artifact-emitting :class:RollforwardWorkflowResult
  • .readiness(...) -> readiness :class:ReadinessRunResult

model and workflow share the same session engine and differ only in whether artifacts are written, so they are two modes of one run. readiness uses a distinct session, config, and defaults, so it is a sibling method on the same object rather than a mode with half-ignored parameters. The module-level functions run (workflow-namespaced: cranalytics.rollforward.run), run_rollforward_workflow, and generate_rollforward_readiness_report are thin shims over this object.

No file I/O in model mode — fully in-memory.

This module carries the workflow's real entry-point logic (the Rollforward class), unlike the pure re-export facades used by other workflows — there is no separate flat module to preserve here. _workflow.py/_readiness.py-style thin wrappers are intentionally kept inline below rather than split into their own submodules: those submodules would need Rollforward from here, and this module re-exports their functions, which is a circular import.

ReadinessRunResult dataclass

No .summary() method here: summary is already a field (the readiness scoring dict), so result.summary already gives the compact summary other Phase 3 workflow results expose via a method call.

plot(**kwargs: Any) -> Any

Forecast-vs-actual chart already written to output_dir. Requires matplotlib.

RollforwardResult dataclass

summary() -> pd.DataFrame

Champion-vs-challenger backtest comparison, best-first by MAPE.

plot(**kwargs: Any) -> Any

Per-segment champion MAPE bar chart. Requires matplotlib.

RollforwardWorkflowResult dataclass

Workflow status and selected Rollforward model information.

summary() -> pd.DataFrame

One-row DataFrame of portfolio KPIs (total balance, champion, etc.).

plot(**kwargs: Any) -> Any

Forecast-vs-actual chart already written to output_dir. Requires matplotlib.

Rollforward

is_ready_to_model() -> bool

Quick pre-flight: no critical data issues and sufficient MOB history (>=18).

run(*, mode: RollforwardRunMode = 'model', output_dir: Path | str | None = None, holdout_months: int = 6, min_train_months: int = 12, step_months: int = 1, variants: list[str] | None = None, monitor_thresholds: dict[str, float] | None = None, segment: str | None = None, strict: bool = False) -> RollforwardResult | RollforwardWorkflowResult

Run the rollforward workflow in-memory (model) or with artifacts (workflow).

Parameters:

Name Type Description Default
mode RollforwardRunMode

"model" returns an in-memory result; "workflow" also writes committee-ready artifacts to output_dir.

'model'
output_dir Path | str | None

Required when mode="workflow"; ignored otherwise.

None
holdout_months int

Final months reserved for holdout evaluation.

6
min_train_months int

Minimum historical months required for training.

12
step_months int

Backtest step size.

1
variants list[str] | None

Optional candidate variant names.

None
monitor_thresholds dict[str, float] | None

Optional KPI threshold overrides.

None
segment str | None

Optional single segment to model.

None
strict bool

Whether warnings should fail validation.

False

Returns:

Type Description
RollforwardResult | RollforwardWorkflowResult

class:RollforwardResult for model mode, or

RollforwardResult | RollforwardWorkflowResult

class:RollforwardWorkflowResult for workflow mode.

Raises:

Type Description
ValueError

If mode is not "model" or "workflow", or if mode="workflow" is used without output_dir. For readiness reports use :meth:readiness.

readiness(*, output_dir: Path | str, holdout_months: int = 6, min_train_months: int = 6, segment: str | None = None, strict: bool = False, scoring_config: ReadinessConfig | None = None, weights: Mapping[str, float] | None = None) -> ReadinessRunResult

Generate a rollforward readiness report and emit its artifacts.

Readiness uses a distinct session and scoring configuration from :meth:run, including a lower default min_train_months.

build_facade_result(session: RollforwardWorkflowSessionResult) -> RollforwardResult

Translate a workflow session result into a Rollforward facade result.

build_rollforward_run_summary(*, surface: RollforwardResultSurface, status: str, issue_count: int = 0, max_mob: int | None = None, champion: str | None = None, challengers: Sequence[str] = (), promotion_reason: str | None = None, output_dir: Path | None = None, details: Mapping[str, Any] | None = None, is_production_ready: bool | None = None) -> RollforwardRunSummary

Build a canonical rollforward run summary from surface-specific inputs.

normalize_rollforward_operational_status(status: str, *, issue_count: int = 0, is_production_ready: bool | None = None) -> RollforwardOperationalStatus

Map surface-specific statuses into a shared pass/attention/blocker vocabulary.

rollforward_run_summary_payload(summary: RollforwardRunSummary) -> dict[str, Any]

Return a JSON-friendly payload for a shared rollforward run summary.

run(df: pd.DataFrame, **kwargs) -> RollforwardResult

Convenience one-liner: initialize, run in-memory model mode, return result.

For artifact-emitting workflow runs or readiness reports, use the :class:Rollforward object directly (.run(mode="workflow", ...) / .readiness(...)) — those need an output_dir and have different defaults, so they are not folded into this convenience function.

run_rollforward_workflow(df: pd.DataFrame, *, output_dir: Path, holdout_months: int = 6, min_train_months: int = 12, step_months: int = 1, variants: list[str] | None = None, monitor_thresholds: dict[str, float] | None = None, amtloan_col: str = 'amtloan', segment: str | None = None, strict: bool = False) -> RollforwardWorkflowResult

Run the canonical monthly Rollforward workflow and emit artifacts.

Parameters:

Name Type Description Default
df DataFrame

Aggregated monthly flow data.

required
output_dir Path

Directory for normalized data, diagnostics, forecasts, and committee-ready artifacts.

required
holdout_months int

Number of final months reserved for holdout evaluation.

6
min_train_months int

Minimum historical months required for training.

12
step_months int

Backtest step size.

1
variants list[str] | None

Optional candidate variant names.

None
monitor_thresholds dict[str, float] | None

Optional KPI threshold overrides.

None
amtloan_col str

Original-loan-amount column used by contract checks.

'amtloan'
segment str | None

Optional single segment to model.

None
strict bool

Whether warnings should fail validation.

False

Returns:

Type Description
RollforwardWorkflowResult

Workflow result with status, output directory, champion, and

RollforwardWorkflowResult

challengers.

Examples:

>>> from tempfile import TemporaryDirectory
>>> import pandas as pd
>>> from cranalytics.rollforward import run_rollforward_workflow
>>> rows = [
...     {"segment_id": "prime", "month_on_book": mob, "payments": 100.0,
...      "chargeoffs": 5.0, "outstanding_balance": 2000.0 - mob * 100,
...      "amtloan": 2000.0}
...     for mob in range(1, 19)
... ]
>>> with TemporaryDirectory() as output_dir:
...     result = run_rollforward_workflow(pd.DataFrame(rows), output_dir=output_dir)
...     result.status in {"ok", "data_issues", "insufficient_data"}
True

generate_rollforward_readiness_report(data: pd.DataFrame, *, output_dir: Path, holdout_months: int = 6, min_train_months: int = 6, segment: str | None = None, amtloan_col: str = 'amtloan', strict: bool = False, scoring_config: ReadinessConfig | None = None, weights: Mapping[str, float] | None = None) -> ReadinessRunResult

Generate Rollforward readiness report artifacts from a rollforward frame.

DataFrame-first, matching the rest of the library. File reading is the caller's (or the CLI's) responsibility. Thin shim over :meth:Rollforward.readiness.

Rollforward Contract

The contract module owns reusable validation for aggregated monthly flow data. Use it when integrating a new source or diagnosing alias resolution.

cranalytics.rollforward._contract

Public input-contract helpers for the Rollforward workflow.

RollforwardContractResult dataclass

Bases: IssueTableResultMixin

Normalized rollforward data plus collected contract issues.

normalized_df(*, segment: str | None = None) -> pd.DataFrame

Return normalized rollforward data, optionally filtered to one segment.

amtloan_series(*, segment: str | None = None) -> pd.Series | None

Return resolved denominator series, optionally filtered to one segment.

amtloan_map(*, segment: str | None = None) -> dict[str, float]

Return resolved denominators as a segment->value mapping.

validate_rollforward_input_contract(df: pd.DataFrame, *, amtloan_col: str = 'amtloan', strict: bool = False) -> RollforwardContractResult

Normalize columns, resolve aliases, and collect rollforward data issues.

Rollforward Backtest

Backtest helpers compare candidate Rollforward variants over historical holdouts. Use these lower-level functions when you need custom evaluation control beyond the workflow boundary.

cranalytics.rollforward._backtest

Backtesting helpers for Rollforward workflow variants.

run_rollforward_backtest_sweeps(df: pd.DataFrame, *, variants: list[str] | None = None, holdout_horizons: tuple[int, ...] = (3, 6), min_train_months: int = 12, step_months: int = 1, amtloan_by_segment: pd.Series | None = None, amtloan_col: str = 'amtloan') -> pd.DataFrame

Run rolling OOT backtests across configured rollforward variants.

summarize_rollforward_variant_performance(results: pd.DataFrame) -> pd.DataFrame

Aggregate split-level rollforward backtest results to one row per variant.

select_rollforward_champion_and_challengers(summary: pd.DataFrame, *, benchmark_variant: str = 'baseline_flat_last_hazard', challenger_count: int = 2) -> dict[str, Any]

Select a champion variant subject to baseline promotion rules.