Part 1 of 3 for #27: quiet hours, user pause and digests. These were stored and editable but never applied. Parts 2 (#29, reminders and escalation) and 3 (#28, teams and mutes) are merged, and this branch has develop merged in.
Quiet hours use the user's timeZone, handle windows that cross midnight (22:00-07:00) and quietDays. Severities at or above quietBypassSeverity (default CRITICAL) break through.
Pause (pausedUntil) and quiet hours apply only to push channels (email, email lists, webhooks and the like). The in-app bell is never suppressed, which matches develop's existing pause rule. Channel subscriptions are unaffected.
A channel below its minimum severity is now logged as a SUPPRESSED MIN_SEVERITY row instead of being silently skipped.
Reminders and escalations (#29) are sent immediately, never digested, but still respect pause and quiet hours on push channels.
Digests:
DIGEST_HOURLY and DIGEST_DAILY subscriptions queue DIGEST deliveries, each with a digestKey (recipient, window start, mode) and nextAttemptAt set to the end of the window.
The hidden hourly alertsSendDigests job sends one grouped message per user (or channel) per window: hourly, or daily at the user's digestHour in their time zone. It goes through the existing email path (qbit-email's EmailApi when installed) or as one in-app notification.
Visibility is checked again at send time, empty digests aren't sent, and durable dispatch claims stop a window from being sent twice. Failed, interrupted or oversized windows (more than 500 events) stay visible as FAILED rows for review rather than being retried automatically, so nobody gets a digest twice.
Schema: guarded changeset 27 (21-26 are taken by #28 and #29).
Tests:mvnw -o -B verify green after merging develop: 165 tests, 94.3% instruction coverage, checkstyle and guardrails pass. The 19 quiet-hours and digest tests cover the window inside and outside, across midnight, quiet days, CRITICAL bypass, pause, the in-app exemption, channel subscriptions, hourly and daily digests in a time zone, grouping, empty digests and an idempotent re-run.
The qbit-slack agent will build Slack on top of this (it reuses AlertTiming.isQuiet). After this merges, qbit-alerts has #23, #26, #27 (all three parts) and #28 for an RC.5.
Part 1 of 3 for #27: quiet hours, user pause and digests. These were stored and editable but never applied. Parts 2 (#29, reminders and escalation) and 3 (#28, teams and mutes) are merged, and this branch has develop merged in.
**Routing** (design §5.4 order): notify switch, mutes, flapping, visibility, **USER_PAUSED**, **QUIET_HOURS**, **MIN_SEVERITY**, channel disabled, rate limit, duplicate.
- Quiet hours use the user's `timeZone`, handle windows that cross midnight (22:00-07:00) and `quietDays`. Severities at or above `quietBypassSeverity` (default CRITICAL) break through.
- Pause (`pausedUntil`) and quiet hours apply only to push channels (email, email lists, webhooks and the like). The in-app bell is never suppressed, which matches develop's existing pause rule. Channel subscriptions are unaffected.
- A channel below its minimum severity is now logged as a SUPPRESSED `MIN_SEVERITY` row instead of being silently skipped.
- Reminders and escalations (#29) are sent immediately, never digested, but still respect pause and quiet hours on push channels.
**Digests:**
- DIGEST_HOURLY and DIGEST_DAILY subscriptions queue `DIGEST` deliveries, each with a `digestKey` (recipient, window start, mode) and `nextAttemptAt` set to the end of the window.
- The hidden hourly `alertsSendDigests` job sends one grouped message per user (or channel) per window: hourly, or daily at the user's `digestHour` in their time zone. It goes through the existing email path (qbit-email's EmailApi when installed) or as one in-app notification.
- Visibility is checked again at send time, empty digests aren't sent, and durable dispatch claims stop a window from being sent twice. Failed, interrupted or oversized windows (more than 500 events) stay visible as FAILED rows for review rather than being retried automatically, so nobody gets a digest twice.
**Schema:** guarded changeset **27** (21-26 are taken by #28 and #29).
**Tests:** `mvnw -o -B verify` green after merging develop: 165 tests, 94.3% instruction coverage, checkstyle and guardrails pass. The 19 quiet-hours and digest tests cover the window inside and outside, across midnight, quiet days, CRITICAL bypass, pause, the in-app exemption, channel subscriptions, hourly and daily digests in a time zone, grouping, empty digests and an idempotent re-run.
The qbit-slack agent will build Slack on top of this (it reuses `AlertTiming.isQuiet`). After this merges, qbit-alerts has #23, #26, #27 (all three parts) and #28 for an RC.5.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Part 1 of 3 for #27: quiet hours, user pause and digests. These were stored and editable but never applied. Parts 2 (#29, reminders and escalation) and 3 (#28, teams and mutes) are merged, and this branch has develop merged in.
Routing (design §5.4 order): notify switch, mutes, flapping, visibility, USER_PAUSED, QUIET_HOURS, MIN_SEVERITY, channel disabled, rate limit, duplicate.
timeZone, handle windows that cross midnight (22:00-07:00) andquietDays. Severities at or abovequietBypassSeverity(default CRITICAL) break through.pausedUntil) and quiet hours apply only to push channels (email, email lists, webhooks and the like). The in-app bell is never suppressed, which matches develop's existing pause rule. Channel subscriptions are unaffected.MIN_SEVERITYrow instead of being silently skipped.Digests:
DIGESTdeliveries, each with adigestKey(recipient, window start, mode) andnextAttemptAtset to the end of the window.alertsSendDigestsjob sends one grouped message per user (or channel) per window: hourly, or daily at the user'sdigestHourin their time zone. It goes through the existing email path (qbit-email's EmailApi when installed) or as one in-app notification.Schema: guarded changeset 27 (21-26 are taken by #28 and #29).
Tests:
mvnw -o -B verifygreen after merging develop: 165 tests, 94.3% instruction coverage, checkstyle and guardrails pass. The 19 quiet-hours and digest tests cover the window inside and outside, across midnight, quiet days, CRITICAL bypass, pause, the in-app exemption, channel subscriptions, hourly and daily digests in a time zone, grouping, empty digests and an idempotent re-run.The qbit-slack agent will build Slack on top of this (it reuses
AlertTiming.isQuiet). After this merges, qbit-alerts has #23, #26, #27 (all three parts) and #28 for an RC.5.🤖 Generated with Claude Code