feat(signals): add anomaly investigation to inbox source config UI - #71533
Conversation
Adds a toggle for the Product Analytics anomaly investigation signal source (source_product `analytics`, source_type `anomaly_investigation`) to the Inbox source config UI, and lists it as a filterable source in the report list. The backend model, enum, migration, and generated types already accept this source; there was just no way to enable it from the UI. Mirrors the existing health-checks source wiring. Generated-By: PostHog Code Task-Id: 5e9f9ae6-e664-4e61-be04-edcd46d519d7
|
Hey @oliverb123! 👋 It looks like your git author email on this PR isn't your
You can fix it for this repo with: git config user.email "you@posthog.com"Or set it globally with |
🦔 Hogbox preview · ✅ ready▶ Open the preview
commit |
|
Reviews (1): Last reviewed commit: "feat(signals): add anomaly investigation..." | Re-trigger Greptile |
| actions.toggleSignalSource({ | ||
| sourceProduct: SignalSourceProduct.Analytics, | ||
| sourceType: SignalSourceType.AnomalyInvestigation, | ||
| enabled: desiredEnabled, | ||
| }) |
There was a problem hiding this comment.
Rapid Disable Skips Persistence
When a user toggles this new source on and then off before the create request finishes, the second action sees the optimistic new_ config with enabled: false. toggleSignalSource does not update or create anything for that state, so the first request can still persist the source as enabled and the requested disable is lost.
There was a problem hiding this comment.
Not reachable through the UI, so resolving without a change here.
The toggle passes loading={isAnomalyInvestigationToggling}, and LemonButton sets disabled = true whenever loading is set and swallows clicks while disabled (LemonButton.tsx:207 + the onClick guard at :266). That flag flips synchronously: the toggleAnomalyInvestigation listener dispatches toggleSignalSource before it awaits anything, and toggleSignalSource is the action that adds the key to togglingSourceKeys. So the button is already disabled by the time React repaints after the first click, and stays disabled until the create resolves (loadSourceConfigs then refetches truth) — the user can't fire the second toggle mid-flight.
Two caveats:
- The guard is purely the in-flight
loadingstate. If the actions were dispatched programmatically (bypassing the button), thenew_-config +enabled:falseno-op you describe is real. - This is pre-existing and pattern-wide — health checks, conversations, eval reports, and session analysis all share this exact wiring. This PR doesn't introduce it.
If we want to harden against the programmatic/edge case, the right place is the shared toggleSignalSource listener (once, for all sources) rather than this per-source handler — happy to take that as a follow-up.
🤖 CI report
|
| 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.14 MiB · 2,981 files | no change | █████████░ 87.9% 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.3 KiB | ../node_modules/.pnpm/posthog-js@1.402.3/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.9 KiB | ../node_modules/.pnpm/posthog-js@1.402.3/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 |
| 105.8 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 — 🔺 +2.7 KiB (+0.0%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 1315.45 MiB · 🔺 +2.7 KiB (+0.0%)
Problem
Anomaly investigations run and emit signals with
source_product = analytics/source_type = anomaly_investigation, but there was no way to configure that source: noSignalSourceConfigrow could be created from the product because the Inbox source-config UI had no entry for it. So the signals never flowed into the inbox even when investigations happened.Changes
SourcesList.tsx), wired throughsignalSourcesLogicexactly like the existing health-checks source (action, optimistic reducer, config + toggling selectors, and a listener that creates/updates theSignalSourceConfigrow).analyticsas a filterable source in the report list source dropdown (filterOptions.tsx).No backend changes: the model choice, enum, migration (
0062_add_analytics_anomaly_investigation_source), and generated frontend types already accept this source — the only gap was the UI.How did you test this code?
Ran
pnpm --filter=@posthog/frontend format(oxfmt left all three changed files untouched — already conformant) andtypescript:check: no errors reference the changed files or the new symbols (toggleAnomalyInvestigation,anomalyInvestigationConfig,isAnomalyInvestigationToggling). kea typegen forsignalSourcesLogicregenerates cleanly with the new action/selectors. No automated tests were added — this follows the established per-source toggle pattern, which has no unit coverage today. Not manually exercised in a running app.Automatic notifications
Docs update
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Authored by the PostHog Slack app after a thread noticed an anomaly investigation had run but produced no inbox signals, because the
SignalSourceConfigfor it could not be created from the UI. Skills invoked:/signalsand/inbox-exploration(to confirm noanalytics/anomaly_investigationsource config existed for the project and that signals were otherwise flowing). Used the Explore agent to map the source-config UI, then mirrored the health-checks source pattern acrosssignalSourcesLogic.ts,SourcesList.tsx, andfilterOptions.tsx. Chose the health-checks pattern over the session-replay one because anomaly investigation is a plain single(source_product, source_type)on/off toggle with no extra config.Created with PostHog from a Slack thread