Run initial test for Climate Resilience Verification Suite
Add first part of Alert Quality Analytics
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
{
|
||||
"scenario": {
|
||||
"id": "ward-outage-reconnect-01",
|
||||
"name": "ICU Ward Isolation — Critical Potassium During Uplink Loss",
|
||||
"description": "Post-surgical ICU patient with stable vitals, then critical hyperkalemia during simulated central link loss. Nurse acknowledges on ward gateway. Reconnect syncs to central without duplicate pages.",
|
||||
"durationMinutes": 90,
|
||||
"tags": ["climate-resilience", "gateway", "critical-value", "sync", "potassium"]
|
||||
},
|
||||
"patient": {
|
||||
"firstName": "James",
|
||||
"lastName": "Wu",
|
||||
"dateOfBirth": "1968-11-02",
|
||||
"gender": "Male"
|
||||
},
|
||||
"encounter": {
|
||||
"department": "Icu",
|
||||
"encounterType": "Inpatient",
|
||||
"attendingPhysician": "Dr. Elena Park",
|
||||
"roomBed": "ICU-3B-12",
|
||||
"admissionReason": "Post-op monitoring — abdominal surgery"
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"offsetMinutes": 0,
|
||||
"type": "observation",
|
||||
"data": { "code": "HEART_RATE", "value": 82, "unit": "bpm", "source": "Device" },
|
||||
"note": "Baseline vitals — stable post-op ICU admission"
|
||||
},
|
||||
{
|
||||
"offsetMinutes": 0,
|
||||
"type": "observation",
|
||||
"data": { "code": "TEMP_C", "value": 36.8, "unit": "°C", "source": "Manual" }
|
||||
},
|
||||
{
|
||||
"offsetMinutes": 0,
|
||||
"type": "observation",
|
||||
"data": { "code": "SPO2", "value": 98, "unit": "%", "source": "Device" }
|
||||
},
|
||||
{
|
||||
"offsetMinutes": 0,
|
||||
"type": "observation",
|
||||
"data": { "code": "POTASSIUM_MEQ_L", "value": 4.2, "unit": "mEq/L", "source": "Lab" }
|
||||
},
|
||||
{
|
||||
"offsetMinutes": 45,
|
||||
"type": "observation",
|
||||
"data": { "code": "POTASSIUM_MEQ_L", "value": 6.8, "unit": "mEq/L", "source": "Lab" },
|
||||
"note": "Critical hyperkalemia — must alert locally even if central is down"
|
||||
},
|
||||
{
|
||||
"offsetMinutes": 50,
|
||||
"type": "alert_ack",
|
||||
"data": {
|
||||
"alertType": "CRITICAL_POTASSIUM_MEQ_L",
|
||||
"clinicianId": "RN-Wu",
|
||||
"note": "Calcium gluconate ordered, ECG at bedside"
|
||||
}
|
||||
},
|
||||
{
|
||||
"offsetMinutes": 60,
|
||||
"type": "observation",
|
||||
"data": { "code": "HEART_RATE", "value": 78, "unit": "bpm", "source": "Device" }
|
||||
},
|
||||
{
|
||||
"offsetMinutes": 75,
|
||||
"type": "observation",
|
||||
"data": { "code": "POTASSIUM_MEQ_L", "value": 5.4, "unit": "mEq/L", "source": "Lab" },
|
||||
"note": "Repeat lab — improving after treatment"
|
||||
}
|
||||
],
|
||||
"expectedOutcomes": [
|
||||
{
|
||||
"afterOffsetMinutes": 45,
|
||||
"type": "alert",
|
||||
"alertType": "CRITICAL_POTASSIUM_MEQ_L",
|
||||
"description": "Critical potassium alert fires at K+ 6.8 mEq/L — locally on gateway during outage"
|
||||
},
|
||||
{
|
||||
"afterOffsetMinutes": 50,
|
||||
"type": "alert",
|
||||
"alertType": "CRITICAL_POTASSIUM_MEQ_L",
|
||||
"description": "Alert acknowledged by RN-Wu — buffered for sync to central"
|
||||
},
|
||||
{
|
||||
"afterOffsetMinutes": 75,
|
||||
"type": "score",
|
||||
"scoreType": "NEWS2",
|
||||
"expectedMinimum": 0,
|
||||
"description": "NEWS2 unavailable on gateway during outage — replays on central after sync (Tier 3 deferred)"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -29,7 +29,7 @@ public static class ScenarioValidator
|
||||
|
||||
private static readonly HashSet<string> ValidEventTypes = new()
|
||||
{
|
||||
"observation", "order", "medication", "order_result"
|
||||
"observation", "order", "medication", "order_result", "alert_ack"
|
||||
};
|
||||
|
||||
private static readonly HashSet<string> ValidOrderTypes = new()
|
||||
@@ -131,6 +131,19 @@ public static class ScenarioValidator
|
||||
"(sepsis bundle orders are auto-created when SOFA_SEPSIS or QSOFA_SCREEN fires)");
|
||||
}
|
||||
}
|
||||
|
||||
if (evt.Type == "alert_ack")
|
||||
{
|
||||
var alertType = evt.Data.TryGetProperty("alertType", out var alertTypeProp)
|
||||
? alertTypeProp.GetString() : null;
|
||||
if (string.IsNullOrWhiteSpace(alertType))
|
||||
errors.Add($"events[{i}]: alert_ack.alertType is required");
|
||||
|
||||
var clinicianId = evt.Data.TryGetProperty("clinicianId", out var clinicianProp)
|
||||
? clinicianProp.GetString() : null;
|
||||
if (string.IsNullOrWhiteSpace(clinicianId))
|
||||
errors.Add($"events[{i}]: alert_ack.clinicianId is required");
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
"required": ["offsetMinutes", "type", "data"],
|
||||
"properties": {
|
||||
"offsetMinutes": { "type": "number", "minimum": 0 },
|
||||
"type": { "type": "string", "enum": ["observation", "order", "medication", "order_result"] },
|
||||
"type": { "type": "string", "enum": ["observation", "order", "order_result", "medication", "alert_ack"] },
|
||||
"data": { "type": "object" },
|
||||
"note": { "type": "string" }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user