feat(alerts): capture insight alert destination create/delete events - #71027
Conversation
Insight alert messaging destinations (Slack, Discord, Microsoft Teams, webhook) are created as separate HogFunctions after the alert, so neither `alert created` nor `alert updated` records which destination type was attached. That left no way to measure adoption of individual destination types. Emit `insight alert destination created` (one per successfully created destination, tagged with `type`) and `insight alert destination deleted` (tagged with the type derived from the HogFunction template_id), mirroring the existing `logs alert destination created`/`deleted` events. Adds a `notificationTypeFromTemplateId` helper next to the existing template mapping, with a parameterized test guarding the two against drift. Generated-By: PostHog Code Task-Id: e9e87adc-1734-4175-b5e1-b2854d717329
🤖 CI report
|
| File | Size | Δ vs base |
|---|---|---|
posthog-app/_parent/products/tracing/frontend/TracingScene.js |
102.3 KiB | 🔺 +2.4 KiB (+2.4%) |
Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report
✅ Eager graph — within budget
How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.
| Root | Eager (shipped) | Δ vs base | Budget |
|---|---|---|---|
entry (logged-out pages, app bootstrap)src/index.tsx |
1.22 MiB · 22 files | no change | ███░░░░░░░ 28.4% of 4.29 MiB |
authenticated shell (every logged-in page)src/scenes/AuthenticatedShell.tsx |
8.15 MiB · 2,978 files | no change | █████████░ 88.1% of 9.25 MiB |
🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 [object Object] stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
🟢 [object Object] stays out of src/scenes/AuthenticatedShell.tsx
Largest files eagerly shipped from src/index.tsx
| Size | File |
|---|---|
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 24.6 KiB | ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js |
| 6.3 KiB | ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js |
| 4.5 KiB | ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js |
| 3.9 KiB | ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js |
| 1.4 KiB | ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js |
| 1.3 KiB | src/RootErrorBoundary.tsx |
| 912 B | ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js |
| 789 B | src/scenes/ChunkLoadErrorBoundary.tsx |
| 762 B | src/index.tsx |
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
| Size | File |
|---|---|
| 281.1 KiB | ../node_modules/.pnpm/posthog-js@1.401.0/node_modules/posthog-js/dist/rrweb.js |
| 267.7 KiB | ../node_modules/.pnpm/@posthog+icons@0.38.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 235.5 KiB | src/taxonomy/core-filter-definitions-by-group.json |
| 222.7 KiB | ../node_modules/.pnpm/posthog-js@1.401.0/node_modules/posthog-js/dist/module.js |
| 164.0 KiB | src/queries/validators.js |
| 154.3 KiB | ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 106.1 KiB | src/lib/api.ts |
| 93.3 KiB | ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js |
| 92.7 KiB | ../packages/quill/packages/quill/dist/index.js |
Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479
✅ Dist folder size — 🔺 +34.0 KiB (+0.0%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 1308.11 MiB · 🔺 +34.0 KiB (+0.0%)
Centralize the notification-type → HogFunction template_id mapping into one TEMPLATE_ID_BY_NOTIFICATION_TYPE map. buildAlertDestination reads it and notificationTypeFromTemplateId inverts it, instead of each hand-listing the same four `template-*` literals. Generated-By: PostHog Code Task-Id: e9e87adc-1734-4175-b5e1-b2854d717329
The `insight alert destination deleted` capture fired unconditionally before deleteWithUndo resolved, so it was recorded even when the DELETE request failed (deleteWithUndo swallows errors) and on the undo action — inflating deletion counts. Move the capture into the deleteWithUndo callback and gate it on the non-undo path, so it only fires after a delete actually lands. The destination type is resolved from the closure up front since the HogFunction is gone from state by the time the callback runs. Generated-By: PostHog Code Task-Id: e9e87adc-1734-4175-b5e1-b2854d717329
🦔 Hogbox preview · ✅ ready▶ Open the preview
commit |
|
Reviews (1): Last reviewed commit: "fix(alerts): only capture destination de..." | Re-trigger Greptile |
There was a problem hiding this comment.
Frontend-only analytics instrumentation adding posthog.capture calls for insight alert destination create/delete, with parameterized test coverage and a STRONG-familiarity author; not risky territory (no migrations, API contracts, auth, billing, deps, or CI touched).
- Author wrote 89% of the modified lines and has 0 merged PRs in these paths (familiarity STRONG).
- greptile-apps[bot] reviewed the current head.
- Unresolved greptile inline comment: deleting a destination with an unrecognized/legacy template_id still emits the deletion event with type: null, so type-filtered deletion reports will undercount those destinations. Minor analytics-completeness gap, not a correctness or safety issue — fine to address as a fast-follow.
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✓ | no deny categories matched |
| size | ✓ | 60L, 2F substantive, 84L/3F incl. docs/generated/snapshots — within ceiling |
| tier | ✓ | T1-agent / T1b-small (84L, 3F, single-area, feat) |
| stamphog 2.0.0b3 | .stamphog/policy.yml @ 4f77bdc · reviewed head 01c80d8 |
|
👋 Visual changes detected for this PR. Review and approve in PostHog Visual Review If these changes are unexpected, they may be caused by a flaky test or a broken snapshot on master. Don't approve — rerun the job or wait for a fix. |
Addresses a Greptile review finding: the delete path could emit `insight alert destination deleted` with `type: null` when a destination's template_id isn't recognized, which pollutes type-filtered deletion reports. Guard the capture on a known type so the delete path only emits classifiable events, matching the create path which always carries a known type. Generated-By: PostHog Code Task-Id: e9e87adc-1734-4175-b5e1-b2854d717329
New commits pushed (delta classified non_trivial_delta) — stamphog approval dismissed; re-review running automatically.
There was a problem hiding this comment.
Frontend-only analytics instrumentation (posthog.capture calls) with no auth/billing/migration/API surface touched; author is on the owning team with strong familiarity, added tests cover the new mapping helper, and the one substantive reviewer comment (unrecognized template losing type on delete) was already addressed in the diff.
- Author wrote 89% of the modified lines and has 0 merged PRs in these paths (familiarity STRONG).
- 👍 on the PR from greptile-apps[bot], hex-security-app[bot].
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✓ | no deny categories matched |
| size | ✓ | 63L, 2F substantive, 87L/3F incl. docs/generated/snapshots — within ceiling |
| tier | ✓ | T1-agent / T1b-small (87L, 3F, single-area, feat) |
| stamphog 2.0.0b3 | .stamphog/policy.yml @ 79cffa7 · reviewed head 6f33174 |
…lytics Generated-By: PostHog Code Task-Id: e9e87adc-1734-4175-b5e1-b2854d717329
The frontend typecheck gate runs kea-typegen and fails on any drift between generated and committed types. notebookNodeSQLV2Logic's committed inline type block on master was missing the isInterrupting value and the interruptRun/setIsInterrupting actions that the logic already declares, so every PR merging with master (including this one) failed the "types up to date" check. Regenerate the block to include those entries. The resulting file matches kea-typegen's output exactly (blob 2f2b6c6). No logic change — generated types only. Generated-By: PostHog Code Task-Id: e9e87adc-1734-4175-b5e1-b2854d717329
New commits pushed (delta classified non_trivial_delta) — stamphog approval dismissed; re-review running automatically.
There was a problem hiding this comment.
Additive analytics-only change (new posthog.capture calls for alert destination create/delete) with a shared, tested mapping helper; the one prior reviewer concern (unclassified deletions) is already fixed in the current diff. The unrelated notebookNodeSQLV2Logic.ts hunk is just inline-typegen interface additions matching already-existing implementation, not new behavior.
- Author wrote 89% of the modified lines and has 0 merged PRs in these paths (familiarity STRONG).
- 👍 on the PR from greptile-apps[bot], hex-security-app[bot].
Gate mechanics and policy version
| Gate | Result | |
|---|---|---|
| prerequisites | ✓ | all clear |
| deny-list | ✓ | no deny categories matched |
| size | ✓ | 70L, 3F substantive, 94L/4F incl. docs/generated/snapshots — within ceiling |
| tier | ✓ | T1-agent / T1b-small (94L, 4F, two-areas, feat) |
| stamphog 2.0.0b3 | .stamphog/policy.yml @ d72a7eb · reviewed head 411f792 |
Problem
We can't measure adoption of insight-alert messaging destinations by type. When a user adds a Slack, Discord, Microsoft Teams, or webhook destination to an insight alert, it's created as a separate HogFunction after the alert — so neither
alert creatednoralert updatedrecords which destination type was attached. The only broad proxy,integration created, is generic (it also fires for Linear, Google Ads, etc., which aren't alert destinations at all), so it can't answer "how many Discord/Teams alert destinations were set up?"This gap surfaced when trying to report on Discord and Microsoft Teams alert-destination adoption — there was simply no signal that tied a destination type to an alert.
Changes
Emit dedicated analytics events from the insight alert notification flow, mirroring the existing
logs alert destination created/logs alert destination deletedevents:insight alert destination created— one per successfully created destination, tagged withtype(slack/discord/microsoft_teams/webhook) andalert_id.insight alert destination deleted— tagged with thetypederived from the HogFunction'stemplate_id, andalert_id.Adds a small
notificationTypeFromTemplateIdhelper next to the existingbuildAlertDestinationtemplate mapping so the two stay in sync.How did you test this code?
notificationTypeFromTemplateId(template → type mapping, plus null/unknown handling).jest products/alerts/frontend/logic/alertNotifications.test.tspasses (17/17).kea-typegenon the changed logic — types generate cleanly.posthog.capturepattern already used elsewhere in this logic file and in the logs equivalent.This new test catches drift between the destination
template_ids written inbuildAlertDestinationand the type mapping used to label the analytics events — a mismatch would silently mislabel adoption.🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Authored by the PostHog Slack app (Claude) from a Slack thread. The task started as a data question about Discord/Microsoft Teams insight-alert-destination adoption; the data showed no measurable signal, and investigation traced this to missing instrumentation rather than zero usage. Chose to mirror the established logs-alert destination events rather than enriching
alert created/alert updated, because destinations are created as independent HogFunctions and would not be reliably captured on the alert lifecycle events.No skills were required (frontend-only kea logic change; no DRF/migration/generated-API-type changes).
Created with PostHog from a Slack thread