Repository navigation
Closed
Labels
pm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatch
Description
发现于 #4867(修同文件两个计数器的 catch { return 1 })。仅记录,未在该 PR 中修改 —— 不属于同一个编号家族,按 Prime Directive #10 单开,未指派。
现象
packages/metadata-protocol/src/sys-metadata-repository.ts,publishDraft() 里(origin/main 约 665–676 行,#4867 的 PR #4980 之后行号会下移):
// Drop the draft row — it has been promoted. Tolerate races where
// a second publisher already drained it.
try {
await this.delete(ref, {
parentVersion: draft.hash,
actor: opts.actor,
source: opts.source ?? 'sys-metadata-repo.publish',
intent: opts.intent ?? 'override-artifact',
state: 'draft',
});
} catch {
// best-effort: a concurrent publisher may have already drained
// the draft; the active row's authoritative content is intact.
}注释只点名了一个原因(并发发布者已经抽走了 draft —— 这时 delete 抛 ConflictError,确实良性),catch 却吞掉全部失败:连接抖动、超时、权限不足、驱动错误,以及 draft 在此期间被改写导致的 parentVersion 不匹配。这与 #4728 / #4825 / #4867 是同一族形状 —— 一个良性原因赦免了所有原因,只是这里的数字换成了一行残留数据。
后果
publishDraft() 返回成功,active 行也确实是对的(这一点注释说得没错),但 sys_metadata 里那条 state='draft' 的行还在:
- Studio / Setup 会继续把这个 artifact 显示为「有未发布的改动」,而它其实已经发布了 —— 用户看到一个点了没用的按钮;
- 下一次
publishDraft()会拿这条陈旧 draft 当新内容再发布一次,写出一条内容与 active 完全相同的历史事件(甚至可能把已经被覆盖的旧 body 重新推成 active); - 没有任何日志,重试不修、重启也不修。
按 AGENTS.md「Degradation log levels」的那一问:降级之后系统对外看起来完全正常,而它声称已经清理的东西并没有清理 —— 属于 error 那一类,不是 warn。
建议(与 #4728/#4825/#4867 一致的形状)
按错误类型判别,只赦免真正良性的那一个:
ConflictError(以及「行已不存在」)—— 并发发布者已抽走,静默,这正是注释里写的那个情况;- 其余失败 —— 以
error上报后果(draft 行残留、UI 会继续显示未发布改动、下一次 publish 会重复发布)与修复动作,然后决定是抛出还是仅上报。这里与 [metadata-protocol] SysMetadataRepository 的 nextEventSeq()/nextItemVersion() 同样把读失败当「表还没建」,静默从 1 重新发号 —— #4825 在 canonical 路径上的同形缺陷 #4867 不同,delete在put提交之后,抛出会把一次已经成功的发布报成失败,所以「抛 vs 只报」需要判断,不能照抄 [metadata-protocol] SysMetadataRepository 的 nextEventSeq()/nextItemVersion() 同样把读失败当「表还没建」,静默从 1 重新发号 —— #4825 在 canonical 路径上的同形缺陷 #4867 的结论 —— 这也是本条单开而不是塞进 [metadata-protocol] SysMetadataRepository 的 nextEventSeq()/nextItemVersion() 同样把读失败当「表还没建」,静默从 1 重新发号 —— #4825 在 canonical 路径上的同形缺陷 #4867 的原因之一。
参考
- [metadata-protocol] SysMetadataRepository 的 nextEventSeq()/nextItemVersion() 同样把读失败当「表还没建」,静默从 1 重新发号 —— #4825 在 canonical 路径上的同形缺陷 #4867(同文件,
nextEventSeq()/nextItemVersion(),PR fix(metadata-protocol): never invent event_seq/version from a failed history read (#4867) #4980) - [metadata] nextEventSeq() 把驱动读失败也当成「表还没建」,静默从 1 重新发号 —— #4632 同形,机械检查覆盖不到 #4825(
DatabaseLoader.nextEventSeq(),PR fix(metadata): 历史序号 event_seq 不再从一次失败的读里凭空发号 —— 只有「表还没建」可以从 1 开始 (#4825) #4872)、[metadata] database-loader 吞掉 sys_metadata 的 DDL 失败后仍置 schemaReady=true —— 第二类降级(#4632 规则),本轮因包冻结未修 #4728(ensureSchema())、[convention] best-effort 降级导致"看起来正常、实则不持久"时不应记 warn——把 #4460 的点状修复定成规则 #4632(降级日志级别规则 + gate)
Metadata
Metadata
Assignees
Labels
pm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatch
Activity
claude commentedon Aug 3, 2026
🔒 认领:PM 循环第 5 轮
会话:
session_01NrmBxj8rK2uGCnh9aipjwX(账号xuyushun441-sys)分支:
claude/issue-4981-publishdraft-drain-discriminateWorktree:
objectstack-issue-4981域:
domain:engine文件面:
packages/metadata-protocol/src/sys-metadata-repository.ts(publishDraft)及同目录测试throw-vs-report 裁定(issue 单开的那个问题):只报不抛。理由沿两轴:(1) delete 在 put 提交之后,抛出会把一次已持久化成功的发布谎报成失败,且诱发调用方重试 —— 重试恰恰触发「陈旧 draft 再发布」这条真正的数据伤害路径;(2) 防 AI 错轴:响亮 + 机器可读的部分成功信号让调用方无法把缺口读成良性,#4969(今日先例,维护者已过目)同形 ——「决策成立,但绝不静默」。判别按 #4728/#4825/#4867 族:仅 ConflictError / 行已不存在静默;其余 error 级上报后果与修复动作。若要加结构化字段而它构成 spec 契约变更 —— 本轮禁区,退回 log-only 并报告。
⛔
spec/**/protocol.ts零改动;releases/ 零触碰。Generated by Claude Code
claude commentedon Aug 3, 2026
🔁 接手记录:原 dev agent 因会话额度耗尽被杀(不可恢复),worktree
objectstack-issue-4981与未提交改动完好。按 worktree 接手协议派新 agent 继续 —— 同一认领、同一分支,本条为交接记录,原认领评论继续有效。会话:session_01NrmBxj8rK2uGCnh9aipjwX。Generated by Claude Code
claude commentedon Aug 4, 2026
✅ 验收通过 —— PR #5025(draft,CI 跑完入队);接手协议全程执行
对照实际 diff 复核(5 文件,+650/-14;⛔ spec / protocol.ts / releases 零触碰,逐一核实):
draftDrainFailed可选字段 —— 且 dev 核实了裁定第 2 条的前提:promoteDraft 是 class-only 方法,不在 MetadataRepository 接口、不在 protocol.ts、不在 spec —— 非破坏性附加成立,不是宣称。dropPromotedDraftRow具名并入门禁台账(11 seams 全响)。CI 绿后转 ready 入合并队列。
Generated by Claude Code
test(metadata-protocol): record the #4981 draft-drain fake in the eng…
claude commentedon Aug 4, 2026
✅ 返工验收通过(HEAD
92e0623)—— CI 绿即入队closes指向 metadata-core 下沉路线([engine-double-contract] 四条 metadata-protocol 基线条目的closes指向一个不可能的动作:加 @objectstack/objectql devDependency 会让 turbo 直接判环 #4987),原实现零改动;check:objectui-pin-fresh为 main 上既有、只挡 release PR,已挂 Release process: prevent frontend (objectui) changesets being missed when the console pin lags #3340,不重复立案);Generated by Claude Code
Merge remote-tracking branch 'origin/main' into claude/issue-4998-see…
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…