代码门禁误报率怎么记:一份可解释的审查台账

发布时间:2026/10/28 9:27:00
代码门禁误报率怎么记:一份可解释的审查台账

门禁报了十次,其中三次被开发者关闭,于是报告写“误报率 30%”。关闭可能因为真误报,也可能是临时豁免、重复告警或风险被接受。状态按钮不是人工裁决。

一份能解释的台账要先分清告警、真实问题、待定项和例外,再谈比例。否则模型给出的“准确率”只会让争议变得更难追踪。

先写清分母

在已裁决告警中,误报占比是误报数除以“有效告警加误报告警”。这是告警层面的错误发现比例。统计学里的假阳性率则需要所有真实负例,包括没有触发告警的负例,不能混用名字。

召回率还需要独立问题审计:有多少真实问题被规则发现,有多少漏掉。只看触发的告警,永远看不到漏报。审计样本的抽样方式也要公开;专挑已知 bug 的结果不能代表整个仓库。

图中的“误报率”特指已裁决告警中的误报占比,并非统计学 FPR;待定项另列。

两类记录分别计算

保存为review-ledger.mjs,运行node review-ledger.mjs。下方全部是人工构造样例,没有对应团队成绩。

import assert from "node:assert/strict"; function alertSummary(alerts) { const count = { valid: 0, false: 0, pending: 0 }; const ids = new Set(); for (const a of alerts) { if (ids.has(a.id) || !["valid", "false", "pending"].includes(a.verdict)) throw new Error("duplicate or invalid verdict"); ids.add(a.id); count[a.verdict]++; } const reviewed = count.valid + count.false; return { ...count, reviewed, falseDiscoveryRatio: reviewed ? count.false / reviewed : null }; } function recallFromIssueAudit(issues) { if (!issues.length) return null; if (issues.some(x => typeof x.detected !== "boolean")) throw new Error("audit result missing"); return issues.filter(x => x.detected).length / issues.length; } const alerts = [ { id: "a", verdict: "valid" }, { id: "b", verdict: "valid" }, { id: "c", verdict: "false" }, { id: "d", verdict: "pending" } ]; assert.equal(alertSummary(alerts).falseDiscoveryRatio, 1 / 3); assert.equal(alertSummary(alerts).pending, 1); assert.equal(alertSummary([{ id: "x", verdict: "pending" }]).falseDiscoveryRatio, null); assert.equal(recallFromIssueAudit([{ detected: true }, { detected: false }]), 0.5); assert.equal(recallFromIssueAudit([]), null); assert.throws(() => alertSummary([...alerts, alerts[0]])); console.log("ledger denominators passed; fixture ratios are not team measurements");

待定项不进入已裁决分母,同时单独展示数量。若待定占比很高,报告要说清楚,不能把一个看似漂亮的比例放在首页却藏掉积压。样本少时展示原始数量比保留两位小数更有用。

每条告警要能回到原样例

最少记录规则 ID 与版本、工具版本、提交、文件位置、原始输入、诊断理由、裁决人、裁决时间和后续动作。规则改版后不要覆盖旧裁决:相同样例可以在新版本重新跑,形成前后对照。

重复告警按独立问题聚合,但保留出现次数。临时豁免只表示某个范围暂不阻断,不意味着告警是误报;基线调整也不是修复。把这些状态分开,才能判断问题在规则还是流程。

对于语义争议,可由第二位审查者独立裁决,再记录分歧与最终解释。AI 可以归纳候选与相似案例,不应自行把争议改成 valid,也不应为了让 CI 通过修改金标准。

阻断级别随证据调整

确定且高影响的规则可以进入必需检查;有价值但边界较多的规则先提醒;高噪声规则应补样例或缩小范围。格式、语义和性能波动应分开统计,不能把 Lighthouse 噪声直接算成 ESLint 的语义误报。

保护分支仍要核对必需检查名称、评审和 bypass 配置。台账完整不代表合并控制已经生效;本地报告变绿也不能代替服务端配置验证。

本轮已执行 Node v26.3.0 的分母与重复记录测试,没有扫描真实仓库,没有人工标注团队样本,也没有可报告的实际准确率。示例仅证明计算口径,不证明某条规则有效。

参考资料:ESLint 自定义规则,滚动文档;LHCI 配置,滚动文档;GitHub 保护分支,滚动文档。采用前核对规则与审计样本版本。