Skip to content

feat(messaging): mark a code send that leaves the sender to the project - #578

Closed
Silthus wants to merge 9 commits into
email-v2/08-admission-checks-djangofrom
email-v2/09-route-idempotency
Closed

Silthus wants to merge 9 commits into
email-v2/08-admission-checks-djangofrom
email-v2/09-route-idempotency

Conversation

@Silthus

@Silthus Silthus commented Oct 25, 2026 •

Copy link
Copy Markdown
Owner

Part of the code-first rebuild of the email send stack; replaces parts of PostHog#121867 (one send per idempotency key on send/email/).

Problem

  • A developer who retries a keyed code send after the project's default sender changed gets 422 idempotency_key_reused, and the first send's answer is lost.
  • The caller sent the same request. Only the sender PostHog picked for them changed.
  • This is the Django half. feat(cdp): key a code send on the sender the caller chose #580 is the cdp-api half, which keys a code send on the sender the caller chose.

Impact

Pays into Grow Workflows through billed workflows_emails actions per paying org: a retry with the same key replays instead of failing. In scope: Messaging, email API sends.

Merge Danger

Note

🟢 Merge risk: low · two-way door: a revert keys a default-sender send on the resolved sender again

  • Code sends on send/email/ only, behind workflows-email-from-code. Template sends keep the template's sender.
  • No merge order with feat(cdp): key a code send on the sender the caller chose #580. An older cdp-api ignores the marker and keys on the resolved sender, as today. A newer cdp-api without the marker does the same.

Changes

Kind Files Lines
Production 1 +6 −1
Tests 1 +7 −2
  • A keyed code send without from replays after the project's default sender changed. Django marks the sender it resolved as the project default (send.from.isDefault), and cdp-api leaves it out of the key.
  • A send that names a from keys on that address, as before.
  • The idempotency store, its replayed answer and the 422 and 409 refusals are master's, unchanged.

How did you test this code?

Test seams: send/email/ through the DRF client, asserting the body posted to cdp-api (test_transactional_email.py).

Test rationale: the code-send rows that compare the whole send dict now expect isDefault: true without from, and no marker with one. A marker that is missing, or set on a named sender, fails them.

Proofs on this head 1fa81ec (saved with fleet proof):

  • Live run: Django at this head, cdp-api and both CDP workers at the node stack f9abed0, maildev as the sink. 21 requests through the public API. The same Idempotency-Key on a code send answers replayed: true with one email.
  • Shadow diff: the same 21 requests on feat(messaging): point a sender refusal at the from a send names #579's head, this PR's base, and on this head. No difference: replays, refusals and deliveries match.
  • Cross-version: Django at feat(messaging): point a sender refusal at the from a send names #579 against the node stack sends as this head does. Django at this head against cdp-api master: sends by id without options, sends by key, uploads and edits deliver; code sends and sends with options answer 503 delivery_unavailable, nothing reaches maildev, and nothing goes out twice. The node stack deploys first.
  • Prod shape: a gap, accepted by the standing rule until read-only production access exists on 2026-11-02.
  • Lane gate on this head: ruff, the IDOR check, the migration checks, repo-wide mypy, and the messaging and workflows tests pass.
Earlier live run, 2026-10-31
  • Live run, 2026-10-31. Django at the top of the stack (3a30f51c529), cdp-api and both CDP workers at feat(cdp): send a template from the workflow version Django graded #584 (f9abed0841c), mail caught in maildev.

    Step Result
    Keyed code send without from 202, sent from the default sender@example.com
    Switch the project's default sender to other@example.com, then resend the same key and body 202 replayed: true with the same id, one email in total
    New code send without from 202, sent from other@example.com
    Same key and body twice before the switch 202, then replayed: true, one email
  • Prod shape: a gap until read-only production access exists on 2026-11-02.

CI: the fork has no Depot runners, so those jobs never start. Semgrep Checks Pass fails on every fork PR, because its path filter job runs only for the PostHog owner; semgrep with the repo's rules passes locally on the changed files. The lane check reports cross_lane=false.

Release status

  • This change is behind a feature flag and is not available to users

Docs update

None.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Agent: Claude Code, Claude Opus 5.5 (claude-opus-5-5)

Question Answer Who Where
Does this PR keep its own idempotency store? No; it reuses master's store and refusal code, and keeps the code-aware PIPELINE_REFUSALS decoder 👤 Human map #461, 2026-10-28
Does a default-sender change break a keyed retry? No: Django marks the default sender and cdp-api leaves it out of the key 👤 Human map #461, lane brief of 2026-10-25
May the code carry comments? No; names carry the reasons 👤 Human map #461, 2026-10-25

Involvement: one brief with Michael's shrink decision; one review round (GPT-6.1 Sol) with no findings; QA swarm on 2026-11-01 with one panel round (GPT-6.1 Sol review, Opus 5.5 fresh eyes): 1 finding fixed by running the owed proofs; later changes are merges from below; live, shadow-diff and cross-version proof captured.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

🤖 CI report

✅ Complexity (TypeScript) — clean

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.

✅ Bundle size — no change

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

Total: 76.62 MiB · no change

No file changed by more than 1000 B.

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
1019.4 KiB · 24 files no change █████████░ 87.0% 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.95 MiB · 620 files no change ██████████ 97.4% of 3.03 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
7.44 MiB · 2,549 files no change ██████████ 99.2% of 7.50 MiB
dashboard scene
src/scenes/dashboard/Dashboard.tsx
9.89 MiB · 3,716 files no change ██████████ 98.8% 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.61 MiB · 2,641 files no change ██████████ 98.4% 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
7.86 MiB · 2,633 files no change ██████████ 99.4% of 7.91 MiB
events scene
src/scenes/activity/explore/EventsScene.tsx
9.34 MiB · 3,503 files no change ██████████ 97.4% of 9.59 MiB
web analytics scene
src/scenes/web-analytics/WebAnalyticsScene.tsx
10.25 MiB · 3,735 files no change █████████░ 94.6% of 10.83 MiB
replay detail scene
src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
8.38 MiB · 3,084 files no change █████████░ 88.5% 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.6 KiB src/index.tsx
1.3 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
322.5 KiB ../node_modules/.pnpm/posthog-js@1.438.21_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
215.9 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
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
99.8 KiB src/products.tsx
86.2 KiB src/lib/api.ts
68.2 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
322.5 KiB ../node_modules/.pnpm/posthog-js@1.438.21_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
285.9 KiB src/taxonomy/core-filter-definitions-by-group.json
239.8 KiB ../packages/quill/packages/quill/dist/index.js
215.9 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
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
99.8 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.2 KiB src/lib/api.ts
Largest files eagerly shipped from src/scenes/dashboard/Dashboard.tsx
Size File
322.5 KiB ../node_modules/.pnpm/posthog-js@1.438.21_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
285.9 KiB src/taxonomy/core-filter-definitions-by-group.json
239.8 KiB ../packages/quill/packages/quill/dist/index.js
215.9 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
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
99.8 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
322.5 KiB ../node_modules/.pnpm/posthog-js@1.438.21_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
285.9 KiB src/taxonomy/core-filter-definitions-by-group.json
239.8 KiB ../packages/quill/packages/quill/dist/index.js
215.9 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
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
99.8 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.2 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
322.5 KiB ../node_modules/.pnpm/posthog-js@1.438.21_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
285.9 KiB src/taxonomy/core-filter-definitions-by-group.json
239.8 KiB ../packages/quill/packages/quill/dist/index.js
215.9 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
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
99.8 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
322.5 KiB ../node_modules/.pnpm/posthog-js@1.438.21_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
285.9 KiB src/taxonomy/core-filter-definitions-by-group.json
239.8 KiB ../packages/quill/packages/quill/dist/index.js
215.9 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
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
99.8 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
322.5 KiB ../node_modules/.pnpm/posthog-js@1.438.21_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
285.9 KiB src/taxonomy/core-filter-definitions-by-group.json
239.8 KiB ../packages/quill/packages/quill/dist/index.js
215.9 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
182.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
99.8 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
322.5 KiB ../node_modules/.pnpm/posthog-js@1.438.21_@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.438.21_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js
285.9 KiB src/taxonomy/core-filter-definitions-by-group.json
239.8 KiB ../packages/quill/packages/quill/dist/index.js
215.9 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
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
99.8 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 PostHog#32479

✅ Toolbar bundle — eager 2.29 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.29 MiB · 18 files no change ████░░░░░░ 40.0% 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
902.2 KiB dist/toolbar/toolbar-app-PUACMHS6.css
692.2 KiB dist/toolbar/chunk-chunk-QQQ5YJLC.js
260.7 KiB dist/toolbar/chunk-chunk-L6XVLVLY.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
130.4 KiB dist/toolbar/chunk-chunk-BIOZUYB7.js
74.8 KiB dist/toolbar/toolbar-app-3H3VSIEG.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
35.6 KiB dist/toolbar/chunk-chunk-EIARHJWB.js
21.7 KiB dist/toolbar/chunk-chunk-JR4YE4FS.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 — 🔺 +150 B (+0.0%)

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

Total: 964.92 MiB · 🔺 +150 B (+0.0%)

ℹ️ MCP UI apps size — 34 app(s), 27969.1 KB JS

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

App JS CSS
debug 844.3 KB 209.1 KB
action 767.7 KB 209.1 KB
action-list 835.3 KB 209.1 KB
cohort 766.7 KB 209.1 KB
cohort-list 834.3 KB 209.1 KB
email-template 766.6 KB 209.1 KB
error-details 771.6 KB 209.1 KB
error-issue 768.9 KB 209.1 KB
error-issue-list 836.7 KB 209.1 KB
experiment 832.4 KB 209.1 KB
experiment-list 836.1 KB 209.1 KB
experiment-results 834.9 KB 209.1 KB
feature-flag 834.7 KB 209.1 KB
feature-flag-list 838.4 KB 209.1 KB
feature-flag-testing 770.0 KB 209.1 KB
inline-scan 767.2 KB 209.1 KB
insight-actors 833.8 KB 209.1 KB
llm-costs 831.1 KB 209.1 KB
session-recording 768.9 KB 209.1 KB
survey 768.3 KB 209.1 KB
survey-global-stats 831.1 KB 209.1 KB
survey-list 836.0 KB 209.1 KB
survey-stats 831.1 KB 209.1 KB
trace-span 767.1 KB 209.1 KB
trace-span-list 835.2 KB 209.1 KB
vision-observation-list 834.4 KB 209.1 KB
workflow 767.0 KB 209.1 KB
workflow-list 834.7 KB 209.1 KB
workflow-setup-status 766.7 KB 209.1 KB
query-results 1086.5 KB 209.1 KB
render-ui 1162.4 KB 209.1 KB
visual-review-snapshots 771.6 KB 209.1 KB
workflow-data-suggestions 769.4 KB 209.1 KB
workflow-sending-rules 768.0 KB 209.1 KB
ℹ️ MCP agent API — agent-facing tool changes

What this PR changes for agents, from the tool schema snapshots and tool definitions.

Tools changed (1):

Tool Params Scopes Annotations Schema chars
workflows-send-email description changed

@Silthus
Silthus force-pushed the email-v2/08-admission-checks branch from c4fc6e3 to c55794e Compare October 25, 2026 11:39
@Silthus
Silthus force-pushed the email-v2/09-route-idempotency branch from a02de53 to 54de7cd Compare October 25, 2026 11:39
@Silthus
Silthus changed the base branch from email-v2/08-admission-checks to email-v2/08-admission-checks-django October 25, 2026 11:49
@Silthus Silthus closed this Oct 25, 2026
@Silthus Silthus reopened this Oct 25, 2026
@Silthus
Silthus force-pushed the email-v2/08-admission-checks-django branch from 49cab17 to 24881fa Compare October 25, 2026 15:00
@Silthus
Silthus force-pushed the email-v2/09-route-idempotency branch from 54de7cd to f9c45be Compare October 25, 2026 15:00
@Silthus
Silthus force-pushed the email-v2/08-admission-checks-django branch from 24881fa to 801bdfc Compare October 25, 2026 17:38
@Silthus
Silthus force-pushed the email-v2/09-route-idempotency branch 3 times, most recently from e70cb46 to 79e619b Compare October 25, 2026 20:58
@Silthus
Silthus force-pushed the email-v2/08-admission-checks-django branch from a5d494f to 1d7fe4c Compare October 25, 2026 22:28
@Silthus
Silthus force-pushed the email-v2/09-route-idempotency branch from 79e619b to ad8792b Compare October 25, 2026 23:01
@Silthus
Silthus force-pushed the email-v2/08-admission-checks-django branch from 1d7fe4c to 0eeb308 Compare October 26, 2026 01:11
@Silthus
Silthus force-pushed the email-v2/09-route-idempotency branch from ad8792b to c4c5ff0 Compare October 26, 2026 01:12
@Silthus
Silthus force-pushed the email-v2/08-admission-checks-django branch from 0eeb308 to 25f064a Compare October 26, 2026 02:35
@Silthus
Silthus force-pushed the email-v2/09-route-idempotency branch from c4c5ff0 to 67987fd Compare October 26, 2026 02:35
@Silthus
Silthus force-pushed the email-v2/08-admission-checks-django branch from 25f064a to 0f434a3 Compare October 26, 2026 05:29
@Silthus
Silthus force-pushed the email-v2/09-route-idempotency branch from 67987fd to c6e5910 Compare October 26, 2026 05:30
@Silthus
Silthus force-pushed the email-v2/08-admission-checks-django branch from 0f434a3 to f3b92ce Compare October 31, 2026 13:47
@Silthus
Silthus force-pushed the email-v2/09-route-idempotency branch from c6e5910 to 688eba5 Compare October 31, 2026 13:49
@Silthus Silthus changed the title feat(messaging): send each email once per idempotency key feat(messaging): mark a code send that leaves the sender to the project Oct 31, 2026
A code send without `from` now tells cdp-api its sender is the project's
default (`from.isDefault`). cdp-api keys an Idempotency-Key retry on the
sender the caller chose, so a retry after the default sender changed
replays the first send instead of answering that the key was reused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Silthus
Silthus force-pushed the email-v2/08-admission-checks-django branch from f3b92ce to 1c8455d Compare October 31, 2026 16:09
@Silthus
Silthus force-pushed the email-v2/09-route-idempotency branch from 688eba5 to 303f239 Compare October 31, 2026 16:11
Silthus and others added 8 commits November 1, 2026 17:49
…oute-idempotency

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oute-idempotency

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oute-idempotency

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…oute-idempotency

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Silthus

Silthus commented Nov 2, 2026

Copy link
Copy Markdown
Owner Author

Moved to PostHog#127182.

@Silthus Silthus closed this Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant