Skip to content

feat(workflows): resolve the first-run email sender - #455

Closed
Silthus wants to merge 1 commit into
workflows-sandbox/first-deliveryfrom
workflows-sandbox/first-run-sender
Closed

Silthus wants to merge 1 commit into
workflows-sandbox/first-deliveryfrom
workflows-sandbox/first-run-sender

Conversation

@Silthus

@Silthus Silthus commented Oct 12, 2026 •

Copy link
Copy Markdown
Owner

Problem

Workflow authors without a verified sender still enter an empty email sender field when creating their first workflow.

Supersedes PostHog#112003 (left open as the original draft).

Stack: layer 11 of 12, stacked on #454. Next: #456.

This fork PR moves to an upstream PostHog/posthog PR after review.

Warning

🟡 Merge risk: medium · two-way door (merge-risk rubric)

  • New email steps can select the managed sender automatically; provisioning and asynchronous insertion must preserve project boundaries.
  • The sandbox fallback requires its flag and no verified own sender. Template and insertion tests cover the editor boundary.

Changes

  • Only dedicated email actions can provision or receive the sandbox fallback; generic email functions retain own-sender assignment.
  • New workflow templates, trigger-prefilled new workflows and inserted email steps select their sender in one pass, before the email editor mounts.
  • Verified project defaults and sole verified own senders take precedence. Existing sender values remain intact.
  • Sandbox provisioning coalesces concurrent requests and awaits the refreshed integration list.
  • Accepted email drops survive drag cleanup and wait for template defaults.
  • While an email step's sender is still resolving, insertion asks the user to wait. Build panel controls show "Preparing the email sender…", and the tile canvas, command bar and quick add show a wait toast.
  • Saving a new workflow waits for that sender, so the step is never dropped. Both save buttons are disabled with "An email step is still being added. Try again in a moment.", and a submit returns with that message as an info toast.
  • Broadcasts keep own senders, configured Reply-To prevents sandbox selection, and transient provisioning failures permit a later explicit retry.

Note

Flag-off deviation from master: a template email with a custom From address and no integration no longer receives the project's own default sender, which master filled in. The first-run check treats any From as configured.

Before:

flowchart LR
    A[Create email step] --> B[Own sender default] --> C[Mount editor]
    classDef phBlue fill:#1d4aff,stroke:#1d4aff,color:#fff;
    classDef phYellow fill:#f9bd2b,stroke:#f9bd2b,color:#000;
    class A,C phYellow;
    class B phBlue;
Loading

After:

flowchart LR
    A[Create template or email step] --> B[Resolve verified own sender]
    B --> C[Provision flagged sandbox fallback]
    C --> D[Assign sender and mount editor]
    classDef phBlue fill:#1d4aff,stroke:#1d4aff,color:#fff;
    classDef phRed fill:#f54e00,stroke:#f54e00,color:#fff;
    classDef phYellow fill:#f9bd2b,stroke:#f9bd2b,color:#000;
    class A,D phYellow;
    class B phBlue;
    class C phRed;
Loading

UI walk at fa33d78fb36. Captures from a local preview of the stack tip fa33d78fb36, flag workflows-sandbox-sender, demo data. Flag off is the before. Real SES is unreachable in this preview, so sends stop at the SES call, shown as ECONNREFUSED.

Before: template email step without a sender

Before (flag off): a new workflow from a template, in a project without senders, has no sender.

After: template email step starts with the sandbox sender

After (flag on): the template's email step starts with the sandbox sender.

Before: new email step without a sender

Before (flag off): a new Email step has no sender.

After: new email step starts with the sandbox sender

After (flag on): a new Email step starts with the sandbox sender.

After: verified own sender wins over the sandbox sender

With a verified own sender, a new Email step starts with that sender instead.

Earlier captures. Each caption names the commit it was taken at.

New email step in a project without senders defaults to the sandbox sender

In a project with no sender of its own, a new Email step starts with the sandbox sender. Taken at 90dc9d4d649 in the combined live preview of both stacks.

How did you test this code?

Current evidence, 2026-10-24, head 5d9f05a387c.

Owed proofs:

  • Live run: rerun at the stack tip 8ac8853cc82, which contains this layer. The stack's cdp-api sent through the workflow test-run endpoint to a local SES fake that records each request. 9 of 9 cases pass. 12 of 13 recorded cases match the run at fa33d78fb36. Case 2c (an unverified member on To) now shows the verify-your-email guidance with reason recipient_unverified, and makes no SES request. For this layer: case 1 covers delivery from a step on the sandbox sender. The UI walk shows the first-run selection.
  • UI walk: local preview of the stack tip fa33d78fb36, flag workflows-sandbox-sender off (before) and on (after), demo data. The captures sit in Changes, beside the behavior each one shows. Round 4 changes no UI in this layer, so these fa33d78fb36 captures still hold at the round 4 head.
  • Prod shape: gap, accepted by Michael on 2026-10-24 until production read access on 2026-11-02. Until then it is unknown how many stored workflow email steps and email integration rows take each changed branch.

Changes in this layer since the 2026-10-19 heads (restacked onto fork master 448d802: the editor logic keeps master's UTM defaults, and the first-run sender pass replaces master's default sender pass):

  • Round 1 fixed: a duplicated generic function email step no longer receives the sandbox sender; only function_email does.
  • Round 1 fixed: trigger-prefilled new workflows, which master added, get the first-run sender, and templates and prefills run one sender pass (preselects the first-run sender once, template and trigger prefill cases).
  • Round 1 fixed: the palette, command bar and quick add ask the user to wait instead of adding a step while an email sender resolves (asks to wait instead of adding from the palette/command bar/quick add).
  • Round 1 fixed: master's duplicate-email test now awaits the async insertion; it failed at the restacked head.
  • Round 2 fixed: saving a new workflow while an email step's sender resolves is held, so the step is never dropped. Round 1 had shown a toast on save, which never appeared because the save replaces the route (holds the save of a new workflow until its email step has a sender, red then green; removing the guard fails it).
  • Final read: GPT-6.1 Sol read the G5 layer range-diffs and found nothing.
  • Round 4: no change in this layer.
  • Final read 2: GPT-6.1 Sol read the round 4 range-diffs per group and found nothing.
Local gate at the stack tip 8ac8853cc82, shared by every layer

Test seams: real workflow template loading and editor insertion, the workflow save actions, plus shared integration request/reload actions.

Test rationale: The generic-action case catches invalid sandbox assignment and now requires zero provisioning requests. Existing cases protect own-sender defaults, Reply-To, drag cleanup and concurrent requests.

Gaps: real AWS SES delivery and the AWS-side tenant pause (every proof uses a local SES fake or an unreachable SES), clustered Valkey, the production data shape (prod-shape gap until production read access on 2026-11-02), and fork CI, which fails during setup: path selection fails without a GitHub App client ID, and the Security aggregate rejects its fork-skipped path-filter job. Application CI is a verification gap. The UI walk could not create an own sender through the UI, because SES was unreachable; it seeded own senders in the database instead. The UI walk did not capture the held save; the Jest test above covers it.

Earlier evidence (superseded heads)

Round 3 heads, 2026-10-23. This layer's head: 85263304b6a. Stack tip fa33d78fb36.

Whole-stack QA swarm, 2026-10-19. Reviewed tip cfee7e148ae. This layer's head: 2ece04ed51f.

  • Live run at b9bd346ed0e (this stack's cdp-api against a local SES fake, workflow test-run endpoint): a sandbox send to a verified member went out from the fixed identity through the sandbox tenant and configuration set. The step's From name, From address and Reply-To were ignored with a log line. A non-member on CC and an unverified member were blocked with the clear message. A paused tenant state skipped sandbox sends while own-sender sends continued.
  • Shadow diff: an own-sender send produced the same SES request and the same stored message on master and on this stack.
  • Cross-version: a worker on master reports a sandbox send as sent without calling SES. See the deploy order in feat(workflows): provision a managed sandbox email sender #426's merge risk.
  • Checks at the tip (Node suites at 1a0fe3663c2; later fixes touch no Node code): Node CDP messaging, members and rate limiter suites (including email-tracking.service.test.ts, which now runs), the cdp-api suite, the Python sandbox, tenant, tier, reputation and validation suites, the frontend Jest suites of this stack, ruff, and the strict pre-push preflight: pass.
  • Gaps: real AWS SES delivery, clustered Valkey, and the production data shape (no production read access yet). Fork CI still fails during setup.

Rebased onto master 734468db6f9 (2026-10-19), head ccdbb0e2123.

  • Drift: Master now runs withDefaultEmailSender on template workflows after load (feat(workflows): open entry-point broadcasts and workflows ready to send PostHog/posthog#114807).
  • Adapted: Import merge. Both sender passes stay. The first-run pass runs first, and the default pass fills only steps that still have no sender, so it never overrides a sandbox choice or sends a second preselection event for the same step.
  • This layer: Jest for workflowLogic (first-run sender and autosave) and firstRun passes at the tip (below).
  • Gaps at modernize time: email-tracking.service.test.ts did not run then. It runs now; see the QA swarm block above. Fork CI still fails during setup, as noted below. Real AWS delivery and clustered Valkey remain unchecked.
Checks at the stack tip

Stack tip b9bd346ed0e (#456), shared by every layer:

  • Python, 354 passed: sandbox sender, sender validation, CDP validation, reputation, SES tenant state and events, sending tier.
  • Node CDP messaging, managers, and rate limiter: 17 suites, 599 passed.
  • Frontend Jest, 37 suites, 487 passed. Five suites timed out under host load in the batch run and passed when rerun alone.
  • Frontend tsgo: no errors. Node tsgo: no errors in CDP. The 23 errors it reports are all in session replay files that need the unbuilt Rust @posthog/replay-anonymizer module.
  • ruff, oxfmt, oxlint, prettier, eslint, product:lint (workflows, cdp), IDOR coverage, hogli build:openapi (no diff), and the strict pre-push preflight: pass.
  • Review: GPT-6.1 Sol read every conflict resolution in the stack and found no issues.
Observed targeted verification after QA fixes
workflowLogic.firstRunSender.test.ts: 17 passed
integrationsLogic.test.ts: 44 passed
Observed combined-stack gate
Node.js typecheck and build: exit 0
Frontend typecheck and build: exit 0
Success: no issues found in 23388 source files
product:lint workflows: All checks passed
ci:preflight --strict: failures 0

👉 Stay up-to-date with PostHog coding conventions for a smoother review.

Release status

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

Docs update

No existing document covers first-run sender assignment. The policy is described in Changes above; the sending-tiers document keeps its delivery scope.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Decisions

Question Answer Who Where
Prod-shape proofs before production read access Accepted as gaps until production read access on 2026-11-02 👤 Human decision comment
Save while an email step's sender is still resolving (R2-9) Hold the save with a reason. Alternative: save and drop the step with a toast, which never shows because the save replaces the route 🤖 Agent decision comment
Flag off: a template email with a custom From address and no integration Accepted deviation: it no longer receives the own default sender that master filled in, because the first-run check treats any From as configured. Rare state 🤖 Agent decision comment
One first-run preparation operation for the editor and templates (G5-4) Follow-up refactor. The round 1 fixes already removed the second sender pass 🤖 Agent decision comment
Pending markers on the tile canvas and tree dropzones (G5-7, G5-8) Follow-up. Insertion asks the user to wait in the meantime 🤖 Agent decision comment

Involvement: restack onto fork master 448d802 on 2026-10-23; round 1 with GPT-6.1 Sol lanes plus Claude Opus 5.5 fresh eyes for group G5; round 2 on the fix diff; final read 1 by GPT-6.1 Sol per group, with no findings; proofs captured; final read 2 by GPT-6.1 Sol on the round 4 decisions, with no findings; the round 4 live run and a UI walk of the two changed surfaces. Before that: the 2026-10-19 whole-stack QA swarm and the modernize rebase (see Earlier evidence). No review bots run on the fork.

Agent: Codex with GPT-6.1 Sol (gpt-6.1-sol) built the original layers, orchestrated by Claude Code with Claude Opus 5.5 (claude-opus-5-5). Restack, review fixes and this description refresh: Claude Opus 5.5 (claude-opus-5-5). Review: GPT-6.1 Sol (gpt-6.1-sol). Fresh eyes: Claude Opus 5.5 (claude-opus-5-5).

Skills: tdd, pr, writing-pr-descriptions, stacking-prs, merge-risk, writing-voice, writing-kea-logics, running-ci-preflight, qa-swarm, writing-user-facing-copy, and writing-tests. The description refresh used pr-description, writing-pr-descriptions, writing-voice and merge-risk.

The recreation preserves master's project default and sole verified sender behavior. Public source and invented fixtures only.

Two review rounds checked the increment and repairs. Final fixes also cancel stale editor completions and avoid provisioning for Reply-To-only templates.

🤖 Generated with Claude Code

@Silthus
Silthus added this pull request to stack #429 October 12, 2026 17:28
@Silthus Silthus self-assigned this Oct 12, 2026
@Silthus
Silthus force-pushed the workflows-sandbox/first-run-sender branch from 90dc9d4 to 8be6830 Compare October 12, 2026 23:16
@Silthus
Silthus force-pushed the workflows-sandbox/first-run-sender branch from 8be6830 to 522564b Compare October 12, 2026 23:53
@Silthus
Silthus force-pushed the workflows-sandbox/first-run-sender branch 2 times, most recently from 4f6e8cf to ccdbb0e Compare October 19, 2026 10:58
@Silthus
Silthus force-pushed the workflows-sandbox/first-run-sender branch from ccdbb0e to 9a7295a Compare October 19, 2026 13:11
@Silthus
Silthus force-pushed the workflows-sandbox/first-run-sender branch from 9a7295a to 2ece04e Compare October 19, 2026 13:36
@Silthus
Silthus force-pushed the workflows-sandbox/first-run-sender branch from 2ece04e to 8526330 Compare October 23, 2026 16:26
@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

🤖 CI report

⚠️ Complexity (TypeScript) — 17 functions above the limit (max 64)

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
onDrop products/workflows/frontend/Workflows/hogflows/hogFlowEditorLogic.tsx:2869 64 10
saveWorkflowSuccess products/workflows/frontend/Workflows/workflowLogic.ts:4482 42 10
runSave products/workflows/frontend/Workflows/workflowLogic.ts:3416 41 10
WorkflowActions products/workflows/frontend/Workflows/WorkflowActions.tsx:22 39 10
<anonymous> products/workflows/frontend/Workflows/workflowLogic.ts:3955 39 10
handleOauthCallback frontend/src/lib/integrations/integrationsLogic.ts:1434 27 10
StepView products/workflows/frontend/Workflows/hogflows/steps/components/StepView.tsx:22 26 10
HogFlowTreeStep products/workflows/frontend/Workflows/hogflows/tree/HogFlowTreeStep.tsx:17 25 10
HogFlowTreeDropzone products/workflows/frontend/Workflows/hogflows/tree/HogFlowTreeDropzone.tsx:15 20 10
fitView products/workflows/frontend/Workflows/hogflows/hogFlowEditorLogic.tsx:3152 15 10
getBranchLabel products/workflows/frontend/Workflows/hogflows/hogFlowEditorLogic.tsx:102 14 10
resolveFirstRunSender products/workflows/frontend/firstRun/firstRunSenderLogic.ts:115 13 10
submit products/workflows/frontend/Workflows/workflowLogic.ts:3607 12 10
<anonymous> products/workflows/frontend/Workflows/hogflows/hogFlowEditorLogic.tsx:2792 11 10
HogFlowEditorToolbarNode products/workflows/frontend/Workflows/hogflows/panel/HogFlowEditorPanelBuild.tsx:22 11 10
handleDrop products/workflows/frontend/Workflows/hogflows/tree/HogFlowTreeDropzone.tsx:57 11 10
loadWorkflowSuccess products/workflows/frontend/Workflows/workflowLogic.ts:4436 11 10
⚠️ Bundle size — 🔺 +5.4 KiB (+0.0%)

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

Total: 76.02 MiB · 🔺 +5.4 KiB (+0.0%)

File Size Δ vs base
render-query/src/render-query/render-query.js 24.65 MiB 🔺 +3.0 KiB (+0.0%)

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

⚠️ Eager graph — 2 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 · 24 files no change █████████░ 88.6% 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.94 MiB · 620 files 🔺 +119 B (+0.0%) ██████████ 96.9% of 3.03 MiB
🟡 authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
7.65 MiB · 2,633 files 🟢 -84 B (-0.0%) ██████████ 102.1% of 7.50 MiB
dashboard scene
src/scenes/dashboard/Dashboard.tsx
9.68 MiB · 3,703 files 🟢 -1.1 KiB (-0.0%) ██████████ 96.7% of 10.01 MiB
🟡 today home path
src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
8.06 MiB · 2,977 files 🟢 -84 B (-0.0%) ██████████ 104.2% 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.90 MiB · 2,706 files 🟢 -84 B (-0.0%) █████████░ 88.2% of 8.96 MiB
events scene
src/scenes/activity/explore/EventsScene.tsx
9.15 MiB · 3,495 files 🟢 -500 B (-0.0%) ██████████ 95.4% of 9.59 MiB
web analytics scene
src/scenes/web-analytics/WebAnalyticsScene.tsx
10.01 MiB · 3,713 files 🟢 -500 B (-0.0%) █████████░ 92.4% of 10.83 MiB
replay detail scene
src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
8.23 MiB · 3,075 files 🔺 +21 B (+0.0%) █████████░ 86.9% 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
🟢 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
🟢 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.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.4 KiB src/index.tsx
1.3 KiB src/RootErrorBoundary.tsx
1.3 KiB src/lib/utils/bootTiming.ts
912 B ../node_modules/.pnpm/ieee754@1.2.1/node_modules/ieee754/index.js
Largest files eagerly shipped from src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
Size File
321.9 KiB ../node_modules/.pnpm/posthog-js@1.438.18_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
220.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
106.3 KiB src/products.tsx
98.9 KiB src/lib/api.ts
69.4 KiB src/lib/lemon-ui/icons/icons.tsx
38.7 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
33.9 KiB ../node_modules/.pnpm/kea@4.0.0-pre.6_patch_hash=139b8d1f1304f9d9da452a9a1244c94ea679dbcb85687d8999563146879fb6f5_react@18.3.1/node_modules/kea/lib/index.cjs.js
29.4 KiB src/scenes/scenes.ts
27.0 KiB src/lib/constants.tsx
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
Size File
321.9 KiB ../node_modules/.pnpm/posthog-js@1.438.18_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.8 KiB src/taxonomy/core-filter-definitions-by-group.json
238.5 KiB ../packages/quill/packages/quill/dist/index.js
220.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.7 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
143.2 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
106.3 KiB src/products.tsx
98.9 KiB src/lib/api.ts
93.3 KiB ../node_modules/.pnpm/prosemirror-view@1.40.1/node_modules/prosemirror-view/dist/index.js
Largest files eagerly shipped from src/scenes/dashboard/Dashboard.tsx
Size File
321.9 KiB ../node_modules/.pnpm/posthog-js@1.438.18_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.8 KiB src/taxonomy/core-filter-definitions-by-group.json
238.5 KiB ../packages/quill/packages/quill/dist/index.js
220.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.7 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
143.2 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
106.3 KiB src/products.tsx
98.9 KiB src/lib/api.ts
93.3 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
321.9 KiB ../node_modules/.pnpm/posthog-js@1.438.18_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.8 KiB src/taxonomy/core-filter-definitions-by-group.json
238.5 KiB ../packages/quill/packages/quill/dist/index.js
220.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.7 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
143.2 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
106.3 KiB src/products.tsx
98.9 KiB src/lib/api.ts
93.3 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/ai-first/AiFirstHomepage.tsx
Size File
321.9 KiB ../node_modules/.pnpm/posthog-js@1.438.18_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.8 KiB src/taxonomy/core-filter-definitions-by-group.json
238.5 KiB ../packages/quill/packages/quill/dist/index.js
220.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.7 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
143.2 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
106.3 KiB src/products.tsx
98.9 KiB src/lib/api.ts
93.3 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
321.9 KiB ../node_modules/.pnpm/posthog-js@1.438.18_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.8 KiB src/taxonomy/core-filter-definitions-by-group.json
238.5 KiB ../packages/quill/packages/quill/dist/index.js
220.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.7 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
143.2 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
106.3 KiB src/products.tsx
98.9 KiB src/lib/api.ts
93.3 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
321.9 KiB ../node_modules/.pnpm/posthog-js@1.438.18_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs
286.8 KiB src/taxonomy/core-filter-definitions-by-group.json
238.5 KiB ../packages/quill/packages/quill/dist/index.js
220.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
183.2 KiB src/queries/validators.js
153.7 KiB ../node_modules/.pnpm/re2js@0.4.1/node_modules/re2js/build/index.esm.js
143.2 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
106.3 KiB src/products.tsx
98.9 KiB src/lib/api.ts
Largest files eagerly shipped from src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
Size File
321.9 KiB ../node_modules/.pnpm/posthog-js@1.438.18_@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.18_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js
286.8 KiB src/taxonomy/core-filter-definitions-by-group.json
238.5 KiB ../packages/quill/packages/quill/dist/index.js
220.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.7 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.3 KiB src/products.tsx
98.9 KiB src/lib/api.ts
93.3 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 ████░░░░░░ 39.9% 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
899.4 KiB dist/toolbar/toolbar-app-FHAKV2CJ.css
691.5 KiB dist/toolbar/chunk-chunk-P2Q5W6MF.js
260.7 KiB dist/toolbar/chunk-chunk-HRRIOF34.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
130.4 KiB dist/toolbar/chunk-chunk-56VOFFKM.js
74.8 KiB dist/toolbar/toolbar-app-Y5KIAIV6.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
35.6 KiB dist/toolbar/chunk-chunk-3KUCHJRN.js
21.7 KiB dist/toolbar/chunk-chunk-PKO5KPTA.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 — 🔺 +95.0 KiB (+0.0%)

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

Total: 1020.90 MiB · 🔺 +95.0 KiB (+0.0%)

@Silthus
Silthus force-pushed the workflows-sandbox/first-run-sender branch from 8526330 to 5d9f05a Compare October 24, 2026 13:12
@Silthus

Silthus commented Oct 24, 2026

Copy link
Copy Markdown
Owner Author

Note

🤖 Claude Opus 5.5 responding on behalf of Michael

Decision lines for this PR. The Decisions table in the description links each row here.

  • 👤 Prod-shape proofs before production read access Accepted as gaps until production read access on 2026-11-02.
  • 🤖 Save while an email step's sender is still resolving (R2-9) Hold the save with a reason. Alternative: save and drop the step with a toast, which never shows because the save replaces the route
  • 🤖 Flag off: a template email with a custom From address and no integration Accepted deviation: it no longer receives the own default sender that master filled in, because the first-run check treats any From as configured. Rare state
  • 🤖 One first-run preparation operation for the editor and templates (G5-4) Follow-up refactor. The round 1 fixes already removed the second sender pass
  • 🤖 Pending markers on the tile canvas and tree dropzones (G5-7, G5-8) Follow-up. Insertion asks the user to wait in the meantime

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

Silthus commented Oct 27, 2026

Copy link
Copy Markdown
Owner Author

Replaced by the re-sliced fork stack: #622 and #623. Tracked in Silthus/personal#71.

@Silthus Silthus closed this Oct 27, 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