phase 9 notification toggles (per-alert, per-category, master; default-disabled)

This commit is contained in:
2026-04-18 23:51:59 +00:00
parent 39a5482516
commit 8a45b59b28
12 changed files with 520 additions and 33 deletions

View File

@@ -1,19 +1,18 @@
/**
* Canonical notification alert registry.
*
* Single source of truth for the 30 standard-threshold-driven alert keys used
* across surgeChecker, patternChecker, and staffNotifications. Consumed by:
* - the three checker services (startup drift-check)
* Single source of truth for the 32 registered alert keys across surgeChecker,
* patternChecker, staffNotifications, and chatAlertChecker. Consumed by:
* - the checker services (startup drift-check, Phase 9 enable gating)
* - routes/internalApi.js GET /notifications/alerts
* - settings-site UI (via proxied /api/notifications/alerts, with fallback)
*
* Not covered here (intentionally fallback-only in the UI):
* - rapid_t2_t3 — uses count-milestone firing, not shouldFire()
* - chat_messages/time — owned by chatAlertChecker.js, out of Phase 5 scope
* - rapid_t2_t3 — uses count-milestone firing, not shouldFire()
*
* `windowType` is the reset window used by shouldFire() for pattern keys
* (today/week/month). For surge and unclaimed, firing is cooldown-escalating
* rather than window-based, so windowType is null.
* (today/week/month). For surge, unclaimed, and chat, firing is
* cooldown-escalating rather than window-based, so windowType is null.
*/
const REGISTRY = Object.freeze({
@@ -174,13 +173,27 @@ const REGISTRY = Object.freeze({
description: 'Reminds all staff notification channels about unclaimed tickets. Thresholds are per-ticket age — each threshold fires once per ticket and resets on escalation.',
windowType: null
})
]),
chat: Object.freeze([
Object.freeze({
key: 'chat_messages',
description: 'Fires when pending user message volume in monitored chat channels crosses configured count thresholds without staff replies.',
windowType: null
}),
Object.freeze({
key: 'chat_time',
description: 'Fires when a monitored chat channel has had no staff response for the given duration with pending user messages. Resets when staff responds.',
windowType: null
})
])
});
const ALL_KEYS = Object.freeze([
...REGISTRY.surge.map(e => e.key),
...REGISTRY.patterns.map(e => e.key),
...REGISTRY.unclaimed.map(e => e.key)
...REGISTRY.unclaimed.map(e => e.key),
...REGISTRY.chat.map(e => e.key)
]);
const ALL_KEYS_SET = new Set(ALL_KEYS);