feat(spec,service-automation): a run says when its acted count is incomplete, instead of guessing (#4354) - #4397
Merged
Conversation
…ncomplete, instead of guessing (#4354) #4354 shipped selected/acted counts sourced from the executors that know what they did, but left out the four node types a flow uses to act on anything OUTSIDE the platform. That gap was not cosmetic: a sweep whose whole job runs through a connector reported `acted: 0` and looked exactly like the dead sweep the counter exists to find. A detector that fires on healthy runs is worse than none — operators tune it out, and then it is not watching the flows that really did stop. Closing it needed a third answer, because for two of those nodes the platform genuinely cannot know what happened: - `connector_action` — `ConnectorActionDescriptor` declares nothing about whether an action reads or writes, so `acted: 0` understates a create and `acted: 1` overstates a lookup (and makes the alert never fire, which is the original bug one layer out). Reports `unmeasuredEffect` instead. #4395 proposes declaring the effect kind, which would make it a real count. - `http` — knowable from the method. GET/HEAD/OPTIONS report a real `acted: 0`; an accepted mutating call reports 1; `durable: true` reports 1 (the outbox row is a durable effect this run caused); a rejected or timed-out mutating call reports unmeasured, because a 500 can arrive after the write landed. - `script` — deliberately unchanged. A registered function is contractually pure (data I/O stays on the flow graph), so reporting no record metrics is accurate rather than a guess. Nothing enforces that purity — filed as #4396 rather than papered over, since a blanket `unmeasuredEffect` here would suppress the signal on every flow calling any function to cover one contract violation. The alert gains a clause: `selected > 0 AND acted = 0 AND unmeasured = 0`, with an `unmeasured_count` column to serve it — without the third clause it fires on every healthy connector-driven flow. The log line gains `unmeasured=N` only when non-zero, since its PRESENCE is what a reader must not miss. `unmeasured` propagates through subflow/map roll-ups and `creditChildRun`, so a parent whose child dispatched an uncountable effect knows its own `acted` is incomplete. `FlowRunSummary.unmeasured` is optional and undefined is NOT 0: a run recorded before this existed did not track uncountable effects at all. Verified: service-automation 546/47 (21 new), spec 7193/281 (2 new); all 8 check:generated gates plus the seven pure audits; check:nul-bytes and eslint clean. Branch restarted from main after #4377 merged; #4347's fix confirmed first by running that issue's own repro. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SzJqHp1yXjri1tqKP8WoL4
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 2 package(s): 107 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#4354 的后续。承接 #4377(已合并)。
问题:补漏时撞上的第三种答案
#4377 给每次运行装上了
selected/acted,计数由"知道自己干了什么"的执行器申报。但漏掉了四类节点 —— 而这个缺口不是装饰性的:connector_action、http、script恰恰是 flow 对平台外部动手的方式,所以一条完全靠 connector 干活的 sweep 会报acted: 0,看起来和这个计数器要抓的那种死掉的 sweep一模一样。在健康运行上误报的探测器比没有探测器更糟:运维学会忽略它,然后它就不再看着那些真的停了的 flow 了。
补这个洞需要第三种答案,因为其中两类节点平台确实无法知道发生了什么。
三个节点,三种处理
connector_action—— 不可知,现在它明说不可知。ConnectorActionDescriptor声明了key/label/description/inputSchema/outputSchema,唯独没有"这个 action 是读还是写"。所以crm.push_opportunity和crm.lookup_account在运行时眼里是同一个形状:acted: 0→ 低报了一次 Salesforce create,每条健康的 connector sweep 都会触发告警acted: 1→ 高报了一次 lookup,于是告警永远不会响 —— 这就是 Surface flow run summaries (selected / acted / skipped) — a scheduled flow that does nothing is currently indistinguishable from one with nothing to do #4354 原本的 bug,只是往外挪了一层改为上报
metrics: { unmeasuredEffect: true },运行汇总带一个unmeasured计数。已提 #4395 提议让 connector 声明 effect 类型,那样这里就能变成真实计数。http—— 可知,于是真的数。 method 就说明了一切:GET/HEAD/OPTIONSacted: 0—— 读永远不会写acted: 1durable: trueacted: 1—— outbox 行是这次运行造成的真实持久效果unmeasured—— 500 可能在写入落库之后才回来script—— 刻意不动。 注册函数在契约上是纯的("Data I/O stays on the flow graph — the function itself does no writes"),所以它造成的每一次写都是下游节点自己在数,"不上报记录指标"是准确而非猜测。但没有任何东西强制这个纯度 —— 已提 #4396,而不是在这里糊过去:给script无差别打上unmeasuredEffect会为了迁就一次契约违反,压掉所有调用函数的 flow 的信号。告警多一个子句
sys_automation_run新增unmeasured_count列。日志行新增unmeasured=N,只在非零时出现 —— 因为它的出现才是读者不能错过的东西:一行同时写着acted=0和unmeasured=3,意思是"说不准",不是"什么都没干"。传播与兼容
unmeasured会穿过subflow/map上卷,以及子运行 pause 后回冒的creditChildRun,所以子运行派发了不可数效果的父运行知道自己的acted不完整。子运行里 N 次不可数效果在父节点那一步收敛成一个布尔标记 —— 真实计数留在子运行自己的行里,而这里要回答的问题("父的 acted 完整吗")本来就是布尔。FlowRunSummary.unmeasured是可选的,且undefined不是0:此前记录的运行根本没有追踪不可数效果,默认成零等于告诉运维"已完整测量"——而那次运行根本没人测量。和已有的null计数列同一条规则。纯增量:只加可选字段,无新导出,执行行为零变化。
顺带确认了 #4347
动手前用 issue #4347 自带的 repro 实跑验证了它已修复:
region 内 conversion 递归、loop-body 与顶层存成同一形状、以及字典序恒真那条改为报错 —— 三点都到位。
验证
@objectstack/service-automation546 / 47(新增 21)@objectstack/spec7193 / 281(新增 2)check:generated全绿,外加七项纯审计(liveness / empty-state / variant-docs / strictness-ledger / react-conformance / skill-examples / exported-any)check:nul-bytes、eslint 干净🤖 Generated with Claude Code
https://claude.ai/code/session_01SzJqHp1yXjri1tqKP8WoL4
Generated by Claude Code