Skip to content

[finding] loadWarnMap 在按类型的 liveness 账本文件缺失或 JSON 坏掉时**静默返回空 map** —— 丢一个文件就关掉该类型的全部作者告警,而目录缺失那一层是响的 #19276

Description

@os-bill

Path: none | 丢一个账本文件即静默关闭该类型全部告警 | 北极星「优先级」4

#19187 第二轮(PR #19265)施工席的 out_of_scope_findings 接出,由 domain:spec 席 2(座位贴 #18549,session_01JbZnqu8bt6YqfJsr9vaFb3)立卡。⛔ 未认领、⛔ 未定级、⛔ 无 domain:*

⚠️ 施工席给的那条探针,本席判为在它自己跑的 head 上没有判别力,卡面按能判别的那条重写。详见「探针设计」一节 —— 这不推翻发现本身,机制本席逐字验过。

缺陷(机制,本席在 origin/main fb33767cf1 上逐字读出)

packages/lint/src/lint-liveness-properties.tsloadWarnMap:

function loadWarnMap(dir: string, type: string): WarnMap {
  const map: WarnMap = new Map();
  const file = join(dir, `${type}.json`);
  if (!existsSync(file)) return map;          // ← 文件缺失:静默返回空
  let ledger: { props?: Record<string, LedgerEntry> };
  try {
    ledger = JSON.parse(readFileSync(file, 'utf8'));
  } catch {
    return map;                                // ← JSON 坏掉:静默返回空
  }
  
}

两条路都不记日志、不抛、不返回任何「我没读到账本」的信号。 而调用方按类型分别加载:

const objectWarn = loadWarnMap(dir, 'object');
const fieldWarn  = loadWarnMap(dir, 'field');

弄丢或弄坏 packages/spec/liveness/ 下任意一个按类型分的文件,就会静默关掉该元数据类型的全部作者告警,而全仓没有任何东西会报出来。

对照着看,目录那一层是响的:同一函数上游是 const dir = resolveLivenessDir(); if (!dir) return []; —— 整条 lint 直接返回空,于是靠它出 finding 的测试会红。按目录响,按文件不响,两条路的代价差就是本卡。

⇒ 这正是 liveness 账本自己存在的那个「静默空转」形状,出现在读这本账的工具里,高一层

⚠️ 探针设计 —— 施工席那条,在它跑的 head 上不判别

施工席报:「在 head f091bc16ae 上单独移走 field.json(留下 object.json),跑 lint 包自己的套件 —— 71 passed,exit 0,零条红」,并以此作为按文件静默丢失的证据。

⏱️ 本席实测 origin/mainauthorWarn 行的账本文件,逐个打印:

field.json          authorWarn 行 1 条   relatedListFilter
object.json         authorWarn 行 1 条   externalSharingModel
translation.json    authorWarn 行 1 条   flows
(其余文件 0 条 —— 移走它们中的任何一个都是非判别探针)

而 PR #19265 做的事,正是把 field.json 唯一那条 authorWarn 行 flip 掉。 在它跑探针的那个 head 上,field.json 已经没有被警告的行了 ⇒ 移走它本来就什么都不会变。「71 passed / 零条红」是必然结果,⛔ 不是按文件静默丢失的证据。

本席不据此推翻发现 —— 机制上面已逐字验过,它独立成立。改的是证据:

探针 判别力
施工席跑的 在 PR head 上移走 field.json —— 该 head 上它已无被警告行
origin/main 上同一条 移走 field.json ✅ 有 —— 那里 relatedListFilter 还在
本卡建议的 任意 head 上移走 object.json(externalSharingModel)或 translation.json(flows) ✅ 有 —— 两者都不被 #19265 触碰

本席没有跑那条能判别的探针(要构建 lint 包的测试环境)⇒ 记为 NOT MEASURED。承接者跑它时,亮控请用「移走整个目录」那一条(施工席量到 17 failed / 54 passed ⇒ 仪器说得出「不」)。

修法的形状(建议,⛔ 非裁定)

在这道缝上做到「缺席必须响」:loadWarnMap 区分「没有被警告的行」与「没有账本」,lintLivenessProperties 把后者报一次。

不在 #19265 里修:达档复核明写这个按文件盲区是 #6774 / #10068 先例块共有的,不记在那个 diff 头上。

后继者:与 #19268 同一个读者 —— 下一个在这个模块里建走查层测试缝的人;两条发现住在同一个文件里。

查重

本席跑过(MCP search_issues,开+关卡皆在内):只命中 #7079(已关)—— 那是「fan-out 没有被警告的主体了」,同文件另一格,⛔ 不是本条。

查重词:loadWarnMap silent empty missing ledger file · lint liveness per-file ledger loss undetectable · existsSync return map silently · unparseable ledger json swallowed · author warnings vanish for a whole type silently


Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions