Skip to content

fix(automation): array-form flow triggerType fails loudly, not silently never firing (#3481)#3484

Merged
os-zhuang merged 1 commit into
mainfrom
fix/3481-array-triggertype-silent
Jul 25, 2026
Merged

fix(automation): array-form flow triggerType fails loudly, not silently never firing (#3481)#3484
os-zhuang merged 1 commit into
mainfrom
fix/3481-array-triggertype-silent

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes #3481.

Problem

An array triggerType on a flow start node — the shape an author (or an AI authoring pass) naturally reaches for to fire on more than one event:

config: { objectName: 'app_task', triggerType: ['record-after-create', 'record-after-delete'] }

was accepted everywhere and armed nowhere. Multi-event unions are deliberately unsupported (only the single tokens plus the record-after-write create-OR-update union exist — see #3457), but nothing said so:

  1. spec — start-node config is an open z.record, so defineFlow passes the array.
  2. engineresolveTriggerBinding's typeof config.triggerType === 'string' check folds the array to undefined → the flow is misclassified as manual.
  3. binding auditgetTriggerBindingAudit skips flows with no resolved trigger, so it never appears in the CLI startup summary.
  4. lintvalidate-flow-trigger-readiness used the same typeof narrowing → isRecordTriggered false → zero findings.

Net result: the flow binds to nothing and never fires, with zero output at any layer — the same silent-never-fire class as #3427 / #3472, and the last authoring shape still slipping past every guard.

Fix (defensive — arrays stay unsupported, they now fail loudly)

Contract-first (AGENTS.md Prime Directive #12): reject at authoring, don't add a consumer-side tolerance for the unsupported shape.

  • lint (validate-flow-trigger-readiness): an array triggerType containing any record-* element now yields a flow-trigger-unknown-event warning at os validate time, steering to record-after-write (created-or-updated) or one flow per event.
  • engine (resolveTriggerBinding): such an array is routed to the record_change trigger — exactly as an unmappable single token (record-after-updated) already is — instead of folding to a manual flow, so it reaches the trigger's bind-time rejection.
  • trigger (record-change): the bind-time rejection detects the array shape and emits a targeted warning (names the flow, points at record-after-write and flow record trigger: consider multi-event triggerType (array / unions beyond create-or-update) #3457) rather than the generic unknown-token line.

Scope is intentionally narrow: no new authoring form, no array semantics — that stays deferred under #3457. This only makes the unsupported shape loud.

Tests

Each new test proves red against the pre-fix code first, then green:

  • packages/lint/src/validate-flow-trigger-readiness.test.ts — array flagged (incl. arrays of individually-valid tokens); non-record array left alone.
  • packages/services/service-automation/src/trigger-dispatch-observability.test.ts — array routed to record_change (binding handed to the trigger, appears in getActiveTriggerBindings); non-record array stays manual.
  • packages/triggers/trigger-record-change/src/record-change-trigger.test.ts — targeted array warning, not bound; generic warning preserved for non-array bad tokens.

Full suites green: lint 326, service-automation 356, trigger-record-change 49. DTS type-check clean for all three packages.

Refs #3457 (the deferred multi-event design + restart criteria), #3427 / #3446 (record-after-write), #3472 (same-family silent defect).

🤖 Generated with Claude Code

…ly never firing (#3481)

An array `triggerType` on a flow start node (e.g. ['record-after-create',
'record-after-delete']) — the shape an author or AI authoring pass naturally
reaches for to fire on multiple events — was accepted everywhere and armed
nowhere. Multi-event unions are deliberately unsupported (#3457), but nothing
said so: defineFlow passed the array, the engine's `typeof === 'string'` check
folded it to no trigger and misclassified the flow as manual (so it never
entered the binding audit), and the flow-trigger-readiness lint used the same
narrowing and produced no finding. The flow bound to nothing and never fired,
with zero output at any layer — the last authoring shape still slipping past
the #3427/#3472 silent-never-fire guards.

Defensive fix (arrays stay unsupported; they now fail loudly):

- lint (validate-flow-trigger-readiness): an array triggerType with any
  record-* element yields a flow-trigger-unknown-event warning at os validate
  time, steering to record-after-write or one flow per event.
- engine (resolveTriggerBinding): route such an array to the record_change
  trigger — as an unmappable single token is — instead of folding to a manual
  flow, so it reaches the trigger's bind-time rejection and the binding audit.
- trigger (record-change): the bind-time rejection detects the array shape and
  emits a targeted warning (names the flow, points at record-after-write and
  #3457) rather than the generic unknown-token line.

Each new test proves red against the pre-fix code first.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 25, 2026 2:45am

Request Review

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Jul 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/lint, packages/services, packages/triggers.

7 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/automation/webhooks.mdx (via packages/services)
  • content/docs/kernel/runtime-services/audit-service.mdx (via packages/services)
  • content/docs/kernel/runtime-services/index.mdx (via packages/services)
  • content/docs/kernel/runtime-services/settings-service.mdx (via packages/services)
  • content/docs/permissions/authorization.mdx (via @objectstack/lint)
  • content/docs/plugins/packages.mdx (via packages/services)
  • content/docs/protocol/kernel/i18n-standard.mdx (via packages/services)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang merged commit 9dcc0ae into main Jul 25, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the fix/3481-array-triggertype-silent branch July 25, 2026 02:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

flow record trigger: array-form triggerType is silently dead at every layer (no lint, no audit, no runtime warn)

1 participant