发现于 #4632(降级日志级别规则 + 盘点)。packages/metadata-protocol/** 本轮被冻结(#4556 正在改写入路径),因此只记录不修,按 PM 约束单开此单。
现象
packages/metadata-protocol/src/seed-loader.ts(约 953–966 行,pass-2 延迟引用回填):
} catch (err: any) {
// LOUD FAILURE (framework#2805): the target resolved but the
// back-fill WRITE failed (a transient error that outlasted the
// retry budget, a validation veto, …). The reference stays NULL —
// the very corruption pass 2 exists to prevent — so this must be a
// reported, counted error, never a silent warning. Swallowing it
// returned `success: true` / `totalErrored: 0` over a load that
// left a circular relationship half-written.
this.logger.warn('[SeedLoader] Failed to write deferred reference', {
object: deferred.objectName,
field: deferred.field,
error: err?.message,
});
this.recordDeferredError(deferred, allResults, allErrors, ...);
}
注释与代码直接矛盾:注释明确写 "this must be a reported, counted error, never a silent warning",紧跟着的调用却是 logger.warn。
为什么这是 #4632 的第二类降级
按 #4632 的判定问句 ——「降级后系统对外表现是否仍然『正常』,而声称已持久化的东西实际没有落盘?」—— 答案是是,而且注释自己已经把后果说得比我更清楚:回填写入失败 ⇒ 引用字段停在 NULL ⇒ 循环关系半写入。这就是「记录看起来种下去了、关系实际没落盘」。
一点公允之处:紧随其后的 recordDeferredError(...) 确实把它计入 allErrors,所以不是完全静默 —— 结果对象里数得到。但日志行本身是这次 seed 在控制台唯一可见的痕迹,warn 级别正是 #4420 里没人读的那一级。计数与日志级别应当一致。
期望
机械检查说明
#4632 的 pnpm check:durability-log-level 不会自动发现这一处 —— 该 gate 靠一份显式的「持久化关键操作」词表(DURABILITY_CRITICAL_CALLEES)判定,故意做窄以避免误报,而这里的写入走的是通用 SEED_OPTIONS 写路径,没有可识别的调用名。这是该 gate 已在脚本头部声明的局限(能防已知缝隙回退,不能发现新缝隙)。修本单时如果能给这条写路径一个稳定的命名入口,可一并加进词表。
参考
发现于 #4632(降级日志级别规则 + 盘点)。
packages/metadata-protocol/**本轮被冻结(#4556 正在改写入路径),因此只记录不修,按 PM 约束单开此单。现象
packages/metadata-protocol/src/seed-loader.ts(约 953–966 行,pass-2 延迟引用回填):注释与代码直接矛盾:注释明确写 "this must be a reported, counted error, never a silent warning",紧跟着的调用却是
logger.warn。为什么这是 #4632 的第二类降级
按 #4632 的判定问句 ——「降级后系统对外表现是否仍然『正常』,而声称已持久化的东西实际没有落盘?」—— 答案是是,而且注释自己已经把后果说得比我更清楚:回填写入失败 ⇒ 引用字段停在
NULL⇒ 循环关系半写入。这就是「记录看起来种下去了、关系实际没落盘」。一点公允之处:紧随其后的
recordDeferredError(...)确实把它计入allErrors,所以不是完全静默 —— 结果对象里数得到。但日志行本身是这次 seed 在控制台唯一可见的痕迹,warn级别正是 #4420 里没人读的那一级。计数与日志级别应当一致。期望
error,文案按 [convention] best-effort 降级导致"看起来正常、实则不持久"时不应记 warn——把 #4460 的点状修复定成规则 #4632 的要求说清后果(<object>.<field>的引用停在 NULL,循环关系半写入)与修复动作(修掉下面的写入错误后重跑 seed;或检查 validation veto);this.logger.warn是否也属第二类 —— 至少writeRecoveringSummary(约 1056 行,roll-up summary 重算耗尽重试)是明确的第一类:注释说明记录已经写入、只是 summary 值可能陈旧,warn是对的,不要一起提。机械检查说明
#4632 的
pnpm check:durability-log-level不会自动发现这一处 —— 该 gate 靠一份显式的「持久化关键操作」词表(DURABILITY_CRITICAL_CALLEES)判定,故意做窄以避免误报,而这里的写入走的是通用SEED_OPTIONS写路径,没有可识别的调用名。这是该 gate 已在脚本头部声明的局限(能防已知缝隙回退,不能发现新缝隙)。修本单时如果能给这条写路径一个稳定的命名入口,可一并加进词表。参考