Skip to content

[metadata-protocol] seed-loader 的「LOUD FAILURE」注释要求 error,代码却记 warn —— 第二类降级(#4632 规则),本轮因包冻结未修 #4729

Description

@os-zhuang

发现于 #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 里没人读的那一级。计数与日志级别应当一致。

期望

机械检查说明

#4632pnpm check:durability-log-level 不会自动发现这一处 —— 该 gate 靠一份显式的「持久化关键操作」词表(DURABILITY_CRITICAL_CALLEES)判定,故意做窄以避免误报,而这里的写入走的是通用 SEED_OPTIONS 写路径,没有可识别的调用名。这是该 gate 已在脚本头部声明的局限(能防已知缝隙回退,不能发现新缝隙)。修本单时如果能给这条写路径一个稳定的命名入口,可一并加进词表。

参考

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions