Run initial test for Climate Resilience Verification Suite

Add first part of Alert Quality Analytics
This commit is contained in:
voltsrage
2026-06-24 03:01:00 +08:00
parent 032cd1d240
commit 185dc93fa1
50 changed files with 4116 additions and 55 deletions
+60 -11
View File
@@ -20,25 +20,43 @@ public class ReplayEngine
// --- 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}");
if (options.ExistingEncounterId.HasValue)
{
result.EncounterId = options.ExistingEncounterId.Value;
if (options.Target == ReplayTarget.Gateway)
SimulatorConsole.DryRun($"Gateway mode — would use existing encounter {result.EncounterId}");
else
SimulatorConsole.DryRun($"Would use existing encounter {result.EncounterId}");
}
else
{
SimulatorConsole.DryRun("Would register patient: " +
$"{scenario.Patient.FirstName} {scenario.Patient.LastName}");
SimulatorConsole.DryRun("Would open encounter: " +
$"{scenario.Encounter.Department} / {scenario.Encounter.EncounterType}");
}
}
else if (options.Target == ReplayTarget.Gateway && options.ExistingEncounterId.HasValue)
{
result.EncounterId = options.ExistingEncounterId.Value;
SimulatorConsole.Info($"Gateway mode — using existing encounter {result.EncounterId}");
}
else if (options.ExistingEncounterId.HasValue)
{
result.EncounterId = options.ExistingEncounterId.Value;
SimulatorConsole.Info($"Using existing encounter {result.EncounterId}");
}
else
{
patient = await _client.RegisterPatientAsync(new RegisterPatientRequest(
var 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(
var encounter = await _client.OpenEncounterAsync(patient.Id, new OpenEncounterRequest(
scenario.Encounter.EncounterType,
DepartmentMapper.ToApiDepartment(scenario.Encounter.Department),
scenario.Encounter.AttendingPhysician,
@@ -91,6 +109,9 @@ public class ReplayEngine
case "order_result":
await ReplayOrderResult(evt, simTimestamp, options, result);
break;
case "alert_ack":
await ReplayAlertAck(evt, simTimestamp, options, result, ct);
break;
}
}
@@ -115,7 +136,9 @@ public class ReplayEngine
{
var observations = new List<IngestObservationRequest>();
var offsetMinutes = cluster[0].OffsetMinutes;
var recordedAt = _scenarioStartTime.AddMinutes(offsetMinutes);
var recordedAt = options.Target == ReplayTarget.Gateway
? DateTimeOffset.UtcNow
: _scenarioStartTime.AddMinutes(offsetMinutes);
foreach (var evt in cluster)
{
@@ -135,7 +158,7 @@ public class ReplayEngine
}
if (!options.DryRun && observations.Count > 0)
await _client.SendObservationBatchAsync(result.EncounterId, observations);
await _client.SendObservationBatchAsync(result.EncounterId, observations, options.Target);
}
private async Task ReplayMedication(
@@ -238,4 +261,30 @@ public class ReplayEngine
"Lab" or "LAB" or "lab" => "LAB",
_ => throw new InvalidOperationException($"Unknown observation source: '{source}'")
};
private async Task ReplayAlertAck(
ScenarioEvent evt, string simTime, ReplayOptions options, ReplayResult result,
CancellationToken ct)
{
var alertType = evt.Data.GetProperty("alertType").GetString()!;
var clinicianId = evt.Data.GetProperty("clinicianId").GetString()!;
var note = evt.Data.TryGetProperty("note", out var n) ? n.GetString() : null;
if (options.DryRun)
{
SimulatorConsole.DryRun($"[{simTime}] ACK {alertType} by {clinicianId}");
return;
}
var waitForAlert = options.Target == ReplayTarget.Central
? TimeSpan.FromSeconds(30)
: (TimeSpan?)null;
var ok = await _client.TryAcknowledgeAlertAsync(
result.EncounterId, alertType, clinicianId, note, waitForAlert, ct);
if (ok)
SimulatorConsole.Event(simTime, $"ACK {alertType} by {clinicianId}");
else
SimulatorConsole.Warn($"[{simTime}] ACK failed — no open {alertType} alert found");
}
}
+5 -1
View File
@@ -1,5 +1,9 @@
public enum ReplayTarget { Central, Gateway }
public record ReplayOptions(
double Speed = 60,
bool Poll = false,
int PollIntervalSeconds = 5,
bool DryRun = false);
bool DryRun = false,
ReplayTarget Target = ReplayTarget.Central,
Guid? ExistingEncounterId = null);