Skip to content

MetadataProtocol.listCommits 把 commit store 读不到答成 [] —— ADR-0067 时间线上「无历史」与「读不到」不可分辨(零日志,JSDoc 里写着这是设计) #5980

Description

@hotlong

发现于 #5186(为「读接缝把故障答成空值」这一族新增闸门)实施期,由新规则在 packages/metadata-protocol 扫出;不在该单文件面内(#5186 是纯 scripts/ 闸门单,不改被扫包),故单独立卡并已作为 baseline 条目记录在 scripts/durability-read-invention.baseline.json

现象

packages/metadata-protocol/src/protocol.tslistCommits()(约 9720–9745 行,以 origin/main 为准):

/**
 * List the commit timeline for a package, newest-first (ADR-0067). Returns
 * [] if the commit store is unavailable.        ←← JSDoc 自己就这么写
 */
async listCommits(request): Promise< [] > {
  try {
    const rows = (await this.engine.find('sys_metadata_commit', { where,})) as any[];
    // … 映射 + 按 createdAt 倒序 …
    return mapped;
  } catch {
    return [];
  }
}

catch 里:没有任何日志、没有 rethrow、没有按错误类型区分

为什么这是缺陷而不是设计

这是 ADR-0110 D3(miss 与 outage 是两个意义相反的事实,消费方不得把其中一个读成另一个)在 ADR-0067 提交时间线上的违反,与 #5108DatabaseLoader 修的、#5532同一个文件getMetaItems 修的是同一形状:

  • 存储读不到 → 调用方看到「这个 package 没有任何提交历史」;
  • 「没有提交历史」与「有 12 次提交但库连不上」在返回值上完全一致;
  • 一行日志都没有,整条链路上没有任何地方说过这次读失败了。

后果面朝向 revert:提交时间线是 revertCommit 的选择面。历史被答成空的那一刻,UI 上「无可回滚项」,而实际上有——一次故障期间的运维判断会因此做反。

同一个文件几千行之上已经有了正确形状的处方:rethrowUnlessMetadataStoreUnprovisioned()(#5532 引入),它问 isMissingTableError,良性放行、其余包成 503 上抛。listCommits 只是没走它。

修法

} catch (error) {
  this.rethrowUnlessMetadataStoreUnprovisioned(error);   // 良性(表未建)放行
  return [];                                            // 首启确实没有提交
}

isMissingTableError 与该 guard 在本文件里都已经在用,无新依赖。

验收

  • sys_metadata_commit 未 provision(首启)→ 仍返回 [],不抛、不噪;
  • 驱动报连接错误 / 超时 / 权限失败 → 上抛(503 信封),调用方能把 outage 与 miss 分开;
  • 更新 JSDoc:删掉「Returns [] if the commit store is unavailable」这句(它现在描述的是缺陷);
  • 修好后删除 scripts/durability-read-invention.baseline.json 里的 packages/metadata-protocol/src/protocol.ts::listCommits 条目(shrink-only,条目失效即红)。

关联

#5186(新增本族闸门,本卡由它扫出)、#5532(同文件、同处方,getMetaItems)、#5108(同族,DatabaseLoader 五处读)、#5841(同文件另一处,退休手抄的 /no such table/i)、#4825 / #4728(同族)、ADR-0110 D3、ADR-0067、AGENTS.md「Absence must be loud」。

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions