Skip to content

build-schemas.ts 检查 (b) 用叶名匹配 conversion surface —— 无关簇的 .type 就能让一个 tombstone 冒充「已登记迁移」 #4659

Description

@os-zhuang

#4658(双源清账 C6)的路线定价实验里掉出来的范围外发现,不在 #4658 的 PR 里修,单独立案。与 #4650 同族(都是 authorable-surface 门禁的自我校验漏洞)。

事实

packages/spec/scripts/build-schemas.ts 检查 (b)(「live → retired 必须有登记的迁移」)这样匹配:

const surfaces = registeredRetirementSurfaces().flatMap((s) => s.split(' / '));
const unregistered = newlyRetired.filter(
  (k) => !surfaces.some((s) => s.endsWith('.' + k.split(':')[1])),
);

k 形如 automation/Event:type,k.split(':')[1] 只取叶名 type,再拿它跟全部 major 的所有 conversion surface 做 endsWith。匹配完全不看 key 属于哪个 def —— 任何一条无关的 conversion 只要 surface 以同名叶子结尾,就把这个 tombstone 判为「已登记」。

实测证据

#4658 的定价实验里,我把 src/automation/state-machine.zod.tsEventSchema 两个 key 同时改成 retiredKey(...),没有新增任何 conversion。pnpm check:authorable-surface 的输出:

❌ 1 key(s) were tombstoned with no registered migration:
     - automation/Event:schema

只报了 schemaautomation/Event:type 静默通过 —— 因为 CONVERSIONS_BY_MAJOR[11]flowNodeHttpRenamesurface: 'flow.node.type'.type 结尾。两者毫无关系:一个是 flow 节点的 type,一个是 automation 状态机事件的 type

为什么要紧

检查 (b) 的整个目的是保证退休进入 spec-changes.json / upgrade guide / os migrate meta(ADR-0087 D4)。叶名匹配让这个保证对常见叶名整体失效:typenameconfigfilterschema 之外的 objectNameflowName 等 surface 已在册,任何以它们结尾的 key 都能零迁移文档退休,门禁全绿,消费者只能靠失败才知道。

这与 #4650 是同一类问题:门禁的证据链自己不设防。#4650 是「删基线行没人校验」,本单是「登记检查可被无关条目满足」。

建议处置(需维护者裁决,故不自行动手)

把匹配从叶名收紧到定位到 def 的路径。两个方向:

  1. surface 里带上 def。让 conversion 的 surface${defKey}:${name} 可判定地对应(或加一个显式的 retires: ['automation/Event:type'] 字段),检查 (b) 改成精确集合匹配。最严格,但要回填现有 conversion。
  2. 保留 surface 的散文形态,另加一个显式登记表。新增 RETIRED_KEYS_BY_MAJOR: Record<number, string[]>,值就是 ${defKey}:${name},检查 (b) 只认这张表。改动小,且「declared = enforced」。

倾向 2:它让登记这件事从「碰巧字符串对上」变成作者必须写下确切的 key,正是 AI 生成的元数据最容易蒙混的那一环。

关联:#4650(基线手编漏洞)、#4658(发现现场)、#4535、ADR-0087、ADR-0104

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions