Breaking Changes
AssumptionError API Redesign
The AssumptionError / AssumptionException type has been redesigned across all 7 languages:
- Removed
functionName parameter from all factory methods. Violations are now identified solely by (id, subject) pairs, simplifying the error model.
- New
Domain assumption ID (priority 1, between Validity and Positivity). Used for parameter-level domain violations (e.g., misrate out of range, sample too small for requested precision).
- New
Misrate subject added alongside X and Y. Allows violations to report which specific parameter was invalid.
- Priority order changed: Validity (0) > Domain (1) > Positivity (2) > Sparity (3). Previously Positivity was 1, Sparity was 2.
Migration: Update any code that constructs or pattern-matches on AssumptionError factory methods (e.g., Validity(functionName, subject) becomes Validity(subject)).
Removed Deprecated Rng.UniformInt (C#)
The Rng.UniformInt(long, long) method deprecated in v6 has been removed. Use Rng.UniformInt64 instead.
Two-Sample Bounds: Min-Misrate Domain Guard
ShiftBounds and RatioBounds now reject misrate values below the minimum achievable misrate for the given sample sizes. Previously, impossible misrate values would silently produce degenerate bounds. This will surface as a Domain error for callers passing very small misrate with small samples.
RatioBounds: Domain Check Before Positivity
RatioBounds now checks the Domain assumption (misrate validity) before checking Positivity. This changes which error is reported first when both violations are present.
Go Number Constraint Expanded
The Number generic constraint now includes unsigned integer types (uint, uint8, ..., uint64). This is technically additive but may affect type inference in edge cases.
Test Data Overhaul
Cross-language reference test data has been substantially reorganized:
- Removed:
tests/assumptions/ directory and all assumption-specific test suites. Error cases are now co-located with each estimator's test data using expected_error fields.
- Regenerated:
shift-bounds/ and ratio-bounds/ test files with larger minimum sample sizes (5 instead of 1-3) and new error test cases.
- Renamed: Many test files to follow the new naming taxonomy (
natural-5-5 instead of natural-3-2, etc.).
New Features
CenterBounds Estimator
Exact distribution-free confidence bounds for the Hodges-Lehmann pseudomedian (Center). One-sample analog of ShiftBounds/RatioBounds, based on Wilcoxon signed-rank theory. Uses the FastCenterQuantiles algorithm to extract order statistics from the implicit pairwise average matrix without materializing all N(N+1)/2 pairs.
from pragmastat import center_bounds
bounds = center_bounds([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 0.05)
# Bounds(lower=3.5, upper=7.5)
Available in all 7 languages: CenterBounds (C#), center_bounds (Python/Rust/R), centerBounds (TypeScript/Kotlin/Go).
SignedRankMargin Function
Computes the critical margin for one-sample signed-rank bounds, analogous to PairwiseMargin for two-sample bounds. Uses exact Wilcoxon signed-rank distribution via dynamic programming for n <= 63 and Edgeworth approximation for larger n.
from pragmastat import signed_rank_margin
margin = signed_rank_margin(10, 0.05) # 18
Available in all 7 languages.
Rng.resample (Bootstrap Sampling)
New method for sampling with replacement (bootstrap resampling):
from pragmastat import Rng
rng = Rng("demo-resample")
rng.resample([1, 2, 3, 4, 5], 7) # [5, 1, 1, 3, 3, 4, 5]
Available in all 7 languages. Cross-language reproducibility verified via reference test data in tests/resample/.
GaussCdf Shared Module
Extracted standard normal CDF implementation (ACM Algorithm 209) into a shared internal module, replacing code previously inlined in PairwiseMargin. Now shared between PairwiseMargin and SignedRankMargin.
Bug Fixes
fast_spread bounds corruption under parallel load (Rust): Changed internal index types from usize to u32/u64 to prevent overflow with large inputs. Added bounds-checking guards and fixed accumulator types for count variables.
Multiplic quantile guards (C#): Removed overly aggressive epsilon guards (1e-9) in the quantile function. Now only returns boundary values at exact 0 and 1.
- Go
Median overflow: Now computes (float64(a) + float64(b)) / 2 instead of float64(a + b) / 2, preventing integer overflow with large values.
Infrastructure
Version Management
- Version is now managed via a single
VERSION file at the repository root, replacing the previous manual/version.typ approach.
- New
mise run version <ver> task propagates the version to all language manifests.
- New
mise run publish <ver> task bumps version, pushes, and triggers the publish workflow.
CI Improvements
- Added
ci-success gate job aggregating all language CI results for branch protection.
- Added
cs:check step to C# CI pipeline.
- Go CI now uses mise tasks (
go:check, go:test) instead of raw commands.
- Dev branch excluded from push-triggered CI.
Publish Workflow
- Publish is now triggered via
workflow_dispatch instead of tag push.
- Tags are created programmatically during the publish job.
- Version is read from
VERSION file instead of parsed from Typst source.
TypeScript: ESLint 8 to 9 Migration
Migrated from .eslintrc.js (legacy config) to eslint.config.js (flat config). ESLint upgraded from v8 to v9, @typescript-eslint packages upgraded from v6 to v8.
Tooling
- Replaced deprecated
serde_yaml with serde_yml in the tools crate.
- Removed deprecated
UniformInt methods from Rust RNG internals.
- Added
typst to mise-managed tools.
- Downgraded Java toolchain from Temurin 23 to Temurin 11 (Kotlin compatibility).
- Added
ts:restore as dependency for ts:build.
- Fixed
cs:clean to not run dotnet clean (which requires restore).
- Added
r:restore as dependency for r:check and r:ci.
Simulation Infrastructure
- New Rust simulation crate (
rs/pragmastat-sim): Parallel simulation runner with indicatif progress bars, supporting avg-drift, disp-drift, center-bounds, shift-bounds, and ratio-bounds simulations.
- C# simulation improvements: Split monolithic coverage simulation into 4 dedicated commands, migrated to
Rng-based sampling with string seeds for reproducibility, switched to Release builds, added AssumptionException recording in output, 10x default sample count.
- New mise tasks:
rs:sim, rs:sim:all, cs:sim:all.
Documentation
- New manual sections: one-sample bounds methodology,
CenterBounds toolkit reference, SignedRankMargin toolkit reference, resample toolkit reference.
- New algorithm documentation:
FastCenterQuantiles, FastSignedRankMargin.
- New study: bootstrap vs signed-rank approaches for center bounds.
- New study: median bounds efficiency analysis.
- Test suite documentation added for
center-bounds and signed-rank-margin.
- Comprehensive
tests/README.md documenting test file format, naming taxonomy, and tolerance values.
- Updated AGENTS.md API list to reflect new one-sample bounds and margin functions.
Test Data
New test suites:
tests/center-bounds/ (40 files): natural, symmetric, asymmetric, additive, uniform, edge cases, properties, error cases
tests/signed-rank-margin/ (40 files): exact, medium-n approximation, boundary, demo, error cases
tests/resample/ (16 files): cross-language bootstrap reproducibility
Removed:
tests/assumptions/ (4 files): assumption error tests moved inline to each estimator's test suite using expected_error fields
Regenerated with larger minimum sample sizes:
tests/shift-bounds/ and tests/ratio-bounds/: minimum sample size increased from 1-3 to 5, new error test cases for min-misrate domain guard
Full Changelog: https://github.com/AndreyAkinshin/pragmastat/compare/v6.0.1...v7.0.0