Learn · Changelog
Development Changelog
Development history for vfairness. Version 0.1.0 is the first public beta, published 2026-10-02 from the v0.1.0 tag. The gate that decided whether it could be pushed passed: scripts/release_gate.py reports BETA READY, with all eight beta conditions met. The API is not frozen until the stable 1.0.0. We follow Keep a Changelog and Semantic Versioning conventions.
vfairness 0.1.0 is the first public beta, published 2026-10-02. Install it with pip install vfairness on Python 3.11 or newer; the early 0.0.1 placeholder that held this name before the release has been yanked. The API is not frozen until the stable 1.0.0 release. We welcome feedback and contributions via GitHub.
“Beta” here is the version number, not a verdict that the library is ready to rely on. Run again on 2026-10-01, scripts/release_gate.py reports BETA READY: all eight beta conditions are met and no known defect is open, while the full 1.0 gate still waits for a second examiner on part of the graded code. The earlier measurement is kept below as it was taken. Run on 2026-09-18, scripts/release_gate.py reports NOT BETA READY and NOT READY, four of five criteria failing in each. Two separate measurements sit behind that and are never added together: the 215-row capability census carries 0 open defects, and of the 420 code units graded so far on the wider surface, 95 are DEFECT OPEN. The standing figures and the criteria are on Quality & Hardening, and the release pipeline page records where the gate stands.
Roadmap to 1.0.0
The following features are planned for the stable 1.0.0 release:
Stable API
Finalized, documented API with backward compatibility guarantees.
Complete Test Coverage
Comprehensive unit and integration tests with >90% coverage. Measured at 81% line and branch combined as of 2026-09-11, commit 8559dda; the CI floor is 55% and the per-pull-request diff floor is 80%.
Production Documentation
Full API reference, tutorials, and deployment guides.
PyPI Publication
Done for the beta: 0.1.0 was published to PyPI on 2026-10-02. 1.0.0 will be the first stable release under the backwards-compatibility contract.
Unreleased
on main
Hide
Unreleased
on mainFixed4
run_pulse
ciMethod
ciLevel
ciNotComputedReason
build_assurance_verdict
pValueSelection
selectionComparisons
pipeline._intersectional_grid
v0.1.0
2026-10-02
Hide
v0.1.0
2026-10-02The most recent entries under ## [0.1.0] - 2026-10-02 in CHANGELOG.md, summarised (updated 1 Oct 2026; the file has every change in full). Within each group below, the newest entries come first.
Added8
headline_excluded_groups
n_rows_missing_prediction
uncovered_groups
groups_without_measured_calibration
prediction_fn_available
finite_or_nan
MetricsStore.window_now
BoundRole
set_branding() and branding_enabled() remove the validant.ai mark from generated SVGs and reports, honouring an explicit call, then the VFAIRNESS_BRANDING environment variable, then a branded default. A single chart can opt out with render_svg(name, {"branding": False}). An unbranded chart contains no occurrence of the brand string at all, and the switch is unconditional by design: nothing verifies a licence or calls home.set_branding
branding_enabled
vfairness.net)validate_endpoint resolves and vets the target, guarded_post is a drop-in for requests.post, PinnedIPAdapter pins the vetted IP against DNS rebinding, and a refusal raises SSRFError. Wired into the LLM api_proxy, so assessment traffic cannot be pointed at loopback, private, link-local or cloud-metadata targets. A local model server needs the explicit allow_loopback=True opt-in, which unlocks loopback only.vfairness.net
validate_endpoint
guarded_post
PinnedIPAdapter
SSRFError
vfairness.validity)VG_* metric identifiers (faithfulness, groundedness, hallucination rate, citation accuracy, context precision and recall, answer correctness), a GroundednessScorer, a fail-closed judge ladder (GroundednessJudge / LlmGroundednessJudge) and aggregate_validity. Deliberately not registered in the capability manifest yet, so nothing can be sealed on it before its gold set lands.vfairness.validity
GroundednessScorer
aggregate_validity
*_with_ci variants cover disparate impact, FPR parity, negative predictive value, conditional demographic disparity, pricing disparity, the integrated calibration index and multicalibration. Custom-shape statistics get an interval from a new bootstrap_over_index helper that resamples row indices stratified by group. The interval width feeds the three-state verdict.bootstrap_over_index
disparate_impact_ratio_with_ci
multicalibration_with_ci
disparate_impact_ratio (the four-fifths selection-rate ratio), conditional_demographic_disparity (the CJEU objective-justification mirror), negative_predictive_value_difference, auroc_parity (a validity gate against levelling-down), grid-free integrated_calibration_index and multicalibration, the TRIPOD recalibration diagnostics calibration_in_the_large and calibration_slope, plus pricing_disparity, net_benefit_parity and conditional_adverse_impact. The error-rate metrics the catalogue referenced but the engine lacked (fpr_parity_difference, fnr_parity_difference, accuracy_parity_difference, worst_group_accuracy) also landed, closing the overclaims found in the knowledge-graph spine audit.ruff check src tests and mypy src are both blocking on every library change, with the toolchain declared in the dev extra so CI, pre-commit and local runs agree. The type burndown reached zero errors and surfaced three real bugs (a dead subgroup-robustness audit in Pulse, a crash on list-valued sample_weight in FairRegressor.fit, and a no-op correlation proxy detector). Also added: mutation testing on the band logic, new property-based / determinism / deserialization-safety / reference-parity suites, an sdist allowlist, beta-programme materials, and the supply-chain governance files.Changed4
scripts/release_gate.py reports BETA READY: all eight beta conditions met, including two new ones anyone can re-run. Every capability that an established library also computes gives the same answer (34 of 34), and no capability that measures invents a number on broken data (109 of 109). Second-examiner confirmation of every grade is now a condition of 1.0, not of the beta.release_gate.py
B6
B7
FeasibleThresholds is a dict, the proxy results are lists); some can now return None, meaning could not check, so test them with is None; some now raise instead of returning a misleading value. The full list is in CHANGELOG.md.find_feasible_thresholds
identify_proxy_variables
find_proxy_chains
is_satisfied
require_checked
to_json
NOTICE file alongside the LICENSE.requires-python is now >=3.11, following Scientific Python SPEC 0.Fixed7
subgroup_robustness_audit
RAGBiasAnalyzer.full_analysis
AnchorsExplainer
EmergentBiasDetector
TextFairnessAnalyzer
intersectional_disparity_analysis
True and a measured-looking bar for NaN, regularisers that accepted a negative strength, and a task envelope that read "false" as success.prepare_protected_attributes
BaseRegularizer
TaskResult.from_envelope
compute_regression_effect_sizes
cohens_d
permutation_test_equal_opportunity
MetricsStore.compute_health_score
MetricsStore.ingest_alert
ModelFairnessGate
DecodingTrustRunner
FairnessDashboard
predictive_parity_difference, fpr_parity_difference, fnr_parity_difference and equalized_odds_difference collapsed a NaN per-group rate (a group with no positive predictions, no negatives, or no positives) into a 0.0 “perfect parity” result, which read as PASS with a deceptively tight [0.0, 0.0] bootstrap CI. They now return NaN so the verdict routes to insufficient_evidence, mirroring the earlier NPV fix.multicalibration, negative_predictive_value_difference, auroc_parity and conditional_demographic_disparity now return NaN when there is no evidence, and the last of those renormalises its stratum weights instead of biasing toward “fair” in proportion to the un-assessable population.MetricResult gains a three-state verdict (fair / unfair / insufficient_evidence), and is_fair becomes an alias for verdict == 'fair'. A wide small-sample interval is no longer reported as a pass or a fail. predictive_parity_difference_with_ci closes the last sufficiency metric that shipped as a bare point estimate.Security2
trust_input / VFAIRNESS_TRUST_MODEL_INPUT), closing a remote-code-execution vector. An AST guard test also stops the metric core from swallowing computation errors silently.load_dataframe tool rejects remote data_path URLs, so an agent-supplied path cannot become network egress; the Pulse artifact download pins the scheme to https and caps the response size; and the deserialization-safety scan now resolves aliased imports and covers marshal, pandas.read_pickle, jsonpickle and shelve.
v0.0.9
August 2026
Show
v0.0.9
August 2026Added5
render_svg choke point (so every adapter and .to_svg() inherits it): an auto-generated on-canvas explanation (concept → how to read it → the finding on this chart → recommended action) plus an accessible, machine-readable layer (role="img", <title>, a one-line <desc>, and a <metadata> JSON block). Severity is derived from the same data the badge uses, so the explanation can never contradict the badge. Curated content covers every template.vfairness.rendering.explain
CHART_META
render_svg applies Blanco (“The Silent Gallery”) by default: a single post-render transform giving sharp corners, editorial type (Plus Jakarta Sans / JetBrains Mono), desaturated graphite chrome, and colour reserved for the four semantic tones. It never touches the templates or adapters themselves.apply_skin
list_skins
SKINS
FairnessAnalyzer report, so a numeric regression fails loudly instead of drifting silently.tests/test_golden_metrics.py
render_svg for every registered SVG template and asserts well-formed XML with no unrendered Jinja tokens.tests/test_rendering.py
TaskResult dataclass formalises the task-handler result envelope (schema_version, task_type, success, data/error, optional warnings) with a backward-compatible to_dict(). Coverage is now measured in CI (--cov=vfairness) behind a ratcheting --cov-fail-under gate.vfairness.result.TaskResult
Changed3
-m fairness marker matched zero tests (so CI silently ran nothing); the filter was removed from both GitHub and GitLab pipelines, and both now install the extras the suite exercises.TaskResult.to_dict(). The success/data/error semantics are unchanged; the envelope gains additive schema_version and task_type keys.Fixed7
y_true) is now surfaced in assessment.not_assessable_metrics and excluded from the fairness score, instead of being mis-scored as a FAIL. The classification report gains a not_assessable_metrics field.fisher_exact_test uses the real exact test (no silent chi-square degrade); Bayesian credible intervals delegate to scipy (the homegrown Beta PPF had collapsed “95%” intervals to ~55% coverage); Wilson score intervals replace NaN bounds for large groups; multiple-testing correction runs real two-proportion z-tests instead of inverted pseudo p-values.NOT ASSESSABLE instead of certifying fairness_score 1.0; critical findings floor the overall risk band (1+ → MEDIUM, 3+ → HIGH) so three critical issues can no longer average out to a green badge; constant-probability ECE/MCE report the true error instead of a “perfect” 0.0.vfairness._bands module drives every severity/threshold decision, so the badge, radar chart, detailed report and explanation text can no longer give contradictory verdicts for the same input; the divergent 0.2/0.4/0.6/0.8 risk scale was eliminated everywhere; NaN scores render a neutral N/A badge rather than a green MINIMAL.BetaCalibrator is now real Kull et al. 2017 beta calibration; GridSearch predicts with the classifier it reports; FairRegressor raises instead of silently fitting an unconstrained model for unsupported objectives; the adversarial debiasing loss trains its adversary in the correct direction; the outcome column is no longer scanned as its own proxy.DeepExplainer had made every deep job fail); SHAP attributions, base value and prediction now come from one class; causal identification and refuter-crash disclosure fixed; monitoring/drift windows and health-score trends corrected.requirements.txt now includes the hard runtime deps requests and scikit-learn (a minimal install previously could not even import vfairness); the mcp extra is gated to Python ≥ 3.10 so the project locks again; frozen-surface exports (calibration_difference, r2_parity_difference, residual_bias) restored; ~800 new regression tests across tests/test_audit_wave1–5 pin every fix. Documentation examples corrected against the real APIs.
v0.0.8
March 2026
Show
v0.0.8
March 2026Added22
repair_level (0 = no change, 1 = full repair) with a tie-robust empirical-CDF mapping. Registered under dispatch key disparate_impact_removal and wired into the platform's pre-processing step (with a configurable repair-strength control).DisparateImpactRemover
disparate_impact_removal
get_massaged_labels() hook and a max_flip_fraction safety cap. Wired into the platform's pre-processing step.LabelMassager
label_massaging
get_resampled_data() hook with configurable strategy and balance_by. The platform rebalances the training split only, leaving the held-out test split intact for honest evaluation.Resampler
resampling
BCE + λ · GroupFairnessRegularizer. The fairness metric (demographic parity, equalized odds, equal opportunity, or FPR parity) is selected from the chosen fairness definition, and the penalty strength gives continuous control over the accuracy-fairness trade-off. Registered under dispatch key fairness_regularization; falls back to reweighting if torch is unavailable.GroupFairnessRegularizer
fairness_regularization
transform returns the latent columns (rep_0..). Tunable representation_dim and lambda_fairness; multiple attributes handled via their intersection. Registered as fair_representation and wired into the pre-processing step + Pareto sweep. Requires torch.FairRepresentationTransformer
fair_representation
DisparateImpactRemover, LabelMassager, Resampler, FairRepresentationTransformer and the fairness-regularization training loop now operate on the intersection of all protected attributes rather than only the first (e.g. they repair / rebalance / penalize race x gender jointly); (2) the regularizer accepts secondary fairness constraints (penalized jointly); (3) a degenerate-collapse guard detects and softens penalties that drive the model to a single class; (4) a training-row cap keeps the torch sweep responsive on large datasets; (5) pre-processing techniques (Disparate Impact Removal, Label Massaging, Resampling, Fair Representation) gained Pareto strength sweeps; and (6) results surface proxy-survival notes and small-sample / confidence warnings so a near-unchanged metric is explained rather than mistaken for a no-op.get_massaged_labels
get_resampled_data
secondary_constraints
attribute_historical_pattern(attribute, domain) helper resolves 24 documented (attribute class × regulated domain) precedents -- race / gender / age / national-origin / religion / disability / geographic proxy across hiring, lending, healthcare, justice, insurance and education. Pulse attaches the citation-backed envelope onto bias findings so the “Historical pattern” channel keys off a structured flag instead of regex-matching evidence text.attribute_historical_pattern
CRITICAL
HIGH
MEDIUM
_statistics.pybootstrap_ci
stratified_bootstrap_ci
bayesian_proportion_ci
bayesian_difference_ci
compute_metric_with_ci
proportion_z_test
fisher_exact_test
cohens_h
minimum_detectable_effect
power_warning
intersectional_disparity.svg) with ground truth overlay, severity-colored bars, prediction delta indicators, most/least advantaged comparison cards, and insight cards. 44th SVG template in the rendering module.intersectional_disparity_to_svg()
identify_privileged_groups() and intersectional_disparity_analysis() now compute ground truth rates, false positive rates, and prediction deltas per subgroup. New outcome_polarity parameter supports both favorable (loan approval) and unfavorable (recidivism) outcome directions.ground_truth_rate
false_positive_rate
prediction_delta
outcome_polarity
Fixed2
data_validation_to_svg() now safely handles nested dicts and lists, truncates overly long string representations, and only includes scalar values in metric cards. Previously, raw Python repr output (e.g., {'count': 5}) could appear in the SVG text.outcome_polarity='positive_unfavorable'. Previously, the ratio calculation was inverted for unfavorable outcomes, making insights misleading.
v0.0.7
February 2026
Show
v0.0.7
February 2026Added18
vfairness.operations.reportingMetricsStore
FairnessDashboard
ReportGenerator
InteractiveDashboard
vfairness.operations.experimentationFairnessExperiment
FairnessPowerAnalyzer
ExperimentAnalysis
FairnessDriftDetector
AdaptiveThresholdManager
FairnessAlertPrioritizer
monitoring_dashboard
drift_report
alert_timeline
temporal_analysis
vfairness.operations.cicdHierarchicalGateConfig
FairnessReportCard
SmallSampleWarning
log_fairness_to_wandb()@auto_log_fairnessvfairness-check-config
vfairness-check-model-card
pytest11 entry point with marker, fixture, and terminal summary.@pytest.mark.fairness
fairness_gate
fairness-checks.yml
workflow_overview
hierarchical_gate
report_card
reporting_units_3.ipynb
experimentation_unit_4.ipynb
vfairness_8_workflow_integration.ipynb
correlation_matrix
causal_decomposition
robustness_testing
ranking_fairness
data_validation
auto_discovery
regression_fairness
reporting_dashboard
adapters_robustness.py
adapters_ranking.py
adapters_validation.py
adapters_discovery.py
adapters_regression.py
adapters_reporting.py
Changed7
sys.modules aliasing.pyproject.tomldata/library-stats.json at page load rather than typed in, so read them there rather than here.)Fixed3
correlation_heatmap and correlation_matrix templates were painted over by grid cells. Fixed text-anchor from end to start, increased font size to 12px, and added 100px panel headroom.dot_x computation around the axis position and added smart label placement for negative values.
Major feature and documentation release. New modules require optional dependencies: pip install vfairness[reporting], pip install vfairness[experimentation], or pip install vfairness[mlops].
v0.0.5-dev
February 2026
Show
v0.0.5-dev
February 2026Added10
ThresholdOptimizer
GroupThresholdOptimizer
PredictionReweighter
RejectionOptionClassifier
CalibratedEqualizer
DataBiasValidator
ModelFairnessGate
BiasMonitor
DriftAlert
FairnessConstraintType
FairnessTestSuite
@fairness_test
vfairness.rendering
Changed4
evaluation.integrations to dedicated operations.cicd module.
v0.0.3-dev
January – February 2026
Show
v0.0.3-dev
January – February 2026Added14
FairExplAIner
GroupCalibrator
IntersectionalCalibrator
CalibrationAnalyzer
vfairness.preprocessing.feature_engineering
FeatureEngineeringAnalyzer
vfairness.in_processing
ExponentiatedGradient
FairClassifier
TemperatureScaling
PlattScaling
TrainableGroupCalibrator
classification_fairness_report()
FairnessTrainingAnalyzer
FairClassifier
FairRegressor
Changed5
Performance3
Fixed3
vfairness is no longer detection-only. With in-processing and post-processing modules, it now covers the full ML fairness pipeline.
v0.0.1-alpha
December 2025
Show
v0.0.1-alpha
December 2025Added16
FairnessAnalyzer
BiasDetector
log_fairness_to_mlflow()
Fixed3
First public development release. Not recommended for production use. Install from source or GitHub.
What's Next
Some of the most interesting parts of vfairness are already in the code and maturing toward a full documentation page and a frozen API; others are planned. Here is where the work is heading.
In progress (already in the code)
- Explainability & XAI: the SHAP family, the Lundberg fairness decomposition and DiCE counterfactuals (shipping in the code today; full documentation page landing this release)
- Validity / groundedness axis: the VG-* metric family with a fail-closed LLM judge (interim, live)
- Vision representation fairness: Skew / NDKL / bias-amplification math shipped, plus an optional FairFace demographic sidecar
- Causal fairness graphs and fairness-aware model selection
Planned
- A per-symbol API reference for every top-level export
- An owned groundedness detector to succeed the interim LLM judge
- Continuous monitoring dashboard
- Enterprise compliance reports
Found a bug or have a feature request? Please open an issue on GitHub. We welcome contributions from the community.