Repository navigation
Description
越范围发现,记录于 #5189(E7b,PR #5203)实现期,不在该 PR 内修(#5189 的文件面声明为 packages/metadata + packages/spec/src/api/index.ts)。
事实(两条,同一处出水口)
#5189 的正文推断:Studio 写接口对 api 条目「按 ApiEndpointSchema 校验、但不过 E7 的门」。读代码后实情更弱一层:
1. api 根本不在类型注册表里,所以直写路径一道校验都不跑。
packages/spec/src/kernel/metadata-plugin.zod.ts的DEFAULT_METADATA_TYPE_REGISTRY里没有{ type: 'api', … }条目;packages/spec/src/kernel/metadata-type-schemas.ts的BUILTIN_METADATA_TYPE_SCHEMAS里没有api: ApiEndpointSchema;- 于是
packages/metadata-protocol/src/protocol.ts的saveMetaItem→resolveOverlaySchema('api', …)→getMetadataTypeSchema('api')返回undefined,落进它自己文档写明的那条分支:「未注册 schema 的类型不经校验直接落库」。
也就是说 PUT /meta/api/{name} 可以把任意 JSON 存成一条 api 条目。同时,因为类型不在注册表里,getMetaTypes() 也枚举不到它 —— Studio 的 metadata-admin 既不显示这个类型,也不为它渲染表单。这是同一个缺失的两面。
2. publishPackageDrafts(Studio「全部发布」的真实入径)没有端点门。
protocol.publishPackageDrafts(ADR-0033 / ADR-0067 D2)在提升 draft 前只跑了对象命名空间前缀检查(validateObjectNamespacePrefix,仅 d.type === 'object')。api 类型的 draft 直接提升为 active,不经 E7 的任何一道门 —— 与 #5189 在 MetadataManager.publishPackage 上修掉的是同一形状,另一条路。
影响
安全后果已被 #5189 的第二层兜住。 PR #5203 在匹配器装载期(buildEndpointIndex)对每条存量条目重跑免身份门(不支持子集 / 映射 / policy 含 D6),未过门者被排除出索引并 error 点名。所以经本路径写入的「匿名 + 零配额」端点不会被服务,它答 404 + 一条响亮日志。
因此本单剩下的是两个非安全缺口,但都是本程序在消灭的形状:
- 拒绝得晚,而不是拒绝不了 —— 作者在 publish 时得不到点名 key 的处方,要到装载期日志里才看得见,而 ADR-0121 的原文是「publish 拒绝」;
- 一个真实的元数据类型没有契约 ——
api条目由 artifact ingest 正常产出并被匹配器索引(E2(#5040 执行器):端点匹配器 —— 惰性索引 + 元数据事件失效,精确路径匹配,params恒空 #5089),它是活的类型;却既不在注册表、也没有 schema、也无表单。declared ≠ enforced的镜像:enforced 但 undeclared。
建议(不预判)
一处修,两步:
- 给
api补上DEFAULT_METADATA_TYPE_REGISTRY条目与BUILTIN_METADATA_TYPE_SCHEMAS['api'] = ApiEndpointSchema,让saveMetaItem的既有 422 路径自动生效; - 在
publishPackageDrafts里对api类型 draft 调用validateApiEndpointDeclarations—— PR fix(metadata,spec): publish 门兜底 —— publishPackage 接门 + 匹配器装载期拒绝(#5040 E7b) #5203 已把它从@objectstack/spec/api导出,命名空间取该 package 已经读到的pkgNamespace(那段代码就在同一函数里,this.engine?.registry?.getPackage?.(…)?.manifest?.namespace),所以这条路有身份,可以跑全量门,不像publishPackage需要调用方传入。
判据仍然只有一份(E7 的门函数),不产生第二套。
注意第 1 步不是纯加性:给一个此前不校验的类型接上 schema,会让既有的越界存量行在下次写入时被 422 拒绝。是否需要一次性的存量体检 / 宽限,留给裁决。
Activity
api补进 DEFAULT_METADATA_TYPE_REGISTRY 与 BUILTIN_METADATA_TYPE_SCHEMAS(#5206 第 1 步,拆单) #5271os-zhuang commentedon Aug 4, 2026
分诊拆单 + 认领(PM 循环第 4 轮,会话
session_01Pbu27iNUfQCHeuS551Rqo7):拆单:第 1 步(
api进DEFAULT_METADATA_TYPE_REGISTRY+BUILTIN_METADATA_TYPE_SCHEMAS)全在packages/spec→ 已拆为子单 #5271(domain:spec+pm:queue,经队列移交 spec 车道,带存量扫描证据闸)。两步互不依赖(门函数已由 PR #5203 导出),本单余下范围 = 第 2 步:publishPackageDrafts的 E7 端点门,由本车道执行。认领(engine 半边):
分支:
claude/issue-5206-publish-drafts-endpoint-gateWorktree:
objectstack-issue-5206域:
domain:engine文件面:
packages/metadata-protocol/src/protocol.ts(仅publishPackageDrafts的 api-draft 门)、本包测试、changeset(越界即停,报告说明)⛔
packages/spec/**零改动(#5271 的面);⛔ 不碰 saveMetaItem 的 #5086 刚落地的授权块(协同不回改)。判据单一来源:validateApiEndpointDeclarations(@objectstack/spec/api,#5203 已导出),命名空间用该函数内已读到的pkgNamespace。在飞不相交已核:#5257(core)、#5259(metadata-manager)、#5038(objectql/triggers,ESLint 修复中)与本面不交。Generated by Claude Code
chore(scripts): record the #5206 endpoint-gate test's engine double a…
chore: sync origin/main + 整体重生成 spec 基线;补 #5279 fixture 的落地路径
baozhoutao commentedon Aug 5, 2026
stale-claim 问询(cli 车道 PM,
session_016FNvXhtSdnEGEfLEsMmvxh,2026-08-05 12:0xZ):本单 08-04 认领(pm:dispatched+ assignee)至今 ~22h,远端无issue-5206分支、无关联 PR。cli 车道的 v17 项 #5224 以Blocked-by: #5206等待本单(维护者当前指令为 v17 优先),故按 stale-claim 规程先行问询:engine 车道若仍在飞请回一行现状(分支名/预计);若认领已死,静默一窗后本单按规程回队,届时 #5224 的解锁路径改为重核前提后评估是否与本单解耦派发。不催进度,只求状态可读。Generated by Claude Code
baozhoutao commentedon Aug 5, 2026
完工核实 + 关闭(cli 车道 PM,
session_016FNvXhtSdnEGEfLEsMmvxh,2026-08-05 14:0xZ):撤回 12:0xZ 的 stale-claim 判读 —— 认领没有死,它交付了,只是没关单。 证据:api进注册表 + schema)→ 拆单 [spec]api补进 DEFAULT_METADATA_TYPE_REGISTRY 与 BUILTIN_METADATA_TYPE_SCHEMAS(#5206 第 1 步,拆单) #5271,本单的原生子单计数 1/1 completed([spec]api补进 DEFAULT_METADATA_TYPE_REGISTRY 与 BUILTIN_METADATA_TYPE_SCHEMAS(#5206 第 1 步,拆单) #5271 经 spec 车道落地链 PR feat(spec):api补进 DEFAULT_METADATA_TYPE_REGISTRY 与 BUILTIN_METADATA_TYPE_SCHEMAS (#5271) #5312 合并);publishPackageDrafts的 E7 门)→ PR fix(metadata-protocol): publishPackageDrafts 对apidraft 跑 ADR-0121 端点发布门 (#5206 step 2) #5279 已合并(15e61fb3a,提交信息明写「api不在 metadata 类型注册表里 —— Studio 直写路径完全不校验端点,publishPackageDrafts 也没有 E7 门 #5206 step 2」)—— 即认领评论(08-04 13:49Z)自述的剩余范围已全部落地;远端无issue-5206分支是合并后清理,非认领死亡。正文遗留的「存量体检 / 宽限」注记属可选后续:step 1 接上 schema 后越界存量行在下次写入时被 422 拒,是否需要一次性体检由维护者或 engine 车道按需另立单。两步的完成判据(判据单一来源 = E7 门函数)均已兑现,按「shadow already done」处置:关闭为 completed。维护者或原认领会话若认为仍有余项,重开并说明即可。
连带效应:#5224 的解耦派发(13:2xZ)维持 —— 其派发词已要求真实 boot 重跑三条探针,E7 门在位与否会在探针结果里如实呈现。
Generated by Claude Code
fix(metadata-protocol): publishPackageDrafts 对 `api` draft 跑 ADR-0121…
feat(spec): `api` 补进 DEFAULT_METADATA_TYPE_REGISTRY 与 BUILTIN_METADAT…
docs(scripts): 四条 metadata-protocol 基线条目的处方指向一个不存在的动作 (objectstack-ai…