diff --git a/enterprise-admin-alert-escalation-guard/README.md b/enterprise-admin-alert-escalation-guard/README.md new file mode 100644 index 00000000..8e468008 --- /dev/null +++ b/enterprise-admin-alert-escalation-guard/README.md @@ -0,0 +1,48 @@ +# Enterprise Admin Alert Escalation Guard + +This module is a dependency-free, synthetic-data-only guard for SCIBASE +Enterprise Tooling. It validates whether enterprise admin alerts can safely be +muted, digested, throttled, or routed through webhooks without hiding +compliance, security, export, or integration obligations. + +## What It Checks + +- Critical or high-severity alerts delayed by digest settings. +- Urgent alerts muted by owner preferences. +- Quiet-hours overrides for compliance and security alerts. +- Alerts routed to inactive owners or admins on leave. +- Required webhook routes with unhealthy failure rates. +- Duplicate suppression near compliance or export deadlines. +- Missing delivery channels for admin dashboard events. + +## Local Commands + +```bash +npm run check +npm test +npm run demo +``` + +The demo writes reviewer artifacts under `reports/`: + +- `admin-alert-escalation-packet.json` +- `admin-alert-escalation-report.md` +- `summary.svg` +- `demo.mp4` + +## Requirements Map + +| Issue #19 capability | Coverage in this slice | +| --- | --- | +| Admin dashboards | Emits dashboard badges for digest bypass, owner fallback, webhook fallback, and visible deadlines. | +| Compliance tracking | Keeps compliance, security, IRB, and export obligations visible until acknowledged. | +| API and webhooks | Emits webhook-ready event summaries without delivering live webhooks. | +| Enterprise governance | Enforces owner fallback, quiet-hours override, and duplicate-suppression safety for institutional admins. | + +## Safety Boundaries + +- Uses only synthetic fixtures in `sample-data.js`. +- Does not deliver live email, SMS, Slack, webhook, or external provider + notifications. +- Does not include real institutional alerts, private users, credentials, or + project data. diff --git a/enterprise-admin-alert-escalation-guard/demo.js b/enterprise-admin-alert-escalation-guard/demo.js new file mode 100644 index 00000000..f24d083a --- /dev/null +++ b/enterprise-admin-alert-escalation-guard/demo.js @@ -0,0 +1,136 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +const { spawnSync } = require('child_process'); +const sampleAlerts = require('./sample-data'); +const { evaluateAlerts } = require('./index'); + +const reportDir = path.join(__dirname, 'reports'); +const asOfDate = '2026-05-22'; + +fs.mkdirSync(reportDir, { recursive: true }); + +const portfolio = evaluateAlerts(sampleAlerts, { asOfDate }); +const jsonPath = path.join(reportDir, 'admin-alert-escalation-packet.json'); +const markdownPath = path.join(reportDir, 'admin-alert-escalation-report.md'); +const svgPath = path.join(reportDir, 'summary.svg'); +const mp4Path = path.join(reportDir, 'demo.mp4'); + +fs.writeFileSync(jsonPath, `${JSON.stringify(portfolio, null, 2)}\n`); +fs.writeFileSync(markdownPath, renderMarkdown(portfolio)); +fs.writeFileSync(svgPath, renderSvg(portfolio)); +renderVideo(portfolio, mp4Path); + +console.log(`Wrote ${path.relative(process.cwd(), jsonPath)}`); +console.log(`Wrote ${path.relative(process.cwd(), markdownPath)}`); +console.log(`Wrote ${path.relative(process.cwd(), svgPath)}`); +console.log(`Wrote ${path.relative(process.cwd(), mp4Path)}`); + +function renderMarkdown(portfolio) { + return [ + '# Enterprise Admin Alert Escalation Guard Report', + '', + `As of: ${portfolio.asOfDate}`, + `Alert digest: \`${portfolio.auditDigest}\``, + '', + '## Summary', + '', + `- Alerts reviewed: ${portfolio.alertCount}`, + `- Findings: ${portfolio.findingCount}`, + `- Escalated alerts: ${portfolio.escalatedAlerts.join(', ') || 'none'}`, + `- Actions: ${Object.entries(portfolio.byAction).map(([action, count]) => `${action}=${count}`).join(', ')}`, + '', + '## Alert Decisions', + '', + '| Alert | Category | Severity | Action | Findings | Dashboard badges |', + '| --- | --- | --- | --- | ---: | --- |', + ...portfolio.packets.map((packet) => `| ${packet.alertId} | ${packet.category} | ${packet.severity} | ${packet.action} | ${packet.findingCount} | ${packet.dashboardBadges.join(', ') || 'none'} |`), + '', + '## Guardrails', + '', + '- Uses synthetic enterprise alert, owner, routing, digest, and webhook metadata only.', + '- Does not deliver live email, SMS, Slack, webhook, or external provider notifications.', + '- Keeps critical compliance/security alerts visible even when muted, digested, quiet-hours, duplicated, or routed to unavailable owners.', + '- Emits deterministic dashboard badges, webhook-ready event summaries, and audit digests.', + '' + ].join('\n'); +} + +function renderSvg(portfolio) { + const actions = Object.entries(portfolio.byAction) + .map(([action, count]) => `${escapeXml(action)} (${count})`) + .join(' / '); + + return ` + + Enterprise admin alert escalation guard summary + Synthetic enterprise alert delivery and escalation decisions. + + + Enterprise admin alert escalation guard + Mute, digest, owner, webhook, and quiet-hours routing checks + + ${portfolio.alertCount} alerts + admin routing + + ${portfolio.escalatedAlerts.length} escalated + mute bypass + + ${portfolio.findingCount} findings + review packets + Actions: ${actions} + Digest: ${portfolio.auditDigest.slice(0, 32)}... + +`; +} + +function renderVideo(portfolio, outputPath) { + const font = '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'; + const filters = [ + drawText(font, 'SCIBASE #19 Enterprise Tooling', 64, 72, 40, 'white'), + drawText(font, 'Admin notification escalation guard', 64, 136, 36, 'white'), + drawText(font, `Reviewed ${portfolio.alertCount} synthetic admin alerts`, 84, 238, 33, '0xdbeafe'), + drawText(font, `${portfolio.escalatedAlerts.length} alerts escalated before mute or digest`, 84, 304, 32, '0xfecaca'), + drawText(font, `${portfolio.findingCount} findings with dashboard badges and webhook summaries`, 84, 370, 28, '0xdcfce7'), + drawText(font, 'Checks quiet hours owner fallback webhook health duplicates and digest delays', 84, 462, 25, '0xe0f2fe'), + drawText(font, 'No live notification delivery email SMS Slack webhooks or external providers', 84, 522, 25, '0xfef3c7'), + drawText(font, `Audit digest ${portfolio.auditDigest.slice(0, 24)}`, 84, 596, 24, '0xcbd5e1') + ].join(','); + + const result = spawnSync('ffmpeg', [ + '-y', + '-f', 'lavfi', + '-i', 'color=c=0x233142:s=1280x720:d=4:r=25', + '-vf', filters, + '-c:v', 'libx264', + '-pix_fmt', 'yuv420p', + outputPath + ], { encoding: 'utf8' }); + + if (result.status !== 0) { + const message = [result.stdout, result.stderr].filter(Boolean).join('\n'); + throw new Error(`ffmpeg failed to render demo.mp4:\n${message}`); + } +} + +function drawText(font, text, x, y, size, color) { + return `drawtext=fontfile='${font}':text='${escapeDrawText(text)}':x=${x}:y=${y}:fontsize=${size}:fontcolor=${color}`; +} + +function escapeDrawText(value) { + return String(value) + .replace(/\\/g, '\\\\') + .replace(/:/g, '\\:') + .replace(/'/g, "\\'") + .replace(/,/g, '\\,') + .replace(/&/g, '\\&'); +} + +function escapeXml(value) { + return String(value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); +} diff --git a/enterprise-admin-alert-escalation-guard/index.js b/enterprise-admin-alert-escalation-guard/index.js new file mode 100644 index 00000000..d4b2e9f1 --- /dev/null +++ b/enterprise-admin-alert-escalation-guard/index.js @@ -0,0 +1,242 @@ +'use strict'; + +const crypto = require('crypto'); + +const DEFAULT_POLICY = Object.freeze({ + asOfDate: '2026-05-22', + criticalSeverities: ['critical', 'high'], + urgentCategories: ['compliance_deadline', 'security_integration', 'export_failure', 'irb_risk'], + maxDigestDelayHours: 4, + maxWebhookFailureRate: 0.15, + maxDuplicateWindowHours: 24, + quietHoursOverrideSeverities: ['critical', 'high'] +}); + +function stableStringify(value) { + if (Array.isArray(value)) return `[${value.map(stableStringify).join(',')}]`; + if (value && typeof value === 'object') { + return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`).join(',')}}`; + } + return JSON.stringify(value); +} + +function digest(value) { + return crypto.createHash('sha256').update(stableStringify(value)).digest('hex'); +} + +function normalizeToken(value) { + return String(value || '').trim().toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, ''); +} + +function addFinding(findings, code, severity, message, remediation) { + findings.push({ code, severity, message, remediation }); +} + +function hoursUntil(dueAt, asOfDate) { + if (!dueAt) return null; + const due = new Date(dueAt); + const asOf = new Date(`${asOfDate}T00:00:00Z`); + if (Number.isNaN(due.getTime())) throw new Error(`Invalid dueAt: ${dueAt}`); + return Math.round((due.getTime() - asOf.getTime()) / (60 * 60 * 1000)); +} + +function evaluateAlert(alert, options = {}) { + const policy = Object.assign({}, DEFAULT_POLICY, options.policy || {}, { + asOfDate: options.asOfDate || (options.policy && options.policy.asOfDate) || DEFAULT_POLICY.asOfDate + }); + const severity = normalizeToken(alert.severity || 'low'); + const category = normalizeToken(alert.category || 'general'); + const routing = alert.routing || {}; + const owner = alert.owner || {}; + const webhook = alert.webhook || {}; + const digestSettings = routing.digest || {}; + const findings = []; + const urgent = policy.criticalSeverities.includes(severity) || policy.urgentCategories.includes(category); + const dueInHours = hoursUntil(alert.dueAt, policy.asOfDate); + + if (urgent && digestSettings.enabled && Number(digestSettings.delayHours || 0) > policy.maxDigestDelayHours) { + addFinding( + findings, + 'urgent_alert_delayed_by_digest', + 'critical', + `${alert.id} is urgent but digest delay is ${digestSettings.delayHours} hours`, + 'bypass digest and deliver immediately to primary plus escalation owners' + ); + } + + if (urgent && routing.muted === true) { + addFinding( + findings, + 'urgent_alert_muted', + 'critical', + `${alert.id} is urgent but owner preferences mute the route`, + 'override mute for compliance-critical alert and log preference bypass' + ); + } + + if (routing.quietHours === true && policy.quietHoursOverrideSeverities.includes(severity)) { + addFinding( + findings, + 'quiet_hours_override_required', + severity === 'critical' ? 'critical' : 'high', + `${alert.id} falls in quiet hours but severity is ${severity}`, + 'use emergency channel and record quiet-hours override justification' + ); + } + + if (owner.active === false || owner.onLeave === true) { + addFinding( + findings, + 'inactive_owner_route', + 'high', + `${alert.id} is routed to inactive or unavailable owner ${owner.id || 'unknown'}`, + 'route to delegated owner group and update dashboard ownership metadata' + ); + } + + if (webhook.required && Number(webhook.failureRate || 0) > policy.maxWebhookFailureRate) { + addFinding( + findings, + 'webhook_health_fallback_required', + urgent ? 'high' : 'medium', + `${alert.id} webhook failure rate ${(Number(webhook.failureRate) * 100).toFixed(1)}% exceeds policy`, + 'fallback to admin inbox and include webhook repair action in the packet' + ); + } + + if (routing.duplicateSuppressed === true && dueInHours !== null && dueInHours <= policy.maxDuplicateWindowHours) { + addFinding( + findings, + 'duplicate_suppression_near_deadline', + 'high', + `${alert.id} is deduplicated with ${dueInHours} hours before deadline`, + 'show one canonical alert and keep deadline badge visible until acknowledged' + ); + } + + if (!routing.channels || routing.channels.length === 0) { + addFinding( + findings, + 'missing_delivery_channel', + urgent ? 'high' : 'medium', + `${alert.id} has no delivery channel`, + 'assign admin inbox channel and require owner acknowledgement' + ); + } + + const selected = selectAction(findings); + const packet = { + alertId: alert.id, + category, + severity, + dueInHours, + urgent, + action: selected.action, + decisionSeverity: selected.severity, + reason: selected.reason, + ownerId: owner.id || null, + routedChannels: routing.channels || [], + webhookRequired: Boolean(webhook.required), + findingCount: findings.length, + findings, + dashboardBadges: buildDashboardBadges(alert, findings), + webhookEvent: buildWebhookEvent(alert, selected, findings) + }; + + packet.auditDigest = digest(Object.assign({}, packet, { auditDigest: undefined })); + return packet; +} + +function selectAction(findings) { + if (findings.some((finding) => finding.severity === 'critical')) { + return { + action: 'deliver_now_and_escalate', + severity: 'critical', + reason: 'urgent enterprise alert would otherwise be muted, delayed, or hidden' + }; + } + + if (findings.some((finding) => finding.severity === 'high')) { + return { + action: 'hold_digest_and_route_owner_fallback', + severity: 'high', + reason: 'alert requires owner fallback or visible escalation before digesting' + }; + } + + if (findings.some((finding) => finding.severity === 'medium')) { + return { + action: 'warn_and_repair_delivery_path', + severity: 'medium', + reason: 'delivery path should be repaired while alert remains visible' + }; + } + + return { + action: 'allow_digest_or_standard_delivery', + severity: 'low', + reason: 'alert routing satisfies admin notification policy' + }; +} + +function buildDashboardBadges(alert, findings) { + const badges = []; + if (findings.some((finding) => finding.code.includes('digest') || finding.code.includes('muted'))) badges.push('bypass-digest'); + if (findings.some((finding) => finding.code.includes('owner'))) badges.push('owner-fallback'); + if (findings.some((finding) => finding.code.includes('webhook'))) badges.push('webhook-fallback'); + if (findings.some((finding) => finding.code.includes('deadline'))) badges.push('deadline-visible'); + if (badges.length === 0 && normalizeToken(alert.severity) === 'low') badges.push('standard-delivery'); + return badges; +} + +function buildWebhookEvent(alert, selected, findings) { + return { + eventType: 'enterprise.alert.routing.reviewed', + alertId: alert.id, + action: selected.action, + findingCodes: findings.map((finding) => finding.code), + requiresAcknowledgement: selected.severity === 'critical' || selected.severity === 'high', + eventDigest: digest({ + alertId: alert.id, + action: selected.action, + findingCodes: findings.map((finding) => finding.code) + }) + }; +} + +function evaluateAlerts(alerts, options = {}) { + const packets = alerts.map((alert) => evaluateAlert(alert, options)); + const summary = packets.reduce((acc, packet) => { + acc.byAction[packet.action] = (acc.byAction[packet.action] || 0) + 1; + acc.bySeverity[packet.decisionSeverity] = (acc.bySeverity[packet.decisionSeverity] || 0) + 1; + if (packet.decisionSeverity === 'critical' || packet.decisionSeverity === 'high') acc.escalatedAlerts.push(packet.alertId); + acc.findingCount += packet.findingCount; + return acc; + }, { + byAction: {}, + bySeverity: {}, + escalatedAlerts: [], + findingCount: 0 + }); + + const portfolio = { + asOfDate: options.asOfDate || DEFAULT_POLICY.asOfDate, + alertCount: packets.length, + findingCount: summary.findingCount, + escalatedAlerts: summary.escalatedAlerts, + byAction: summary.byAction, + bySeverity: summary.bySeverity, + packets + }; + + portfolio.auditDigest = digest(portfolio); + return portfolio; +} + +module.exports = { + DEFAULT_POLICY, + digest, + evaluateAlert, + evaluateAlerts, + hoursUntil +}; diff --git a/enterprise-admin-alert-escalation-guard/package.json b/enterprise-admin-alert-escalation-guard/package.json new file mode 100644 index 00000000..74abe3f3 --- /dev/null +++ b/enterprise-admin-alert-escalation-guard/package.json @@ -0,0 +1,13 @@ +{ + "name": "enterprise-admin-alert-escalation-guard", + "version": "1.0.0", + "private": true, + "description": "Synthetic enterprise admin notification escalation guard for SCIBASE enterprise tooling.", + "main": "index.js", + "scripts": { + "check": "node --check index.js && node --check sample-data.js && node --check test.js && node --check demo.js", + "test": "node test.js", + "demo": "node demo.js" + }, + "license": "MIT" +} diff --git a/enterprise-admin-alert-escalation-guard/reports/admin-alert-escalation-packet.json b/enterprise-admin-alert-escalation-guard/reports/admin-alert-escalation-packet.json new file mode 100644 index 00000000..395ab803 --- /dev/null +++ b/enterprise-admin-alert-escalation-guard/reports/admin-alert-escalation-packet.json @@ -0,0 +1,202 @@ +{ + "asOfDate": "2026-05-22", + "alertCount": 4, + "findingCount": 8, + "escalatedAlerts": [ + "ALERT-COMPLIANCE-001", + "ALERT-WEBHOOK-022" + ], + "byAction": { + "deliver_now_and_escalate": 1, + "hold_digest_and_route_owner_fallback": 1, + "warn_and_repair_delivery_path": 1, + "allow_digest_or_standard_delivery": 1 + }, + "bySeverity": { + "critical": 1, + "high": 1, + "medium": 1, + "low": 1 + }, + "packets": [ + { + "alertId": "ALERT-COMPLIANCE-001", + "category": "compliance_deadline", + "severity": "critical", + "dueInHours": 18, + "urgent": true, + "action": "deliver_now_and_escalate", + "decisionSeverity": "critical", + "reason": "urgent enterprise alert would otherwise be muted, delayed, or hidden", + "ownerId": "research-office-primary", + "routedChannels": [ + "admin_digest" + ], + "webhookRequired": true, + "findingCount": 6, + "findings": [ + { + "code": "urgent_alert_delayed_by_digest", + "severity": "critical", + "message": "ALERT-COMPLIANCE-001 is urgent but digest delay is 12 hours", + "remediation": "bypass digest and deliver immediately to primary plus escalation owners" + }, + { + "code": "urgent_alert_muted", + "severity": "critical", + "message": "ALERT-COMPLIANCE-001 is urgent but owner preferences mute the route", + "remediation": "override mute for compliance-critical alert and log preference bypass" + }, + { + "code": "quiet_hours_override_required", + "severity": "critical", + "message": "ALERT-COMPLIANCE-001 falls in quiet hours but severity is critical", + "remediation": "use emergency channel and record quiet-hours override justification" + }, + { + "code": "inactive_owner_route", + "severity": "high", + "message": "ALERT-COMPLIANCE-001 is routed to inactive or unavailable owner research-office-primary", + "remediation": "route to delegated owner group and update dashboard ownership metadata" + }, + { + "code": "webhook_health_fallback_required", + "severity": "high", + "message": "ALERT-COMPLIANCE-001 webhook failure rate 32.0% exceeds policy", + "remediation": "fallback to admin inbox and include webhook repair action in the packet" + }, + { + "code": "duplicate_suppression_near_deadline", + "severity": "high", + "message": "ALERT-COMPLIANCE-001 is deduplicated with 18 hours before deadline", + "remediation": "show one canonical alert and keep deadline badge visible until acknowledged" + } + ], + "dashboardBadges": [ + "bypass-digest", + "owner-fallback", + "webhook-fallback", + "deadline-visible" + ], + "webhookEvent": { + "eventType": "enterprise.alert.routing.reviewed", + "alertId": "ALERT-COMPLIANCE-001", + "action": "deliver_now_and_escalate", + "findingCodes": [ + "urgent_alert_delayed_by_digest", + "urgent_alert_muted", + "quiet_hours_override_required", + "inactive_owner_route", + "webhook_health_fallback_required", + "duplicate_suppression_near_deadline" + ], + "requiresAcknowledgement": true, + "eventDigest": "699c9912707d495d6a9b34fd099859ed00df5a8ced1cbd78fa74d1b738caa1f5" + }, + "auditDigest": "0e910b57e1e875b89e998e647ee6871aa620caabc4422ee34f80d1b170e48f4d" + }, + { + "alertId": "ALERT-WEBHOOK-022", + "category": "security_integration", + "severity": "high", + "dueInHours": 57, + "urgent": true, + "action": "hold_digest_and_route_owner_fallback", + "decisionSeverity": "high", + "reason": "alert requires owner fallback or visible escalation before digesting", + "ownerId": "integration-admin", + "routedChannels": [ + "slack", + "admin_inbox" + ], + "webhookRequired": true, + "findingCount": 1, + "findings": [ + { + "code": "webhook_health_fallback_required", + "severity": "high", + "message": "ALERT-WEBHOOK-022 webhook failure rate 24.0% exceeds policy", + "remediation": "fallback to admin inbox and include webhook repair action in the packet" + } + ], + "dashboardBadges": [ + "webhook-fallback" + ], + "webhookEvent": { + "eventType": "enterprise.alert.routing.reviewed", + "alertId": "ALERT-WEBHOOK-022", + "action": "hold_digest_and_route_owner_fallback", + "findingCodes": [ + "webhook_health_fallback_required" + ], + "requiresAcknowledgement": true, + "eventDigest": "851c86c5b4962302b9f916a8dcbf79812b6bd3a7b0e102f3d0830635e11f0940" + }, + "auditDigest": "3b59e442a407076677b3e19f2b7a9332da97a5f637707eeaf4e22b461ac7fe7a" + }, + { + "alertId": "ALERT-DASHBOARD-077", + "category": "usage_anomaly", + "severity": "medium", + "dueInHours": 180, + "urgent": false, + "action": "warn_and_repair_delivery_path", + "decisionSeverity": "medium", + "reason": "delivery path should be repaired while alert remains visible", + "ownerId": "department-chair", + "routedChannels": [], + "webhookRequired": false, + "findingCount": 1, + "findings": [ + { + "code": "missing_delivery_channel", + "severity": "medium", + "message": "ALERT-DASHBOARD-077 has no delivery channel", + "remediation": "assign admin inbox channel and require owner acknowledgement" + } + ], + "dashboardBadges": [], + "webhookEvent": { + "eventType": "enterprise.alert.routing.reviewed", + "alertId": "ALERT-DASHBOARD-077", + "action": "warn_and_repair_delivery_path", + "findingCodes": [ + "missing_delivery_channel" + ], + "requiresAcknowledgement": false, + "eventDigest": "6d6746d55dc430be4bc450358fc95d10cab304a7959aa2160d26c5151fdf7da2" + }, + "auditDigest": "61e2358f2125cb99be6c435441e7613b1b264faff6bad4b94f899e46e26b798f" + }, + { + "alertId": "ALERT-INFO-100", + "category": "weekly_summary", + "severity": "low", + "dueInHours": 348, + "urgent": false, + "action": "allow_digest_or_standard_delivery", + "decisionSeverity": "low", + "reason": "alert routing satisfies admin notification policy", + "ownerId": "research-ops", + "routedChannels": [ + "admin_digest" + ], + "webhookRequired": false, + "findingCount": 0, + "findings": [], + "dashboardBadges": [ + "standard-delivery" + ], + "webhookEvent": { + "eventType": "enterprise.alert.routing.reviewed", + "alertId": "ALERT-INFO-100", + "action": "allow_digest_or_standard_delivery", + "findingCodes": [], + "requiresAcknowledgement": false, + "eventDigest": "04a40a820e3ad0ed259e8c05153cdb1c53b3e4aec11230d167095bf898da5f02" + }, + "auditDigest": "d50f57932c5a1a13a3ce187053be1b8a88b57cf8546250db2ed605a27ab009c7" + } + ], + "auditDigest": "828b10bdaf88976168cd68d7b4b5506a0565b681bfd2d5d0f25395bfcb4254bc" +} diff --git a/enterprise-admin-alert-escalation-guard/reports/admin-alert-escalation-report.md b/enterprise-admin-alert-escalation-guard/reports/admin-alert-escalation-report.md new file mode 100644 index 00000000..bc2340ab --- /dev/null +++ b/enterprise-admin-alert-escalation-guard/reports/admin-alert-escalation-report.md @@ -0,0 +1,27 @@ +# Enterprise Admin Alert Escalation Guard Report + +As of: 2026-05-22 +Alert digest: `828b10bdaf88976168cd68d7b4b5506a0565b681bfd2d5d0f25395bfcb4254bc` + +## Summary + +- Alerts reviewed: 4 +- Findings: 8 +- Escalated alerts: ALERT-COMPLIANCE-001, ALERT-WEBHOOK-022 +- Actions: deliver_now_and_escalate=1, hold_digest_and_route_owner_fallback=1, warn_and_repair_delivery_path=1, allow_digest_or_standard_delivery=1 + +## Alert Decisions + +| Alert | Category | Severity | Action | Findings | Dashboard badges | +| --- | --- | --- | --- | ---: | --- | +| ALERT-COMPLIANCE-001 | compliance_deadline | critical | deliver_now_and_escalate | 6 | bypass-digest, owner-fallback, webhook-fallback, deadline-visible | +| ALERT-WEBHOOK-022 | security_integration | high | hold_digest_and_route_owner_fallback | 1 | webhook-fallback | +| ALERT-DASHBOARD-077 | usage_anomaly | medium | warn_and_repair_delivery_path | 1 | none | +| ALERT-INFO-100 | weekly_summary | low | allow_digest_or_standard_delivery | 0 | standard-delivery | + +## Guardrails + +- Uses synthetic enterprise alert, owner, routing, digest, and webhook metadata only. +- Does not deliver live email, SMS, Slack, webhook, or external provider notifications. +- Keeps critical compliance/security alerts visible even when muted, digested, quiet-hours, duplicated, or routed to unavailable owners. +- Emits deterministic dashboard badges, webhook-ready event summaries, and audit digests. diff --git a/enterprise-admin-alert-escalation-guard/reports/demo.mp4 b/enterprise-admin-alert-escalation-guard/reports/demo.mp4 new file mode 100644 index 00000000..f765f58e Binary files /dev/null and b/enterprise-admin-alert-escalation-guard/reports/demo.mp4 differ diff --git a/enterprise-admin-alert-escalation-guard/reports/summary.svg b/enterprise-admin-alert-escalation-guard/reports/summary.svg new file mode 100644 index 00000000..ea1fa50b --- /dev/null +++ b/enterprise-admin-alert-escalation-guard/reports/summary.svg @@ -0,0 +1,20 @@ + + + Enterprise admin alert escalation guard summary + Synthetic enterprise alert delivery and escalation decisions. + + + Enterprise admin alert escalation guard + Mute, digest, owner, webhook, and quiet-hours routing checks + + 4 alerts + admin routing + + 2 escalated + mute bypass + + 8 findings + review packets + Actions: deliver_now_and_escalate (1) / hold_digest_and_route_owner_fallback (1) / warn_and_repair_delivery_path (1) / allow_digest_or_standard_delivery (1) + Digest: 828b10bdaf88976168cd68d7b4b5506a... + diff --git a/enterprise-admin-alert-escalation-guard/sample-data.js b/enterprise-admin-alert-escalation-guard/sample-data.js new file mode 100644 index 00000000..d26ac24e --- /dev/null +++ b/enterprise-admin-alert-escalation-guard/sample-data.js @@ -0,0 +1,64 @@ +'use strict'; + +module.exports = [ + { + id: 'ALERT-COMPLIANCE-001', + category: 'compliance_deadline', + severity: 'critical', + dueAt: '2026-05-22T18:00:00Z', + owner: { id: 'research-office-primary', active: false, onLeave: true }, + routing: { + channels: ['admin_digest'], + muted: true, + quietHours: true, + duplicateSuppressed: true, + digest: { enabled: true, delayHours: 12 } + }, + webhook: { required: true, failureRate: 0.32 } + }, + { + id: 'ALERT-WEBHOOK-022', + category: 'security_integration', + severity: 'high', + dueAt: '2026-05-24T09:00:00Z', + owner: { id: 'integration-admin', active: true, onLeave: false }, + routing: { + channels: ['slack', 'admin_inbox'], + muted: false, + quietHours: false, + duplicateSuppressed: false, + digest: { enabled: false, delayHours: 0 } + }, + webhook: { required: true, failureRate: 0.24 } + }, + { + id: 'ALERT-DASHBOARD-077', + category: 'usage_anomaly', + severity: 'medium', + dueAt: '2026-05-29T12:00:00Z', + owner: { id: 'department-chair', active: true, onLeave: false }, + routing: { + channels: [], + muted: false, + quietHours: false, + duplicateSuppressed: false, + digest: { enabled: true, delayHours: 2 } + }, + webhook: { required: false, failureRate: 0 } + }, + { + id: 'ALERT-INFO-100', + category: 'weekly_summary', + severity: 'low', + dueAt: '2026-06-05T12:00:00Z', + owner: { id: 'research-ops', active: true, onLeave: false }, + routing: { + channels: ['admin_digest'], + muted: false, + quietHours: false, + duplicateSuppressed: false, + digest: { enabled: true, delayHours: 2 } + }, + webhook: { required: false, failureRate: 0 } + } +]; diff --git a/enterprise-admin-alert-escalation-guard/test.js b/enterprise-admin-alert-escalation-guard/test.js new file mode 100644 index 00000000..b9883f9a --- /dev/null +++ b/enterprise-admin-alert-escalation-guard/test.js @@ -0,0 +1,98 @@ +'use strict'; + +const assert = require('assert'); +const sampleAlerts = require('./sample-data'); +const { evaluateAlert, evaluateAlerts, hoursUntil } = require('./index'); + +const asOfDate = '2026-05-22'; + +function testHoursUntil() { + assert.equal(hoursUntil('2026-05-22T18:00:00Z', asOfDate), 18); +} + +function testCriticalAlertBypassesMuteDigestAndQuietHours() { + const packet = evaluateAlert(sampleAlerts[0], { asOfDate }); + + assert.equal(packet.action, 'deliver_now_and_escalate'); + assert.equal(packet.decisionSeverity, 'critical'); + assert.ok(packet.findings.some((finding) => finding.code === 'urgent_alert_muted')); + assert.ok(packet.findings.some((finding) => finding.code === 'urgent_alert_delayed_by_digest')); + assert.ok(packet.findings.some((finding) => finding.code === 'quiet_hours_override_required')); + assert.ok(packet.dashboardBadges.includes('bypass-digest')); + assert.equal(packet.webhookEvent.requiresAcknowledgement, true); +} + +function testWebhookFailureFallbackForHighSeverity() { + const packet = evaluateAlert(sampleAlerts[1], { asOfDate }); + + assert.equal(packet.action, 'hold_digest_and_route_owner_fallback'); + assert.equal(packet.decisionSeverity, 'high'); + assert.ok(packet.findings.some((finding) => finding.code === 'webhook_health_fallback_required')); + assert.ok(packet.dashboardBadges.includes('webhook-fallback')); +} + +function testMissingChannelWarnsMediumAlert() { + const packet = evaluateAlert(sampleAlerts[2], { asOfDate }); + + assert.equal(packet.action, 'warn_and_repair_delivery_path'); + assert.equal(packet.decisionSeverity, 'medium'); + assert.ok(packet.findings.some((finding) => finding.code === 'missing_delivery_channel')); +} + +function testStandardDigestAllowed() { + const packet = evaluateAlert(sampleAlerts[3], { asOfDate }); + + assert.equal(packet.action, 'allow_digest_or_standard_delivery'); + assert.equal(packet.findingCount, 0); + assert.ok(packet.dashboardBadges.includes('standard-delivery')); +} + +function testDuplicateSuppressionNearDeadline() { + const packet = evaluateAlert({ + id: 'ALERT-DEDUPE', + category: 'export_failure', + severity: 'high', + dueAt: '2026-05-22T20:00:00Z', + owner: { id: 'export-admin', active: true, onLeave: false }, + routing: { + channels: ['admin_inbox'], + muted: false, + quietHours: false, + duplicateSuppressed: true, + digest: { enabled: false, delayHours: 0 } + }, + webhook: { required: false, failureRate: 0 } + }, { asOfDate }); + + assert.equal(packet.action, 'hold_digest_and_route_owner_fallback'); + assert.ok(packet.findings.some((finding) => finding.code === 'duplicate_suppression_near_deadline')); + assert.ok(packet.dashboardBadges.includes('deadline-visible')); +} + +function testPortfolioSummary() { + const portfolio = evaluateAlerts(sampleAlerts, { asOfDate }); + + assert.equal(portfolio.alertCount, 4); + assert.equal(portfolio.byAction.deliver_now_and_escalate, 1); + assert.equal(portfolio.byAction.hold_digest_and_route_owner_fallback, 1); + assert.equal(portfolio.byAction.warn_and_repair_delivery_path, 1); + assert.equal(portfolio.byAction.allow_digest_or_standard_delivery, 1); + assert.ok(portfolio.escalatedAlerts.includes('ALERT-COMPLIANCE-001')); + assert.equal(portfolio.auditDigest.length, 64); +} + +const tests = [ + testHoursUntil, + testCriticalAlertBypassesMuteDigestAndQuietHours, + testWebhookFailureFallbackForHighSeverity, + testMissingChannelWarnsMediumAlert, + testStandardDigestAllowed, + testDuplicateSuppressionNearDeadline, + testPortfolioSummary +]; + +for (const test of tests) { + test(); +} + +console.log(`${tests.length} enterprise admin alert escalation guard tests passed`);