Skip to content

[metadata-protocol] SysMetadataRepository 的 nextEventSeq()/nextItemVersion() 同样把读失败当「表还没建」,静默从 1 重新发号 —— #4825 在 canonical 路径上的同形缺陷 #4867

Description

@os-zhuang

发现于 #4825(修 DatabaseLoader.nextEventSeq())。仅记录,未在该 PR 中修改 —— 落点在另一个包(packages/metadata-protocol),按 Prime Directive #10 单开。

现象

packages/metadata-protocol/src/sys-metadata-repository.ts 有两个同形的 catch

// nextEventSeq(ctx) — 约 1051 行
    return max + 1;
  } catch {
    // Table not provisioned yet (fresh DB) — start at 1.
    return 1;
  }
// nextItemVersion(ref, ctx) — 紧随其后
    return max + 1;
  } catch {
    return 1;
  }

两者都读 sys_metadata_history,都把全部读失败折成 return 1

为什么值得单开(比 #4825 更该修,不是更不该)

#4825 修的是 DatabaseLoader —— TSDoc 自称 legacy、非事务的那条路径。这里是 canonical 路径#4825 的正文与分诊都把 SysMetadataRepository 称作「历史写入应当收敛过去的地方」。同一个缺陷在目的地上原样存在。

而且这里有两个数字,不是一个:

  • event_seq —— 历史排序 / 回滚定位的依据。已有 N 行时一次瞬时读失败让下一条拿到 1,与既有行撞号;
  • version —— nextItemVersion() 的 TSDoc 明说它刻意从 history 取 MAX「so delete + recreate continues incrementing instead of restarting at 1」。一次读失败正好把它恢复成它明确要避免的那个行为:lineage 从 1 重启,与既有 lineage 行撞号。而 MetadataManager.rollback(type, name, version)POST /api/v1/meta/:type/:name/rollback 正是按 version 定位快照的 —— 撞号之后回滚可能指向另一条记录的同号版本。

关键危害与 #4825 相同,是「落盘的字节是错的」而不是「字节没落盘」:insert 成功、日志一行没有、系统对外完全正常,错误只在版本顺序里,重试不修、重启也不修。

有一点值得注意但不改变结论:这两个调用都在事务里(put/delete 的 txn body)。事务解决的是并发撞号,解决不了读失败被折成 1——一个成功提交的事务照样可以提交一个错号。

建议

#4825 落地的方案一致,直接复用它的判别器,不要另起一套:

⚠️ 跨包复用需要先定一件事:该判别器目前是 @objectstack/metadata内部工具(未从包入口导出),而 @objectstack/metadata-protocol 是另一个包。三个选项,值得在动手前定:

  1. @objectstack/metadata 导出(最小改动,但把一个内部工具变成公共 API 面);
  2. 下沉到两个包共同的依赖里(@objectstack/types@objectstack/spec/shared)—— 注意 Prime Directive ✨ Set up Copilot instructions #2packages/spec 不放业务逻辑,错误分类算不算,需要判断;
  3. metadata-protocol 里复制一份 —— 不建议,正是 [metadata] nextEventSeq() 把驱动读失败也当成「表还没建」,静默从 1 重新发号 —— #4632 同形,机械检查覆盖不到 #4825 刻意避免的「同一问题两套判别」。

倾向 2(若落点合法)或 1,由维护者定。

参考

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions