Skip to content

[finding] service-automation: a subflow child that ends refused is rolled up by the parent as an ordinary success — the refusal reaches nobody #18110

Description

@claude

Reported by the domain:services dev that delivered #15788 (lane 2 of the #14945 ruling 2′) as an out-of-scope finding, and filed here by the seat — dev agents report findings with dedupe words; they ⛔ do not file.

Mechanism

packages/services/service-automation/src/builtin/subflow-node.ts branches only on child.status === 'paused'. Every other child status falls through the same success path, so a child run recorded refused returns success: true and the parent walks straight down the subflow node's out-edges.

⇒ An author who writes a refusing end inside a subflow gets the opposite of what the refusal means at the parent level: the parent continues as though the child said yes.

Why it is filed now, and why it is ⛔ NOT a regression of #15788

Before #15788's delivery nothing could write refused at all, so the parent's behaviour was identical (a refusing child merely completed, and the parent continued). ⛔ PR #18109 does not change subflow-node.ts and does not make any existing flow behave differently.

What changed is reachability: the end executor now produces refused, so this path becomes live the moment authors start writing refusals — which is exactly what lane 2 was ruled in to enable. ⚠️ The #14945 ruling says nothing about subflow rollup, so this is ⛔ not a shortfall in that ruling and ⛔ not something #18109 should have ridden in.

Relationship to the sibling card

⚠️ #16314 is the INVERSE direction and is a different card: it is about subflow and map rolling a child's contained failures into the parent's failed through the ExecutionStepMetrics failure slot. This card is about a refused child rolling up as success — the refusal reaching nobody. Same file, opposite failure mode. ⛔ Do not close either as a duplicate of the other.

Not prescribed here

The fix direction is a real fork and belongs to whoever takes this, not to the filer: does a refusing child terminate the parent run as refused, surface as a distinguishable branch the author can route on, or stay a success with the refusal recorded? A refusal is a successful evaluation that says no, ⛔ not a failure, so folding it into the failed rollup #16314 describes would be the wrong answer in a way that is easy to reach for.

Dedupe words

subflow child refused rollup · subflow-node.ts child.status paused · refused subflow parent continues · end node outcome refused subflow · #14945 lane 2 subflow

Related: #16314 · #14945 · #15788 · PR #18109

domain:*, type and priority are the triage seat's; this card is filed ungraded.


os-decision-facets

① 项目长远合理性:A(NodeExecutionResultrefuse? / refusalMessage?)缩小特例 —— 它把拒绝并入 suspend 已在用的同一条 unwinding 协议,而 FlowRefusalSignal 的 docblock 逐字要求「reuses the mechanism rather than inventing a second unwinding protocol」;B(不导出的内部暗缝)是特例增生,且按 dev 实测,为保住 #4354 的 metrics 上卷它会把同样大的面长回信号内部。
② 实际业务拉动:仓内 两个一方调用点 —— subflow-node.ts(本卡)与 map-node.ts(本席复验同形洞,已立 #18555),两者需要同一条通道;第三方执行器拉动 0,⛔ 未测得。
③ 防 AI 犯错:A 强 —— 公开成员有声明、可评审、紧挨既有 suspend,一条规则覆盖两个站点;B 弱 —— 面藏在 barrel 之外评审看不见,且两个站点要写成两个特例。
④ 创业阶段不扩散:唯一指向 B 的一棱 —— A 在已发布包 @objectstack/service-automation 上加公开成员,把终止-拒绝能力一并发给零实测拉动的第三方执行器。

Prior rulings read: subflow,refused,service-automation,child,ends,rolled,parent,ordinary,success,refusal,reaches,nobody → 35 hits; ADR-0119 D4, ADR-0119 D1, ADR-0006 D3, ADR-0019 D2, ADR-0029 D9.9, ADR-0039 D7, ADR-0044 D3, ADR-0056 D6, ADR-0068 D2 — ⭐ 本席逐个读了与本题最近的两个,⛔ 不是只抄工具输出:ADR-0119 是事务 / 原子批,关键词假阳性;ADR-0019 D2(approval-as-flow-node) 裁的是「approval 是插件贡献的节点而非引擎核心」,其 refusal 条款只管 resume 的授权答复,⛔ 未裁refused 子运行该不该传播到父运行」。⇒ 无既有裁决答本题,本卡是决策而非执行。

推荐:A,并把本卡实施 PR 的 Clause-② 更正为 yes、走契约复审档复核。自检「只看①选 A;②③④ 是否翻转:③ 同向 A,② 同向 A(两个一方站点要同一条通道),仅 ④ 反向 ⇒ 不翻转,落在 A」。

置信缺口:第三方节点执行器是否真需要这条通道未测(实测拉动 0)。若维护者判定已发布公开面不可动,B 是可执行退路,但须接受 dev 实测的代价:为不丢 #4354 的 metrics 上卷,同样大的面会回流进内部信号,且评审看不见。


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions