Fix issues with critical alerts breaking the simulation

This commit is contained in:
voltsrage
2026-06-25 02:06:35 +08:00
parent df6fbed401
commit 09a84f34ba
29 changed files with 196 additions and 155 deletions
@@ -6,9 +6,9 @@ import { useAuthStore } from '@/stores/auth'
const alert = {
id: 'alert-1',
alertType: 'SofaSepsis',
severity: 'Critical',
status: 'Open',
alertType: 'SOFA_SEPSIS',
severity: 'CRITICAL',
status: 'OPEN',
details: 'SOFA delta >= 2',
}
@@ -5,9 +5,9 @@ import AlertCard from '@/components/alerts/AlertCard.vue'
const openAlert = {
id: 'alert-1',
alertType: 'SepsisWarning',
severity: 'Critical',
status: 'Open',
alertType: 'SEPSIS_WARNING',
severity: 'CRITICAL',
status: 'OPEN',
details: 'SIRS criteria met',
triggeredAt: '2026-06-19T12:00:00Z',
}
@@ -15,7 +15,7 @@ const openAlert = {
const resolvedAlert = {
...openAlert,
id: 'alert-2',
status: 'Resolved',
status: 'RESOLVED',
}
describe('AlertCard', () => {
@@ -25,7 +25,7 @@ describe('AlertCard', () => {
it('showsAlertTypeAndSeverity', () => {
const wrapper = mount(AlertCard, { props: { alert: openAlert } })
expect(wrapper.text()).toContain('Critical')
expect(wrapper.text()).toContain('CRITICAL')
expect(wrapper.text()).toContain('Sepsis Warning (SIRS — Legacy)')
})
@@ -55,7 +55,7 @@ describe('AlertCard', () => {
props: {
alert: {
...openAlert,
status: 'Acknowledged',
status: 'ACKNOWLEDGED',
acknowledgedBy: 'Demo Nurse (NURSE)',
acknowledgedAt: '2026-06-19T12:30:00Z',
},
@@ -3,19 +3,19 @@ import { alertTypeLabel, bundleTriggerLabel } from '@/api/normalize'
describe('AlertLabels', () => {
it('sofaSepsisLabel', () => {
expect(alertTypeLabel('SofaSepsis')).toBe('Sepsis Alert (SOFA)')
expect(alertTypeLabel('SOFA_SEPSIS')).toBe('Sepsis Alert (SOFA)')
})
it('legacySepsisLabel', () => {
expect(alertTypeLabel('SepsisWarning')).toBe('Sepsis Warning (SIRS — Legacy)')
expect(alertTypeLabel('SEPSIS_WARNING')).toBe('Sepsis Warning (SIRS — Legacy)')
})
it('qsofaScreenLabel', () => {
expect(alertTypeLabel('QsofaScreen')).toBe('qSOFA Screen')
expect(alertTypeLabel('QSOFA_SCREEN')).toBe('qSOFA Screen')
})
it('gcsCriticalLabel', () => {
expect(alertTypeLabel('GcsCritical')).toBe('GCS Critical (≤ 8)')
expect(alertTypeLabel('GCS_CRITICAL')).toBe('GCS Critical (≤ 8)')
})
it('bundleTriggerSofa', () => {
@@ -5,16 +5,16 @@ import AlertReasoning from '@/components/alerts/AlertReasoning.vue'
const sepsisAlert = {
id: 'alert-1',
alertType: 'SepsisWarning',
severity: 'Critical',
alertType: 'SEPSIS_WARNING',
severity: 'CRITICAL',
details: 'SIRS criteria met',
triggeredAt: '2026-06-19T12:00:00Z',
}
const qsofaScreenAlert = {
id: 'alert-2',
alertType: 'QsofaScreen',
severity: 'Warning',
alertType: 'QSOFA_SCREEN',
severity: 'WARNING',
details: 'qSOFA screen positive',
triggeredAt: '2026-06-19T12:30:00Z',
}
@@ -42,7 +42,7 @@ describe('AlertReasoning', () => {
const unknown = {
id: 'alert-3',
alertType: 'CustomUnknown',
severity: 'Warning',
severity: 'WARNING',
details: 'Something unusual happened',
triggeredAt: '2026-06-19T13:00:00Z',
}
@@ -54,8 +54,8 @@ describe('AlertReasoning', () => {
it('showsStructuredExplanationWhenPresent', () => {
const news2Alert = {
id: 'alert-4',
alertType: 'News2Emergency',
severity: 'Critical',
alertType: 'NEWS2_EMERGENCY',
severity: 'CRITICAL',
details: 'NEWS2 score 8 (HIGH): RESP_RATE=3, SPO2=2',
triggeredAt: '2026-06-19T14:00:00Z',
explanation: {
@@ -18,9 +18,9 @@ describe('CriticalAlertBanner', () => {
const alertStore = useAlertStore()
alertStore.bannerAlerts = [{
id: 'alert-1',
alertType: 'SofaSepsis',
severity: 'Critical',
status: 'Open',
alertType: 'SOFA_SEPSIS',
severity: 'CRITICAL',
status: 'OPEN',
details: 'SOFA delta >= 2',
explanation: {
narrativeSummary: 'SOFA 6 — respiratory (+2), renal (+2).',
@@ -13,9 +13,9 @@ const events = [
{
type: 'alert',
timestamp: '2026-06-23T11:00:00Z',
alertType: 'QsofaScreen',
severity: 'Warning',
status: 'Open',
alertType: 'QSOFA_SCREEN',
severity: 'WARNING',
status: 'OPEN',
},
{
type: 'medication',
@@ -23,8 +23,8 @@ vi.mock('@/stores/alertQuality', () => ({
const defaultProps = {
alertId: 'alert-1',
alertType: 'SepsisWarning',
severity: 'Critical',
alertType: 'SEPSIS_WARNING',
severity: 'CRITICAL',
}
function ratingButtons(wrapper) {
@@ -10,8 +10,8 @@ const { mockSummaryStats, mockByAlertType } = vi.hoisted(() => ({
falsePositiveRate: 33,
},
mockByAlertType: {
SepsisWarning: [{ rating: 'useful' }, { rating: 'would-act' }],
WarningHeartRate: [{ rating: 'false-positive' }],
SEPSIS_WARNING: [{ rating: 'useful' }, { rating: 'would-act' }],
WARNING_HEART_RATE: [{ rating: 'false-positive' }],
},
}))
@@ -3,23 +3,23 @@ import { detectNewCriticalAlerts, isNotifiableCriticalAlert } from '@/composable
const criticalOpen = {
id: 'a1',
severity: 'Critical',
status: 'Open',
alertType: 'SofaSepsis',
severity: 'CRITICAL',
status: 'OPEN',
alertType: 'SOFA_SEPSIS',
}
const criticalAcknowledged = {
id: 'a2',
severity: 'Critical',
status: 'Acknowledged',
alertType: 'News2Emergency',
severity: 'CRITICAL',
status: 'ACKNOWLEDGED',
alertType: 'NEWS2_EMERGENCY',
}
const warningOpen = {
id: 'a3',
severity: 'Warning',
status: 'Open',
alertType: 'News2Warning',
severity: 'WARNING',
status: 'OPEN',
alertType: 'NEWS2_WARNING',
}
describe('criticalAlertDetect', () => {
@@ -39,7 +39,7 @@ describe('criticalAlertDetect', () => {
it('detectsNewCriticalAlertsAfterSeed', () => {
const seeded = detectNewCriticalAlerts([criticalOpen], [], false)
const next = detectNewCriticalAlerts(
[criticalOpen, { ...criticalOpen, id: 'a4', alertType: 'GcsCritical' }],
[criticalOpen, { ...criticalOpen, id: 'a4', alertType: 'GCS_CRITICAL' }],
seeded.nextSeenIds,
seeded.seeded,
)
@@ -29,7 +29,7 @@ const enrichment = {
admissionReason: 'Sepsis workup',
patient: { allergies: 'Penicillin' },
},
openAlerts: [{ alertType: 'News2Emergency' }],
openAlerts: [{ alertType: 'NEWS2_EMERGENCY' }],
pendingOrders: [{ description: 'Blood cultures', status: 'Pending' }],
vitals: extractLatestVitals([
{ observationCode: 'HEART_RATE', value: 110, unit: 'bpm', recordedAt: '2026-06-23T10:00:00Z' },
@@ -11,9 +11,9 @@ describe('alert store notifications', () => {
const store = useAlertStore()
const critical = {
id: 'alert-1',
severity: 'Critical',
status: 'Open',
alertType: 'SofaSepsis',
severity: 'CRITICAL',
status: 'OPEN',
alertType: 'SOFA_SEPSIS',
}
expect(store.applyPollResults([critical])).toEqual([])
@@ -21,9 +21,9 @@ describe('alert store notifications', () => {
const next = {
id: 'alert-2',
severity: 'Critical',
status: 'Open',
alertType: 'GcsCritical',
severity: 'CRITICAL',
status: 'OPEN',
alertType: 'GCS_CRITICAL',
}
const newAlerts = store.applyPollResults([critical, next])
expect(newAlerts.map(alert => alert.id)).toEqual(['alert-2'])
@@ -14,7 +14,7 @@ describe('useFeedbackStore', () => {
it('addFeedback_createsEntry', () => {
const store = useFeedbackStore()
store.addFeedback('a1', 'SepsisWarning', 'Critical', 'useful')
store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'useful')
expect(store.entries).toHaveLength(1)
expect(store.entries[0].alertId).toBe('a1')
@@ -23,8 +23,8 @@ describe('useFeedbackStore', () => {
it('addFeedback_updatesExisting', () => {
const store = useFeedbackStore()
store.addFeedback('a1', 'SepsisWarning', 'Critical', 'useful')
store.addFeedback('a1', 'SepsisWarning', 'Critical', 'false-positive')
store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'useful')
store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'false-positive')
expect(store.entries).toHaveLength(1)
expect(store.entries[0].rating).toBe('false-positive')
@@ -32,10 +32,10 @@ describe('useFeedbackStore', () => {
it('stats_computesCorrectly', () => {
const store = useFeedbackStore()
store.addFeedback('a1', 'SepsisWarning', 'Critical', 'useful')
store.addFeedback('a2', 'SepsisWarning', 'Critical', 'would-act')
store.addFeedback('a3', 'WarningHeartRate', 'Warning', 'false-positive')
store.addFeedback('a4', 'WarningHeartRate', 'Warning', 'too-early')
store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'useful')
store.addFeedback('a2', 'SEPSIS_WARNING', 'CRITICAL', 'would-act')
store.addFeedback('a3', 'WARNING_HEART_RATE', 'WARNING', 'false-positive')
store.addFeedback('a4', 'WARNING_HEART_RATE', 'WARNING', 'too-early')
expect(store.stats.total).toBe(4)
expect(store.stats.useful).toBe(2)
@@ -46,18 +46,18 @@ describe('useFeedbackStore', () => {
it('byAlertType_groupsCorrectly', () => {
const store = useFeedbackStore()
store.addFeedback('a1', 'SepsisWarning', 'Critical', 'useful')
store.addFeedback('a2', 'WarningHeartRate', 'Warning', 'false-positive')
store.addFeedback('a3', 'SepsisWarning', 'Critical', 'too-early')
store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'useful')
store.addFeedback('a2', 'WARNING_HEART_RATE', 'WARNING', 'false-positive')
store.addFeedback('a3', 'SEPSIS_WARNING', 'CRITICAL', 'too-early')
expect(Object.keys(store.byAlertType)).toHaveLength(2)
expect(store.byAlertType.SepsisWarning).toHaveLength(2)
expect(store.byAlertType.WarningHeartRate).toHaveLength(1)
expect(store.byAlertType.SEPSIS_WARNING).toHaveLength(2)
expect(store.byAlertType.WARNING_HEART_RATE).toHaveLength(1)
})
it('exportAsJson_generatesValidJson', () => {
const store = useFeedbackStore()
store.addFeedback('a1', 'SepsisWarning', 'Critical', 'useful')
store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'useful')
let capturedBlob = null
const click = vi.fn()
@@ -81,7 +81,7 @@ describe('useFeedbackStore', () => {
it('clearAll_emptiesEntries', () => {
const store = useFeedbackStore()
store.addFeedback('a1', 'SepsisWarning', 'Critical', 'useful')
store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'useful')
store.clearAll()
expect(store.entries).toHaveLength(0)
@@ -89,7 +89,7 @@ describe('useFeedbackStore', () => {
it('persistsToLocalStorage', () => {
const store = useFeedbackStore()
store.addFeedback('a1', 'SepsisWarning', 'Critical', 'useful')
store.addFeedback('a1', 'SEPSIS_WARNING', 'CRITICAL', 'useful')
const stored = JSON.parse(localStorage.getItem('vigilcare-feedback'))
expect(stored).toHaveLength(1)