Skip to content

feat(workflows): enable waits for an unverified sender and goes live once it verifies - #590

Draft
Silthus wants to merge 10 commits into
t3/workflows-sender-verification-refreshfrom
wf71/sov-v1-waiting-go-live
Draft

Silthus wants to merge 10 commits into
t3/workflows-sender-verification-refreshfrom
wf71/sov-v1-waiting-go-live

Conversation

@Silthus

@Silthus Silthus commented Oct 27, 2026 •

Copy link
Copy Markdown
Owner

Problem

A project whose email domain is still verifying cannot turn on a workflow that sends from it and have it start on its own once the domain verifies. Today Enable either goes live with an unverified sender or the person has to come back later and turn it on.

This is the first slice of "send once verified" (Silthus/personal#195): an agent or API caller can already see and rely on it, before any UI exists.

Impact: pays into workflow activation. It adds the event for a waiting workflow that went live after verification (hog_flow_activated with activated_by: domain_verified). The event for a workflow turned on while it waits follows in the next slice.

Caution

🔴 Merge risk: high · one-way door (merge-risk rubric)

  • Adds migration 0039 on HogFlow and a new waiting_for_domain status in the API and MCP contract. Waiting workflows go live by themselves and send real email once their domain verifies.
  • Limits: the sender check on Enable runs only with workflows-email-domain-wizard on. Flag off, Enable behaves as on master. Node loads only status='active' flows, so a waiting workflow never runs.
  • Lands after feat(workflows): let the node hog flow type hold a waiting for domain status #617, which carries this PR's one nodejs/ line (hogflow.ts status enum) so upstream's lane check passes. Once feat(workflows): let the node hog flow type hold a waiting for domain status #617 merges, this diff against master has no nodejs/ change.
  • This PR lands together with the next two slices in one merge-queue batch. Alone, it has no cohort delete guard or search for waiting workflows, and no protection for an edit that meets a go-live.

Changes

  • Enable can wait. With the flag on, PATCH status=active or a create as active saves waiting_for_domain when an email step sends from an unverified sender. A rotation waits for any unverified member. MCP workflows-enable PATCHes, so it returns the same status.
  • Go-live on verification. EmailIntegration.apply_verification queues enable_waiting_workflows_task on commit. The task takes each waiting workflow live once none of its senders is unverified, and ignores the flag.
  • Event per workflow. The task sends hog_flow_activated (activated_by: domain_verified) right after each workflow goes live, credited to the person who enabled it. A retry after a later failure cannot drop it.
  • New read-only fields: enable_requested_at, went_live_at. enable_requested_by is stored for event credit.
  • Edits to a waiting workflow. The edit validates as an activation and saves in place. It goes live at once when its senders are now all verified (PATCH, /graph, the email edit, and publish).
  • Activation event from a person. Every change from not active to active by a person sends hog_flow_activated (activated_by: user), so enabling an archived workflow counts too.
  • Archived workflows. Enabling an archived workflow follows the enable rule, like a draft: it goes active, or waiting_for_domain with an unverified sender. Before, it returned 200 and stayed archived.
  • Refusals. A client cannot send waiting_for_domain itself (400).
  • Integration delete guard. An email sender used by a waiting workflow cannot be deleted. The message now says "enabled workflows".
  • Reload first. Workers reload the verified senders before the go-live is queued. When that reload fails, the go-live waits six minutes, past the workers' five-minute integration cache. So no workflow goes live while a worker still holds its sender as unverified.
  • A broker or task failure never fails the verification: it logs and counts workflows_enable_waiting_failed_total, and the workflow keeps waiting.
  • Mechanical: generated API and MCP types, the Node HogFlowSchema status enum (type only), raw_id_fields for the new FK in admin.
flowchart LR
    A[Enable: PATCH status=active] --> B{flag on and a sender unverified?}
    B -- no --> C[active]
    B -- yes --> D[waiting_for_domain]
    E[apply_verification] -- reload workers --> R{reload sent?}
    R -- yes --> F[enable_waiting_workflows_task]
    R -- no: wait past the worker cache --> F
    F --> G{senders all verified?}
    G -- yes --> C
    G -- no --> D
    classDef ph fill:#1d4aff,color:#fff,stroke:#1d4aff
    classDef wait fill:#f7a501,color:#000,stroke:#f7a501
    class C ph
    class D wait
Loading

Production lines: 474 (+439 −35) against the base, by git diff --numstat. Tests, generated types and the migration are excluded. This is over the 400-line budget because the review fixes (edit go-live, its activation event, the integration delete guard, the archived enable and the reload wait) belong with the behavior they protect.

Replaces part of PostHog#123660 (the send once verified core). The rest of that PR follows in the next slices.

How did you test this code?

  • Lane gate on HEAD: ruff lint and format, hogli ci:preflight --strict (pre-push, no failures). The suites of every touched module ran: products/workflows/backend (all passed), and the targeted send once verified, posthog/api/test/test_integration.py and posthog/models/integration suites (all passed). Repo-wide mypy is clean on the stacked slice above, which contains this HEAD.
  • CI: fork CI cannot run here, so CI on HEAD is a recorded gap.
  • Red → green: the new tests failed on the base tree and pass on HEAD (evidence in proof storage).

Live run (on 6bc8eef8217; eb0db58e39d reuses it, see Proofs). A dev server, a real Celery worker and the local MCP server ran from this branch, on a private database and Redis.

  • Enable through the REST API and through MCP workflows-enable, with an unverified sender: the workflow saves waiting_for_domain. The CDP trigger loader's own query (status='active') does not return it.
  • POST …/integrations/<id>/email/verify: the worker takes the workflow active, sets went_live_at, and the loader query returns it.
  • With a verified sender, Enable goes active at once. A client sending waiting_for_domain gets a 400. ?status=waiting_for_domain lists the waiting workflow.
  • Rows the base code wrote, migrated to 0039 afterwards, behave the same.
  • Simulated: SES. The unverified senders use the dev maildev provider with verified: false, the state an SES sender has before its DNS checks pass. The flag is stubbed on at posthoganalytics.feature_enabled, the seam the API tests patch.

Shadow diff (base 287950a29f1, this PR's base). The same 20 requests went to a base server and a HEAD server with identical seeded rows: create, rename, enable, re-enable, live and draft edits, MCP graph edit, publish, disable, archive and enable, create as active with a verified sender and a verified rotation, and lists. Responses, saved workflows, versions and revisions match the base. The only differences are the fields this PR adds (enable_requested_at, went_live_at, enable_requested_by_id). The first run found the archived enable no-op above; it is fixed test-first.

Test rationale:

  • TestHogFlowSendOnceVerified (API level, test_hog_flow.py): Enable saves the status its senders and the flag allow, a rotation waits, re-enable after verification activates once, create-as-active waits, a client cannot set waiting_for_domain, an archived workflow follows the enable rule and sends the activation event only when it goes live, a failing edit is refused, and an edit or publish to a verified sender takes it live with one activation event. No existing test covers the enable rule. The API level is the contract agents use.
  • TestVerifiedSenderTakesWaitingWorkflowsLive (test_email_sender_verification.py): verification takes waiting workflows live with or without the flag. A second unverified sender keeps it waiting, and a workflow turned off first stays off. A broker failure keeps the verification. A failed last retry is logged and counted. A partial batch keeps the events of the workflows already live. Senders reload on workers before the go-live is queued, and a failed reload queues it past the worker cache. A lookup failure after go-live does not retry the task. These go through apply_verification and the Celery task, the seam the go-live runs on.

Test seams: the HogFlow REST API, EmailIntegration.apply_verification, and enable_waiting_workflows_task.

Proofs (per qa-swarm PROOF.md):

Proof State
Review GPT-6.1 Sol. Round 1: 4 findings, fixed in b81b27d61fb. Final reads: the missing activation event on edits (fixed in 214c842217e), the missing publish test (added in 8c40e5f1573), then three reads with no findings. Round 2 on the archived enable fix: a go-live after a failed worker reload, and no activation event for archived to active, both fixed in eb0db58e39d. Final read of eb0db58e39d: no findings. Each fix has a red-first test
Live run passed on 6bc8eef8217 (above); reused for eb0db58e39d, which changes only the countdown after a failed reload and a usage event
Shadow diff passed on 6bc8eef8217 (above); reused for eb0db58e39d, which changes no response or saved field
Prod shape gap: read-only production access arrives later; accepted by a standing rule until then
CI gap: fork CI cannot run
Post-deploy watch owed after merge

Decisions

Question Answer Who Where
What does the flag gate? Only the sender check on Enable; go-live never checks it 👍 Silthus/personal#195
How do the first slices land? This slice and the next two in one merge-queue batch 🤖 Silthus/personal#195
What moves out of this slice to stay near 400 lines? The enable-requested and waiting-cancelled events, wait times, and the canvas enable path; all go to the next slice 🤖 Silthus/personal#195
Fix the lost go-live events on a partial-batch retry now or in the race-fix slice? Now: it is a bug in code this slice adds 🤖 Silthus/personal#195
Keep the review fixes here although the slice goes over 400 lines? Yes: without them a waiting workflow can lose its sender or never go live after an edit 🤖 Silthus/personal#195
What does Enable do to an archived workflow? It follows the enable rule, like a draft, instead of leaving it archived 🤖 Silthus/personal#195
When does a person's change send hog_flow_activated? On every change from not active to active, archived included 🤖 Silthus/personal#195
What happens when the worker reload fails? The go-live waits six minutes, past the worker cache, instead of going at once 🤖 Silthus/personal#195
What is the shadow diff's base? This PR's base, so the diff shows only this slice 🤖 Silthus/personal#195

Involvement: no grilling rounds; reviews by GPT-6.1 Sol (2 rounds, 6 final reads); live run and shadow diff captured.

Release status

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

Docs update

None. The behavior is behind a flag and has no user docs yet.

🤖 Agent context

Autonomy: Human-driven (agent-assisted)

Agent: Claude Code, Claude Opus 5.5 (implementation); GPT-6.1 Sol (review)

🤖 Generated with Claude Code

Silthus and others added 3 commits October 27, 2026 05:17
…once it verifies

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…once it verifies

Behind workflows-email-domain-wizard, turning on a workflow whose email sender
is not verified saves waiting_for_domain instead of active. When the domain
verifies, a background task takes each waiting workflow live and sends
hog_flow_activated with activated_by domain_verified. Go-live never checks the
flag. Adds enable_requested_at, enable_requested_by and went_live_at to
HogFlow (migration 0039).

Refs Silthus/personal#195

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

enable_waiting yields each workflow as it commits, after its timing sweep, and
the task sends that workflow's activation event before it moves on. A retry
skips workflows that are live already, so their events can no longer be lost
when a later workflow raises.

Refs Silthus/personal#195

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Silthus Silthus self-assigned this Oct 27, 2026
@github-actions

github-actions Bot commented Oct 27, 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.

✅ Comment density — 3% of added code lines are comments (23 of 797)

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
products/workflows/backend/models/hog_flow/hog_flow.py 5 16
products/workflows/backend/tasks/waiting_workflows.py 5 77
products/workflows/backend/presentation/views/hog_flow.py 3 52
products/workflows/backend/services/hog_flow_writes.py 3 133
products/workflows/backend/facade/enums.py 2 4
posthog/models/integration/email.py 1 13
products/workflows/backend/facade/api.py 1 9
products/workflows/backend/facade/contracts.py 1 18

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

✅ Bundle size — no change

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

Total: 76.88 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
1022.4 KiB · 24 files no change █████████░ 87.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.96 MiB · 620 files no change ██████████ 97.7% of 3.03 MiB
authenticated shell (every logged-in page)
src/scenes/AuthenticatedShell.tsx
7.47 MiB · 2,557 files no change ██████████ 99.7% of 7.50 MiB
dashboard scene
src/scenes/dashboard/Dashboard.tsx
9.92 MiB · 3,725 files no change ██████████ 99.1% 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.65 MiB · 2,649 files no change ██████████ 98.8% 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.89 MiB · 2,641 files no change ██████████ 99.8% of 7.91 MiB
events scene
src/scenes/activity/explore/EventsScene.tsx
9.37 MiB · 3,508 files no change ██████████ 97.7% of 9.59 MiB
web analytics scene
src/scenes/web-analytics/WebAnalyticsScene.tsx
10.30 MiB · 3,755 files no change ██████████ 95.1% of 10.83 MiB
replay detail scene
src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
8.40 MiB · 3,086 files no change █████████░ 88.7% 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/lib/utils/bootTiming.ts
1.6 KiB src/index.tsx
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.9 KiB ../node_modules/.pnpm/posthog-js@1.438.23_@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
100.8 KiB src/products.tsx
86.1 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.9 KiB ../node_modules/.pnpm/posthog-js@1.438.23_@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
100.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.1 KiB src/lib/api.ts
Largest files eagerly shipped from src/scenes/dashboard/Dashboard.tsx
Size File
322.9 KiB ../node_modules/.pnpm/posthog-js@1.438.23_@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
100.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.9 KiB ../node_modules/.pnpm/posthog-js@1.438.23_@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
100.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.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
322.9 KiB ../node_modules/.pnpm/posthog-js@1.438.23_@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
100.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.9 KiB ../node_modules/.pnpm/posthog-js@1.438.23_@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
100.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.9 KiB ../node_modules/.pnpm/posthog-js@1.438.23_@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
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
100.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.9 KiB ../node_modules/.pnpm/posthog-js@1.438.23_@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.23_@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
100.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.1% 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
904.9 KiB dist/toolbar/toolbar-app-PJL3ZOG5.css
694.7 KiB dist/toolbar/chunk-chunk-S67E62V7.js
259.9 KiB dist/toolbar/chunk-chunk-LBUEMA4R.js
131.8 KiB dist/toolbar/chunk-chunk-FDH2IBXT.js
130.4 KiB dist/toolbar/chunk-chunk-RZCYPLTY.js
74.8 KiB dist/toolbar/toolbar-app-U2PZEED2.js
69.0 KiB dist/toolbar/chunk-chunk-TSAL54PB.js
35.6 KiB dist/toolbar/chunk-chunk-3Y7AY6NT.js
21.7 KiB dist/toolbar/chunk-chunk-WUPVVGIN.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 — 🔺 +6.4 KiB (+0.0%)

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

Total: 968.92 MiB · 🔺 +6.4 KiB (+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

Silthus and others added 4 commits October 27, 2026 05:49
… broken

- Verification reloads the senders on workers before it queues the go-live, so
  a workflow never goes live while workers still hold its sender as unverified.
- A lookup failure while sending the go-live event no longer retries the task,
  which would skip the workflow that is live already and drop its event.
- An edit to a waiting workflow checks its senders again, so switching to a
  verified sender takes it live.
- The integration delete guard counts waiting workflows, so a sender a waiting
  workflow uses cannot be deleted before the workflow goes live.

Refs Silthus/personal#195

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

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ing workflow live

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Silthus and others added 3 commits October 27, 2026 06:33
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Enabling an archived workflow through the API or MCP returned 200 and left it
archived, while the base enabled it. It now waits for an unverified sender or
goes live, like enabling a draft.

Refs Silthus/personal#195

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When the reload of verified senders on the workers failed, waiting workflows
still went live at once, while workers could hold the sender as unverified for
up to five minutes and fail its sends. The go-live now waits past that cache.
Enabling an archived workflow now also reports hog_flow_activated, like a draft.

Refs Silthus/personal#195

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

This branch has not been deployed

No deployments
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