Skip to main content
KaireonAI ships two production-grade model-health surfaces:
  1. Fairness — five standard audit-recognized bias metrics evaluated over any slice of decision outcomes.
  2. Drift — Population Stability Index + two-sample Kolmogorov– Smirnov tests over feature distributions, with a multi-feature rollup verdict (none / monitor / alert).
Both are purpose-built for the EU AI Act Article 10 § 2(f) examination-for-biases requirement and for Reg B / ECOA disparate- impact demonstrations under the four-fifths rule (29 CFR § 1607.4D).

Fairness evaluation

POST /api/v1/fairness/evaluate

Two input modes: Inline — CI / regression workflows supply samples directly:
curl -X POST https://your-host/api/v1/fairness/evaluate \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $KAIREON_API_KEY" \
  -d '{
    "mode": "inline",
    "samples": [
      { "group": "A", "prediction": true,  "label": true  },
      { "group": "A", "prediction": false, "label": true  },
      { "group": "B", "prediction": true,  "label": false },
      ...
    ]
  }'
Trace-join — server pulls a decision-trace window and joins to a caller-supplied groupLookup map:
curl -X POST https://your-host/api/v1/fairness/evaluate \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $KAIREON_API_KEY" \
  -d '{
    "mode": "trace-join",
    "from": "2026-04-01T00:00:00Z",
    "to": "2026-04-22T00:00:00Z",
    "offerId": "off_premium_card",
    "groupLookup": {
      "cust_1": "female", "cust_2": "male", ...
    },
    "labelLookup": { "cust_1": true, ... }
  }'
Protected attributes live only in the request — this route never persists them beyond the audit log’s aggregate counts.

Response

{
  "sampleSize": 1000,
  "groups": [
    { "group": "female", "count": 520, "positiveDecisions": 180, "positiveRate": 0.346 },
    { "group": "male",   "count": 480, "positiveDecisions": 240, "positiveRate": 0.500 }
  ],
  "demographicParityGap": 0.154,
  "disparateImpactRatio": 0.692,
  "fourFifthsRuleViolated": true,
  "equalOpportunityGap": 0.08,
  "equalizedOddsGap": 0.12,
  "warnings": [
    "disparate impact ratio 0.692 is below 0.80 four-fifths-rule threshold (29 CFR § 1607.4D)"
  ]
}
Metrics explained:
  • demographicParityGapmax − min positive-decision rate.
  • disparateImpactRatiomin / max. Below 0.80 triggers the four-fifths-rule flag when every group has ≥ 30 samples.
  • equalOpportunityGap — TPR gap across groups (requires ground- truth label on each sample).
  • equalizedOddsGapmax(TPR gap, FPR gap).

Drift detection

POST /api/v1/models/:id/drift

Submit two feature-value snapshots (reference + current) and the endpoint returns PSI + KS per feature plus an aggregate severity:
curl -X POST https://your-host/api/v1/models/mdl_gbm/drift \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: $KAIREON_API_KEY" \
  -d '{
    "reference": {
      "recent_transaction_count": [ ... training-window values ... ],
      "tenure_months":            [ ... ]
    },
    "current": {
      "recent_transaction_count": [ ... last 24h values ... ],
      "tenure_months":            [ ... ]
    }
  }'
Response:
{
  "modelId": "mdl_gbm",
  "features": [
    {
      "feature": "recent_transaction_count",
      "psi": { "psi": 0.284, "severity": "alert", "bins": [...] },
      "ks":  { "d": 0.22, "pValue": 1e-5, "significant": true }
    }
  ],
  "overallSeverity": "alert",
  "alertFeatures": ["recent_transaction_count"]
}

PSI thresholds (Siddiqi 2005, Basel-recognized)

PSISeverityAction
< 0.1noneno action
0.1 – 0.25monitorwatch next week
≥ 0.25alertinvestigate / retrain

KS significance

Two-sided p-value via the Kolmogorov distribution Q(λ) with regime switching (alternating series for λ ≥ 0.3, Jacobi-theta alternative for smaller λ). significant: true when p < 0.05.

Overall severity

alert fires if any feature has PSI ≥ 0.25 OR a significant KS with D > 0.1. monitor fires if any feature crosses 0.1 PSI without alerting. Otherwise none.

Rate limits + audit

  • POST /fairness/evaluate — 20/min/tenant, audit-logged as action=fairness_evaluate.
  • POST /models/:id/drift — 30/min/tenant, audit-logged as action=drift_evaluate.
Both are tenant-scoped; cross-tenant lookup returns 404.