Skip to content

标量 config.timeRelative(如 timeRelative: 'daily')= 引擎解析不出任何 trigger,flow 永不触发且全层零输出 #5647

Description

@os-zhuang

发现于 #5496(time-relative 描述符 authoring 期校验)的实测。属 PD #10 的范围外发现,#5496 内刻意不修(见下「为什么不在 #5496 里修」),交 PM 定级。

事实(实测,非推断)

config.timeRelative 写成非对象标量时,引擎解析不出任何 trigger,flow 绑不上任何东西、永不触发,而且每一层都零输出

复现的 flow(除描述符外一切合规:对象存在、status: 'active'runAs: 'system'):

{
  name: 'scalar_time_relative',
  type: 'autolaunched',
  status: 'active',
  runAs: 'system',
  nodes: [
    { id: 'start', type: 'start', config: { timeRelative: 'daily' } },
    { id: 'end', type: 'end' },
  ],
  edges: [{ id: 'e1', source: 'start', target: 'end' }],
}

实测两条 flow lint 的输出:

validateFlowTriggerReadiness = []
lintFlowPatterns             = []

原因链,逐环:

  1. AutomationEngine.resolveTriggerBinding(packages/services/service-automation/src/engine.ts:1517)的路由判据是
    config.timeRelative != null && typeof config.timeRelative === 'object' —— 标量不满足,不路由到 time_relative
  2. 继续下落:config.schedule != null || flow.type === 'schedule' 不成立(autolaunched、无 schedule),flow.type === 'api' || triggerType === 'api' 不成立 → 函数 return undefined(engine.ts:1554)。
  3. activateFlowTriggerif (!resolved) return;(engine.ts:1564)—— 静默返回,连 warn 都没有。对比:描述符是对象时至少有 TimeRelativeTrigger.start() 的 bind 期 warn。
  4. authoring 期同样沉默:validate-flow-trigger-readiness.tsisTimeRelative 也要求 typeof === 'object'(与引擎一致),所以 §1b 两条规则都不看它;更关键的是 isAutoTriggered 因此为 false,连 flow-draft-status-ambiguous 都不报。lint-flow-patterns.ts:254startCfg.timeRelative != null 倒是命中,但那条规则只在 runAs 未提权时才出诊断,本例 runAs: 'system' 已合规,故也沉默。

所以标量描述符比对象描述符更静默:后者至少有一行服务器日志 warn(这正是 #5496 修掉的 authoring 期缺口),前者连那行都没有。

#3481 的同构

这与 validate-flow-trigger-readiness.ts §1d 存在的理由(#3481)完全同构,只是换了一个键:非字符串 triggerType 折叠成「无 trigger」→ flow 被当作 manual → 零输出。该文件的 §1d 注释原话:「a non-string triggerType folds to "no trigger"… so it binds to nothing and never fires, with zero output at any layer」。把 triggerType 换成 timeRelative、把「非字符串」换成「非对象」,就是本条。#3481 当时被判定为值得单开一条规则。

为什么不在 #5496 里修

#5496 落地的规则(PR 见该单)判据刻意与引擎的路由判据逐字一致(!= null && typeof === 'object'),这样规则只为「引擎真正交给 time-relative trigger 的那些 flow」发言。要覆盖标量就得放宽 isTimeRelative,而该变量同时喂 §1b 的 unknown-object 规则和 isAutoTriggered(draft-status 规则)—— 放宽会改变另外两条已发布规则的覆盖面,超出 #5496 的范围。故单开。

建议方向(供 PM 定级,不预设结论)

  1. validate-flow-trigger-readiness.ts 新增一条判据:config.timeRelative != null && typeof !== 'object' → 报「这个槽要求描述符对象,标量不会被路由到任何 trigger,flow 永不触发」。不动 isTimeRelative,新增独立判据,避免波及另两条规则。规则 id 可复用 timeRelative 描述符跑不通时 authoring 期零诊断 —— 两条 flow lint 一条只看非空、一条只看对象名(#4966 建议 2) #5496 的族前缀风格(flow-time-relative-descriptor-invalid,或另起一条点明「不是对象」)。
  2. 同时补 isAutoTriggered:让标量 timeRelative 也算「作者意图自动触发」,这样 draft-status 规则也能覆盖。需评估对现有 flow 的诊断增量。
  3. 什么都不做:标量拼法罕见,且 未知键静默剥离仍是全仓默认:把 #3405 的 strict 收紧从一个 schema 推广到整个可授权面(ADR-0078 完整性闸门) #4001 收紧后描述符对象内部的键已有保护。

倾向 1 的理由在「让 AI 写的元数据难以写错」这一轴上:AI 作者把 cadence 概念和描述符概念混淆时,timeRelative: 'daily' 是一个很自然的错写,而它当前的反馈是绝对静默——比 #5496 修掉的那个缺口还差一档。同时这不引入任何消费端宽容(PD #12):不接受标量、不做 coercion,只是把「引擎解析不出 trigger」这件已经确定的事提前到 authoring 期报出来。

关联:#5496(本条的来源)、#3481(同构先例)、#5482(同族:节点 config 里已能判定、authoring 期无人报警)、ADR-0018(node config 开放槽)。

Blocked-by: #5496


Generated by Claude Code

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions