Skip to content

feat(spec)!: converge RetryPolicy onto one declaration (#4661, C8) - #4670

Merged
os-zhuang merged 5 commits into
mainfrom
claude/issue-4661-retry-policy-dual-source
Aug 2, 2026
Merged

feat(spec)!: converge RetryPolicy onto one declaration (#4661, C8)#4670
os-zhuang merged 5 commits into
mainfrom
claude/issue-4661-retry-policy-dual-source

Conversation

@os-zhuang

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

Copy link
Copy Markdown
Contributor

Fixes #4661

按维护者在 #4661 的裁决实施:路线 C1(收敛为能力并集,backoffMs 作为唯一基础延迟拼法)、正典默认值 maxRetries: 0 / backoffMultiplier: 1、约束取 max(10) / min(1) / min(0)。基线 22 → 20

已合入 main(#4664)并全套复验通过 —— 见 §10。


1. 四仓 import 语句级扫描:两侧都活,无死侧

RetryPolicySchema / RetryPolicy 的 import 说明
cloud / cloud-v1 / objectui 0 org code search 对 RetryPolicySchema 排除本仓后 total_count: 0
objectstack 本仓 0 直接 import 该符号 但两侧各有真实执行方,按属性名读

零 importer 不等于有死侧(#4653 已立此规矩)。两侧都被执行器按属性名消费:

2. 立单前提修正:automation 侧的可达机制与立单描述不同(结论更强)

立单说 automation 侧「经 retry:FlowSchema」。静态 $ref 图上不成立:flow.zod.ts:163configz.record(z.string(), z.unknown())(开放 record),TryCatchConfigSchemaflow.zod.ts 里一次都没被引用。

C8 判 ✅ 可达是靠 system 侧成立的:BUILTIN_METADATA_TYPE_SCHEMAS.job = JobSchemaJobSchema.retryPolicy

但实质结论更强:automation 侧经节点 config 缝被作者真写、被执行器真解析,而 TryCatchConfigSchema 不是 .strict() —— 掉一个 key 就是 Zod 静默吞掉作者写的值。所以 tombstone 是硬要求,已照做。

3. 两侧形状 diff(automation 5 key / system 3 key)

FROM ./automation FROM ./system TO(两个入口)
基础延迟 retryDelayMs,min 0,default 1000 backoffMs,positive,default 1000 backoffMs,min 0,default 1000
maxRetries 0–10,default 0 ≥0 无上限,default 3 0–10,default 0
backoffMultiplier 1,default 1 positive,default 2 1,default 1
maxRetryDelayMs default 30000 (无) default 30000
jitter default false (无) default false
RetryPolicy 类型 z.input z.infer z.input(新增 RetryPolicyParsed 承载 z.infer)

并集不可能无损:retryDelayMsbackoffMs 是同一概念的两个拼写(两侧退避公式与两个执行器实现完全一致),同时声明两者就是 alias 反模式。所以必然丢一个 key —— 这是本 PR 唯一的可作者化损失。

4. 为什么是 backoffMs,以及为什么声明放在 shared/

拼法选 backoffMs 的证据(不是偏好):

声明落在新文件 packages/spec/src/shared/retry-policy.zod.ts,且刻意不进 shared/index.ts 关键机制:发布的 def key 形如 入口命名空间/名字,由哪个入口 barrel 再导出决定(build-schemas.ts 遍历命名空间对象)。因此一份声明被 ./automation./system 同时再导出时,两个 def key 都存活且 key 集合相同 —— 这正是本簇只付 1 个 key 而不是 8 个的原因。不进 shared/index.ts 是为了避免多出第三个 shared/RetryPolicy def 和 5 行纯噪音(retired-key.ts / strict-object.ts 同样不进 barrel,有先例)。放 shared/ 而非任一域:control-flow.zod.ts 会拉进整个 flow.zod 节点图,不该为一个 5 字段策略把它塞进 system/job.zod.ts

5. 消失的 key:1 个,tombstone + conversion 证据

authorable-surface.json 相对 main完整 diff(由 gen:schema 重写,未手编):

+    "automation/RetryPolicy:backoffMs",
-    "automation/RetryPolicy:retryDelayMs",
+    "automation/RetryPolicy:retryDelayMs [RETIRED]",
+    "system/RetryPolicy:jitter",
+    "system/RetryPolicy:maxRetryDelayMs",
+    "system/RetryPolicy:retryDelayMs [RETIRED]",

零 key vanish —— 唯一的删除行是 retryDelayMs 改标为 [RETIRED]system/RetryPolicy:retryDelayMs [RETIRED] 是新增的「生而退休」key(同一声明),检查 (b) 只对 live → retired 触发,故不受影响;它的效果是好的:从 flow 抄了 retry 块的 job 作者会拿到明确处方。

⚠️ 关于 #4659:我核实过 surface 真的对上,没靠 leaf-name 巧合

检查 (b) 把 surface 按 / 切开后做 endsWith('.' + leaf),任何以 .retryDelayMs 结尾的无关 clause 都能蒙混过关。我枚举了 ALL_CONVERSIONS 的全部 clause,合并 #4664 之后重跑:

total conversions: 40 | total clauses: 72
clauses ending in ".retryDelayMs":
  - retry-policy-converged  ->  flow.node.config.retry.retryDelayMs
MATCH COUNT: 1
  [extractQuery] -> mapping-inert-keys-removed
  [errorPolicy]  -> mapping-inert-keys-removed
  [batchSize]    -> mapping-inert-keys-removed
  [includeAll]   -> app-dead-authoring-keys-removed
  [placement]    -> app-dead-authoring-keys-removed

全仓仅 1 条匹配,就是本 PR 的,且 flow.node.config.retry.retryDelayMs 字面上就是 automation/RetryPolicy:retryDelayMs 所在的位置 —— try_catch 节点 config 里的 retry 区域。不是巧合匹配。#4664 新引入的五个退休 leaf 各自对上自己的 conversion,与本簇零交叉。

6. 默认值:conversion 把「静默翻转」变成「零行为变化」

本 PR 最容易被下游误读的一点,changeset 里已显式写明。

正典默认值取 automation 现值(maxRetries: 0 / backoffMultiplier: 1)。单看这一步会让存量 job 静默停止重试,所以 retry-policy-converged conversion 把 pre-17 的数值显式写进每个省略了它们的存量 job.retryPolicy:

// before                    // after `os migrate meta --from 16`
{ "backoffMs": 5000 }        { "backoffMs": 5000, "maxRetries": 3, "backoffMultiplier": 2 }

已部署的栈行为完全不变;改变的只是新写的省略是什么意思(= 不重试)。理由采纳裁决:重试会重放已经发生的副作用(job handler 的写入与外呼、try 区域的副作用),隐式重放是测试最难捕获、生产代价最高的失败模式;同一读法在 flow-retry-max-retries-required(#4247)已有先例。

两个 walker 都是先验证再用,不是假设:mapCollection(stack, 'jobs', …)(jobs 确认是 bundle 集合键,app-plugin.ts:799-802)与 mapFlowNodes(递归进 config.body.nodes)。fixture 覆盖三种 job(省略两者 / 都写了 / 无 retryPolicy 块)与两种 try_catch(旧拼写 / 已正典),expectedNotices: 3

约束收紧(maxRetries 上限 10、backoffMultiplier 下限 1)无无损改写,故登记为 semantic 迁移条目 job-retry-policy-constraints-tightened,而非伪造 conversion。乘数小于 1 描述的是逐次变短的延迟 —— 对失败的依赖越重试越快,与 backoff 相反。

7. Sabotage 验证(#4642:pin 必须是运行时断言且必须证明会红)

回归 pin 在 packages/spec/src/shared/retry-policy.test.ts,用运行时模块命名空间断言(不是编译期条件类型 —— 该包 tsconfig exclude**/*.test.ts,vitest 未开 typecheck,编译期 pin 空转)。

Sabotage A —— 让 system 重新自带一份声明(即回到双源):

 × ./automation and ./system export the SAME RetryPolicySchema object
 × both entries re-export the canonical shared declaration
 × publishes exactly the converged key set from both entries
 × keeps the `retryDelayMs` tombstone loud from both entries
 AssertionError: expected [Function] to be [Function] // Object.is equality
 Tests  4 failed | 4 passed (8)

Sabotage B —— 只把 maxRetries 默认值从 0 改成 3(一个字符)。这条同时是 #4666 的证据:

$ pnpm check:authorable-surface
✅ Generated bundled schema: objectstack.json (1686 definitions)
✅ Successfully generated 1703 schemas.          ← 门禁全绿

$ npx vitest run src/shared/retry-policy.test.ts
 × pins the opt-in defaults that no gate can observe
 AssertionError: expected 3 to be +0 // Object.is equality
 Tests  1 failed | 7 passed (8)                  ← 只有 pin 抓住了

即:默认值翻转对门禁完全不可见,唯一的补偿控制是这个手写 pin。已按裁决单独立案 #4666(unassigned,未修)。

Sabotage B 在合并 #4664 之后重跑,仍然红(见 §10)。两个 sabotage 均已还原,git status 干净。

8. 也顺手修好的既有缺陷

config-schemas.test.ts 的 try_catch 断言从不检查基础延迟这个 key,而 control-flow-form-zod-ledger.test.ts 只比对顶层 config key(try/catch/errorVariable/retry)—— 所以嵌套的 retry 子键改名两个 parity 测试都不会红。已补上 backoffMs 存在 + retryDelayMs 不存在的断言,把这个缝堵上。

严格性台账已同步:automation/ 88 → 87 sites,control-flow.zod.ts 6 → 5,并在 Note 里写明该 site 去了哪、以及该台账只 section 了 ui//data//automation//security//studio/,shared/ 不在其覆盖范围(既有 scoping 选择,非本 PR 造成,但值得维护者知道)。

文档侧顺带消掉了一个既有混淆:原先 references/automation/job.mdxreferences/system/job.mdx 两页都叫 Job、各自文档一个形状不同的 RetryPolicy,现在是同一形状的 retry-policy.mdx 两页。

9. 与 #4664 的语义边界

17.0.0 同窗退休的 mapping.errorPolicy 的取值里有 'retry',读者可能误以为要迁到 retryPolicy不是 —— 它是另一个类型上的惰性枚举,处方指向「import REQUEST 自己的 options」,与本簇零关系。已在 changeset 里单列一节说明,避免误读。

10. 合并 main(#4664)与复验

main 走到 5966c2abe(#4664,又一个 spec 退休 PR),与本分支在 5 个文件相撞。处置:

合并后全套重跑(不是只跑 build):

命令 合并后结果
pnpm build(spec,含 BUILD_DTS)
check:dual-source-exports 4314 names across 16 entry points — 163 re-exported (single declaration), **20** accepted dual-source (baseline)
check:generated All 8 generated artifacts are up to date.
pnpm test(spec) 292 files / **7310** tests passed
check:liveness
check:strictness-ledger 67 file(s) across 5 triaged director(ies) — site counts match, section totals balance
check:empty-state
check:variant-docs
check:exported-any 1886 types + 1638 schemas
check:skill-examples 202 prose examples type-check
service-job test 5 files / 39 tests
service-automation test 53 files / 649 tests
conversion fixture retry-policy-converged: before → after, emits 3 notice(s)
#4659 surface 唯一性复核 MATCH COUNT: 1(见 §5)
Sabotage B 复跑 ✅ 仍然红(expected 3 to be +0)
全仓 pnpm typecheck Tasks: 122 successful, 122 total(0 条 error TS,exit 0)

service-job / service-automation 首轮曾因 @objectstack/platform-objects / @objectstack/core / @objectstack/formula 在新 worktree 里没 dist 而解析失败(与本改动无关);构建这三个依赖后全绿。

.changeset/pre.json 仍是 mode: pre / tag: rc,major 通道未关闭,本簇赶在 changeset pre exit 之前。

⛔ 未触碰 content/docs/releases/。PR 保持 draft

`@objectstack/spec/automation` and `@objectstack/spec/system` both exported
`RetryPolicySchema` / `RetryPolicy` resolving to DIFFERENT declarations, so the
shape a consumer got depended only on the import path (the #4411 trap). They
were never two concepts: the `try_catch` node's `retry` region and
`job.retryPolicy` both compute `delay = base * multiplier^(retry-1)`, and both
executors implemented that identical formula.

One declaration now lives in `shared/retry-policy.zod.ts`, re-exported by both
entries, carrying the union of what the two sides could express. Because the
published def key is derived from the entry namespace, both
`automation/RetryPolicy` and `system/RetryPolicy` survive with an identical key
set — so the convergence costs exactly ONE authorable key instead of eight.

Authorable surface: `automation/RetryPolicy:retryDelayMs` is the single
casualty, TOMBSTONED (`retiredKey`) rather than deleted because neither owning
schema is `.strict()` — a plain removal would have Zod swallow the authored
number and silently fall back to the 1000ms default.

Defaults are the half no gate can see: the authorable-surface ratchet compares
key sets, and a default is not a key. `job.retryPolicy` defaulted
`maxRetries: 3` / `backoffMultiplier: 2` where automation defaulted 0 / 1. The
merged declaration takes 0 / 1 (retry replays side effects, so it is opt-in),
and the `retry-policy-converged` conversion writes the pre-17 numbers explicitly
into every existing `job.retryPolicy` that omitted them — deployed stacks keep
their exact behaviour; only a newly authored omission changes meaning. Filed
separately as #4666 (gates are blind to default/constraint changes).

`job.retryPolicy` gains `maxRetryDelayMs` and `jitter`, both now enforced in
`runWithPolicy` rather than merely declared (ADR-0049).

Baseline: 22 -> 20.

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

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

Request Review

claude added 2 commits August 2, 2026 15:51
#4664 (spec key retirements + doc.tags) landed on main and touched the same
five files. Resolution:

- authorable-surface.json / spec-changes.json / docs/protocol-upgrade-guide.md
  REGENERATED from source (gen:schema / gen:spec-changes / gen:upgrade-guide),
  never hand-merged — hand-editing the authorable surface is forbidden (#4650).
  The regenerated surface differs from main by exactly this branch's delta:
  `automation/RetryPolicy:backoffMs` added, `:retryDelayMs` relabelled
  [RETIRED], and system/RetryPolicy gaining jitter / maxRetryDelayMs / the
  tombstone.
- conversions/registry.ts auto-merged; verified 40 entries, zero duplicate ids,
  every declared conversion grouped, both `mappingInertKeysRemoved` (#4664) and
  `retryPolicyConverged` (#4661) present in the major-17 block.
- migrations/registry.ts hand-resolved: both sides appended a paragraph to
  step17's `rationale` and an entry to `conversionIds`. Kept both. #4664's
  paragraph ended the string literal, so the concatenation was repaired and this
  branch's opener reworded ("Finally" -> "The same window") to avoid two
  "Finally"s in one rationale.

Re-verified after the merge that exactly ONE conversion clause still ends in
`.retryDelayMs` and it is `retry-policy-converged` — #4664 added five retired
leaves (extractQuery / errorPolicy / batchSize / includeAll / placement), none
of which collide with this cluster under the #4659 leaf-name match.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M9uWvoEp9CoLzYjNExj9sL
…y convergence

#4664 retires `mapping.errorPolicy` in the same 17.0.0 window and its values
included 'retry', so a reader could plausibly assume it migrates into a
`retryPolicy` block. It does not — different type, inert enum, and its own
prescription points at the import REQUEST's options.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M9uWvoEp9CoLzYjNExj9sL
@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:system tests tooling size/l labels Aug 2, 2026
@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/service-automation, @objectstack/service-job, @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/service-job, @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/service-job, @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/service-job, @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.

生成物冲突以三路集合合并解决(等价于重新生成),手写登记表以
base→ours 的 hunk 打到 main 版上,双方条目均保留:

- dual-source-exports.baseline.json: 22 → 19(C8 去 RetryPolicy ×2,
  main 的 #4662 去 ActivationEventSchema ×1)
- conversions/registry.ts: retryPolicyConverged 与 main 的
  objectManagedBySystemToSystemData 同时注册
- migrations/registry.ts: job-retry-policy-constraints-tightened 保留
- protocol-upgrade-guide.md: 两侧表格行都保留

未跑本地全套门禁 —— 由 CI 的 check:generated 验证生成物确实等于
重新生成的结果,这是与维护者商定的快路径(main 上 spec PR 密度使
本地十几分钟的门禁跑完即过期)。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M9uWvoEp9CoLzYjNExj9sL
@os-zhuang
os-zhuang enabled auto-merge August 2, 2026 16:27
上一个合并提交用集合合并解决 spec-changes.json 的冲突,但该文件是
对象数组而非字符串数组,集合合并退化成「取变了的那一侧」,丢掉了
main 侧 #3355 的 object-managed-by-system-to-system-data 条目,
check:spec-changes 因此报 stale。

改为真的跑 gen:spec-changes(+ gen:upgrade-guide 确认无漂移)。
现三条条目齐备:retry-policy-converged、
object-managed-by-system-to-system-data、
job-retry-policy-constraints-tightened。

check:spec-changes / check:upgrade-guide / check:skill-docs 均绿。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M9uWvoEp9CoLzYjNExj9sL
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 protocol:system size/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

spec 双源清账 C8:RetryPolicy / RetryPolicySchema(./automation ≠ ./system)—— 2 条

2 participants