Skip to content

feat(alerts): acknowledge incidents from Slack/Discord cards and in PagerDuty - #2289

Merged
Makisuo merged 18 commits into
feat/alert-ack-uifrom
feat/alert-ack-chat
Nov 6, 2026
Merged

Makisuo merged 18 commits into
feat/alert-ack-uifrom
feat/alert-ack-chat

Conversation

@Makisuo

@Makisuo Makisuo commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator

Part 3 of 3 of acknowledging alert incidents: #2287 (core, API, MCP) → #2288 (UI) → this PR: Slack/Discord buttons and PagerDuty sync. It is based on #2288.

What

Acknowledge from Slack and Discord alert cards

  • Button. Trigger and reminder cards of an open incident get an Acknowledge button. Once acked it becomes Unacknowledge, with "Acknowledged by name" on the card. Resolve, test and digest cards have no button.
  • Who can click. In Slack, anyone in the channel may ack, and the Slack display name is recorded with no Maple user, because Slack has no account linking. In Discord, a linked chat identity records the Maple user; otherwise the display name is recorded.
  • Controls. They are alert_ack:<uuid> and alert_unack:<uuid>, decoded strictly. The org always comes from the workspace the click arrived from (Slack team.id, Discord guild_id), and both the ack and the card lookup are scoped to that org. A forged control can only name an incident in the clicker's own org.
  • Redraw. The clicked card is redrawn in place. AlertChatCardService rebuilds it from the delivery row that posted it, with the chart, values and template intact. A resolved or unknown incident gets a private note, not an error in the channel.
  • Bundle size. The relay runs in apps/chat-bot. The alerting Worker imports neither new service.

Maple → PagerDuty acknowledge (one way)

  • What gets sent. A Maple ack from any surface (web, API, MCP, chat) queues event_action: "acknowledge" in the ack's transaction, and the alerting dispatcher sends it. Unacknowledge sends nothing, because PagerDuty has no un-acknowledge. PagerDuty → Maple is out of scope.
  • Which destinations. Only PagerDuty destinations that already delivered this incident's page. So an ack never reaches a pager that was not notified, and never lands before the page itself.
  • Which keys. The base dedup key, plus the :critical key when the rule pages critical under its own key or the incident ever peaked at critical.
  • Stale acks. The dispatcher reads the ack right before sending and skips it if an escalation cleared it meanwhile, so it cannot silence the new page. An ack delivery does not restart the reminder clock.
  • Public API. acknowledge is an internal delivery type. The v2 API keeps its four public event types and leaves acknowledgement syncs out of /v2/alerts/deliveries, because shipped iOS builds decode the event type as a closed enum.

Verification

  • chat-platform: 349 tests pass. They cover both renderers in both states, the control-id round trip and malformed ids.
  • chat-bot: 119 tests pass. The relay tests cover:
    • ack and unack;
    • linked and unlinked clickers;
    • resolved and unknown incidents;
    • a missing card;
    • an unlinked workspace and a malformed id.
  • Backend, PGlite: all 541 tests in services/alerts and services/push pass. New ones cover:
    • acks queued only to PagerDuty destinations that already delivered a page (not one still waiting to send, a disabled one, or a chat one);
    • the card rebuilt in both states, and not found for a foreign org or message;
    • the PagerDuty body and keys for single-key, tiered, and peaked-then-untiered rules;
    • end-to-end dispatch that leaves the reminder clock untouched and skips a stale ack.
  • API: the v2 deliveries list leaves out an acknowledge row (alerts.http.test.ts, 21 pass).
  • iOS: ios:openapi:check is up to date.
  • Typecheck: backend, chat-platform, chat-bot, alerting, api, ai, domain, web-data and web. Lint is clean.

Not verified: a real Slack or Discord click, because no workspace is linked locally or on previews. The relay uses the same transport.edit path as agent approvals. Slack's click payload gives user.name, which may be the handle rather than the display name.

Follow-ups:

  • Only the clicked card is redrawn. The same incident's other cards keep their old button, but each button names the state it sets, so a stale one can only re-apply that state.
  • PagerDuty → Maple sync.

🤖 Generated with Claude Code


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.

Summary by CodeRabbit

  • New Features
    • Alert cards in Slack and Discord now include controls to acknowledge open incidents and undo acknowledgements, with the acknowledging person shown on the card.
    • Acknowledging an incident can send an acknowledgement to PagerDuty when it has a qualifying delivery. Chat cards update to reflect acknowledgement changes.
  • Bug Fixes
    • Acknowledgement events are excluded from notification delivery history and mobile push notifications.
    • Resolved or no-longer-acknowledged incidents are not sent as PagerDuty acknowledgements.

…agerDuty

Alert cards posted to a chat channel for an open incident now carry an
Acknowledge button (Unacknowledge once acked, with "Acknowledged by <name>").
A click reaches the chat-bot relay as an alert_ack:/alert_unack: control that
names only the incident (a UUID, strictly decoded); the org always comes from
the workspace the click landed in. The relay runs AlertIncidentAckService for
that org (linked Maple user where the connector has identity, else the
platform display name), then redraws the clicked card from the delivery that
posted it, so the chart, values and template stay. A resolved or unknown
incident gets a short private note instead.

Acknowledging also queues a PagerDuty acknowledge in the same transaction: a
new "acknowledge" delivery event type, queued only to the enabled pagerduty
destinations of the rule or that already paged the incident, and drained by
the alerting dispatcher like any delivery. It acks the current tier's dedup
key, and for a critical incident of a tiered rule the warning key too. The
dispatcher skips an ack the incident no longer holds (resolved, or an
escalation cleared it) and never restarts the reminder clock for one.
Unacknowledge sends nothing: PagerDuty has no un-acknowledge.
# Conflicts:
#	packages/web-data/src/alerts/incident-timeline.test.ts
…hem after a page

Review fixes for the PagerDuty acknowledge sync:
- The public API keeps its four notification event types. `acknowledge`
  deliveries are left out of /v2/alerts/deliveries, since shipped clients
  decode the event type as a closed enum.
- An acknowledgement goes only to PagerDuty destinations that already
  delivered this incident's page, so it never reaches a pager that was not
  notified or lands before the page itself.
- Both dedup keys are acknowledged when the rule pages critical under its
  own key or the incident ever peaked at critical.
- The dispatcher reads the ack right before sending, so an escalation that
  committed after the claim is not silenced.
@coderabbitai

coderabbitai Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Explain Change →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 6 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: dbd945b9-5491-46f1-b631-80249862282a
Commits

Reviewing files that changed from the base of the PR and between 7826d2c and 8487a74.

Files selected for processing: 34

  • apps/api/src/routes/v2/alert-deliveries.http.ts
  • apps/api/src/routes/v2/alert-incidents.http.ts
  • apps/api/src/routes/v2/alerts.http.test.ts
  • apps/chat-bot/src/relay/run.ts
  • apps/chat-bot/src/relay/settle.test.ts
  • apps/chat-bot/src/relay/turn.test.ts
  • apps/chat-bot/src/relay/turn.ts
  • packages/backend/src/services/alerts/AlertChatCardService.ts
  • packages/backend/src/services/alerts/AlertIncidentAck.chat.test.ts
  • packages/backend/src/services/alerts/AlertIncidentAckService.ts
  • packages/backend/src/services/alerts/AlertReadModelsService.ts
  • packages/backend/src/services/alerts/AlertsService.delivery.test.ts
  • packages/backend/src/services/alerts/AlertsService.ts
  • packages/backend/src/services/alerts/delivery/context.ts
  • packages/backend/src/services/alerts/delivery/dispatch.ts
  • packages/backend/src/services/alerts/delivery/paging-dedup.ts
  • packages/backend/src/services/alerts/delivery/stored-payload.ts
  • packages/backend/src/services/alerts/delivery/transports/chat.test.ts
  • packages/backend/src/services/alerts/delivery/transports/chat.ts
  • packages/backend/src/services/alerts/delivery/transports/linear.ts
  • packages/backend/src/services/alerts/delivery/transports/pagerduty.ts
  • packages/backend/src/services/alerts/delivery/transports/render.test.ts
  • packages/backend/src/services/push/MobilePushService.ts
  • packages/chat-platform/src/action-token.test.ts
  • packages/chat-platform/src/action-token.ts
  • packages/chat-platform/src/connectors/discord/render.test.ts
  • packages/chat-platform/src/connectors/discord/render.ts
  • packages/chat-platform/src/connectors/slack/render.test.ts
  • packages/chat-platform/src/connectors/slack/render.ts
  • packages/chat-platform/src/render/blocks.ts
  • packages/domain/src/http/alerts.ts
  • packages/domain/src/http/v2/alert-deliveries.ts
  • packages/domain/src/http/v2/alert-incidents.ts
  • packages/web-data/src/alerts/form-utils.ts

No actionable comments were generated in the recent review.

Walkthrough

This change adds acknowledge and unacknowledge controls to alert cards in Slack and Discord, routes those actions to incident state updates, and redraws the cards. Newly acknowledged incidents queue PagerDuty acknowledgement deliveries. V2 notification history excludes internal acknowledgement events.

Changes: Alert acknowledgement flow

Layer / File(s) Summary
Acknowledgement and event contracts
packages/domain/src/http/alerts.ts, packages/domain/src/http/v2/*, packages/chat-platform/src/action-token.ts, packages/chat-platform/src/render/blocks.ts, packages/web-data/src/alerts/form-utils.ts, related tests
Delivery event types now include acknowledge, while public notification types exclude it. Chat controls have acknowledge and unacknowledge actions with validated incident IDs. Alert blocks can carry acknowledgement data.
Acknowledgement controls on alert cards
packages/backend/src/services/alerts/delivery/transports/chat.ts, packages/chat-platform/src/connectors/{slack,discord}/render.ts, related tests
Eligible open alert cards include acknowledgement data. Slack and Discord render an acknowledge or unacknowledge control and show the acknowledger when available.
Incident updates and card rebuilding
packages/backend/src/services/alerts/AlertIncidentAckService.ts, packages/backend/src/services/alerts/AlertChatCardService.ts, packages/backend/src/services/alerts/delivery/stored-payload.ts, related tests
A newly acknowledged incident queues events for enabled PagerDuty destinations that had a successful prior page. The card service finds the matching chat delivery and rebuilds its blocks using stored delivery data and current incident and rule data.
Relay actions and chat-card redraw
apps/chat-bot/src/relay/*
The relay decodes acknowledgement controls, resolves workspace and clicker details, calls the acknowledgement port, then redraws a returned card or sends a private notice based on the outcome.
PagerDuty acknowledgement delivery
packages/backend/src/services/alerts/AlertsService.ts, packages/backend/src/services/alerts/delivery/*, packages/backend/src/services/push/MobilePushService.ts, related tests
Delivery processing checks that the incident is still open and acknowledged. It skips unsupported destinations, sends PagerDuty acknowledgement actions for applicable deduplication keys, and does not update notification timestamps for acknowledgement events. Mobile push does not target these events.
Public notification history
packages/backend/src/services/alerts/AlertReadModelsService.ts, apps/api/src/routes/v2/*, packages/domain/src/http/v2/*, related tests
The delivery-event query can exclude acknowledgement events. V2 delivery and incident responses expose notification event types only, and the pagination test checks that acknowledgement events are omitted.

Estimated code review effort: 4 (Complex) | ~60 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant ChatPlatform
  participant RelayTurn
  participant AlertIncidentAckService
  participant AlertChatCardService
  ChatPlatform->>RelayTurn: Send acknowledgement control action
  RelayTurn->>AlertIncidentAckService: Acknowledge or unacknowledge incident
  RelayTurn->>AlertChatCardService: Rebuild card for chat message
  AlertChatCardService-->>RelayTurn: Return optional card blocks
  RelayTurn-->>ChatPlatform: Redraw card or send private notice
Loading

Possibly related PRs

Suggested reviewers: jeremyfunk

Merge Risk: Low · previous review 7826d

This adds acknowledge buttons to Slack and Discord alert cards and sends the acknowledgement to PagerDuty. The code paths look consistent. The end-to-end click has not been exercised in a real workspace, so check it after merge.

Pre-merge checks: Passed 5

Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly describes the main changes: incident acknowledgement from Slack and Discord cards and delivery of acknowledgements to PagerDuty.
Docstring Coverage Passed No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 34 files.

Finishing Touches

Generate docstrings

  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Recent review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 37e947a7-faca-41dc-8311-c838740c7eed
Commits

Reviewing files that changed from the base of the PR and between e3feeaf and 7826d2c.

Files selected for processing: 34

  • apps/api/src/routes/v2/alert-deliveries.http.ts
  • apps/api/src/routes/v2/alert-incidents.http.ts
  • apps/api/src/routes/v2/alerts.http.test.ts
  • apps/chat-bot/src/relay/run.ts
  • apps/chat-bot/src/relay/settle.test.ts
  • apps/chat-bot/src/relay/turn.test.ts
  • apps/chat-bot/src/relay/turn.ts
  • packages/backend/src/services/alerts/AlertChatCardService.ts
  • packages/backend/src/services/alerts/AlertIncidentAck.chat.test.ts
  • packages/backend/src/services/alerts/AlertIncidentAckService.ts
  • packages/backend/src/services/alerts/AlertReadModelsService.ts
  • packages/backend/src/services/alerts/AlertsService.delivery.test.ts
  • packages/backend/src/services/alerts/AlertsService.ts
  • packages/backend/src/services/alerts/delivery/context.ts
  • packages/backend/src/services/alerts/delivery/dispatch.ts
  • packages/backend/src/services/alerts/delivery/paging-dedup.ts
  • packages/backend/src/services/alerts/delivery/stored-payload.ts
  • packages/backend/src/services/alerts/delivery/transports/chat.test.ts
  • packages/backend/src/services/alerts/delivery/transports/chat.ts
  • packages/backend/src/services/alerts/delivery/transports/linear.ts
  • packages/backend/src/services/alerts/delivery/transports/pagerduty.ts
  • packages/backend/src/services/alerts/delivery/transports/render.test.ts
  • packages/backend/src/services/push/MobilePushService.ts
  • packages/chat-platform/src/action-token.test.ts
  • packages/chat-platform/src/action-token.ts
  • packages/chat-platform/src/connectors/discord/render.test.ts
  • packages/chat-platform/src/connectors/discord/render.ts
  • packages/chat-platform/src/connectors/slack/render.test.ts
  • packages/chat-platform/src/connectors/slack/render.ts
  • packages/chat-platform/src/render/blocks.ts
  • packages/domain/src/http/alerts.ts
  • packages/domain/src/http/v2/alert-deliveries.ts
  • packages/domain/src/http/v2/alert-incidents.ts
  • packages/web-data/src/alerts/form-utils.ts

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 2 remain after this review.

@maple-review-bot

This comment has been minimized.

@maple-review-bot

This comment has been minimized.

@maple-review-bot

This comment has been minimized.

@Makisuo
Makisuo added this pull request to stack #2300 November 6, 2026 11:13
…rt-ack-chat

# Conflicts:
#	packages/backend/src/services/alerts/delivery/transports/pagerduty.ts
@maple-review-bot

This comment has been minimized.

@maple-review-bot

This comment has been minimized.

@maple-review-bot

This comment has been minimized.

@maple-review-bot

This comment has been minimized.

@maple-review-bot

maple-review-bot Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 10/10 · safe to merge. Production hunks were read end to end and every ack path is org-scoped; a real Slack/Discord click and the test-file diffs are unverified by me.
no findings · tests covered · risk high · 4/4 new units observable

Adds an Acknowledge/Unacknowledge control to Slack and Discord alert cards with an in-place redraw, and syncs a Maple acknowledgement to the PagerDuty destinations that already paged. Every path is scoped to the org of the workspace the click arrived in; safe to merge.

  • Alert cards carry alert_ack/alert_unack controls and are redrawn in place after a click
  • AlertIncidentAckService queues acknowledge rows only for PagerDuty destinations that already paged
  • The PagerDuty acknowledge covers the base key and :critical when the rule tiers or the incident peaked
  • v2 deliveries and last_delivered_event_type hide the internal acknowledge type

8487a74 · What was checked, coverage and telemetry details are on the Maple / review check. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@Makisuo
Makisuo merged commit dcaaf4c into main Nov 6, 2026
62 of 64 checks passed
@Makisuo
Makisuo deleted the feat/alert-ack-chat branch November 6, 2026 13:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant