Alert governance (fighting fatigue)
SauBit emits deterministic clinical alerts (clinical_alerts) on top of drug-drug
interactions. In real settings, alert overload causes fatigue: clinicians start ignoring
warnings — including critical ones. Alert governance lets each organization tune what is
shown without ever changing the clinical truth.
Safety principles
- Suppression is presentation, not diagnosis. A suppressed alert still counts towards
the
prescription_risk_level. Governance never lowers prescription risk. - Critical risk cannot be hidden. Alerts at/above
confirm_min_severity(defaultCONTRAINDICADO) are always surfaced and flaggedrequires_confirmation: true— no policy lever can suppress them. - Every suppression is auditable. Each suppressed item carries the reason
(
suppression_reason) and, for known-alert overrides, the recorded justification.
Response fields
Each clinical_alerts item exposes:
| Field | Description |
|---|---|
id | Stable alert id (drug-order independent). Use it to suppress/justify known alerts. |
requires_confirmation | true when explicit confirmation is required before proceeding. |
And the response gains the alert_governance block:
"alert_governance": {
"applied": true,
"policy_enabled": true,
"view": "pharmacist",
"unit": "icu",
"min_severity": "MODERADO",
"confirm_min_severity": "CONTRAINDICADO",
"requires_confirmation": true,
"confirmation_required_ids": ["drug_allergy-1a2b3c4d5e"],
"total_alerts": 4,
"visible_count": 2,
"suppressed_count": 2,
"suppressed": [
{ "type": "food_alcohol", "severity": "LEVE", "id": "food_alcohol-9f8e7d6c5b", "suppression_reason": "below_min_severity", "justification": "" }
]
}
Suppression reasons:
| Reason | Meaning |
|---|---|
below_min_severity | Below the configured minimum severity. |
suppressed_type | Alert type suppressed by policy (global or per unit). |
policy_override | Known alert suppressed with a recorded justification. |
out_of_view | Outside the role view (e.g. drug_disease in the pharmacist view). |
Role views (physician × pharmacist)
Send the X-SauBit-Alert-View header (or ?alert_view=) with medico or farmaceutico:
curl -X POST https://api.saubit.com.br/api/v1/interactions/check \
-H "X-API-Key: sm_live_..." \
-H "X-SauBit-Alert-View: farmaceutico" \
-H "Content-Type: application/json" \
-d '{ "medications": [ { "name": "ibuprofeno" } ], "patient_record": { "conditions": ["insuficiência renal"] } }'
medico— sees every alert type.farmaceutico— sees operational/dispensing alerts (allergy, duplication, max dose, IV compatibility, drug × lab, renal/hepatic adjustment); diagnostic-reasoning alerts (e.g.drug_disease) leave the list without_of_view.
Critical alerts are always surfaced, regardless of the view.
Role security: when the API key has a bound role (set by the admin —
physician/pharmacist), it is authoritative and theX-SauBit-Alert-Viewheader is ignored (it cannot escalate privilege). The header applies only as a presentation hint when the key has no bound role. Suppression is display-only and never lowers risk — but the authentic role must come from identity, not a free header.
Hospital unit
The unit is inferred from patient_context.setting (e.g. "UTI", "Pediatria",
"Oncologia") and normalized to a tag (icu, pediatrics, oncology, emergency,
obstetrics). A policy can define per-unit rules.
Policy (per organization / API key)
The policy is a JSON object configured per organization (with per-API-key override). Fields:
| Field | Type | Effect |
|---|---|---|
enabled | bool | When false, becomes pass-through (keeps only critical confirmation). |
min_severity | LEVE·MODERADO·GRAVE·CONTRAINDICADO | Suppresses alerts below the threshold. |
confirm_min_severity | same | Severity at/above which confirmation is required (default CONTRAINDICADO). |
suppressed_types | list | Alert types always suppressed (e.g. ["food_alcohol"]). |
suppressed_signatures | list | Known-alert overrides: { "signature": "<id>", "justification": "...", "expires_at"?: "ISO 8601" }. With expires_at, the override expires and the alert resurfaces. |
unit_rules | object | Per-unit override: { "UTI": { "min_severity": "GRAVE" } }. |
role_types | object | Visible types per role: { "pharmacist": ["drug_allergy", "max_dose"] }. |
Example policy:
{
"enabled": true,
"min_severity": "MODERADO",
"confirm_min_severity": "CONTRAINDICADO",
"suppressed_types": ["food_alcohol"],
"unit_rules": {
"UTI": { "min_severity": "GRAVE" },
"Pediatria": { "suppressed_types": [] }
},
"suppressed_signatures": [
{ "signature": "duplicate_therapy-1a2b3c4d5e", "justification": "Approved institutional protocol" }
]
}
Configuration (admin routes)
The policy is configured through admin routes (admin JWT, under /api/v1/admin/*), with
the API key policy taking precedence over the organization policy. As admin routes,
they are documented in the Admin Swagger (/docs/admin), kept separate from the hospital
routes — including GET/PUT/DELETE …/organizations/{org_id}/alert-governance and
…/api-keys/{key_id}/alert-governance.
Invalid input (severity outside the set, unknown alert type, override without justification)
returns 422. Values are normalized (e.g. min_severity upper-cased, unit converted to a tag).
Propagation: API-key authentication is cached for ~60s; policy changes take effect within 60 seconds (a per-key override busts the cache immediately).
Metric: alerts that changed conduct
The headline governance KPI is not "how many alerts were generated" but how many changed the clinical decision. To measure it, the client records the decision taken on each surfaced alert.
Decision memory (the organization "teaches" the system without changing the clinical decision)
Every recorded decision feeds a per-organization memory:
- In
check, the same alert (sameidsignature) comes back withdecision_history— how many times it was acknowledged, overridden or modified, the override rate and the last justification. It shows local practice to the prescriber without lowering severity, suppressing anything or changing theprescription_risk_level. - In chat (
/chat/messagewithanalysis_id) and MCP, the history enters the context as a block explicitly labelled "institutional memory — not clinical evidence". - Governance suggestions: when an alert is repeatedly overridden for the same reason, the
platform produces suppression-by-signature suggestions for an admin to approve. Nothing
is applied automatically;
CONTRAINDICADOalerts are never candidates. Admin route (Admin Swagger):GET /admin/organizations/{org_id}/alert-governance/suggestions.
Why not "self-learning"? A decision-support system that changes its own behaviour based on overrides would learn to silence alerts (alert fatigue) and would no longer be a locked, auditable algorithm. Memory is context; the decision stays deterministic and versioned.