diff --git a/.claude/settings.json b/.claude/settings.json index 29ad246..7c86c5c 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -1,7 +1,8 @@ { "permissions": { "allow": [ - "Bash(dotnet test *)" + "Bash(dotnet test *)", + "Bash(dotnet build *)" ] } } diff --git a/VigilCare.Simulator/Client/Models/AlertResponse.cs b/VigilCare.Simulator/Client/Models/AlertResponse.cs new file mode 100644 index 0000000..ab76b2e --- /dev/null +++ b/VigilCare.Simulator/Client/Models/AlertResponse.cs @@ -0,0 +1,3 @@ +public record AlertResponse( + Guid Id, string AlertType, string Severity, string Status, + string Details, DateTimeOffset TriggeredAt); \ No newline at end of file diff --git a/VigilCare.Simulator/Client/Models/ApiResponse.cs b/VigilCare.Simulator/Client/Models/ApiResponse.cs new file mode 100644 index 0000000..9a32e89 --- /dev/null +++ b/VigilCare.Simulator/Client/Models/ApiResponse.cs @@ -0,0 +1,2 @@ +public record ApiResponse(bool Success, T Data, string? Error); +public record PagedResponse(List Items, int TotalCount, int Page, int PageSize); \ No newline at end of file diff --git a/VigilCare.Simulator/Client/Models/BatchIngestRequest.cs b/VigilCare.Simulator/Client/Models/BatchIngestRequest.cs new file mode 100644 index 0000000..820f3cd --- /dev/null +++ b/VigilCare.Simulator/Client/Models/BatchIngestRequest.cs @@ -0,0 +1 @@ +public record BatchIngestRequest(List Observations); \ No newline at end of file diff --git a/VigilCare.Simulator/Client/Models/CreateMedicationAdministrationRequest.cs b/VigilCare.Simulator/Client/Models/CreateMedicationAdministrationRequest.cs new file mode 100644 index 0000000..61cf9c8 --- /dev/null +++ b/VigilCare.Simulator/Client/Models/CreateMedicationAdministrationRequest.cs @@ -0,0 +1,3 @@ +public record CreateMedicationAdministrationRequest( + string DrugName, decimal Dose, string DoseUnit, string Route, + DateTimeOffset? AdministeredAt, string AdministeredBy); diff --git a/VigilCare.Simulator/Client/Models/CreateOrderRequest.cs b/VigilCare.Simulator/Client/Models/CreateOrderRequest.cs new file mode 100644 index 0000000..d924347 --- /dev/null +++ b/VigilCare.Simulator/Client/Models/CreateOrderRequest.cs @@ -0,0 +1 @@ +public record CreateOrderRequest(string OrderType, string Description, string OrderedBy); diff --git a/VigilCare.Simulator/Client/Models/EncounterResponse.cs b/VigilCare.Simulator/Client/Models/EncounterResponse.cs new file mode 100644 index 0000000..e82d521 --- /dev/null +++ b/VigilCare.Simulator/Client/Models/EncounterResponse.cs @@ -0,0 +1,4 @@ +public record EncounterResponse( + Guid Id, Guid PatientId, string EncounterType, string Status, + string Department, string AttendingPhysician, string? RoomBed, + string? AdmissionReason, DateTimeOffset AdmittedAt); \ No newline at end of file diff --git a/VigilCare.Simulator/Client/Models/IngestObservationRequest.cs b/VigilCare.Simulator/Client/Models/IngestObservationRequest.cs new file mode 100644 index 0000000..a0c27e0 --- /dev/null +++ b/VigilCare.Simulator/Client/Models/IngestObservationRequest.cs @@ -0,0 +1,5 @@ + +public record IngestObservationRequest( + string ObservationCode, decimal Value, string Unit, + string Source, DateTimeOffset RecordedAt, string? IdempotencyKey); + diff --git a/VigilCare.Simulator/Client/Models/News2Response.cs b/VigilCare.Simulator/Client/Models/News2Response.cs new file mode 100644 index 0000000..d61542f --- /dev/null +++ b/VigilCare.Simulator/Client/Models/News2Response.cs @@ -0,0 +1,5 @@ +public record News2Response( + Guid Id, int TotalScore, string RiskLevel, bool HasSingleParamThree, + int RespRateScore, int Spo2Score, int SystolicBpScore, + int HeartRateScore, int ConsciousnessScore, int TemperatureScore, + int SupplementalO2Score, DateTimeOffset CalculatedAt); \ No newline at end of file diff --git a/VigilCare.Simulator/Client/Models/OpenEncounterRequest.cs b/VigilCare.Simulator/Client/Models/OpenEncounterRequest.cs new file mode 100644 index 0000000..812dbe6 --- /dev/null +++ b/VigilCare.Simulator/Client/Models/OpenEncounterRequest.cs @@ -0,0 +1,4 @@ + +public record OpenEncounterRequest( + string EncounterType, string Department, string AttendingPhysician, + string? RoomBed = null, string? AdmissionReason = null); \ No newline at end of file diff --git a/VigilCare.Simulator/Client/Models/OrderResponse.cs b/VigilCare.Simulator/Client/Models/OrderResponse.cs new file mode 100644 index 0000000..91a8fdf --- /dev/null +++ b/VigilCare.Simulator/Client/Models/OrderResponse.cs @@ -0,0 +1 @@ +public record OrderResponse(Guid Id, string Description, string Status); diff --git a/VigilCare.Simulator/Client/Models/PatientResponse.cs b/VigilCare.Simulator/Client/Models/PatientResponse.cs new file mode 100644 index 0000000..4876a24 --- /dev/null +++ b/VigilCare.Simulator/Client/Models/PatientResponse.cs @@ -0,0 +1,3 @@ +public record PatientResponse( + Guid Id, string Mrn, string FirstName, string LastName, + DateOnly DateOfBirth, string Gender, string Status, DateTimeOffset CreatedAt); diff --git a/VigilCare.Simulator/Client/Models/RecordOrderResultRequest.cs b/VigilCare.Simulator/Client/Models/RecordOrderResultRequest.cs new file mode 100644 index 0000000..9a4452d --- /dev/null +++ b/VigilCare.Simulator/Client/Models/RecordOrderResultRequest.cs @@ -0,0 +1 @@ +public record RecordOrderResultRequest(string? ResultSummary); \ No newline at end of file diff --git a/VigilCare.Simulator/Client/Models/RegisterPatientRequest.cs b/VigilCare.Simulator/Client/Models/RegisterPatientRequest.cs new file mode 100644 index 0000000..e9fe4f2 --- /dev/null +++ b/VigilCare.Simulator/Client/Models/RegisterPatientRequest.cs @@ -0,0 +1,2 @@ +public record RegisterPatientRequest( + string FirstName, string LastName, DateOnly DateOfBirth, string Gender); diff --git a/VigilCare.Simulator/Client/Models/SepsisBundleResponse.cs b/VigilCare.Simulator/Client/Models/SepsisBundleResponse.cs new file mode 100644 index 0000000..dc7d5e8 --- /dev/null +++ b/VigilCare.Simulator/Client/Models/SepsisBundleResponse.cs @@ -0,0 +1,11 @@ +public record SepsisBundleElementResponse(string Status); + +public record SepsisBundleResponse( + Guid Id, string TriggeringAlertType, string ComplianceStatus, + DateTimeOffset RecognizedAt, DateTimeOffset DeadlineAt, + DateTimeOffset? CompletedAt, + List? Elements = null) +{ + public int ElementsCompleted => + Elements?.Count(e => e.Status == "Completed") ?? 0; +} diff --git a/VigilCare.Simulator/Client/VigilCareApiClient.cs b/VigilCare.Simulator/Client/VigilCareApiClient.cs new file mode 100644 index 0000000..02f6519 --- /dev/null +++ b/VigilCare.Simulator/Client/VigilCareApiClient.cs @@ -0,0 +1,122 @@ +using System.Net.Http.Json; + +public class VigilCareApiClient +{ + private readonly HttpClient _http; + + public VigilCareApiClient(HttpClient http) + { + _http = http; + } + + public async Task RegisterPatientAsync(RegisterPatientRequest req) + { + var response = await _http.PostAsJsonAsync("/api/v1/patients", req); + response.EnsureSuccessStatusCode(); + var envelope = await response.Content.ReadFromJsonAsync>(); + return envelope!.Data; + } + + public async Task OpenEncounterAsync(Guid patientId, OpenEncounterRequest req) + { + var response = await _http.PostAsJsonAsync($"/api/v1/patients/{patientId}/encounters", req); + response.EnsureSuccessStatusCode(); + var envelope = await response.Content.ReadFromJsonAsync>(); + return envelope!.Data; + } + + public async Task SendObservationBatchAsync( + Guid encounterId, List observations) + { + foreach (var chunk in observations.Chunk(10)) + { + var batch = new BatchIngestRequest(chunk.ToList()); + var response = await _http.PostAsJsonAsync( + $"/api/v1/encounters/{encounterId}/observations", batch); + if (!response.IsSuccessStatusCode) + { + var body = await response.Content.ReadAsStringAsync(); + throw new HttpRequestException( + $"Observation batch failed ({(int)response.StatusCode} {response.StatusCode}): {body}"); + } + } + } + + public async Task TrySendMedicationAsync( + Guid encounterId, CreateMedicationAdministrationRequest req) + { + var response = await _http.PostAsJsonAsync( + $"/api/v1/encounters/{encounterId}/medications", req); + if (response.StatusCode == System.Net.HttpStatusCode.NotFound) + return false; + response.EnsureSuccessStatusCode(); + return true; + } + + public async Task TryCreateOrderAsync( + Guid encounterId, CreateOrderRequest req) + { + var response = await _http.PostAsJsonAsync( + $"/api/v1/encounters/{encounterId}/orders", req); + return response.IsSuccessStatusCode; + } + + public async Task TryResultOrderAsync( + Guid encounterId, string orderDescription, string? resultSummary) + { + var ordersResponse = await _http.GetAsync( + $"/api/v1/encounters/{encounterId}/orders?status=Pending"); + if (!ordersResponse.IsSuccessStatusCode) + return false; + + var envelope = await ordersResponse.Content + .ReadFromJsonAsync>>(); + var order = FindPendingOrder(envelope?.Data.Items ?? [], orderDescription); + if (order is null) + return false; + + var resultResponse = await _http.PatchAsJsonAsync( + $"/api/v1/orders/{order.Id}/result", + new RecordOrderResultRequest(resultSummary)); + return resultResponse.IsSuccessStatusCode; + } + + private static OrderResponse? FindPendingOrder( + List items, string description) + { + return items.FirstOrDefault(o => o.Description == description) + ?? items.FirstOrDefault(o => + description.StartsWith(o.Description, StringComparison.OrdinalIgnoreCase)) + ?? items.FirstOrDefault(o => + o.Description.StartsWith(description, StringComparison.OrdinalIgnoreCase)); + } + + // --- Polling endpoints --- + + public async Task> GetAlertsAsync(Guid encounterId) + { + var response = await _http.GetAsync($"/api/v1/encounters/{encounterId}/alerts"); + if (!response.IsSuccessStatusCode) return new(); + var envelope = await response.Content + .ReadFromJsonAsync>>(); + return envelope?.Data.Items.ToList() ?? new(); + } + + public async Task GetCurrentNews2Async(Guid encounterId) + { + var response = await _http.GetAsync($"/api/v1/encounters/{encounterId}/news2/current"); + if (!response.IsSuccessStatusCode) return null; + var envelope = await response.Content.ReadFromJsonAsync>(); + return envelope?.Data; + } + + public async Task GetSepsisBundleAsync(Guid encounterId) + { + var response = await _http.GetAsync( + $"/api/v1/encounters/{encounterId}/sepsis-bundle/current"); + if (!response.IsSuccessStatusCode) return null; + var envelope = await response.Content + .ReadFromJsonAsync>(); + return envelope?.Data; + } +} \ No newline at end of file diff --git a/VigilCare.Simulator/Commands/DryRunCommand.cs b/VigilCare.Simulator/Commands/DryRunCommand.cs new file mode 100644 index 0000000..a78ca4e --- /dev/null +++ b/VigilCare.Simulator/Commands/DryRunCommand.cs @@ -0,0 +1,30 @@ +using System.CommandLine; + +public static class DryRunCommand +{ + public static Command Create() + { + var fileArg = new Argument("scenario-file", "Path to the scenario JSON file"); + var command = new Command("dry-run", "Print event timeline without calling the API") + { + fileArg + }; + + command.SetHandler(async (FileInfo file) => + { + var scenario = ScenarioLoader.Load(file.FullName); + var errors = ScenarioValidator.Validate(scenario); + if (errors.Count > 0) + { + SimulatorConsole.Error($"Scenario validation failed with {errors.Count} error(s):"); + foreach (var err in errors) SimulatorConsole.Error($" • {err}"); + return; + } + + var engine = new ReplayEngine(client: null!, poller: null); + await engine.RunAsync(scenario, new ReplayOptions(DryRun: true)); + }, fileArg); + + return command; + } +} diff --git a/VigilCare.Simulator/Commands/ReplayAllCommand.cs b/VigilCare.Simulator/Commands/ReplayAllCommand.cs new file mode 100644 index 0000000..2971e29 --- /dev/null +++ b/VigilCare.Simulator/Commands/ReplayAllCommand.cs @@ -0,0 +1,56 @@ +using System.CommandLine; + +public static class ReplayAllCommand +{ + public static Command Create() + { + var dirArg = new Argument("directory", "Directory containing scenario JSON files"); + var speedOpt = new Option("--speed", () => 60); + var baseUrlOpt = new Option("--base-url", () => "http://localhost:5270"); + + var command = new Command("replay-all", "Replay all scenarios in a directory") + { + dirArg, speedOpt, baseUrlOpt + }; + + command.SetHandler(async (DirectoryInfo dir, double speed, string baseUrl) => + { + var files = dir.GetFiles("*.json") + .Where(f => f.Name != "schema.json") + .OrderBy(f => f.Name) + .ToList(); + + if (files.Count == 0) + { + SimulatorConsole.Warn($"No .json scenario files found in {dir.FullName}"); + return; + } + + SimulatorConsole.Header($"Replaying {files.Count} scenarios from {dir.Name}"); + + using var http = new HttpClient { BaseAddress = new Uri(baseUrl) }; + var client = new VigilCareApiClient(http); + var engine = new ReplayEngine(client, poller: null); + var results = new List(); + + foreach (var file in files) + { + SimulatorConsole.Divider(); + var scenario = ScenarioLoader.Load(file.FullName); + var errors = ScenarioValidator.Validate(scenario); + if (errors.Count > 0) + { + SimulatorConsole.Error($"Skipping {file.Name}: {errors.Count} validation error(s)"); + continue; + } + + var result = await engine.RunAsync(scenario, new ReplayOptions(speed)); + results.Add(result); + } + + SimulatorConsole.BatchSummary(results); + }, dirArg, speedOpt, baseUrlOpt); + + return command; + } +} \ No newline at end of file diff --git a/VigilCare.Simulator/Commands/ReplayCommand.cs b/VigilCare.Simulator/Commands/ReplayCommand.cs new file mode 100644 index 0000000..e53660e --- /dev/null +++ b/VigilCare.Simulator/Commands/ReplayCommand.cs @@ -0,0 +1,40 @@ +using System.CommandLine; + +public static class ReplayCommand +{ + public static Command Create() + { + var fileArg = new Argument("scenario-file"); + var speedOpt = new Option("--speed", () => 60, "Speed multiplier (0=instant, 1=realtime)"); + var baseUrlOpt = new Option("--base-url", () => "http://localhost:5270"); + var pollOpt = new Option("--poll", () => false, "Poll alerts/scores after each cluster"); + var pollIntervalOpt = new Option("--poll-interval", () => 5, "Seconds between polls"); + + var command = new Command("replay", "Replay a scenario against the API") + { + fileArg, speedOpt, baseUrlOpt, pollOpt, pollIntervalOpt + }; + + command.SetHandler(async (FileInfo file, double speed, string baseUrl, bool poll, int pollInterval) => + { + var scenario = ScenarioLoader.Load(file.FullName); + var errors = ScenarioValidator.Validate(scenario); + if (errors.Count > 0) + { + SimulatorConsole.Error($"Scenario validation failed with {errors.Count} error(s):"); + foreach (var err in errors) SimulatorConsole.Error($" • {err}"); + return; + } + + using var http = new HttpClient { BaseAddress = new Uri(baseUrl) }; + var client = new VigilCareApiClient(http); + var poller = poll ? new ApiPoller(client) : null; + var engine = new ReplayEngine(client, poller); + var options = new ReplayOptions(speed, poll, pollInterval); + + await engine.RunAsync(scenario, options); + }, fileArg, speedOpt, baseUrlOpt, pollOpt, pollIntervalOpt); + + return command; + } +} \ No newline at end of file diff --git a/VigilCare.Simulator/Commands/ValidateCommand.cs b/VigilCare.Simulator/Commands/ValidateCommand.cs new file mode 100644 index 0000000..d2df90d --- /dev/null +++ b/VigilCare.Simulator/Commands/ValidateCommand.cs @@ -0,0 +1,37 @@ +using System.CommandLine; + +public static class ValidateCommand +{ + public static Command Create() + { + var fileArg = new Argument("scenario-file", "Path to the scenario JSON file"); + var command = new Command("validate", "Validate a scenario file without replaying") + { + fileArg + }; + + command.SetHandler((FileInfo file) => + { + var scenario = ScenarioLoader.Load(file.FullName); + var errors = ScenarioValidator.Validate(scenario); + + if (errors.Count == 0) + { + SimulatorConsole.Success($"✓ {file.Name} is valid"); + SimulatorConsole.Info($" {scenario.Events.Count} events over " + + $"{scenario.Events.Last().OffsetMinutes} minutes"); + SimulatorConsole.Info($" Patient: {scenario.Patient.FirstName} " + + $"{scenario.Patient.LastName}"); + SimulatorConsole.Info($" Tags: {string.Join(", ", scenario.Scenario.Tags ?? new())}"); + } + else + { + SimulatorConsole.Error($"✗ {file.Name} has {errors.Count} error(s):"); + foreach (var err in errors) + SimulatorConsole.Error($" • {err}"); + } + }, fileArg); + + return command; + } +} \ No newline at end of file diff --git a/VigilCare.Simulator/Engine/ReplayEngine.cs b/VigilCare.Simulator/Engine/ReplayEngine.cs new file mode 100644 index 0000000..0d9df58 --- /dev/null +++ b/VigilCare.Simulator/Engine/ReplayEngine.cs @@ -0,0 +1,241 @@ +public class ReplayEngine +{ + private readonly VigilCareApiClient _client; + private readonly ApiPoller? _poller; + private DateTimeOffset _scenarioStartTime; + + public ReplayEngine(VigilCareApiClient client, ApiPoller? poller) + { + _client = client; + _poller = poller; + } + + public async Task RunAsync( + ScenarioFile scenario, ReplayOptions options, CancellationToken ct = default) + { + var result = new ReplayResult(scenario.Scenario.Id); + var startTime = DateTimeOffset.UtcNow; + _scenarioStartTime = startTime; + + // --- Phase 1: Setup --- + SimulatorConsole.Header(scenario.Scenario.Name, scenario.Scenario.Description); + + PatientResponse patient; + EncounterResponse encounter; + + if (options.DryRun) + { + SimulatorConsole.DryRun("Would register patient: " + + $"{scenario.Patient.FirstName} {scenario.Patient.LastName}"); + SimulatorConsole.DryRun("Would open encounter: " + + $"{scenario.Encounter.Department} / {scenario.Encounter.EncounterType}"); + } + else + { + patient = await _client.RegisterPatientAsync(new RegisterPatientRequest( + scenario.Patient.FirstName, + scenario.Patient.LastName, + DateOnly.Parse(scenario.Patient.DateOfBirth), + scenario.Patient.Gender)); + + encounter = await _client.OpenEncounterAsync(patient.Id, new OpenEncounterRequest( + scenario.Encounter.EncounterType, + scenario.Encounter.Department, + scenario.Encounter.AttendingPhysician, + scenario.Encounter.RoomBed, + scenario.Encounter.AdmissionReason)); + + SimulatorConsole.Info($"Patient registered: {patient.Id} ({patient.Mrn})"); + SimulatorConsole.Info($"Encounter opened: {encounter.Id} ({encounter.Status})"); + result.PatientId = patient.Id; + result.EncounterId = encounter.Id; + } + + // --- Phase 2: Replay events --- + double lastOffset = 0; + var clusters = scenario.Events + .GroupBy(e => e.OffsetMinutes) + .OrderBy(g => g.Key) + .ToList(); + + foreach (var cluster in clusters) + { + ct.ThrowIfCancellationRequested(); + + var deltaMinutes = cluster.Key - lastOffset; + if (deltaMinutes > 0 && options.Speed > 0 && !options.DryRun) + { + var delayMs = (int)(deltaMinutes * 60_000 / options.Speed); + SimulatorConsole.Wait(deltaMinutes, delayMs); + await Task.Delay(delayMs, ct); + } + + var simTimestamp = FormatSimTime(cluster.Key); + var observationEvents = cluster.Where(e => e.Type == "observation").ToList(); + var otherEvents = cluster.Where(e => e.Type != "observation").ToList(); + + if (observationEvents.Count > 0) + await ReplayObservationCluster(observationEvents, simTimestamp, options, result); + + foreach (var evt in otherEvents) + { + switch (evt.Type) + { + case "order": + await ReplayOrder( + evt, simTimestamp, options, result, scenario.Encounter.AttendingPhysician); + break; + case "medication": + await ReplayMedication(evt, simTimestamp, options, result); + break; + case "order_result": + await ReplayOrderResult(evt, simTimestamp, options, result); + break; + } + } + + lastOffset = cluster.Key; + + if (options.Poll && !options.DryRun && _poller is not null) + { + await Task.Delay(options.PollIntervalSeconds * 1000, ct); + await _poller.PollAndDisplayAsync(result.EncounterId, simTimestamp); + } + } + + // --- Phase 3: Summary --- + result.Duration = DateTimeOffset.UtcNow - startTime; + SimulatorConsole.Summary(result); + return result; + } + + private async Task ReplayObservationCluster( + List cluster, string simTime, ReplayOptions options, + ReplayResult result) + { + var observations = new List(); + var offsetMinutes = cluster[0].OffsetMinutes; + var recordedAt = _scenarioStartTime.AddMinutes(offsetMinutes); + + foreach (var evt in cluster) + { + var code = evt.Data.GetProperty("code").GetString()!; + var value = evt.Data.GetProperty("value").GetDecimal(); + var unit = evt.Data.GetProperty("unit").GetString()!; + var source = evt.Data.TryGetProperty("source", out var s) ? s.GetString()! : "Manual"; + + SimulatorConsole.Event(simTime, $"{code} {value} {unit}"); + result.ObservationsSent++; + + if (!options.DryRun) + { + observations.Add(new IngestObservationRequest( + code, value, unit, ToApiSource(source), recordedAt, null)); + } + } + + if (!options.DryRun && observations.Count > 0) + await _client.SendObservationBatchAsync(result.EncounterId, observations); + } + + private async Task ReplayMedication( + ScenarioEvent evt, string simTime, ReplayOptions options, ReplayResult result) + { + var drugName = evt.Data.GetProperty("drugName").GetString()!; + var dose = evt.Data.GetProperty("dose").GetDecimal(); + var doseUnit = evt.Data.GetProperty("doseUnit").GetString()!; + var route = evt.Data.GetProperty("route").GetString()!; + var administeredBy = evt.Data.GetProperty("administeredBy").GetString()!; + + if (options.DryRun) + { + SimulatorConsole.DryRun($"[{simTime}] MEDICATION {drugName} {dose}{doseUnit} {route}"); + return; + } + + var sent = await _client.TrySendMedicationAsync(result.EncounterId, + new CreateMedicationAdministrationRequest(drugName, dose, doseUnit, route, null, administeredBy)); + + if (sent) + { + SimulatorConsole.Event(simTime, $"MEDICATION {drugName} {dose}{doseUnit} ({route}) sent"); + result.MedicationsSent++; + } + else + { + SimulatorConsole.Warn($"[{simTime}] MEDICATION skipped — endpoint not available (Phase 15 required)"); + result.MedicationsSkipped++; + } + } + + private async Task ReplayOrder( + ScenarioEvent evt, string simTime, ReplayOptions options, ReplayResult result, + string defaultOrderedBy) + { + var description = evt.Data.GetProperty("description").GetString()!; + var orderType = evt.Data.GetProperty("orderType").GetString()!; + var orderedBy = evt.Data.TryGetProperty("orderedBy", out var ob) + ? ob.GetString()! : defaultOrderedBy; + + if (options.DryRun) + { + SimulatorConsole.DryRun($"[{simTime}] ORDER {orderType}: {description}"); + return; + } + + var placed = await _client.TryCreateOrderAsync(result.EncounterId, + new CreateOrderRequest(orderType, description, orderedBy)); + + if (placed) + { + SimulatorConsole.Event(simTime, $"ORDER {description} placed"); + result.OrdersPlaced++; + } + else + { + SimulatorConsole.Warn($"[{simTime}] ORDER skipped — failed to place '{description}'"); + } + } + + private async Task ReplayOrderResult( + ScenarioEvent evt, string simTime, ReplayOptions options, ReplayResult result) + { + var orderDesc = evt.Data.GetProperty("orderDescription").GetString()!; + var resultSummary = evt.Data.TryGetProperty("resultSummary", out var rs) + ? rs.GetString() : null; + + if (options.DryRun) + { + SimulatorConsole.DryRun($"[{simTime}] ORDER_RESULT {orderDesc}"); + return; + } + + var ok = await _client.TryResultOrderAsync( + result.EncounterId, orderDesc, resultSummary); + + if (ok) + { + SimulatorConsole.Event(simTime, $"ORDER_RESULT {orderDesc} → resulted"); + result.OrdersResulted++; + } + else + { + SimulatorConsole.Warn($"[{simTime}] ORDER_RESULT skipped — order '{orderDesc}' not found or already resulted"); + } + } + + private static string FormatSimTime(double offsetMinutes) + { + var hours = (int)(offsetMinutes / 60); + var mins = (int)(offsetMinutes % 60); + return $"{hours:D2}:{mins:D2}"; + } + + private static string ToApiSource(string source) => source switch + { + "Device" or "DEVICE" or "device" or "monitor" => "DEVICE", + "Manual" or "MANUAL" or "manual" => "MANUAL", + "Lab" or "LAB" or "lab" => "LAB", + _ => throw new InvalidOperationException($"Unknown observation source: '{source}'") + }; +} \ No newline at end of file diff --git a/VigilCare.Simulator/Engine/ReplayOptions.cs b/VigilCare.Simulator/Engine/ReplayOptions.cs new file mode 100644 index 0000000..51493be --- /dev/null +++ b/VigilCare.Simulator/Engine/ReplayOptions.cs @@ -0,0 +1,5 @@ +public record ReplayOptions( + double Speed = 60, + bool Poll = false, + int PollIntervalSeconds = 5, + bool DryRun = false); \ No newline at end of file diff --git a/VigilCare.Simulator/Engine/ReplayResult.cs b/VigilCare.Simulator/Engine/ReplayResult.cs new file mode 100644 index 0000000..6fd997a --- /dev/null +++ b/VigilCare.Simulator/Engine/ReplayResult.cs @@ -0,0 +1,14 @@ +public class ReplayResult +{ + public string ScenarioId { get; } + public Guid PatientId { get; set; } + public Guid EncounterId { get; set; } + public int ObservationsSent { get; set; } + public int MedicationsSent { get; set; } + public int MedicationsSkipped { get; set; } + public int OrdersPlaced { get; set; } + public int OrdersResulted { get; set; } + public TimeSpan Duration { get; set; } + + public ReplayResult(string scenarioId) => ScenarioId = scenarioId; +} \ No newline at end of file diff --git a/VigilCare.Simulator/Output/SimulatorConsole.cs b/VigilCare.Simulator/Output/SimulatorConsole.cs new file mode 100644 index 0000000..e89a8dc --- /dev/null +++ b/VigilCare.Simulator/Output/SimulatorConsole.cs @@ -0,0 +1,83 @@ +using Spectre.Console; + +public static class SimulatorConsole +{ + public static void Header(string title, string? description = null) + { + AnsiConsole.Write(new Rule($"[bold]{title}[/]").LeftJustified()); + if (description is not null) + AnsiConsole.MarkupLine($"[dim]{description}[/]"); + AnsiConsole.WriteLine(); + } + + public static void Event(string simTime, string message) => + AnsiConsole.MarkupLine($"[green][[{simTime}]][/] {Markup.Escape(message)}"); + + public static void Warn(string message) => + AnsiConsole.MarkupLine($"[yellow]{Markup.Escape(message)}[/]"); + + public static void Error(string message) => + AnsiConsole.MarkupLine($"[red]{Markup.Escape(message)}[/]"); + + public static void Info(string message) => + AnsiConsole.MarkupLine($"[blue]{Markup.Escape(message)}[/]"); + + public static void DryRun(string message) => + AnsiConsole.MarkupLine($"[dim]DRY-RUN:[/] {Markup.Escape(message)}"); + + public static void Success(string message) => + AnsiConsole.MarkupLine($"[bold green]{Markup.Escape(message)}[/]"); + + public static void Wait(double deltaMinutes, int delayMs) => + AnsiConsole.MarkupLine( + $"[dim] ⏳ waiting {deltaMinutes:F0}m simulated ({delayMs / 1000.0:F1}s real)...[/]"); + + public static void Divider() => + AnsiConsole.Write(new Rule().RuleStyle(Style.Parse("dim"))); + + public static void Summary(ReplayResult r) + { + AnsiConsole.WriteLine(); + var table = new Table().AddColumn("Metric").AddColumn("Value"); + table.AddRow("Scenario", r.ScenarioId); + table.AddRow("Observations sent", r.ObservationsSent.ToString()); + table.AddRow("Medications sent", r.MedicationsSent.ToString()); + if (r.MedicationsSkipped > 0) + table.AddRow("Medications skipped", r.MedicationsSkipped.ToString()); + table.AddRow("Orders placed", r.OrdersPlaced.ToString()); + table.AddRow("Orders resulted", r.OrdersResulted.ToString()); + table.AddRow("Wall-clock time", $"{r.Duration.TotalSeconds:F1}s"); + AnsiConsole.Write(table); + } + + public static void BatchSummary(List results) + { + AnsiConsole.WriteLine(); + AnsiConsole.Write(new Rule("[bold]Batch Summary[/]").LeftJustified()); + var table = new Table() + .AddColumn("Scenario") + .AddColumn("Observations") + .AddColumn("Medications") + .AddColumn("Time"); + foreach (var r in results) + table.AddRow(r.ScenarioId, r.ObservationsSent.ToString(), + r.MedicationsSent.ToString(), $"{r.Duration.TotalSeconds:F1}s"); + AnsiConsole.Write(table); + } + + public static void PollResults(string simTime, PollResult poll) + { + if (poll.News2 is not null) + AnsiConsole.MarkupLine( + $"[cyan][[{simTime}]][/] NEWS2 = {poll.News2.TotalScore} ({poll.News2.RiskLevel})"); + + foreach (var alert in poll.NewAlerts) + AnsiConsole.MarkupLine( + $"[red][[{simTime}]][/] ALERT {alert.AlertType} ({alert.Severity})"); + + if (poll.SepsisBundle is not null) + AnsiConsole.MarkupLine( + $"[cyan][[{simTime}]][/] SEPSIS BUNDLE {poll.SepsisBundle.ComplianceStatus} " + + $"({poll.SepsisBundle.ElementsCompleted}/4)"); + } +} \ No newline at end of file diff --git a/VigilCare.Simulator/Polling/ApiPoller.cs b/VigilCare.Simulator/Polling/ApiPoller.cs new file mode 100644 index 0000000..8975382 --- /dev/null +++ b/VigilCare.Simulator/Polling/ApiPoller.cs @@ -0,0 +1,20 @@ +public class ApiPoller +{ + private readonly VigilCareApiClient _client; + private readonly HashSet _seenAlertIds = new(); + + public ApiPoller(VigilCareApiClient client) => _client = client; + + public async Task PollAndDisplayAsync(Guid encounterId, string simTime) + { + var news2 = await _client.GetCurrentNews2Async(encounterId); + + var allAlerts = await _client.GetAlertsAsync(encounterId); + var newAlerts = allAlerts.Where(a => _seenAlertIds.Add(a.Id)).ToList(); + + var bundle = await _client.GetSepsisBundleAsync(encounterId); + + var result = new PollResult(news2, newAlerts, bundle); + SimulatorConsole.PollResults(simTime, result); + } +} \ No newline at end of file diff --git a/VigilCare.Simulator/Polling/PollResult.cs b/VigilCare.Simulator/Polling/PollResult.cs new file mode 100644 index 0000000..7ebed10 --- /dev/null +++ b/VigilCare.Simulator/Polling/PollResult.cs @@ -0,0 +1,4 @@ +public record PollResult( + News2Response? News2, + List NewAlerts, + SepsisBundleResponse? SepsisBundle); \ No newline at end of file diff --git a/VigilCare.Simulator/Program.cs b/VigilCare.Simulator/Program.cs new file mode 100644 index 0000000..9f6183e --- /dev/null +++ b/VigilCare.Simulator/Program.cs @@ -0,0 +1,10 @@ +using System.CommandLine; + +var rootCommand = new RootCommand("VigilCare Clinical Replay Simulator"); + +rootCommand.AddCommand(ReplayCommand.Create()); +rootCommand.AddCommand(ReplayAllCommand.Create()); +rootCommand.AddCommand(ValidateCommand.Create()); +rootCommand.AddCommand(DryRunCommand.Create()); + +return await rootCommand.InvokeAsync(args); \ No newline at end of file diff --git a/VigilCare.Simulator/Scenarios/GENERATE_PROMPT.md b/VigilCare.Simulator/Scenarios/GENERATE_PROMPT.md new file mode 100644 index 0000000..aa98fa0 --- /dev/null +++ b/VigilCare.Simulator/Scenarios/GENERATE_PROMPT.md @@ -0,0 +1,199 @@ +# VigilCare Scenario Generator Prompt + +Use the following prompt with Claude or any LLM to generate clinical scenario JSON files. + +--- + +## Prompt + +You are a clinical scenario generator for a hospital patient monitoring system called VigilCare. Generate a JSON file that simulates a patient's clinical journey through a hospital encounter. + +### JSON Structure + +```json +{ + "scenario": { + "id": "kebab-case-id", + "name": "Human-readable scenario name", + "description": "1-2 sentence clinical summary", + "durationMinutes": 240, + "tags": ["sepsis", "ed", "deterioration"] + }, + "patient": { + "firstName": "Eleanor", + "lastName": "Chen", + "dateOfBirth": "1954-03-15", + "gender": "Female" + }, + "encounter": { + "department": "Emergency", + "encounterType": "Emergency | Inpatient | Outpatient", + "attendingPhysician": "Dr. Sarah Mitchell", + "roomBed": "ED-12A", + "admissionReason": "Fever, confusion, dysuria" + }, + "events": [ + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 88, + "unit": "bpm", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "medication", + "data": { + "drugName": "ceftriaxone", + "dose": 1, + "doseUnit": "g", + "route": "IV", + "administeredBy": "nurse-rn-1" + } + }, + { + "offsetMinutes": 45, + "type": "order", + "data": { + "orderType": "Lab", + "description": "Urinalysis with culture", + "orderedBy": "Dr. Sarah Mitchell" + } + }, + { + "offsetMinutes": 45, + "type": "order_result", + "data": { + "orderDescription": "SEP-1: Blood cultures", + "resultSummary": "Pending gram stain" + } + } + ], + "expectedOutcomes": [ + { + "afterOffsetMinutes": 30, + "type": "alert", + "alertType": "WARNING_HEART_RATE", + "description": "HR enters warning range" + }, + { + "afterOffsetMinutes": 120, + "type": "alert", + "alertType": "SEPSIS_WARNING", + "description": "SIRS criteria met" + }, + { + "afterOffsetMinutes": 180, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 7, + "description": "NEWS2 reaches HIGH risk" + }, + { + "afterOffsetMinutes": 120, + "type": "bundle", + "description": "Sepsis bundle auto-created with 4 orders" + } + ] +} +``` + +### Available Observation Codes + +| Code | Unit | Normal Range | Warning Range | Critical Range | +|------|------|-------------|---------------|----------------| +| HEART_RATE | bpm | 51–90 | 41–50 or 91–110 | ≤40 or ≥111 | +| RESP_RATE | /min | 12–20 | 9–11 or 21–24 | ≤8 or ≥25 | +| SYSTOLIC_BP | mmHg | 111–219 | 101–110 | ≤100 or ≥220 | +| DIASTOLIC_BP | mmHg | 60–90 | 50–59 or 91–100 | ≤49 or ≥101 | +| TEMP_C | °C | 36.1–38.0 | 35.1–36.0 or 38.1–39.0 | ≤35.0 or ≥39.1 | +| SPO2 | % | 96–100 | 94–95 | ≤93 | +| AVPU | score | 0 (Alert) | — | 1 (Voice) 2 (Pain) 3 (Unresponsive) | +| SUPPLEMENTAL_O2 | flag | 0 (No) | — | 1 (Yes) | +| WBC_K_UL | ×10³/µL | 4.5–11.0 | — | <4.0 or >12.0 | +| POTASSIUM_MEQ_L | mEq/L | 3.5–5.0 | 3.0–3.4 or 5.1–5.5 | <3.0 or >5.5 | +| LACTATE_MMOL_L | mmol/L | 0.5–1.5 | 1.6–2.0 | >2.0 | +| GLUCOSE_MG_DL | mg/dL | 70–140 | 141–180 | <70 or >180 | + +### Clinical Scoring Rules + +**NEWS2** (computed from: HEART_RATE, RESP_RATE, SYSTOLIC_BP, TEMP_C, SPO2, AVPU, SUPPLEMENTAL_O2): +- Total score 5–6 → `NEWS2_WARNING` alert +- Total score ≥7 OR any single parameter scores 3 → `NEWS2_EMERGENCY` alert + +**SIRS** (≥2 of 4 criteria → `SEPSIS_WARNING`): +- Temperature >38.3°C or <36.0°C +- Heart rate >90 bpm +- Respiratory rate >20/min +- WBC >12.0 or <4.0 ×10³/µL + +**qSOFA** (≥2 of 3 criteria → `QSOFA_WARNING`): +- Respiratory rate ≥22/min +- Systolic BP ≤100 mmHg +- AVPU ≥1 (any altered mentation) + +**Trend alerts** — rapid rise or fall in a vital sign within a 30-minute sliding window triggers `RAPID_DETERIORATION`. + +**Sepsis bundle** — when `SEPSIS_WARNING` or `QSOFA_WARNING` fires, the system auto-creates a sepsis bundle with 4 orders (use these **exact** descriptions in `order_result` events; do **not** add `order` events for them): + +| Description | +|---| +| `SEP-1: Blood cultures` | +| `SEP-1: Serum lactate` | +| `SEP-1: Broad-spectrum antibiotics` | +| `SEP-1: IV fluid bolus` | + +Place `order_result` events for bundle orders **after** the sepsis alert would fire. For any other lab/imaging order, add an `order` event before `order_result`. + +### Order event types + +Place order (required before `order_result` unless sepsis bundle auto-order): +```json +{ + "offsetMinutes": 40, + "type": "order", + "data": { + "orderType": "Lab", + "description": "Urinalysis with culture", + "orderedBy": "Dr. Sarah Mitchell" + } +} +``` + +Valid `orderType` values: `Lab`, `Imaging`, `Medication`, `Procedure`. `orderedBy` defaults to `encounter.attendingPhysician` if omitted. + +### Rules for Generating Realistic Scenarios + +1. **Vital signs arrive in clusters.** In real hospitals, nurses take a full set of vitals every 15–60 minutes. Each cluster should include at minimum: HEART_RATE, RESP_RATE, SYSTOLIC_BP, TEMP_C, SPO2, AVPU. Add SUPPLEMENTAL_O2 only when oxygen is administered. Add lab values (WBC, LACTATE, POTASSIUM, GLUCOSE) only at specific lab draw times, not every cluster. + +2. **Deterioration is gradual.** A patient does not jump from HR 80 to HR 130 in one reading. Realistic deterioration progresses over 2–6 hours: HR 80 → 88 → 95 → 102 → 110 → 118. Each step is 15–60 minutes apart. + +3. **Vital signs correlate.** Sepsis shows rising HR + rising temp + rising RR + falling BP together. Hemorrhagic shock shows rising HR + falling BP + falling SpO2. Respiratory failure shows falling SpO2 + rising RR. Don't change vital signs independently. + +4. **Include physiological noise.** Real vital signs fluctuate. A stable HR of 75 might read 73, 76, 74, 77 across 4 readings. Add ±2–5% variation on stable values. + +5. **Start with a baseline.** The first event cluster (offsetMinutes: 0) should be a complete set of normal or near-normal vitals establishing the patient's baseline. + +6. **offsetMinutes must be non-decreasing.** Events within the same minute are fine (a full vital sign set arrives at the same offset). Never go backwards. + +7. **Max 10 observations per offset.** The API accepts at most 10 observations per batch. A full vital set is 7 codes (HR, RR, SBP, TEMP, SpO2, AVPU, plus SUPPLEMENTAL_O2 when on oxygen). If you add lab values at the same minute, keep the total ≤10 — e.g. put labs at `offsetMinutes + 1` when vitals + labs would exceed 10. + +8. **Use realistic source values.** Observation source is `"Device"` for continuous monitoring (HR, SpO2, BP) or `"Manual"` for nurse-measured values (temp, AVPU, supplemental O2). Lab draws (WBC, lactate, potassium, glucose) are `"Lab"`. + +9. **Medications need clinical justification.** Only include medication events that make clinical sense for the scenario. Include the medication type events only if the scenario involves treatment response. + +10. **Orders before results.** Every `order_result` must have a matching pending order. Use an `order` event first for routine labs/imaging. Sepsis bundle orders are auto-created — only use `order_result` with the exact SEP-1 descriptions above. + +11. **Expected outcomes must be achievable.** Only list expected outcomes that the given vital sign trajectory will actually trigger based on the scoring rules above. Calculate NEWS2 scores mentally. Count SIRS criteria. Check qSOFA thresholds. + +### Generate This Scenario + +- 72-year-old with UTI → sepsis over 4 hours +- Baseline normals → rising temp, HR, RR → SIRS triggers → qSOFA triggers → bundle auto-created +- Includes order results completing the sepsis bundle +- Expected: `SEPSIS_WARNING`, `QSOFA_WARNING`, `NEWS2_EMERGENCY`, sepsis bundle `COMPLIANT` + +Output ONLY the JSON file. No explanation or commentary. \ No newline at end of file diff --git a/VigilCare.Simulator/Scenarios/List/cardiac-arrest-post-mi-01.json b/VigilCare.Simulator/Scenarios/List/cardiac-arrest-post-mi-01.json new file mode 100644 index 0000000..da0d3ca --- /dev/null +++ b/VigilCare.Simulator/Scenarios/List/cardiac-arrest-post-mi-01.json @@ -0,0 +1,1272 @@ +{ + "scenario": { + "id": "cardiac-arrest-post-mi-01", + "name": "Cardiac Arrest Post-MI with Hemodynamic Collapse", + "description": "65-year-old male admitted for chest pain evolving into STEMI with hemodynamic collapse over 3 hours. Rising HR, falling BP and SpO2 culminate in near-arrest requiring vasopressor support. Triggers NEWS2_EMERGENCY and RAPID_DETERIORATION.", + "durationMinutes": 180, + "tags": [ + "cardiac", + "stemi", + "arrest", + "deterioration", + "emergency", + "cardiology", + "vasopressor" + ] + }, + "patient": { + "firstName": "Robert", + "lastName": "Callahan", + "dateOfBirth": "1961-03-14", + "gender": "Male" + }, + "encounter": { + "department": "Emergency", + "encounterType": "Emergency", + "attendingPhysician": "Dr. Anita Sharma", + "roomBed": "ED-03A", + "admissionReason": "Acute chest pain radiating to left arm, diaphoresis" + }, + "events": [ + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 82, + "unit": "bpm", + "source": "Device" + }, + "note": "Baseline triage \u2014 chest pain but vitals near-normal. NEWS2=0" + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 18, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 138, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 85, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 85, + "unit": "bpm", + "source": "Device" + }, + "note": "Slight increase in HR, physiological noise. NEWS2=0" + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 17, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 136, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 84, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.1, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 88, + "unit": "bpm", + "source": "Device" + }, + "note": "Mild tachycardia trend beginning. NEWS2=0" + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 18, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 132, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 80, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 32, + "type": "observation", + "data": { + "code": "POTASSIUM_MEQ_L", + "value": 4.2, + "unit": "mEq/L", + "source": "Lab" + }, + "note": "First lab draw \u2014 troponin ordered, potassium and glucose normal" + }, + { + "offsetMinutes": 32, + "type": "observation", + "data": { + "code": "GLUCOSE_MG_DL", + "value": 118, + "unit": "mg/dL", + "source": "Lab" + } + }, + { + "offsetMinutes": 27, + "type": "order", + "data": { + "orderType": "Lab", + "description": "Troponin I, stat", + "orderedBy": "Dr. Anita Sharma" + } + }, + { + "offsetMinutes": 32, + "type": "order_result", + "data": { + "orderDescription": "Troponin I, stat", + "resultSummary": "Troponin I 0.08 ng/mL (borderline elevated, reference <0.04)" + }, + "note": "Initial troponin mildly elevated, consistent with early ACS" + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 93, + "unit": "bpm", + "source": "Device" + }, + "note": "HR crosses into warning range (91-110). NEWS2: HR=1. Total=1" + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 19, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 128, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 78, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "SPO2", + "value": 96, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 98, + "unit": "bpm", + "source": "Device" + }, + "note": "Tachycardia progressing, BP starting to drop. NEWS2: HR=1. Total=1" + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 20, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 122, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 75, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.1, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "SPO2", + "value": 96, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 106, + "unit": "bpm", + "source": "Device" + }, + "note": "Accelerating deterioration \u2014 HR rising, SpO2 dropping. NEWS2: HR=1, RR=2, SpO2=1. Total=4" + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 22, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 115, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 71, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "SPO2", + "value": 95, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 112, + "unit": "bpm", + "source": "Device" + }, + "note": "HR enters critical range (>=111). NEWS2: HR=2, RR=2, SBP=1, SpO2=1. Total=6 -> WARNING" + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 23, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 108, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 66, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.1, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "SPO2", + "value": 94, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 121, + "unit": "bpm", + "source": "Device" + }, + "note": "Rapid worsening \u2014 NEWS2: HR=2, RR=2, SBP=2, SpO2=2. Total=8 -> EMERGENCY. RAPID_DETERIORATION triggered." + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 24, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 100, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 62, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "SPO2", + "value": 93, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 128, + "unit": "bpm", + "source": "Device" + }, + "note": "Severe deterioration \u2014 NEWS2: HR=2, RR=3, SBP=3, SpO2=2. Total=10 -> EMERGENCY (RR single=3, SBP single=3)" + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 26, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 92, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 56, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.9, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "SPO2", + "value": 92, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 122, + "type": "observation", + "data": { + "code": "POTASSIUM_MEQ_L", + "value": 4.8, + "unit": "mEq/L", + "source": "Lab" + }, + "note": "Repeat labs \u2014 potassium rising, glucose elevated (stress response), troponin markedly elevated" + }, + { + "offsetMinutes": 122, + "type": "observation", + "data": { + "code": "GLUCOSE_MG_DL", + "value": 168, + "unit": "mg/dL", + "source": "Lab" + } + }, + { + "offsetMinutes": 122, + "type": "observation", + "data": { + "code": "LACTATE_MMOL_L", + "value": 3.4, + "unit": "mmol/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 117, + "type": "order", + "data": { + "orderType": "Lab", + "description": "Troponin I, repeat stat", + "orderedBy": "Dr. Anita Sharma" + } + }, + { + "offsetMinutes": 122, + "type": "order_result", + "data": { + "orderDescription": "Troponin I, repeat stat", + "resultSummary": "Troponin I 8.6 ng/mL (markedly elevated, reference <0.04) \u2014 consistent with acute STEMI" + }, + "note": "Troponin confirms large territory MI" + }, + { + "offsetMinutes": 130, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 134, + "unit": "bpm", + "source": "Device" + }, + "note": "Critical phase \u2014 NEWS2: HR=3, RR=3, SBP=3, SpO2=3, AVPU=3. Total=15 -> EMERGENCY" + }, + { + "offsetMinutes": 130, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 28, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 130, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 86, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 130, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 50, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 130, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.7, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 130, + "type": "observation", + "data": { + "code": "SPO2", + "value": 91, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 130, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 140, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 142, + "unit": "bpm", + "source": "Device" + }, + "note": "Peak crisis \u2014 near-arrest. NEWS2: HR=3, RR=3, SBP=3, SpO2=3, AVPU=3. Total=15 -> EMERGENCY" + }, + { + "offsetMinutes": 140, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 30, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 140, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 80, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 140, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 46, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 140, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.5, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 140, + "type": "observation", + "data": { + "code": "SPO2", + "value": 89, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 140, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 150, + "type": "medication", + "data": { + "drugName": "aspirin", + "dose": 325, + "doseUnit": "mg", + "route": "PO", + "administeredBy": "nurse-rn-2" + }, + "note": "Resuscitation medications initiated \u2014 aspirin for ACS" + }, + { + "offsetMinutes": 151, + "type": "medication", + "data": { + "drugName": "heparin", + "dose": 5000, + "doseUnit": "units", + "route": "IV", + "administeredBy": "nurse-rn-2" + }, + "note": "Anticoagulation for STEMI" + }, + { + "offsetMinutes": 153, + "type": "medication", + "data": { + "drugName": "morphine sulfate", + "dose": 4, + "doseUnit": "mg", + "route": "IV", + "administeredBy": "nurse-rn-2" + }, + "note": "Analgesia for chest pain and afterload reduction" + }, + { + "offsetMinutes": 155, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 138, + "unit": "bpm", + "source": "Device" + }, + "note": "O2 applied, medications given. NEWS2: HR=3, RR=3, SBP=3, SpO2=3, AVPU=3, O2=2. Total=17 -> EMERGENCY" + }, + { + "offsetMinutes": 155, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 28, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 155, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 82, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 155, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 48, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 155, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.6, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 155, + "type": "observation", + "data": { + "code": "SPO2", + "value": 90, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 155, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 155, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + }, + "note": "High-flow nasal cannula 15L/min started" + }, + { + "offsetMinutes": 158, + "type": "medication", + "data": { + "drugName": "norepinephrine", + "dose": 8, + "doseUnit": "mcg/min", + "route": "IV", + "administeredBy": "nurse-rn-2" + }, + "note": "Vasopressor initiated for cardiogenic shock" + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 128, + "unit": "bpm", + "source": "Device" + }, + "note": "Early vasopressor response. NEWS2: HR=2, RR=3, SBP=3, SpO2=3, AVPU=3, O2=2. Total=16 -> EMERGENCY" + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 26, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 88, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 52, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.8, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { + "code": "SPO2", + "value": 91, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 118, + "unit": "bpm", + "source": "Device" + }, + "note": "End of scenario \u2014 stabilizing on vasopressor + O2 but still critical. NEWS2: HR=2, RR=2, SBP=2, SpO2=2, O2=2. Total=10 -> EMERGENCY. Transfer to cath lab pending." + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 24, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 94, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 58, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.9, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "SPO2", + "value": 93, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 175, + "type": "order", + "data": { + "orderType": "Imaging", + "description": "12-Lead ECG, stat", + "orderedBy": "Dr. Anita Sharma" + } + }, + { + "offsetMinutes": 180, + "type": "order_result", + "data": { + "orderDescription": "12-Lead ECG, stat", + "resultSummary": "ST elevation in leads II, III, aVF with reciprocal ST depression in I, aVL \u2014 inferior STEMI confirmed, cardiology consulted for emergent PCI" + }, + "note": "ECG confirms inferior STEMI, cath lab activation" + } + ], + "expectedOutcomes": [ + { + "afterOffsetMinutes": 45, + "type": "alert", + "alertType": "WARNING_HEART_RATE", + "description": "HR enters warning range (93 bpm, 91-110 range scores NEWS2=1)" + }, + { + "afterOffsetMinutes": 90, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 6, + "description": "NEWS2 reaches 6 (HR=2, RR=2, SBP=1, SpO2=1) -> NEWS2_WARNING threshold" + }, + { + "afterOffsetMinutes": 90, + "type": "alert", + "alertType": "NEWS2_WARNING", + "description": "NEWS2 total of 6 triggers WARNING (5-6 range)" + }, + { + "afterOffsetMinutes": 105, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 8, + "description": "NEWS2 reaches 8 (HR=2, RR=2, SBP=2, SpO2=2) -> exceeds EMERGENCY threshold of 7" + }, + { + "afterOffsetMinutes": 105, + "type": "alert", + "alertType": "NEWS2_EMERGENCY", + "description": "NEWS2 total of 8 (>=7) triggers EMERGENCY alert \u2014 rapid hemodynamic compromise" + }, + { + "afterOffsetMinutes": 105, + "type": "alert", + "alertType": "RAPID_DETERIORATION", + "description": "HR rose from 88 to 121 (+33 bpm) and SBP fell from 132 to 100 (-32 mmHg) within 75 minutes, SpO2 dropped from 97 to 93 \u2014 consistent with rapid deterioration detection" + }, + { + "afterOffsetMinutes": 130, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 15, + "description": "NEWS2 reaches 15 (HR=3, RR=3, SBP=3, SpO2=3, AVPU=3) \u2014 critical hemodynamic collapse with altered consciousness" + }, + { + "afterOffsetMinutes": 155, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 17, + "description": "NEWS2 reaches 17 (HR=3, RR=3, SBP=3, SpO2=3, AVPU=3, O2=2) \u2014 peak score with supplemental oxygen added" + }, + { + "afterOffsetMinutes": 180, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 10, + "description": "NEWS2 stabilizes at 10 (HR=2, RR=2, SBP=2, SpO2=2, O2=2) \u2014 still EMERGENCY but improving on vasopressor support" + } + ] +} diff --git a/VigilCare.Simulator/Scenarios/List/dka-electrolyte-01.json b/VigilCare.Simulator/Scenarios/List/dka-electrolyte-01.json new file mode 100644 index 0000000..43734b0 --- /dev/null +++ b/VigilCare.Simulator/Scenarios/List/dka-electrolyte-01.json @@ -0,0 +1,1701 @@ +{ + "scenario": { + "id": "dka-electrolyte-01", + "name": "Diabetic Ketoacidosis with Electrolyte Derangement", + "description": "34-year-old male presenting with Kussmaul breathing, tachycardia, and dehydration. Glucose >400 on arrival with hyperkalemia (5.6 mEq/L) due to acidosis. During insulin/fluid resuscitation, potassium drops critically low (3.0 mEq/L) requiring KCl replacement. Demonstrates V-shaped potassium curve and gradual normalization over 5 hours.", + "durationMinutes": 300, + "tags": [ + "dka", + "diabetes", + "electrolyte", + "potassium", + "hyperglycemia", + "emergency", + "insulin", + "kussmaul", + "acidosis" + ] + }, + "patient": { + "firstName": "Marcus", + "lastName": "Devlin", + "dateOfBirth": "1992-04-17", + "gender": "Male" + }, + "encounter": { + "department": "Emergency", + "encounterType": "Emergency", + "attendingPhysician": "Dr. Priya Nair", + "roomBed": "ED-07B", + "admissionReason": "Altered mental status, rapid deep breathing, severe dehydration, blood glucose >400 mg/dL" + }, + "events": [ + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 112, + "unit": "bpm", + "source": "Device" + }, + "note": "Arrival \u2014 Kussmaul breathing, tachycardia, dry mucous membranes. NEWS2: HR=2, RR=3, SBP=1, Temp=0, SpO2=0, AVPU=0. Total=6, RR single=3 -> EMERGENCY" + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 28, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 102, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 58, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.2, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 2, + "type": "observation", + "data": { + "code": "GLUCOSE_MG_DL", + "value": 438, + "unit": "mg/dL", + "source": "Lab" + }, + "note": "Initial labs \u2014 critically elevated glucose, hyperkalemia from acidotic K+ shift, elevated lactate" + }, + { + "offsetMinutes": 2, + "type": "observation", + "data": { + "code": "POTASSIUM_MEQ_L", + "value": 5.6, + "unit": "mEq/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 2, + "type": "observation", + "data": { + "code": "LACTATE_MMOL_L", + "value": 2.4, + "unit": "mmol/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 0, + "type": "order", + "data": { + "orderType": "Lab", + "description": "Basic metabolic panel, stat", + "orderedBy": "Dr. Priya Nair" + } + }, + { + "offsetMinutes": 2, + "type": "order_result", + "data": { + "orderDescription": "Basic metabolic panel, stat", + "resultSummary": "Glucose 438 mg/dL (critical high), K+ 5.6 mEq/L (critical high), CO2 12 mEq/L (low), anion gap 28 (elevated), BUN 32 mg/dL (elevated), Cr 1.4 mg/dL \u2014 consistent with DKA" + }, + "note": "BMP confirms DKA: high anion gap metabolic acidosis with hyperglycemia" + }, + { + "offsetMinutes": 0, + "type": "order", + "data": { + "orderType": "Lab", + "description": "Venous blood gas, stat", + "orderedBy": "Dr. Priya Nair" + } + }, + { + "offsetMinutes": 3, + "type": "order_result", + "data": { + "orderDescription": "Venous blood gas, stat", + "resultSummary": "pH 7.18 (low), pCO2 22 mmHg (compensatory respiratory alkalosis), HCO3 10 mEq/L (critically low) \u2014 severe metabolic acidosis" + }, + "note": "VBG confirms severe acidosis driving Kussmaul breathing" + }, + { + "offsetMinutes": 0, + "type": "order", + "data": { + "orderType": "Lab", + "description": "Urinalysis, stat", + "orderedBy": "Dr. Priya Nair" + } + }, + { + "offsetMinutes": 4, + "type": "order_result", + "data": { + "orderDescription": "Urinalysis, stat", + "resultSummary": "Ketones 3+ (large), glucose 4+ (>1000 mg/dL), specific gravity 1.035 (concentrated) \u2014 confirms ketonuria and dehydration" + } + }, + { + "offsetMinutes": 5, + "type": "medication", + "data": { + "drugName": "sodium chloride 0.9% (Normal Saline)", + "dose": 1000, + "doseUnit": "mL", + "route": "IV", + "administeredBy": "nurse-rn-4" + }, + "note": "NS 1L bolus started for volume resuscitation" + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 115, + "unit": "bpm", + "source": "Device" + }, + "note": "Worsening slightly before treatment effect. NS bolus running. NEWS2: HR=2, RR=3, SBP=2, Temp=0, SpO2=0, AVPU=0. Total=7, RR single=3 -> EMERGENCY" + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 29, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 100, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 56, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.1, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 30, + "type": "medication", + "data": { + "drugName": "regular insulin", + "dose": 0.1, + "doseUnit": "units/kg/hr", + "route": "IV", + "administeredBy": "nurse-rn-4" + }, + "note": "Insulin drip started at 0.1 units/kg/hr after first liter NS \u2014 will drive K+ intracellularly" + }, + { + "offsetMinutes": 30, + "type": "medication", + "data": { + "drugName": "sodium chloride 0.9% (Normal Saline)", + "dose": 500, + "doseUnit": "mL/hr", + "route": "IV", + "administeredBy": "nurse-rn-4" + }, + "note": "NS continued at 500 mL/hr for ongoing volume resuscitation" + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 118, + "unit": "bpm", + "source": "Device" + }, + "note": "Peak worsening \u2014 insulin drip just started. NEWS2: HR=2, RR=3, SBP=2, Temp=0, SpO2=0, AVPU=0. Total=7, RR single=3 -> EMERGENCY" + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 30, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 98, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 55, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.2, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "SPO2", + "value": 96, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 116, + "unit": "bpm", + "source": "Device" + }, + "note": "Insulin/fluids running 15 min. Slight HR improvement. NEWS2: HR=2, RR=3, SBP=2, Temp=0, SpO2=0, AVPU=0. Total=7, RR single=3 -> EMERGENCY" + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 28, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 100, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 57, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.1, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 114, + "unit": "bpm", + "source": "Device" + }, + "note": "Glucose dropping, K+ declining as insulin drives it intracellular. NEWS2: HR=2, RR=3, SBP=1, Temp=0, SpO2=0, AVPU=0. Total=6, RR single=3 -> EMERGENCY" + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 27, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 102, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 59, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.1, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 62, + "type": "observation", + "data": { + "code": "GLUCOSE_MG_DL", + "value": 380, + "unit": "mg/dL", + "source": "Lab" + }, + "note": "1-hour labs \u2014 glucose dropping nicely, K+ falling as insulin shifts it intracellularly (dangerous trend)" + }, + { + "offsetMinutes": 62, + "type": "observation", + "data": { + "code": "POTASSIUM_MEQ_L", + "value": 4.8, + "unit": "mEq/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 62, + "type": "observation", + "data": { + "code": "LACTATE_MMOL_L", + "value": 2.1, + "unit": "mmol/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 57, + "type": "order", + "data": { + "orderType": "Lab", + "description": "Basic metabolic panel, repeat", + "orderedBy": "Dr. Priya Nair" + } + }, + { + "offsetMinutes": 62, + "type": "order_result", + "data": { + "orderDescription": "Basic metabolic panel, repeat", + "resultSummary": "Glucose 380 mg/dL (critical high, down from 438), K+ 4.8 mEq/L (down from 5.6, now normal range), CO2 14 mEq/L (improving), anion gap 24 (still elevated)" + }, + "note": "K+ dropping from 5.6 to 4.8 in 1 hour \u2014 rate suggests will fall below 3.5 within 2 hours, anticipate replacement need" + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 112, + "unit": "bpm", + "source": "Device" + }, + "note": "Gradual improvement with fluids. NEWS2: HR=2, RR=3, SBP=1, Temp=0, SpO2=0, AVPU=0. Total=6, RR single=3 -> EMERGENCY" + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 26, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 104, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 60, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 110, + "unit": "bpm", + "source": "Device" + }, + "note": "HR drops out of critical range. RR still critical. NEWS2: HR=1, RR=3, SBP=1, Temp=0, SpO2=0, AVPU=0. Total=5, RR single=3 -> EMERGENCY" + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 25, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 106, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 62, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 108, + "unit": "bpm", + "source": "Device" + }, + "note": "Improving \u2014 RR drops below 25. NEWS2: HR=1, RR=2, SBP=1, Temp=0, SpO2=0, AVPU=0. Total=4. No longer EMERGENCY by total or single param." + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 24, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 108, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 64, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 105, + "unit": "bpm", + "source": "Device" + }, + "note": "NEWS2: HR=1, RR=2, SBP=1, Temp=0, SpO2=0, AVPU=0. Total=4. K+ critically low on labs!" + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 23, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 108, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 65, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 122, + "type": "observation", + "data": { + "code": "GLUCOSE_MG_DL", + "value": 245, + "unit": "mg/dL", + "source": "Lab" + }, + "note": "2-hour labs \u2014 glucose improving but K+ critically low at 3.2, nadir of V-curve. Cardiac risk from hypokalemia." + }, + { + "offsetMinutes": 122, + "type": "observation", + "data": { + "code": "POTASSIUM_MEQ_L", + "value": 3.2, + "unit": "mEq/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 122, + "type": "observation", + "data": { + "code": "LACTATE_MMOL_L", + "value": 1.6, + "unit": "mmol/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 122, + "type": "order_result", + "data": { + "orderDescription": "Basic metabolic panel, repeat", + "resultSummary": "Glucose 245 mg/dL (critical high, improving), K+ 3.2 mEq/L (WARNING \u2014 dropped from 4.8, insulin-driven intracellular shift), CO2 17 mEq/L (improving), anion gap 18 (closing)" + }, + "note": "CRITICAL: K+ 3.2 \u2014 below 3.5, risk of cardiac arrhythmia. Must start KCl replacement before K+ drops further." + }, + { + "offsetMinutes": 118, + "type": "order", + "data": { + "orderType": "Imaging", + "description": "12-Lead ECG, stat", + "orderedBy": "Dr. Priya Nair" + } + }, + { + "offsetMinutes": 123, + "type": "order_result", + "data": { + "orderDescription": "12-Lead ECG, stat", + "resultSummary": "Sinus tachycardia at 105 bpm, ST depression in V3-V4, prominent U waves in V2-V4, flattened T waves \u2014 changes consistent with hypokalemia" + }, + "note": "ECG changes confirm electrophysiologic effects of hypokalemia" + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 103, + "unit": "bpm", + "source": "Device" + }, + "note": "NEWS2: HR=1, RR=2, SBP=1, Temp=0, SpO2=0, AVPU=0. Total=4. Awaiting K+ replacement order." + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 22, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 110, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 66, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 150, + "type": "medication", + "data": { + "drugName": "potassium chloride (KCl)", + "dose": 40, + "doseUnit": "mEq", + "route": "IV", + "administeredBy": "nurse-rn-4" + }, + "note": "KCl 40 mEq IV over 4 hours started for critical hypokalemia (K+ 3.2). Max rate 10 mEq/hr via peripheral line." + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 100, + "unit": "bpm", + "source": "Device" + }, + "note": "K+ replacement started. NEWS2: HR=1, RR=2, SBP=0, Temp=0, SpO2=0, AVPU=0. Total=3." + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 22, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 112, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 68, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 170, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 98, + "unit": "bpm", + "source": "Device" + }, + "note": "Steady improvement. Glucose still dropping, K+ being replaced. NEWS2: HR=1, RR=2, SBP=0, Temp=0, SpO2=0, AVPU=0. Total=3." + }, + { + "offsetMinutes": 170, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 21, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 170, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 114, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 170, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 70, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 170, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 170, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 170, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 182, + "type": "observation", + "data": { + "code": "GLUCOSE_MG_DL", + "value": 168, + "unit": "mg/dL", + "source": "Lab" + }, + "note": "3-hour labs \u2014 glucose near warning range, K+ recovering with replacement, lactate normalizing" + }, + { + "offsetMinutes": 182, + "type": "observation", + "data": { + "code": "POTASSIUM_MEQ_L", + "value": 3.6, + "unit": "mEq/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 182, + "type": "observation", + "data": { + "code": "LACTATE_MMOL_L", + "value": 1.2, + "unit": "mmol/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 182, + "type": "order_result", + "data": { + "orderDescription": "Basic metabolic panel, repeat", + "resultSummary": "Glucose 168 mg/dL (warning range, improving), K+ 3.6 mEq/L (recovering with replacement, now normal), CO2 20 mEq/L (normalizing), anion gap 14 (closed)" + }, + "note": "Anion gap closed \u2014 DKA resolving. K+ responding to replacement. Consider switching to D5 1/2NS when glucose <200." + }, + { + "offsetMinutes": 185, + "type": "medication", + "data": { + "drugName": "dextrose 5% in 0.45% sodium chloride (D5 1/2NS)", + "dose": 250, + "doseUnit": "mL/hr", + "route": "IV", + "administeredBy": "nurse-rn-4" + }, + "note": "Switched to D5 1/2NS as glucose approaching 200 mg/dL \u2014 prevents hypoglycemia while continuing insulin drip" + }, + { + "offsetMinutes": 190, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 95, + "unit": "bpm", + "source": "Device" + }, + "note": "Continued improvement. NEWS2: HR=1, RR=0, SBP=0, Temp=0, SpO2=0, AVPU=0. Total=1." + }, + { + "offsetMinutes": 190, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 20, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 190, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 116, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 190, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 72, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 190, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 190, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 190, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 93, + "unit": "bpm", + "source": "Device" + }, + "note": "Nearly normal vitals. NEWS2: HR=1, RR=0, SBP=0, Temp=0, SpO2=0, AVPU=0. Total=1." + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 19, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 118, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 74, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 90, + "unit": "bpm", + "source": "Device" + }, + "note": "Near baseline. NEWS2: HR=0, RR=0, SBP=0, Temp=0, SpO2=0, AVPU=0. Total=0." + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 18, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 120, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 76, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.9, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 270, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 88, + "unit": "bpm", + "source": "Device" + }, + "note": "Final vital cluster. NEWS2: HR=0, RR=0, SBP=0, Temp=0, SpO2=0, AVPU=0. Total=0." + }, + { + "offsetMinutes": 270, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 17, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 270, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 122, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 270, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 78, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 270, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 270, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 270, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 272, + "type": "observation", + "data": { + "code": "GLUCOSE_MG_DL", + "value": 124, + "unit": "mg/dL", + "source": "Lab" + }, + "note": "Final labs \u2014 glucose normal, K+ recovered to normal, lactate normal. DKA resolved." + }, + { + "offsetMinutes": 272, + "type": "observation", + "data": { + "code": "POTASSIUM_MEQ_L", + "value": 4.1, + "unit": "mEq/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 272, + "type": "observation", + "data": { + "code": "LACTATE_MMOL_L", + "value": 0.9, + "unit": "mmol/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 272, + "type": "order_result", + "data": { + "orderDescription": "Basic metabolic panel, repeat", + "resultSummary": "Glucose 124 mg/dL (normal), K+ 4.1 mEq/L (normal), CO2 22 mEq/L (normal), anion gap 10 (normal), BUN 18 mg/dL, Cr 1.1 mg/dL \u2014 DKA fully resolved" + }, + "note": "DKA resolved: anion gap closed, bicarbonate normalized, glucose normal. Plan to transition to subcutaneous insulin." + }, + { + "offsetMinutes": 268, + "type": "order", + "data": { + "orderType": "Lab", + "description": "Venous blood gas, repeat", + "orderedBy": "Dr. Priya Nair" + } + }, + { + "offsetMinutes": 273, + "type": "order_result", + "data": { + "orderDescription": "Venous blood gas, repeat", + "resultSummary": "pH 7.38 (normal), pCO2 38 mmHg (normal), HCO3 22 mEq/L (normal) \u2014 acidosis fully corrected" + }, + "note": "VBG normalized \u2014 supports transition from insulin drip to subcutaneous regimen" + }, + { + "offsetMinutes": 300, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 86, + "unit": "bpm", + "source": "Device" + }, + "note": "End of scenario \u2014 fully resolved. NEWS2: HR=0, RR=0, SBP=0, Temp=0, SpO2=0, AVPU=0. Total=0. Patient stable for step-down." + }, + { + "offsetMinutes": 300, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 16, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 300, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 124, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 300, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 78, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 300, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 300, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 300, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + } + ], + "expectedOutcomes": [ + { + "afterOffsetMinutes": 0, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 6, + "description": "NEWS2=6 on arrival (HR=2, RR=3, SBP=1). RR single param=3 triggers EMERGENCY despite total only 6." + }, + { + "afterOffsetMinutes": 0, + "type": "alert", + "alertType": "NEWS2_EMERGENCY", + "description": "NEWS2_EMERGENCY on arrival \u2014 RR 28 scores 3 (single parameter >=3 triggers emergency regardless of total)" + }, + { + "afterOffsetMinutes": 2, + "type": "alert", + "alertType": "CRITICAL_GLUCOSE", + "description": "Glucose 438 mg/dL \u2014 critically elevated (>180 mg/dL), consistent with DKA presentation" + }, + { + "afterOffsetMinutes": 2, + "type": "alert", + "alertType": "CRITICAL_POTASSIUM_HIGH", + "description": "Potassium 5.6 mEq/L \u2014 critically high (>5.5), caused by acidotic extracellular K+ shift in DKA" + }, + { + "afterOffsetMinutes": 2, + "type": "alert", + "alertType": "CRITICAL_LACTATE", + "description": "Lactate 2.4 mmol/L \u2014 critically elevated (>2.0), indicating tissue hypoperfusion" + }, + { + "afterOffsetMinutes": 30, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 7, + "description": "NEWS2 peaks at 7 (HR=2, RR=3, SBP=2) at T+30 when vitals are worst before treatment effect. RR single=3 -> EMERGENCY." + }, + { + "afterOffsetMinutes": 62, + "type": "alert", + "alertType": "CRITICAL_GLUCOSE", + "description": "Glucose 380 mg/dL \u2014 still critically high but trending down from 438. Insulin drip effect visible." + }, + { + "afterOffsetMinutes": 90, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 5, + "description": "NEWS2=5 at T+90 (HR=1, RR=3, SBP=1). Still EMERGENCY due to RR single=3 but total score improving." + }, + { + "afterOffsetMinutes": 105, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 4, + "description": "NEWS2 drops to 4 (HR=1, RR=2, SBP=1) \u2014 RR finally below 25, no more single param=3. No longer EMERGENCY." + }, + { + "afterOffsetMinutes": 122, + "type": "alert", + "alertType": "CRITICAL_POTASSIUM_LOW", + "description": "Potassium 3.2 mEq/L \u2014 WARNING range (3.0-3.4). Dangerous drop from 5.6 to 3.2 during insulin treatment as K+ shifts intracellularly. ECG shows hypokalemic changes." + }, + { + "afterOffsetMinutes": 122, + "type": "alert", + "alertType": "CRITICAL_GLUCOSE", + "description": "Glucose 245 mg/dL \u2014 still critically high (>180) but steadily improving from 438 to 245 over 2 hours" + }, + { + "afterOffsetMinutes": 150, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 3, + "description": "NEWS2=3 at T+150 (HR=1, RR=2). Improving \u2014 KCl replacement started." + }, + { + "afterOffsetMinutes": 182, + "type": "alert", + "alertType": "WARNING_POTASSIUM", + "description": "Potassium 3.6 mEq/L \u2014 recovered to normal range (3.5-5.0) with KCl replacement" + }, + { + "afterOffsetMinutes": 190, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 1, + "description": "NEWS2=1 at T+190 (HR=1 only). Near-normal vitals as DKA resolves." + }, + { + "afterOffsetMinutes": 240, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 0, + "description": "NEWS2=0 at T+240. All vitals normalized \u2014 HR 90, RR 18, SBP 120, SpO2 98." + }, + { + "afterOffsetMinutes": 272, + "type": "alert", + "alertType": "NORMAL_GLUCOSE", + "description": "Glucose 124 mg/dL \u2014 normalized (70-140 range). DKA fully resolved." + }, + { + "afterOffsetMinutes": 272, + "type": "alert", + "alertType": "NORMAL_POTASSIUM", + "description": "Potassium 4.1 mEq/L \u2014 fully normalized. V-curve complete: 5.6 (high) -> 3.2 (critical low) -> 4.1 (normal)." + } + ] +} diff --git a/VigilCare.Simulator/Scenarios/List/hypothermia-elderly-01.json b/VigilCare.Simulator/Scenarios/List/hypothermia-elderly-01.json new file mode 100644 index 0000000..cbaa5f7 --- /dev/null +++ b/VigilCare.Simulator/Scenarios/List/hypothermia-elderly-01.json @@ -0,0 +1,985 @@ +{ + "scenario": { + "id": "hypothermia-elderly-01", + "name": "Elderly Hypothermia with Bradycardia \u2014 Rewarming Recovery", + "description": "81-year-old female found outdoors in winter with core temp 33.5\u00b0C on arrival. Presents with hypothermia-induced bradycardia, hypotension, and altered mentation. Gradual active rewarming over 4 hours with warm IV fluids and warming blankets leads to full recovery of vitals and consciousness.", + "durationMinutes": 240, + "tags": [ + "hypothermia", + "bradycardia", + "elderly", + "rewarming", + "recovery", + "emergency", + "winter" + ] + }, + "patient": { + "firstName": "Margaret", + "lastName": "Thornton", + "dateOfBirth": "1945-01-14", + "gender": "Female" + }, + "encounter": { + "department": "Emergency", + "encounterType": "Emergency", + "attendingPhysician": "Dr. Elena Vasquez", + "roomBed": "ED-03A", + "admissionReason": "Found unresponsive outdoors in winter, hypothermia, bradycardia" + }, + "events": [ + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 48, + "unit": "bpm", + "source": "Device" + }, + "note": "Arrival \u2014 severe hypothermia, bradycardia, altered mentation. NEWS2=14 (EMERGENCY)" + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 10, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 96, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 54, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 33.5, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "SPO2", + "value": 93, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + }, + "note": "Nasal cannula 2L/min started on arrival" + }, + { + "offsetMinutes": 0, + "type": "order", + "data": { + "orderType": "Procedure", + "description": "Active warming protocol \u2014 forced-air warming blanket", + "orderedBy": "Dr. Elena Vasquez" + } + }, + { + "offsetMinutes": 5, + "type": "order_result", + "data": { + "orderDescription": "Active warming protocol \u2014 forced-air warming blanket", + "resultSummary": "Bair Hugger warming blanket applied, set to 43\u00b0C" + }, + "note": "Warming blanket order initiated" + }, + { + "offsetMinutes": 8, + "type": "medication", + "data": { + "drugName": "sodium chloride 0.9% (warmed to 40\u00b0C)", + "dose": 1000, + "doseUnit": "mL", + "route": "IV", + "administeredBy": "nurse-rn-2" + }, + "note": "Warm IV fluids \u2014 first bolus for active core rewarming and volume support" + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { + "code": "GLUCOSE_MG_DL", + "value": 74, + "unit": "mg/dL", + "source": "Lab" + }, + "note": "Initial labs \u2014 glucose low-normal, potassium borderline high (hypothermia shifts K+ extracellularly)" + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { + "code": "POTASSIUM_MEQ_L", + "value": 5.4, + "unit": "mEq/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { + "code": "LACTATE_MMOL_L", + "value": 2.3, + "unit": "mmol/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 47, + "unit": "bpm", + "source": "Device" + }, + "note": "Minimal change \u2014 rewarming just started. NEWS2=14 (EMERGENCY)" + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 10, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 94, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 53, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 33.7, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "SPO2", + "value": 93, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 46, + "unit": "bpm", + "source": "Device" + }, + "note": "Slow rewarming \u2014 temp barely above 34\u00b0C. SpO2 slightly improved with O2. NEWS2=13 (EMERGENCY)" + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 11, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 95, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 55, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 34.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "SPO2", + "value": 94, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 50, + "type": "medication", + "data": { + "drugName": "sodium chloride 0.9% (warmed to 40\u00b0C)", + "dose": 500, + "doseUnit": "mL", + "route": "IV", + "administeredBy": "nurse-rn-2" + }, + "note": "Second warm IV fluid bolus \u2014 continued active rewarming" + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 48, + "unit": "bpm", + "source": "Device" + }, + "note": "One hour into rewarming \u2014 temp 34.3\u00b0C, still bradycardic. NEWS2=13 (EMERGENCY)" + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 11, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 97, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 56, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 34.3, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "SPO2", + "value": 94, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 50, + "unit": "bpm", + "source": "Device" + }, + "note": "Temp approaching 35\u00b0C \u2014 HR and RR beginning to improve. NEWS2=12 (EMERGENCY)" + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 12, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 100, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 58, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 34.8, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "SPO2", + "value": 95, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 54, + "unit": "bpm", + "source": "Device" + }, + "note": "Temp crosses 35\u00b0C threshold \u2014 major improvement. HR normalizing, BP improving. NEWS2=7 (EMERGENCY \u2014 AVPU still 3)" + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 13, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 104, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 62, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 35.2, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "SPO2", + "value": 96, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 125, + "type": "observation", + "data": { + "code": "GLUCOSE_MG_DL", + "value": 88, + "unit": "mg/dL", + "source": "Lab" + }, + "note": "Repeat labs at T+120 \u2014 glucose normalizing, potassium trending down as rewarming drives K+ intracellularly" + }, + { + "offsetMinutes": 125, + "type": "observation", + "data": { + "code": "POTASSIUM_MEQ_L", + "value": 4.6, + "unit": "mEq/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 125, + "type": "observation", + "data": { + "code": "LACTATE_MMOL_L", + "value": 1.7, + "unit": "mmol/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 58, + "unit": "bpm", + "source": "Device" + }, + "note": "Significant recovery \u2014 patient responding to name, temp 35.8\u00b0C. NEWS2=4 (below WARNING threshold)" + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 14, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 108, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 65, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 35.8, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 62, + "unit": "bpm", + "source": "Device" + }, + "note": "Temp in normal range \u2014 all vitals normalizing. O2 weaned off. NEWS2=0" + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 15, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 112, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 68, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.2, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 65, + "unit": "bpm", + "source": "Device" + }, + "note": "Continued monitoring \u2014 stable, fully alert. NEWS2=0" + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 15, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 118, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 70, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.4, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 68, + "unit": "bpm", + "source": "Device" + }, + "note": "End of scenario \u2014 near-normal vitals, temp 36.5\u00b0C. Full recovery. NEWS2=0" + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 16, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 122, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 72, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.5, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + } + ], + "expectedOutcomes": [ + { + "afterOffsetMinutes": 0, + "type": "alert", + "alertType": "NEWS2_EMERGENCY", + "description": "NEWS2=14 on arrival: Temp 33.5\u21923, HR 48\u21921, SBP 96\u21922, RR 10\u21921, SpO2 93\u21922, AVPU 1\u21923, O2\u21922. Total \u22657 with multiple single-param 3s" + }, + { + "afterOffsetMinutes": 0, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 14, + "description": "Initial NEWS2 of 14 \u2014 critically elevated due to severe hypothermia with multi-organ effects" + }, + { + "afterOffsetMinutes": 0, + "type": "alert", + "alertType": "WARNING_HEART_RATE", + "description": "HR 48 bpm in warning range (41-50) \u2014 hypothermia-induced bradycardia" + }, + { + "afterOffsetMinutes": 0, + "type": "alert", + "alertType": "WARNING_POTASSIUM", + "description": "Potassium 5.4 mEq/L \u2014 borderline high (warning range 5.1-5.5) due to hypothermic cellular shifts" + }, + { + "afterOffsetMinutes": 90, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 12, + "description": "NEWS2 decreasing to 12 at T+90: Temp 34.8\u21923, HR 50\u21921, SBP 100\u21922, RR 12\u21920, SpO2 95\u21921, AVPU 1\u21923, O2\u21922. Still EMERGENCY" + }, + { + "afterOffsetMinutes": 120, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 7, + "description": "NEWS2 drops to 7 at T+120: Temp 35.2\u21921, HR 54\u21920, SBP 104\u21921, RR 13\u21920, SpO2 96\u21920, AVPU 1\u21923, O2\u21922. Still EMERGENCY due to AVPU=3" + }, + { + "afterOffsetMinutes": 120, + "type": "alert", + "alertType": "NEWS2_EMERGENCY", + "description": "NEWS2 still \u22657 at T+120 \u2014 AVPU single-param score of 3 alone triggers EMERGENCY even as other parameters normalize" + }, + { + "afterOffsetMinutes": 150, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 0, + "description": "NEWS2 drops to 4 at T+150: Temp 35.8\u21921, HR 58\u21920, SBP 108\u21921, RR 14\u21920, SpO2 97\u21920, AVPU 0\u21920, O2\u21922. Below WARNING threshold \u2014 recovery evident" + }, + { + "afterOffsetMinutes": 180, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 0, + "description": "NEWS2 drops to 0 at T+180: all vitals in normal range, O2 weaned off. Full recovery from hypothermia" + }, + { + "afterOffsetMinutes": 240, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 0, + "description": "NEWS2 remains 0 at end of scenario \u2014 sustained normothermia at 36.5\u00b0C with normal hemodynamics" + } + ] +} diff --git a/VigilCare.Simulator/Scenarios/List/medication-false-alarm-01.json b/VigilCare.Simulator/Scenarios/List/medication-false-alarm-01.json new file mode 100644 index 0000000..0d6a240 --- /dev/null +++ b/VigilCare.Simulator/Scenarios/List/medication-false-alarm-01.json @@ -0,0 +1,602 @@ +{ + "scenario": { + "id": "medication-false-alarm-01", + "name": "Medication-Induced False Alarm (Stable Patient on Beta-Blocker)", + "description": "45-year-old female on metoprolol (beta-blocker) with baseline low HR (~52 bpm) and controlled hypertension. Vitals fluctuate near warning thresholds but patient never truly deteriorates. Tests the system's alert behavior near boundaries and alert-fatigue patterns.", + "durationMinutes": 180, + "tags": ["false-alarm", "beta-blocker", "bradycardia", "boundary-testing", "alert-fatigue", "stable"] + }, + "patient": { + "firstName": "Sandra", + "lastName": "Kowalski", + "dateOfBirth": "1981-03-14", + "gender": "Female" + }, + "encounter": { + "department": "GeneralMedicine", + "encounterType": "Inpatient", + "attendingPhysician": "Dr. Helen Tranh", + "roomBed": "GM-214A", + "admissionReason": "Observation for controlled hypertension, medication titration" + }, + "events": [ + { + "offsetMinutes": 0, + "type": "observation", + "data": { "code": "HEART_RATE", "value": 54, "unit": "bpm", "source": "Device" }, + "note": "Baseline vitals — patient on scheduled metoprolol, resting comfortably. NEWS2=0" + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { "code": "RESP_RATE", "value": 14, "unit": "/min", "source": "Device" } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { "code": "SYSTOLIC_BP", "value": 136, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { "code": "DIASTOLIC_BP", "value": 78, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { "code": "TEMP_C", "value": 36.9, "unit": "°C", "source": "Manual" } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { "code": "SPO2", "value": 98, "unit": "%", "source": "Device" } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "Manual" } + }, + + { + "offsetMinutes": 0, + "type": "medication", + "data": { + "drugName": "metoprolol tartrate", + "dose": 25, + "doseUnit": "mg", + "route": "PO", + "administeredBy": "nurse-rn-12" + }, + "note": "Scheduled beta-blocker dose — expected to maintain low HR" + }, + + { + "offsetMinutes": 15, + "type": "observation", + "data": { "code": "HEART_RATE", "value": 50, "unit": "bpm", "source": "Device" }, + "note": "HR dips to lower boundary of warning range (41-50) post-dose. NEWS2=1 (HR=1)" + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { "code": "RESP_RATE", "value": 15, "unit": "/min", "source": "Device" } + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { "code": "SYSTOLIC_BP", "value": 134, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { "code": "DIASTOLIC_BP", "value": 76, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { "code": "TEMP_C", "value": 36.8, "unit": "°C", "source": "Manual" } + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { "code": "SPO2", "value": 98, "unit": "%", "source": "Device" } + }, + { + "offsetMinutes": 15, + "type": "observation", + "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "Manual" } + }, + + { + "offsetMinutes": 30, + "type": "observation", + "data": { "code": "HEART_RATE", "value": 49, "unit": "bpm", "source": "Device" }, + "note": "HR remains in warning range — metoprolol peak effect. NEWS2=1 (HR=1)" + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { "code": "RESP_RATE", "value": 14, "unit": "/min", "source": "Device" } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { "code": "SYSTOLIC_BP", "value": 132, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { "code": "DIASTOLIC_BP", "value": 75, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { "code": "TEMP_C", "value": 37.0, "unit": "°C", "source": "Manual" } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { "code": "SPO2", "value": 97, "unit": "%", "source": "Device" } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "Manual" } + }, + + { + "offsetMinutes": 45, + "type": "observation", + "data": { "code": "HEART_RATE", "value": 52, "unit": "bpm", "source": "Device" }, + "note": "HR recovers to normal range (51-90). NEWS2=0" + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { "code": "RESP_RATE", "value": 15, "unit": "/min", "source": "Device" } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { "code": "SYSTOLIC_BP", "value": 130, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { "code": "DIASTOLIC_BP", "value": 74, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { "code": "TEMP_C", "value": 36.9, "unit": "°C", "source": "Manual" } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { "code": "SPO2", "value": 98, "unit": "%", "source": "Device" } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "Manual" } + }, + + { + "offsetMinutes": 60, + "type": "observation", + "data": { "code": "HEART_RATE", "value": 51, "unit": "bpm", "source": "Device" }, + "note": "Routine check — all within normal limits. NEWS2=0" + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { "code": "RESP_RATE", "value": 14, "unit": "/min", "source": "Device" } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { "code": "SYSTOLIC_BP", "value": 133, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { "code": "DIASTOLIC_BP", "value": 76, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { "code": "TEMP_C", "value": 37.0, "unit": "°C", "source": "Manual" } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { "code": "SPO2", "value": 97, "unit": "%", "source": "Device" } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "Manual" } + }, + + { + "offsetMinutes": 75, + "type": "observation", + "data": { "code": "HEART_RATE", "value": 48, "unit": "bpm", "source": "Device" }, + "note": "HR dips again after position change — back into warning range. NEWS2=1 (HR=1)" + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { "code": "RESP_RATE", "value": 16, "unit": "/min", "source": "Device" } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { "code": "SYSTOLIC_BP", "value": 128, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { "code": "DIASTOLIC_BP", "value": 73, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { "code": "TEMP_C", "value": 36.8, "unit": "°C", "source": "Manual" } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { "code": "SPO2", "value": 98, "unit": "%", "source": "Device" } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "Manual" } + }, + + { + "offsetMinutes": 90, + "type": "observation", + "data": { "code": "HEART_RATE", "value": 53, "unit": "bpm", "source": "Device" }, + "note": "HR recovers again — normal range. NEWS2=0" + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { "code": "RESP_RATE", "value": 15, "unit": "/min", "source": "Device" } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { "code": "SYSTOLIC_BP", "value": 131, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { "code": "DIASTOLIC_BP", "value": 75, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { "code": "TEMP_C", "value": 37.0, "unit": "°C", "source": "Manual" } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { "code": "SPO2", "value": 97, "unit": "%", "source": "Device" } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "Manual" } + }, + + { + "offsetMinutes": 105, + "type": "observation", + "data": { "code": "HEART_RATE", "value": 55, "unit": "bpm", "source": "Device" }, + "note": "Stable — metoprolol wearing off slightly before next dose. NEWS2=0" + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { "code": "RESP_RATE", "value": 14, "unit": "/min", "source": "Device" } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { "code": "SYSTOLIC_BP", "value": 130, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { "code": "DIASTOLIC_BP", "value": 74, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { "code": "TEMP_C", "value": 36.9, "unit": "°C", "source": "Manual" } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { "code": "SPO2", "value": 98, "unit": "%", "source": "Device" } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "Manual" } + }, + + { + "offsetMinutes": 120, + "type": "medication", + "data": { + "drugName": "metoprolol tartrate", + "dose": 25, + "doseUnit": "mg", + "route": "PO", + "administeredBy": "nurse-rn-12" + }, + "note": "Second scheduled metoprolol dose" + }, + + { + "offsetMinutes": 120, + "type": "observation", + "data": { "code": "HEART_RATE", "value": 52, "unit": "bpm", "source": "Device" }, + "note": "Pre-dose vitals taken with medication. NEWS2=0" + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { "code": "RESP_RATE", "value": 15, "unit": "/min", "source": "Device" } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { "code": "SYSTOLIC_BP", "value": 126, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { "code": "DIASTOLIC_BP", "value": 72, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { "code": "TEMP_C", "value": 37.0, "unit": "°C", "source": "Manual" } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { "code": "SPO2", "value": 97, "unit": "%", "source": "Device" } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "Manual" } + }, + + { + "offsetMinutes": 135, + "type": "observation", + "data": { "code": "HEART_RATE", "value": 48, "unit": "bpm", "source": "Device" }, + "note": "Post-dose HR dip — second metoprolol taking effect. NEWS2=1 (HR=1)" + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { "code": "RESP_RATE", "value": 14, "unit": "/min", "source": "Device" } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { "code": "SYSTOLIC_BP", "value": 112, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { "code": "DIASTOLIC_BP", "value": 68, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { "code": "TEMP_C", "value": 36.8, "unit": "°C", "source": "Manual" } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { "code": "SPO2", "value": 98, "unit": "%", "source": "Device" } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "Manual" } + }, + + { + "offsetMinutes": 150, + "type": "observation", + "data": { "code": "HEART_RATE", "value": 47, "unit": "bpm", "source": "Device" }, + "note": "Lowest HR of scenario — SBP also drifts near warning boundary. NEWS2=2 (HR=1, SBP=1)" + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { "code": "RESP_RATE", "value": 15, "unit": "/min", "source": "Device" } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { "code": "SYSTOLIC_BP", "value": 110, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { "code": "DIASTOLIC_BP", "value": 66, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { "code": "TEMP_C", "value": 36.9, "unit": "°C", "source": "Manual" } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { "code": "SPO2", "value": 97, "unit": "%", "source": "Device" } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "Manual" } + }, + + { + "offsetMinutes": 165, + "type": "observation", + "data": { "code": "HEART_RATE", "value": 50, "unit": "bpm", "source": "Device" }, + "note": "HR still in warning but recovering, SBP back to normal. NEWS2=1 (HR=1)" + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { "code": "RESP_RATE", "value": 14, "unit": "/min", "source": "Device" } + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { "code": "SYSTOLIC_BP", "value": 114, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { "code": "DIASTOLIC_BP", "value": 70, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { "code": "TEMP_C", "value": 37.0, "unit": "°C", "source": "Manual" } + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { "code": "SPO2", "value": 98, "unit": "%", "source": "Device" } + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "Manual" } + }, + + { + "offsetMinutes": 180, + "type": "observation", + "data": { "code": "HEART_RATE", "value": 52, "unit": "bpm", "source": "Device" }, + "note": "End of scenario — patient stable, HR back in normal range. NEWS2=0" + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { "code": "RESP_RATE", "value": 15, "unit": "/min", "source": "Device" } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { "code": "SYSTOLIC_BP", "value": 118, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { "code": "DIASTOLIC_BP", "value": 72, "unit": "mmHg", "source": "Device" } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { "code": "TEMP_C", "value": 36.9, "unit": "°C", "source": "Manual" } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { "code": "SPO2", "value": 97, "unit": "%", "source": "Device" } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "Manual" } + } + ], + "expectedOutcomes": [ + { + "afterOffsetMinutes": 15, + "type": "alert", + "alertType": "WARNING_HEART_RATE", + "description": "HR drops to 50 bpm (warning range 41-50) after first metoprolol dose — expected medication effect" + }, + { + "afterOffsetMinutes": 15, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 1, + "description": "NEWS2=1 (HR=1 only) — below WARNING threshold of 5, no escalation needed" + }, + { + "afterOffsetMinutes": 30, + "type": "alert", + "alertType": "WARNING_HEART_RATE", + "description": "HR 49 bpm — sustained warning-range bradycardia during metoprolol peak effect" + }, + { + "afterOffsetMinutes": 45, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 0, + "description": "NEWS2=0 — HR recovers to 52 bpm (normal range), all parameters normal" + }, + { + "afterOffsetMinutes": 75, + "type": "alert", + "alertType": "WARNING_HEART_RATE", + "description": "HR dips to 48 bpm after position change — transient, self-resolving" + }, + { + "afterOffsetMinutes": 135, + "type": "alert", + "alertType": "WARNING_HEART_RATE", + "description": "HR 48 bpm after second metoprolol dose — repeat of earlier pattern" + }, + { + "afterOffsetMinutes": 150, + "type": "alert", + "alertType": "WARNING_HEART_RATE", + "description": "HR 47 bpm — lowest point of scenario, still within warning (not critical)" + }, + { + "afterOffsetMinutes": 150, + "type": "alert", + "alertType": "WARNING_SYSTOLIC_BP", + "description": "SBP 110 mmHg — briefly enters warning range (101-110), self-resolves by T+165" + }, + { + "afterOffsetMinutes": 150, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 2, + "description": "Peak NEWS2=2 (HR=1 + SBP=1) — maximum score in scenario, well below WARNING threshold of 5" + }, + { + "afterOffsetMinutes": 165, + "type": "alert", + "alertType": "WARNING_HEART_RATE", + "description": "HR 50 bpm — still in warning range but trending upward toward recovery" + }, + { + "afterOffsetMinutes": 180, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 0, + "description": "NEWS2=0 at end of scenario — patient fully stable, no active alerts. Confirms no escalation occurred." + } + ] +} \ No newline at end of file diff --git a/VigilCare.Simulator/Scenarios/List/post-op-hemorrhage-01.json b/VigilCare.Simulator/Scenarios/List/post-op-hemorrhage-01.json new file mode 100644 index 0000000..e517658 --- /dev/null +++ b/VigilCare.Simulator/Scenarios/List/post-op-hemorrhage-01.json @@ -0,0 +1,1685 @@ +{ + "scenario": { + "id": "post-op-hemorrhage-01", + "name": "Post-Op Hemorrhagic Shock", + "description": "58-year-old male, 2 hours post open abdominal surgery (colectomy), develops occult intra-abdominal hemorrhage over 4 hours. Classic hemorrhagic shock progression: compensatory tachycardia gives way to falling blood pressure, dropping SpO2, and altered consciousness. Temperature remains relatively stable throughout. Fluid and blood product resuscitation initiated at T+180 with partial stabilization by scenario end.", + "durationMinutes": 240, + "tags": [ + "hemorrhage", + "post-op", + "surgery", + "shock", + "deterioration", + "transfusion", + "rapid-response" + ] + }, + "patient": { + "firstName": "Gerald", + "lastName": "Kowalski", + "dateOfBirth": "1968-03-14", + "gender": "Male" + }, + "encounter": { + "department": "Surgery", + "encounterType": "Inpatient", + "attendingPhysician": "Dr. Anita Sharma", + "roomBed": "SURG-4A-12", + "admissionReason": "Post-operative monitoring following open colectomy for sigmoid diverticular disease" + }, + "events": [ + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 74, + "unit": "bpm", + "source": "Device" + }, + "note": "Post-op baseline \u2014 patient arrived from PACU, awake and oriented, incision clean and dry" + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 14, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 128, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 76, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.8, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + }, + "note": "Nasal cannula 2L/min \u2014 standard post-op order" + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 72, + "unit": "bpm", + "source": "Device" + }, + "note": "Stable post-op recovery, patient resting comfortably" + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 13, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 130, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 78, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.7, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "LACTATE_MMOL_L", + "value": 1.2, + "unit": "mmol/L", + "source": "Lab" + }, + "note": "Routine post-op labs \u2014 lactate within normal limits" + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "POTASSIUM_MEQ_L", + "value": 4.1, + "unit": "mEq/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "GLUCOSE_MG_DL", + "value": 138, + "unit": "mg/dL", + "source": "Lab" + } + }, + { + "offsetMinutes": 25, + "type": "order", + "data": { + "orderType": "Lab", + "description": "Post-op CBC and metabolic panel", + "orderedBy": "Dr. Anita Sharma" + } + }, + { + "offsetMinutes": 30, + "type": "order_result", + "data": { + "orderDescription": "Post-op CBC and metabolic panel", + "resultSummary": "Hgb 12.8 g/dL, Hct 38.4%, WBC 9.2 K/uL, platelets 198 K/uL, BMP within normal limits. Expected post-operative values." + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 76, + "unit": "bpm", + "source": "Device" + }, + "note": "Normal post-op fluctuation" + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 14, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 126, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 74, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.9, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 80, + "unit": "bpm", + "source": "Device" + }, + "note": "End of stable phase \u2014 subtle upward HR drift begins" + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 15, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 125, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 73, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.8, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 85, + "unit": "bpm", + "source": "Device" + }, + "note": "Early compensatory tachycardia \u2014 occult bleeding suspected in hindsight" + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 16, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 120, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 70, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.7, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 88, + "unit": "bpm", + "source": "Device" + }, + "note": "HR rising \u2014 still within normal range but trend is concerning" + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 17, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 118, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 68, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.8, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "SPO2", + "value": 96, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 95, + "unit": "bpm", + "source": "Device" + }, + "note": "HR now in warning range (91-110) \u2014 compensatory tachycardia accelerating" + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 18, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 112, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 66, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.7, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "SPO2", + "value": 96, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 102, + "unit": "bpm", + "source": "Device" + }, + "note": "Hemorrhagic shock Class II \u2014 tachycardia with early hypotension" + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 20, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 105, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 62, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.9, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "SPO2", + "value": 95, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "LACTATE_MMOL_L", + "value": 2.4, + "unit": "mmol/L", + "source": "Lab" + }, + "note": "Stat labs drawn \u2014 lactate elevated above normal, indicating tissue hypoperfusion" + }, + { + "offsetMinutes": 122, + "type": "observation", + "data": { + "code": "POTASSIUM_MEQ_L", + "value": 4.3, + "unit": "mEq/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 121, + "type": "observation", + "data": { + "code": "GLUCOSE_MG_DL", + "value": 152, + "unit": "mg/dL", + "source": "Lab" + } + }, + { + "offsetMinutes": 115, + "type": "order", + "data": { + "orderType": "Lab", + "description": "Stat CBC and metabolic panel", + "orderedBy": "Dr. Anita Sharma" + } + }, + { + "offsetMinutes": 120, + "type": "order_result", + "data": { + "orderDescription": "Stat CBC and metabolic panel", + "resultSummary": "Hgb 10.1 g/dL (down from 12.8), Hct 30.3%, WBC 11.8 K/uL, platelets 172 K/uL, lactate 2.4 mmol/L elevated. Hemoglobin drop of 2.7 g/dL in 90 minutes \u2014 active hemorrhage suspected." + }, + "note": "Significant hemoglobin drop triggers surgical team notification" + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 110, + "unit": "bpm", + "source": "Device" + }, + "note": "Rapid deterioration \u2014 hemorrhagic shock Class II-III transition" + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 22, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 98, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 58, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.8, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "SPO2", + "value": 94, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 118, + "unit": "bpm", + "source": "Device" + }, + "note": "Class III hemorrhagic shock \u2014 critical HR with hypotension" + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 24, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 92, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 54, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.7, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "SPO2", + "value": 93, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 160, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 124, + "unit": "bpm", + "source": "Device" + }, + "note": "Peak deterioration \u2014 patient confused, diaphoretic, pale. Rapid response team called." + }, + { + "offsetMinutes": 160, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 26, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 160, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 86, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 160, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 50, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 160, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.6, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 160, + "type": "observation", + "data": { + "code": "SPO2", + "value": 91, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 160, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + }, + "note": "AVPU=1 (Voice) \u2014 patient responding only to verbal stimuli" + }, + { + "offsetMinutes": 160, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 170, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 128, + "unit": "bpm", + "source": "Device" + }, + "note": "Sustained critical state \u2014 awaiting blood bank crossmatch" + }, + { + "offsetMinutes": 170, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 27, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 170, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 84, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 170, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 48, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 170, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.5, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 170, + "type": "observation", + "data": { + "code": "SPO2", + "value": 90, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 170, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 170, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 180, + "type": "medication", + "data": { + "drugName": "Normal Saline 0.9%", + "dose": 1000, + "doseUnit": "mL", + "route": "IV", + "administeredBy": "nurse-rn-7" + }, + "note": "Aggressive fluid resuscitation initiated \u2014 wide-bore IV access x2" + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 130, + "unit": "bpm", + "source": "Device" + }, + "note": "Nadir \u2014 resuscitation started, blood products being crossmatched" + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 28, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 82, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 46, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.4, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "SPO2", + "value": 89, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "LACTATE_MMOL_L", + "value": 4.1, + "unit": "mmol/L", + "source": "Lab" + }, + "note": "Severely elevated lactate \u2014 significant tissue hypoperfusion" + }, + { + "offsetMinutes": 175, + "type": "order", + "data": { + "orderType": "Lab", + "description": "Stat CBC, type and crossmatch", + "orderedBy": "Dr. Anita Sharma" + } + }, + { + "offsetMinutes": 180, + "type": "order_result", + "data": { + "orderDescription": "Stat CBC, type and crossmatch", + "resultSummary": "Hgb 7.8 g/dL (critical \u2014 down from 10.1 at T+120), Hct 23.4%, platelets 155 K/uL, lactate 4.1 mmol/L. Type and crossmatch: A-positive, 4 units pRBC ordered STAT." + }, + "note": "Critical hemoglobin triggers massive transfusion protocol consideration" + }, + { + "offsetMinutes": 190, + "type": "medication", + "data": { + "drugName": "Packed Red Blood Cells", + "dose": 1, + "doseUnit": "unit", + "route": "IV", + "administeredBy": "nurse-rn-7" + }, + "note": "First unit pRBC \u2014 rapid infuser, transfusion started" + }, + { + "offsetMinutes": 190, + "type": "medication", + "data": { + "drugName": "Normal Saline 0.9%", + "dose": 500, + "doseUnit": "mL", + "route": "IV", + "administeredBy": "nurse-rn-12" + }, + "note": "Concurrent crystalloid via second IV line" + }, + { + "offsetMinutes": 195, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 126, + "unit": "bpm", + "source": "Device" + }, + "note": "Early response to volume resuscitation \u2014 HR beginning to decrease" + }, + { + "offsetMinutes": 195, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 26, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 195, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 86, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 195, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 50, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 195, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.5, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 195, + "type": "observation", + "data": { + "code": "SPO2", + "value": 90, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 195, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 195, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 205, + "type": "medication", + "data": { + "drugName": "Packed Red Blood Cells", + "dose": 1, + "doseUnit": "unit", + "route": "IV", + "administeredBy": "nurse-rn-7" + }, + "note": "Second unit pRBC started" + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 118, + "unit": "bpm", + "source": "Device" + }, + "note": "Responding to transfusion \u2014 HR decreasing, BP improving" + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 24, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 94, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 56, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.6, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "SPO2", + "value": 92, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 220, + "type": "medication", + "data": { + "drugName": "Tranexamic Acid", + "dose": 1, + "doseUnit": "g", + "route": "IV", + "administeredBy": "nurse-rn-7" + }, + "note": "TXA administered to reduce surgical bleeding" + }, + { + "offsetMinutes": 225, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 112, + "unit": "bpm", + "source": "Device" + }, + "note": "Continued improvement with ongoing transfusion" + }, + { + "offsetMinutes": 225, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 22, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 225, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 100, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 225, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 60, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 225, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.7, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 225, + "type": "observation", + "data": { + "code": "SPO2", + "value": 93, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 225, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + }, + "note": "Patient more alert \u2014 responding appropriately to questions" + }, + { + "offsetMinutes": 225, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 230, + "type": "observation", + "data": { + "code": "LACTATE_MMOL_L", + "value": 3.2, + "unit": "mmol/L", + "source": "Lab" + }, + "note": "Lactate trending down from 4.1 \u2014 tissue perfusion improving with resuscitation" + }, + { + "offsetMinutes": 225, + "type": "order", + "data": { + "orderType": "Lab", + "description": "Post-transfusion CBC and lactate", + "orderedBy": "Dr. Anita Sharma" + } + }, + { + "offsetMinutes": 230, + "type": "order_result", + "data": { + "orderDescription": "Post-transfusion CBC and lactate", + "resultSummary": "Hgb 9.2 g/dL (up from 7.8, 2 units pRBC given), Hct 27.6%, lactate 3.2 mmol/L (down from 4.1). Surgical team planning return to OR for exploration and hemostasis." + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 106, + "unit": "bpm", + "source": "Device" + }, + "note": "End of scenario \u2014 partial stabilization, patient being prepared for return to OR" + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 21, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 104, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 62, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.7, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "SPO2", + "value": 94, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + } + ], + "expectedOutcomes": [ + { + "afterOffsetMinutes": 105, + "type": "alert", + "alertType": "WARNING_HEART_RATE", + "description": "HR enters warning range at 95 bpm (91-110 \u2192 NEWS2 HR=1)" + }, + { + "afterOffsetMinutes": 120, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 5, + "description": "NEWS2 reaches 5 at T+120 (HR=1, SBP=1, SpO2=1, O2=2) \u2192 WARNING threshold" + }, + { + "afterOffsetMinutes": 120, + "type": "alert", + "alertType": "NEWS2_WARNING", + "description": "NEWS2 WARNING triggered \u2014 score 5 (HR 102=1, SBP 105=1, SpO2 95=1, O2=2)" + }, + { + "afterOffsetMinutes": 135, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 7, + "description": "NEWS2 reaches 8 at T+135 (HR=1, RR=2, SBP=2, SpO2=1, O2=2) \u2192 EMERGENCY threshold" + }, + { + "afterOffsetMinutes": 135, + "type": "alert", + "alertType": "NEWS2_EMERGENCY", + "description": "NEWS2 EMERGENCY triggered \u2014 score 8 (HR 110=1, RR 22=2, SBP 98=2, SpO2 94=1, O2=2)" + }, + { + "afterOffsetMinutes": 135, + "type": "alert", + "alertType": "CRITICAL_SYSTOLIC_BP", + "description": "SBP drops to 98 mmHg \u2014 enters critical range (\u2264100)" + }, + { + "afterOffsetMinutes": 130, + "type": "alert", + "alertType": "RAPID_DETERIORATION", + "description": "Rapid HR increase (74\u2192110 over 135 min) and SBP decrease (128\u219298) detected between T+120 and T+150" + }, + { + "afterOffsetMinutes": 160, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 16, + "description": "NEWS2 peaks at 16 (HR=2, RR=3, SBP=3, SpO2=3, AVPU=3, O2=2) \u2014 multiple single-parameter score=3 triggers" + }, + { + "afterOffsetMinutes": 150, + "type": "alert", + "alertType": "CRITICAL_SPO2", + "description": "SpO2 drops to 93% at T+150, enters critical range (\u226493)" + } + ] +} diff --git a/VigilCare.Simulator/Scenarios/List/respiratory-failure-asthma-01.json b/VigilCare.Simulator/Scenarios/List/respiratory-failure-asthma-01.json new file mode 100644 index 0000000..977b34f --- /dev/null +++ b/VigilCare.Simulator/Scenarios/List/respiratory-failure-asthma-01.json @@ -0,0 +1,1298 @@ +{ + "scenario": { + "id": "respiratory-failure-asthma-01", + "name": "Pediatric Asthma Exacerbation Progressing to Respiratory Failure", + "description": "14-year-old male presenting to ED with severe asthma attack, progressive respiratory failure over 2 hours despite nebulized bronchodilators. Rising RR, falling SpO2, compensatory tachycardia with escalation from nasal cannula to non-rebreather mask and IV magnesium sulfate before stabilization.", + "durationMinutes": 120, + "tags": [ + "asthma", + "pediatric", + "respiratory-failure", + "ed", + "deterioration", + "supplemental-o2" + ] + }, + "patient": { + "firstName": "Ethan", + "lastName": "Morales", + "dateOfBirth": "2012-03-15", + "gender": "Male" + }, + "encounter": { + "department": "Emergency", + "encounterType": "Emergency", + "attendingPhysician": "Dr. Sarah Okonkwo", + "roomBed": "ED-03A", + "admissionReason": "Severe asthma exacerbation, acute respiratory distress, wheezing, accessory muscle use" + }, + "events": [ + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 105, + "unit": "bpm", + "source": "Device" + }, + "note": "Triage vitals \u2014 arrives in acute respiratory distress, audible wheezing, accessory muscle use. NEWS2: HR=1 RR=3 SBP=0 Temp=0 SpO2=2 AVPU=0 = 6, single param 3 (RR) \u2192 EMERGENCY" + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 26, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 118, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 74, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.1, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "SPO2", + "value": 93, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 0, + "type": "order", + "data": { + "orderType": "Lab", + "description": "Peak expiratory flow (PEF)", + "orderedBy": "Dr. Sarah Okonkwo" + } + }, + { + "offsetMinutes": 3, + "type": "order_result", + "data": { + "orderDescription": "Peak expiratory flow (PEF)", + "resultSummary": "PEF 120 L/min (predicted 380 L/min for age/height) \u2014 32% predicted, severe obstruction" + }, + "note": "Severely reduced airflow confirms acute severe asthma" + }, + { + "offsetMinutes": 5, + "type": "medication", + "data": { + "drugName": "albuterol nebulizer", + "dose": 2.5, + "doseUnit": "mg", + "route": "Nebulized", + "administeredBy": "nurse-rn-2" + }, + "note": "First-line bronchodilator \u2014 continuous nebulization initiated" + }, + { + "offsetMinutes": 10, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 102, + "unit": "bpm", + "source": "Device" + }, + "note": "Slight improvement post-albuterol. NEWS2: HR=1 RR=2 SBP=0 Temp=0 SpO2=1 AVPU=0 = 4" + }, + { + "offsetMinutes": 10, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 24, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 10, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 117, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 10, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 73, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 10, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.1, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 10, + "type": "observation", + "data": { + "code": "SPO2", + "value": 94, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 10, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 15, + "type": "medication", + "data": { + "drugName": "albuterol nebulizer", + "dose": 2.5, + "doseUnit": "mg", + "route": "Nebulized", + "administeredBy": "nurse-rn-2" + }, + "note": "Second nebulized albuterol \u2014 incomplete response to first dose" + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 108, + "unit": "bpm", + "source": "Device" + }, + "note": "Worsening despite second neb. NEWS2: HR=1 RR=3 SBP=0 Temp=0 SpO2=2 AVPU=0 = 6, single param 3 (RR) \u2192 EMERGENCY" + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 27, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 119, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 74, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "SPO2", + "value": 92, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 25, + "type": "medication", + "data": { + "drugName": "ipratropium bromide nebulizer", + "dose": 0.5, + "doseUnit": "mg", + "route": "Nebulized", + "administeredBy": "nurse-rn-2" + }, + "note": "Added anticholinergic for poor response to albuterol alone" + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 113, + "unit": "bpm", + "source": "Device" + }, + "note": "Continued decline \u2014 HR now critical (\u2265111). NEWS2: HR=2 RR=3 SBP=0 Temp=0 SpO2=3 AVPU=0 = 8 \u2192 EMERGENCY" + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 28, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 117, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 73, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.1, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "SPO2", + "value": 91, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 30, + "type": "order", + "data": { + "orderType": "Lab", + "description": "Venous blood gas", + "orderedBy": "Dr. Sarah Okonkwo" + } + }, + { + "offsetMinutes": 35, + "type": "order_result", + "data": { + "orderDescription": "Venous blood gas", + "resultSummary": "pH 7.36, pCO2 42 mmHg, HCO3 24 \u2014 normal pCO2 in setting of tachypnea suggests impending respiratory failure (should be low if compensating)" + }, + "note": "Ominous VBG \u2014 normal pCO2 with RR 28 indicates respiratory muscle fatigue" + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 118, + "unit": "bpm", + "source": "Device" + }, + "note": "Worsening tachycardia and desaturation. NEWS2: HR=2 RR=3 SBP=0 Temp=0 SpO2=3 AVPU=0 = 8 \u2192 EMERGENCY" + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 30, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 116, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 72, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "SPO2", + "value": 90, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 45, + "type": "medication", + "data": { + "drugName": "methylprednisolone sodium succinate", + "dose": 60, + "doseUnit": "mg", + "route": "IV", + "administeredBy": "nurse-rn-2" + }, + "note": "IV corticosteroid \u2014 systemic anti-inflammatory for severe exacerbation" + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + }, + "note": "Nasal cannula 4L/min started \u2014 SpO2 90% on room air unacceptable" + }, + { + "offsetMinutes": 50, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 115, + "unit": "bpm", + "source": "Device" + }, + "note": "Brief SpO2 improvement on nasal cannula O2. NEWS2: HR=2 RR=3 SBP=0 Temp=0 SpO2=2 AVPU=0 O2=2 = 9 \u2192 EMERGENCY" + }, + { + "offsetMinutes": 50, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 28, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 50, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 116, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 50, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 73, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 50, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.1, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 50, + "type": "observation", + "data": { + "code": "SPO2", + "value": 93, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 50, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 50, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 120, + "unit": "bpm", + "source": "Device" + }, + "note": "Deteriorating on O2 \u2014 bronchospasm overcoming supplemental O2 benefit. NEWS2: HR=2 RR=3 SBP=0 Temp=0 SpO2=3 AVPU=0 O2=2 = 10 \u2192 EMERGENCY" + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 30, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 114, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 71, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "SPO2", + "value": 91, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 65, + "type": "medication", + "data": { + "drugName": "albuterol nebulizer", + "dose": 2.5, + "doseUnit": "mg", + "route": "Nebulized", + "administeredBy": "nurse-rn-2" + }, + "note": "Third nebulized albuterol \u2014 back-to-back dosing for refractory bronchospasm" + }, + { + "offsetMinutes": 70, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 124, + "unit": "bpm", + "source": "Device" + }, + "note": "No improvement from third neb. NEWS2: HR=2 RR=3 SBP=0 Temp=0 SpO2=3 AVPU=0 O2=2 = 10 \u2192 EMERGENCY" + }, + { + "offsetMinutes": 70, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 32, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 70, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 113, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 70, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 70, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 70, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.1, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 70, + "type": "observation", + "data": { + "code": "SPO2", + "value": 89, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 70, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 70, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 80, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 126, + "unit": "bpm", + "source": "Device" + }, + "note": "Progressive failure \u2014 approaching critical thresholds. NEWS2: HR=2 RR=3 SBP=0 Temp=0 SpO2=3 AVPU=0 O2=2 = 10 \u2192 EMERGENCY" + }, + { + "offsetMinutes": 80, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 34, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 80, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 112, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 80, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 70, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 80, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 80, + "type": "observation", + "data": { + "code": "SPO2", + "value": 88, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 80, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 80, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 80, + "type": "order", + "data": { + "orderType": "Imaging", + "description": "Chest X-ray portable AP", + "orderedBy": "Dr. Sarah Okonkwo" + } + }, + { + "offsetMinutes": 85, + "type": "order_result", + "data": { + "orderDescription": "Chest X-ray portable AP", + "resultSummary": "Hyperinflated lung fields bilaterally, no focal consolidation or pneumothorax, no pleural effusion" + }, + "note": "CXR confirms air trapping consistent with severe bronchospasm, no pneumonia or PTX" + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 128, + "unit": "bpm", + "source": "Device" + }, + "note": "Critical \u2014 escalation to non-rebreather mask at 15L/min. NEWS2: HR=2 RR=3 SBP=1 Temp=0 SpO2=3 AVPU=0 O2=2 = 11 \u2192 EMERGENCY" + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 36, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 110, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 68, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.1, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "SPO2", + "value": 87, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 88, + "type": "order", + "data": { + "orderType": "Procedure", + "description": "O2 delivery escalation", + "orderedBy": "Dr. Sarah Okonkwo" + } + }, + { + "offsetMinutes": 93, + "type": "order_result", + "data": { + "orderDescription": "O2 delivery escalation", + "resultSummary": "Changed from nasal cannula 4L/min to non-rebreather mask 15L/min" + }, + "note": "Escalation of respiratory support \u2014 failing nasal cannula" + }, + { + "offsetMinutes": 95, + "type": "medication", + "data": { + "drugName": "magnesium sulfate", + "dose": 40, + "doseUnit": "mg/kg", + "route": "IV", + "administeredBy": "nurse-rn-2" + }, + "note": "IV magnesium sulfate bolus for refractory severe asthma \u2014 smooth muscle relaxation" + }, + { + "offsetMinutes": 100, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 131, + "unit": "bpm", + "source": "Device" + }, + "note": "Peak deterioration \u2014 HR now \u2265131. NEWS2: HR=3 RR=3 SBP=1 Temp=0 SpO2=3 AVPU=0 O2=2 = 12 \u2192 EMERGENCY (peak score)" + }, + { + "offsetMinutes": 100, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 37, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 100, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 108, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 100, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 66, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 100, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 100, + "type": "observation", + "data": { + "code": "SPO2", + "value": 86, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 100, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 100, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 98, + "type": "order", + "data": { + "orderType": "Lab", + "description": "Repeat venous blood gas", + "orderedBy": "Dr. Sarah Okonkwo" + } + }, + { + "offsetMinutes": 103, + "type": "order_result", + "data": { + "orderDescription": "Repeat venous blood gas", + "resultSummary": "pH 7.31, pCO2 52 mmHg, HCO3 25 \u2014 respiratory acidosis, CO2 retention indicating ventilatory failure" + }, + "note": "Rising pCO2 confirms respiratory muscle fatigue \u2014 intubation readiness ordered" + }, + { + "offsetMinutes": 105, + "type": "medication", + "data": { + "drugName": "albuterol nebulizer", + "dose": 2.5, + "doseUnit": "mg", + "route": "Nebulized", + "administeredBy": "nurse-rn-2" + }, + "note": "Continuous nebulization resumed while magnesium takes effect" + }, + { + "offsetMinutes": 110, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 122, + "unit": "bpm", + "source": "Device" + }, + "note": "Treatment response \u2014 MgSO4 + NRB + steroids taking effect. NEWS2: HR=2 RR=3 SBP=0 Temp=0 SpO2=3 AVPU=0 O2=2 = 10 \u2192 EMERGENCY (improving)" + }, + { + "offsetMinutes": 110, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 31, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 110, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 112, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 110, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 70, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 110, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.1, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 110, + "type": "observation", + "data": { + "code": "SPO2", + "value": 91, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 110, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 110, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 115, + "type": "observation", + "data": { + "code": "POTASSIUM_MEQ_L", + "value": 3.8, + "unit": "mEq/L", + "source": "Lab" + }, + "note": "Potassium checked \u2014 albuterol can cause hypokalemia; level acceptable" + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 116, + "unit": "bpm", + "source": "Device" + }, + "note": "Stabilization \u2014 aggressive treatment working but still critical. NEWS2: HR=2 RR=3 SBP=0 Temp=0 SpO2=2 AVPU=0 O2=2 = 9 \u2192 EMERGENCY. Patient to be transferred to PICU for monitoring." + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 26, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 114, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 72, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "SPO2", + "value": 93, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + } + ], + "expectedOutcomes": [ + { + "afterOffsetMinutes": 0, + "type": "alert", + "alertType": "NEWS2_EMERGENCY", + "description": "NEWS2 = 6 at triage with RR score 3 (single parameter = 3 triggers EMERGENCY). Patient arrives already in emergency state." + }, + { + "afterOffsetMinutes": 0, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 6, + "description": "NEWS2 = 6 at arrival: HR=1(105) + RR=3(26) + SBP=0(118) + Temp=0(37.1) + SpO2=2(93) + AVPU=0" + }, + { + "afterOffsetMinutes": 20, + "type": "alert", + "alertType": "RAPID_DETERIORATION", + "description": "SpO2 drops from 94% (T+10) to 92% (T+20) \u2014 rapid decline after brief post-albuterol improvement" + }, + { + "afterOffsetMinutes": 30, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 8, + "description": "NEWS2 = 8 at T+30: HR=2(113) + RR=3(28) + SBP=0(117) + Temp=0(37.1) + SpO2=3(91) + AVPU=0 \u2014 worsening despite bronchodilators" + }, + { + "afterOffsetMinutes": 50, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 9, + "description": "NEWS2 = 9 at T+50: HR=2(115) + RR=3(28) + SBP=0(116) + Temp=0(37.1) + SpO2=2(93) + AVPU=0 + O2=2 \u2014 supplemental O2 adds 2 points" + }, + { + "afterOffsetMinutes": 70, + "type": "alert", + "alertType": "RAPID_DETERIORATION", + "description": "SpO2 drops from 93% (T+50 on O2) to 89% (T+70 on O2) \u2014 failing supplemental oxygen therapy" + }, + { + "afterOffsetMinutes": 90, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 11, + "description": "NEWS2 = 11 at T+90: HR=2(128) + RR=3(36) + SBP=1(110) + Temp=0(37.1) + SpO2=3(87) + AVPU=0 + O2=2 \u2014 critical deterioration" + }, + { + "afterOffsetMinutes": 100, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 12, + "description": "NEWS2 = 12 (peak) at T+100: HR=3(131) + RR=3(37) + SBP=1(108) + Temp=0(37.0) + SpO2=3(86) + AVPU=0 + O2=2 \u2014 maximum severity before treatment effect" + }, + { + "afterOffsetMinutes": 100, + "type": "alert", + "alertType": "NEWS2_EMERGENCY", + "description": "Sustained NEWS2 EMERGENCY throughout scenario \u2014 peak score 12 at T+100 with HR, RR, and SpO2 all at maximum NEWS2 scores" + }, + { + "afterOffsetMinutes": 120, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 9, + "description": "NEWS2 = 9 at T+120 \u2014 still EMERGENCY but improving from peak of 12. SpO2 recovering to 93% on non-rebreather. Patient stabilized for PICU transfer." + } + ] +} diff --git a/VigilCare.Simulator/Scenarios/List/stable-baseline-01.json b/VigilCare.Simulator/Scenarios/List/stable-baseline-01.json new file mode 100644 index 0000000..131244d --- /dev/null +++ b/VigilCare.Simulator/Scenarios/List/stable-baseline-01.json @@ -0,0 +1,1067 @@ +{ + "scenario": { + "id": "stable-baseline-01", + "name": "Stable Baseline \u2014 Routine Inpatient Monitoring", + "description": "52-year-old female admitted for elective cholecystectomy. Completely uneventful 8-hour post-op monitoring period with all vitals remaining normal throughout. This is a CONTROL scenario that validates the system does NOT generate false alerts on a stable patient. NEWS2 remains 0 at every observation cluster.", + "durationMinutes": 480, + "tags": [ + "stable", + "baseline", + "control", + "surgery", + "post-op", + "cholecystectomy", + "no-alert" + ] + }, + "patient": { + "firstName": "Linda", + "lastName": "Weston", + "dateOfBirth": "1974-02-18", + "gender": "Female" + }, + "encounter": { + "department": "Surgery", + "encounterType": "Inpatient", + "attendingPhysician": "Dr. James Nakamura", + "roomBed": "SURG-204B", + "admissionReason": "Elective laparoscopic cholecystectomy \u2014 routine post-operative monitoring" + }, + "events": [ + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 72, + "unit": "bpm", + "source": "Device" + }, + "note": "Post-op arrival to surgical floor. All vitals normal, patient alert and comfortable. NEWS2=0" + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 14, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 124, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 74, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.8, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 74, + "unit": "bpm", + "source": "Device" + }, + "note": "First routine check \u2014 minor physiological noise, all normal. NEWS2=0" + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 15, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 122, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 76, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.7, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 30, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 70, + "unit": "bpm", + "source": "Device" + }, + "note": "Second routine check \u2014 all normal. NEWS2=0" + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 14, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 126, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 73, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.8, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "SPO2", + "value": 99, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "GLUCOSE_MG_DL", + "value": 118, + "unit": "mg/dL", + "source": "Lab" + }, + "note": "Routine post-op labs \u2014 all within normal limits" + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "POTASSIUM_MEQ_L", + "value": 4.0, + "unit": "mEq/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 61, + "type": "observation", + "data": { + "code": "WBC_K_UL", + "value": 8.2, + "unit": "\u00d710\u00b3/\u00b5L", + "source": "Lab" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 73, + "unit": "bpm", + "source": "Device" + }, + "note": "Third routine check \u2014 all normal. NEWS2=0" + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 15, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 120, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 74, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.9, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 71, + "unit": "bpm", + "source": "Device" + }, + "note": "Fourth routine check \u2014 patient reports mild incisional discomfort. All vitals normal. NEWS2=0" + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 14, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 125, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 75, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.8, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "medication", + "data": { + "drugName": "Acetaminophen", + "dose": 1000, + "doseUnit": "mg", + "route": "PO", + "administeredBy": "RN Garcia" + }, + "note": "Acetaminophen 1000mg PO for mild post-op incisional discomfort" + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 66, + "unit": "bpm", + "source": "Device" + }, + "note": "Patient sleeping \u2014 mild sleep bradycardia, HR dips to 66. Entirely normal. NEWS2=0" + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 12, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 118, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 70, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.7, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 73, + "unit": "bpm", + "source": "Device" + }, + "note": "Sixth check \u2014 patient awake, back to baseline. NEWS2=0" + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 15, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 126, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 76, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.9, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 75, + "unit": "bpm", + "source": "Device" + }, + "note": "Seventh check \u2014 all normal. NEWS2=0" + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 16, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 128, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 78, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.8, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "GLUCOSE_MG_DL", + "value": 105, + "unit": "mg/dL", + "source": "Lab" + }, + "note": "Second routine lab draw \u2014 all within normal limits" + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "POTASSIUM_MEQ_L", + "value": 4.1, + "unit": "mEq/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 72, + "unit": "bpm", + "source": "Device" + }, + "note": "Eighth check \u2014 all normal, temp 37.0. Surgical wound check performed. NEWS2=0" + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 14, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 124, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 74, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 235, + "type": "order", + "data": { + "orderType": "Procedure", + "description": "Surgical wound assessment \u2014 laparoscopic cholecystectomy port sites", + "orderedBy": "Dr. James Nakamura" + } + }, + { + "offsetMinutes": 240, + "type": "order_result", + "data": { + "orderDescription": "Surgical wound assessment \u2014 laparoscopic cholecystectomy port sites", + "resultSummary": "All four port sites intact, clean and dry. No erythema, swelling, drainage, or dehiscence. Steri-strips in place. No signs of infection." + }, + "note": "Routine post-op wound check \u2014 normal findings" + }, + { + "offsetMinutes": 300, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 70, + "unit": "bpm", + "source": "Device" + }, + "note": "Check at 5 hours \u2014 all normal. NEWS2=0" + }, + { + "offsetMinutes": 300, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 15, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 300, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 122, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 300, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 73, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 300, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.9, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 300, + "type": "observation", + "data": { + "code": "SPO2", + "value": 99, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 300, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 360, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 74, + "unit": "bpm", + "source": "Device" + }, + "note": "Check at 6 hours \u2014 all normal. NEWS2=0" + }, + { + "offsetMinutes": 360, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 14, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 360, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 130, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 360, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 78, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 360, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 360, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 360, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 420, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 71, + "unit": "bpm", + "source": "Device" + }, + "note": "Check at 7 hours \u2014 all normal. NEWS2=0" + }, + { + "offsetMinutes": 420, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 16, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 420, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 126, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 420, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 75, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 420, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.8, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 420, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 420, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 480, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 73, + "unit": "bpm", + "source": "Device" + }, + "note": "Final check at 8 hours \u2014 all vitals normal. Patient stable, tolerating diet, ambulating. NEWS2=0. Ready for discharge planning." + }, + { + "offsetMinutes": 480, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 14, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 480, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 124, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 480, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 74, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 480, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 36.9, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 480, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 480, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + } + ], + "expectedOutcomes": [ + { + "afterOffsetMinutes": 0, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 0, + "description": "NEWS2 score is 0 at baseline (T+0). All parameters in normal range: HR 72 (score 0), RR 14 (score 0), SBP 124 (score 0), SpO2 98 (score 0), Temp 36.8 (score 0), AVPU 0 (score 0), no supplemental O2 (score 0)." + }, + { + "afterOffsetMinutes": 150, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 0, + "description": "NEWS2 score remains 0 during sleep period (T+150). Sleep bradycardia HR 66 still within NEWS2 score-0 range (51-90), RR 12 still within score-0 range (12-20). No alert should fire." + }, + { + "afterOffsetMinutes": 240, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 0, + "description": "NEWS2 score remains 0 at mid-monitoring (T+240). All vitals stable and well within normal ranges. Surgical wound check normal." + }, + { + "afterOffsetMinutes": 480, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 0, + "description": "NEWS2 score remains 0 at end of 8-hour monitoring period (T+480). No alerts fired throughout entire scenario. Patient stable for discharge planning. This confirms the system correctly avoids false positives on a stable patient." + } + ] +} diff --git a/VigilCare.Simulator/Scenarios/List/uti-sepsis-elderly-01.json b/VigilCare.Simulator/Scenarios/List/uti-sepsis-elderly-01.json new file mode 100644 index 0000000..05d07b1 --- /dev/null +++ b/VigilCare.Simulator/Scenarios/List/uti-sepsis-elderly-01.json @@ -0,0 +1,1353 @@ +{ + "scenario": { + "id": "uti-sepsis-elderly-01", + "name": "UTI Progressing to Sepsis in Elderly Patient", + "description": "72-year-old female presenting with UTI symptoms who deteriorates into sepsis over 4 hours, triggering SIRS, qSOFA, and NEWS2 alerts with sepsis bundle compliance.", + "durationMinutes": 240, + "tags": [ + "sepsis", + "uti", + "elderly", + "ed", + "deterioration", + "bundle-compliance" + ] + }, + "patient": { + "firstName": "Eleanor", + "lastName": "Whitfield", + "dateOfBirth": "1954-02-08", + "gender": "Female" + }, + "encounter": { + "department": "Emergency", + "encounterType": "Emergency", + "attendingPhysician": "Dr. Marcus Reyes", + "roomBed": "ED-07B", + "admissionReason": "Fever, confusion, dysuria, urinary frequency" + }, + "events": [ + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 78, + "unit": "bpm", + "source": "Device" + }, + "note": "Baseline triage vitals" + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 16, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 132, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 78, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.4, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 0, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 76, + "unit": "bpm", + "source": "Device" + }, + "note": "Stable with physiological noise" + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 15, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 134, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 77, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.5, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "SPO2", + "value": 98, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 20, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 80, + "unit": "bpm", + "source": "Device" + }, + "note": "Subtle upward trend beginning" + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 16, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 129, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 75, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.6, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 40, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "WBC_K_UL", + "value": 10.2, + "unit": "\u00d710\u00b3/\u00b5L", + "source": "Lab" + }, + "note": "Initial lab draw \u2014 all within normal limits" + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "LACTATE_MMOL_L", + "value": 1.3, + "unit": "mmol/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "GLUCOSE_MG_DL", + "value": 112, + "unit": "mg/dL", + "source": "Lab" + } + }, + { + "offsetMinutes": 45, + "type": "observation", + "data": { + "code": "POTASSIUM_MEQ_L", + "value": 4.1, + "unit": "mEq/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 40, + "type": "order", + "data": { + "orderType": "Lab", + "description": "Urinalysis with culture", + "orderedBy": "Dr. Marcus Reyes" + }, + "note": "Initial UTI workup" + }, + { + "offsetMinutes": 45, + "type": "order_result", + "data": { + "orderDescription": "Urinalysis with culture", + "resultSummary": "Positive nitrites, leukocyte esterase 3+, >100 WBC/hpf" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 84, + "unit": "bpm", + "source": "Device" + }, + "note": "Mild tachycardia developing, temp rising" + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 17, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 126, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 73, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 37.9, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 60, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 91, + "unit": "bpm", + "source": "Device" + }, + "note": "HR crosses into warning range (>90)" + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 18, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 122, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 70, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 38.1, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "SPO2", + "value": 96, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 75, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 96, + "unit": "bpm", + "source": "Device" + }, + "note": "SIRS criteria met: Temp >38.3 + HR >90 \u2192 SEPSIS_WARNING" + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 20, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 116, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 67, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 38.4, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "SPO2", + "value": 96, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 90, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 92, + "type": "order_result", + "data": { + "orderDescription": "SEP-1: Blood cultures", + "resultSummary": "Two sets drawn from separate sites, sent to lab" + }, + "note": "Sepsis bundle order 1 of 4" + }, + { + "offsetMinutes": 95, + "type": "order_result", + "data": { + "orderDescription": "SEP-1: Serum lactate", + "resultSummary": "Specimen collected, sent to lab" + }, + "note": "Sepsis bundle order 2 of 4" + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 101, + "unit": "bpm", + "source": "Device" + }, + "note": "Continued deterioration \u2014 NEWS2 reaches 5 (WARNING)" + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 21, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 112, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 64, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 38.6, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "SPO2", + "value": 95, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 105, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 110, + "type": "order_result", + "data": { + "orderDescription": "SEP-1: Serum lactate", + "resultSummary": "Lactate 2.4 mmol/L (elevated)" + }, + "note": "Lactate result confirms tissue hypoperfusion" + }, + { + "offsetMinutes": 115, + "type": "order_result", + "data": { + "orderDescription": "SEP-1: Blood cultures", + "resultSummary": "Pending \u2014 gram stain in progress" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 106, + "unit": "bpm", + "source": "Device" + }, + "note": "NEWS2 = 6, SIRS 3 of 4 criteria met (Temp, HR, RR)" + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 22, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 108, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 61, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 38.9, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "SPO2", + "value": 95, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "WBC_K_UL", + "value": 14.8, + "unit": "\u00d710\u00b3/\u00b5L", + "source": "Lab" + }, + "note": "Repeat labs \u2014 WBC elevated, lactate rising, SIRS 4/4" + }, + { + "offsetMinutes": 120, + "type": "observation", + "data": { + "code": "LACTATE_MMOL_L", + "value": 2.8, + "unit": "mmol/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 121, + "type": "observation", + "data": { + "code": "GLUCOSE_MG_DL", + "value": 156, + "unit": "mg/dL", + "source": "Lab" + } + }, + { + "offsetMinutes": 121, + "type": "observation", + "data": { + "code": "POTASSIUM_MEQ_L", + "value": 4.6, + "unit": "mEq/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 125, + "type": "medication", + "data": { + "drugName": "ceftriaxone", + "dose": 2, + "doseUnit": "g", + "route": "IV", + "administeredBy": "nurse-rn-4" + }, + "note": "Sepsis bundle order 3 of 4 \u2014 broad-spectrum antibiotic" + }, + { + "offsetMinutes": 130, + "type": "medication", + "data": { + "drugName": "sodium chloride 0.9%", + "dose": 1000, + "doseUnit": "mL", + "route": "IV", + "administeredBy": "nurse-rn-4" + }, + "note": "Sepsis bundle order 4 of 4 \u2014 IV fluid resuscitation (30 mL/kg bolus)" + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 112, + "unit": "bpm", + "source": "Device" + }, + "note": "NEWS2 = 8 \u2192 EMERGENCY (HR critical, temp critical, all parameters worsening)" + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 23, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 104, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 57, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 39.1, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "SPO2", + "value": 94, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 135, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 118, + "unit": "bpm", + "source": "Device" + }, + "note": "Peak deterioration \u2014 qSOFA 3/3 (RR \u226522, SBP \u2264100, AVPU \u22651)" + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 24, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 98, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 53, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 39.3, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "SPO2", + "value": 93, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 150, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 155, + "type": "order_result", + "data": { + "orderDescription": "SEP-1: Blood cultures", + "resultSummary": "Gram-negative rods identified in 1 of 2 bottles" + } + }, + { + "offsetMinutes": 155, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + }, + "note": "Nasal cannula 2L/min started" + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 116, + "unit": "bpm", + "source": "Device" + }, + "note": "On supplemental O2, SpO2 improving slightly" + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 23, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 100, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 55, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 39.2, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { + "code": "SPO2", + "value": 95, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 165, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "WBC_K_UL", + "value": 15.2, + "unit": "\u00d710\u00b3/\u00b5L", + "source": "Lab" + }, + "note": "Follow-up labs \u2014 WBC still rising, lactate peaked" + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "LACTATE_MMOL_L", + "value": 3.1, + "unit": "mmol/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "GLUCOSE_MG_DL", + "value": 148, + "unit": "mg/dL", + "source": "Lab" + } + }, + { + "offsetMinutes": 180, + "type": "observation", + "data": { + "code": "POTASSIUM_MEQ_L", + "value": 4.4, + "unit": "mEq/L", + "source": "Lab" + } + }, + { + "offsetMinutes": 195, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 112, + "unit": "bpm", + "source": "Device" + }, + "note": "Early treatment response \u2014 HR and BP beginning to stabilize" + }, + { + "offsetMinutes": 195, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 22, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 195, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 104, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 195, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 58, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 195, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 39.0, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 195, + "type": "observation", + "data": { + "code": "SPO2", + "value": 96, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 195, + "type": "observation", + "data": { + "code": "AVPU", + "value": 1, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 195, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 106, + "unit": "bpm", + "source": "Device" + }, + "note": "Continued improvement with fluid resuscitation and antibiotics" + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 21, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 108, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 62, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 38.8, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "SPO2", + "value": 96, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 210, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + }, + { + "offsetMinutes": 225, + "type": "observation", + "data": { + "code": "LACTATE_MMOL_L", + "value": 2.2, + "unit": "mmol/L", + "source": "Lab" + }, + "note": "Lactate trending down from 3.1 \u2014 tissue perfusion improving" + }, + { + "offsetMinutes": 225, + "type": "order_result", + "data": { + "orderDescription": "SEP-1: Blood cultures", + "resultSummary": "Preliminary: Escherichia coli, susceptibilities pending" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "HEART_RATE", + "value": 100, + "unit": "bpm", + "source": "Device" + }, + "note": "End of scenario \u2014 stabilizing but still requires ICU-level monitoring" + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "RESP_RATE", + "value": 20, + "unit": "/min", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "SYSTOLIC_BP", + "value": 112, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "DIASTOLIC_BP", + "value": 66, + "unit": "mmHg", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "TEMP_C", + "value": 38.6, + "unit": "\u00b0C", + "source": "Manual" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "SPO2", + "value": 97, + "unit": "%", + "source": "Device" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "AVPU", + "value": 0, + "unit": "score", + "source": "Manual" + } + }, + { + "offsetMinutes": 240, + "type": "observation", + "data": { + "code": "SUPPLEMENTAL_O2", + "value": 1, + "unit": "flag", + "source": "Manual" + } + } + ], + "expectedOutcomes": [ + { + "afterOffsetMinutes": 75, + "type": "alert", + "alertType": "WARNING_HEART_RATE", + "description": "HR enters warning range (91 bpm)" + }, + { + "afterOffsetMinutes": 90, + "type": "alert", + "alertType": "SEPSIS_WARNING", + "description": "SIRS criteria met: Temp 38.4\u00b0C (>38.3) + HR 96 (>90) = 2 of 4" + }, + { + "afterOffsetMinutes": 90, + "type": "bundle", + "description": "Sepsis bundle auto-created with 4 orders: blood cultures, serum lactate, broad-spectrum antibiotics, IV fluid resuscitation" + }, + { + "afterOffsetMinutes": 105, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 5, + "description": "NEWS2 reaches 5 (HR=1, RR=2, Temp=1, SpO2=1) \u2192 WARNING threshold" + }, + { + "afterOffsetMinutes": 135, + "type": "alert", + "alertType": "NEWS2_EMERGENCY", + "description": "NEWS2 reaches 8 (HR=2, RR=2, SBP=1, Temp=2, SpO2=1) \u22657 \u2192 EMERGENCY" + }, + { + "afterOffsetMinutes": 135, + "type": "score", + "scoreType": "NEWS2", + "expectedMinimum": 7, + "description": "NEWS2 \u22657 sustained through peak deterioration" + }, + { + "afterOffsetMinutes": 150, + "type": "alert", + "alertType": "QSOFA_WARNING", + "description": "qSOFA 3/3: RR 24 (\u226522) + SBP 98 (\u2264100) + AVPU 1 (\u22651)" + }, + { + "afterOffsetMinutes": 130, + "type": "bundle", + "description": "Sepsis bundle COMPLIANT \u2014 all 4 orders completed within 40 minutes (blood cultures T+92, lactate T+95, ceftriaxone T+125, IV fluids T+130)" + } + ] +} diff --git a/VigilCare.Simulator/Scenarios/ScenarioFile.cs b/VigilCare.Simulator/Scenarios/ScenarioFile.cs new file mode 100644 index 0000000..5967e3f --- /dev/null +++ b/VigilCare.Simulator/Scenarios/ScenarioFile.cs @@ -0,0 +1,28 @@ +using System.Text.Json; + +public record ScenarioFile( + ScenarioMeta Scenario, + ScenarioPatient Patient, + ScenarioEncounter Encounter, + List Events, + List? ExpectedOutcomes); + +public record ScenarioMeta( + string Id, string Name, string? Description, + int? DurationMinutes, List? Tags); + +public record ScenarioPatient( + string FirstName, string LastName, string DateOfBirth, + string Gender); + +public record ScenarioEncounter( + string Department, string EncounterType, string AttendingPhysician, + string? RoomBed, string? AdmissionReason); + +public record ScenarioEvent( + double OffsetMinutes, string Type, JsonElement Data, string? Note); + +public record ExpectedOutcome( + double AfterOffsetMinutes, string Type, + string? AlertType, string? ScoreType, + double? ExpectedMinimum, string? Description); \ No newline at end of file diff --git a/VigilCare.Simulator/Scenarios/ScenarioLoader.cs b/VigilCare.Simulator/Scenarios/ScenarioLoader.cs new file mode 100644 index 0000000..e422020 --- /dev/null +++ b/VigilCare.Simulator/Scenarios/ScenarioLoader.cs @@ -0,0 +1,26 @@ +using System.Text.Json; + +public static class ScenarioLoader +{ + private static readonly JsonSerializerOptions JsonOptions = new() + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + ReadCommentHandling = JsonCommentHandling.Skip, + AllowTrailingCommas = true + }; + + public static ScenarioFile Load(string path) + { + if (!File.Exists(path)) + throw new FileNotFoundException($"Scenario file not found: {path}"); + + var json = File.ReadAllText(path); + var scenario = JsonSerializer.Deserialize(json, JsonOptions) + ?? throw new InvalidOperationException($"Failed to deserialize: {path}"); + + return scenario with + { + Events = scenario.Events.OrderBy(e => e.OffsetMinutes).ToList() + }; + } +} \ No newline at end of file diff --git a/VigilCare.Simulator/Scenarios/ScenarioValidator.cs b/VigilCare.Simulator/Scenarios/ScenarioValidator.cs new file mode 100644 index 0000000..ff98baa --- /dev/null +++ b/VigilCare.Simulator/Scenarios/ScenarioValidator.cs @@ -0,0 +1,138 @@ +public static class ScenarioValidator +{ + private static readonly HashSet ValidCodes = new() + { + "HEART_RATE", "RESP_RATE", "SYSTOLIC_BP", "DIASTOLIC_BP", + "TEMP_C", "SPO2", "AVPU", "SUPPLEMENTAL_O2", + "WBC_K_UL", "POTASSIUM_MEQ_L", "LACTATE_MMOL_L", "GLUCOSE_MG_DL" + }; + + private static readonly HashSet ValidSources = new() + { + "Manual", "Device", "Lab" + }; + + private static readonly HashSet ValidDepartments = new() + { + "Icu", "GeneralMedicine", "Emergency", "Cardiology", "Surgery", "Pediatrics" + }; + + private static readonly HashSet ValidEncounterTypes = new() + { + "Inpatient", "Outpatient", "Emergency" + }; + + private static readonly HashSet ValidEventTypes = new() + { + "observation", "order", "medication", "order_result" + }; + + private static readonly HashSet ValidOrderTypes = new() + { + "Lab", "Imaging", "Medication", "Procedure" + }; + + private static readonly string[] SepsisBundleOrderPrefixes = + [ + "SEP-1: Blood cultures", + "SEP-1: Serum lactate", + "SEP-1: Broad-spectrum antibiotics", + "SEP-1: IV fluid bolus" + ]; + + public static List Validate(ScenarioFile scenario) + { + var errors = new List(); + + if (string.IsNullOrWhiteSpace(scenario.Scenario.Id)) + errors.Add("scenario.id is required"); + if (string.IsNullOrWhiteSpace(scenario.Scenario.Name)) + errors.Add("scenario.name is required"); + if (string.IsNullOrWhiteSpace(scenario.Encounter.AttendingPhysician)) + errors.Add("encounter.attendingPhysician is required"); + if (!ValidDepartments.Contains(scenario.Encounter.Department)) + errors.Add($"encounter.department '{scenario.Encounter.Department}' is not valid"); + if (!ValidEncounterTypes.Contains(scenario.Encounter.EncounterType)) + errors.Add($"encounter.encounterType '{scenario.Encounter.EncounterType}' is not valid"); + if (scenario.Events.Count == 0) + errors.Add("events array is empty"); + + foreach (var group in scenario.Events + .Where(e => e.Type == "observation") + .GroupBy(e => e.OffsetMinutes)) + { + if (group.Count() > 10) + errors.Add( + $"offsetMinutes {group.Key}: {group.Count()} observations exceeds API batch limit of 10"); + } + + var placedOrders = new HashSet(StringComparer.OrdinalIgnoreCase); + double lastOffset = -1; + for (int i = 0; i < scenario.Events.Count; i++) + { + var evt = scenario.Events[i]; + if (evt.OffsetMinutes < 0) + errors.Add($"events[{i}]: offsetMinutes cannot be negative"); + if (evt.OffsetMinutes < lastOffset) + errors.Add($"events[{i}]: offsetMinutes goes backwards ({evt.OffsetMinutes} < {lastOffset})"); + lastOffset = evt.OffsetMinutes; + + if (!ValidEventTypes.Contains(evt.Type)) + errors.Add($"events[{i}]: unknown type '{evt.Type}'"); + + if (evt.Type == "observation") + { + var code = evt.Data.TryGetProperty("code", out var codeProp) ? codeProp.GetString() : null; + if (code is null || !ValidCodes.Contains(code)) + errors.Add($"events[{i}]: unknown observation code '{code}'"); + + var source = evt.Data.TryGetProperty("source", out var sourceProp) ? sourceProp.GetString() : null; + if (source is not null && !ValidSources.Contains(source)) + errors.Add($"events[{i}]: unknown observation source '{source}'"); + } + + if (evt.Type == "order") + { + var description = evt.Data.TryGetProperty("description", out var descProp) + ? descProp.GetString() : null; + if (string.IsNullOrWhiteSpace(description)) + errors.Add($"events[{i}]: order.description is required"); + + var orderType = evt.Data.TryGetProperty("orderType", out var typeProp) + ? typeProp.GetString() : null; + if (orderType is null || !ValidOrderTypes.Contains(orderType)) + errors.Add($"events[{i}]: order.orderType '{orderType}' is not valid"); + + if (!string.IsNullOrWhiteSpace(description)) + placedOrders.Add(description); + } + + if (evt.Type == "order_result") + { + var orderDescription = evt.Data.TryGetProperty("orderDescription", out var descProp) + ? descProp.GetString() : null; + if (string.IsNullOrWhiteSpace(orderDescription)) + { + errors.Add($"events[{i}]: order_result.orderDescription is required"); + continue; + } + + if (!placedOrders.Contains(orderDescription) + && !IsSepsisBundleOrder(orderDescription) + && !placedOrders.Any(p => orderDescription.StartsWith(p, StringComparison.OrdinalIgnoreCase))) + { + errors.Add( + $"events[{i}]: order_result '{orderDescription}' has no matching prior 'order' event " + + "(sepsis bundle orders are auto-created when SEPSIS_WARNING or QSOFA_WARNING fires)"); + } + } + } + + return errors; + } + + private static bool IsSepsisBundleOrder(string description) => + SepsisBundleOrderPrefixes.Any(p => + description.Equals(p, StringComparison.OrdinalIgnoreCase) + || description.StartsWith(p, StringComparison.OrdinalIgnoreCase)); +} diff --git a/VigilCare.Simulator/Scenarios/schema.json b/VigilCare.Simulator/Scenarios/schema.json new file mode 100644 index 0000000..5a6f123 --- /dev/null +++ b/VigilCare.Simulator/Scenarios/schema.json @@ -0,0 +1,68 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "VigilCare Clinical Scenario", + "type": "object", + "required": ["scenario", "patient", "encounter", "events"], + "properties": { + "scenario": { + "type": "object", + "required": ["id", "name"], + "properties": { + "id": { "type": "string", "pattern": "^[a-z0-9-]+$" }, + "name": { "type": "string" }, + "description": { "type": "string" }, + "durationMinutes": { "type": "integer", "minimum": 1 }, + "tags": { "type": "array", "items": { "type": "string" } } + } + }, + "patient": { + "type": "object", + "required": ["firstName", "lastName", "dateOfBirth", "gender"], + "properties": { + "firstName": { "type": "string" }, + "lastName": { "type": "string" }, + "dateOfBirth": { "type": "string", "format": "date" }, + "gender": { "type": "string", "enum": ["Male", "Female"] } + } + }, + "encounter": { + "type": "object", + "required": ["department", "encounterType", "attendingPhysician"], + "properties": { + "department": { "type": "string", "enum": ["Icu", "GeneralMedicine", "Emergency", "Cardiology", "Surgery", "Pediatrics"] }, + "encounterType": { "type": "string", "enum": ["Inpatient", "Outpatient", "Emergency"] }, + "attendingPhysician": { "type": "string" }, + "roomBed": { "type": "string" }, + "admissionReason": { "type": "string" } + } + }, + "events": { + "type": "array", + "items": { + "type": "object", + "required": ["offsetMinutes", "type", "data"], + "properties": { + "offsetMinutes": { "type": "number", "minimum": 0 }, + "type": { "type": "string", "enum": ["observation", "order", "medication", "order_result"] }, + "data": { "type": "object" }, + "note": { "type": "string" } + } + } + }, + "expectedOutcomes": { + "type": "array", + "items": { + "type": "object", + "required": ["afterOffsetMinutes", "type"], + "properties": { + "afterOffsetMinutes": { "type": "number", "minimum": 0 }, + "type": { "type": "string", "enum": ["alert", "score", "bundle"] }, + "alertType": { "type": "string" }, + "scoreType": { "type": "string" }, + "expectedMinimum": { "type": "number" }, + "description": { "type": "string" } + } + } + } + } +} \ No newline at end of file diff --git a/VigilCare.Simulator/VigilCare.Simulator.csproj b/VigilCare.Simulator/VigilCare.Simulator.csproj new file mode 100644 index 0000000..7cd77a2 --- /dev/null +++ b/VigilCare.Simulator/VigilCare.Simulator.csproj @@ -0,0 +1,19 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + diff --git a/VigilCareClinical.sln b/VigilCareClinical.sln index 6dd4281..a2c9365 100644 --- a/VigilCareClinical.sln +++ b/VigilCareClinical.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VigilCareClinicalAPI", "Vig EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VigilCareClinicalAPI.Tests", "VigilCareClinicalAPI.Tests\VigilCareClinicalAPI.Tests.csproj", "{EECD0F7B-CF7E-4F42-826E-BE0E67AAC0A9}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VigilCare.Simulator", "VigilCare.Simulator\VigilCare.Simulator.csproj", "{F9C415E2-732C-4DB6-9229-EB389A710911}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -24,5 +26,9 @@ Global {EECD0F7B-CF7E-4F42-826E-BE0E67AAC0A9}.Debug|Any CPU.Build.0 = Debug|Any CPU {EECD0F7B-CF7E-4F42-826E-BE0E67AAC0A9}.Release|Any CPU.ActiveCfg = Release|Any CPU {EECD0F7B-CF7E-4F42-826E-BE0E67AAC0A9}.Release|Any CPU.Build.0 = Release|Any CPU + {F9C415E2-732C-4DB6-9229-EB389A710911}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F9C415E2-732C-4DB6-9229-EB389A710911}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F9C415E2-732C-4DB6-9229-EB389A710911}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F9C415E2-732C-4DB6-9229-EB389A710911}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/VigilCareClinicalAPI/appsettings.json b/VigilCareClinicalAPI/appsettings.json index aec5ec9..072661e 100644 --- a/VigilCareClinicalAPI/appsettings.json +++ b/VigilCareClinicalAPI/appsettings.json @@ -45,7 +45,7 @@ }, "NumPartitions": 6, "OutboxBatchSize": 100, - "OutboxPollIntervalMs": 500 + "OutboxPollIntervalMs": 1000 }, "Elasticsearch": { "Uri": "http://localhost:9200", diff --git a/docs/scenarios/cardiac-ward-01.json b/docs/scenarios/cardiac-ward-01.json deleted file mode 100644 index 8856178..0000000 --- a/docs/scenarios/cardiac-ward-01.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "scenario": { - "id": "cardiac-ward-01", - "name": "Cardiac Ward — Atrial Fibrillation with Rapid Ventricular Response", - "description": "78-year-old woman on cardiac ward with known AF. Rate-controlled on admission but develops rapid ventricular response over 3 hours. Heart rate climbs while other vitals remain relatively stable — tests whether the system correctly alerts on isolated tachycardia escalation.", - "durationMinutes": 180, - "tags": ["cardiac", "afib", "tachycardia", "single-parameter"] - }, - "patient": { - "firstName": "Margaret", - "lastName": "Tsai", - "dateOfBirth": "1948-01-28", - "gender": "Female", - "mrn": "SIM-005" - }, - "encounter": { - "department": "Cardiac", - "room": "CARD-2A", - "bed": "1", - "encounterType": "Inpatient", - "chiefComplaint": "Atrial fibrillation — rate control monitoring" - }, - "events": [ - { "offsetMinutes": 0, "type": "observation", "data": { "code": "HEART_RATE", "value": 82, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "RESP_RATE", "value": 16, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 138, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 84, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "TEMP_C", "value": 36.6, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "SPO2", "value": 96, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 30, "type": "observation", "data": { "code": "HEART_RATE", "value": 88, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 30, "type": "observation", "data": { "code": "RESP_RATE", "value": 16, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 30, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 134, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 30, "type": "observation", "data": { "code": "TEMP_C", "value": 36.7, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 30, "type": "observation", "data": { "code": "SPO2", "value": 96, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 30, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 60, "type": "observation", "data": { "code": "HEART_RATE", "value": 98, "unit": "bpm", "source": "monitor" }, "note": "HR climbing — AF losing rate control" }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "RESP_RATE", "value": 17, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 130, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 82, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "TEMP_C", "value": 36.7, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "SPO2", "value": 96, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 90, "type": "observation", "data": { "code": "HEART_RATE", "value": 112, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "RESP_RATE", "value": 18, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 126, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 80, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "TEMP_C", "value": 36.8, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "SPO2", "value": 95, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 120, "type": "observation", "data": { "code": "HEART_RATE", "value": 128, "unit": "bpm", "source": "monitor" }, "note": "Rapid ventricular response" }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "RESP_RATE", "value": 20, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 118, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 76, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "TEMP_C", "value": 36.8, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "SPO2", "value": 94, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 130, "type": "medication", "data": { "drugName": "metoprolol", "dose": 5, "doseUnit": "mg", "route": "IV", "administeredBy": "nurse-rn-3" }, "note": "IV metoprolol for rate control" }, - - { "offsetMinutes": 150, "type": "observation", "data": { "code": "HEART_RATE", "value": 136, "unit": "bpm", "source": "monitor" }, "note": "Not yet responding to IV metoprolol" }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "RESP_RATE", "value": 22, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 112, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 72, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "TEMP_C", "value": 36.9, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "SPO2", "value": 93, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 180, "type": "observation", "data": { "code": "HEART_RATE", "value": 108, "unit": "bpm", "source": "monitor" }, "note": "Rate starting to respond" }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "RESP_RATE", "value": 19, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 120, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 76, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "TEMP_C", "value": 36.8, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "SPO2", "value": 95, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } } - ], - "expectedOutcomes": [ - { "afterOffsetMinutes": 60, "type": "alert", "alertType": "WARNING_HEART_RATE", "description": "HR 98 enters warning range" }, - { "afterOffsetMinutes": 90, "type": "alert", "alertType": "RAPID_DETERIORATION", "description": "HR climbed 82→112 in 90 minutes" }, - { "afterOffsetMinutes": 120, "type": "score", "scoreType": "NEWS2", "expectedMinimum": 5, "description": "NEWS2 medium risk from HR + SpO2 contributions" }, - { "afterOffsetMinutes": 120, "type": "alert", "alertType": "NEWS2_WARNING", "description": "NEWS2 5-6" }, - { "afterOffsetMinutes": 150, "type": "alert", "alertType": "NEWS2_EMERGENCY", "description": "NEWS2 ≥7 — HR scores 3 (≥131), SpO2 falling" } - ] -} diff --git a/docs/scenarios/hypothermia-elderly-01.json b/docs/scenarios/hypothermia-elderly-01.json deleted file mode 100644 index a2c24f8..0000000 --- a/docs/scenarios/hypothermia-elderly-01.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "scenario": { - "id": "hypothermia-elderly-01", - "name": "Elderly Hypothermia — Subtle Deterioration", - "description": "85-year-old woman brought from nursing home with low-grade hypothermia and confusion. Vitals look deceptively near-normal except low temperature and altered mentation. Tests whether the system catches the NEWS2 escalation from temperature and AVPU contributions that are easy to miss clinically.", - "durationMinutes": 180, - "tags": ["elderly", "hypothermia", "subtle", "avpu", "nursing-home"] - }, - "patient": { - "firstName": "Mei-Ling", - "lastName": "Wu", - "dateOfBirth": "1941-04-12", - "gender": "Female", - "mrn": "SIM-006" - }, - "encounter": { - "department": "Emergency", - "room": "ED-5", - "bed": "B", - "encounterType": "Emergency", - "chiefComplaint": "Found confused and cold at nursing home, not eating for 2 days" - }, - "events": [ - { "offsetMinutes": 0, "type": "observation", "data": { "code": "HEART_RATE", "value": 68, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "RESP_RATE", "value": 14, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 118, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 72, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "TEMP_C", "value": 35.8, "unit": "°C", "source": "manual" }, "note": "Low-normal temperature" }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "SPO2", "value": 96, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "AVPU", "value": 1, "unit": "score", "source": "manual" }, "note": "Responds to voice — confused" }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "GLUCOSE_MG_DL", "value": 62, "unit": "mg/dL", "source": "lab" }, "note": "Borderline hypoglycemia" }, - - { "offsetMinutes": 45, "type": "observation", "data": { "code": "HEART_RATE", "value": 64, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 45, "type": "observation", "data": { "code": "RESP_RATE", "value": 13, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 45, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 114, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 45, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 70, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 45, "type": "observation", "data": { "code": "TEMP_C", "value": 35.4, "unit": "°C", "source": "manual" }, "note": "Temperature dropping further" }, - { "offsetMinutes": 45, "type": "observation", "data": { "code": "SPO2", "value": 96, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 45, "type": "observation", "data": { "code": "AVPU", "value": 1, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 90, "type": "observation", "data": { "code": "HEART_RATE", "value": 58, "unit": "bpm", "source": "monitor" }, "note": "Bradycardic — hypothermia effect" }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "RESP_RATE", "value": 11, "unit": "/min", "source": "manual" }, "note": "RR dropping — warning range" }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 108, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 66, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "TEMP_C", "value": 35.0, "unit": "°C", "source": "manual" }, "note": "Hypothermic — critical range" }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "SPO2", "value": 95, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "AVPU", "value": 2, "unit": "score", "source": "manual" }, "note": "Now responds to pain only" }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "GLUCOSE_MG_DL", "value": 54, "unit": "mg/dL", "source": "lab" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "WBC_K_UL", "value": 3.8, "unit": "×10³/µL", "source": "lab" }, "note": "Low WBC — possible immunosuppression" }, - - { "offsetMinutes": 120, "type": "observation", "data": { "code": "HEART_RATE", "value": 54, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "RESP_RATE", "value": 10, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 104, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 62, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "TEMP_C", "value": 34.8, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "SPO2", "value": 94, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "AVPU", "value": 2, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 150, "type": "observation", "data": { "code": "HEART_RATE", "value": 50, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "RESP_RATE", "value": 9, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 100, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 58, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "TEMP_C", "value": 34.5, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "SPO2", "value": 93, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "AVPU", "value": 2, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 180, "type": "observation", "data": { "code": "HEART_RATE", "value": 46, "unit": "bpm", "source": "monitor" }, "note": "HR in critical range" }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "RESP_RATE", "value": 8, "unit": "/min", "source": "manual" }, "note": "RR critical" }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 96, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 54, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "TEMP_C", "value": 34.2, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "SPO2", "value": 91, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "AVPU", "value": 3, "unit": "score", "source": "manual" }, "note": "Unresponsive — ICU transfer" } - ], - "expectedOutcomes": [ - { "afterOffsetMinutes": 45, "type": "alert", "alertType": "WARNING_TEMP_C", "description": "Temp 35.4 enters warning range" }, - { "afterOffsetMinutes": 90, "type": "alert", "alertType": "WARNING_RESP_RATE", "description": "RR 11 enters warning range" }, - { "afterOffsetMinutes": 90, "type": "score", "scoreType": "NEWS2", "expectedMinimum": 7, "description": "NEWS2 HIGH — temp 3pts + AVPU 3pts + RR + low WBC" }, - { "afterOffsetMinutes": 90, "type": "alert", "alertType": "NEWS2_EMERGENCY", "description": "NEWS2 ≥7 with AVPU score 3" }, - { "afterOffsetMinutes": 90, "type": "alert", "alertType": "QSOFA_WARNING", "description": "qSOFA ≥2: AVPU 2 + RR borderline — depends on exact threshold" }, - { "afterOffsetMinutes": 90, "type": "alert", "alertType": "SEPSIS_WARNING", "description": "SIRS: temp <36, WBC <4 — possible sepsis in elderly" }, - { "afterOffsetMinutes": 180, "type": "alert", "alertType": "RAPID_DETERIORATION", "description": "Multi-parameter decline: HR, RR, temp, SpO2 all trending down" } - ] -} diff --git a/docs/scenarios/medication-false-alarm-01.json b/docs/scenarios/medication-false-alarm-01.json deleted file mode 100644 index c77ff6f..0000000 --- a/docs/scenarios/medication-false-alarm-01.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "scenario": { - "id": "medication-false-alarm-01", - "name": "Post-Metoprolol BP Drop — Expected Pharmacology", - "description": "68-year-old man admitted for hypertension management. Receives metoprolol for high BP. BP and HR drop into warning range afterward — this is the expected drug effect, not deterioration. Tests whether clinicians rate the post-medication alerts as false positives.", - "durationMinutes": 180, - "tags": ["medication", "false-positive", "hypertension", "expected-response"] - }, - "patient": { - "firstName": "David", - "lastName": "Huang", - "dateOfBirth": "1958-11-03", - "gender": "Male", - "mrn": "SIM-004" - }, - "encounter": { - "department": "Medical", - "room": "MED-7A", - "bed": "2", - "encounterType": "Inpatient", - "chiefComplaint": "Uncontrolled hypertension, headache" - }, - "events": [ - { "offsetMinutes": 0, "type": "observation", "data": { "code": "HEART_RATE", "value": 92, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "RESP_RATE", "value": 16, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 168, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 98, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "TEMP_C", "value": 36.9, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "SPO2", "value": 97, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 30, "type": "medication", "data": { "drugName": "metoprolol", "dose": 50, "doseUnit": "mg", "route": "PO", "administeredBy": "nurse-rn-2" }, "note": "Metoprolol administered for BP control" }, - - { "offsetMinutes": 60, "type": "observation", "data": { "code": "HEART_RATE", "value": 78, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "RESP_RATE", "value": 15, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 142, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 88, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "TEMP_C", "value": 36.8, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "SPO2", "value": 97, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 90, "type": "observation", "data": { "code": "HEART_RATE", "value": 64, "unit": "bpm", "source": "monitor" }, "note": "HR dropping — expected metoprolol effect" }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "RESP_RATE", "value": 14, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 118, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 76, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "TEMP_C", "value": 36.8, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "SPO2", "value": 98, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 120, "type": "observation", "data": { "code": "HEART_RATE", "value": 56, "unit": "bpm", "source": "monitor" }, "note": "HR in low range — metoprolol peak effect" }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "RESP_RATE", "value": 14, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 106, "unit": "mmHg", "source": "manual" }, "note": "SBP approaching warning range" }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 68, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "TEMP_C", "value": 36.7, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "SPO2", "value": 97, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 150, "type": "observation", "data": { "code": "HEART_RATE", "value": 52, "unit": "bpm", "source": "monitor" }, "note": "HR 52 — warning range but expected" }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "RESP_RATE", "value": 13, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 102, "unit": "mmHg", "source": "manual" }, "note": "SBP 102 — warning range but expected" }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 64, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "TEMP_C", "value": 36.7, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "SPO2", "value": 98, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 180, "type": "observation", "data": { "code": "HEART_RATE", "value": 58, "unit": "bpm", "source": "monitor" }, "note": "Stabilizing — effect wearing off slightly" }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "RESP_RATE", "value": 14, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 110, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 70, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "TEMP_C", "value": 36.8, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "SPO2", "value": 97, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } } - ], - "expectedOutcomes": [ - { "afterOffsetMinutes": 120, "type": "alert", "alertType": "WARNING_SYSTOLIC_BP", "description": "SBP 106 enters warning range — should be annotated with metoprolol context if Phase 15 active" }, - { "afterOffsetMinutes": 150, "type": "alert", "alertType": "WARNING_HEART_RATE", "description": "HR 52 enters low warning range — expected metoprolol effect" }, - { "afterOffsetMinutes": 150, "type": "alert", "alertType": "RAPID_DETERIORATION", "description": "HR dropped 92→52 and SBP dropped 168→102 — trajectory alert, but pharmacologically expected" } - ] -} diff --git a/docs/scenarios/post-op-pain-01.json b/docs/scenarios/post-op-pain-01.json deleted file mode 100644 index 8434566..0000000 --- a/docs/scenarios/post-op-pain-01.json +++ /dev/null @@ -1,87 +0,0 @@ -{ - "scenario": { - "id": "post-op-pain-01", - "name": "Post-Operative Pain Crisis — Opioid Effect on Respiratory Rate", - "description": "45-year-old woman post-abdominal surgery with escalating pain. Morphine administered at 30 minutes. Respiratory rate drops to warning range afterward — expected opioid effect. Heart rate rises from pain before medication, then normalizes. Tests whether clinicians distinguish pain-related tachycardia from pathological tachycardia, and opioid-related respiratory depression from deterioration.", - "durationMinutes": 180, - "tags": ["post-op", "pain", "opioid", "respiratory-depression", "medication-effect"] - }, - "patient": { - "firstName": "Sarah", - "lastName": "Lin", - "dateOfBirth": "1981-09-17", - "gender": "Female", - "mrn": "SIM-007" - }, - "encounter": { - "department": "Surgical", - "room": "SURG-6C", - "bed": "1", - "encounterType": "Inpatient", - "chiefComplaint": "Post-op day 0 — open appendectomy (complicated appendicitis)" - }, - "events": [ - { "offsetMinutes": 0, "type": "observation", "data": { "code": "HEART_RATE", "value": 86, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "RESP_RATE", "value": 16, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 134, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 82, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "TEMP_C", "value": 37.4, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "SPO2", "value": 97, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 20, "type": "observation", "data": { "code": "HEART_RATE", "value": 104, "unit": "bpm", "source": "monitor" }, "note": "Tachycardia from pain" }, - { "offsetMinutes": 20, "type": "observation", "data": { "code": "RESP_RATE", "value": 20, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 20, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 146, "unit": "mmHg", "source": "manual" }, "note": "Hypertensive from pain" }, - { "offsetMinutes": 20, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 92, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 20, "type": "observation", "data": { "code": "TEMP_C", "value": 37.5, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 20, "type": "observation", "data": { "code": "SPO2", "value": 97, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 20, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 30, "type": "medication", "data": { "drugName": "morphine", "dose": 4, "doseUnit": "mg", "route": "IV", "administeredBy": "nurse-rn-4" }, "note": "Morphine for post-op pain" }, - - { "offsetMinutes": 60, "type": "observation", "data": { "code": "HEART_RATE", "value": 82, "unit": "bpm", "source": "monitor" }, "note": "HR normalizing with pain relief" }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "RESP_RATE", "value": 14, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 126, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 78, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "TEMP_C", "value": 37.4, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "SPO2", "value": 96, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 90, "type": "observation", "data": { "code": "HEART_RATE", "value": 76, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "RESP_RATE", "value": 10, "unit": "/min", "source": "manual" }, "note": "RR dropping — morphine respiratory depression" }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 118, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 72, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "TEMP_C", "value": 37.3, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "SPO2", "value": 95, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 120, "type": "observation", "data": { "code": "HEART_RATE", "value": 74, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "RESP_RATE", "value": 9, "unit": "/min", "source": "manual" }, "note": "RR 9 — warning range" }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 116, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 70, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "TEMP_C", "value": 37.2, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "SPO2", "value": 94, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 150, "type": "observation", "data": { "code": "HEART_RATE", "value": 76, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "RESP_RATE", "value": 11, "unit": "/min", "source": "manual" }, "note": "RR recovering slowly" }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 120, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 74, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "TEMP_C", "value": 37.3, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "SPO2", "value": 95, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 180, "type": "observation", "data": { "code": "HEART_RATE", "value": 78, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "RESP_RATE", "value": 13, "unit": "/min", "source": "manual" }, "note": "RR normalizing" }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 122, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 76, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "TEMP_C", "value": 37.4, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "SPO2", "value": 96, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } } - ], - "expectedOutcomes": [ - { "afterOffsetMinutes": 20, "type": "alert", "alertType": "WARNING_HEART_RATE", "description": "HR 104 — pain-related tachycardia, not pathological" }, - { "afterOffsetMinutes": 90, "type": "alert", "alertType": "WARNING_RESP_RATE", "description": "RR 10 enters warning range — morphine respiratory depression" }, - { "afterOffsetMinutes": 120, "type": "alert", "alertType": "RAPID_DETERIORATION", "description": "RR dropped 20→9 — trajectory alert but pharmacologically expected" } - ] -} diff --git a/docs/scenarios/respiratory-failure-01.json b/docs/scenarios/respiratory-failure-01.json deleted file mode 100644 index 07b34e2..0000000 --- a/docs/scenarios/respiratory-failure-01.json +++ /dev/null @@ -1,96 +0,0 @@ -{ - "scenario": { - "id": "respiratory-failure-01", - "name": "Post-Surgical Respiratory Deterioration", - "description": "55-year-old man on surgical ward after abdominal surgery. Stable for 2 hours, then gradual respiratory deterioration: falling SpO2, rising RR, supplemental oxygen started. NEWS2 reaches HIGH risk by hour 3.", - "durationMinutes": 240, - "tags": ["respiratory", "surgical", "deterioration", "supplemental-o2"] - }, - "patient": { - "firstName": "Robert", - "lastName": "Wang", - "dateOfBirth": "1971-08-22", - "gender": "Male", - "mrn": "SIM-002" - }, - "encounter": { - "department": "Surgical", - "room": "SURG-4B", - "bed": "1", - "encounterType": "Inpatient", - "chiefComplaint": "Post-op day 1 — laparoscopic cholecystectomy" - }, - "events": [ - { "offsetMinutes": 0, "type": "observation", "data": { "code": "HEART_RATE", "value": 76, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "RESP_RATE", "value": 14, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 132, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 82, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "TEMP_C", "value": 37.0, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "SPO2", "value": 98, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 60, "type": "observation", "data": { "code": "HEART_RATE", "value": 78, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "RESP_RATE", "value": 15, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 130, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 80, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "TEMP_C", "value": 37.1, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "SPO2", "value": 97, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 120, "type": "observation", "data": { "code": "HEART_RATE", "value": 82, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "RESP_RATE", "value": 18, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 126, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 78, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "TEMP_C", "value": 37.3, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "SPO2", "value": 95, "unit": "%", "source": "monitor" }, "note": "SpO2 starting to drift down" }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 140, "type": "observation", "data": { "code": "HEART_RATE", "value": 88, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 140, "type": "observation", "data": { "code": "RESP_RATE", "value": 21, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 140, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 124, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 140, "type": "observation", "data": { "code": "TEMP_C", "value": 37.4, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 140, "type": "observation", "data": { "code": "SPO2", "value": 93, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 140, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 150, "type": "observation", "data": { "code": "SUPPLEMENTAL_O2", "value": 1, "unit": "flag", "source": "manual" }, "note": "Nurse starts 2L nasal cannula" }, - - { "offsetMinutes": 160, "type": "observation", "data": { "code": "HEART_RATE", "value": 94, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 160, "type": "observation", "data": { "code": "RESP_RATE", "value": 24, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 160, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 120, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 160, "type": "observation", "data": { "code": "TEMP_C", "value": 37.5, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 160, "type": "observation", "data": { "code": "SPO2", "value": 92, "unit": "%", "source": "monitor" }, "note": "SpO2 92 despite supplemental O2" }, - { "offsetMinutes": 160, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 180, "type": "observation", "data": { "code": "HEART_RATE", "value": 102, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "RESP_RATE", "value": 26, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 118, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "TEMP_C", "value": 37.6, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "SPO2", "value": 90, "unit": "%", "source": "monitor" }, "note": "SpO2 dropping further" }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "SUPPLEMENTAL_O2", "value": 1, "unit": "flag", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 210, "type": "observation", "data": { "code": "HEART_RATE", "value": 108, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 210, "type": "observation", "data": { "code": "RESP_RATE", "value": 28, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 210, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 116, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 210, "type": "observation", "data": { "code": "TEMP_C", "value": 37.7, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 210, "type": "observation", "data": { "code": "SPO2", "value": 88, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 210, "type": "observation", "data": { "code": "SUPPLEMENTAL_O2", "value": 1, "unit": "flag", "source": "manual" } }, - { "offsetMinutes": 210, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 240, "type": "observation", "data": { "code": "HEART_RATE", "value": 112, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "RESP_RATE", "value": 30, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 114, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "TEMP_C", "value": 37.8, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "SPO2", "value": 86, "unit": "%", "source": "monitor" }, "note": "Critical desaturation — ICU consult called" }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "SUPPLEMENTAL_O2", "value": 1, "unit": "flag", "source": "manual" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } } - ], - "expectedOutcomes": [ - { "afterOffsetMinutes": 140, "type": "alert", "alertType": "WARNING_RESP_RATE", "description": "RR 21 enters warning range" }, - { "afterOffsetMinutes": 140, "type": "score", "scoreType": "NEWS2", "expectedMinimum": 4, "description": "NEWS2 rising from SpO2 and RR contributions" }, - { "afterOffsetMinutes": 160, "type": "alert", "alertType": "NEWS2_WARNING", "description": "NEWS2 5-6 with supplemental O2 + low SpO2 + high RR" }, - { "afterOffsetMinutes": 160, "type": "alert", "alertType": "RAPID_DETERIORATION", "description": "SpO2 dropping 98→92 over short window" }, - { "afterOffsetMinutes": 180, "type": "alert", "alertType": "NEWS2_EMERGENCY", "description": "NEWS2 ≥7 with critical SpO2 on supplemental O2" }, - { "afterOffsetMinutes": 210, "type": "alert", "alertType": "WARNING_HEART_RATE", "description": "HR 108 enters warning range" } - ] -} diff --git a/docs/scenarios/sepsis-ed-01.json b/docs/scenarios/sepsis-ed-01.json deleted file mode 100644 index 715d147..0000000 --- a/docs/scenarios/sepsis-ed-01.json +++ /dev/null @@ -1,111 +0,0 @@ -{ - "scenario": { - "id": "sepsis-ed-01", - "name": "ED Sepsis Deterioration — UTI Source", - "description": "72-year-old woman presents to ED with UTI symptoms. Over 4 hours she develops sepsis: rising temperature, tachycardia, hypotension. Antibiotics started at 1 hour. Sepsis bundle completed by hour 2.", - "durationMinutes": 240, - "tags": ["sepsis", "ed", "deterioration", "bundle-completion"] - }, - "patient": { - "firstName": "Eleanor", - "lastName": "Chen", - "dateOfBirth": "1954-03-15", - "gender": "Female", - "mrn": "SIM-001" - }, - "encounter": { - "department": "Emergency", - "room": "ED-12", - "bed": "A", - "encounterType": "Emergency", - "chiefComplaint": "Fever, confusion, dysuria for 2 days" - }, - "events": [ - { "offsetMinutes": 0, "type": "observation", "data": { "code": "HEART_RATE", "value": 88, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "RESP_RATE", "value": 18, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 128, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 78, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "TEMP_C", "value": 38.2, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "SPO2", "value": 97, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 30, "type": "observation", "data": { "code": "HEART_RATE", "value": 94, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 30, "type": "observation", "data": { "code": "RESP_RATE", "value": 20, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 30, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 122, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 30, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 74, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 30, "type": "observation", "data": { "code": "TEMP_C", "value": 38.6, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 30, "type": "observation", "data": { "code": "SPO2", "value": 96, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 30, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - { "offsetMinutes": 30, "type": "observation", "data": { "code": "WBC_K_UL", "value": 14.2, "unit": "×10³/µL", "source": "lab" }, "note": "Initial labs — elevated WBC" }, - - { "offsetMinutes": 60, "type": "observation", "data": { "code": "HEART_RATE", "value": 105, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "RESP_RATE", "value": 22, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 112, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 68, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "TEMP_C", "value": 39.1, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "SPO2", "value": 95, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 65, "type": "medication", "data": { "drugName": "ceftriaxone", "dose": 2, "doseUnit": "g", "route": "IV", "administeredBy": "nurse-rn-1" }, "note": "Broad-spectrum antibiotics started" }, - - { "offsetMinutes": 75, "type": "order_result", "data": { "orderDescription": "SEP-1: Blood cultures", "resultValue": "2 sets drawn — pending", "resultedBy": "nurse-rn-1" } }, - { "offsetMinutes": 80, "type": "order_result", "data": { "orderDescription": "SEP-1: Serum lactate", "resultValue": "2.8 mmol/L", "resultedBy": "lab-tech-1" } }, - - { "offsetMinutes": 90, "type": "observation", "data": { "code": "HEART_RATE", "value": 112, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "RESP_RATE", "value": 24, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 102, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 62, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "TEMP_C", "value": 39.3, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "SPO2", "value": 94, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "AVPU", "value": 1, "unit": "score", "source": "manual" }, "note": "Patient confused — responds to voice" }, - { "offsetMinutes": 90, "type": "observation", "data": { "code": "LACTATE_MMOL_L", "value": 2.8, "unit": "mmol/L", "source": "lab" } }, - - { "offsetMinutes": 100, "type": "order_result", "data": { "orderDescription": "SEP-1: Broad-spectrum antibiotics", "resultValue": "Ceftriaxone 2g IV administered", "resultedBy": "nurse-rn-1" } }, - { "offsetMinutes": 105, "type": "order_result", "data": { "orderDescription": "SEP-1: IV fluid bolus", "resultValue": "1L NS bolus started", "resultedBy": "nurse-rn-1" } }, - - { "offsetMinutes": 120, "type": "observation", "data": { "code": "HEART_RATE", "value": 118, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "RESP_RATE", "value": 26, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 96, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 58, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "TEMP_C", "value": 39.4, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "SPO2", "value": 93, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "AVPU", "value": 1, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 150, "type": "observation", "data": { "code": "HEART_RATE", "value": 115, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "RESP_RATE", "value": 24, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 100, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 60, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "TEMP_C", "value": 39.0, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "SPO2", "value": 94, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "AVPU", "value": 1, "unit": "score", "source": "manual" } }, - { "offsetMinutes": 150, "type": "observation", "data": { "code": "LACTATE_MMOL_L", "value": 3.4, "unit": "mmol/L", "source": "lab" }, "note": "Repeat lactate — rising" }, - - { "offsetMinutes": 180, "type": "observation", "data": { "code": "HEART_RATE", "value": 108, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "RESP_RATE", "value": 22, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 105, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 64, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "TEMP_C", "value": 38.7, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "SPO2", "value": 95, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" }, "note": "Mentation improving — alert again" }, - - { "offsetMinutes": 240, "type": "observation", "data": { "code": "HEART_RATE", "value": 98, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "RESP_RATE", "value": 20, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 112, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 68, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "TEMP_C", "value": 38.3, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "SPO2", "value": 96, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "LACTATE_MMOL_L", "value": 2.1, "unit": "mmol/L", "source": "lab" }, "note": "Lactate improving after fluids" } - ], - "expectedOutcomes": [ - { "afterOffsetMinutes": 30, "type": "alert", "alertType": "WARNING_TEMP_C", "description": "Temperature 38.6 enters warning range" }, - { "afterOffsetMinutes": 60, "type": "alert", "alertType": "WARNING_HEART_RATE", "description": "HR 105 enters warning range" }, - { "afterOffsetMinutes": 60, "type": "alert", "alertType": "SEPSIS_WARNING", "description": "SIRS criteria met: temp >38.3, HR >90, RR >20, WBC >12" }, - { "afterOffsetMinutes": 90, "type": "alert", "alertType": "QSOFA_WARNING", "description": "qSOFA ≥2: RR 24, SBP 102, AVPU 1" }, - { "afterOffsetMinutes": 90, "type": "bundle", "description": "Sepsis bundle auto-created with 4 orders" }, - { "afterOffsetMinutes": 105, "type": "bundle", "description": "All 4 bundle elements completed — COMPLIANT" }, - { "afterOffsetMinutes": 120, "type": "score", "scoreType": "NEWS2", "expectedMinimum": 7, "description": "NEWS2 reaches HIGH risk" }, - { "afterOffsetMinutes": 120, "type": "alert", "alertType": "NEWS2_EMERGENCY", "description": "NEWS2 ≥7 or single parameter 3" }, - { "afterOffsetMinutes": 120, "type": "alert", "alertType": "RAPID_DETERIORATION", "description": "HR climbed 88→118 and SBP dropped 128→96 rapidly" } - ] -} diff --git a/docs/scenarios/stable-baseline-01.json b/docs/scenarios/stable-baseline-01.json deleted file mode 100644 index 02b877b..0000000 --- a/docs/scenarios/stable-baseline-01.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "scenario": { - "id": "stable-baseline-01", - "name": "Stable Observation Patient — Control", - "description": "40-year-old healthy male admitted for 4-hour observation after minor outpatient procedure. Vitals remain normal throughout with natural physiological noise. No alerts should fire. This is a control scenario to test for false positives.", - "durationMinutes": 240, - "tags": ["stable", "control", "observation", "no-alerts"] - }, - "patient": { - "firstName": "James", - "lastName": "Liu", - "dateOfBirth": "1986-05-10", - "gender": "Male", - "mrn": "SIM-003" - }, - "encounter": { - "department": "Day Surgery", - "room": "DS-3", - "bed": "A", - "encounterType": "Observation", - "chiefComplaint": "Post-procedure observation — arthroscopic knee surgery" - }, - "events": [ - { "offsetMinutes": 0, "type": "observation", "data": { "code": "HEART_RATE", "value": 72, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "RESP_RATE", "value": 14, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 124, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 76, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "TEMP_C", "value": 36.8, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "SPO2", "value": 99, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 0, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 60, "type": "observation", "data": { "code": "HEART_RATE", "value": 75, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "RESP_RATE", "value": 13, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 120, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 74, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "TEMP_C", "value": 36.7, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "SPO2", "value": 98, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 60, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 120, "type": "observation", "data": { "code": "HEART_RATE", "value": 70, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "RESP_RATE", "value": 15, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 126, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 78, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "TEMP_C", "value": 36.9, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "SPO2", "value": 99, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 120, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 180, "type": "observation", "data": { "code": "HEART_RATE", "value": 73, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "RESP_RATE", "value": 14, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 122, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 76, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "TEMP_C", "value": 36.8, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "SPO2", "value": 98, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 180, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } }, - - { "offsetMinutes": 240, "type": "observation", "data": { "code": "HEART_RATE", "value": 74, "unit": "bpm", "source": "monitor" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "RESP_RATE", "value": 14, "unit": "/min", "source": "manual" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "SYSTOLIC_BP", "value": 124, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "DIASTOLIC_BP", "value": 76, "unit": "mmHg", "source": "manual" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "TEMP_C", "value": 36.7, "unit": "°C", "source": "manual" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "SPO2", "value": 99, "unit": "%", "source": "monitor" } }, - { "offsetMinutes": 240, "type": "observation", "data": { "code": "AVPU", "value": 0, "unit": "score", "source": "manual" } } - ], - "expectedOutcomes": [] -}