Skip to content

fix(spec): OpenAPI components.schemas 不再是空的 —— lazySchema Proxy 撞上 typeof === 'object',并补上产物自洽门禁 - #5459

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-5168-openapi-components
Aug 5, 2026
Merged

fix(spec): OpenAPI components.schemas 不再是空的 —— lazySchema Proxy 撞上 typeof === 'object',并补上产物自洽门禁#5459
os-zhuang merged 2 commits into
mainfrom
claude/issue-5168-openapi-components

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #5168

前提复核(基线已前移)

单子写的基线是 81e2744,现已前移到 ed0d2aac0;#5293 昨日动过 build-openapi.ts(退役 HttpServerConfigSchema)。逐条对 origin/main 复核,前提完全成立:

  • 判据行仍在 packages/spec/scripts/build-openapi.ts:255,一字未动;
  • 对照实验在当前 origin/main 上复现,唯一变量是 Proxy:
$ npx tsx scripts/build-openapi.ts                    -> Components: 0
$ OS_EAGER_SCHEMAS=1 npx tsx scripts/build-openapi.ts -> Components: 9
  • 6 个悬空 $ref 与单子列的完全一致:ApiError / CreateRequest / DeleteResponse / ListRecordResponse / SingleRecordResponse / UpdateRequest,defined schemas: [];
  • 运行时探针确认判据是第一段短路,不是第二段:typeof'function',而 '_zod' in schematrue

改动一:放宽判据(建议 1)

判据同时接受 'object''function'lazySchema 不需要改动 —— 它专门维护了 _zod facade 供 toJSONSchema 遍历,判据的第二段对 Proxy 本来就有效。

改动二:产物自洽门禁(建议 2)

生成器在写盘之前自检两条,任一不满足即非零退出,自恰不了的文档根本不会被写出来(红臂实测:失败时 json-schema/openapi.json 未被创建):

  1. 每个本地 $ref 必须解析得到 —— 按 JSON Pointer 解析而非按 #/components/schemas/ 前缀匹配,将来新增的 #/$defs/... 引用自动覆盖;报错逐条点名悬空 $ref 及其文档位置,并把「已定义 schema 列表」一并打出(哪一侧是空的是读者最先需要的信息)。
  2. 没有 schema 被静默降级 —— 九个契约 schema 是一张字面清单,某个名字没产出永远是缺陷。原循环写成 if (像 zod) { 收 }没有 else,正是这个静默跳过的形状让九次跳过发布成了空文档;现在声明即强制。z.toJSONSchema() 抛错时原先塞一个 {type:'object'} 占位冒充契约,同样改为响亮失败(当前九个全部干净转换,零占位)。

接线点选择(实测后定):接在生成器内部,不做独立 check: 脚本。因为 packages/spec/json-schema/.gitignore:61、每次 pnpm build 重新生成 —— 独立检查脚本无论如何都要先跑一次生成器才有东西可查。「产物自洽」这类断言不需要任何基线快照,比「产物最新」更便宜。

关于「提交 json-schema/openapi.json

做不到,也不该做:该目录是 gitignore 的,产物不入库,由 pnpm build(gen:schema && gen:openapi && tsup)每次重新生成,并通过 files + exports 随包发布。所以本 PR 不含产物文件;真实 pnpm --filter @objectstack/spec build 产出的结果已在报告与下方 tests 中附上(components: 9,DANGLING: NONE)。

typeof === 'object' 普查结果(只报告,未改)

没有第二处'_zod' in 这个成员测试全仓仅此一处。其它生成器用的是 instanceof z.ZodType(仅 build-schemas.ts),而实测 instanceof 对 Proxy 返回 true —— 即这个惯用法是 Proxy 安全的,不存在同类隐患。另外 build-schemas.ts / build-react-blocks-contract.ts / check-liveness.mts / check-variant-docs.mts / check-react-blocks-declaration-parity.ts 都在文件顶部设了 OS_EAGER_SCHEMAS=1,build-openapi.ts 是唯一没设的 —— 本 PR 让它对 Proxy 直接免疫,比依赖环境变量更稳。

packages/rest 侧:仅注释,无行为改动

三处以现在时陈述「components.schemas 是空的」的注释被本 PR 证伪,已按事实更新(openapi-endpoints.ts 一处、openapi-endpoints.test.ts 两处)。行为与断言一字未改:声明式端点的 enrichment 仍然只写 type: object 而不编造 $ref —— 理由从「components 是空的」修正为「九个契约 schema 是通用 CRUD 信封,不是某个具体对象的 body 形状」,结论不变。

越范围发现

已立 #5456(finding,未认领、未进 pm:queue):base spec 用 7 条手写 path 描述路由面,与 rest 真实路由无任何对账,漂移了不会红 —— 即 check:generated ledger 里 gen:openapi 那条 why 真正说的那件事(本 PR 补的是自洽,不是对账)。实测当前未漂移,故为休眠缺口。该单顺带澄清:「最新性门」(单子建议 3)在这里没有对象,因为产物不入库,没有入库快照可以变陈旧 —— 建议按「对账」而非「最新性」定级。


Generated by Claude Code

@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 12:48pm

Request Review

@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation tests tooling 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/rest.

11 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/connect-mcp.mdx (via @objectstack/rest)
  • content/docs/api/error-handling-server.mdx (via @objectstack/rest)
  • content/docs/api/index.mdx (via @objectstack/rest)
  • content/docs/permissions/authentication.mdx (via @objectstack/rest)
  • content/docs/plugins/index.mdx (via @objectstack/rest)
  • content/docs/plugins/packages.mdx (via @objectstack/rest)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/rest)
  • content/docs/protocol/kernel/i18n-standard.mdx (via packages/rest)
  • content/docs/releases/implementation-status.mdx (via @objectstack/rest)
  • content/docs/releases/v12.mdx (via @objectstack/rest)
  • content/docs/releases/v17.mdx (via @objectstack/rest)

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.

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

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

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

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

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

    �[41m�[1m FAIL �[22m�[49m src/commands/serve-email-config-parity.contract.test.ts�[2m > �[22mEmailServiceConfigSchema ↔ resolveEmailCapabilityArg�[2m > �[22mreads every key it declares, but for the fi
    

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 5 个失败构建(不含本次)。

分诊清单:

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

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

Copy link
Copy Markdown
Contributor Author

分诊(spec 车道 PM):第 3 型 —— 同批连坐,非本 PR 回归,非 flaky,不需人工重排。

失败测试 serve-email-config-parity.contract.test.ts 不存在于本 PR 的改动里 —— 它来自同批排在前面的 #5465(本次构建链在其推测合并之上)。根因与处置见 #5465 的分诊评论(与已合入的 #5470 语义冲突,#5465 已出队修复中)。

已核实:队列已自动将本 PR 重建到纯 main(cd2efe62a)之上(队列分支 pr-5459-cd2efe62a… 在),等待其自然落地即可。给 flaky 检索者:这次失败不要计入该测试的 flaky 记录。


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/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

发布出去的 OpenAPI 文档 components.schemas 是空的,而 6 个 $ref 全部悬空 —— lazySchema Proxy 撞上 typeof === 'object' 判据

2 participants