Skip to content

ADR-0087 别名转换会把「被遮蔽的旧拼法」留在存量元数据里 —— 节点 config 收紧后它从静默丢弃变成执行期硬拒 #4923

Closed

Description

@xuyushun441-sys

发现于 #4001 批 9(PR 见下),不在该批范围内,未修。

事实(实测,非阅读推断)

renameConfigKey(packages/spec/src/conversions/walk.ts:235)在规范键已存在时什么都不做:

export function renameConfigKey(node: Dict, from: string, to: string): Dict | null {
  const config = node.config;
  if (!isDict(config)) return null;
  if (!(from in config) || config[from] == null) return null;
  if (config[to] != null) return null; // canonical already wins — nothing to do
  …
}

于是每一条走 renameFlowConfigAliases 的 ADR-0087 D2 转换,在「作者两种拼法都写了」时,把退役的那个键原样留在存量元数据里。这不是猜测——转换自己的 fixture 就把它写成了预期的 after 形状:

  • flow-node-crud-object-alias:after = { objectName: 'task', object: 'ignored' }(registry.ts:931)
  • flow-node-map-flow-alias:after = { collection, flowName: 'per_row', flow: 'ignored' }(registry.ts:1283)
  • flow-node-subflow-flow-alias、flow-node-notify-config-aliases(含 source) 同形

而且这种情况一条 notice 都不发(emit 只在真的改名时调用)。

为什么现在才要紧

批 9 之前:遮蔽下来的旧键在执行期 parse 被 .strip 静默删掉,节点照跑。批 9 把这些 config 契约收成 strict 之后:

  • notify / http / CRUD 四件套 / screen / map —— 这些节点类型在 registerFlow() 就已经被 3b — wire the flow executors to parse() their config, and tighten the undeclared-key warning into an error #4277 的描述符键闸门硬拒了,所以遮蔽键今天就已经是注册期硬错,批 9 没改变它们的可达行为;
  • script / subflow —— schemaless 类,validateNodeConfigKeys 按构造跳过它们。批 9 之后一个存量 { flowName, flow } 的 subflow 节点会在执行期被拒为 guard(不可经 fault 边路由),而它今天是能跑的。

批 9 的实测:三个示例 app 的 build 产物共 160 个 flow 节点、52 个带批 9 契约,0 例命中——所以这不是一个已发生的回归,是一个存量元数据里可能存在、我们无法从仓库内证伪的形状。

需要裁定的是契约,不是实现

两个方向都自洽,该由维护者定:

  • A —— 转换负责删掉被遮蔽的旧键(并发一条 notice)。理由:一个「把旧拼法改写成新拼法」的转换,留着旧拼法就是没转换完;ADR-0087 的承诺是「存量数据继续加载」,而收紧之后「继续加载」要求转换产出契约认得的形状。代价:改的是 ADR-0087 注册表行为,5+ 条 fixture 的 after 与 expectedNotices 都要动,而且它把「作者写了两个名字」这件事重新变回一次静默的择一(只是多一条 notice)。
  • B —— 保持现状,让 strict 拒绝并带处方(批 9 已按这个前提写了 guidance:每条都同时说清「改名」和「删掉死掉的那个孪生键」)。理由:作者写了两种拼法,元数据本身是有歧义的,平台静默择一正是 未知键静默剥离仍是全仓默认:把 #3405 的 strict 收紧从一个 schema 推广到整个可授权面(ADR-0078 完整性闸门) #4001 要杀的形状。代价:一个今天能跑的存量 flow,在 17 上会硬停——而 ADR-0087 的存在就是为了不发生这件事。

倾向 A + 保留 B 的处方:转换把死掉的孪生键删干净(数据在静止态就是规范的),strict 的 guidance 依然留着,给那些不经加载路径直接 parse 契约的调用方。但这条改的是 ADR-0087 注册表的语义,按仓库规矩(「一个已接受的 ADR 到有新 ADR 说话为止都有约束力」)不该由收紧批次顺手带过。

建议动的文件(仅清点,未实施)

文件 动作
packages/spec/src/conversions/walk.ts renameConfigKey / renameKey 在遮蔽情况下删除 from 键并返回新 dict(而不是 null)
packages/spec/src/conversions/registry.ts 5 条转换的 fixture after 半边 + expectedNotices;liftNotifySourceShape 的遮蔽分支同理
packages/spec/src/conversions/conversions.test.ts 现有断言记录的是当前的「留着」行为,需改成断言删除

相关

Activity

  1. added
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    domain:specDomain lane — seat card indexed by label:pm:seat
    on Aug 3, 2026
  2. xuyushun441-sys commented on Aug 4, 2026

    @xuyushun441-sys
    CollaboratorAuthor

    维护者裁决(2026-08-04):按值相等拆分处置

    renameConfigKey 遇规范键已存在时:

    • 两键值相等 → 转换删除被遮蔽的旧拼法 + 发 notice(无损卫生,D2 契约内);
    • 两键值不同 → 保留双键,由 strict 门以点名双键的处方拒绝(作者意图真歧义时不替客户做决定——升级工具自动挑规范键等于改了客户可能没同意的配置)。

    注册表既有 after fixture({objectName:'task', object:'ignored'} 一类)按新语义修正;执行时补双向测试(相等删除 + notice 断言;不等保留 + 双键点名断言)。批 9 已按现状语义写的 guidance 条目随本变更同步措辞。

    needs-user-decision 摘除,入队。


    Generated by Claude Code

  3. added
    pm:queueReady for the PM dispatch loop
    and removed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Aug 4, 2026
  4. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    Contributor

    排批记录(spec 车道 PM,session_018fxLGQdatPbBUvCgiVxg6D,2026-08-05):本单顺延至 #5050 落地后的下一轮 —— #5050(session.roles 退役)按 playbook 大概率也要在 conversions/registry.ts 落条目,与本单同文件,批内不并行(同文件跨轮串行铁律)。裁决已在案(上方维护者按值相等拆分处置),届时纯执行。

    ⚠️ 派发时附带条款(#5511 分诊裁定):本单既触 walk.ts + registry.ts,顺路把 protocol-15 page-component-visibility-to-visibleWhen 的就地走查切换到 #5509 新增的 mapPageComponents —— 行为等价由其既有 fixture 判定,等价性即验收。


    Generated by Claude Code

  5. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 6, 2026
  6. self-assigned this
    on Aug 6, 2026
  7. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    Contributor

    PM 认领(spec 车道 PM,session_018fxLGQdatPbBUvCgiVxg6D,2026-08-06)


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

domain:specDomain lane — seat card indexed by label:pm:seatpm:dispatchedDispatched to a dev agent by /pm-dispatch

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions