Skip to main content
Docs vCurrent•API —
Version: Current

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.

Copia um prompt pronto com fluxo de integração, payload e exemplos.

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 (default CONTRAINDICADO) are always surfaced and flagged requires_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:

FieldDescription
idStable alert id (drug-order independent). Use it to suppress/justify known alerts.
requires_confirmationtrue 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:

ReasonMeaning
below_min_severityBelow the configured minimum severity.
suppressed_typeAlert type suppressed by policy (global or per unit).
policy_overrideKnown alert suppressed with a recorded justification.
out_of_viewOutside 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 with out_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 the X-SauBit-Alert-View header 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:

FieldTypeEffect
enabledboolWhen false, becomes pass-through (keeps only critical confirmation).
min_severityLEVE·MODERADO·GRAVE·CONTRAINDICADOSuppresses alerts below the threshold.
confirm_min_severitysameSeverity at/above which confirmation is required (default CONTRAINDICADO).
suppressed_typeslistAlert types always suppressed (e.g. ["food_alcohol"]).
suppressed_signatureslistKnown-alert overrides: { "signature": "<id>", "justification": "...", "expires_at"?: "ISO 8601" }. With expires_at, the override expires and the alert resurfaces.
unit_rulesobjectPer-unit override: { "UTI": { "min_severity": "GRAVE" } }.
role_typesobjectVisible 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 (same id signature) comes back with decision_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 the prescription_risk_level.
  • In chat (/chat/message with analysis_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; CONTRAINDICADO alerts 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.

Self-feeding per organization​

Every informative decision (a justification, a modified prescription or a changed conduct) automatically feeds the organization itself — and only it:

  1. The organization's knowledge base (tenant RAG). The decision becomes a short document with no patient data (the justification is PII-redacted), indexed in the vector store exclusive to that organization — the same one its chat searches. Questions like "how do we usually handle NSAIDs in renal patients?" now retrieve the institution's own recorded decisions. Bare acknowledgements without justification are not indexed (noise).
  2. Conduct profile. An aggregated summary (volume, override rate, most-overridden alert types and typical justification) enters the context of every chat of the organization, labelled as institutional memory, not evidence.
  3. Versioned training datasets. With formal consent recorded, the platform generates immutable snapshots (anonymized JSONL, row count and SHA-256) — on demand and automatically every week — for offline tuning of the text models (summary and chat). Each tuning run can cite exactly the dataset it used (dossier traceability).

Hard limits: none of this reaches the deterministic engine; isolation is per organization; export/generation is disabled by default and requires per-organization consent. Admin routes (Admin Swagger): consent, generation, listing and download of snapshots.

Record a decision​

POST /api/v1/interactions/alerts/decision (API-key auth, scope interactions:check):

curl -X POST https://api.saubit.com.br/api/v1/interactions/alerts/decision \
-H "X-API-Key: sm_live_..." \
-H "Content-Type: application/json" \
-d '{
"analysis_id": "a1b2c3...",
"alert_id": "drug_disease-1a2b3c4d5e",
"decision": "modified",
"changed_conduct": true,
"justification": "Swapped for a pregnancy-safe alternative"
}'
FieldDescription
analysis_idId of the analysis (check/recheck) that produced the alert.
alert_idThe alert id from clinical_alerts.
decisionacknowledged (saw it, kept), overridden (overrode) or modified (changed conduct).
changed_conducttrue if the alert actually changed the prescription/conduct.
justificationRequired when decision = "overridden".

The server validates that the analysis belongs to the organization and backfills alert_type/severity from the stored analysis.

Query the metric​

The aggregated query (changed_conduct_rate = share of decisions where the alert changed conduct, plus by-type/severity breakdowns) is an admin route documented in the Admin Swagger (/docs/admin): GET …/organizations/{org_id}/alert-metrics. The recorded decisions also feed the admin Dashboard/ROI.