fix(deployment): prevent trigger registry initialization crash (#6342)

* fix(deployment): initialize block registry before triggers

* fix(triggers): break the triggers <-> blocks initialization cycle

Replaces the import-order guard from the previous commit with the structural fix.

Block configs spread `getTrigger('...').subBlocks` while their module body runs, so
`blocks/*` depends on `triggers/*` by design. Thirteen edges closed the loop back the
other way, which made module evaluation order load-bearing: enter the graph through
`@/triggers` and a block config calls `getTrigger()` before `TRIGGER_REGISTRY` is
initialized, throwing

  ReferenceError: Cannot access 'TRIGGER_REGISTRY' before initialization

Eleven deployment routes crashed on import: `POST /api/workflows/[id]/deploy`, the v1
public and admin deploy/rollback/activate routes, both deployment-version routes, and
the three custom-tool deployment routes. All of them funnel through
`lib/webhooks/deploy.ts`, which stayed safe only because it imported a value from
`@/blocks` — biome sorts that above `@/triggers`, so the safe barrel always evaluated
first. #6272 deleted that import as unused cleanup and took the whole surface with it.

The reverse edges came from two places, both layering violations rather than anything
inherent to triggers:

- `triggers/index.ts` imported the mock-payload generator from `trigger-utils`, which
  imports `@/blocks` for unrelated helpers. The generator is pure, so it moves to
  `lib/workflows/triggers/mock-payload.ts` and both callers import it there.
- Eleven trigger modules statically imported the editor's Zustand stores to read
  sub-block values inside `fetchOptions`/`fetchOptionById`. Those reads now go through
  `triggers/editor-state.ts`, which loads the stores with a dynamic `import()` —
  resolved when the resolver is called, not during module evaluation, so it carries no
  initialization-order obligation.

Side effect: `@/triggers` drops from 744 statically reachable modules to 526. The block
registry, the workflow Zustand stores and their React Query graph are no longer pulled
into every server module that imports a trigger.

`scripts/check-trigger-block-cycle.ts` fails the build if a static edge returns, and
reports the shortest offending chain. The existing suite could not have caught this —
`deploy.test.ts` mocks both `@/blocks/registry` and `@/triggers`, and `vitest.setup.ts`
mocks `@/blocks/registry` globally, so it passed 18/18 against the broken code.

---------

Co-authored-by: Bill Leoutsakos <billleoutsakos@Bills-MacBook-Pro.local>
Co-authored-by: Waleed Latif <walif6@gmail.com>
This commit is contained in:
Bill Leoutsakos
2026-08-06 15:02:37 -07:00
committed by GitHub
co-authored by Bill Leoutsakos Waleed Latif
parent a4973ec576
commit b04fee8aa7
18 changed files with 391 additions and 196 deletions
+3
View File
@@ -159,6 +159,9 @@ jobs:
- name: Tool request transport boundary audit
run: bun run check:tool-request-boundary
- name: Trigger/block initialization cycle audit
run: bun run check:trigger-block-cycle
- name: SQL Date binding audit
run: bun run check:sql-date-binding