Skip to content

feat(cdp): record the queued and sent status of each transactional email - #124736

Merged
trunk-io[bot] merged 2 commits into
masterfrom
posthog/messaging-email-status-writers
Oct 28, 2026
Merged

trunk-io[bot] merged 2 commits into
masterfrom
posthog/messaging-email-status-writers

Conversation

@mayteio

@mayteio mayteio commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Problem

This PR starts the Node writes, and #124751 adds the rest. #123932 reads the table.

Refs #120921.

Changes

  • A transactional email gets a queued row from the send API, then sent from the email step.
  • When the provider rejects the send, the email step writes failed with reason provider_error.
  • version puts a status rank above the time, so a status only moves forward in whatever order the rows arrive.
  • The send API's 202 waits at most 1s for the row. Rows still in flight are produced in the background.
  • Writes are best-effort. A failed produce is logged and counted in cdp_email_status_write_failed, and the send goes on.
  • A run counts as transactional when its trigger event is $transactional_email, the same test the hog flow sensitivity check uses.
  • EMAIL_STATUS_ENABLED gates every write. It is on in dev and test, and off elsewhere.
  • Mechanical: the config keys, the output registration, the topic constant, and the service wiring. The worker's rows flush with the other invocation result sinks.

Warning

Rollout order: create the topic on the cyclotron WarpStream cluster, run migration 0362_email_status (#124696), deploy this stack, then set EMAIL_STATUS_ENABLED for every CDP deployment in one config change. The send API writes queued and the workers write every later status, so a partial switch leaves emails at queued.

How did you test this code?

Test rationale: a wrong rank or a missed write leaves the public status wrong with no error.

  • email-status.service.test.ts (new): the row shape, the version order under out-of-order times, and dropped rows that are counted.
  • email.service.test.ts: the row for a send SES accepts, a send it rejects, a test send, and a workflow email. Extends the existing send tests.
  • cdp-api.serial.test.ts: a queued row for a send, one row for a replayed idempotency key, and none for a refused send.

Ran locally: the Jest suites under src/cdp/services/messaging/, the hog function and hog flow executor tests, the invocation results service, the transactional cases of cdp-api.serial.test.ts, and tsc with no errors in src/cdp.

Not checked yet: a send end to end on the local stack.

Release status

  • No feature flag controls this change

Docs update

None. #123932 documents the endpoint.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Agent: PostHog Desktop (Claude Code), Claude Opus 5.5

🤖 Generated with Claude Code

@mayteio mayteio self-assigned this Oct 28, 2026
@github-actions

github-actions Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

🤖 CI report

✅ Trunk lane — non-backend lane

This PR is assigned to the non-backend lane. It does not run backend Python tests and may merge in parallel with PRs in other lanes.

⚠️ Complexity (TypeScript) — 40 functions above the limit (max 36)

Cyclomatic complexity above the limit in changed typescript files (10 for production files, 15 for test files). Warn only: worth simplifying when you next touch these functions.

Function Location Complexity Limit
ExperimentMetricForm frontend/src/scenes/experiments/ExperimentMetricForm.tsx:139 36 10
Playlist frontend/src/scenes/session-recordings/playlist/Playlist.tsx:82 36 10
isValidRecordingFilters frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.ts:336 31 10
PlayerSidebar frontend/src/scenes/session-recordings/player/PlayerSidebar.tsx:25 30 10
SessionRecordingsPlaylistScene frontend/src/scenes/session-recordings/playlist/SessionRecordingsPlaylistScene.tsx:81 28 10
<anonymous> frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:2359 27 10
updateAnimation frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:3551 26 10
captureRenderedScrollSample frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:273 23 10
loadSessionRecordings frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.ts:1170 23 10
ReplayFiltersTab frontend/src/scenes/session-recordings/filters/RecordingsUniversalFiltersEmbed.tsx:561 22 10
handleMetricTypeChange frontend/src/scenes/experiments/ExperimentMetricForm.tsx:200 20 10
urlToAction frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.ts:2504 20 10
syncSnapshotsWithPlayer frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:3179 19 10
syncPlayerState frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:3041 18 10
<anonymous> frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:4041 17 10
SessionRecordingPreviewCompact frontend/src/scenes/session-recordings/playlist/SessionRecordingPreviewCompact.tsx:77 17 10
SummarizeButton products/replay_vision/frontend/components/SummarizeButton.tsx:21 17 10
setCurrentSegment frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:2975 16 10
<anonymous> frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.ts:2589 16 10
FocusPane products/replay_vision/frontend/components/RecordingMoments.tsx:231 16 10
NativeEmailTemplaterForm frontend/src/scenes/hog-functions/email-templater/EmailTemplater.tsx:580 15 10
convertLegacyFiltersToUniversalFilters frontend/src/scenes/session-recordings/playlist/sessionRecordingsPlaylistLogic.ts:406 15 10
<anonymous> frontend/src/scenes/hog-functions/email-templater/emailTemplaterLogic.tsx:964 14 10
SessionRecordingPlayerInternal frontend/src/scenes/session-recordings/player/SessionRecordingPlayer.tsx:98 14 10
NativeEmailIntegrationChoice frontend/src/scenes/hog-functions/email-templater/EmailTemplater.tsx:274 13 10
computeRenderability frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:2213 13 10
ReplayListColumnView frontend/src/scenes/session-recordings/playlist/ReplayListColumn.tsx:53 13 10
SessionRecordingPreviewBase frontend/src/scenes/session-recordings/playlist/SessionRecordingPreview.tsx:133 13 10
getSessionLinkabilityEventNames frontend/src/scenes/experiments/utils.ts:342 12 10
readRenderedScroll frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:221 12 10
ReplayListHeader frontend/src/scenes/session-recordings/playlist/ReplayListHeader.tsx:16 12 10
runSummary products/replay_vision/frontend/logics/observationsDockLogic.ts:411 12 10
getDefaultMetricTitle frontend/src/scenes/experiments/MetricsView/shared/utils.ts:60 11 10
getEventCountSeries frontend/src/scenes/experiments/utils.ts:658 11 10
Header frontend/src/scenes/session-recordings/SessionRecordings.tsx:61 11 10
findSegmentForTimestamp frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:518 11 10
<anonymous> frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:2053 11 10
<anonymous> frontend/src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts:4124 11 10
SessionRecordingsPlaylistTopSettings frontend/src/scenes/session-recordings/playlist/SessionRecordingsPlaylistSettings.tsx:536 11 10
RecordingMoments products/replay_vision/frontend/components/RecordingMoments.tsx:320 11 10
✅ Duplication (Python) — clean

New Python code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.

✅ Duplication (TypeScript) — clean

New TypeScript code duplication introduced by this branch. Fails at 70+ tokens in app code, or 150+ tokens when both copies live in test files. Advisory while the gate proves itself: extract a shared helper instead of copying.

🚨 Comment density — 11% of added code lines are comments (39 of 365)

This section warns when comments are more than 3% of the code lines a PR adds, and alerts above 6%. Before agent-assisted PRs, the typical share was about 2%. Only full-line comments count. Docstrings, generated files, snapshots, migrations, and workflow files are left out.

Comments that restate the code, record how the change came about, or narrate the next line add noise for the next reader. Keep the comments that explain a reason the code cannot show, and remove the rest. See .agents/skills/writing-code-comments/SKILL.md for the house rules.

Files with the most added comment lines:

File Comment lines Added lines
nodejs/src/cdp/services/messaging/email-status.service.ts 27 154
nodejs/src/cdp/services/messaging/email.service.ts 4 14
nodejs/src/cdp/config.ts 3 10
nodejs/src/cdp/services/messaging/email-status.service.test.ts 2 73
nodejs/src/cdp/cdp-api.ts 1 9
nodejs/src/cdp/cdp-services.ts 1 11
nodejs/src/common/config/kafka-topics.ts 1 2

This check does not block merging. It updates on every push and clears when the share drops.

⚠️ Bundle size — 🔺 +64.4 KiB (+0.1%)

Uncompressed size of every built .js bundle, compared against the base branch.

Total: 77.18 MiB · 🔺 +64.4 KiB (+0.1%)

File Size Δ vs base
render-query/src/render-query/render-query.js 24.99 MiB 🔺 +54.7 KiB (+0.2%)
exporter/src/queries/schema.js 1.27 MiB 🔺 +3.3 KiB (+0.3%)
posthog-app/src/queries/schema.js 1.27 MiB 🔺 +3.3 KiB (+0.3%)

Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report

⚠️ Eager graph — 3 over 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.01 MiB · 25 files 🔺 +356 B (+0.0%) █████████░ 88.2% of 1.14 MiB
logged-out boot: index + App + bootApp (preloaded by every page, including /login)
src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
2.98 MiB · 621 files 🔺 +1.0 KiB (+0.0%) ██████████ 98.1% of 3.03 MiB
🟡 authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
7.59 MiB · 2,568 files 🔺 +6.3 KiB (+0.1%) ██████████ 101.3% of 7.50 MiB
dashboard scene
src/scenes/dashboard/Dashboard.tsx
9.96 MiB · 3,733 files 🔺 +6.9 KiB (+0.1%) ██████████ 99.5% of 10.01 MiB
🟡 today home path
src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
7.78 MiB · 2,661 files 🔺 +6.3 KiB (+0.1%) ██████████ 100.5% of 7.74 MiB
🟡 AI-first home path
src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
8.02 MiB · 2,654 files 🔺 +6.3 KiB (+0.1%) ██████████ 101.5% of 7.91 MiB
events scene
src/scenes/activity/explore/EventsScene.tsx
9.40 MiB · 3,514 files 🔺 +6.8 KiB (+0.1%) ██████████ 98.1% of 9.59 MiB
web analytics scene
src/scenes/web-analytics/WebAnalyticsScene.tsx
10.35 MiB · 3,765 files 🔺 +11.8 KiB (+0.1%) ██████████ 95.5% of 10.83 MiB
replay detail scene
src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
8.44 MiB · 3,109 files 🔺 +22.2 KiB (+0.3%) █████████░ 89.1% of 9.47 MiB

🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/index.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/index.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/layout/navigation-3000/navigationLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/scenes/dashboard/dashboardLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/lemon-ui/LemonMarkdown/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/RichContentEditor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/CodeSnippet/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/taxonomy/core-filter-definitions-by-group.json stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/zod/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/scenes/billing/billingLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/ProductEmptyState/productSetupPreloadLogic.ts stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/ActivityLog/describers stays out of src/scenes/AuthenticatedShell.tsx
🟢 products/dashboards/frontend/widgets/previews/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 products/wizard/frontend/runs/WizardRunDetailsDrawer.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/TodayShell.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/TodayContextPanelFloating.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/TodaySidePanel.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/TodayTopBar.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/todayRailItems.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 zod/v4/locales/de.js stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/playlist/SessionRecordingsPlaylist.tsx stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/queries/validators.js stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/scenes/project-homepage/today/TodayReportPage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/queries/Query/Query.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 packages/quill/packages/charts/ stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 products/posthog_ai/frontend/components/tool/widgets/VisualizationWidget.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 products/posthog_ai/frontend/components/tool/widgets/RecordingsWidget.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 src/queries/Query/Query.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 products/posthog_ai/frontend/api/primitives.ts stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 src/scenes/notebooks/Notebook/notebookLogic.ts stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 src/scenes/session-recordings/playlist/SessionRecordingsPlaylist.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/queries/validators.js stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/scenes/web-analytics/LiveMetricsDashboard/LiveWebAnalyticsMetrics.tsx stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 products/product_analytics/frontend/insights/trends/WorldMap/countryVectors.tsx stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 src/scenes/settings/SettingsMap.tsx stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
🟢 @jspm/core/nodelibs/browser/fs stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.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.7 KiB ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js
4.0 KiB ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js
1.7 KiB ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js
1.7 KiB src/index.tsx
1.6 KiB src/lib/utils/bootTiming.ts
1.2 KiB src/RootErrorBoundary.tsx
949 B src/scenes/ChunkLoadErrorBoundary.tsx
Largest files eagerly shipped from src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
Size File
323.1 KiB ../node_modules/.pnpm/posthog-js@1.439.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.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
102.1 KiB src/products.tsx
86.1 KiB src/lib/api.ts
68.3 KiB src/lib/lemon-ui/icons/icons.tsx
41.9 KiB ../node_modules/.pnpm/@dnd-kit+core@6.0.8_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js
36.4 KiB ../node_modules/.pnpm/kea@4.0.0-pre.6_patch_hash=139b8d1f1304f9d9da452a9a1244c94ea679dbcb85687d8999563146879fb6f5_react@18.3.1/node_modules/kea/lib/index.cjs.js
27.0 KiB ../node_modules/.pnpm/tailwind-merge@2.2.2/node_modules/tailwind-merge/dist/bundle-mjs.mjs
24.6 KiB ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
323.1 KiB ../node_modules/.pnpm/posthog-js@1.439.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 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
102.1 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
86.1 KiB src/lib/api.ts
Largest files eagerly shipped from src/scenes/dashboard/Dashboard.tsx
Size File
323.1 KiB ../node_modules/.pnpm/posthog-js@1.439.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
144.1 KiB ../packages/quill/packages/primitives/dist/index.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
102.1 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
Size File
323.1 KiB ../node_modules/.pnpm/posthog-js@1.439.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 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
102.1 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
86.1 KiB src/lib/api.ts
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
Size File
323.1 KiB ../node_modules/.pnpm/posthog-js@1.439.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
144.1 KiB ../packages/quill/packages/primitives/dist/index.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
102.1 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/activity/explore/EventsScene.tsx
Size File
323.1 KiB ../node_modules/.pnpm/posthog-js@1.439.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
144.1 KiB ../packages/quill/packages/primitives/dist/index.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
102.1 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/web-analytics/WebAnalyticsScene.tsx
Size File
323.1 KiB ../node_modules/.pnpm/posthog-js@1.439.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
187.9 KiB src/queries/validators.js
153.8 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
144.1 KiB ../packages/quill/packages/primitives/dist/index.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
102.1 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
Largest files eagerly shipped from src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
Size File
323.1 KiB ../node_modules/.pnpm/posthog-js@1.439.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
316.1 KiB ../node_modules/.pnpm/posthog-js@1.439.0_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js
286.4 KiB src/taxonomy/core-filter-definitions-by-group.json
239.9 KiB ../packages/quill/packages/quill/dist/index.js
217.5 KiB ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js
153.8 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
102.1 KiB src/products.tsx
94.5 KiB ../node_modules/.pnpm/@tiptap+core@3.20.6_@tiptap+pm@3.20.6/node_modules/@tiptap/core/dist/index.js
92.5 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/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

✅ Toolbar bundle — eager 2.30 MiB within budget

What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.

Metric Size Δ vs base Budget
Eager (shipped)
entry + static imports
2.30 MiB · 18 files 🔺 +688 B (+0.0%) ████░░░░░░ 40.3% of 5.72 MiB
Deferred (lazy) 2.11 MiB · 40 files no change n/a — loads on demand
Loader dist/toolbar.js 1.2 KiB no change █░░░░░░░░░ 6.0% of 19.5 KiB
Largest eagerly-shipped chunks
Size File
915.2 KiB dist/toolbar/toolbar-app-SM4KM3FT.css
695.1 KiB dist/toolbar/chunk-chunk-U3442AL4.js
259.9 KiB dist/toolbar/chunk-chunk-WGO24YVJ.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
130.4 KiB dist/toolbar/chunk-chunk-OUJWRTLQ.js
74.8 KiB dist/toolbar/toolbar-app-U572JKAF.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
35.6 KiB dist/toolbar/chunk-chunk-XCCLDCK3.js
21.7 KiB dist/toolbar/chunk-chunk-UW2K5BF6.js
6.8 KiB dist/toolbar/chunk-chunk-DV7IWQNF.js

Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile

✅ Dist folder size — 🔺 +1.22 MiB (+0.1%)

Total size of the built frontend/dist folder (all assets), compared against the base branch.

Total: 973.41 MiB · 🔺 +1.22 MiB (+0.1%)

ℹ️ MCP UI apps size — 35 app(s), 29001.2 KB JS

Built size of each MCP UI app (main.js + styles.css).

App JS CSS
debug 844.3 KB 211.1 KB
explain-chart 1005.6 KB 211.1 KB
action 767.7 KB 211.1 KB
action-list 835.3 KB 211.1 KB
cohort 766.7 KB 211.1 KB
cohort-list 834.3 KB 211.1 KB
email-template 766.6 KB 211.1 KB
error-details 771.6 KB 211.1 KB
error-issue 768.9 KB 211.1 KB
error-issue-list 836.8 KB 211.1 KB
experiment 832.4 KB 211.1 KB
experiment-list 836.1 KB 211.1 KB
experiment-results 835.0 KB 211.1 KB
feature-flag 834.7 KB 211.1 KB
feature-flag-list 838.4 KB 211.1 KB
feature-flag-testing 770.0 KB 211.1 KB
inline-scan 767.2 KB 211.1 KB
insight-actors 833.8 KB 211.1 KB
llm-costs 831.1 KB 211.1 KB
session-recording 769.0 KB 211.1 KB
survey 768.3 KB 211.1 KB
survey-global-stats 831.1 KB 211.1 KB
survey-list 836.0 KB 211.1 KB
survey-stats 831.1 KB 211.1 KB
trace-span 767.1 KB 211.1 KB
trace-span-list 835.2 KB 211.1 KB
vision-observation-list 834.4 KB 211.1 KB
workflow 767.1 KB 211.1 KB
workflow-list 834.7 KB 211.1 KB
workflow-setup-status 766.7 KB 211.1 KB
query-results 1087.6 KB 211.1 KB
render-ui 1187.2 KB 211.1 KB
visual-review-snapshots 771.6 KB 211.1 KB
workflow-data-suggestions 769.4 KB 211.1 KB
workflow-sending-rules 768.1 KB 211.1 KB

@trunk-io

trunk-io Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Static Badge   Static Badge   Static Badge

View Full Report ↗︎ ⋅ Docs

The send API writes `queued`, and the email step writes `sent`, or `failed` with
`provider_error` when the provider rejects the send. EMAIL_STATUS_ENABLED gates
every write and is off outside dev and test. The send API's 202 waits at most 1s
for the status row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mayteio
mayteio force-pushed the posthog/messaging-email-status-writers branch from e504373 to b91ea2f Compare October 28, 2026 11:39
@mayteio mayteio changed the title feat(cdp): record each transactional email's status feat(cdp): record the queued and sent status of each transactional email Oct 28, 2026
@mayteio
mayteio changed the base branch from posthog/messaging-email-status-table to master October 28, 2026 11:40
@trunk-io

trunk-io Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

😎 This pull request was merged.

@github-actions

Copy link
Copy Markdown
Contributor

React Doctor found no issues in the changed files. 🎉

Reviewed by React Doctor for commit b91ea2f.

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review · Standard · reviewed b91ea2f: 1 Should fix.

This Standard review started from the posthog-review label. Comment @posthog review --deep for a Deep review, or @posthog help to see all commands.

See this review and its findings in PostHog Review.

Comment on lines +154 to +157
await Promise.all(
rows.map(async (row) => {
try {
await this.outputs.produce(EMAIL_STATUS_OUTPUT, {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 · Bound status flushes on worker paths

When email_status acknowledgements stall, workers await this produce through InvocationResultsService.flush(). The producer's 10s instrumentation timeout only logs, so Kafka consumer-v2 reaches its 60s background-task timeout and latches a fatal error, stopping offset advancement despite successful sends. Bound worker status flushes as well as API flushes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 664757b. flush() itself now waits at most 1s on every path, including the worker batch flush through InvocationResultsService, and rows still in flight are produced in the background. A test covers a produce that never settles.

@posthog posthog Bot removed the posthog-review Run a Standard PostHog Review label Oct 28, 2026
- A status flush waits at most 1s on every path, including the worker batch flush, so a stalled produce cannot hold up a batch past its timeout.
- The status ranks leave gaps, so a failure can rank between two statuses without renumbering rows already written.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@mayteio
mayteio marked this pull request as ready for review October 28, 2026 12:43
@parameterai

parameterai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Risk: No findings

This PR adds best-effort Kafka writes of transactional email status rows (queued/sent/failed) for the upcoming email_status ClickHouse table, gated by EMAIL_STATUS_ENABLED. I traced every new write path (send API, email step, worker flush) and found no security issue: all row fields are server-generated, the one externally visible value (message_id) is strictly UUID-validated before parsing, rows are JSON-serialized with no query or template assembly, and the request-path flush is bounded at 1s.

Sentinel reviewed 664757b · Review settings

@mayteio mayteio added the stamphog Request AI approval (no full review) label Oct 28, 2026 — with PostHog
@pr-assigner-resolver-posthog
pr-assigner-resolver-posthog Bot requested a review from a team October 28, 2026 12:44

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved.

The new write path has owning-team authorship as assurance. The older review's worker-stall concern is fixed by bounding the shared status flush, with a stalled-producer regression test; no substantive concerns remain.

  • Author wrote 55% of the modified lines and has 35 merged PRs in these paths (familiarity MODERATE).
Gate mechanics and policy version
Gate Result
prerequisites ✓ all clear
deny-list ✓ no deny categories matched
size ✓ 243L, 9F substantive, 420L/17F incl. docs/generated/snapshots — within ceiling
tier ✓ T1-agent / T1d-complex (420L, 17F, single-area, feat)
stamphog 2.6.1 .stamphog/policy.yml @ 664757b · reviewed head 664757b

@trunk-io

trunk-io Bot commented Oct 28, 2026

Copy link
Copy Markdown

This pull request is queued for merge as part of 124751, which will merge 124736, 124751.

@trunk-io

trunk-io Bot commented Oct 28, 2026

Copy link
Copy Markdown

Stacked PR 124751 failed testing in the merge queue. Please investigate the failure and re-submit the stack.

@trunk-io

trunk-io Bot commented Oct 28, 2026

Copy link
Copy Markdown

This pull request is queued for merge as part of 124751, which will merge 124736, 124751.

@trunk-io
trunk-io Bot merged commit ef2369a into master Oct 28, 2026
315 checks passed
@trunk-io
trunk-io Bot deleted the posthog/messaging-email-status-writers branch October 28, 2026 18:19
@trunk-io

trunk-io Bot commented Oct 28, 2026

Copy link
Copy Markdown

This pull request was merged into master as part of stacked PR 124751.

@deployment-status-posthog

deployment-status-posthog Bot commented Oct 28, 2026 •

Copy link
Copy Markdown

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-10-28 18:50 UTC Run
prod-us ✅ Deployed 2026-10-28 19:06 UTC Run
prod-eu ✅ Deployed 2026-10-28 19:12 UTC Run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stamphog Request AI approval (no full review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants