From cf7a499907d6d8b967c5aaba8a45f09fff67f871 Mon Sep 17 00:00:00 2001 From: Aaron Scott Date: Wed, 2 Sep 2026 21:06:23 -0400 Subject: [PATCH] perf(worker): the signing workflow stops dragging Zod into every cold start MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Startup module graph: 843.7 KiB → 410.6 KiB across 54 → 42 modules, a 51% cut, from moving one import. Zod and @hono/zod-openapi leave the startup path entirely. A Workflow class must be EXPORTED FROM THE WORKER ENTRY for the runtime to bind it, so every module it imports statically is evaluated on every cold start. `SignCompletionWorkflow` imported the tenant email builder, which reaches the branding service, which reaches `@hono/zod-openapi` — and with it 261 KiB of Zod. A third of the worker's startup cost was validation code built for an API request that had not arrived, paid by every request that is not a signing workflow. The API itself was already lazy (`getApi()` in workers/app.ts) — that boundary was deliberate and it held. Zod was not crossing it; it was riding in beside it, through an export the runtime requires. The import moves inside the step that uses it. The class still extends WorkflowEntrypoint and is still exported eagerly, so the runtime contract is untouched — only the subtree behind it became lazy. That is deliberately the smaller change: stubbing the class the way `InspectorMcp` is stubbed would also work for the graph, but a Workflow's binding contract is not something to guess at when the failure mode is silent. Measured, not inferred: walk the STATIC imports of build/server/index.js transitively. A chunking fix (manualChunks splitting hono/zod/openapi) was tried first and REJECTED — it moved the weight between chunks and measured 843.7 → 857.3 KiB, slightly worse. The path mattered, not the packing. Diminishing returns from here: what remains is flat, topped by results-doc (85 KiB, needed by the collab Durable Object, also an entry export). Verified: 62/62 gates, both type-checks, 8,201 API + 170 workers tests, bundle 69.2% of the Free limit. Co-Authored-By: Claude Opus 5 --- server/workflows/sign-completion-workflow.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/server/workflows/sign-completion-workflow.ts b/server/workflows/sign-completion-workflow.ts index 3f9a32d5..99a825fc 100644 --- a/server/workflows/sign-completion-workflow.ts +++ b/server/workflows/sign-completion-workflow.ts @@ -6,7 +6,6 @@ import { AuditLogService } from '../services/audit-log.service'; import { m2mAgreementRenderUrl } from '../lib/public-urls'; import { envelopeVerifyUrl } from '../lib/agreement-verify-url'; import { buildEvidencePack } from '../services/evidence-pack.service'; -import { buildTenantEmailService } from '../lib/email/build-email-service'; import { getDeploymentProfile } from '../lib/deployment-profile'; import { PlanQuotaGuard, readTenantTier } from '../features/plan-quota/guard'; import { tenantAiCapsLoader } from '../features/plan-quota/ai-caps'; @@ -273,6 +272,19 @@ export class SignCompletionWorkflow extends WorkflowEntrypoint