Skip to content

isSystem 写入仍可产生悬空 lookup 引用——需要一条只报告不拦截的巡检(#4441 残留) #4551

Description

@os-zhuang

#4441 让引擎在写入路径上强制 lookup 引用完整性,但刻意豁免了 isSystem 写入:种子重放、包安装、启动期供给合法地以「批次完成后才自洽」的顺序写入,让它们 fail-closed 会把一个排序细节变成启动失败。

这个豁免是对的,但它留下一个缺口:平台自身仍可写入指向虚无的引用,而没有任何东西会说出来。#4441 的 PR 已明确记录该残留、未静默接受,本 issue 是它的落地跟进。

为什么不能靠「把豁免去掉」解决

去掉豁免会把种子排序问题变成启动失败——这正是豁免存在的理由。而且平台确实有合法的非 id 写入:sys_metadata_history.recorded_bylookup('sys_user'),平台以 actor ?? 'system' 填入哨兵字符串,且该写入不带 isSystem(这一条已由 #4441 收窄为跳过 readonly 字段处理)。拒绝平台自身的写入不是报告问题的正确方式。

建议形态:只报告,不改写

#4469inspectStrandedRequests() 同一形状——那条巡检的判断已经过一轮实践检验,可直接借鉴:

  • 只报告,绝不改写。 数据是真实写入的;自动清理会让审计与事实不符。
  • 报告面向人工:哪个对象、哪条记录、哪个字段、指向哪个不存在的 id、目标对象是什么。
  • 不可知与不存在必须分开。 目标对象未注册、无 driver、探测抛错 —— 计入 undetermined 而非判定为悬空,这样「0 条悬空」永远不会被误读成「一切正常」。[approvals] 存量僵尸请求无人认领:已终态但 run 悬空的请求落在 releaseDeadRunRequests 的盲区里 #4469 的巡检为此专门写了两条测试。
  • 挂在既有的清扫时钟上,让运维不必知道要去找。

范围建议

验收

边界

只做巡检与报告。不要改动 #4441 的强制逻辑,不要新增可作者化的 spec key(「悬空引用改为 opt-in」是另一个待维护者决策的方向,见 #4441)。

发现自 #4482 v17 验收批次;#4441 的 PR #4511 记录了这一残留。

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions