Skip to content

ApiEndpointSchema 在 #5312 把 api 注册成元数据类型之后仍是开放 z.object —— apis: 条目的未声明键两条路都静默落地,严格性账本还把 api/ 整目录记作「wire,按设计宽容」 #5384

Description

@baozhoutao

#5000 的核实工作里撞到的(给 CLI 的元数据门写 pin 测试时,逐类型扫到 api)。

事实

#5312(实现 #5271/#5206)把 api 补进了 DEFAULT_METADATA_TYPE_REGISTRYBUILTIN_METADATA_TYPE_SCHEMAS,api: ApiEndpointSchema。但 ApiEndpointSchema 本身是 z.object({...}),没有 .strict()(packages/spec/src/api/endpoint.zod.ts:56),而 stack 根部 apis: z.array(ApiEndpointSchema)(packages/spec/src/stack.zod.ts:329)也就继承了这份宽容。

实测(origin/main cdfbee2):

getMetadataTypeSchema('api').safeParse({ …合法端点…, aKeyThatIsNotDeclared: 1 })
  → 只报既有必填项问题,从不报 unrecognized_keys

os validate(端点合法、路径符合 ADR-0121 D1 carve-out)
  → ✓ Validation passed
  → ⚠ apis.probe_endpoint.aKeyThatIsNotDeclared: 'aKeyThatIsNotDeclared' is not a
     declared api key, so its value is dropped at load.

也就是说:今天 api 的姿态是 warn(#3786 那层预解析告警)而不是 reject,写路径(saveMetaItem / PUT /meta/api/:name,#5312 刚接上的那道 422)同样只按这份非严格 schema 判,未声明键存进去也不报错

为什么这条值得单独记

  1. 它是 未知键静默剥离仍是全仓默认:把 #3405 的 strict 收紧从一个 schema 推广到整个可授权面(ADR-0078 完整性闸门) #4001 的形状,而且是刚长出来的一块。 api/ 目录在严格性账本(docs/audits/2026-07-unknown-key-strictness-ledger.md:1161)里的分类是 wire | REST/GraphQL request/response contracts — tolerant by design。在 feat(spec): api 补进 DEFAULT_METADATA_TYPE_REGISTRY 与 BUILTIN_METADATA_TYPE_SCHEMAS (#5271) #5312 之前这话没错;feat(spec): api 补进 DEFAULT_METADATA_TYPE_REGISTRY 与 BUILTIN_METADATA_TYPE_SCHEMAS (#5271) #5312 之后 endpoint.zod.ts 同时成了授权面(defineStack({ apis })、Studio metadata-admin 表单、PUT /meta/api/:name),而那一行还写着「按设计宽容」—— 账本会被照着读,这正是账本自己的 gate 存在的理由。

  2. 这一类型的键有安全形状。 authRequired: z.boolean().default(true),以及 ADR-0121 D6 「匿名端点需要 armed budget」的那组判断。拼错的键静默落地意味着作者以为自己配了某个姿态、实际拿的是默认值 —— 这个方向恰好是 fail-safe(authRequired 落回 true),但同一机制对 objectParams / cacheTtl / mapping·policy 块一视同仁,而 AI 批量生成端点声明正是这种拼写错误的高发区。

  3. CLI 与写路径今天是一致的(两边都收、都不报),所以这不是「门不一致」,而是「门本身没关」。objectstack build / validate 从不按 PageSchema 解析页面元数据:ADR-0089 D3a 早就该拒绝的键一路通过,#4001 的「三个示例应用 validate 全过」对 page 面是空证 #5000 的 PR(test(cli): #5000 前提被证伪 —— build/validate 一直按注册表 schema 解析,补上它缺的那份证据 #5380)里我把 api 记成一条明确的账本行:断言两边一致地接受,并断言 排查「手抄 spec 清单 + "keep in sync" 注释」模式:一天内确认三例,全部曾静默漂移 #3786 的告警层确实点名了这个键 —— 等这条 issue 关掉,那行断言会红,那时把 api 挪进「拒绝」表就是一次刻意的棘轮推进。

建议方向(未定,需维护者判)

相关

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions