Skip to content

docs(automation): 屏幕流 resume 契约与审批越权标记的文档 + 两份 changeset(#4502 跟进) - #4517

Merged
os-zhuang merged 4 commits into
mainfrom
claude/v17-flows-docs-and-changesets
Aug 1, 2026
Merged

docs(automation): 屏幕流 resume 契约与审批越权标记的文档 + 两份 changeset(#4502 跟进)#4517
os-zhuang merged 4 commits into
mainfrom
claude/v17-flows-docs-and-changesets

Conversation

@os-zhuang

@os-zhuang os-zhuang commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

#4502 的跟进,只有文档、changeset 与注释文本,没有任何行为改动

#4502 修了 v17 验收缺陷汇总 #4482 里的四个缺陷(#4477 / #4466 / #4469 / #4470),已合入 main5a84d4148),CI 20/20 全绿。下面这些本该在那个 PR 里,但它进入 merge queue 后远端拒绝更新分支:

GH006: Protected branch update failed for refs/heads/claude/v17-verification-defects-gnf9e6-flows.
A pull request for this branch has been added to a merge queue.
Branches that are queued for merging cannot be updated.

我不会自行 dequeue 别人做出的合并决定,所以拆成这个小 PR 落地。已在 #4502 上留言说明(comment),并把 #4469 / #4470 的完整根因与验证证据补成了两个 issue 上的永久评论。


1. content/docs/automation/flows.mdx —— 屏幕流 resume 现在是有契约的

#4477 之前,POST …/runs/:runId/resume 把收到的任意 bag 直接折进流程变量:缺必填字段、以及未声明的键,都能让整个 run 跑完。文档描述的是那个旧行为(暂停节点表里 screen 那一行只说「the UI runner posting the collected inputs」),读者据此会以为客户端校验就是全部校验。

新增一节 A screen resume is checked against the declared fields,放在「Durable pause & resume」下、紧挨着它所对应的 $ 命名空间那条规则(两者是同一条接缝上的两条规则,挨着读最省事):

  • config.fields契约而不只是渲染提示;
  • 拒绝形态写成实际报文:400 + Invalid screen input: Screen field "escalation_reason" is required — declared fields: 'kind', 'escalation_reason',并点明 code: 'INVALID_SCREEN_INPUT'
  • 两类违规(该问而没给的 required、未声明的键)会一次全部报出,空白字符串算缺失;
  • visibleWhen本次提交的值求值,所以隐藏字段的 required 不触发 —— 否则就是把 Console: screen-flow Submit never calls the resume endpoint — every screen flow is un-completable from the UI #3528 那个死锁搬到服务端;求值失败的谓词按隐藏处理,因为客户端才是「用户看到了什么」的权威;
  • 拒绝发生在消费挂起之前,所以 run 仍然停着、改对了再提交仍然能落;
  • 三种不声明契约因而保持 pass-through 的形状(object-form 屏幕、纯消息屏幕、signal.output)。

暂停节点表里 screen 那一行也改成明确写出这些 inputs 会被服务端按声明的 fields 校验。

2. content/docs/automation/approvals.mdx —— 越权标记与终态僵尸请求

管理员越权的 callout(#4466). 原文只说管理员「may act on any pending request」并「audited under the admin's own id」,读起来像是审计已经够用了。#4466 指出的恰恰是它不够用:越权那一行和指定审批人自己批的那一行在字节层面完全相同。现在补上:

  • 写明它实际实现的规则是「操作者是管理员」,而不是「名单无人」—— 所以管理员也能越过一份已配齐的名单,这正是 issue 复现的场景;
  • 因此决策会记录它是从哪扇门进来的sys_approval_action.via_override
  • 为什么同时是指定审批人的管理员记 false(标记记的是哪条分支放行了这次调用,不是操作者有没有管理员权限);
  • 为什么旧行的缺失读作「未记录」而非「不是越权」;
  • 以及在此之前,一份名单被绕过的唯一痕迹是被绕过者后来收到的 409 INVALID_STATE —— 而且只有他碰巧去点了才存在。

死信 callout(#4469). 原文描述的清扫只扫 pending。补上它看不见的那一类:已终态但 run 悬空的请求 —— 决策落库了、流程永远不动,而把请求推入僵尸态的那一步,正是把它推出 pending 的那一步。同时说明新巡检为什么用两个判据、为什么存储读不到时跳过而非判死、以及为什么只报告不改写(决策是真实发生过的,自动回滚会让审计与事实不符)。

content/docs/references/ 是自动生成的,未触碰。

3. 两份 changeset

#4502#4477 / #4466 的 changeset 已随该 PR 合入;这里补上剩下两份:

4. 把两处「filed separately」指向真正的 issue

flow-durable-suspend.dogfood.test.ts 的 KNOWN GAP 注释和上面那份 changeset 都告诉读者「该缺口已另行记录」却没给编号 —— 那是一个指向不存在之处的指针,恰恰是本分支想避免的那种过期记录。现在都指向 #4518bootStack({ databaseFile }) 的数据活不过进程内重启:表在、行没了,普通业务记录同样不保留,所以归因在 harness/驱动层而非挂起存储)。

纯注释/文本改动,无行为变化。


相关

关联:#4477 #4466 #4469 #4470 —— 这些 issue 已由 #4502 关闭,本 PR 不重复 Fixes

claude added 2 commits August 1, 2026 15:13
…he harness store (#4469, #4470)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017gEHJN2NFpS9VMeURvakgD
…e marker (#4477, #4466, #4469)

flows.mdx — a new subsection on the durable-pause seam, beside the existing
`$`-namespace rule it mirrors: a `screen` node's `config.fields` is a contract,
`resume` enforces it server-side with 400 `INVALID_SCREEN_INPUT`, `visibleWhen`
is evaluated against the submitted values so a hidden field's `required` never
fires, the refusal precedes consuming the suspension, and the three shapes that
declare no contract keep the pass-through. The pausing-node table's `screen` row
now says the inputs are validated rather than merely posted.

approvals.mdx — the admin-override callout now states the rule it actually
implements ("the actor is an admin", not "the slate is unstaffed"), which is why
`sys_approval_action.via_override` records which door the decision came through,
including why an admin who IS an approver records `false` and why a legacy row's
absent value reads as "not recorded". The dead-run callout gains the terminal
request shape its pending-only scan cannot see, and why the new inspection
reports rather than rewrites.

content/docs/references/ is generated and untouched.

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

vercel Bot commented Aug 1, 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 1, 2026 3:18pm

Request Review

claude added 2 commits August 1, 2026 15:17
Both the durable-suspend proof's KNOWN GAP note and the `@objectstack/verify`
changeset told the reader the harness persistence gap was "filed separately"
without naming it — a pointer to nothing, which is the shape of stale record
this branch exists to avoid. It is #4518.

Comment/changeset text only; no behaviour change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017gEHJN2NFpS9VMeURvakgD
@github-actions github-actions Bot added the tests label Aug 1, 2026
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

No hand-written docs reference the 0 changed package(s). ✅

@os-zhuang
os-zhuang marked this pull request as ready for review August 1, 2026 15:30
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 1, 2026
Merged via the queue into main with commit c2a1134 Aug 1, 2026
21 checks passed
@os-zhuang
os-zhuang deleted the claude/v17-flows-docs-and-changesets branch August 1, 2026 15:35
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