Skip to content

check:durability-log-level 结构性看不见「读接缝把故障答成空值」这一类 —— #4825 / #5108 全家都在闸门盲区里 #5186

Closed

Description

@os-zhuang

发现于 #5108(DatabaseLoader 读故障吞成空结果)实现期,不在该单范围内,故单独立卡。未认领 —— 只是记录。观察类,今天没有用户会撞到。

现象

scripts/check-durability-degradation-log-level.mjs 是 #4632 那条规则的机械执行者。它的判据是:

catch 块里调了 DURABILITY_CRITICAL_CALLEES 词表里的操作,而日志级别低于 error 且没有 rethrow → 红。

这个模型对写/DDL 接缝是合身的,对读接缝则结构性地表达不了。两条都不成立:

  1. 词表是按 callee 名字匹配的,而读接缝的 callee 是 find / findOne / count 这种彻底通用的名字 —— 加进词表会把全仓库每一处数据读取都拖进来,不可行。词表现有 9 项(syncSchema、initObjects、writeRecord、dropPromotedDraftRow…)清一色是写/DDL 语义的专名。
  2. 更根本的:读接缝的错误形态不是「日志太轻」,而是「编了一个返回值,且一行都不记」。 catch { return []; } 在闸门眼里连一个可判级别的日志调用都没有 —— 它检查的那个维度在这里是空的。DatabaseLoader 把存储读故障吞成空结果 —— ADR-0110 D3 的 miss/outage 之分在复数读路径上不成立 #5108 修掉的那五处正是这个形状:catch {} → [] / false / null,零日志。[metadata] nextEventSeq() 把驱动读失败也当成「表还没建」,静默从 1 重新发号 —— #4632 同形,机械检查覆盖不到 #4825(nextEventSeq 的 catch { return 1 })是同一族,而且是最贵的那半(写进去的数是错的)。

也就是说:这个族已经在这一个包里出现过三次(#4728 → #4825 → #5108),每次都是人读出来的,闸门一次都没有帮上忙,而且照现在的模型也帮不上。

这一类的可判据形状

三次实例长得一模一样,可以描述:

  • 一个 catch 包着一次读(driver/engine 的 find / findOne / count,或它们的薄封装);
  • catch 体里没有任何日志,也没有 rethrow;
  • 而是 return 一个该方法的空值/零值([] / false / null / 0 / 1)。

判据的关键不在「调了什么」,而在「没读到,却编了一个答案出来」。良性豁免也已经有现成词汇:isMissingTableError()(packages/metadata/src/errors.ts 专门为跨包导出它而存在)—— 一个 catch 只要按错误类型区分过、且只在良性分支返回空值,就应当放行。#4825 和 #5108 修完之后的代码正好就是这个形状,可以直接当 fixture。

为什么不该塞进别的单

建议方向(裁决留给维护者)

  1. 给现有脚本加一条独立规则(不走 DURABILITY_CRITICAL_CALLEES):catch 无日志无 rethrow + return 空值 + 块内含读调用 → 红,除非 catch 里出现按错误类型的区分(isMissingTableError 之类)。必然需要一份 baseline —— 全仓库这个形状的 catch 大概率不少,而且相当一部分是合法的功能性降级;
  2. 或者判定这一族不适合机械判(误报率过高),转而只在 AGENTS.md 里把「读接缝不得编造答案」写成明文规则,靠 review 兜 —— 但那样就要接受它会再犯,并且明说这个取舍;
  3. 或者收窄到只扫元数据/持久化层的读接缝(packages/metadata、packages/metadata-protocol、packages/objectql 的存储缝),把误报面压到可管的范围,再逐步放开。

两条不是本卡要定的;要定的是「这一族目前完全没有机械保护,而它已经复发三次」这一点。

复现

# 现状:五处 `catch {} → 空值` 的读接缝(#5108 修复前的 database-loader.ts)
# 对闸门完全透明 ——
node scripts/check-durability-degradation-log-level.mjs
# → OK,12 durability-critical catch seam(s), all loud or rethrowing

关联

#4632(立规矩)、#4728 / #4825 / #5108(同一族的三次复发)、#4754(词表覆盖的另一半:写接缝)、AGENTS.md「Degradation log levels — warn vs error」「Absence must be loud」、packages/metadata/src/errors.ts(良性判据的现成词汇)。

Activity

  1. added
    toolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    domain:devxDomain lane — seat card indexed by label:pm:seat
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 4, 2026
  2. os-zhuang commented on Aug 5, 2026

    @os-zhuang
    ContributorAuthor

    发现分诊轮:转 needs-user-decision,并按落点改 domain:engine → domain:devx(摘 finding)。

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  3. claude commented on Aug 6, 2026

    @claude
    Contributor

    处置(2026-08-06):退回派发队列,定向方向 3。

    复核结论:三次真实复发(#4728/#4825/#5108),「Absence must be loud」是 AGENTS.md 已明文的不变量,机械化它不是新决策。

    范围:读接缝规则收窄到 metadata / metadata-protocol / objectql 存储缝 + shrink-only baseline;防误报方法论照本脚本自己的先例(#4754/#5241:显式词表、非启发式)。不取方向 2(只写文档=明示接受第四次复发)。量级 M。

    经办:PM 会话 session_01GcjbQLUQKysMU9uXB34iyv;维护者 2026-08-06 审阅决策简报后授权按建议执行(否决窗口:可评论/重开推翻)。


    Generated by Claude Code

  4. added
    pm:queueReady for the PM dispatch loop
    and removed
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    on Aug 6, 2026
  5. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    【裁决落地】维护者 2026-08-06 批复全舰队决策箱评估报告(批复「同意」),本单裁定:

    裁 3——收窄先行:新规则(catch 无日志无 rethrow + return 空值 + 含读调用 → 红,isMissingTableError 豁免)先只扫元数据/持久化层,带 baseline 落地;误报面/成本可控验证后再评估放开全仓(届时由 devx 座位自提,不必回决策箱)。⛔ 不选 2(纯 AGENTS.md 靠 review = 接受 #4728→#4825→#5108 第四次复发)。

    流转:摘 needs-user-decision → pm:queue,归 devx 车道(落点 scripts/)。

    评估与落地会话:session_01N3uGFF8teXbpgtbEJ1aYXu


    Generated by Claude Code

  6. self-assigned this
    on Aug 6, 2026
  7. hotlong commented on Aug 6, 2026

    @hotlong
    Contributor

    认领:PM 循环第 1 轮(devx 车道)
    会话:session_01BDmDsu2575gDxeMCxXhDE3
    分支:claude/issue-5186-durability-read-seam-gate
    Worktree:objectstack-issue-5186
    域:domain:devx
    文件面:scripts/check-durability-degradation-log-level.mjs、scripts/ 下新增 baseline/fixture、.changeset/(越界即停,报告说明)

    按 10:44Z 已落地的裁 3 执行:新读接缝规则收窄到 metadata / metadata-protocol / objectql 存储缝 + shrink-only baseline,isMissingTableError 类型区分豁免;⛔ 不做方向 2。


    Generated by Claude Code

  8. hotlong commented on Aug 6, 2026

    @hotlong
    Contributor

    验收(devx 车道,会话 session_01BDmDsu2575gDxeMCxXhDE3):ACCEPT → PR #5986,已转 ready 并挂入合并队列。

    交付摘要(按维护者 10:44Z「裁 3 —— 收窄先行」):


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:devxDomain lane — seat card indexed by label:pm:seatpm:dispatchedDispatched to a dev agent by /pm-dispatchpm:queueReady for the PM dispatch looptoolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions