Skip to content

authorable-surface 的 tombstone 门禁可被手编基线绕过 —— 删掉基线行就删掉了证据(#4638 / #4643 已两次这样过绿) #4650

Description

@os-zhuang

症状

packages/spec/scripts/build-schemas.ts 的可作者化面 ratchet 检查 (a)(约 L408–428)本意是:可作者化 key 不许无声消失,因为这些 schema 不是 .strict(),Zod 会静默 STRIP 未知键 —— 作者继续写就得到一次干净的 parse 和一个永不生效的设置(#3733、ADR-0104)。错误文案要求走 tombstone:retiredKey() + D2 conversion + D3 chain step + major changeset。

但检查是这样做的:

const prev = new Map(surfaceDoc.keys.map(...));         // ← 读**磁盘上**的 authorable-surface.json
const vanished = [...prev.keys()].filter((k) => !currentKeys.has(k));
if (vanished.length > 0) { /* 报错 + process.exit(1) */ }

surfaceDoc 读的是同一个 commit 里可以被随手改掉的基线文件。把要删的 key 从 authorable-surface.json 里手工删掉,prev 里就没有它,vanished 为空,门禁静默通过 —— 删掉基线行就是删掉证据

文件自己的 description 与错误文案都写着:

A tombstone that has aged out (~two majors) is the ONE legitimate reason to delete a line here — do it in the same PR, deliberately.

但没有任何东西校验这一条。 基线行的删除既不要求对应 [RETIRED] 标记存在过,也不要求它已 aged out,更不要求有 conversion 登记。

已发生两次

PR 删除的 key tombstone conversion / migration 结果
#4638(C3) ui/Notification:*ui/NotificationConfig:*system/NotificationConfig:* 绿
#4643(C4) identity/Session:* 全部 10 个 绿

复核 #4643 的 commit 21676eb5d:authorable-surface.json 里 10 行 identity/Session:* 被直接删除,src/conversions/src/migrations/ 零改动

这两次的实质是否有害?

倾向于无害,但不该被当先例:

  • identity/Session 是 DB 行 / 运行时形状,ui/Notification 是 toast 实例形状 —— 都不是作者在元数据文件里手写的类型,三仓 import 级扫描也已证实零消费方。
  • 更根本的问题是 authorable-surface.json 过度收集:它记录每个被发出的 schema 的全部 properties,包括 api/SessionResponse:successapi/SessionResponse:meta 这类 REST 信封字段 —— 这些无论如何都不是「metadata author 可写」的东西。文件的名字比它的内容强。

所以真正的缺口有两个,建议分开处置。

建议

(1) 堵住捷径。 让基线行的删除必须自证合法。最小实现:检查 (a) 之外再加一条 —— 对比 git show HEAD:packages/spec/authorable-surface.json 与工作树版本,任何被删除的行必须满足「上一版本带 [RETIRED] 标记」且「其 surface 已在 CONVERSIONS_BY_MAJOR / MIGRATIONS_BY_MAJOR 登记过、且登记的 major 距当前 ≥ 2」。不满足就红,错误信息指向本单。

注意实现时别把 (a) 的现有语义弄反:(a) 防的是形状变了而基线没动,新检查防的是基线动了而形状没有正当理由 —— 两者都需要。

(2) 收窄收集面。 ratchet 应只记录从真作者面可达的 schema(object / field / flow / view / connector / plugin 等作者手写的元数据类型,及其传递引用),而不是每个被 gen:schema 发出的 schema。否则「可作者化」这个判定在评审时不可用 —— 每次都要人肉判断某个 key 是不是真的作者面,而这正是 #4638 / #4643 两次都得靠 reviewer 直觉的原因。

(2) 比 (1) 影响面大,可能需要先确定「真作者面根集合」的定义,建议单独排期;(1) 是可以立刻落的窄修。

影响范围

关联

#4535(双源清账主单,v17 重切一节记录了同一发现)、#3733#3855、ADR-0059 §5、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