Skip to content

fix(spec): automation/etl.zod.ts 的九个别名回到 X / XParsed house convention (#4963) - #5514

Merged
os-zhuang merged 4 commits into
mainfrom
claude/issue-4963-etl-parsed-aliases
Aug 5, 2026
Merged

fix(spec): automation/etl.zod.ts 的九个别名回到 X / XParsed house convention (#4963)#5514
os-zhuang merged 4 commits into
mainfrom
claude/issue-4963-etl-parsed-aliases

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #4963

裁定按认领评论取 A,一次做完:裸名翻转为 z.input(作者写的形状),新增九个 *Parsed = z.infer(parse 之后的形状),两个 factory 回归设计意图,SYNC_ARCHITECTURE.md 两段示例修到可编译。

前提复核(先证,再改)

九个别名现状 —— origin/main 上确认九个全是 z.infer 且零 *Parsed 对应物,issue 描述属实。

三仓零 importer —— 三个仓都先 git fetch,再对各自 origin/maingit -C 复测(不用 cd):

origin/main HEAD ETL 符号命中
objectstack 0285f7f99 packages/spec/src/automation/etl.{zod,test}.ts 自身 + 文档/changeset/生成物;etl.test.ts 只 import schema,不 import 任何类型别名
objectui 4ed825077 0
cloud 71554418 0

两个 sibling 仓均有权限,无需退回本仓证据。迁移面为空。

为什么这不是纯风格问题(实测,不是目测)

本文件六个键带 .default(),外加 scheduleCronExpressionInputSchema(transform,输出是 { dialect, source } 信封)。在 z.infer 下这些全部必填、裸 cron 字符串被拒。把翻转前的 etl.zod.ts 放回、只留新测试跑一遍,编译器报的就是这些:

doc-example-0:
  TS2741: Property 'continueOnError' is missing in type '{ type: "join"; ... }'   (x3)
  TS2322: Type 'string' is not assignable to type '{ dialect: "cel" | "cron" | "template"; ... }'
author-source:
  TS2741: Property 'enabled' is missing in type '{ cursorField: string; }'
author-destination:
  TS2741: Property 'writeMode' is missing in type '{ type: "database"; config: { table: string; }; }'
author-run:
  TS2739: Type '{}' is missing the following properties ...: recordsRead, recordsWritten, recordsErrored, bytesProcessed

翻转后全部为空。

改了什么

  1. 九对别名(packages/spec/src/automation/etl.zod.ts)。裸名 = z.input,新增九个 *Parsed = z.infer。四个 enum 别名(ETLEndpointType / ETLTransformationType / ETLSyncMode / ETLRunStatus)两者同型,仍然成对 —— 理由写在文件里:约定的价值就是读者不必先知道九个里哪个带默认值才能选注解,而一个 enum 日后加 .transform() 就会重开这个 issue。ETLPipelineRun 是 wire 形状,也照同一条规则走,与 automation/ 里另一个 wire 形状 FlowVersionHistory 一致。
  2. 两个 factory 回归设计意图。删掉 enabled: true(纯粹在复述 schema 自己的默认值,只因 z.infer 让键必填才写);schedule 直接透传,不再 typeof s === 'string' ? { dialect: 'cron', source: s } : s 预包装 —— 归一化本来就该在 parse 时发生。保留各自的 syncMode / writeMode:那是两个 helper 各自决定的东西(incremental+upsert vs full+append),这组对比正是这对 helper 存在的理由,读者不该为看懂它去查两个默认值。
  3. SYNC_ARCHITECTURE.md。三段 ETLPipeline 示例全部修到可编译并以「作者形状」示范(默认键省略)。issue 说翻转后「只剩 source.config 必填一个错误」—— 对 "After (L2)" 成立,对 "Before (L2)" 不成立:那段还缺 namedestination(两个都是必填、与默认值无关),一并补齐。
  4. strictness 台账(docs/audits/2026-07-unknown-key-strictness-ledger.md)。etl.zod.ts 行的"仍未关闭"尾巴改为已关闭,并记下这批分类留下的教训:「因为导出的类型就是授权门,所以是 authorable」是一个需要编译验证的断言,不是可以假定的事实 —— 批 12 门读对了,没人编译过。
  5. 生成物:gen:api-surface 整体重生成,+9 −0,无手改。

测试

新增 packages/spec/src/automation/etl-author-shape.test.ts,走 compiler API 而不是类型级 pin —— #4642 已经确认 packages/spec 里的条件类型 pin 是 no-op(tsconfig.json 排除 **/*.test.ts,vitest 从不开 typecheck),所以 @ts-expect-error / expectTypeOf 在这个包里没人读。测试自带 anti-vacuity 守卫,含一个必须报错的 harness-self-test 探针,否则解析失败会表现为「三段示例全绿」。

  • SYNC_ARCHITECTURE.md 的三段 ETL 示例逐字编译(含 import 行,@objectstack/spec/automation 通过 paths 映射到 entry barrel),零诊断。块总数钉死为 6,新增块必须显式分类。
  • 同一份字面量在 ETLPipeline 下编译通过、在 ETLPipelineParsed 下必须红 —— 正负共用一份文档,所以红不可能是「字面量因为别的原因坏了」。
  • 顶层默认键单独一支:除 syncMode / enabled 外全部补齐的字面量,在 ETLPipelineParsed 下必须报 TS2739 并点名这两个键。(合并在上一支里做不到:TypeScript 只报它找到的最深层不匹配就停,嵌套的 writeMode / continueOnError 会把顶层两个键完全遮掉。)

反向验证的方向,是在跑之前先定的,结果分两类,如实报告:

  • 常规红:把翻转前的 etl.zod.ts 放回,author-* 探针和三段文档示例全红(诊断见上)。这一半按预期成立。

  • 红得不是地方:同一次回退里,parsed-* 探针报的是 TS2305: Module '"@objectstack/spec/automation"' has no exported member 'ETLPipelineParsed' / TS2724 … Did you mean 'ETLDestinationParsed' → 'ETLDestination'? —— 名字根本不存在,红是红,但和「方向对不对」无关,不构成证据。所以另做了一次真正的 sabotage:实现打上之后,单把 ETLPipelineParsed 指向 z.input,预期这三条 pin 转红且报「本该有诊断却是空的」。实测:

    × rejects the same pipeline literal under `ETLPipelineParsed`
        AssertionError: expected '' to contain 'writeMode'
    × requires `syncMode` and `enabled` on `ETLPipelineParsed` — the top-level defaults
        AssertionError: expected '' to contain 'TS2739'
    × accepts a bare cron string only on the author side
        AssertionError: expected '' to contain 'Type \'string\' is not assignable'
     Test Files  1 failed (1)
          Tests  3 failed | 13 passed (16)
    

    这才是 parsed 半边的 pin 是活的的证据。改回后 16/16 绿。

命令与结果(合并 origin/main 之后重跑):

pnpm --filter @objectstack/spec typecheck        → tsc --noEmit,无输出
pnpm --filter @objectstack/spec test             → Test Files 313 passed (313)
                                                   Tests 7978 passed (7978)
pnpm --filter @objectstack/spec check:generated  → All 9 generated artifacts are up to date
pnpm --filter @objectstack/spec check:dual-source-exports
                                                 → 4197 names / 0 accepted dual-source
pnpm --filter @objectstack/spec check:exported-any
                                                 → 1822 types + 1560 schemas,无 any
pnpm check:doc-authoring / check:docs-audit-scope / check:type-check-coverage
  / check:release-notes / check:nul-bytes        → 全绿
eslint packages/spec/src/automation/etl{.zod,-author-shape.test}.ts → 无输出

packages/spec/api-surface.json 相对 origin/main 的 delta:+9 类型,0 移除

范围外发现

未做的事

SYNC_ARCHITECTURE.md 的三段 L3 Connector 示例不在本 PR 的编译门内 —— 它们属于 integration/connector.zod.ts,其中两段用裸 ... 做省略(不是 TypeScript)。测试里把块总数钉死,就是为了让这条豁免不能悄悄扩大。

🤖 Generated with Claude Code

https://claude.ai/code/session_018fxLGQdatPbBUvCgiVxg6D


Generated by Claude Code

claude added 2 commits August 5, 2026 14:26
…ention (#4963)

裸名翻转为 `z.input`(作者写的形状),新增九个 `*Parsed` = `z.infer`(parse 之后的
形状),与 `shared/retry-policy.zod.ts` 记下的 house convention 一致。

翻转之前九个别名全是 `z.infer`,而本文件有六个带 `.default()` 的键,外加
`schedule` 是 `CronExpressionInputSchema` transform —— 于是
`const p: ETLPipeline = { … }`(三仓零 parse site,这就是本文件唯一的授权门)
根本编译不过。SYNC_ARCHITECTURE.md 的三段示例就是证据,同 PR 修到可编译并加
compiler-API 测试逐字编译它们。

两个 ETL factory 去掉为满足自身返回类型而写的 `enabled: true` 与 cron 预包装。

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

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

Request Review

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

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

109 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/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/tenancy-modes.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/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/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/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/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/apps.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.

Copy link
Copy Markdown
Contributor Author

范围外发现补记 —— #5515

PR body 的「未做的事」里写了 L3 Connector 示例不在本 PR 的编译门内。既然探针已经在手,顺手量了一次,结果值得单独记:那段不是因为 ... 省略而不可编译,它是完整字面量,报四条诊断,其中三条是写了 schema 会拒收的键名/取值:

  • fieldMappings[].sourceField / targetField → schema 是 source / target(shared/mapping.zod.ts:101)。而且 sourceField 是挂了 curated alias 的被拒键 —— connector.test.ts:1028 明写 // a real alias, deliberately: the message must name it
  • transform.type: 'custom' → 枚举只有 map / lookup / constant / cast / javascript
  • webhooks[].retryPolicyWebhookConfigSchema 没有这个键。

第四条是 cron 字符串被拒,根因和本 issue 同款:connector.zod.ts:742Connectorz.infer(该文件用的是第三种命名 ConnectorInput,不是 house convention 的 XParsed)。但那边迁移面不为空(20 个 z.infer 裸名别名,且在 live parse path 上),不能照搬本 PR「零 importer 所以一次做完」的路线,所以没有顺手带进本 PR。

已 file 为 #5515(未打标签,交 PM triage)。本 PR 里把该文档 ```typescript 块总数钉死为 6,就是为了让 L3 那三段进不进门是一个必须显式做的决定。


Generated by Claude Code

原文写「六个键」却列了五个具名键 + 一整个 retry 块,内部不自洽;改为逐类点名
(五个具名键 + retry 的五个 + stats 的四个),不再给一个含混的总数。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018fxLGQdatPbBUvCgiVxg6D
原注释说三段 L3 块「两段用 ... 省略」,读起来像第三段没问题;实测第三段
(sapConnector)是完整字面量、报四条诊断,其中三条写的是 schema 会拒收的
键名/取值。已 file 为 #5515,注释直接点名,免得下一个读者以为那是已审阅的豁免。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018fxLGQdatPbBUvCgiVxg6D
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