Skip to content

[P2] engine ADR: durable pause inside structured regions (unlock topology-level parallel approvals / waits / subflows) #3267

Closed as not planned

Description

@os-zhuang

Ruled: 5770959025 · letter A · 2026-09-22T03:52Z — batch #209 item 2 re-presented in summon #26; closed not_planned; reopen condition in the ruling (named scenario ⇒ ADR from the five questions, no new decision card)

审批增强三阶段中的 Phase 2(引擎线):Phase 1 = #3266(节点内 quorum/会签,不依赖本 issue)→ 本 issue → Phase 3 企业版治理(objectstack-ai/cloud#861)。产出物是一份 ADR + 实现。

现状(硬限制)

流引擎的结构化区域(parallel / loop 容器)禁止持久挂起:

  • service-automation/src/engine.ts:2388-2412 — “Durable pause (suspend) inside a region is not supported … converted into a clear error”
  • builtin/parallel-node.ts:33-34 — 分支内 durable pause 为硬错误
  • engine.ts:363-366 — “durable pause across parallel gateways is out of scope for ADR-0019 M1”

因此凡是需要挂起的节点(approval、signal wait、含挂起的 subflow)都进不了 parallel 区域;现有 parallel 块仅服务同步工作(Promise.all,parallel-node.ts:82)。

为什么以引擎通用能力立项(而不是审批特性)

受益方不止审批:并行分支内的 wait 信号等待、subflow 嵌套挂起(现有 linked-runs 模型已支持单链,见 showcase ClosureSignoffSubflow)、未来任意 human-task 节点。审批只是第一个消费者——Phase 1(#3266)已用节点内语义解决主流场景(钉钉/Salesforce 模式),本 issue 解锁的是拓扑级并行(跨对象、跨记录、审批+等待混排的复杂编排,即 Camunda parallel gateway + multi-instance 一类能力)。

ADR 需要决策的问题

  1. 挂起状态模型:区域内多点挂起时 SuspendedRun 如何表示(单 run 多 suspension?子 run per branch,复用 linked-runs?)
  2. join 语义:全部完成 / 任一完成(competing)/ N-of-M 完成;失败分支对 join 的影响
  3. 审批约束联动:“每记录一个 pending 请求”(approval-service.ts:479)在拓扑并行下如何演进——多请求并存时的记录锁、approvalStatusField 镜像、收件箱呈现
  4. 恢复语义:多挂起点的 resume 幂等性、乱序 resume、部分分支 recall
  5. 兼容性:现有同步 parallel 块行为不变;BPMN interop 映射(bpmn-interop.zod.ts 的 parallel_gateway/join_gateway)是否借此落地执行语义

验收

  • ADR 提交并 accepted(含上述 5 项决策)
  • 引擎:区域内挂起/恢复 + join 语义实现,现有同步 parallel 行为零回归
  • 两个 approval 节点在并行分支同时 pending、join 后推进的端到端用例
  • wait 信号节点在并行分支内可用
  • 文档(flows.mdx / approvals.mdx)更新

Generated by Claude Code

Activity

  1. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    存量裁决轮(维护者 2026-08-06 委托,session_01LeEfA7CFwbJb7JJmXm2KM3):裁定停放(pm:on-hold)。结构化区域禁止持久挂起的硬限制仍在(parallel-node.ts:29 经 origin/main 核实),但 Phase 1(#3266 节点内 quorum/会签,2026-07-19 完成)已覆盖主流审批场景,拓扑级并行目前无业务拉动——创业阶段聚焦原则下刻意延后能力扩张。重启条件:出现真实客户/示例场景需要并行分支内挂起(并行审批、wait 信号、含挂起 subflow 的编排),或 Phase 3 企业版治理(cloud#861)正式排期。


    Generated by Claude Code

  2. os-zhuang commented on Aug 21, 2026

    @os-zhuang
    ContributorAuthor

    H11 re-check (triage seat, scheduled fire 2026-08-21 ~03:47Z): hold stands. Body Restart-when: verified live against its upstream — objectstack-ai/cloud#861 is open, itself pm:blocked on cloud#855, and not scheduled; no customer/example scenario needing durable suspension inside a parallel branch has been filed. No state change.


    Generated by Claude Code

  3. os-support-ai commented on Aug 26, 2026

    @os-support-ai
    Collaborator

    Half-state patrol disposition (H11) — hold is lawful, liveness re-checked, no state change

    domain:services seat, session session_0157mMVAq9fjGe2kaSD2aJC8, round 1. Anchor #9857, swept 02:12:33Z.

    H11 reports this as an important card parked past the 7-day threshold (priority:p2 in pm:on-hold, ~38d). H11 is an inventory row, not a defect row — its instruction is to re-check the hold's liveness in the round, which is what this comment records.

    ⚠️ Note this card carries no H9, and that is correct: the exit is already on it, first line of the body —

    Restart-when: objectstack-ai/cloud#861 (Phase 3 EE governance) is scheduled, or a real customer / example scenario needs durable suspension inside a parallel branch

    Two channels, both fireable, and the second one is the honest half: it fires on pull, not on a date.

    Liveness read

    • Upstream leg: objectstack-ai/cloud#861 is not reachable from this session's account (list_repos returns nothing for cloud), so ⚠️ NOT MEASURED — recorded as unmeasured rather than assumed either way. The repo:cloud seat can answer it in one read; this is not worth a cross-seat card on its own, since the second leg governs anyway.
    • Pull leg: no measured pull. Phase 1 ([P1] approvals: quorum (M-of-N) + grouped per-group sign-off (会签) + decision attachments #3266, in-node quorum) already covers the mainstream approval scenarios (the DingTalk / Salesforce shape); what this card unlocks is topology-level parallelism — approvals and waits mixed inside a parallel gateway. Nothing in this lane's queue or recent findings has needed it.

    ⇒ pm:on-hold stays. A P2 engine-ADR card whose own restart condition is "when someone actually needs it" is parked correctly, and 38 days is not by itself evidence of anything — that is exactly why H11 asks for a liveness read instead of a promotion.

    What this card is NOT waiting on

    For the record, so no future round mistakes the neighbours for blockers: it is not gated on #3266 (shipped, independent by design) and it is not gated on any card in this lane's queue. The engine-side surface it would touch (service-automation/src/engine.ts region guards, builtin/parallel-node.ts) is free today.


    Generated by Claude Code

  4. hotlong commented on Sep 17, 2026

    @hotlong
    Contributor

    Ruling: batch #146 item 1 · letter 禁 (the region limit becomes declared design: structured regions do not support durable pause or run-terminating signals; the card stays parked) · maintainer 「146 同意」 2026-09-17T13:15Z

    Director seat, summon #24, session_01Wj1HUjzyeiBQ8atRf1ZhaL. Presented in detail on the direct channel as the root question behind #15646 (ruled C in batch #145) and #18112, with the recommendation 禁; the maintainer agreed 「146 同意」, after stating the governing principle verbatim: 「创业期现在不追求功能多,追求稳定」 (recorded on the seat post, 5714323508). Facts: the engine refuses durable pause inside parallel / loop / try_catch (engine.ts region guard, parallel-node.ts), ADR-0019 M1 left the parallel-gateway pause out of scope; Phase 1 (#3266, in-node quorum / 会签) covers the mainstream approval shapes; the 2026-08-06 delegated round parked this card and two patrol re-checks found no pull; cloud#861 is unscheduled and itself blocked.

    Ruling — 禁

    Four-facet reading: ① the topology-level shape should be designed against the first real scenario, not guessed; ② zero measured pull across two patrol re-checks; ③ what matters is that the limit is loud and early — #15646 C delivers that; ④ 「不追求功能多,追求稳定」.

    Execution

    No label change (pm:on-hold stands; this comment is the ruling of record). #15646 (C) and #18112 (A) execute the limit; #18110 (A) is unaffected (a refusal inside a subflow node's own child terminates through the node, not a region).


    Generated by Claude Code

  5. hotlong commented on Sep 17, 2026

    @hotlong
    Contributor

    Confirmation — director seat · 2026-09-17T14:09Z: under the corrected need standard (5715688324) the seat re-read this card to the maintainer (topology-level durable pause is a standing capability of mature engines) and proposed 「排期」; the maintainer ruled 「3267 停放」. The ruling 禁 (5714974100) and the park stand unchanged: pm:on-hold, Restart-when: as written; #15646 (C) and #18112 (A) remain the correct state until this restarts.


    Generated by Claude Code

  6. os-steve commented on Sep 21, 2026

    @os-steve
    Collaborator

    回决策箱(维护者指令,skills 席 2 代执行)— 2026-09-21T03:45Z

    出处三件(SKILL.md :149 代执行他人指令,评论带出处三件)— 谁的指令:维护者,在本席(domain:skills seat 2,session_017ETYWqMQD4qMtZzAGovWNi,席位帖 #19287)会话内的真实用户轮次。在哪说:本席会话聊天,2026-09-21,在本席呈交「停放排查」四组清单(全板 165 张停放卡:pm:blocked 64 + pm:on-hold 101;其中 38 张的停放条件已消失——正文与评论里 Blocked-by: / Restart-when: 指向的卡或 PR 全部已关或已合)之后。原话(逐字,⛔ 未翻译、未润色):「还有哪些应该解除停放的你一起排查一下」;对四组清单:「同意」。

    本卡属第三组「条件已消失的决策卡 ⇒ 回决策箱」:本席于 2026-09-21T03:00Z 机器复核,本卡停放所指向的目标已全部关闭/合并;卡的本体是一道待维护者裁的题,停放条件消失后它不该继续 hold,而该回到 needs-user-decision 收件箱排批。

    动作:停放状态标签一笔换为 needs-user-decision;⛔ 本席不代裁、不派发。所属车道席位或总监席在下次决策批前按 SKILL.md 〈决策箱勤务〉补全四棱卡面块与「维护者速读」(存量卡低频子轮回填);H62 在补全前对本卡报行属正常。


    Generated by Claude Code

  7. os-support-ai commented on Sep 22, 2026

    @os-support-ai
    Collaborator

    Ruling: batch #209 item 2 (re-presented in summon #26) · letter A · maintainer 「同意」 2026-09-22T03:52Z

    Director seat, summon #26 (session_01SPwf6Kmqo1gqzCSWSuMtQM). Presented by summon #25 as batch #209 item 2 but never seen by the maintainer (「3267 是什么没看到」); re-presented today in full — what the card is, why it is back in the box, three options with costs, the four facets — and approved 「同意」.

    Governing text: ruling batch #146 item 1 「禁」 (5714974100, maintainer 「146 同意」, 2026-09-17 — structured regions do not support durable pause; declared design, enforced at authoring time by #15646 (C) and #18112 (A) and at runtime by the region-boundary error); the maintainer's 「3267 停放」 (5715763622) and 「创业期现在不追求功能多,追求稳定」 (5714323508); the state rule 「无机制可唤醒的卡 ⛔ 不 hold:关 not planned,理由/出处载关单评论;重开免费」.

    Ruled (A): closed not_planned, completely. The region limit stays the declared design; #15646 (C) and #18112 (A) stand. The card's Restart-when: (cloud#861 scheduled, or a real customer / example scenario) can no longer fire: cloud#861 is closed (skills seat 2's machine re-check, 5755101132 at 2026-09-21T03:00Z — cloud is outside this session's reach, so the reading is attributed), and 「a named customer scenario」 is not a machine-readable trigger, so the card does not hold. ⛔ B (hold on a non-mechanical condition) refused. ⛔ C (schedule the ADR now) refused against the two standing rulings and zero measured pull over two patrol re-checks.

    Reopen condition, ruled now so no further decision card is ever needed: a NAMED customer or example scenario that needs durable suspension inside a parallel branch (a parallel approval, a wait signal, or a subflow containing a pause). On that evidence any seat reopens THIS card and the ADR starts from the five decisions in its body (suspension model, join semantics, approval-constraint interplay, resume idempotency, BPMN mapping); the existing synchronous parallel behaviour is a zero-regression constraint; both run-terminating signals (pause, refusal) are decided together per ADR-0019 M1's open item. ⛔ The maintainer is not asked again for permission to start — this ruling is it, conditional on the named scenario.

    State in this stroke: needs-user-decision removed; closed not_planned; enhancement · priority:p2 · domain:services stay as attribution; the Restart-when: line leaves the body with the hold it belonged to.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions