Users can now get notifications in Slack, chosen per category next to In-app and Email. This implements QRun-IO/qbit-slack docs/DESIGN.md section 10. The owner decision of 2026-10-14 supersedes "Slack stays a group or monitor channel only, never per user". docs/NOTIFICATIONS.md is updated to match.
Changeset 28:
alerts_notification_preference gets slackMode (OFF, IMMEDIATE or DAILY_DIGEST; default OFF) and slackMinSeverity (default WARNING).
alerts_notification_recipient gets slackStatus and slackMessageId.
NotificationSlackSender runs after the emailer, in the deliver-notifications step.
It sends through core SendMessageAction to the provider set by slackProviderName (default slack), addressed user:<id>. There is no qbit-slack import (G1).
qbit-slack sends the DM through the recipient's own connection, in their tenant's workspace.
Pause and quiet hours reuse AlertRouter.isPaused and AlertTiming.isQuiet; CRITICAL bypasses quiet hours.
SECURITY notices send the title and link only. ALERT and muted categories are excluded, as for email.
Users on DAILY_DIGEST get one DM at their digest hour, and those rows are marked DIGESTED.
Outcomes: no provider gives SKIPPED; a user-facing refusal (for example, Slack isn't connected) gives SKIPPED; other errors give FAILED. The notification itself never fails.
RC.6 gaps:
There's no idempotency key on the input yet, so slackStatus prevents resends (STAND-IN(core=QRun-IO/qqq#1194, removeBy=4.1.0-RC.8)).
slackMessageId stays null until the output carries an id.
Availability is checked with getMessagingProvider(name) != null.
Tests:NotificationSlackTest has 8 tests: immediate, muted, quiet hours, paused, no provider, errors, SECURITY with no body, and digest.
Build:verify passes locally (173 tests; Checkstyle, guardrails and JaCoCo green).
The implementation is by a Sonnet subagent (Codex is unavailable here). I reviewed it.
Users can now get notifications in Slack, chosen per category next to In-app and Email. This implements QRun-IO/qbit-slack `docs/DESIGN.md` section 10. The owner decision of 2026-10-14 supersedes "Slack stays a group or monitor channel only, never per user". `docs/NOTIFICATIONS.md` is updated to match.
- **Changeset 28:**
- `alerts_notification_preference` gets `slackMode` (OFF, IMMEDIATE or DAILY_DIGEST; default OFF) and `slackMinSeverity` (default WARNING).
- `alerts_notification_recipient` gets `slackStatus` and `slackMessageId`.
- **`NotificationSlackSender`** runs after the emailer, in the deliver-notifications step.
- It sends through core `SendMessageAction` to the provider set by `slackProviderName` (default `slack`), addressed `user:<id>`. There is no qbit-slack import (G1).
- qbit-slack sends the DM through the recipient's own connection, in their tenant's workspace.
- Pause and quiet hours reuse `AlertRouter.isPaused` and `AlertTiming.isQuiet`; CRITICAL bypasses quiet hours.
- SECURITY notices send the title and link only. ALERT and muted categories are excluded, as for email.
- Users on DAILY_DIGEST get one DM at their digest hour, and those rows are marked DIGESTED.
- Outcomes: no provider gives SKIPPED; a user-facing refusal (for example, Slack isn't connected) gives SKIPPED; other errors give FAILED. The notification itself never fails.
- **RC.6 gaps:**
- There's no idempotency key on the input yet, so `slackStatus` prevents resends (`STAND-IN(core=QRun-IO/qqq#1194, removeBy=4.1.0-RC.8)`).
- `slackMessageId` stays null until the output carries an id.
- Availability is checked with `getMessagingProvider(name) != null`.
- **Tests:** `NotificationSlackTest` has 8 tests: immediate, muted, quiet hours, paused, no provider, errors, SECURITY with no body, and digest.
- **Build:** `verify` passes locally (173 tests; Checkstyle, guardrails and JaCoCo green).
The implementation is by a Sonnet subagent (Codex is unavailable here). I reviewed it.
🤖 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.
Users can now get notifications in Slack, chosen per category next to In-app and Email. This implements QRun-IO/qbit-slack
docs/DESIGN.mdsection 10. The owner decision of 2026-10-14 supersedes "Slack stays a group or monitor channel only, never per user".docs/NOTIFICATIONS.mdis updated to match.alerts_notification_preferencegetsslackMode(OFF, IMMEDIATE or DAILY_DIGEST; default OFF) andslackMinSeverity(default WARNING).alerts_notification_recipientgetsslackStatusandslackMessageId.NotificationSlackSenderruns after the emailer, in the deliver-notifications step.SendMessageActionto the provider set byslackProviderName(defaultslack), addresseduser:<id>. There is no qbit-slack import (G1).AlertRouter.isPausedandAlertTiming.isQuiet; CRITICAL bypasses quiet hours.slackStatusprevents resends (STAND-IN(core=QRun-IO/qqq#1194, removeBy=4.1.0-RC.8)).slackMessageIdstays null until the output carries an id.getMessagingProvider(name) != null.NotificationSlackTesthas 8 tests: immediate, muted, quiet hours, paused, no provider, errors, SECURITY with no body, and digest.verifypasses locally (173 tests; Checkstyle, guardrails and JaCoCo green).The implementation is by a Sonnet subagent (Codex is unavailable here). I reviewed it.
🤖 Generated with Claude Code