feat(routing): resolve ROLE and IdP Group teams; per-alert mutes (#27, part 3) #28

Merged
KofTwentyTwo merged 1 commits from fix/team-sources-mute-scope into develop 2026-10-14 15:50:35 +00:00
KofTwentyTwo commented 2026-10-14 15:46:46 +00:00 (Migrated from github.com)

Part 3 of 3 for #27: team member sources and mute scope. Parts 1 (quiet hours and digests) and 2 (reminders and escalation) are separate PRs.

Team sources

  • New public SPI AlertAudienceResolver (resolve(sourceType, sourceValue) -> Set<userId>), registered with AlertsQBitConfig.withAudienceResolver(...). The qbit doesn't depend on the role or Authentik qbits; the host supplies the resolver.
  • The router merges the resolved users with the MANUAL members, de-duplicates them and caps the list at maxAudienceSize. Over the cap it logs and stops adding, and doesn't fail routing for everyone else. Each user still goes through the visibility check.
  • With no resolver, or a resolver that throws, ROLE and IdP Group teams resolve to nobody. The router logs a warning, and the team screen help says "ROLE and IdP Group members need a host resolver; none is configured" (worked out at runtime).

Mutes

  • The per-alert Mute action now mutes only that alert, using a new ALERT scope keyed on type plus dedup key. Mute this alert type is a separate action.
  • RECORD-scope mutes store scopeRecordId, and the matcher now compares it. Before, it was always passed null, so RECORD mutes never matched.
  • Changesets 21 (alerts_mute.scope_record_id) and 22 (widen scope_value to 520) are guarded. If part 1 or 2 merges first and takes those numbers, I'll renumber on the merge.

Tests: mvnw -o -B verify green (112 tests, 93.9% instruction coverage, checkstyle, guardrails). New tests cover resolver expansion (ROLE, IdP Group, de-duplication with MANUAL, no resolver), the per-alert mute, RECORD-scope matching and the type mute.

🤖 Generated with Claude Code

Part 3 of 3 for #27: team member sources and mute scope. Parts 1 (quiet hours and digests) and 2 (reminders and escalation) are separate PRs. **Team sources** - New public SPI `AlertAudienceResolver` (`resolve(sourceType, sourceValue) -> Set<userId>`), registered with `AlertsQBitConfig.withAudienceResolver(...)`. The qbit doesn't depend on the role or Authentik qbits; the host supplies the resolver. - The router merges the resolved users with the MANUAL members, de-duplicates them and caps the list at `maxAudienceSize`. Over the cap it logs and stops adding, and doesn't fail routing for everyone else. Each user still goes through the visibility check. - With no resolver, or a resolver that throws, ROLE and IdP Group teams resolve to nobody. The router logs a warning, and the team screen help says "ROLE and IdP Group members need a host resolver; none is configured" (worked out at runtime). **Mutes** - The per-alert **Mute** action now mutes only that alert, using a new `ALERT` scope keyed on type plus dedup key. **Mute this alert type** is a separate action. - RECORD-scope mutes store `scopeRecordId`, and the matcher now compares it. Before, it was always passed null, so RECORD mutes never matched. - Changesets **21** (`alerts_mute.scope_record_id`) and **22** (widen `scope_value` to 520) are guarded. If part 1 or 2 merges first and takes those numbers, I'll renumber on the merge. Tests: `mvnw -o -B verify` green (112 tests, 93.9% instruction coverage, checkstyle, guardrails). New tests cover resolver expansion (ROLE, IdP Group, de-duplication with MANUAL, no resolver), the per-alert mute, RECORD-scope matching and the type mute. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.