Skip to content

feat(spec,service-automation): a run says when its acted count is incomplete, instead of guessing (#4354) - #4397

Merged
os-zhuang merged 1 commit into
mainfrom
claude/flow-run-summaries-xddi6c
Jul 31, 2026
Merged

feat(spec,service-automation): a run says when its acted count is incomplete, instead of guessing (#4354)#4397
os-zhuang merged 1 commit into
mainfrom
claude/flow-run-summaries-xddi6c

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

#4354 的后续。承接 #4377(已合并)。

问题:补漏时撞上的第三种答案

#4377 给每次运行装上了 selected / acted,计数由"知道自己干了什么"的执行器申报。但漏掉了四类节点 —— 而这个缺口不是装饰性的:connector_actionhttpscript 恰恰是 flow 对平台外部动手的方式,所以一条完全靠 connector 干活的 sweep 会报 acted: 0,看起来和这个计数器要抓的那种死掉的 sweep一模一样

在健康运行上误报的探测器比没有探测器更糟:运维学会忽略它,然后它就不再看着那些真的停了的 flow 了。

补这个洞需要第三种答案,因为其中两类节点平台确实无法知道发生了什么。

三个节点,三种处理

connector_action —— 不可知,现在它明说不可知。

ConnectorActionDescriptor 声明了 key / label / description / inputSchema / outputSchema,唯独没有"这个 action 是读还是写"。所以 crm.push_opportunitycrm.lookup_account 在运行时眼里是同一个形状:

改为上报 metrics: { unmeasuredEffect: true },运行汇总带一个 unmeasured 计数。已提 #4395 提议让 connector 声明 effect 类型,那样这里就能变成真实计数。

http —— 可知,于是真的数。 method 就说明了一切:

情况 上报
GET / HEAD / OPTIONS acted: 0 —— 读永远不会写
变更类方法,上游接受 acted: 1
durable: true acted: 1 —— outbox 行是这次运行造成的真实持久效果
变更类方法,被拒/超时 unmeasured —— 500 可能在写入落库之后才回来

script —— 刻意不动。 注册函数在契约上是纯的("Data I/O stays on the flow graph — the function itself does no writes"),所以它造成的每一次写都是下游节点自己在数,"不上报记录指标"是准确而非猜测。但没有任何东西强制这个纯度 —— 已提 #4396,而不是在这里糊过去:给 script 无差别打上 unmeasuredEffect 会为了迁就一次契约违反,压掉所有调用函数的 flow 的信号

告警多一个子句

where: {
  status: 'completed',
  selected_count: { $gt: 0 },
  acted_count: 0,
  // 没有这一条,告警会在每条健康的 connector flow 上响:
  // 那些运行的 acted 是「不完整」,不是「零」。
  unmeasured_count: 0,
}

sys_automation_run 新增 unmeasured_count 列。日志行新增 unmeasured=N,只在非零时出现 —— 因为它的出现才是读者不能错过的东西:一行同时写着 acted=0unmeasured=3,意思是"说不准",不是"什么都没干"。

传播与兼容

unmeasured 会穿过 subflow / map 上卷,以及子运行 pause 后回冒的 creditChildRun,所以子运行派发了不可数效果的父运行知道自己的 acted 不完整。子运行里 N 次不可数效果在父节点那一步收敛成一个布尔标记 —— 真实计数留在子运行自己的行里,而这里要回答的问题("父的 acted 完整吗")本来就是布尔。

FlowRunSummary.unmeasured 是可选的,且 undefined 不是 0:此前记录的运行根本没有追踪不可数效果,默认成零等于告诉运维"已完整测量"——而那次运行根本没人测量。和已有的 null 计数列同一条规则。

纯增量:只加可选字段,无新导出,执行行为零变化。

顺带确认了 #4347

动手前用 issue #4347 自带的 repro 实跑验证了它已修复:

-- A) bare string condition
   loop-body edge stored as : {"dialect":"cel","source":"row.shouldRun == true"}
   records written          : 1  gate opened
-- C) legacy dotted-string path: REFUSED: 'oppRecord.amount' is an unresolved expression reference

region 内 conversion 递归、loop-body 与顶层存成同一形状、以及字典序恒真那条改为报错 —— 三点都到位。

验证

  • @objectstack/service-automation 546 / 47(新增 21)
  • @objectstack/spec 7193 / 281(新增 2)
  • spec 八项 check:generated 全绿,外加七项纯审计(liveness / empty-state / variant-docs / strictness-ledger / react-conformance / skill-examples / exported-any)
  • check:nul-bytes、eslint 干净

一处非本 PR 引入的观察:nested-region-parity.test.ts(随 #4347#4381 进来)新增了 3 个 TS2341: Property 'flows' is private 类型错误,而 check-type-check-coverage.mjs@objectstack/service-automation 的 note 仍写着 "code-tier 2"。棘轮整体是通过的(它算总量),只是那条 note 已经和实际不符,值得顺手校正。

🤖 Generated with Claude Code

https://claude.ai/code/session_01SzJqHp1yXjri1tqKP8WoL4


Generated by Claude Code

…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
@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 31, 2026 10:56am

Request Review

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

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/service-automation, @objectstack/spec.

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

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/service-automation, @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/service-automation, @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/service-automation, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/service-automation, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/service-automation, @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

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 marked this pull request as ready for review July 31, 2026 11:28
@os-zhuang
os-zhuang merged commit d25a0ec into main Jul 31, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the claude/flow-run-summaries-xddi6c branch July 31, 2026 11:28
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.

2 participants