---
name: od-notifications
description: Notification spam incidents — repeated alerts, toast fatigue, level-triggered pings, missing dedupe, reminder loops. Triggers on notification, notify, spam, ping, alert, reminder, popup, toast, fatigue, dedupe. Invoke BEFORE adding another notifier.
---

# Notification spam — incident playbook

audience: AI coding agents first. BLUF: edge-triggered only → auto-remediate before notify → dedupe on stable episode identity.

## Covers

**Absorbs:** `notification-spam`, `notification-fatigue`.

**Keywords:** notification, notify, spam, ping, alert, reminder, popup, toast, fatigue, dedupe, repeated alerts.

**Registry coverage:** 22 of 217 (2026-08-08). Recurring: level-triggered "still bad" re-notify every poll tick; timestamp dedupe fails across restarts; alert without remediation path.

## Doctrine

Edge-triggered only. Auto-remediate before notifying. Dedupe on stable episode identity, never timestamps.

## First steps — silence is not the fix

1. **Find notifier:** trace to source — systray, collector alerter, mem-guard, harness event, desktop gdbus. Read its config + cooldown.
2. **Level vs edge:** if condition still true and notifier fires again → level-triggered bug. Fix: notify on transition (clear→act) only; clear episode on recovery.
3. **Episode identity:** dedupe key = stable id (run-id, item-id, host+scope, rule+target). NEVER dedupe on `Date.now()` or wall clock alone.
4. **Auto-remediate first:** notification must follow attempted fix or explicit "cannot auto-fix" branch. Owner ping = last resort.
5. **Quiet hours / cooldown:** verify config seeded from mined thresholds (`ANNOYANCE_FATIGUE §7`) — do not invent thresholds; disabled alerter must say how to enable.
6. **Repro:** simulate flapping signal — must produce ≤1 notify per episode.

## Never-touch — applies here

From `modules/workstation/claude/incidents/never-touch.md`:

- NEVER bypass admission queue (batch fixes still queued).
- NEVER disable guards globally to stop notify side effects — fix notifier.

## Placement map — read these paths

`modules/workstation/claude/incidents/placement-map.md`:

- `~/.overdeck` — systray, notifier config.
- `~/.local/state/overdeck` — `items.jsonl`, alerter state.
- Collector `collector/src/alerter.ts` — deck alert rules; deploy clone is runtime copy.

## Resolve — exact CLI (never guess syntax)

```
od-incidents list [--type notification-spam] [--state S]
od-incidents show <id>
od-incidents search <query>
od-incidents resolve <id> --artifact <ref> [--summary <line>]
```

`resolve` REFUSES without `--artifact` (exit 2). Artifact = test showing single notify per episode, or config diff + observed quiet period.
