Skip to content

docs(automation): flows.mdx 的 Scheduled flow 示例补 runAs: 'system' (#5692) - #6012

Queued
hotlong wants to merge 1 commit into
mainfrom
claude/issue-5692-flows-mdx-runas-system
Queued

docs(automation): flows.mdx 的 Scheduled flow 示例补 runAs: 'system' (#5692)#6012
hotlong wants to merge 1 commit into
mainfrom
claude/issue-5692-flows-mdx-runas-system

Conversation

@hotlong

@hotlong hotlong commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Fixes #5692

问题

content/docs/automation/flows.mdx 的 "Scheduled flow" worked example contract_expiration_checktype: 'schedule'、nodes 含 top-level get_record(find_expiring)的流程,却没有声明 runAs

schedule run 解析不到 trigger user,生效的 runAs 是 spec 默认 'user',get_record 没有身份可 scope —— flow-runas-unscopedseverity: 'error' 判红。照抄这段的作者会得到一次失败的构建;硬闯过去则运行时被引擎拒绝(#3760)。

这份文档在同一个文件里把这条约束讲了两遍,然后在最可能被整段复制的示例里违反了它:

  • ~35 行之下的 time-relative 邻例 renewal_reminder 写对了,还把理由带成一行注释;
  • 同文档 runAs 属性表散文写明 "declare 'system' for schedule / time-relative / API triggers"。

改动

一行,docs-only:

   name: 'contract_expiration_check',
   label: 'Contract Expiration Check',
   type: 'schedule',
   status: 'active',
+  runAs: 'system', // a schedule run has no trigger user — elevate explicitly
   nodes: [

注释理由照抄邻例(// a sweep has no trigger user — elevate explicitly),句式与结尾逐字保持一致,只把主语换成本例真实的触发形态:在本文档里 "sweep" 是 timeRelative 描述符那一形态的术语("a schedule flow whose start node declares a timeRelative descriptor is swept on a schedule"),而本例是普通 cron schedule,照搬 "a sweep" 会把错误的术语带进语料。

实测(A/B,两侧都跑)

探针不是手抄片段,而是直接从 flows.mdx 抽取 fenced typescript 代码块、求值成 flow 对象后跑真规则 lintFlowPatterns()(packages/lint 的构建产物),所以测的就是作者会复制的那段文本本身。

Before(origin/main @ f192981,未改动的文件):

doc: content/docs/automation/flows.mdx
snippets evaluated: contract_expiration_check, renewal_reminder

1 x flow-runas-unscoped  <-  contract_expiration_check (type: 'schedule', no runAs)
      error: schedule-triggered flow runs as the default `runAs:'user'`, but a schedule run has no trigger user — so its data node 'find_expiring' (get_record) has no identity to scope to and will be REFUSED at run time.
      where: flow 'contract_expiration_check' · runAs
0 x flow-runas-unscoped  <-  renewal_reminder (type: 'schedule', runAs: 'system')

TOTAL flow-runas-unscoped findings: 1

After(本 PR):

doc: content/docs/automation/flows.mdx
snippets evaluated: contract_expiration_check, renewal_reminder

0 x flow-runas-unscoped  <-  contract_expiration_check (type: 'schedule', runAs: 'system')
0 x flow-runas-unscoped  <-  renewal_reminder (type: 'schedule', runAs: 'system')

TOTAL flow-runas-unscoped findings: 0

方向是跑之前就定好的:目标片段 1 次(error)→ 0,邻例 renewal_reminder 作为对照两侧都是 0。全文件 type: 'schedule' 的示例只有这两个(L1245 / L1282),改完之后该规则对本文件命中归零。

#5633 的关系

本片段的证据节点 find_expiringtop-level get_record,所以 #5633(把同一条规则加宽到 nested regions)前后对它的判定逐字节一致 —— 这是既有的语料缺陷,不是回归,也不在 #5633 的范围内。

门禁(本地,已跑)

✓ doc authoring guard: 362 files clean — no bare metadata literals.
check-nul-bytes: OK (scanned 5763 tracked text file(s); ... no raw ASCII control bytes).
✓ docs-accuracy-audit scope is in sync with content/docs/: 178 hand-written doc(s).

Changeset

docs-only,没有可发布的包变更 —— 不提交空 changeset(空 frontmatter 的 changeset 会真的进 changesets/action,#4898),改为打 skip-changeset 标签。

不扩面

issue 正文末尾提的「提取 fenced flow 片段、对其跑 authoring rules 的语义门禁」是另立单范围,本 PR 不做,也不动其它示例。


Generated by Claude Code

`contract_expiration_check` 是 `type: 'schedule'` 且 nodes 含 top-level
`get_record` 的流程,却没有声明 `runAs`。schedule run 解析不到 trigger user,
生效的是 spec 默认 `runAs: 'user'`,`get_record` 没有身份可 scope ——
`flow-runas-unscoped` 按 `severity: 'error'` 判红:照抄这段的作者会得到一次
失败的构建,硬闯过去则运行时被引擎拒绝(#3760)。

同文件 ~35 行之下的 time-relative 邻例 `renewal_reminder` 已经写对,并把理由
带成一行注释;同文档的 `runAs` 属性表散文也写明了同一条规则。文档把约束讲了
两遍,然后在最可能被整段复制的示例里违反了它 —— 本次只补上那一行。

注释理由照抄邻例,只把主语换成本例真实的触发类型:邻例是 `timeRelative`
描述符的 sweep(本文档对该形态的术语),本例是普通 cron schedule。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BDmDsu2575gDxeMCxXhDE3
@vercel

vercel Bot commented Aug 6, 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 Aug 6, 2026 2:53pm

Request Review

@hotlong hotlong added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 6, 2026 — with Claude
@github-actions github-actions Bot added size/xs documentation Improvements or additions to documentation labels Aug 6, 2026
@hotlong
hotlong marked this pull request as ready for review August 6, 2026 15:00
@hotlong
hotlong added this pull request to the merge queue Aug 6, 2026
Any commits made after this event will not be merged.
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 6, 2026
@hotlong
hotlong added this pull request to the merge queue Aug 6, 2026
Any commits made after this event will not be merged.

hotlong commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

队列处置审计(devx 车道 PM,会话 session_01BDmDsu2575gDxeMCxXhDE3,双向让行记录):

15:1xZ 本 PR 被合并队列踢出(CI_FAILURE)。判读:分组队列同批失败外溢 —— 本 PR 自身 25 项 PR 级检查 14:56Z 全绿(docs-only +1 行),排前的 #5991 正常落地、排后的 #5983/#6010 重建后仍在队,mergeable_state: clean。按已知形态原样重投(auto-merge 已重挂)。

⚠️ 若再次被踢:停止盲投,取 merge_group 失败 run 的完整签名再诊断(Operational notes 2)。队列管家座位如已处置请以本评论为让行依据,后续由先动方跟进。


Generated by Claude Code

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 31115031138 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Build Docs — 失败步骤: Set up job(日志不可读,点进 job 看)
  • Test Core (1/3) — 失败步骤: Set up job(日志不可读,点进 job 看)

历史信号:

  • ⚠️ 本 PR 过去 24h 已在队列失败 1 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 14 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 在其他 PR 的同类评论里搜同名测试;出现过 ⇒ flaky 实锤,开 issue 修/隔离那条测试。修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

hotlong commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

队列分诊结论(devx 车道 PM,回应上方 triage 评论,让行依据刷新):

本 PR 两次队列失败(run 31114893903 邻批 / 31115031138 本批)的失败步骤均为 Set up job —— runner 起步即败、零测试执行,签名 = 15:14–15:25Z GitHub Actions 平台故障(action 下载 5xx,同窗口另有 5 个 PR 级 run 同签名,重跑后全部恢复绿)。非 flaky、非语义冲突、非本 PR 回归(docs-only +1 行);「24h 队列 14 个失败构建」大头即该窗口。

处置:PR 已被自动重排在队(15:32Z 队列分支确认),不再手动干预;若第三次被踢且签名非 Set up job/基础设施类,届时按真问题重新诊断。队列管家座位无需按 flaky 台账处置本单。


Generated by Claude Code

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 31116185080 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

  • Test Core (1/3) — 失败步骤: Set up job(日志不可读,点进 job 看)

  • Test Core (2/3) — 失败步骤: Run this shard's tests

    �[41m�[1m FAIL �[22m�[49m src/__tests__/datasource-pool-support.test.ts�[2m > �[22m#5714 — the driver factory rejects a pool it cannot honour�[2m > �[22msqlite WITHOUT a pool still builds exactly as b
    �[90mstderr�[2m | src/sql-driver-unique-tenancy.test.ts�[2m > �[22m�[2mSqlDriver unique × tenancy (#3696)�[2m > �[22m�[2mretires a legacy global unique index and replaces it with the composite
    �[90mstderr�[2m | src/sql-driver-unique-tenancy.test.ts�[2m > �[22m�[2mSqlDriver unique × tenancy (#3696)�[2m > �[22m�[2mretires the legacy `uniq_<table>_<col>` index left by the drift rebuild path
    �[90mstderr�[2m | src/sql-driver-unique-tenancy.test.ts�[2m > �[22m�[2mSqlDriver unique × tenancy (#3696)�[2m > �[22m�[2mbare-composite tightening + duplicate pre-flight (ADR-0120 D4)�[2m > �[22m�[2ma
    �[90mstderr�[2m | src/sql-driver-unique-tenancy.test.ts�[2m > �[22m�[2mSqlDriver unique × tenancy (#3696)�[2m > �[22m�[2mbare-composite tightening + duplicate pre-flight (ADR-0120 D4)�[2m > �[22m�[2mB
    �[22m�[39m[schema-drift] product: cannot tighten 'uniq_product_organization_id_code' as UNIQUE (COALESCE(organization_id, '__global__'), code) — existing rows already violate the NULL-safe unique cons
    �[90mstderr�[2m | src/sql-driver-unique-tenancy.test.ts�[2m > �[22m�[2mSqlDriver unique × tenancy (#3696)�[2m > �[22m�[2mbare-composite tightening + duplicate pre-flight (ADR-0120 D4)�[2m > �[22m�[2mB
    �[22m�[39m[schema-drift] REFUSING to rebuild 'uniq_product_organization_id_code' on 'product' as a NULL-safe unique — 1 duplicate group(s) violate it (e.g. organization_id="__global__", code="DUP" × 2
    

历史信号:

  • ⚠️ 本 PR 过去 24h 已在队列失败 2 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 17 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 在其他 PR 的同类评论里搜同名测试;出现过 ⇒ flaky 实锤,开 issue 修/隔离那条测试。修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

hotlong commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

队列分诊终注(devx 车道 PM,三次被踢全归因):

  1. 第 1/2 次(run 31114893903 / 31115031138):Set up job 失败 = 15:14–15:25Z GitHub Actions 平台故障;
  2. 第 3 次(run 31116185080):Test Core (2/3) 真失败,签名 datasource-pool-support.test.ts「sqlite WITHOUT a pool still builds」= 已立案的已知 flaky flaky(service-datasource): datasource-pool-support.test.ts 的「sqlite WITHOUT a pool still builds」在合并队列全量跑间歇红 —— 今日已踢 2 个不相关 PR(#5999、#5973) #6044(datasource pool 声明在 sqlite / sqlite-wasm 驱动臂被静默丢弃(pg / mysql 生效) #5714→PR fix(service-datasource): sqlite / sqlite-wasm 臂的 pool 声明改为响亮拒绝,不再静默丢弃 (#5714) #5954 合入后在队列全量跑间歇红,今日已踢 fix(metadata-core): delete 判定末尾改真值测试,假值标量 where.id 不再答 by-id (#5747) #5999/fix(spec)!: HierarchyScopeContext 声明 organizationId 为权威租户字段并转必填 (#5858) #5973 两个不相关 PR)—— 非本 PR 回归(docs-only +1 行,零代码面)。

PR 已自动重排在队,不做人工干预;该 flaky 的修复/隔离由 #6044 跟踪,与本单无涉。队列管家按台账处置时本评论即让行依据。


Generated by Claude Code

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Aug 6, 2026
@hotlong
hotlong added this pull request to the merge queue Aug 6, 2026
Any commits made after this event will not be merged.
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 31120011702 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

失败的 job(日志抽取,best effort):

历史信号:

  • ⚠️ 本 PR 过去 24h 已在队列失败 5 次(不含本次)。 内容未变而反复失败 ⇒ 高度怀疑 flaky 测试或与同组 PR 的语义冲突,重排不解决。
  • 过去 24h 队列共有 36 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 在其他 PR 的同类评论里搜同名测试;出现过 ⇒ flaky 实锤,开 issue 修/隔离那条测试。修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to no response for status checks Aug 6, 2026
@hotlong
hotlong added this pull request to the merge queue Aug 6, 2026
Any commits made after this event will not be merged.
@claude

claude Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

队列管家:让行 + 签名归因(Routine pm-queue-steward,第 15 轮,2026-08-06 19:1x–19:2xZ)

让行:本 PR 于 18:58:35Zgithub-merge-queue[bot] 移出队列,车道(hotlong)已于 18:59:18Z(43 秒后)自行重新入队 ⇒ 车道已在处置,队列管家让行 —— 本座位不重投、不干预队列顺序。以下仅补一份完整签名归因供车道参考。

本次踢出的完整签名(完整 job 归档,original_length 63 / 80,⛔ 未看 tail)

job 结束 终报错
Test Core 18:54:06Z test matrix aggregate result: abandoned (filter job: success)::error::Test Core shards did not pass (aggregate result: abandoned)
Dogfood Regression Gate 19:03:01Z dogfood matrix aggregate result: abandoned / dogfood-verify result: abandoned → 两条 leg 各判红

run 31123566813(head pr-6012-e478c1d5…)内 零测试失败:14 个 job 中 10 个 success、4 个于 18:18:52Z 被 cancelled(队列重建丢弃了这条已被取代的分片链)。Test Core 判红 4 分 29 秒后本 PR 被移出队列(timeline removed_from_merge_queue 核实)。

判读:假红,与本 PR 的 diff 无关

abandonedrun 生命周期状态(分片被队列重建丢弃),不是分片判决;而 .github/workflows/ci.yml 聚合门禁的白名单只有 success|skipped|cancelled,abandoned 落进 *) 兜底 ⇒ 判红 ⇒ 踢出。case 正上方的注释(引 #3668)论证的恰恰是它的反面:cancelled "is a run-lifecycle state …, not a verdict, and failing here would paint a false red" —— 同一条推理逐字适用于 abandoned,只是该状态没被写进白名单。

本座位为何自己不重投

该签名尚未进 #5810 签名台账(第 14 轮已提请人工升级,仍待裁定)。台账只有人工能升级,裁定前本座位对该签名一律拦截不重投。车道自行重投属车道权责,本座位不置喙 —— 仅提醒:在当前停滞面下重投大概率复现(见下)。

同签名今日第 3 例

PR 判红时刻 结果
#6010 17:32:13Z 被踢(第 14 轮已拦截并通知 identity 车道)
#6012(本 PR) 18:54:06Z 被踢 → 车道 18:59:18Z 自行重投
#6013 19:06:15Z 未被踢(仍在链上第 4 位)

origin/main15:14:30Z~4 小时零落地,期间队列反复重建 —— 每重建一次就把在队 PR 判成假红,被踢者重投后又加深队列,停滞与踢出互相喂养。完整停滞面与人工裁定提请见 #5810 第 15 轮简报


Generated by Claude Code

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/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs corpus teaches a flow the build REJECTS: flows.mdx contract_expiration_check is a schedule flow with a top-level get_record and no runAs: 'system'

2 participants