Migrating to v0.50#

The v0.50 release is the SPEC 7 rng parameter adoption, the follow-up to v0.49’s _rng.py scaffold. Every Tier-1 public function that consumes a NumPy RNG now exposes a canonical rng: RNGLike | SeedLike | None parameter per Scientific Python SPEC 7. Bodies normalize via np.random.default_rng(rng).

If you’re jumping from v0.48 (or earlier) and have not migrated through v0.49, read migration/v0.49.md first.

What’s BREAKING at v0.50#

22 Tier-1 function signatures renamed: seed: int = X / random_state: int | Nonerng: RNGLike | SeedLike | None = X. Defaults preserved (still deterministic-by-default).

Affected functions#

  • bootstrap.py (7 public + 1 private): bootstrap_ci, paired_bootstrap_diff, paired_bootstrap_ece_diff, paired_bootstrap_op_point_diff, paired_mde, block_bootstrap_on_folds, cross_validate_metric, _bootstrap_t_ci.

  • metrics.py: expected_calibration_error_debiased.

  • thresholds.py: selected_operating_point + _bootstrap_threshold_metric_cis.

  • analysis.py: bootstrap_metric_from_predictions, paired_diff_from_prediction_refs.

  • harness.py (6 sites): evaluate, evaluate_scorer_on_slice, _bootstrap_auc_ci, _evaluate_scores, _compute_paired_diffs, _score_all_slices.

  • scorecards.py: scorecard, _evaluate_spec.

  • stacking.py: LogisticStacker.random_stateLogisticStacker.rng class-field rename (sklearn pass-through derives int at the boundary).

Migration recipe#

Before:

bootstrap_ci(y, scores, pr_auc, seed=42)
LogisticStacker(random_state=7)

After:

bootstrap_ci(y, scores, pr_auc, rng=42)
LogisticStacker(rng=7)

Bit-for-bit reproducibility is preserved when migrating seed=42rng=42 (int seed is SeedLike; np.random.default_rng(42) is the canonical normalization).

Config schema (Tier-2 additive)#

evaluate() config dict key "seed""rng". Generator-typed input serializes as repr(rng); int/None serialize as-is (backward-compatible for prior int-seed usage).

Exceptions to SPEC 7 (KEPT seed: — documented in STYLE.md §3a + ADR 0004 D4)#

  • seeds.set_global_seeds(seed: int) — global-state setter, not per-function RNG.

  • adversarial.py dataclass fields + functional wrappers — use Python stdlib random.Random(seed), not NumPy.

  • splits.py Splitter dataclass class-fields (HoldoutSplitter.seed, StratifiedKFoldSplitter.seed, etc.) — configuration storage, not a user-facing RNG parameter.

  • loaders.py:903 YAML config schema key — declarative; renaming would break consumer YAMLs.

Known issues addressed in v0.51#

The v0.50.0 ship discovered (via Round 8 audit) that the SPEC 7 contract has implementation gaps when callers pass Generator-typed input. v0.51 fixes these: see migration/v0.51.md for the spawn_seed_sequences state-respecting fix (R8-C4b) and the _score_all_slices boundary-spawn refactor (R8-C4a).