Repository navigation
Closed
Labels
bugSomething isn't workingSomething isn't workingpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatchpm:queueReady for the PM dispatch loopReady for the PM dispatch loop
Description
发现于 #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 落地的方案一致,直接复用它的判别器,不要另起一套:
packages/metadata/src/utils/schema-sync-errors.ts里的isMissingTableError()([metadata] nextEventSeq() 把驱动读失败也当成「表还没建」,静默从 1 重新发号 —— #4632 同形,机械检查覆盖不到 #4825 新增,与 [metadata] database-loader 吞掉 sys_metadata 的 DDL 失败后仍置 schemaReady=true —— 第二类降级(#4632 规则),本轮因包冻结未修 #4728 的isSchemaAlreadyExistsError()共用同一个 code / errno / message +cause链匹配器);- 只在确实是表不存在时返回 1;其余读失败按 AGENTS.md「Degradation log levels」以
error上报后果(序号将从 1 重新发号、与既有行撞号、版本顺序与回滚目标不可信)并抛出,让调用方决定。
@objectstack/metadata 的内部工具(未从包入口导出),而 @objectstack/metadata-protocol 是另一个包。三个选项,值得在动手前定:
- 从
@objectstack/metadata导出(最小改动,但把一个内部工具变成公共 API 面); - 下沉到两个包共同的依赖里(
@objectstack/types或@objectstack/spec/shared)—— 注意 Prime Directive ✨ Set up Copilot instructions #2:packages/spec不放业务逻辑,错误分类算不算,需要判断; - 在
metadata-protocol里复制一份 —— 不建议,正是 [metadata] nextEventSeq() 把驱动读失败也当成「表还没建」,静默从 1 重新发号 —— #4632 同形,机械检查覆盖不到 #4825 刻意避免的「同一问题两套判别」。
倾向 2(若落点合法)或 1,由维护者定。
参考
- [metadata] nextEventSeq() 把驱动读失败也当成「表还没建」,静默从 1 重新发号 —— #4632 同形,机械检查覆盖不到 #4825(
DatabaseLoader.nextEventSeq(),同形,已修) - [metadata] database-loader 吞掉 sys_metadata 的 DDL 失败后仍置 schemaReady=true —— 第二类降级(#4632 规则),本轮因包冻结未修 #4728(
ensureSchema()的同形缺陷,已修)、[convention] best-effort 降级导致"看起来正常、实则不持久"时不应记 warn——把 #4460 的点状修复定成规则 #4632(降级日志级别规则 + gate)、[automation/approvals] 进程重启后审批决策静默失效:挂起 flow run 仍只存内存(#1518 标记 COMPLETED 但 17.0.0-rc.1 未生效),approve 落库却永不推进且零报错 #4420(事故)、[core/ADR-0116] init 阶段取服务的顺序契约是自愿声明的——不声明就没人拦,#4085 与 #4420 都是这么发生的 #4471(根因模式)
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't workingpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatchpm:queueReady for the PM dispatch loopReady for the PM dispatch loop
Activity
claude commentedon Aug 3, 2026
🔒 认领:PM 循环第 2 轮
会话:
session_01NrmBxj8rK2uGCnh9aipjwX(账号xuyushun441-sys)分支:
claude/issue-4867-sysmetadata-repo-seqWorktree:
objectstack-issue-4867域:
domain:engine文件面:
packages/metadata-protocol/src/sys-metadata-repository.ts+packages/metadata/src/utils/schema-sync-errors.ts(导出)及同目录测试⛔ 硬约束:
packages/spec/**及生成物零改动(维护者本轮指令)。全局在飞不相交已核:与队列中 PR #4950/#4954/#4957/#4969、等 CI 的 #4972/#4975、他 PM 在飞 #4250/#4550/#4719/#4801/#4851/#4916/#4001/#4911 文件面均不交。
Generated by Claude Code
claude commentedon Aug 3, 2026
✅ 验收通过 —— PR #4980(draft,等 CI 绿后入队)
对照实际 diff 复核(8 文件,+658/-5;⛔
spec/**/protocol.ts/ releases/ 零触碰,逐一核实):nextEventSeq/nextItemVersion都改为按错误类型判别 —— 仅真·表不存在返回 1;其余读失败经共享historyCounterVerdict()以 error 级一次性上报(后果 + 处方),再抛出令事务中止 —— 不再提交撞号;恢复时补 info。@objectstack/metadata/errors),且给出了比根导出更强的理由 —— 根入口拖着 manager/loaders/YAML 依赖,40 行谓词背着这重量恰会诱发下一次复制。采纳,理由记录在案。依赖闭包已验无环;新 workspace 边有真实证据(TS2307 先红、install 后绿)。衍生:#4981(
publishDraft()把 draft 清理的全部失败折成「并发发布者已抽走」,但它在 put 提交之后,throw-vs-report 需要单独裁定)已核实立案,engine 车道下轮分诊;同文件 close()/broadcast() 两处 catch 经查属正当静默,刻意不立案 —— 这个「不立案也说明理由」的习惯很好。CI 绿后转 ready 入合并队列(与 #4952 不同包,无串行约束)。
Generated by Claude Code
test(metadata-protocol): record the #4867 engine double in the delete…
claude commentedon Aug 3, 2026
✅ 返工验收通过(HEAD
99be8e9)—— 等 CI 绿入队返工 diff 精确:仅 +7 行基线条目(
scripts/engine-double-contract.baseline.json),原修复零改动。Cyclic dependency detected: metadata-protocol#build ↔ objectql#build),证据留档后回滚;DEBT vs EXEMPT 的分类理由(该 ledger 的 EXEMPT 保留给无驱动的类型见证)也站得住。closes指向一个不可能的动作:加 @objectstack/objectql devDependency 会让 turbo 直接判环 #4987 已核实立案 —— 基线里既有 4 条 metadata-protocol 条目的closes处方正是这条被实测证伪的成环路线,不改的话每个后来者都要重做一遍同样的实验;正确处方是把判别器下沉到双方共同依赖(metadata-core)。devx 车道分诊。CI 绿后转 ready 入合并队列。
Generated by Claude Code
test(metadata-protocol): record the #4981 draft-drain fake in the eng…
fix(metadata-protocol): never invent event_seq/version from a failed …
fix(metadata-protocol): publishDraft 的 draft-drain 按错因判别,不再一律吞掉 (obje…
chore(scripts): record the #5206 endpoint-gate test's engine double a…
fix(metadata-protocol): publishPackageDrafts 对 `api` draft 跑 ADR-0121…
docs(scripts): 四条 metadata-protocol 基线条目的处方指向一个不存在的动作 (objectstack-ai…
fix(metadata-protocol): an unreadable sys_metadata is an outage, not …