Skip to content

[Feat] Offer Discord destinations for suggester, announcer, and platform-issue alerts#413

Merged
daniel-lxs merged 8 commits into
developfrom
feat/discord-remaining-destinations
Jul 16, 2026
Merged

[Feat] Offer Discord destinations for suggester, announcer, and platform-issue alerts#413
daniel-lxs merged 8 commits into
developfrom
feat/discord-remaining-destinations

Conversation

@daniel-lxs

@daniel-lxs daniel-lxs commented Jul 16, 2026

Copy link
Copy Markdown
Member

Completes #268's per-automation Discord destinations: the three destination fields that stayed Slack-only get the same one-of Slack-or-Discord picker as the six triage/auditor automations.

Changes

  • suggester — declares discord in its registry entry (capability badge becomes "Slack · Discord only"); scheduled suggestion summaries already routed to a targeted Discord channel via the destination waterfall, so only the write path + picker were missing. The experimental suggestion-routing-flag UI is untouched.
  • announcer — picker added (delivery already worked via the communication adapter).
  • platform-issue alerts — the real gap: it had no Discord delivery at all and, it turns out, no rendered settings card either — the Alert on Config Errors definition, dirty-tracking, and save wiring existed but nothing displayed it. This PR renders the card (picker-only, in Other automations) and adds Discord delivery in record-task-message-envelope: when the automation's own target is a Discord channel, the alert posts there via the runtime-credentials provider (best-effort, Slack path unchanged, slackPostedAt reused as the posted-anywhere marker so no migration).

One-of semantics, keep-persisted preservation, and validation mirror the existing six fields; the new zod inputs are optional so in-flight clients keep working across a deploy.

Screenshots

Captured on this branch against a dev deployment with one connected Discord server (Slack also connected, so options carry the "(Discord)" suffix — it is omitted on Discord-only deployments).

The combined destination picker — Discord channels alongside Slack in one searchable dropdown:

download

A Discord channel selected as an automation's destination (provider-neutral label):

download (1)

The "Slack · Discord only" capability badge on Suggest Ideas and the newly rendered Alert on Config Errors card:

download (2)

Alert on Config Errors expanded with a Discord channel selected — this automation previously had no Discord delivery and no settings card:

download (3)

Review note

Rendering the previously-orphaned platform-issue card is the one product-facing judgment call here — the alternative was a configurable Discord destination with no way to configure it. The card's label/description/icon all pre-existed.

Validation

  • Real-DB settings tests: discord save clears slack (and vice versa), unrelated saves preserve targets, platform-issue enablement counts a Discord channel — 8/8
  • New platform-issue delivery tests: Discord target, Slack manager-channel fallback unchanged, missing Discord credentials leaves the report unposted — 3/3
  • Full web automations UI/command suites (72), sdk task-runs (258+3), db (286), types (572) green; check-types 26/26, oxlint, format, knip pass

🤖 Generated with Claude Code

… alerts

Extends the PR #268 Slack-or-Discord one-of destination picker to the three
remaining automation destination fields:

- suggester: registry now declares 'discord' in
  supportedCommunicationProviders (scheduled-suggestion delivery already
  falls through Slack -> Discord); settings write path and picker added.
- announcer: settings write path and picker added (Discord delivery already
  worked via resolveAutomationRuntimeDestination + the comms adapter).
- platform_issue_alerts: settings write path, picker, and a new Discord
  delivery branch in record-task-message-envelope — when the automation's
  own destination target is a Discord channel, the alert posts there via
  the Discord communication provider instead of Slack (best-effort, and the
  existing slackPostedAt marker doubles as the posted-anywhere gate).

Details:

- normalizeBackgroundAgentSettings now exposes suggesterDiscordChannelId,
  announcerDiscordChannelId, and platformIssueDiscordChannelId from the
  automations' discord_channel targets.
- settings-update upserts the three automations with
  buildDestinationChannelTargets + managedTargetKinds ['slack_channel',
  'discord_channel'], with the same server-side one-of backstop (Discord
  preferred) as the six existing pickers. Their keep-persisted Slack values
  stay un-suppressed because these three resolve via
  getAutomationSlackChannelTarget, which never merges the manager-channel
  fallback.
- The shared renderSlackDestinationField now serves suggester, announcer,
  and a newly rendered Alert on Config Errors card; platform_issue_alerts
  joins MANAGER_REPORTING_AUTOMATION_KEYS so its "Reports to" line resolves.
- Suggester's capability badge changes from "Slack only" to
  "Slack · Discord only".

Tests: settings-update-discord real-DB coverage for the three fields
(discord save clears slack, slack save clears discord, unrelated saves
preserve), a new platform-issue alert delivery test (Discord target, Slack
fallback, missing Discord credentials), registry provider-list assertion,
and render coverage for the new card.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@roomote-roomote

roomote-roomote Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

No code issues remain; no new code issues found in the latest commit. See task

  • apps/web/src/trpc/commands/automations/settings-update.ts:377-385 Treat omitted Discord fields as “preserve” rather than “clear.” The API allows older clients to omit these fields, but normalizeOptionalText(undefined) becomes null; saving the same automation then removes its persisted Discord target, and a Discord-only platform-issue alert is disabled entirely.
  • apps/web/src/trpc/commands/automations/settings-update.ts:654-676 Preserve one-of semantics when an older client submits a Slack channel while omitting the new Discord field. These branches retain the persisted Discord target while the Slack path still resolves the submitted channel, so both targets are written; runtime initially chooses Slack, but a later current-client save submits both and the Discord-wins backstop silently switches routing back to Discord. An explicit legacy Slack selection should clear the persisted Discord target, while an empty Slack value should preserve it.

Reviewed a17acd1

daniel-lxs and others added 7 commits July 15, 2026 23:48
'Post summaries to this Slack channel' above a picker that offers (or
has selected) a Discord channel reads as a bug; drop the provider word
when Discord options are shown.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The announcer delivers to whichever provider its destination resolves
to, and the card now offers Discord channels directly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…cted

On a Discord-only deployment the suffix disambiguates nothing and every
option reads as noise. Gate it on the slackConnected capability rather
than the momentary Slack channel list so labels don't flicker while the
list loads.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The destination renderer read slackConnected without declaring it as a
useCallback dependency, so a Slack connect/disconnect while mounted
would keep rendering labels for the old state. Use the component-scope
value consistently and depend on it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The three new Discord destination fields are optional in the API so
in-flight clients keep working across a deploy, but an omitted field was
normalized to null and treated as an explicit clear: an older client
re-saving the same automation wiped its Discord target, disabling a
Discord-only platform-issue alert entirely. Only an explicitly submitted
value now reaches resolution; omission keeps the persisted channel
without re-validating it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Preserve-on-omit left both targets stored when a pre-deploy client
picked a Slack channel while unable to send the Discord field; a later
current-client save would then submit both and the Discord-wins
backstop silently flipped routing back to Discord. An explicitly
selected Slack channel now clears the invisible Discord target; an
empty Slack value still preserves it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@daniel-lxs
daniel-lxs merged commit e9f097e into develop Jul 16, 2026
17 checks passed
@daniel-lxs
daniel-lxs deleted the feat/discord-remaining-destinations branch July 16, 2026 15:38
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