# 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](https://scientific-python.org/specs/spec-0007/). 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 | None` → `rng: 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_state` → `LogisticStacker.rng` class-field rename (sklearn pass-through derives int at the boundary). ### Migration recipe **Before:** ```text bootstrap_ci(y, scores, pr_auc, seed=42) LogisticStacker(random_state=7) ``` **After:** ```text bootstrap_ci(y, scores, pr_auc, rng=42) LogisticStacker(rng=7) ``` Bit-for-bit reproducibility is preserved when migrating `seed=42` → `rng=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).