Skip to content

feat(spec)!: 重试策略的最后两种方言收敛到 RetryPolicySchema (#4964, #4962) - #5162

Merged
xuyushun441-sys merged 4 commits into
mainfrom
claude/issue-4964-retry-vocab-converge
Aug 4, 2026
Merged

feat(spec)!: 重试策略的最后两种方言收敛到 RetryPolicySchema (#4964, #4962)#5162
xuyushun441-sys merged 4 commits into
mainfrom
claude/issue-4964-retry-vocab-converge

Conversation

@xuyushun441-sys

Copy link
Copy Markdown
Contributor

Fixes #4964
Fixes #4962

按 2026-08-04 维护者裁决执行:A + 默认 0。方向不重议,本 PR 只落地。

为什么 #4661 漏掉了这两处

#4661 收敛重试策略,驱动它的是 dual-source 仪器,而那个仪器问的问题是「有几个声明共用同一个导出名」。另外两份同概念编码对它是构造性不可见的 —— 两者都是嵌在更大 schema 里的匿名内联 z.object,根本没有导出名可供冲突:

分歧 状态
job.retryPolicy / try_catch.retry #4661 已收敛
flow.errorHandling (#4964) 基础延迟拼作 retryDelayMs 本 PR
ETLPipeline.retry (#4962) 次数拼作 maxAttempts、默认 3、缺三个键 本 PR

仪器没坏,它精确回答了自己被问的那个问题;那个问题只是不等于大家从它身上读出的那个。而收敛完成之后,残存的方言读起来就像「被审视过并保留」。

这份分歧的代价,恰好落在做对了事的作者身上:shared/retry-policy.zod.tsretryDelayMs 立了墓碑、叫作者改写 backoffMs,而 flow.errorHandling 随即拒绝 backoffMs 并索要 retryDelayMs —— 读了较新的文件反而被惩罚。AI 作者先读到哪个文件是随机的,所以这是它最容易复现的路径。

改了什么

四个面现在全部从同一个 retryPolicyShape() 构建。

flow.errorHandling:只付 retryDelayMsbackoffMs 一个词。其余每个键、每个界、每个默认值本来就已经相同 —— 这正是它能存活一个大版本的原因:它看起来像被审过。strategy 留在外层(它决定策略是否运行,不是策略的一部分)。

ETLPipeline.retry:maxAttemptsmaxRetries(数字不变 —— 两者都数「初次之后」的重试;⛔ 不要减一,减一属于 integration/connector.zod.ts 里同名的 RetryConfig.maxAttempts,那个键含首次尝试,是另一个数)、默认 3 → 0、新增 backoffMultiplier / maxRetryDelayMs / jitter

默认值为什么定 0

不是「循 #4661 的先例」,是业务依据:ETL 的目的地按定义就是外部系统 —— 数仓、别人的 API、别人的库。对非幂等目的地的静默重试 = 重复写入:第二张发票、第二次导出、第二个 webhook。默认 0 让「重试」成为作者显式声明、并因此自证幂等的动作。而没写出来的键,恰恰是 LLM 写的 metadata 藏东西的地方。

迁移面

  • flow.errorHandling 是活的:retryExecution 读这个键(现已改读 backoffMs),retry-policy-converged D2 转换新增 flow 级分支覆盖存量,已部署行为不变。
  • ETLPipeline.retry 的迁移面今天是空的,这正是「现在做」的理由:etl.zod.ts 在三仓零 parse 站点(批 12 的测量),且 ETL pipeline 不是 defineStack collection,没有任何存量文档可供 walker 触达。所以它刻意不给 D2 步骤,只给墓碑 —— 写一个走不到任何东西的分支,就是在宣告一份并不存在的迁移覆盖度,而那正是本注册表该阻止、不该自己犯的 ADR-0049 错误。一旦 ETL 引擎落地,这个默认值翻转就从「改一份 schema」变成「改所有已部署管道的行为」。

验证

  • sabotage-red,四个断言类各自证伪:ETL 默认改回 3 → 只红「defaults」一条;flow 重新引入 retryDelayMs → 红「key set」+「tombstones」;摘掉 D2 flow 分支 → 红转换 fixture;删掉 maxAttempts 墓碑 → 红墓碑两条。
  • direct-parse probe 走 BUILT 产物,且负控先证红(首版 fixture 缺 type,探针在量错东西 —— 修正后才取信)。
  • 十个 spec check:* 全绿;pnpm test(spec 7757 + service-automation 665)、全仓 typecheck(124 包)、三个示例 app validate 全 0 退出。
  • 合并 main(12 个提交,含 dashboard widget compareTo:三个声明分支在 ADR-0021 dataset 路径上全部无效(两个静默丢弃,一个抛错) #5011 / 批 17 / 批 18)后全部重跑,并核对注册表两侧都在。

台账

flow / etl 两行只动叙述,strip 计数保持 1 和 3 不变 —— 两者都停在刻意的 wire floor,本 PR 是已关闭站点内部的词表变更,不是新的关闭。liveness flow.jsonretryDelayMs 按墓碑规则保留 dead 行(retiredKey 让键留在被遍历的 shape 里),并注明此处 dead 意为已退休而非从未被读 —— 它直到改名前一刻都是 live 的。

顺带修掉的两处 #4661 遗留

service-automation/README.mdcontent/docs/automation/flows.mdx 里两个 try_catchretry 示例仍写着 retryDelayMs。这是 #4661 改名时漏掉的文档,同一个键、同一次收敛;由「加宽该墓碑」的这个 PR 留着一份教人写墓碑拼法的文档会自相矛盾,故一并改正,未另开 issue。


🤖 Generated with Claude Code

https://claude.ai/code/session_01Ehu85kbvMcrNTUJjwxvLJ9


Generated by Claude Code

claude added 4 commits August 4, 2026 06:20
…ryPolicySchema (#4964, #4962)

#4661 converged the retry policy onto one declaration, driven by the
dual-source instrument — which asks "how many declarations share one exported
NAME?". Two further encodings of the identical concept were invisible to it by
construction, both anonymous inline `z.object`s with no exported name:
`Flow.errorHandling` (#4964) and `ETLPipeline.retry` (#4962). After a
convergence lands, a surviving dialect reads as reviewed-and-kept.

Both now build from `retryPolicyShape()` — one declaration of the key set,
bounds and defaults across all four surfaces.

flow.errorHandling: base delay `retryDelayMs` → `backoffMs`; every other key,
bound and default already matched, which is why it looked reviewed. The
`retry-policy-converged` D2 conversion gains a flow-level branch. Note the
divergence's real cost: `shared/retry-policy.zod.ts` tombstoned `retryDelayMs`
and prescribed `backoffMs`, and this block then REJECTED `backoffMs` — reading
the newer file was punished.

ETLPipeline.retry: `maxAttempts` → `maxRetries` (same number — do NOT subtract
one, that belongs to connector `RetryConfig.maxAttempts` which includes the
first attempt); default 3 → 0; gains backoffMultiplier/maxRetryDelayMs/jitter.
Default 0 on business grounds: an ETL destination is a foreign system by
definition, so an implicit retry against a non-idempotent one is a duplicate
write. No D2 branch, deliberately — an ETL pipeline is not a defineStack
collection and etl.zod.ts has no parse site in any of the three repos, so a
walker would advertise coverage that does not exist. The tombstone reaches the
only doors there are.

Both sites stay strict; 批 11/批 12 curation preserved and updated — the five
ETL entries that described the divergence dissolved with it.

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

- spec-changes.json / protocol-upgrade-guide.md / content/docs/references /
  skill refs: regenerated via check:generated --fix (only the 4 proved stale).
- liveness/flow.json: errorHandling.retryDelayMs → backoffMs (live), plus the
  `dead` tombstone row the retiredKey requires — it stays in the walked shape
  (rls.priority precedent). Note `dead` here means RETIRED, not never-read:
  the key was live in retryExecution right up to the rename.
- strictness ledger: flow/etl row prose records the convergence. Strip counts
  UNCHANGED (1 and 3) — both sit at deliberate wire floors and this is a
  vocabulary change inside already-closed sites, not a new closure.
- docs/automation/flows.mdx: errorHandling now documents backoffMs, plus the
  breaking-change callout. Also fixes two try_catch `retry` examples still
  spelling `retryDelayMs` (README + flows.mdx) — #4661 renamed the key but
  missed these two, and leaving them would teach a tombstoned spelling from
  the PR that widens the tombstone.
- changeset: major, FROM→TO for both spellings and the default change.

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

os-regen deferred spec-changes.json + protocol-upgrade-guide.md (both are
object arrays, where git's textual merge is not trustworthy). Rebuilt spec and
regenerated; verified BOTH sides survive — #5011's dashboard-widget compareTo
rows and this branch's retry-policy rows are all present, and the branch delta
vs main is exactly this PR's two entries.

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

vercel Bot commented Aug 4, 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 4, 2026 7:17am

Request Review

@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation tests tooling labels Aug 4, 2026
@github-actions

github-actions Bot commented Aug 4, 2026

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 @objectstack/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/http-protocol.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/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.

@xuyushun441-sys
xuyushun441-sys marked this pull request as ready for review August 4, 2026 07:31
@xuyushun441-sys
xuyushun441-sys added this pull request to the merge queue Aug 4, 2026
Merged via the queue into main with commit 4845f85 Aug 4, 2026
25 checks passed
@xuyushun441-sys
xuyushun441-sys deleted the claude/issue-4964-retry-vocab-converge branch August 4, 2026 07:43
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/l tests tooling

Projects

None yet

2 participants