slopbrick 0.18.7 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,415 @@
1
1
  var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __esm = (fn, res) => function __init() {
4
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
+ };
2
6
  var __export = (target, all) => {
3
7
  for (var name in all)
4
8
  __defProp(target, name, { get: all[name], enumerable: true });
5
9
  };
6
10
 
11
+ // src/engine/parser-rust.ts
12
+ import Parser from "tree-sitter";
13
+ import Rust from "tree-sitter-rust";
14
+ function getRustParser() {
15
+ if (cachedParser) return { ok: true, parser: cachedParser };
16
+ if (loadError) return { ok: false, error: loadError };
17
+ try {
18
+ rustLanguage = Rust;
19
+ if (!rustLanguage || typeof rustLanguage !== "object") {
20
+ throw new Error("tree-sitter-rust: language export is missing or malformed");
21
+ }
22
+ const parser = new Parser();
23
+ parser.setLanguage(rustLanguage);
24
+ cachedParser = parser;
25
+ return { ok: true, parser };
26
+ } catch (err) {
27
+ loadError = err instanceof Error ? err : new Error(String(err));
28
+ return { ok: false, error: loadError };
29
+ }
30
+ }
31
+ function effectiveParser() {
32
+ if (forcedFailure) return { ok: false, error: forcedFailure };
33
+ return getRustParser();
34
+ }
35
+ function parseRust(source) {
36
+ const result = effectiveParser();
37
+ if (!result.ok) return null;
38
+ if (!source || source.trim() === "") return null;
39
+ try {
40
+ const rawTree = result.parser.parse(source);
41
+ if (!rawTree) return null;
42
+ const tree = rawTree;
43
+ if (!tree || !tree.rootNode) return null;
44
+ if (tree.rootNode.type === "ERROR" && tree.rootNode.childCount === 0) {
45
+ return null;
46
+ }
47
+ return tree;
48
+ } catch {
49
+ return null;
50
+ }
51
+ }
52
+ function isRustParserAvailable() {
53
+ const result = getRustParser();
54
+ return result.ok;
55
+ }
56
+ var cachedParser, rustLanguage, loadError, forcedFailure;
57
+ var init_parser_rust = __esm({
58
+ "src/engine/parser-rust.ts"() {
59
+ "use strict";
60
+ cachedParser = null;
61
+ rustLanguage = null;
62
+ loadError = null;
63
+ forcedFailure = null;
64
+ }
65
+ });
66
+
67
+ // src/engine/visitors/rust.ts
68
+ function parseRustFile(filePath, source, options = {}) {
69
+ const empty = {
70
+ imports: [],
71
+ functions: [],
72
+ structs: [],
73
+ traits: [],
74
+ impls: []
75
+ };
76
+ if (!isRustParserAvailable() || options.forceFallback) {
77
+ return empty;
78
+ }
79
+ const tree = parseRust(source);
80
+ if (!tree) return empty;
81
+ return walkRustTree(tree);
82
+ }
83
+ function walkRustTree(tree) {
84
+ const ctx = { inTestConfig: false };
85
+ const out = {
86
+ imports: [],
87
+ functions: [],
88
+ structs: [],
89
+ traits: [],
90
+ impls: []
91
+ };
92
+ walkChildren(tree.rootNode, ctx, out);
93
+ return out;
94
+ }
95
+ function walkChildren(node, ctx, out) {
96
+ for (let i = 0; i < node.namedChildCount; i++) {
97
+ const child = node.namedChild(i);
98
+ if (!child) continue;
99
+ visitNode(child, ctx, out);
100
+ }
101
+ }
102
+ function visitNode(node, ctx, out) {
103
+ const innerCtx = { ...ctx };
104
+ const attrState = readPrecedingAttributes(node);
105
+ switch (node.type) {
106
+ case "use_declaration": {
107
+ out.imports.push(extractUse(node));
108
+ return;
109
+ }
110
+ case "function_item": {
111
+ const isMethod = isInImplBlock(node);
112
+ out.functions.push(extractFunction(node, attrState, innerCtx.inTestConfig, isMethod));
113
+ walkChildren(getField(node, "body") ?? node, innerCtx, out);
114
+ return;
115
+ }
116
+ case "struct_item": {
117
+ out.structs.push(extractStruct(node, attrState));
118
+ const body = getField(node, "body");
119
+ if (body) walkChildren(body, innerCtx, out);
120
+ return;
121
+ }
122
+ case "trait_item": {
123
+ out.traits.push(extractTrait(node, attrState));
124
+ const body = getField(node, "body");
125
+ if (body) walkChildren(body, innerCtx, out);
126
+ return;
127
+ }
128
+ case "impl_item": {
129
+ const implEntry = extractImpl(node, attrState, innerCtx);
130
+ out.impls.push(implEntry.entry);
131
+ const body = getField(node, "body");
132
+ if (body) walkChildren(body, innerCtx, out);
133
+ return;
134
+ }
135
+ case "mod_item": {
136
+ const modIsTest = innerCtx.inTestConfig || attrState.isTestCfg;
137
+ const modCtx = { ...innerCtx, inTestConfig: modIsTest };
138
+ const body = getField(node, "body");
139
+ if (body) walkChildren(body, modCtx, out);
140
+ return;
141
+ }
142
+ default: {
143
+ for (let i = 0; i < node.namedChildCount; i++) {
144
+ const child = node.namedChild(i);
145
+ if (child) visitNode(child, innerCtx, out);
146
+ }
147
+ }
148
+ }
149
+ }
150
+ function readPrecedingAttributes(node) {
151
+ const state = {
152
+ isTestCfg: false,
153
+ isTest: false,
154
+ isPub: false,
155
+ derives: []
156
+ };
157
+ const parent = node.parent;
158
+ if (!parent) return state;
159
+ for (let i = 0; i < parent.namedChildCount; i++) {
160
+ const sibling = parent.namedChild(i);
161
+ if (!sibling || sibling === node) continue;
162
+ if (sibling.endIndex > node.startIndex) continue;
163
+ if (sibling.type !== "attribute_item") continue;
164
+ decodeAttribute(sibling, state);
165
+ }
166
+ return state;
167
+ }
168
+ function decodeAttribute(attr, state) {
169
+ for (let i = 0; i < attr.namedChildCount; i++) {
170
+ const child = attr.namedChild(i);
171
+ if (!child || child.type !== "attribute") continue;
172
+ const name = firstIdentifier(child);
173
+ if (!name) continue;
174
+ if (name === "cfg") {
175
+ const cfgText = child.text;
176
+ if (/\btest\b/.test(cfgText) && !/\bnot\(test\)/.test(cfgText)) {
177
+ state.isTestCfg = true;
178
+ }
179
+ } else if (name === "test") {
180
+ state.isTest = true;
181
+ } else if (name === "derive") {
182
+ for (let j = 0; j < child.namedChildCount; j++) {
183
+ const inner = child.namedChild(j);
184
+ if (inner) {
185
+ const matches = inner.text.matchAll(/\b([A-Z][A-Za-z0-9_]*)\b/g);
186
+ for (const m of matches) state.derives.push(m[1]);
187
+ }
188
+ }
189
+ }
190
+ }
191
+ }
192
+ function firstIdentifier(node) {
193
+ const text = node.text;
194
+ const idMatch = text.match(/^([a-zA-Z_][a-zA-Z0-9_]*)/);
195
+ return idMatch ? idMatch[1] : null;
196
+ }
197
+ function extractUse(node) {
198
+ const text = node.text;
199
+ const argument = node.namedChild(0);
200
+ const argField = node.childForFieldName("argument");
201
+ const path = argField?.text ?? argument?.text ?? "";
202
+ const names = [];
203
+ let isGlob = false;
204
+ const useListNode = findUseListNode(argument);
205
+ if (useListNode) {
206
+ for (let i = 0; i < useListNode.namedChildCount; i++) {
207
+ const item = useListNode.namedChild(i);
208
+ if (item.type === "use_wildcard") {
209
+ isGlob = true;
210
+ } else if (item.type === "identifier") {
211
+ names.push({ name: item.text });
212
+ } else if (item.type === "use_as_clause") {
213
+ const alias = item.childForFieldName("alias");
214
+ const binding = item.childForFieldName("path");
215
+ if (binding) {
216
+ names.push({ name: binding.text, alias: alias?.text });
217
+ } else {
218
+ names.push({ name: item.text });
219
+ }
220
+ } else if (item.type === "scoped_identifier") {
221
+ const idents = collectIdentifiers(item);
222
+ names.push({ name: idents[idents.length - 1] ?? item.text });
223
+ } else if (item.text.includes(" as ")) {
224
+ const [head, alias] = item.text.split(/\s+as\s+/);
225
+ names.push({ name: (head ?? "").trim(), alias: alias?.trim() });
226
+ } else {
227
+ names.push({ name: item.text });
228
+ }
229
+ }
230
+ } else if (argument?.type === "use_wildcard") {
231
+ isGlob = true;
232
+ } else if (argument) {
233
+ const idents = collectIdentifiers(argument);
234
+ const last = idents[idents.length - 1] ?? argument.text;
235
+ names.push({ name: last });
236
+ const asMatch = text.match(/\s+as\s+(\w+)\s*;?\s*$/);
237
+ if (asMatch) names[0].alias = asMatch[1];
238
+ }
239
+ return {
240
+ path: path.trim(),
241
+ names,
242
+ isGlob,
243
+ line: node.startPosition.row + 1,
244
+ column: node.startPosition.column
245
+ };
246
+ }
247
+ function extractFunction(node, attrs, inheritedTestConfig, isMethod) {
248
+ const nameNode = node.childForFieldName("name");
249
+ const name = nameNode?.text ?? "<anon>";
250
+ const params = node.childForFieldName("parameters");
251
+ const body = node.childForFieldName("body");
252
+ const visibilityMod = node.namedChild(0);
253
+ const isPublic = visibilityMod?.type === "visibility_modifier";
254
+ let receiver;
255
+ if (isMethod && params) {
256
+ const selfParam = findSelfParameter(params);
257
+ if (selfParam) receiver = selfParam.text;
258
+ }
259
+ const bodyLines = body ? body.endPosition.row - body.startPosition.row + 1 : 0;
260
+ const inTestConfig = inheritedTestConfig || attrs.isTest || attrs.isTestCfg || isFunctionAttrTest(node);
261
+ return {
262
+ name,
263
+ line: node.startPosition.row + 1,
264
+ column: node.startPosition.column,
265
+ isPublic,
266
+ isMethod,
267
+ receiver,
268
+ bodyLines,
269
+ inTestConfig
270
+ };
271
+ }
272
+ function extractStruct(node, attrs) {
273
+ const nameNode = node.childForFieldName("name");
274
+ return {
275
+ name: nameNode?.text ?? "<anon>",
276
+ line: node.startPosition.row + 1,
277
+ column: node.startPosition.column,
278
+ isPublic: hasVisibility(node),
279
+ isDerive: attrs.derives.length > 0,
280
+ derives: [...attrs.derives]
281
+ };
282
+ }
283
+ function extractTrait(node, _attrs) {
284
+ const nameNode = node.childForFieldName("name");
285
+ return {
286
+ name: nameNode?.text ?? "<anon>",
287
+ line: node.startPosition.row + 1,
288
+ column: node.startPosition.column,
289
+ isPublic: hasVisibility(node)
290
+ };
291
+ }
292
+ function extractImpl(node, _attrs, _ctx) {
293
+ const traitNode = node.childForFieldName("trait");
294
+ const typeNode = node.childForFieldName("type");
295
+ const typeText = typeNode?.text ?? "<anon>";
296
+ const traitText = traitNode?.text;
297
+ const body = node.childForFieldName("body");
298
+ const methods = [];
299
+ if (body) {
300
+ for (let i = 0; i < body.namedChildCount; i++) {
301
+ const child = body.namedChild(i);
302
+ if (child?.type === "function_item") {
303
+ const m = child.childForFieldName("name");
304
+ if (m) methods.push(m.text);
305
+ }
306
+ }
307
+ }
308
+ return {
309
+ entry: {
310
+ type: typeText,
311
+ trait: traitText ?? void 0,
312
+ methods,
313
+ line: node.startPosition.row + 1,
314
+ column: node.startPosition.column
315
+ }
316
+ };
317
+ }
318
+ function findUseListNode(argument) {
319
+ if (!argument) return null;
320
+ if (argument.type === "use_list") return argument;
321
+ if (argument.type === "scoped_use_list") {
322
+ for (let i = 0; i < argument.namedChildCount; i++) {
323
+ const c = argument.namedChild(i);
324
+ if (c?.type === "use_list") return c;
325
+ }
326
+ }
327
+ return null;
328
+ }
329
+ function getField(node, fieldName) {
330
+ return node.childForFieldName(fieldName);
331
+ }
332
+ function collectIdentifiers(node) {
333
+ const out = [];
334
+ for (let i = 0; i < node.namedChildCount; i++) {
335
+ const child = node.namedChild(i);
336
+ if (!child) continue;
337
+ if (child.type === "identifier" || child.type === "type_identifier") {
338
+ out.push(child.text);
339
+ } else if (child.type === "scoped_identifier" || child.type === "nested_identifier") {
340
+ out.push(...collectIdentifiers(child));
341
+ }
342
+ }
343
+ return out;
344
+ }
345
+ function hasVisibility(node) {
346
+ return node.namedChild(0)?.type === "visibility_modifier";
347
+ }
348
+ function isInImplBlock(node) {
349
+ for (let p = node.parent; p; p = p.parent) {
350
+ if (p.type === "impl_item") return true;
351
+ if (p.type === "function_item" || p.type === "source_file") return false;
352
+ }
353
+ return false;
354
+ }
355
+ function findSelfParameter(params) {
356
+ for (let i = 0; i < params.namedChildCount; i++) {
357
+ const child = params.namedChild(i);
358
+ if (child?.type === "self_parameter") return child;
359
+ }
360
+ return null;
361
+ }
362
+ function isFunctionAttrTest(node) {
363
+ void node;
364
+ return false;
365
+ }
366
+ var SERVICE_SUFFIXES, SERVICE_SUFFIX_GROUP, RUST_SERVICE_STRUCT_RE, RUST_SERVICE_IMPL_RE;
367
+ var init_rust = __esm({
368
+ "src/engine/visitors/rust.ts"() {
369
+ "use strict";
370
+ init_parser_rust();
371
+ SERVICE_SUFFIXES = [
372
+ "Service",
373
+ "Manager",
374
+ "Handler",
375
+ "Repository",
376
+ "Controller",
377
+ "Helper",
378
+ "Factory",
379
+ "Provider",
380
+ "Store",
381
+ "API",
382
+ "Client",
383
+ "Adapter",
384
+ "Resolver",
385
+ "Mapper",
386
+ "Transformer",
387
+ "Serializer",
388
+ "Validator",
389
+ "Strategy",
390
+ "Facade",
391
+ "Decorator",
392
+ "Observer",
393
+ "Builder",
394
+ "Command",
395
+ "Processor",
396
+ "Worker",
397
+ "Job",
398
+ "Actor",
399
+ "Executor"
400
+ ];
401
+ SERVICE_SUFFIX_GROUP = `(?:${SERVICE_SUFFIXES.join("|")})`;
402
+ RUST_SERVICE_STRUCT_RE = new RegExp(
403
+ `^(?:pub(?:\\(crate\\)|\\(super\\))?\\s+)?struct\\s+(\\w+?)${SERVICE_SUFFIX_GROUP}?\\b`,
404
+ "gm"
405
+ );
406
+ RUST_SERVICE_IMPL_RE = new RegExp(
407
+ `^impl(?:<[^>]+>)?\\s+(?:${SERVICE_SUFFIX_GROUP}\\s+for\\s+)?(\\w+?)${SERVICE_SUFFIX_GROUP}?\\b`,
408
+ "gm"
409
+ );
410
+ }
411
+ });
412
+
7
413
  // src/engine/worker.ts
8
414
  import { isMainThread, parentPort, workerData } from "worker_threads";
9
415
  import { extname as extname6 } from "path";
@@ -4239,7 +4645,7 @@ function parseBlankModule(source) {
4239
4645
  tsx: false,
4240
4646
  target: "es2022"
4241
4647
  });
4242
- return { ast, source: replaced };
4648
+ return { ast, source };
4243
4649
  }
4244
4650
  function parseScriptContent(content, isTypeScript) {
4245
4651
  if (isTypeScript) {
@@ -4325,8 +4731,16 @@ function parseSource(source, filePath) {
4325
4731
  // but no SWC support. Return a blank-padded empty module so
4326
4732
  // regex-only rules can still fire (markdown-leakage, comment-
4327
4733
  // ratio, etc.) without burning the parseError path.
4734
+ // v0.18.9: `.rs` is in the same bucket. The visitor layer
4735
+ // (`engine/visitors/rust.ts`) carries the tree-sitter-backed
4736
+ // parse + extractFacts attaches the result to `facts.v2.rustFile`.
4737
+ // The rule layer (`rules/rust/*.ts`) reads that field. parseBlankModule
4738
+ // lets the worker continue past the parser — without this, parseWithSwc
4739
+ // would throw on every .rs file, the worker would count it as a
4740
+ // parseError, and the v2-build's buildRustFileRecord would never run.
4328
4741
  case "py":
4329
4742
  case "go":
4743
+ case "rs":
4330
4744
  return parseBlankModule(source);
4331
4745
  default:
4332
4746
  return parseWithSwc(source, filePath);
@@ -5021,76 +5435,6 @@ function tokenizeIdentifiers(source) {
5021
5435
  return tokens;
5022
5436
  }
5023
5437
  var SQRT_2_TIMES_LN_2 = Math.sqrt(2 * Math.LN2);
5024
- function ecdfAt(sortedSamples, x) {
5025
- let lo = 0;
5026
- let hi = sortedSamples.length;
5027
- while (lo < hi) {
5028
- const mid = lo + hi >>> 1;
5029
- if (sortedSamples[mid] <= x) lo = mid + 1;
5030
- else hi = mid;
5031
- }
5032
- return lo / sortedSamples.length;
5033
- }
5034
- function ksStatistic(sampleA, sampleB) {
5035
- if (sampleA.length === 0 || sampleB.length === 0) return 1;
5036
- const sortedA = [...sampleA].sort((a, b) => a - b);
5037
- const sortedB = [...sampleB].sort((a, b) => a - b);
5038
- const allPoints = [...sortedA, ...sortedB].sort((a, b) => a - b);
5039
- let maxDiff = 0;
5040
- for (const x of allPoints) {
5041
- const fa = ecdfAt(sortedA, x);
5042
- const fb = ecdfAt(sortedB, x);
5043
- const diff = Math.abs(fa - fb);
5044
- if (diff > maxDiff) maxDiff = diff;
5045
- }
5046
- return maxDiff;
5047
- }
5048
- function ksPValue(statistic, n, m) {
5049
- if (n === 0 || m === 0) return 1;
5050
- if (statistic < 0) return 1;
5051
- if (statistic > 1) return 0;
5052
- const lambda = Math.sqrt(n * m / (n + m)) * statistic;
5053
- if (lambda > 3.6) return 0;
5054
- let p = 0;
5055
- for (let j = 1; j < 1e3; j++) {
5056
- const term = 2 * Math.pow(-1, j - 1) * Math.exp(-2 * j * j * lambda * lambda);
5057
- p += term;
5058
- if (Math.abs(term) < 1e-15) break;
5059
- }
5060
- return Math.max(0, Math.min(1, p));
5061
- }
5062
- function ksTest(sampleA, sampleB, alpha = 0.05) {
5063
- const statistic = ksStatistic(sampleA, sampleB);
5064
- const pValue = ksPValue(statistic, sampleA.length, sampleB.length);
5065
- return {
5066
- statistic,
5067
- pValue,
5068
- significant: pValue < alpha,
5069
- n: sampleA.length,
5070
- m: sampleB.length
5071
- };
5072
- }
5073
- function multiFeatureKsTest(features, baselines, alpha = 0.05) {
5074
- const featureNames = [...features.keys()];
5075
- const k = featureNames.length;
5076
- const bonferroniAlpha = k > 0 ? alpha / k : alpha;
5077
- const perFeature = /* @__PURE__ */ new Map();
5078
- const significantFeatures = [];
5079
- for (const name of featureNames) {
5080
- const sample = features.get(name);
5081
- const baseline = baselines.get(name);
5082
- if (!sample || !baseline) continue;
5083
- const result = ksTest(sample, baseline, bonferroniAlpha);
5084
- perFeature.set(name, result);
5085
- if (result.significant) significantFeatures.push(name);
5086
- }
5087
- return {
5088
- perFeature,
5089
- bonferroniAlpha,
5090
- anySignificant: significantFeatures.length > 0,
5091
- significantFeatures
5092
- };
5093
- }
5094
5438
 
5095
5439
  // src/engine/visitors/react.ts
5096
5440
  function isObject(node) {
@@ -6891,6 +7235,7 @@ function dispatchNode(node, parent, path, vctx) {
6891
7235
  }
6892
7236
 
6893
7237
  // src/engine/visitors/v2-build.ts
7238
+ init_rust();
6894
7239
  var TAILWIND_COLOR_RE = /^(?:bg|text|border|ring|from|to|via|fill|stroke)-([a-z]+-\d+|white|black|transparent|current|\[.+?\])$/;
6895
7240
  var TAILWIND_SPACING_RE = /^(?:[pm][xytrbl]?|gap|space-[xy])-(\d+(?:\.\d+)?)$/;
6896
7241
  var TAILWIND_RADIUS_RE = /^(?:rounded(?:-[a-z]+)?)-(.+)$/;
@@ -7071,9 +7416,60 @@ function buildV2Facts(facts, source, ext, framework, config, templateClassNames
7071
7416
  })),
7072
7417
  disabledRules: extractDisabledRules(source),
7073
7418
  templateClassNames,
7419
+ // v0.18.9 — populate the Rust AST record when the file is `.rs`.
7420
+ // Calling `parseRustFile` here keeps the dead-code detector's
7421
+ // import-binding pass a pure function over the same source the
7422
+ // walker saw. The native-binding guard lives inside
7423
+ // `parseRustFile` (returns an empty record when tree-sitter is
7424
+ // unavailable).
7425
+ rustFile: buildRustFileRecord(facts.filePath, source),
7074
7426
  _source: source
7075
7427
  };
7076
7428
  }
7429
+ function buildRustFileRecord(filePath, source) {
7430
+ if (!filePath.toLowerCase().endsWith(".rs")) return void 0;
7431
+ const structure = parseRustFile(filePath, source);
7432
+ return {
7433
+ imports: structure.imports.map((i) => ({
7434
+ path: i.path,
7435
+ names: i.names.map((n) => ({ name: n.name, ...n.alias ? { alias: n.alias } : {} })),
7436
+ isGlob: i.isGlob,
7437
+ line: i.line,
7438
+ column: i.column
7439
+ })),
7440
+ functions: structure.functions.map((f) => ({
7441
+ name: f.name,
7442
+ line: f.line,
7443
+ column: f.column,
7444
+ isPublic: f.isPublic,
7445
+ isMethod: f.isMethod,
7446
+ ...f.receiver ? { receiver: f.receiver } : {},
7447
+ bodyLines: f.bodyLines,
7448
+ inTestConfig: f.inTestConfig
7449
+ })),
7450
+ structs: structure.structs.map((s) => ({
7451
+ name: s.name,
7452
+ line: s.line,
7453
+ column: s.column,
7454
+ isPublic: s.isPublic,
7455
+ isDerive: s.isDerive,
7456
+ derives: [...s.derives]
7457
+ })),
7458
+ traits: structure.traits.map((t) => ({
7459
+ name: t.name,
7460
+ line: t.line,
7461
+ column: t.column,
7462
+ isPublic: t.isPublic
7463
+ })),
7464
+ impls: structure.impls.map((ip) => ({
7465
+ ...ip.trait ? { trait: ip.trait } : {},
7466
+ type: ip.type,
7467
+ methods: [...ip.methods],
7468
+ line: ip.line,
7469
+ column: ip.column
7470
+ }))
7471
+ };
7472
+ }
7077
7473
  function splitFilePath(filePath) {
7078
7474
  const baseName = filePath.split("/").pop() ?? filePath;
7079
7475
  const dotIdx = baseName.lastIndexOf(".");
@@ -34575,9 +34971,43 @@ var unusedImportRule = createRule({
34575
34971
  advice: `Remove the import or use '${binding.name}' somewhere in the file. This is the most common AI-iteration rot \u2014 the model added the import when it introduced a feature, then rewrote the function without cleaning up.`
34576
34972
  });
34577
34973
  }
34974
+ if (facts.v2.rustFile) {
34975
+ const strippedSource = stripUseDeclarations(facts.v2._source ?? "");
34976
+ const referenced = collectRustReferencedNames(strippedSource);
34977
+ for (const imp of facts.v2.rustFile.imports) {
34978
+ for (const nameEntry of imp.names) {
34979
+ if (referenced.has(nameEntry.name)) continue;
34980
+ const source = ` from '${imp.path}'`;
34981
+ issues.push({
34982
+ ruleId: "dead/unused-import",
34983
+ category: "logic",
34984
+ severity: "low",
34985
+ aiSpecific: true,
34986
+ message: `Unused import: '${nameEntry.name}'${source}`,
34987
+ line: imp.line,
34988
+ column: imp.column,
34989
+ advice: `Remove the '${imp.path}' import or use '${nameEntry.name}' somewhere in the file. Rust's compiler only flags unused imports per module \u2014 the tree-sitter-backed walker here surfaces them for slopbrick's dead-code rules regardless of #[allow(unused_imports)].`
34990
+ });
34991
+ }
34992
+ }
34993
+ }
34578
34994
  return issues;
34579
34995
  }
34580
34996
  });
34997
+ function collectRustReferencedNames(source) {
34998
+ const out = /* @__PURE__ */ new Set();
34999
+ for (const m of source.matchAll(/\b([A-Za-z_][A-Za-z0-9_]*)\b/g)) {
35000
+ out.add(m[1]);
35001
+ }
35002
+ return out;
35003
+ }
35004
+ function stripUseDeclarations(source) {
35005
+ let out = source;
35006
+ out = out.replace(/^\s*use\s+[\s\S]*?;\s*$/gm, "");
35007
+ out = out.replace(/\/\/[^\n]*/g, "");
35008
+ out = out.replace(/\/\*[\s\S]*?\*\//g, "");
35009
+ return out;
35010
+ }
34581
35011
 
34582
35012
  // src/rules/dead/unused-local.ts
34583
35013
  var SKIP_NAMES = /* @__PURE__ */ new Set(["React", "_"]);
@@ -35734,6 +36164,218 @@ var brokenLinkRule = createRule({
35734
36164
  }
35735
36165
  });
35736
36166
 
36167
+ // src/rules/dup/identical-block.ts
36168
+ import * as crypto from "crypto";
36169
+ var WINDOW_SIZE = 10;
36170
+ var MIN_NORMALIZED_LENGTH = 40;
36171
+ var HASH_PREFIX_LENGTH = 16;
36172
+ var DEDUP_CACHE = /* @__PURE__ */ new Map();
36173
+ function normalizeAndHash(lines) {
36174
+ const normalized = lines.map(
36175
+ (line) => line.replace(/\/\/.*$/, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s+/g, " ").trim()
36176
+ ).filter((line) => line.length > 0).join("\n");
36177
+ if (normalized.length < MIN_NORMALIZED_LENGTH) return void 0;
36178
+ return crypto.createHash("sha1").update(normalized).digest("hex").slice(0, HASH_PREFIX_LENGTH);
36179
+ }
36180
+ var dupIdenticalBlockRule = createRule({
36181
+ id: "dup/identical-block",
36182
+ category: "logic",
36183
+ severity: "medium",
36184
+ aiSpecific: false,
36185
+ description: "Block of >=10 lines is identical across >=2 files (Type-1 clone detector)",
36186
+ create(_context) {
36187
+ return {};
36188
+ },
36189
+ analyze(_context, facts) {
36190
+ const issues = [];
36191
+ const source = facts.v2?._source;
36192
+ if (!source) return issues;
36193
+ const filePath = facts.filePath;
36194
+ const lines = source.split("\n");
36195
+ for (let i = 0; i <= lines.length - WINDOW_SIZE; i++) {
36196
+ const window = lines.slice(i, i + WINDOW_SIZE);
36197
+ const hash = normalizeAndHash(window);
36198
+ if (!hash) continue;
36199
+ const existing = DEDUP_CACHE.get(hash) ?? [];
36200
+ const matches = existing.filter((m) => m.file !== filePath);
36201
+ for (const match of matches) {
36202
+ issues.push({
36203
+ ruleId: "dup/identical-block",
36204
+ category: "logic",
36205
+ severity: "medium",
36206
+ aiSpecific: false,
36207
+ message: `Identical ${WINDOW_SIZE}-line block at line ${i + 1} also appears in ${match.file}:${match.line + 1}`,
36208
+ line: i + 1,
36209
+ column: 0,
36210
+ advice: "Refactor to a shared helper. This is a Type-1 clone (byte-for-byte identical after normalization). Common in AI-generated code that copy-pastes from training data.",
36211
+ extras: {
36212
+ duplicateOf: {
36213
+ file: match.file,
36214
+ line: match.line + 1,
36215
+ hash
36216
+ }
36217
+ }
36218
+ });
36219
+ }
36220
+ existing.push({ file: filePath, line: i });
36221
+ DEDUP_CACHE.set(hash, existing);
36222
+ }
36223
+ return issues;
36224
+ }
36225
+ });
36226
+
36227
+ // src/rules/go/error-wrap-without-context.ts
36228
+ var ERR_WRAP_REGEX = /fmt\.Errorf\(\s*"((?:[^"\\]|\\.)*)"\s*,\s*([^)]+)\)/g;
36229
+ var GENERIC_PREFIX_REGEX = /^\s*(?:error|err|failed|wrap(?:ping)?|invalid)\s*(?::\s*)?%w\b/i;
36230
+ var goErrorWrapWithoutContextRule = createRule({
36231
+ id: "go/error-wrap-without-context",
36232
+ category: "typo",
36233
+ severity: "low",
36234
+ aiSpecific: true,
36235
+ description: 'fmt.Errorf wrap without operation context \u2014 AI defaults to generic "error: %w"',
36236
+ create(_context) {
36237
+ return {};
36238
+ },
36239
+ analyze(_context, facts) {
36240
+ const issues = [];
36241
+ const source = facts.v2?._source;
36242
+ if (!source) return issues;
36243
+ let match;
36244
+ ERR_WRAP_REGEX.lastIndex = 0;
36245
+ while ((match = ERR_WRAP_REGEX.exec(source)) !== null) {
36246
+ const formatString = match[1];
36247
+ if (!formatString.includes("%w")) continue;
36248
+ if (formatString.length >= 30) continue;
36249
+ if (!GENERIC_PREFIX_REGEX.test(formatString)) continue;
36250
+ const line = source.slice(0, match.index).split("\n").length;
36251
+ issues.push({
36252
+ ruleId: "go/error-wrap-without-context",
36253
+ category: "typo",
36254
+ severity: "low",
36255
+ aiSpecific: true,
36256
+ message: `fmt.Errorf wrap with generic message "${formatString}" \u2014 include the failing operation`,
36257
+ line,
36258
+ column: match[0].indexOf("fmt") + 1,
36259
+ advice: 'Real Go errors include the failing operation: `fmt.Errorf("opening config: %w", err)`. Generic messages ("error: %w", "failed: %w") tell the reader nothing about what failed. Reference: go/error-wrap-without-context v0.19. See: https://github.com/golang/go/wiki/CodeReviewComments#error-strings'
36260
+ });
36261
+ }
36262
+ return issues;
36263
+ }
36264
+ });
36265
+
36266
+ // src/rules/go/nil-slice-vs-empty.ts
36267
+ var NIL_SLICE_DECL_REGEX = /^[\t ]*var\s+([A-Za-z_][A-Za-z0-9_]*)\s+\[\][\w.*]+\b/gm;
36268
+ var EMPTY_SLICE_ASSIGN_REGEX = /^[\t ]*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(?:\[\][\w.*]*\{\}|make\(\[\][\w.*]*)/gm;
36269
+ var goNilSliceVsEmptyRule = createRule({
36270
+ id: "go/nil-slice-vs-empty",
36271
+ category: "typo",
36272
+ severity: "low",
36273
+ aiSpecific: true,
36274
+ description: "Variable declared `var x []int` but later assigned `x = []int{}` or `make([]int, n)` \u2014 pick one form",
36275
+ create(_context) {
36276
+ return {};
36277
+ },
36278
+ analyze(_context, facts) {
36279
+ const issues = [];
36280
+ const source = facts.v2?._source;
36281
+ if (!source) return issues;
36282
+ const nilDecls = /* @__PURE__ */ new Map();
36283
+ let m;
36284
+ NIL_SLICE_DECL_REGEX.lastIndex = 0;
36285
+ while ((m = NIL_SLICE_DECL_REGEX.exec(source)) !== null) {
36286
+ nilDecls.set(m[1], source.slice(0, m.index).split("\n").length);
36287
+ }
36288
+ if (nilDecls.size === 0) return issues;
36289
+ EMPTY_SLICE_ASSIGN_REGEX.lastIndex = 0;
36290
+ while ((m = EMPTY_SLICE_ASSIGN_REGEX.exec(source)) !== null) {
36291
+ const name = m[1];
36292
+ if (!nilDecls.has(name)) continue;
36293
+ const declLine = nilDecls.get(name);
36294
+ const assignLine = source.slice(0, m.index).split("\n").length;
36295
+ if (assignLine <= declLine) continue;
36296
+ issues.push({
36297
+ ruleId: "go/nil-slice-vs-empty",
36298
+ category: "typo",
36299
+ severity: "low",
36300
+ aiSpecific: true,
36301
+ message: `Variable '${name}' declared as nil slice (line ${declLine}) but assigned an empty slice (line ${assignLine}) \u2014 pick one form`,
36302
+ line: declLine,
36303
+ column: 1,
36304
+ advice: "Either declare as `var " + name + " = []int{}` or assign with `make([]int, 0)`. The nil/empty inconsistency is an AI signal \u2014 real code picks one form and sticks with it. Reference: go/nil-slice-vs-empty v0.19."
36305
+ });
36306
+ }
36307
+ return issues;
36308
+ }
36309
+ });
36310
+
36311
+ // src/rules/go/struct-tag-inconsistency.ts
36312
+ var JSON_TAG_REGEX = /`json:"([^",]+)(?:,([^"]+))?"`/g;
36313
+ var goStructTagInconsistencyRule = createRule({
36314
+ id: "go/struct-tag-inconsistency",
36315
+ category: "typo",
36316
+ severity: "low",
36317
+ aiSpecific: true,
36318
+ description: 'Struct fields mix json:"foo" and json:"foo,omitempty" \u2014 pick one convention per struct',
36319
+ create(_context) {
36320
+ return {};
36321
+ },
36322
+ analyze(_context, facts) {
36323
+ const issues = [];
36324
+ const source = facts.v2?._source;
36325
+ if (!source) return issues;
36326
+ const structRegex = /type\s+[A-Z][A-Za-z0-9_]*\s+struct\s*\{/g;
36327
+ let structMatch;
36328
+ while ((structMatch = structRegex.exec(source)) !== null) {
36329
+ const startIdx = structMatch.index;
36330
+ const openBrace = source.indexOf("{", startIdx);
36331
+ if (openBrace < 0) continue;
36332
+ let depth = 1;
36333
+ let i = openBrace + 1;
36334
+ while (i < source.length && depth > 0) {
36335
+ const ch = source[i];
36336
+ if (ch === "{") depth++;
36337
+ else if (ch === "}") depth--;
36338
+ i++;
36339
+ }
36340
+ const structBody = source.slice(openBrace, i);
36341
+ const structLine = source.slice(0, startIdx).split("\n").length;
36342
+ const styleCount = {};
36343
+ const tagMatches = [];
36344
+ let m;
36345
+ JSON_TAG_REGEX.lastIndex = 0;
36346
+ while ((m = JSON_TAG_REGEX.exec(structBody)) !== null) {
36347
+ const tag = m[1];
36348
+ const options = m[2] ?? "";
36349
+ const style = options ? "with-options" : "no-options";
36350
+ styleCount[style] = (styleCount[style] ?? 0) + 1;
36351
+ tagMatches.push({ tag, style, idx: openBrace + m.index });
36352
+ }
36353
+ const styles = Object.keys(styleCount);
36354
+ if (styles.length < 2 || tagMatches.length < 2) continue;
36355
+ const dominant = styles.reduce(
36356
+ (a, b) => (styleCount[a] ?? 0) >= (styleCount[b] ?? 0) ? a : b
36357
+ );
36358
+ const minority = tagMatches.filter((t) => t.style !== dominant);
36359
+ if (minority.length === 0) continue;
36360
+ for (const m2 of minority) {
36361
+ const line = source.slice(0, m2.idx).split("\n").length;
36362
+ issues.push({
36363
+ ruleId: "go/struct-tag-inconsistency",
36364
+ category: "typo",
36365
+ severity: "low",
36366
+ aiSpecific: true,
36367
+ message: `Struct mixes json tag styles \u2014 this field uses "json:"${m2.tag}${m2.style === "with-options" ? ",..." : ""}"" but the dominant style is ${dominant === "with-options" ? "with options (e.g. omitempty)" : "no options"}`,
36368
+ line,
36369
+ column: 1,
36370
+ advice: 'Pick one tag style per struct. If most fields are `json:"foo"`, this field should be too. Real Go code maintains consistency within a struct (or within a package). Reference: go/struct-tag-inconsistency v0.19.'
36371
+ });
36372
+ }
36373
+ if (issues.length > 0) break;
36374
+ }
36375
+ return issues;
36376
+ }
36377
+ });
36378
+
35737
36379
  // src/rules/layout/gap-monopoly.ts
35738
36380
  var GAP_RE = /\bgap(?:-x|-y)?-(\d+)\b/g;
35739
36381
  var gapMonopolyRule = createRule({
@@ -36521,82 +37163,6 @@ var keyPropMissingRule = createRule({
36521
37163
  }
36522
37164
  });
36523
37165
 
36524
- // src/rules/logic/ks-distribution-shift.ts
36525
- var MIN_SAMPLES_PER_FEATURE = 20;
36526
- function extractFileFeatures(source) {
36527
- const lines = source.split("\n");
36528
- const lineLengths = lines.map((l) => l.length);
36529
- const identifierLengths = [];
36530
- const idRe = /[A-Za-z_$][A-Za-z0-9_$]*/g;
36531
- let m;
36532
- while ((m = idRe.exec(source)) !== null) {
36533
- identifierLengths.push(m[0].length);
36534
- }
36535
- const commentDensity = lines.map((l) => {
36536
- const trimmed = l.trim();
36537
- if (trimmed.length === 0) return 0;
36538
- const commentChars = (trimmed.match(/^\/\/.*$/)?.[0]?.length ?? 0) + (trimmed.match(/^\s*\/\*.*?\*\/\s*$/)?.at(0)?.length ?? 0);
36539
- return commentChars / trimmed.length;
36540
- });
36541
- return { lineLengths, identifierLengths, commentDensity };
36542
- }
36543
- var ksDistributionShiftRule = createRule({
36544
- id: "logic/ks-distribution-shift",
36545
- category: "logic",
36546
- severity: "medium",
36547
- aiSpecific: false,
36548
- description: "Multi-feature Kolmogorov\u2013Smirnov distribution-shift vs corpus baseline (Bonferroni-corrected). Peer-reviewed ML distribution-shift detector (arXiv:2510.15996, Oct 2025).",
36549
- create(context) {
36550
- return context;
36551
- },
36552
- analyze(_context, facts) {
36553
- const issues = [];
36554
- if (!facts.v2) return issues;
36555
- const source = facts.v2._source ?? "";
36556
- if (source.length < 200) return issues;
36557
- const features = extractFileFeatures(source);
36558
- const samples = /* @__PURE__ */ new Map([
36559
- ["lineLengths", features.lineLengths],
36560
- ["identifierLengths", features.identifierLengths],
36561
- ["commentDensity", features.commentDensity]
36562
- ]);
36563
- const baselines = getCorpusBaselines();
36564
- const baselinesMap = /* @__PURE__ */ new Map();
36565
- if (baselines) {
36566
- baselinesMap.set("lineLengths", baselines.features.lineLengths.sample);
36567
- baselinesMap.set("identifierLengths", baselines.features.identifierLengths.sample);
36568
- baselinesMap.set("commentDensity", baselines.features.commentDensity.sample);
36569
- } else {
36570
- baselinesMap.set("lineLengths", [20, 25, 30, 32, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]);
36571
- baselinesMap.set("identifierLengths", [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 24, 28]);
36572
- baselinesMap.set("commentDensity", [0, 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.4, 0.5]);
36573
- }
36574
- for (const [name, vals] of samples) {
36575
- if (vals.length < MIN_SAMPLES_PER_FEATURE) samples.delete(name);
36576
- }
36577
- if (samples.size === 0) return issues;
36578
- const result = multiFeatureKsTest(samples, baselinesMap, 0.05);
36579
- if (!result.anySignificant) return issues;
36580
- const shifted = result.significantFeatures.join(", ");
36581
- const details = result.significantFeatures.map((name) => {
36582
- const r = result.perFeature.get(name);
36583
- if (!r) return name;
36584
- return `${name} (D=${r.statistic.toFixed(3)}, p=${r.pValue.toExponential(2)})`;
36585
- }).join("; ");
36586
- issues.push({
36587
- ruleId: "logic/ks-distribution-shift",
36588
- category: "logic",
36589
- severity: "medium",
36590
- aiSpecific: true,
36591
- message: `Distribution shift detected on ${result.significantFeatures.length} of ${result.perFeature.size} features (Bonferroni \u03B1=${result.bonferroniAlpha.toExponential(2)}). Features: ${shifted}. Detail: ${details}.`,
36592
- line: 1,
36593
- column: 1,
36594
- advice: "Inspect the shifted features. KS detects both AI anomalies and production-rot anomalies (it is symmetric); combine with Heaps/Zipf for AI-specific signal."
36595
- });
36596
- return issues;
36597
- }
36598
- });
36599
-
36600
37166
  // src/rules/logic/math-any-density.ts
36601
37167
  var ANY_PER_100_LINES = 5;
36602
37168
  var MIN_ABSOLUTE = 6;
@@ -36658,7 +37224,7 @@ var mathAnyDensityRule = createRule({
36658
37224
  });
36659
37225
 
36660
37226
  // src/rules/logic/math-console-log-storm.ts
36661
- var WINDOW_SIZE = 30;
37227
+ var WINDOW_SIZE2 = 30;
36662
37228
  var STORM_THRESHOLD = 5;
36663
37229
  var CONSOLE_LOG_RE = /\bconsole\.log\s*\(/g;
36664
37230
  var mathConsoleLogStormRule = createRule({
@@ -36689,7 +37255,7 @@ var mathConsoleLogStormRule = createRule({
36689
37255
  let maxEndLine = 0;
36690
37256
  let i = 0;
36691
37257
  for (let j = 0; j < lines.length; j++) {
36692
- while (lines[j] - lines[i] > WINDOW_SIZE) i++;
37258
+ while (lines[j] - lines[i] > WINDOW_SIZE2) i++;
36693
37259
  const count = j - i + 1;
36694
37260
  if (count > maxCount) {
36695
37261
  maxCount = count;
@@ -36703,7 +37269,7 @@ var mathConsoleLogStormRule = createRule({
36703
37269
  category: "logic",
36704
37270
  severity: "high",
36705
37271
  aiSpecific: true,
36706
- message: `${maxCount} console.log calls clustered in a ${WINDOW_SIZE}-line window ending at line ${maxEndLine}. AI debug-sprays logs in a single function; humans use one strategic log.`,
37272
+ message: `${maxCount} console.log calls clustered in a ${WINDOW_SIZE2}-line window ending at line ${maxEndLine}. AI debug-sprays logs in a single function; humans use one strategic log.`,
36707
37273
  line: firstIdx >= 0 ? lines[firstIdx] : 1,
36708
37274
  column: firstIdx >= 0 ? columns[firstIdx] : 1,
36709
37275
  advice: "Replace debug logs with a proper debugger or logger.debug() \u2014 remove all console.log before shipping."
@@ -37490,6 +38056,326 @@ var uxPatternFragmentationRule = createRule({
37490
38056
  }
37491
38057
  });
37492
38058
 
38059
+ // src/rules/rust/stringly-typed.ts
38060
+ var SUSPECT_PARAM_NAMES = /* @__PURE__ */ new Set([
38061
+ "kind",
38062
+ "type",
38063
+ "mode",
38064
+ "event",
38065
+ "status",
38066
+ "category",
38067
+ "action",
38068
+ "state",
38069
+ "level",
38070
+ "role",
38071
+ "tier",
38072
+ "phase",
38073
+ "tag",
38074
+ "format",
38075
+ "shape",
38076
+ "direction",
38077
+ "side",
38078
+ "method"
38079
+ ]);
38080
+ var MAX_VARIANT_COUNT = 32;
38081
+ var rustStringlyTypedRule = createRule({
38082
+ id: "rust/stringly-typed",
38083
+ category: "logic",
38084
+ severity: "medium",
38085
+ aiSpecific: true,
38086
+ description: "String / &str parameter where a typed enum exists in the same file",
38087
+ create(_context) {
38088
+ return {};
38089
+ },
38090
+ analyze(_context, facts) {
38091
+ const issues = [];
38092
+ if (!facts.v2?.rustFile) return issues;
38093
+ const source = facts.v2._source ?? "";
38094
+ if (!source) return issues;
38095
+ const lineOffsets = buildLineOffsets2(source);
38096
+ const enumCandidates = collectEnumCandidates(source);
38097
+ if (enumCandidates.length === 0) return issues;
38098
+ for (const fn of facts.v2.rustFile.functions) {
38099
+ const paramText = extractParameterText(source, lineOffsets, fn);
38100
+ if (!paramText) continue;
38101
+ const matches = scanForStringlyParams(paramText);
38102
+ if (matches.length === 0) continue;
38103
+ issues.push({
38104
+ ruleId: "rust/stringly-typed",
38105
+ category: "logic",
38106
+ severity: "medium",
38107
+ aiSpecific: true,
38108
+ message: matches.length === 1 ? `Parameter '${matches[0].name}' typed as '${matches[0].type}', but enum ${enumCandidates[0].name} exists in the file` : `Function has ${matches.length} stringly-typed parameters; enum ${enumCandidates[0].name} exists in the file`,
38109
+ line: fn.line,
38110
+ column: fn.column,
38111
+ advice: `Replace the String/&str parameter with the typed enum. Stringly-typed APIs lose type information at the boundary; a typo ('Click' vs 'click') only fails at runtime. AI agents introduce these during exploratory scaffolding, then never replace them with the existing enum.`
38112
+ });
38113
+ }
38114
+ return issues;
38115
+ }
38116
+ });
38117
+ function collectEnumCandidates(source) {
38118
+ const out = [];
38119
+ const enumRe = /^(?:pub(?:\([^)]+\))?\s+)?enum\s+(\w+)\s*\{([^}]*)\}/gm;
38120
+ for (const m of source.matchAll(enumRe)) {
38121
+ const body = m[2] ?? "";
38122
+ const variants = body.split(/,(?![^()]*\))/).map((s) => s.trim()).filter((s) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(s.split(/\s+/)[0] ?? ""));
38123
+ if (variants.length > MAX_VARIANT_COUNT) continue;
38124
+ if (variants.length < 2) continue;
38125
+ out.push({ name: m[1], variantCount: variants.length, line: lineOfMatch(source, m.index ?? 0) });
38126
+ }
38127
+ return out;
38128
+ }
38129
+ function lineOfMatch(source, index) {
38130
+ let line = 1;
38131
+ for (let i = 0; i < index && i < source.length; i++) {
38132
+ if (source[i] === "\n") line++;
38133
+ }
38134
+ return line;
38135
+ }
38136
+ function buildLineOffsets2(source) {
38137
+ const out = [0];
38138
+ for (let i = 0; i < source.length; i++) {
38139
+ if (source[i] === "\n") out.push(i + 1);
38140
+ }
38141
+ return out;
38142
+ }
38143
+ function extractParameterText(source, lineOffsets, fn) {
38144
+ const start = lineOffsets[Math.max(0, fn.line - 1)] ?? 0;
38145
+ const head = source.slice(start, start + 400);
38146
+ const openIdx = head.indexOf("(");
38147
+ if (openIdx < 0) return "";
38148
+ let closeIdx = -1;
38149
+ let depth = 0;
38150
+ for (let i = openIdx; i < head.length; i++) {
38151
+ if (head[i] === "(") depth++;
38152
+ else if (head[i] === ")") {
38153
+ depth--;
38154
+ if (depth === 0) {
38155
+ closeIdx = i;
38156
+ break;
38157
+ }
38158
+ }
38159
+ }
38160
+ if (closeIdx < 0) return "";
38161
+ return head.slice(openIdx + 1, closeIdx);
38162
+ }
38163
+ function scanForStringlyParams(paramText) {
38164
+ const out = [];
38165
+ for (const m of paramText.matchAll(
38166
+ /\b([a-z_][a-zA-Z0-9_]*)\s*:\s*(&\s*(?:mut\s+)?(?:str|String)\b)/g
38167
+ )) {
38168
+ const name = m[1];
38169
+ const type = m[2];
38170
+ if (!SUSPECT_PARAM_NAMES.has(name)) continue;
38171
+ out.push({ name, type });
38172
+ }
38173
+ return out;
38174
+ }
38175
+
38176
+ // src/rules/rust/todo-macro.ts
38177
+ init_parser_rust();
38178
+ var TODO_MACROS = /* @__PURE__ */ new Set(["todo", "unimplemented", "todo_unimplemented"]);
38179
+ var rustTodoMacroRule = createRule({
38180
+ id: "rust/todo-macro",
38181
+ category: "logic",
38182
+ severity: "medium",
38183
+ aiSpecific: true,
38184
+ description: "todo!() / unimplemented!() macro invocation in production code",
38185
+ create(_context) {
38186
+ return {};
38187
+ },
38188
+ analyze(_context, facts) {
38189
+ const issues = [];
38190
+ if (!facts.v2?.rustFile) return issues;
38191
+ const source = facts.v2._source ?? "";
38192
+ if (!source) return issues;
38193
+ const tree = parseRust(source);
38194
+ if (!tree) return issues;
38195
+ const testScopes = /* @__PURE__ */ new Set();
38196
+ for (const fn of facts.v2.rustFile.functions) {
38197
+ if (fn.inTestConfig && fn.name) testScopes.add(fn.name);
38198
+ }
38199
+ collectMacroIssues(tree.rootNode, testScopes, issues);
38200
+ return issues;
38201
+ }
38202
+ });
38203
+ function collectMacroIssues(node, testScopes, issues) {
38204
+ if (node.type === "macro_invocation") {
38205
+ const text = node.text;
38206
+ const m = text.match(/^([A-Za-z_][A-Za-z0-9_]*)/);
38207
+ const macroName = m?.[1] ?? "";
38208
+ if (TODO_MACROS.has(macroName)) {
38209
+ if (!isInsideMacroDefinition(node) && !isInsideTestFunction(node, testScopes)) {
38210
+ issues.push({
38211
+ ruleId: "rust/todo-macro",
38212
+ category: "logic",
38213
+ severity: "medium",
38214
+ aiSpecific: true,
38215
+ message: `'${macroName}!()' in production code \u2014 both expand to panic!()`,
38216
+ line: node.startPosition.row + 1,
38217
+ column: node.startPosition.column,
38218
+ advice: `Implement the function body or remove the stub. '${macroName}!()' is fine in test scaffolding (#[cfg(test)]); here it is a panic risk. AI agents commonly leave these behind after iterative refactors when the placeholder branch is never filled in.`
38219
+ });
38220
+ }
38221
+ }
38222
+ }
38223
+ for (let i = 0; i < node.namedChildCount; i++) {
38224
+ const child = node.namedChild(i);
38225
+ if (child) collectMacroIssues(child, testScopes, issues);
38226
+ }
38227
+ }
38228
+ function isInsideMacroDefinition(node) {
38229
+ for (let p = node.parent; p; p = p.parent) {
38230
+ if (p.type === "macro_definition") return true;
38231
+ if (p.type === "source_file") return false;
38232
+ }
38233
+ return false;
38234
+ }
38235
+ function isInsideTestFunction(node, testScopes) {
38236
+ for (let p = node.parent; p; p = p.parent) {
38237
+ if (p.type === "function_item") {
38238
+ const nameField = p.childForFieldName("name");
38239
+ const name = nameField?.text;
38240
+ if (name && testScopes.has(name)) return true;
38241
+ if (p.text.startsWith("#[test]") || p.text.startsWith("#[cfg(test)]")) return true;
38242
+ return false;
38243
+ }
38244
+ if (p.type === "source_file") return false;
38245
+ }
38246
+ return false;
38247
+ }
38248
+
38249
+ // src/rules/rust/unused-pub-fn.ts
38250
+ var API_CONVENTION_NAMES = /* @__PURE__ */ new Set([
38251
+ "new",
38252
+ "default",
38253
+ "from",
38254
+ "from_str",
38255
+ "from_iter",
38256
+ "try_from",
38257
+ "into",
38258
+ "into_iter",
38259
+ "try_into",
38260
+ "as_ref",
38261
+ "as_mut",
38262
+ "clone",
38263
+ "fmt",
38264
+ "eq",
38265
+ "hash",
38266
+ "partial_cmp",
38267
+ "cmp",
38268
+ "ord",
38269
+ "partial_eq"
38270
+ ]);
38271
+ var rustUnusedPubFnRule = createRule({
38272
+ id: "rust/unused-pub-fn",
38273
+ category: "logic",
38274
+ severity: "low",
38275
+ aiSpecific: true,
38276
+ description: "Public function in a Rust file that has no in-file references",
38277
+ create(_context) {
38278
+ return {};
38279
+ },
38280
+ analyze(_context, facts) {
38281
+ const issues = [];
38282
+ if (!facts.v2?.rustFile) return issues;
38283
+ const rust = facts.v2.rustFile;
38284
+ const referenced = collectReferencedNames(facts.v2._source ?? "");
38285
+ for (const fn of rust.functions) {
38286
+ if (!fn.isPublic) continue;
38287
+ if (API_CONVENTION_NAMES.has(fn.name)) continue;
38288
+ if (fn.inTestConfig) continue;
38289
+ if (referenced.has(fn.name)) continue;
38290
+ issues.push({
38291
+ ruleId: "rust/unused-pub-fn",
38292
+ category: "logic",
38293
+ severity: "low",
38294
+ aiSpecific: true,
38295
+ message: `Public function '${fn.name}' is not referenced anywhere in the file`,
38296
+ line: fn.line,
38297
+ column: fn.column,
38298
+ advice: `Remove the function or call it somewhere. Rust's compiler doesn't warn on pub fns missing consumers unless \`#![warn(dead_code)]\` is set at the crate root. AI agents that iterate on a file often leave these behind \u2014 the most common AI-rotation signature for Rust after unused-imports.`
38299
+ });
38300
+ }
38301
+ return issues;
38302
+ }
38303
+ });
38304
+ function collectReferencedNames(source) {
38305
+ const out = /* @__PURE__ */ new Set();
38306
+ for (const m of source.matchAll(/\b([A-Za-z_][A-Za-z0-9_]*)\b/g)) {
38307
+ out.add(m[1]);
38308
+ }
38309
+ return out;
38310
+ }
38311
+
38312
+ // src/rules/rust/unwrap-in-production.ts
38313
+ init_parser_rust();
38314
+ var UNWRAP_METHODS = /* @__PURE__ */ new Set(["unwrap", "expect", "unwrap_or_else"]);
38315
+ var rustUnwrapInProductionRule = createRule({
38316
+ id: "rust/unwrap-in-production",
38317
+ category: "logic",
38318
+ severity: "medium",
38319
+ aiSpecific: true,
38320
+ description: ".unwrap() / .expect() called outside of #[cfg(test)] / #[test] scope",
38321
+ create(_context) {
38322
+ return {};
38323
+ },
38324
+ analyze(_context, facts) {
38325
+ const issues = [];
38326
+ if (!facts.v2?.rustFile) return issues;
38327
+ const source = facts.v2._source ?? "";
38328
+ if (!source) return issues;
38329
+ const tree = parseRust(source);
38330
+ if (!tree) return issues;
38331
+ const testScopes = /* @__PURE__ */ new Set();
38332
+ for (const fn of facts.v2.rustFile.functions) {
38333
+ if (fn.inTestConfig && fn.name) testScopes.add(fn.name);
38334
+ }
38335
+ collectUnwrapIssues(tree.rootNode, testScopes, issues);
38336
+ return issues;
38337
+ }
38338
+ });
38339
+ function collectUnwrapIssues(node, testScopes, issues) {
38340
+ if (node.type === "call_expression") {
38341
+ const fn = node.childForFieldName("function");
38342
+ if (fn && fn.type === "field_expression") {
38343
+ const field = fn.childForFieldName("field");
38344
+ if (field && field.type === "field_identifier" && UNWRAP_METHODS.has(field.text)) {
38345
+ if (!isInsideTestFunction2(node, testScopes)) {
38346
+ issues.push({
38347
+ ruleId: "rust/unwrap-in-production",
38348
+ category: "logic",
38349
+ severity: "medium",
38350
+ aiSpecific: true,
38351
+ message: `'.${field.text}()' called in production code \u2014 panic risk on Err/None`,
38352
+ line: node.startPosition.row + 1,
38353
+ column: node.startPosition.column,
38354
+ advice: `Replace with '?' (early-return on Err), '.map_err(...)' for conversion, or an explicit 'match'. '.${field.text}()' is fine in tests \u2014 wrap with '#[cfg(test)]' or move into a '#[cfg(test)] mod tests' block to suppress.`
38355
+ });
38356
+ }
38357
+ }
38358
+ }
38359
+ }
38360
+ for (let i = 0; i < node.namedChildCount; i++) {
38361
+ const child = node.namedChild(i);
38362
+ if (child) collectUnwrapIssues(child, testScopes, issues);
38363
+ }
38364
+ }
38365
+ function isInsideTestFunction2(node, testScopes) {
38366
+ for (let p = node.parent; p; p = p.parent) {
38367
+ if (p.type === "function_item") {
38368
+ const nameField = p.childForFieldName("name");
38369
+ const name = nameField?.text;
38370
+ if (name && testScopes.has(name)) return true;
38371
+ if (p.text.startsWith("#[test]") || p.text.startsWith("#[cfg(test)]")) return true;
38372
+ return false;
38373
+ }
38374
+ if (p.type === "source_file") return false;
38375
+ }
38376
+ return false;
38377
+ }
38378
+
37493
38379
  // src/rules/security/dangerous-cors.ts
37494
38380
  var HEADER_LITERAL_RE = /['"]Access-Control-Allow-Origin['"]\s*[,:=]\s*['"]\*['"]/g;
37495
38381
  var CORS_BLOCK_RE = /\bcors\s*\(\s*\{([^}]*)\}\s*\)/g;
@@ -38187,7 +39073,7 @@ var unsafeHtmlRenderRule = createRule({
38187
39073
  });
38188
39074
 
38189
39075
  // src/rules/test/utils.ts
38190
- import { createHash as createHash2 } from "crypto";
39076
+ import { createHash as createHash3 } from "crypto";
38191
39077
  function isTestFile(filePath) {
38192
39078
  const normalized = filePath.replace(/\\/g, "/");
38193
39079
  if (/(^|\/)__tests__\//.test(normalized)) return true;
@@ -38347,7 +39233,7 @@ function extractSetupBlocks(source, minLines = 3) {
38347
39233
  }).trim();
38348
39234
  const lineCount = rawBody.split("\n").length;
38349
39235
  if (lineCount < minLines) continue;
38350
- const bodyHash = createHash2("sha1").update(normalizedBody).digest("hex");
39236
+ const bodyHash = createHash3("sha1").update(normalizedBody).digest("hex");
38351
39237
  const { line, column } = lineColumnOf(source, m.index);
38352
39238
  hits.push({
38353
39239
  kind,
@@ -38957,6 +39843,216 @@ function isTautologicalAssertion(hit) {
38957
39843
  return false;
38958
39844
  }
38959
39845
 
39846
+ // src/rules/ts/enum-vs-as-const.ts
39847
+ var ENUM_DECL_REGEX = /^[ \t]*(?:export\s+)?(?:const\s+)?enum\s+[A-Z_][A-Za-z0-9_]*\s*\{/gm;
39848
+ var tsEnumVsAsConstRule = createRule({
39849
+ id: "ts/enum-vs-as-const",
39850
+ category: "typo",
39851
+ severity: "low",
39852
+ aiSpecific: true,
39853
+ description: "Uses `enum` \u2014 modern TS prefers `as const` objects",
39854
+ create(_context) {
39855
+ return {};
39856
+ },
39857
+ analyze(_context, facts) {
39858
+ const issues = [];
39859
+ const source = facts.v2?._source;
39860
+ if (!source) return issues;
39861
+ let match;
39862
+ ENUM_DECL_REGEX.lastIndex = 0;
39863
+ while ((match = ENUM_DECL_REGEX.exec(source)) !== null) {
39864
+ const line = source.slice(0, match.index).split("\n").length;
39865
+ issues.push({
39866
+ ruleId: "ts/enum-vs-as-const",
39867
+ category: "typo",
39868
+ severity: "low",
39869
+ aiSpecific: true,
39870
+ message: `'enum' is an AI / older-TS pattern \u2014 prefer 'as const' for a frozen object literal`,
39871
+ line,
39872
+ column: match[0].indexOf("enum") + 1,
39873
+ advice: 'Replace `enum Foo { A, B }` with `const Foo = { A: "A", B: "B" } as const` (or `const Foo = ["A", "B"] as const`). Modern TS style guides (Google, TS-eslint) prefer `as const` because enums have surprising runtime semantics. Reference: ts/enum-vs-as-const v0.19.'
39874
+ });
39875
+ }
39876
+ return issues;
39877
+ }
39878
+ });
39879
+
39880
+ // src/rules/ts/excessive-type-assertion.ts
39881
+ var DEFAULT_MAX = 3;
39882
+ var FN_DECL_REGEX = /^[ \t]*(?:export\s+)?(?:async\s+)?function\s+[A-Za-z_$][\w$]*\s*\([^)]*\)\s*[^{]*\{|^\s*(?:export\s+)?(?:const|let|var)\s+[A-Za-z_$][\w$]*\s*=\s*(?:async\s+)?\([^)]*\)\s*(?::\s*[^=]+)?\s*=>\s*\{|^\s*(?:public|private|protected|static|async|abstract|readonly|\s)*\s*[A-Za-z_$][\w$]*\s*\([^)]*\)\s*:\s*[^{]*\{/gm;
39883
+ var AS_REGEX = /(?<![\w$])as\s+(?!const)([A-Z][\w$.,<>\[\]|&]*)/g;
39884
+ var tsExcessiveTypeAssertionRule = createRule({
39885
+ id: "ts/excessive-type-assertion",
39886
+ category: "typo",
39887
+ severity: "low",
39888
+ aiSpecific: true,
39889
+ description: "Function with >3 `as` type assertions \u2014 likely AI fighting the type system",
39890
+ create(_context) {
39891
+ return { maxAssertionsPerFunction: DEFAULT_MAX };
39892
+ },
39893
+ analyze(context, facts) {
39894
+ const issues = [];
39895
+ const source = facts.v2?._source;
39896
+ if (!source) return issues;
39897
+ let match;
39898
+ FN_DECL_REGEX.lastIndex = 0;
39899
+ while ((match = FN_DECL_REGEX.exec(source)) !== null) {
39900
+ const startIdx = match.index;
39901
+ const openBraceIdx = source.indexOf("{", startIdx);
39902
+ if (openBraceIdx < 0) continue;
39903
+ let depth = 1;
39904
+ let i = openBraceIdx + 1;
39905
+ while (i < source.length && depth > 0) {
39906
+ const ch = source[i];
39907
+ if (ch === "{") depth++;
39908
+ else if (ch === "}") depth--;
39909
+ i++;
39910
+ }
39911
+ const body = source.slice(openBraceIdx, i);
39912
+ const line = source.slice(0, startIdx).split("\n").length;
39913
+ let asCount = 0;
39914
+ const seen = /* @__PURE__ */ new Set();
39915
+ let asMatch;
39916
+ AS_REGEX.lastIndex = 0;
39917
+ while ((asMatch = AS_REGEX.exec(body)) !== null) {
39918
+ const captured = asMatch[1];
39919
+ if (seen.has(captured)) continue;
39920
+ seen.add(captured);
39921
+ asCount++;
39922
+ }
39923
+ if (asCount > context.maxAssertionsPerFunction) {
39924
+ issues.push({
39925
+ ruleId: "ts/excessive-type-assertion",
39926
+ category: "typo",
39927
+ severity: "low",
39928
+ aiSpecific: true,
39929
+ message: `Function has ${asCount} 'as' assertions (max ${context.maxAssertionsPerFunction}) \u2014 likely AI fighting the type system`,
39930
+ line,
39931
+ column: 1,
39932
+ advice: "More than 3 `as` assertions in a function is a strong signal that the type is wrong, not the code. Fix the type definition (or use a type guard) instead of bypassing the type system. Reference: ts/excessive-type-assertion v0.19."
39933
+ });
39934
+ }
39935
+ }
39936
+ return issues;
39937
+ }
39938
+ });
39939
+
39940
+ // src/rules/ts/import-type-misuse.ts
39941
+ var INLINE_TYPE_IMPORT_REGEX = /^[ \t]*import\s*\{[^}]*\btype\s+[A-Za-z_]/gm;
39942
+ var tsImportTypeMisuseRule = createRule({
39943
+ id: "ts/import-type-misuse",
39944
+ category: "typo",
39945
+ severity: "low",
39946
+ aiSpecific: true,
39947
+ description: "Inline `import { type X }` \u2014 prefer `import type { X }` for clarity",
39948
+ create(_context) {
39949
+ return {};
39950
+ },
39951
+ analyze(_context, facts) {
39952
+ const issues = [];
39953
+ const source = facts.v2?._source;
39954
+ if (!source) return issues;
39955
+ let match;
39956
+ INLINE_TYPE_IMPORT_REGEX.lastIndex = 0;
39957
+ while ((match = INLINE_TYPE_IMPORT_REGEX.exec(source)) !== null) {
39958
+ const line = source.slice(0, match.index).split("\n").length;
39959
+ issues.push({
39960
+ ruleId: "ts/import-type-misuse",
39961
+ category: "typo",
39962
+ severity: "low",
39963
+ aiSpecific: true,
39964
+ message: "Inline `type` in a value import \u2014 split into a separate `import type` statement",
39965
+ line,
39966
+ column: match[0].indexOf("type") + 1,
39967
+ advice: 'Use `import type { X } from "..."` instead of `import { type X } from "..."`. The inline form is valid but the split form is more common in real codebases and makes the type-only intent unambiguous. Reference: ts/import-type-misuse v0.19.'
39968
+ });
39969
+ }
39970
+ return issues;
39971
+ }
39972
+ });
39973
+
39974
+ // src/rules/ts/never-vs-unknown.ts
39975
+ var NEVER_RETURN_REGEX = /^[ \t]*(?:export\s+)?(?:async\s+)?function\s+([A-Za-z_$][\w$]*)[^{]*:\s*(?:Promise<)?never\b[^{]*\{/gm;
39976
+ var THROW_OR_LOOP_REGEX = /\b(?:throw\b|while\s*\(|for\s*\(|process\.exit\b|System\.exit\b)/;
39977
+ var tsNeverVsUnknownRule = createRule({
39978
+ id: "ts/never-vs-unknown",
39979
+ category: "typo",
39980
+ severity: "low",
39981
+ aiSpecific: true,
39982
+ description: "Return type `: never` but body has no throw / loop / exit \u2014 likely AI misuse",
39983
+ create(_context) {
39984
+ return {};
39985
+ },
39986
+ analyze(_context, facts) {
39987
+ const issues = [];
39988
+ const source = facts.v2?._source;
39989
+ if (!source) return issues;
39990
+ let match;
39991
+ NEVER_RETURN_REGEX.lastIndex = 0;
39992
+ while ((match = NEVER_RETURN_REGEX.exec(source)) !== null) {
39993
+ const fnName = match[1];
39994
+ const startIdx = match.index;
39995
+ const line = source.slice(0, startIdx).split("\n").length;
39996
+ const openBraceIdx = source.indexOf("{", startIdx);
39997
+ if (openBraceIdx < 0) continue;
39998
+ let depth = 1;
39999
+ let i = openBraceIdx + 1;
40000
+ while (i < source.length && depth > 0) {
40001
+ const ch = source[i];
40002
+ if (ch === "{") depth++;
40003
+ else if (ch === "}") depth--;
40004
+ i++;
40005
+ }
40006
+ const body = source.slice(openBraceIdx, i);
40007
+ if (THROW_OR_LOOP_REGEX.test(body)) continue;
40008
+ issues.push({
40009
+ ruleId: "ts/never-vs-unknown",
40010
+ category: "typo",
40011
+ severity: "low",
40012
+ aiSpecific: true,
40013
+ message: `Function '${fnName}' returns 'never' but its body has no throw, loop, or exit \u2014 likely AI misuse`,
40014
+ line,
40015
+ column: match[0].indexOf("never") + 1,
40016
+ advice: 'The `never` return type means "this function never returns". Reserve it for functions that always throw, always loop, or always exit. For "impossible" branches, use a concrete type (`void`, `Error`, `unknown`) and an exhaustive check. Reference: ts/never-vs-unknown v0.19.'
40017
+ });
40018
+ }
40019
+ return issues;
40020
+ }
40021
+ });
40022
+
40023
+ // src/rules/ts/optional-chain-overuse.ts
40024
+ var DEFAULT_MIN_CHAIN_LENGTH = 5;
40025
+ var tsOptionalChainOveruseRule = createRule({
40026
+ id: "ts/optional-chain-overuse",
40027
+ category: "logic",
40028
+ severity: "low",
40029
+ aiSpecific: true,
40030
+ description: "Optional chaining (?.) used 5+ times in a single chain \u2014 AI tends to chain rather than narrow",
40031
+ create(_context) {
40032
+ return { minChainLength: DEFAULT_MIN_CHAIN_LENGTH };
40033
+ },
40034
+ analyze(context, facts) {
40035
+ const issues = [];
40036
+ const expressions = facts.v2.logic?.logicalExpressions;
40037
+ if (!expressions) return issues;
40038
+ for (const expression of expressions) {
40039
+ if (expression.depth >= context.minChainLength && expression.isOptionalChainLike) {
40040
+ issues.push({
40041
+ ruleId: "ts/optional-chain-overuse",
40042
+ category: "logic",
40043
+ severity: "low",
40044
+ aiSpecific: true,
40045
+ message: `Optional chain depth ${expression.depth} \u2014 break with an intermediate variable or guard clause`,
40046
+ line: expression.line,
40047
+ column: expression.column,
40048
+ advice: "Long optional chains are an AI pattern. Use a guard clause (`if (!value) return`) or intermediate variables to make the narrowing explicit. Reference: ts/optional-chain-overuse v0.19."
40049
+ });
40050
+ }
40051
+ }
40052
+ return issues;
40053
+ }
40054
+ });
40055
+
38960
40056
  // src/rules/typo/calc-fontsize.ts
38961
40057
  var FONT_SIZE_RE = /\bfont-size\s*:\s*[^;]*\bcalc\s*\(/i;
38962
40058
  var calcFontsizeRule = createRule({
@@ -40497,6 +41593,10 @@ var builtinRules = [
40497
41593
  expiredCodeExampleRule,
40498
41594
  staleFunctionReferenceRule,
40499
41595
  stalePackageReferenceRule,
41596
+ dupIdenticalBlockRule,
41597
+ goErrorWrapWithoutContextRule,
41598
+ goNilSliceVsEmptyRule,
41599
+ goStructTagInconsistencyRule,
40500
41600
  gapMonopolyRule,
40501
41601
  mathElementUniformityRule,
40502
41602
  mathGridUniformityRule,
@@ -40506,7 +41606,6 @@ var builtinRules = [
40506
41606
  ghostDefensiveRule,
40507
41607
  heapsDeviationRule,
40508
41608
  keyPropMissingRule,
40509
- ksDistributionShiftRule,
40510
41609
  mathAnyDensityRule,
40511
41610
  mathConsoleLogStormRule,
40512
41611
  mathGiniClassUsageRule,
@@ -40521,6 +41620,10 @@ var builtinRules = [
40521
41620
  halsteadAnomalyRule,
40522
41621
  terminologyDriftRule,
40523
41622
  uxPatternFragmentationRule,
41623
+ rustStringlyTypedRule,
41624
+ rustTodoMacroRule,
41625
+ rustUnusedPubFnRule,
41626
+ rustUnwrapInProductionRule,
40524
41627
  dangerousCorsRule,
40525
41628
  evalRule,
40526
41629
  exposedEnvVarRule,
@@ -40536,6 +41639,11 @@ var builtinRules = [
40536
41639
  fakePlaceholderRule,
40537
41640
  missingEdgeCaseRule,
40538
41641
  weakAssertionRule,
41642
+ tsEnumVsAsConstRule,
41643
+ tsExcessiveTypeAssertionRule,
41644
+ tsImportTypeMisuseRule,
41645
+ tsNeverVsUnknownRule,
41646
+ tsOptionalChainOveruseRule,
40539
41647
  calcFontsizeRule,
40540
41648
  calcRawPxRule,
40541
41649
  clampOffscaleRule,
@@ -40595,6 +41703,22 @@ var RuleRegistry = class {
40595
41703
  if (!filter) return list;
40596
41704
  return list.filter((r) => filter.kind === "ai" ? r.aiSpecific : !r.aiSpecific);
40597
41705
  }
41706
+ /** v0.18.8: remove every rule where `predicate(rule)` returns true.
41707
+ * Used by focused calibration scripts to scan a single category
41708
+ * without instantiating all 99 rules. */
41709
+ removeWhere(predicate) {
41710
+ let removed = 0;
41711
+ for (const [id, rule] of this.rules) {
41712
+ if (predicate(rule)) {
41713
+ this.rules.delete(id);
41714
+ removed++;
41715
+ }
41716
+ }
41717
+ return removed;
41718
+ }
41719
+ all() {
41720
+ return Array.from(this.rules.values());
41721
+ }
40598
41722
  createContexts(config, filePath, cwd, hotspotIssues = []) {
40599
41723
  const context = {
40600
41724
  config,
@@ -40615,1044 +41739,1943 @@ var RuleRegistry = class {
40615
41739
 
40616
41740
  // src/rules/signal-strength.json
40617
41741
  var signal_strength_default = {
40618
- "logic/math-console-log-storm": {
40619
- recall: 7e-3,
40620
- fpRate: 1e-3,
40621
- ratio: 6.71,
40622
- precision: 0.8968,
40623
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41742
+ "ai/any-density": {
41743
+ recall: 6e-3,
41744
+ fpRate: 37e-4,
41745
+ ratio: 175.31,
41746
+ precision: 0.6523,
41747
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40624
41748
  verdict: "USEFUL",
40625
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=1678, FP=193, P=89.7%, FPR=0.10%, lift=6.7. aiSpecific=True.",
40626
- aiSpecific: true
41749
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=1760, FP=938, P=65.2%, FPR=0.37%, lift=175.31. v7 was USEFUL (TP=1313, FP=758, lift=153.41). v8 was USEFUL (TP=447, FP=180).",
41750
+ aiSpecific: true,
41751
+ _v7Verdict: "USEFUL",
41752
+ _v7Lift: 153.41,
41753
+ _v7Recall: 55e-4,
41754
+ _v7FpRate: 41e-4,
41755
+ _v7Precision: 0.634,
41756
+ _v8Verdict: "USEFUL",
41757
+ _v8Lift: 271.97
40627
41758
  },
40628
- "logic/math-any-density": {
40629
- recall: 16e-4,
40630
- fpRate: 13e-4,
40631
- ratio: 1.17,
40632
- precision: 0.6035,
40633
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40634
- verdict: "NOISY",
40635
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. NOISY \u2014 TP=376, FP=247, P=60.4%, FPR=0.13%, lift=1.2. aiSpecific=True.",
40636
- defaultOff: true,
40637
- aiSpecific: true
41759
+ "ai/comment-ratio": {
41760
+ recall: 0.2771,
41761
+ fpRate: 0.1578,
41762
+ ratio: 4.26,
41763
+ precision: 0.6721,
41764
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41765
+ verdict: "USEFUL",
41766
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=81513, FP=39766, P=67.2%, FPR=15.78%, lift=4.26. v7 was USEFUL (TP=60308, FP=29876, lift=4.11). v8 was USEFUL (TP=21205, FP=9890).",
41767
+ aiSpecific: true,
41768
+ _v7Verdict: "USEFUL",
41769
+ _v7Lift: 4.11,
41770
+ _v7Recall: 0.2545,
41771
+ _v7FpRate: 0.1629,
41772
+ _v7Precision: 0.6687,
41773
+ _v8Verdict: "USEFUL",
41774
+ _v8Lift: 4.73
40638
41775
  },
40639
- "logic/boundary-violation": {
40640
- recall: 0.0263,
40641
- fpRate: 0.0175,
40642
- ratio: 1.5,
40643
- precision: 0.6601,
40644
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40645
- verdict: "HYGIENE",
40646
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=6282, FP=3235, P=66.0%, FPR=1.75%, lift=1.5. aiSpecific=False.",
40647
- aiSpecific: false
41776
+ "ai/compression-profile": {
41777
+ recall: 0.3478,
41778
+ fpRate: 0.1488,
41779
+ ratio: 4.92,
41780
+ precision: 0.7318,
41781
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41782
+ verdict: "USEFUL",
41783
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=102328, FP=37511, P=73.2%, FPR=14.88%, lift=4.92. v7 was USEFUL (TP=75031, FP=27473, lift=4.89). v8 was USEFUL (TP=27297, FP=10038).",
41784
+ aiSpecific: true,
41785
+ _v7Verdict: "USEFUL",
41786
+ _v7Lift: 4.89,
41787
+ _v7Recall: 0.3166,
41788
+ _v7FpRate: 0.1498,
41789
+ _v7Precision: 0.732,
41790
+ _v8Verdict: "USEFUL",
41791
+ _v8Lift: 5
40648
41792
  },
40649
- "logic/reactive-hook-soup": {
40650
- recall: 38e-4,
41793
+ "ai/console-debug-storm": {
41794
+ recall: 73e-4,
40651
41795
  fpRate: 9e-4,
40652
- ratio: 4.29,
40653
- precision: 0.8476,
40654
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41796
+ ratio: 949.21,
41797
+ precision: 0.9,
41798
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40655
41799
  verdict: "USEFUL",
40656
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=901, FP=162, P=84.8%, FPR=0.09%, lift=4.3. aiSpecific=True.",
40657
- aiSpecific: true
41800
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=2150, FP=239, P=90.0%, FPR=0.09%, lift=949.21. v7 was USEFUL (TP=1912, FP=175, lift=960.19). v8 was USEFUL (TP=238, FP=64).",
41801
+ aiSpecific: true,
41802
+ _v7Verdict: "USEFUL",
41803
+ _v7Lift: 960.19,
41804
+ _v7Recall: 81e-4,
41805
+ _v7FpRate: 1e-3,
41806
+ _v7Precision: 0.9161,
41807
+ _v8Verdict: "USEFUL",
41808
+ _v8Lift: 845.55
40658
41809
  },
40659
- "logic/optimistic-no-rollback": {
40660
- recall: 12e-4,
40661
- fpRate: 3e-4,
40662
- ratio: 3.61,
40663
- precision: 0.824,
40664
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41810
+ "ai/default-react-stack": {
41811
+ recall: 1e-3,
41812
+ fpRate: 0,
41813
+ ratio: 251225.49,
41814
+ precision: 0.9966,
41815
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40665
41816
  verdict: "USEFUL",
40666
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=281, FP=60, P=82.4%, FPR=0.03%, lift=3.6. aiSpecific=True.",
40667
- aiSpecific: true
41817
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=294, FP=1, P=99.7%, FPR=0.00%, lift=251225.49. v7 was USEFUL (TP=231, FP=1, lift=182622.43). v8 was USEFUL (TP=63, FP=0). v0.19 default-on (explicit defaultOff: false): P 99.7% / 251k lift \u2014 core AI fingerprint.",
41818
+ aiSpecific: true,
41819
+ _v7Verdict: "USEFUL",
41820
+ _v7Lift: 182622.43,
41821
+ _v7Recall: 1e-3,
41822
+ _v7FpRate: 0,
41823
+ _v7Precision: 0.9957,
41824
+ _v8Verdict: "USEFUL",
41825
+ _v8Lift: 99999,
41826
+ defaultOff: false
40668
41827
  },
40669
- "logic/zombie-state": {
40670
- recall: 1e-4,
40671
- fpRate: 0,
40672
- ratio: 9.26,
40673
- precision: 0.9231,
40674
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41828
+ "ai/errors-near-eof": {
41829
+ recall: 0.0948,
41830
+ fpRate: 0.052,
41831
+ ratio: 13.09,
41832
+ precision: 0.6803,
41833
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40675
41834
  verdict: "USEFUL",
40676
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=24, FP=2, P=92.3%, FPR=0.00%, lift=9.3. aiSpecific=True.",
40677
- aiSpecific: true
41835
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=27874, FP=13097, P=68.0%, FPR=5.20%, lift=13.09. v7 was USEFUL (TP=16673, FP=10112, lift=11.29). v8 was USEFUL (TP=11201, FP=2985).",
41836
+ aiSpecific: true,
41837
+ _v7Verdict: "USEFUL",
41838
+ _v7Lift: 11.29,
41839
+ _v7Recall: 0.0704,
41840
+ _v7FpRate: 0.0551,
41841
+ _v7Precision: 0.6225,
41842
+ _v8Verdict: "USEFUL",
41843
+ _v8Lift: 18.16
40678
41844
  },
40679
- "logic/math-gini-class-usage": {
40680
- recall: 13e-4,
41845
+ "ai/fetch-default-overuse": {
41846
+ recall: 27e-4,
40681
41847
  fpRate: 3e-4,
40682
- ratio: 5.09,
40683
- precision: 0.8683,
40684
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41848
+ ratio: 2679.84,
41849
+ precision: 0.9036,
41850
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40685
41851
  verdict: "USEFUL",
40686
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=310, FP=47, P=86.8%, FPR=0.03%, lift=5.1. aiSpecific=True.",
40687
- aiSpecific: true
41852
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=797, FP=85, P=90.4%, FPR=0.03%, lift=2679.84. v7 was USEFUL (TP=666, FP=76, lift=2166.14). v8 was USEFUL (TP=131, FP=9).",
41853
+ aiSpecific: true,
41854
+ _v7Verdict: "USEFUL",
41855
+ _v7Lift: 2166.14,
41856
+ _v7Recall: 28e-4,
41857
+ _v7FpRate: 4e-4,
41858
+ _v7Precision: 0.8976,
41859
+ _v8Verdict: "USEFUL",
41860
+ _v8Lift: 7139.19
40688
41861
  },
40689
- "visual/math-color-cluster": {
40690
- recall: 2e-4,
41862
+ "ai/library-reinvention": {
41863
+ recall: 3e-4,
40691
41864
  fpRate: 0,
40692
- ratio: 8.95,
40693
- precision: 0.9206,
40694
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41865
+ ratio: 47415.05,
41866
+ precision: 0.9405,
41867
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40695
41868
  verdict: "USEFUL",
40696
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=58, FP=5, P=92.1%, FPR=0.00%, lift=9.0. aiSpecific=True.",
40697
- aiSpecific: true
41869
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=79, FP=5, P=94.0%, FPR=0.00%, lift=47415.05. v7 was USEFUL (TP=64, FP=5, lift=34024.44). v8 was USEFUL (TP=15, FP=0).",
41870
+ aiSpecific: true,
41871
+ _v7Verdict: "USEFUL",
41872
+ _v7Lift: 34024.44,
41873
+ _v7Recall: 3e-4,
41874
+ _v7FpRate: 0,
41875
+ _v7Precision: 0.9275,
41876
+ _v8Verdict: "USEFUL",
41877
+ _v8Lift: 99999
40698
41878
  },
40699
- "visual/math-default-font": {
40700
- recall: 13e-4,
40701
- fpRate: 4e-4,
40702
- ratio: 3.4,
40703
- precision: 0.8151,
40704
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40705
- verdict: "USEFUL",
40706
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=313, FP=71, P=81.5%, FPR=0.04%, lift=3.4. aiSpecific=True.",
40707
- aiSpecific: true
40708
- },
40709
- "visual/math-gradient-hue-rotation": {
41879
+ "ai/log-rank-histogram": {
40710
41880
  recall: 0,
40711
41881
  fpRate: 0,
40712
41882
  ratio: 0,
40713
41883
  precision: 0,
40714
- lastCalibratedAt: "2026-06-25T00:00:00Z",
41884
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40715
41885
  verdict: "DORMANT",
40716
- defaultOff: true,
40717
- _calibrationNote: "v0.10.1 ship \u2014 not in v4 per-rule table. Default-off until calibration data lands. Backed by: Munsell, A. H. (1905), *A Color Notation*, Munsell Color Company; Itten, J. (1961), *The Art of Color*, Van Nostrand Reinhold. (Munsell color space + Itten color wheel \u2014 hue rotation analysis.)",
40718
- aiSpecific: true
41886
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=OK, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
41887
+ aiSpecific: true,
41888
+ _v7Verdict: "OK",
41889
+ _v7Lift: 0,
41890
+ _v7Recall: 0,
41891
+ _v7FpRate: 0,
41892
+ _v7Precision: 0,
41893
+ _v8Verdict: "DORMANT",
41894
+ _v8Lift: 1,
41895
+ defaultOff: true
40719
41896
  },
40720
- "visual/math-rounded-entropy": {
40721
- recall: 37e-4,
40722
- fpRate: 3e-4,
40723
- ratio: 10.9,
40724
- precision: 0.9339,
40725
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40726
- verdict: "USEFUL",
40727
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=876, FP=62, P=93.4%, FPR=0.03%, lift=10.9. aiSpecific=True.",
40728
- aiSpecific: true
41897
+ "ai/markdown-leakage": {
41898
+ recall: 0,
41899
+ fpRate: 0,
41900
+ ratio: 10003.17,
41901
+ precision: 0.3571,
41902
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41903
+ verdict: "OK",
41904
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=5, FP=9, P=35.7%, FPR=0.00%, lift=10003.17. v7 was USEFUL (TP=5, FP=2, lift=65504.64). v8 was INVERTED (TP=0, FP=7).",
41905
+ aiSpecific: true,
41906
+ _v7Verdict: "USEFUL",
41907
+ _v7Lift: 65504.64,
41908
+ _v7Recall: 0,
41909
+ _v7FpRate: 0,
41910
+ _v7Precision: 0.7143,
41911
+ _v8Verdict: "INVERTED",
41912
+ _v8Lift: 0
40729
41913
  },
40730
- "visual/math-font-entropy": {
40731
- recall: 45e-4,
40732
- fpRate: 13e-4,
40733
- ratio: 3.32,
40734
- precision: 0.8114,
40735
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41914
+ "ai/renyi-profile": {
41915
+ recall: 0,
41916
+ fpRate: 0,
41917
+ ratio: 5251.67,
41918
+ precision: 0.25,
41919
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41920
+ verdict: "OK",
41921
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=4, FP=12, P=25.0%, FPR=0.00%, lift=5251.67. v7 was OK (TP=3, FP=9, lift=5094.81). v8 was OK (TP=1, FP=3).",
41922
+ aiSpecific: true,
41923
+ _v7Verdict: "OK",
41924
+ _v7Lift: 5094.81,
41925
+ _v7Recall: 0,
41926
+ _v7FpRate: 0,
41927
+ _v7Precision: 0.25,
41928
+ _v8Verdict: "OK",
41929
+ _v8Lift: 5722.25
41930
+ },
41931
+ "ai/segment-surprisal-cv": {
41932
+ recall: 0.2019,
41933
+ fpRate: 0.0787,
41934
+ ratio: 9.52,
41935
+ precision: 0.7495,
41936
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40736
41937
  verdict: "USEFUL",
40737
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=1067, FP=248, P=81.1%, FPR=0.13%, lift=3.3. aiSpecific=True.",
40738
- aiSpecific: true
41938
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=59390, FP=19849, P=75.0%, FPR=7.87%, lift=9.52. v7 was USEFUL (TP=43498, FP=14983, lift=9.11). v8 was USEFUL (TP=15892, FP=4866).",
41939
+ aiSpecific: true,
41940
+ _v7Verdict: "USEFUL",
41941
+ _v7Lift: 9.11,
41942
+ _v7Recall: 0.1836,
41943
+ _v7FpRate: 0.0817,
41944
+ _v7Precision: 0.7438,
41945
+ _v8Verdict: "USEFUL",
41946
+ _v8Lift: 10.8
40739
41947
  },
40740
- "visual/math-spacing-entropy": {
40741
- recall: 18e-4,
41948
+ "ai/state-default-overuse": {
41949
+ recall: 3e-3,
40742
41950
  fpRate: 6e-4,
40743
- ratio: 3.01,
40744
- precision: 0.7959,
40745
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41951
+ ratio: 1315.06,
41952
+ precision: 0.8451,
41953
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40746
41954
  verdict: "USEFUL",
40747
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=425, FP=109, P=79.6%, FPR=0.06%, lift=3.0. aiSpecific=True.",
40748
- aiSpecific: true
41955
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=884, FP=162, P=84.5%, FPR=0.06%, lift=1315.06. v7 was USEFUL (TP=701, FP=158, lift=947.32). v8 was USEFUL (TP=183, FP=4).",
41956
+ aiSpecific: true,
41957
+ _v7Verdict: "USEFUL",
41958
+ _v7Lift: 947.32,
41959
+ _v7Recall: 3e-3,
41960
+ _v7FpRate: 9e-4,
41961
+ _v7Precision: 0.8161,
41962
+ _v8Verdict: "USEFUL",
41963
+ _v8Lift: 16799.55
40749
41964
  },
40750
- "visual/clamp-soup": {
41965
+ "ai/tailwind-color-overuse": {
41966
+ recall: 0.0264,
41967
+ fpRate: 38e-4,
41968
+ ratio: 230.97,
41969
+ precision: 0.8888,
41970
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41971
+ verdict: "USEFUL",
41972
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=7752, FP=970, P=88.9%, FPR=0.38%, lift=230.97. v7 was USEFUL (TP=5169, FP=958, lift=161.52). v8 was USEFUL (TP=2583, FP=12).",
41973
+ aiSpecific: true,
41974
+ _v7Verdict: "USEFUL",
41975
+ _v7Lift: 161.52,
41976
+ _v7Recall: 0.0218,
41977
+ _v7FpRate: 52e-4,
41978
+ _v7Precision: 0.8436,
41979
+ _v8Verdict: "USEFUL",
41980
+ _v8Lift: 5695.79
41981
+ },
41982
+ "ai/text-like-ratio": {
41983
+ recall: 0,
41984
+ fpRate: 0,
41985
+ ratio: 201664,
41986
+ precision: 0.8,
41987
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41988
+ verdict: "USEFUL",
41989
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=4, FP=1, P=80.0%, FPR=0.00%, lift=201664.00. v7 was USEFUL (TP=3, FP=1, lift=137559.75). v8 was USEFUL (TP=1, FP=0).",
41990
+ aiSpecific: true,
41991
+ _v7Verdict: "USEFUL",
41992
+ _v7Lift: 137559.75,
41993
+ _v7Recall: 0,
41994
+ _v7FpRate: 0,
41995
+ _v7Precision: 0.75,
41996
+ _v8Verdict: "USEFUL",
41997
+ _v8Lift: 99999
41998
+ },
41999
+ "ai/whitespace-regularity": {
42000
+ recall: 0.0733,
42001
+ fpRate: 0.0677,
42002
+ ratio: 8.25,
42003
+ precision: 0.5583,
42004
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42005
+ verdict: "USEFUL",
42006
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=21567, FP=17061, P=55.8%, FPR=6.77%, lift=8.25. v7 was USEFUL (TP=17466, FP=13438, lift=7.71). v8 was USEFUL (TP=4101, FP=3623).",
42007
+ aiSpecific: true,
42008
+ _v7Verdict: "USEFUL",
42009
+ _v7Lift: 7.71,
42010
+ _v7Recall: 0.0737,
42011
+ _v7FpRate: 0.0733,
42012
+ _v7Precision: 0.5652,
42013
+ _v8Verdict: "USEFUL",
42014
+ _v8Lift: 10.06
42015
+ },
42016
+ "arch/astro-island-leak": {
40751
42017
  recall: 0,
40752
42018
  fpRate: 0,
40753
42019
  ratio: 0,
40754
42020
  precision: 0,
40755
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42021
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40756
42022
  verdict: "DORMANT",
40757
- defaultOff: true,
40758
- _calibrationNote: "v0.10.1 ship \u2014 not in v4 per-rule table. Default-off until calibration data lands. Backed by: W3C (2023), CSS Values and Units Module Level 4, W3C CR-css-values-4-20231218. (W3C clamp() spec \u2014 overuse is a code-smell, not a feature.)",
40759
- aiSpecific: true
42023
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
42024
+ aiSpecific: true,
42025
+ _v7Verdict: "DORMANT",
42026
+ _v7Lift: 0,
42027
+ _v7Recall: 0,
42028
+ _v7FpRate: 0,
42029
+ _v7Precision: 0,
42030
+ _v8Verdict: "DORMANT",
42031
+ _v8Lift: 1,
42032
+ defaultOff: true
40760
42033
  },
40761
42034
  "component/giant-component": {
40762
- recall: 0.0176,
40763
- fpRate: 77e-4,
40764
- ratio: 2.3,
40765
- precision: 0.7485,
40766
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42035
+ recall: 0.0181,
42036
+ fpRate: 59e-4,
42037
+ ratio: 132.31,
42038
+ precision: 0.7815,
42039
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40767
42040
  verdict: "USEFUL",
40768
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=4205, FP=1413, P=74.8%, FPR=0.77%, lift=2.3. aiSpecific=True.",
40769
- aiSpecific: true
42041
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=5326, FP=1489, P=78.2%, FPR=0.59%, lift=132.31. v7 was USEFUL (TP=4205, FP=1413, lift=97.16). v8 was USEFUL (TP=1121, FP=76).",
42042
+ aiSpecific: true,
42043
+ _v7Verdict: "USEFUL",
42044
+ _v7Lift: 97.16,
42045
+ _v7Recall: 0.0177,
42046
+ _v7FpRate: 77e-4,
42047
+ _v7Precision: 0.7485,
42048
+ _v8Verdict: "USEFUL",
42049
+ _v8Lift: 846.15
42050
+ },
42051
+ "component/multiple-components-per-file": {
42052
+ recall: 0.0751,
42053
+ fpRate: 0.0423,
42054
+ ratio: 15.96,
42055
+ precision: 0.6747,
42056
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42057
+ verdict: "USEFUL",
42058
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=22103, FP=10655, P=67.5%, FPR=4.23%, lift=15.96. v7 was USEFUL (TP=16288, FP=9589, lift=12.04). v8 was USEFUL (TP=5815, FP=1066).",
42059
+ aiSpecific: false,
42060
+ _v7Verdict: "USEFUL",
42061
+ _v7Lift: 12.04,
42062
+ _v7Recall: 0.0687,
42063
+ _v7FpRate: 0.0523,
42064
+ _v7Precision: 0.6294,
42065
+ _v8Verdict: "USEFUL",
42066
+ _v8Lift: 54.44
40770
42067
  },
40771
42068
  "component/shadcn-prop-mismatch": {
40772
- recall: 13e-4,
42069
+ recall: 16e-4,
40773
42070
  fpRate: 1e-4,
40774
- ratio: 10.1,
40775
- precision: 0.929,
40776
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42071
+ ratio: 9990.98,
42072
+ precision: 0.9512,
42073
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40777
42074
  verdict: "USEFUL",
40778
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=314, FP=24, P=92.9%, FPR=0.01%, lift=10.1. aiSpecific=True.",
40779
- aiSpecific: true
42075
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=468, FP=24, P=95.1%, FPR=0.01%, lift=9990.98. v7 was USEFUL (TP=314, FP=24, lift=7099.57). v8 was USEFUL (TP=154, FP=0). v0.19 default-on (explicit defaultOff: false): P 95.1% / 9990x lift \u2014 UI bug.",
42076
+ aiSpecific: true,
42077
+ _v7Verdict: "USEFUL",
42078
+ _v7Lift: 7099.57,
42079
+ _v7Recall: 13e-4,
42080
+ _v7FpRate: 1e-4,
42081
+ _v7Precision: 0.929,
42082
+ _v8Verdict: "USEFUL",
42083
+ _v8Lift: 99999,
42084
+ defaultOff: false
40780
42085
  },
40781
- "layout/math-grid-uniformity": {
40782
- recall: 3e-4,
40783
- fpRate: 2e-4,
40784
- ratio: 1.72,
40785
- precision: 0.6907,
40786
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40787
- verdict: "OK",
40788
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. OK \u2014 TP=67, FP=30, P=69.1%, FPR=0.02%, lift=1.7. aiSpecific=True.",
40789
- aiSpecific: true
40790
- },
40791
- "layout/math-element-uniformity": {
40792
- recall: 28e-4,
40793
- fpRate: 12e-4,
40794
- ratio: 2.28,
40795
- precision: 0.7475,
40796
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42086
+ "context/import-path-mismatch": {
42087
+ recall: 0.0681,
42088
+ fpRate: 0.0167,
42089
+ ratio: 49.48,
42090
+ precision: 0.8263,
42091
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40797
42092
  verdict: "USEFUL",
40798
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=666, FP=225, P=74.7%, FPR=0.12%, lift=2.3. aiSpecific=True.",
40799
- aiSpecific: true
40800
- },
40801
- "typo/math-button-label-uniformity": {
40802
- recall: 2e-4,
40803
- fpRate: 1e-4,
40804
- ratio: 1.36,
40805
- precision: 0.6379,
40806
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40807
- verdict: "HYGIENE",
40808
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=37, FP=21, P=63.8%, FPR=0.01%, lift=1.4. aiSpecific=False.",
40809
- aiSpecific: false
40810
- },
40811
- "perf/css-bloat": {
40812
- recall: 0.0117,
40813
- fpRate: 32e-4,
40814
- ratio: 3.64,
40815
- precision: 0.8252,
40816
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40817
- verdict: "HYGIENE",
40818
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=2790, FP=591, P=82.5%, FPR=0.32%, lift=3.6. aiSpecific=False.",
40819
- aiSpecific: false
40820
- },
40821
- "wcag/focus-appearance": {
40822
- recall: 26e-4,
40823
- fpRate: 1e-4,
40824
- ratio: 19.68,
40825
- precision: 0.9623,
40826
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40827
- verdict: "HYGIENE",
40828
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=612, FP=24, P=96.2%, FPR=0.01%, lift=19.7. aiSpecific=False.",
40829
- aiSpecific: false
42093
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=20032, FP=4210, P=82.6%, FPR=1.67%, lift=49.48. v7 was USEFUL (TP=17672, FP=4202, lift=35.26). v8 was USEFUL (TP=2360, FP=8).",
42094
+ aiSpecific: false,
42095
+ _v7Verdict: "USEFUL",
42096
+ _v7Lift: 35.26,
42097
+ _v7Recall: 0.0746,
42098
+ _v7FpRate: 0.0229,
42099
+ _v7Precision: 0.8079,
42100
+ _v8Verdict: "USEFUL",
42101
+ _v8Lift: 8554.38
40830
42102
  },
40831
- "wcag/target-size": {
42103
+ "db/duplicate-index": {
40832
42104
  recall: 0,
40833
42105
  fpRate: 0,
40834
42106
  ratio: 0,
40835
42107
  precision: 0,
40836
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42108
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40837
42109
  verdict: "DORMANT",
40838
- defaultOff: true,
40839
- _calibrationNote: "v0.10.1 ship \u2014 not in v4 per-rule table. Default-off until calibration data lands. Backed by: W3C (2018), Web Content Accessibility Guidelines (WCAG) 2.1, Success Criterion 2.5.5 (Target Size); Fitts, P. M. (1954), \u2018The Information Capacity of the Human Motor System in Controlling the Amplitude of Movement\u2019, J. Exp. Psychol. 47(6):381-391. (WCAG 2.5.5 + Fitts's Law \u2014 minimum 24\xD724 CSS px tap target.)",
40840
- aiSpecific: false
40841
- },
40842
- "component/multiple-components-per-file": {
40843
- recall: 0.0681,
40844
- fpRate: 0.052,
40845
- ratio: 1.31,
40846
- precision: 0.6294,
40847
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40848
- verdict: "HYGIENE",
40849
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=16288, FP=9589, P=62.9%, FPR=5.20%, lift=1.3. aiSpecific=False.",
40850
- aiSpecific: false
40851
- },
40852
- "context/import-path-mismatch": {
40853
- recall: 0.0739,
40854
- fpRate: 0.0228,
40855
- ratio: 3.25,
40856
- precision: 0.8079,
40857
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40858
- verdict: "HYGIENE",
40859
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=17672, FP=4202, P=80.8%, FPR=2.28%, lift=3.2. aiSpecific=False.",
40860
- aiSpecific: false
40861
- },
40862
- "logic/key-prop-missing": {
40863
- recall: 17e-4,
40864
- fpRate: 14e-4,
40865
- ratio: 1.28,
40866
- precision: 0.6246,
40867
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40868
- verdict: "HYGIENE",
40869
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=416, FP=250, P=62.5%, FPR=0.14%, lift=1.3. aiSpecific=False.",
40870
- aiSpecific: false
40871
- },
40872
- "logic/math-variable-name-entropy": {
40873
- recall: 2e-4,
40874
- fpRate: 1e-4,
40875
- ratio: 1.07,
40876
- precision: 0.5806,
40877
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40878
- verdict: "HYGIENE",
40879
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=36, FP=26, P=58.1%, FPR=0.01%, lift=1.1. aiSpecific=False.",
40880
- aiSpecific: false
40881
- },
40882
- "security/public-admin-route": {
40883
- recall: 28e-4,
40884
- fpRate: 78e-4,
40885
- ratio: 0.4,
40886
- precision: 0.2251,
40887
- lastCalibratedAt: "2026-06-26T22:30:00Z",
40888
- verdict: "HYGIENE",
40889
- _calibrationNote: "v4 corpus (2026-06-25): 95,599 neg + 76,550 pos (frontend, TS/TSX/JS/JSX). INVERTED \u2014 TP=217, FP=747, P=22.5%, FPR=0.78%, lift=0.4. [v0.12.2: reclassified to HYGIENE because rule is aiSpecific: false]",
40890
- defaultOff: true,
40891
- aiSpecific: false
40892
- },
40893
- "security/unsafe-html-render": {
40894
- recall: 13e-4,
40895
- fpRate: 9e-4,
40896
- ratio: 1.5,
40897
- precision: 0.661,
40898
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40899
- verdict: "HYGIENE",
40900
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=312, FP=160, P=66.1%, FPR=0.09%, lift=1.5. aiSpecific=False.",
40901
- aiSpecific: false
40902
- },
40903
- "visual/naturalness-anomaly": {
40904
- recall: 0.1645,
40905
- fpRate: 0.0617,
40906
- ratio: 2.67,
40907
- precision: 0.7755,
40908
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40909
- verdict: "USEFUL",
40910
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=39319, FP=11382, P=77.6%, FPR=6.17%, lift=2.7. aiSpecific=True.",
40911
- aiSpecific: true
42110
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
42111
+ aiSpecific: false,
42112
+ _v7Verdict: "DORMANT",
42113
+ _v7Lift: 0,
42114
+ _v7Recall: 0,
42115
+ _v7FpRate: 0,
42116
+ _v7Precision: 0,
42117
+ _v8Verdict: "DORMANT",
42118
+ _v8Lift: 1,
42119
+ defaultOff: true
40912
42120
  },
40913
- "perf/halstead-anomaly": {
42121
+ "db/enum-sprawl": {
40914
42122
  recall: 0,
40915
42123
  fpRate: 0,
40916
- ratio: 2.32,
40917
- precision: 0.75,
40918
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40919
- verdict: "USEFUL",
40920
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=3, FP=1, P=75.0%, FPR=0.00%, lift=2.3. aiSpecific=True.",
40921
- aiSpecific: true
42124
+ ratio: 0,
42125
+ precision: 0,
42126
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42127
+ verdict: "DORMANT",
42128
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
42129
+ aiSpecific: false,
42130
+ _v7Verdict: "DORMANT",
42131
+ _v7Lift: 0,
42132
+ _v7Recall: 0,
42133
+ _v7FpRate: 0,
42134
+ _v7Precision: 0,
42135
+ _v8Verdict: "DORMANT",
42136
+ _v8Lift: 1,
42137
+ defaultOff: true
40922
42138
  },
40923
- "arch/astro-island-leak": {
42139
+ "db/missing-fk-index": {
40924
42140
  recall: 0,
40925
42141
  fpRate: 0,
40926
42142
  ratio: 0,
40927
42143
  precision: 0,
40928
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42144
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40929
42145
  verdict: "DORMANT",
40930
- defaultOff: true,
40931
- _calibrationNote: "v0.10.1 ship \u2014 not in v4 per-rule table. Default-off until calibration data lands. Backed by: Hevery, M. (2022), \u2018Islands Architecture: A New Pattern for Server-Component Frameworks\u2019, ACM SIGPLAN International Conference on Object-Oriented Programming, Systems, Languages & Applications (OOPSLA), invited talk; Astro Documentation (2023), https://docs.astro.build. (Astro Islands architecture \u2014 client JS should not leak into server components.)",
40932
- aiSpecific: true
42146
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
42147
+ aiSpecific: false,
42148
+ _v7Verdict: "DORMANT",
42149
+ _v7Lift: 0,
42150
+ _v7Recall: 0,
42151
+ _v7FpRate: 0,
42152
+ _v7Precision: 0,
42153
+ _v8Verdict: "DORMANT",
42154
+ _v8Lift: 1,
42155
+ defaultOff: true
40933
42156
  },
40934
- "logic/qwik-hook-leak": {
42157
+ "db/missing-not-null": {
40935
42158
  recall: 0,
40936
42159
  fpRate: 0,
40937
42160
  ratio: 0,
40938
42161
  precision: 0,
40939
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42162
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40940
42163
  verdict: "DORMANT",
40941
- defaultOff: true,
40942
- _calibrationNote: "v0.10.1 ship \u2014 not in v4 per-rule table. Default-off until calibration data lands. Backed by: Hevery, M. (2022), \u2018Qwik: A Resumable JavaScript Framework\u2019, ACM SIGPLAN OOPSLA companion; Builder.io Technical Report. (Qwik resumability \u2014 serializing state avoids hydration cost.)",
40943
- aiSpecific: true
42164
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
42165
+ aiSpecific: false,
42166
+ _v7Verdict: "DORMANT",
42167
+ _v7Lift: 0,
42168
+ _v7Recall: 0,
42169
+ _v7FpRate: 0,
42170
+ _v7Precision: 0,
42171
+ _v8Verdict: "DORMANT",
42172
+ _v8Lift: 1,
42173
+ defaultOff: true
40944
42174
  },
40945
- "test/missing-edge-case": {
42175
+ "db/naming-inconsistency": {
40946
42176
  recall: 0,
40947
42177
  fpRate: 0,
40948
42178
  ratio: 0,
40949
42179
  precision: 0,
40950
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42180
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40951
42181
  verdict: "DORMANT",
40952
- defaultOff: true,
40953
- _calibrationNote: "v0.10.1 ship \u2014 not in v4 per-rule table. Default-off until calibration data lands. Backed by: Myers, G. J. (1979), *The Art of Software Testing*, Wiley-Interscience (canonical boundary value analysis reference); Beizer, B. (1990), *Software Testing Techniques*, 2nd ed., Van Nostrand Reinhold. (Boundary value analysis \u2014 empty / zero / max / null / type-boundary cases.)",
40954
- aiSpecific: true
42182
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
42183
+ aiSpecific: false,
42184
+ _v7Verdict: "DORMANT",
42185
+ _v7Lift: 0,
42186
+ _v7Recall: 0,
42187
+ _v7FpRate: 0,
42188
+ _v7Precision: 0,
42189
+ _v8Verdict: "DORMANT",
42190
+ _v8Lift: 1,
42191
+ defaultOff: true
40955
42192
  },
40956
- "typo/calc-fontsize": {
42193
+ "db/sql-concat": {
42194
+ recall: 5e-4,
42195
+ fpRate: 1e-4,
42196
+ ratio: 7511.26,
42197
+ precision: 0.8343,
42198
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42199
+ verdict: "USEFUL",
42200
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=141, FP=28, P=83.4%, FPR=0.01%, lift=7511.26. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=141, FP=28).",
42201
+ aiSpecific: true,
42202
+ _v7Verdict: "DORMANT",
42203
+ _v7Lift: 1,
42204
+ _v7Recall: 0,
42205
+ _v7FpRate: 0,
42206
+ _v7Precision: 0,
42207
+ _v8Verdict: "USEFUL",
42208
+ _v8Lift: 2046.08
42209
+ },
42210
+ "dead/dead-branch": {
42211
+ recall: 2e-4,
42212
+ fpRate: 4e-4,
42213
+ ratio: 1080.68,
42214
+ precision: 0.4244,
42215
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42216
+ verdict: "OK",
42217
+ _calibrationNote: "v8.5 (v0.18.9): v85 verdict=OK, v7 was DORMANT, v8 was OK. v0.18.8 v8a first measurement (1000 files): see docs/research/v0.18.8-dead-rules-measurement.md.",
42218
+ aiSpecific: true,
42219
+ _v7Verdict: "DORMANT",
42220
+ _v7Lift: 1,
42221
+ _v7Recall: 0,
42222
+ _v7FpRate: 0,
42223
+ _v7Precision: 0,
42224
+ _v8Verdict: "OK",
42225
+ _v8Lift: 294.38
42226
+ },
42227
+ "dead/unreachable": {
42228
+ recall: 1e-4,
42229
+ fpRate: 6e-4,
42230
+ ratio: 153.14,
42231
+ precision: 0.0966,
42232
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42233
+ verdict: "OK",
42234
+ _calibrationNote: "v8.5 (v0.18.9): v85 verdict=OK, v7 was DORMANT, v8 was OK. v0.18.8 v8a first measurement (1000 files): see docs/research/v0.18.8-dead-rules-measurement.md.",
42235
+ aiSpecific: true,
42236
+ _v7Verdict: "DORMANT",
42237
+ _v7Lift: 1,
42238
+ _v7Recall: 0,
42239
+ _v7FpRate: 0,
42240
+ _v7Precision: 0,
42241
+ _v8Verdict: "OK",
42242
+ _v8Lift: 41.71
42243
+ },
42244
+ "dead/unused-import": {
42245
+ recall: 0.0379,
42246
+ fpRate: 0.0222,
42247
+ ratio: 30.06,
42248
+ precision: 0.6662,
42249
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42250
+ verdict: "USEFUL",
42251
+ _calibrationNote: "v8.5 (v0.18.9): v85 verdict=USEFUL, v7 was DORMANT, v8 was USEFUL. v0.18.8 v8a first measurement (1000 files): see docs/research/v0.18.8-dead-rules-measurement.md.",
42252
+ aiSpecific: true,
42253
+ _v7Verdict: "DORMANT",
42254
+ _v7Lift: 1,
42255
+ _v7Recall: 0,
42256
+ _v7FpRate: 0,
42257
+ _v7Precision: 0,
42258
+ _v8Verdict: "USEFUL",
42259
+ _v8Lift: 8.19
42260
+ },
42261
+ "dead/unused-local": {
42262
+ recall: 0.0477,
42263
+ fpRate: 74e-4,
42264
+ ratio: 120.18,
42265
+ precision: 0.8834,
42266
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42267
+ verdict: "USEFUL",
42268
+ _calibrationNote: "v8.5 (v0.18.9): v85 verdict=USEFUL, v7 was DORMANT, v8 was USEFUL. v0.18.8 v8a first measurement (1000 files): see docs/research/v0.18.8-dead-rules-measurement.md. v0.19 default-on (explicit defaultOff: false): P 88.3% / FPR 0.74% / 120x lift \u2014 code hygiene.",
42269
+ aiSpecific: true,
42270
+ _v7Verdict: "DORMANT",
42271
+ _v7Lift: 1,
42272
+ _v7Recall: 0,
42273
+ _v7FpRate: 0,
42274
+ _v7Precision: 0,
42275
+ _v8Verdict: "USEFUL",
42276
+ _v8Lift: 32.74,
42277
+ defaultOff: false
42278
+ },
42279
+ "dead/unused-parameter": {
42280
+ recall: 8e-4,
42281
+ fpRate: 27e-4,
42282
+ ratio: 98,
42283
+ precision: 0.2628,
42284
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42285
+ verdict: "OK",
42286
+ _calibrationNote: "v8.5 (v0.18.9): v85 verdict=OK, v7 was DORMANT, v8 was OK. v0.18.8 v8a first measurement (1000 files): see docs/research/v0.18.8-dead-rules-measurement.md.",
42287
+ aiSpecific: true,
42288
+ _v7Verdict: "DORMANT",
42289
+ _v7Lift: 1,
42290
+ _v7Recall: 0,
42291
+ _v7FpRate: 0,
42292
+ _v7Precision: 0,
42293
+ _v8Verdict: "OK",
42294
+ _v8Lift: 26.7
42295
+ },
42296
+ "docs/broken-link": {
42297
+ recall: 14e-4,
42298
+ fpRate: 23e-4,
42299
+ ratio: 178.13,
42300
+ precision: 0.4155,
42301
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42302
+ verdict: "OK",
42303
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=418, FP=588, P=41.6%, FPR=0.23%, lift=178.13. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was OK (TP=418, FP=588).",
42304
+ aiSpecific: false,
42305
+ _v7Verdict: "DORMANT",
42306
+ _v7Lift: 1,
42307
+ _v7Recall: 0,
42308
+ _v7FpRate: 0,
42309
+ _v7Precision: 0,
42310
+ _v8Verdict: "OK",
42311
+ _v8Lift: 48.52
42312
+ },
42313
+ "docs/expired-code-example": {
40957
42314
  recall: 0,
40958
42315
  fpRate: 0,
40959
42316
  ratio: 0,
40960
42317
  precision: 0,
40961
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42318
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42319
+ verdict: "INVERTED",
42320
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=0, FP=3, P=0.0%, FPR=0.00%, lift=0.00. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was INVERTED (TP=0, FP=3).",
42321
+ aiSpecific: false,
42322
+ _v7Verdict: "DORMANT",
42323
+ _v7Lift: 1,
42324
+ _v7Recall: 0,
42325
+ _v7FpRate: 0,
42326
+ _v7Precision: 0,
42327
+ _v8Verdict: "INVERTED",
42328
+ _v8Lift: 0,
42329
+ defaultOff: true
42330
+ },
42331
+ "docs/stale-function-reference": {
42332
+ recall: 26e-4,
42333
+ fpRate: 5e-4,
42334
+ ratio: 1638.47,
42335
+ precision: 0.8515,
42336
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42337
+ verdict: "USEFUL",
42338
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=751, FP=131, P=85.1%, FPR=0.05%, lift=1638.47. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=751, FP=131).",
42339
+ aiSpecific: false,
42340
+ _v7Verdict: "DORMANT",
42341
+ _v7Lift: 1,
42342
+ _v7Recall: 0,
42343
+ _v7FpRate: 0,
42344
+ _v7Precision: 0,
42345
+ _v8Verdict: "USEFUL",
42346
+ _v8Lift: 446.32
42347
+ },
42348
+ "docs/stale-package-reference": {
42349
+ recall: 2e-4,
42350
+ fpRate: 4e-4,
42351
+ ratio: 939.43,
42352
+ precision: 0.3429,
42353
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42354
+ verdict: "OK",
42355
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=48, FP=92, P=34.3%, FPR=0.04%, lift=939.43. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was OK (TP=48, FP=92).",
42356
+ aiSpecific: false,
42357
+ _v7Verdict: "DORMANT",
42358
+ _v7Lift: 1,
42359
+ _v7Recall: 0,
42360
+ _v7FpRate: 0,
42361
+ _v7Precision: 0,
42362
+ _v8Verdict: "OK",
42363
+ _v8Lift: 255.9
42364
+ },
42365
+ "dup/identical-block": {
42366
+ recall: 0,
42367
+ fpRate: 0,
42368
+ ratio: 1,
42369
+ precision: 0,
42370
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40962
42371
  verdict: "DORMANT",
40963
- defaultOff: true,
40964
- _calibrationNote: "v0.10.1 ship \u2014 not in v4 per-rule table. Default-off until calibration data lands. Backed by: Marcotte, E. (2016), *Responsive Design: Patterns & Principles*, A Book Apart; Brown, J. (2018), *Every Layout*, self-published (rel='https://every-layout.dev'). (Fluid typography via clamp(min, preferred, max).)",
40965
- aiSpecific: false
42372
+ _calibrationNote: "v0.19: new rule, not yet calibrated. v8.5 calibration does not run dup/* rules. Scheduled for v0.20 calibration on near-dup corpus.",
42373
+ aiSpecific: false,
42374
+ _v7Verdict: "DORMANT",
42375
+ _v7Lift: 1,
42376
+ _v7Recall: 0,
42377
+ _v7FpRate: 0,
42378
+ _v7Precision: 0,
42379
+ _v8Verdict: "DORMANT",
42380
+ _v8Lift: 1,
42381
+ defaultOff: true
40966
42382
  },
40967
- "typo/clamp-offscale": {
42383
+ "go/error-wrap-without-context": {
40968
42384
  recall: 0,
40969
42385
  fpRate: 0,
40970
- ratio: 0,
42386
+ ratio: 1,
40971
42387
  precision: 0,
40972
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42388
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40973
42389
  verdict: "DORMANT",
40974
- defaultOff: true,
40975
- _calibrationNote: "v0.10.1 ship \u2014 not in v4 per-rule table. Default-off until calibration data lands. Backed by: W3C (2023), CSS Values 4 \xA77.2 (Functional Notations: clamp()); Brown, J. (2018), *Every Layout*. (CSS clamp() \u2014 off-scale (negative, >10rem) values are typos.)",
40976
- aiSpecific: false
42390
+ _calibrationNote: "v0.19: new rule (fmt.Errorf wrap with generic message \u2014 needs operation context). Not yet calibrated. Scheduled for v9 calibration.",
42391
+ aiSpecific: true,
42392
+ _v7Verdict: "DORMANT",
42393
+ _v7Lift: 1,
42394
+ _v7Recall: 0,
42395
+ _v7FpRate: 0,
42396
+ _v7Precision: 0,
42397
+ _v8Verdict: "DORMANT",
42398
+ _v8Lift: 1,
42399
+ defaultOff: true
40977
42400
  },
40978
- "typo/math-cta-vocabulary": {
42401
+ "go/nil-slice-vs-empty": {
40979
42402
  recall: 0,
40980
42403
  fpRate: 0,
40981
- ratio: 0,
42404
+ ratio: 1,
40982
42405
  precision: 0,
40983
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42406
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40984
42407
  verdict: "DORMANT",
40985
- defaultOff: true,
40986
- _calibrationNote: "v0.10.1 ship \u2014 not in v4 per-rule table. Default-off until calibration data lands. Backed by: Cialdini, R. B. (1984), *Influence: The Psychology of Persuasion*, Harper Business; Krug, S. (2000), *Don't Make Me Think*, 2nd ed., New Riders. (CTA wording \u2014 vague labels reduce click-through per Cialdini commitment/consistency.)",
40987
- aiSpecific: true
42408
+ _calibrationNote: "v0.19: new rule (Variable declared nil slice but assigned empty slice). Not yet calibrated. Scheduled for v9 calibration.",
42409
+ aiSpecific: true,
42410
+ _v7Verdict: "DORMANT",
42411
+ _v7Lift: 1,
42412
+ _v7Recall: 0,
42413
+ _v7FpRate: 0,
42414
+ _v7Precision: 0,
42415
+ _v8Verdict: "DORMANT",
42416
+ _v8Lift: 1,
42417
+ defaultOff: true
40988
42418
  },
40989
- "layout/forced-layout": {
42419
+ "go/struct-tag-inconsistency": {
40990
42420
  recall: 0,
40991
42421
  fpRate: 0,
40992
- ratio: 0,
42422
+ ratio: 1,
40993
42423
  precision: 0,
40994
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42424
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40995
42425
  verdict: "DORMANT",
40996
- defaultOff: true,
40997
- _calibrationNote: "v0.10.1 ship \u2014 not in v4 per-rule table. Default-off until calibration data lands. Backed by: Mozilla Developer Network (2023), CSS Grid Layout, https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout; W3C (2023), CSS Grid Layout Module Level 3, W3C CR-css-grid-3-20231218. (CSS Grid spec \u2014 forced layout is a fallback hack, not the idiomatic approach.)",
40998
- aiSpecific: true
42426
+ _calibrationNote: "v0.19: new rule (Struct fields mix json tag styles). Not yet calibrated. Scheduled for v9 calibration.",
42427
+ aiSpecific: true,
42428
+ _v7Verdict: "DORMANT",
42429
+ _v7Lift: 1,
42430
+ _v7Recall: 0,
42431
+ _v7FpRate: 0,
42432
+ _v7Precision: 0,
42433
+ _v8Verdict: "DORMANT",
42434
+ _v8Lift: 1,
42435
+ defaultOff: true
40999
42436
  },
41000
- "visual/generic-centering": {
42437
+ "layout/forced-layout": {
41001
42438
  recall: 0,
41002
42439
  fpRate: 0,
41003
42440
  ratio: 0,
41004
42441
  precision: 0,
41005
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42442
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41006
42443
  verdict: "DORMANT",
41007
- defaultOff: true,
41008
- _calibrationNote: "v0.10.1 ship \u2014 not in v4 per-rule table. Default-off until calibration data lands. Backed by: Wertheimer, M. (1923), \u2018Untersuchungen zur Lehre von der Gestalt II\u2019, Psychologische Forschung 4:301-350; M\xFCller-Brockmann, J. (1981), *Grid Systems in Graphic Design*, Niggli. (Gestalt centering + grid systems \u2014 generic centering is anti-grid.)",
41009
- aiSpecific: true
41010
- },
41011
- "product/terminology-drift": {
41012
- recall: 85e-4,
41013
- fpRate: 28e-4,
41014
- ratio: 3,
41015
- precision: 0.7956,
41016
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41017
- verdict: "HYGIENE",
41018
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=2028, FP=521, P=79.6%, FPR=0.28%, lift=3.0. aiSpecific=False.",
41019
- aiSpecific: false
42444
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
42445
+ aiSpecific: true,
42446
+ _v7Verdict: "DORMANT",
42447
+ _v7Lift: 0,
42448
+ _v7Recall: 0,
42449
+ _v7FpRate: 0,
42450
+ _v7Precision: 0,
42451
+ _v8Verdict: "DORMANT",
42452
+ _v8Lift: 1,
42453
+ defaultOff: true
41020
42454
  },
41021
- "product/ux-pattern-fragmentation": {
41022
- recall: 1e-4,
41023
- fpRate: 0,
41024
- ratio: 3.09,
41025
- precision: 0.8,
41026
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42455
+ "layout/gap-monopoly": {
42456
+ recall: 3e-4,
42457
+ fpRate: 1e-4,
42458
+ ratio: 8859.33,
42459
+ precision: 0.8083,
42460
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41027
42461
  verdict: "USEFUL",
41028
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=32, FP=8, P=80.0%, FPR=0.00%, lift=3.1. aiSpecific=True.",
41029
- aiSpecific: true
42462
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=97, FP=23, P=80.8%, FPR=0.01%, lift=8859.33. v7 was USEFUL (TP=88, FP=23, lift=6322.11). v8 was USEFUL (TP=9, FP=0).",
42463
+ aiSpecific: false,
42464
+ _v7Verdict: "USEFUL",
42465
+ _v7Lift: 6322.11,
42466
+ _v7Recall: 4e-4,
42467
+ _v7FpRate: 1e-4,
42468
+ _v7Precision: 0.7928,
42469
+ _v8Verdict: "USEFUL",
42470
+ _v8Lift: 99999
41030
42471
  },
41031
- "security/sql-construction": {
41032
- recall: 3e-3,
41033
- fpRate: 18e-4,
41034
- ratio: 1.63,
41035
- precision: 0.6788,
41036
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41037
- verdict: "OK",
41038
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. OK \u2014 TP=710, FP=336, P=67.9%, FPR=0.18%, lift=1.6. aiSpecific=True.",
41039
- aiSpecific: true
42472
+ "layout/math-element-uniformity": {
42473
+ recall: 29e-4,
42474
+ fpRate: 1e-3,
42475
+ ratio: 770.74,
42476
+ precision: 0.7705,
42477
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42478
+ verdict: "USEFUL",
42479
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=846, FP=252, P=77.0%, FPR=0.10%, lift=770.74. v7 was USEFUL (TP=666, FP=225, lift=609.32). v8 was USEFUL (TP=180, FP=27).",
42480
+ aiSpecific: true,
42481
+ _v7Verdict: "USEFUL",
42482
+ _v7Lift: 609.32,
42483
+ _v7Recall: 28e-4,
42484
+ _v7FpRate: 12e-4,
42485
+ _v7Precision: 0.7475,
42486
+ _v8Verdict: "USEFUL",
42487
+ _v8Lift: 2211.5
41040
42488
  },
41041
- "security/missing-auth-check": {
41042
- recall: 63e-4,
41043
- fpRate: 4e-4,
41044
- ratio: 15.3,
41045
- precision: 0.9247,
41046
- lastCalibratedAt: "2026-06-26T22:30:00Z",
42489
+ "layout/math-grid-uniformity": {
42490
+ recall: 3e-4,
42491
+ fpRate: 1e-4,
42492
+ ratio: 5839.98,
42493
+ precision: 0.7182,
42494
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41047
42495
  verdict: "USEFUL",
41048
- _calibrationNote: "v4 corpus (2026-06-25): 95,599 neg + 76,550 pos (frontend, TS/TSX/JS/JSX). USEFUL \u2014 TP=479, FP=39, P=92.5%, FPR=0.04%, lift=15.3.",
41049
- aiSpecific: false
42496
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=79, FP=31, P=71.8%, FPR=0.01%, lift=5839.98. v7 was USEFUL (TP=67, FP=30, lift=4222.91). v8 was USEFUL (TP=12, FP=1).",
42497
+ aiSpecific: true,
42498
+ _v7Verdict: "USEFUL",
42499
+ _v7Lift: 4222.91,
42500
+ _v7Recall: 3e-4,
42501
+ _v7FpRate: 2e-4,
42502
+ _v7Precision: 0.6907,
42503
+ _v8Verdict: "USEFUL",
42504
+ _v8Lift: 63384.92
41050
42505
  },
41051
- "security/dangerous-cors": {
41052
- recall: 5e-4,
41053
- fpRate: 5e-4,
41054
- ratio: 1.05,
41055
- precision: 0.5758,
41056
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41057
- verdict: "NOISY",
41058
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. NOISY \u2014 TP=114, FP=84, P=57.6%, FPR=0.05%, lift=1.0. aiSpecific=True.",
41059
- defaultOff: true,
41060
- aiSpecific: true
42506
+ "layout/spacing-grid": {
42507
+ recall: 2e-4,
42508
+ fpRate: 2e-4,
42509
+ ratio: 4051.29,
42510
+ precision: 0.6429,
42511
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42512
+ verdict: "USEFUL",
42513
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=72, FP=40, P=64.3%, FPR=0.02%, lift=4051.29. v7 was USEFUL (TP=39, FP=15, lift=8831.00). v8 was USEFUL (TP=33, FP=25).",
42514
+ aiSpecific: false,
42515
+ _v7Verdict: "USEFUL",
42516
+ _v7Lift: 8831,
42517
+ _v7Recall: 2e-4,
42518
+ _v7FpRate: 1e-4,
42519
+ _v7Precision: 0.7222,
42520
+ _v8Verdict: "USEFUL",
42521
+ _v8Lift: 1562.77
41061
42522
  },
41062
- "test/duplicate-setup": {
41063
- recall: 1e-4,
42523
+ "logic/bayesian-conditional": {
42524
+ recall: 0,
41064
42525
  fpRate: 0,
41065
- ratio: 3.6,
41066
- precision: 0.8235,
41067
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42526
+ ratio: 0,
42527
+ precision: 0,
42528
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42529
+ verdict: "DORMANT",
42530
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
42531
+ aiSpecific: true,
42532
+ _v7Verdict: "DORMANT",
42533
+ _v7Lift: 0,
42534
+ _v7Recall: 0,
42535
+ _v7FpRate: 0,
42536
+ _v7Precision: 0,
42537
+ _v8Verdict: "DORMANT",
42538
+ _v8Lift: 1,
42539
+ defaultOff: true
42540
+ },
42541
+ "logic/boundary-violation": {
42542
+ recall: 0.0274,
42543
+ fpRate: 0.0137,
42544
+ ratio: 51.32,
42545
+ precision: 0.7006,
42546
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41068
42547
  verdict: "USEFUL",
41069
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=14, FP=3, P=82.4%, FPR=0.00%, lift=3.6. aiSpecific=True.",
41070
- aiSpecific: true
42548
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=8051, FP=3441, P=70.1%, FPR=1.37%, lift=51.32. v7 was USEFUL (TP=6282, FP=3235, lift=37.42). v8 was USEFUL (TP=1769, FP=206).",
42549
+ aiSpecific: false,
42550
+ _v7Verdict: "USEFUL",
42551
+ _v7Lift: 37.42,
42552
+ _v7Recall: 0.0265,
42553
+ _v7FpRate: 0.0176,
42554
+ _v7Precision: 0.6601,
42555
+ _v8Verdict: "USEFUL",
42556
+ _v8Lift: 298.57
41071
42557
  },
41072
42558
  "logic/ghost-defensive": {
41073
42559
  recall: 1e-4,
41074
42560
  fpRate: 0,
41075
- ratio: 5.79,
41076
- precision: 0.8824,
41077
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42561
+ ratio: 112035.56,
42562
+ precision: 0.8889,
42563
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41078
42564
  verdict: "USEFUL",
41079
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=15, FP=2, P=88.2%, FPR=0.00%, lift=5.8. aiSpecific=True.",
41080
- aiSpecific: true
42565
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=16, FP=2, P=88.9%, FPR=0.00%, lift=112035.56. v7 was USEFUL (TP=15, FP=2, lift=80917.50). v8 was USEFUL (TP=1, FP=0). v0.19 default-on (explicit defaultOff: false): P 88.9% / 112k lift \u2014 code smell.",
42566
+ aiSpecific: true,
42567
+ _v7Verdict: "USEFUL",
42568
+ _v7Lift: 80917.5,
42569
+ _v7Recall: 1e-4,
42570
+ _v7FpRate: 0,
42571
+ _v7Precision: 0.8824,
42572
+ _v8Verdict: "USEFUL",
42573
+ _v8Lift: 99999,
42574
+ defaultOff: false
41081
42575
  },
41082
- "typo/calc-raw-px": {
41083
- recall: 0,
41084
- fpRate: 0,
41085
- ratio: 2.32,
41086
- precision: 0.75,
41087
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41088
- verdict: "HYGIENE",
41089
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=3, FP=1, P=75.0%, FPR=0.00%, lift=2.3. aiSpecific=False.",
41090
- aiSpecific: false
42576
+ "logic/heaps-deviation": {
42577
+ recall: 0.0126,
42578
+ fpRate: 0.0178,
42579
+ ratio: 25.54,
42580
+ precision: 0.4536,
42581
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42582
+ verdict: "OK",
42583
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=3716, FP=4477, P=45.4%, FPR=1.78%, lift=25.54. v7 was USEFUL (TP=2924, FP=2430, lift=41.22). v8 was OK (TP=792, FP=2047).",
42584
+ aiSpecific: false,
42585
+ _v7Verdict: "USEFUL",
42586
+ _v7Lift: 41.22,
42587
+ _v7Recall: 0.0123,
42588
+ _v7FpRate: 0.0132,
42589
+ _v7Precision: 0.5461,
42590
+ _v8Verdict: "OK",
42591
+ _v8Lift: 9.36
41091
42592
  },
41092
- "security/fail-open-auth": {
41093
- recall: 0,
41094
- fpRate: 0,
41095
- ratio: 99.99,
41096
- precision: 1,
41097
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42593
+ "logic/key-prop-missing": {
42594
+ recall: 16e-4,
42595
+ fpRate: 11e-4,
42596
+ ratio: 574.52,
42597
+ precision: 0.629,
42598
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41098
42599
  verdict: "USEFUL",
41099
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=1, FP=0, P=100.0%, FPR=0.00%, lift=inf. aiSpecific=True.",
41100
- aiSpecific: true
42600
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=468, FP=276, P=62.9%, FPR=0.11%, lift=574.52. v7 was USEFUL (TP=416, FP=250, lift=458.26). v8 was USEFUL (TP=52, FP=26).",
42601
+ aiSpecific: false,
42602
+ _v7Verdict: "USEFUL",
42603
+ _v7Lift: 458.26,
42604
+ _v7Recall: 18e-4,
42605
+ _v7FpRate: 14e-4,
42606
+ _v7Precision: 0.6246,
42607
+ _v8Verdict: "USEFUL",
42608
+ _v8Lift: 1760.69
41101
42609
  },
41102
- "wcag/focus-obscured": {
41103
- recall: 33e-4,
41104
- fpRate: 9e-4,
41105
- ratio: 3.51,
41106
- precision: 0.82,
41107
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41108
- verdict: "HYGIENE",
41109
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=797, FP=175, P=82.0%, FPR=0.09%, lift=3.5. aiSpecific=False.",
41110
- aiSpecific: false
42610
+ "logic/math-any-density": {
42611
+ recall: 17e-4,
42612
+ fpRate: 13e-4,
42613
+ ratio: 464.59,
42614
+ precision: 0.6027,
42615
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42616
+ verdict: "USEFUL",
42617
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=496, FP=327, P=60.3%, FPR=0.13%, lift=464.59. v7 was USEFUL (TP=376, FP=247, lift=448.16). v8 was USEFUL (TP=120, FP=80).",
42618
+ aiSpecific: true,
42619
+ _v7Verdict: "USEFUL",
42620
+ _v7Lift: 448.16,
42621
+ _v7Recall: 16e-4,
42622
+ _v7FpRate: 13e-4,
42623
+ _v7Precision: 0.6035,
42624
+ _v8Verdict: "USEFUL",
42625
+ _v8Lift: 515
41111
42626
  },
41112
- "visual/arbitrary-escape": {
41113
- recall: 25e-4,
41114
- fpRate: 9e-4,
41115
- ratio: 2.74,
41116
- precision: 0.7802,
41117
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42627
+ "logic/math-console-log-storm": {
42628
+ recall: 65e-4,
42629
+ fpRate: 11e-4,
42630
+ ratio: 794.4,
42631
+ precision: 0.8729,
42632
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41118
42633
  verdict: "USEFUL",
41119
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=600, FP=169, P=78.0%, FPR=0.09%, lift=2.7. aiSpecific=True.",
41120
- aiSpecific: true
42634
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=1903, FP=277, P=87.3%, FPR=0.11%, lift=794.40. v7 was USEFUL (TP=1678, FP=193, lift=852.30). v8 was USEFUL (TP=225, FP=84).",
42635
+ aiSpecific: true,
42636
+ _v7Verdict: "USEFUL",
42637
+ _v7Lift: 852.3,
42638
+ _v7Recall: 71e-4,
42639
+ _v7FpRate: 11e-4,
42640
+ _v7Precision: 0.8968,
42641
+ _v8Verdict: "USEFUL",
42642
+ _v8Lift: 595.24
41121
42643
  },
41122
- "security/hardcoded-secret": {
42644
+ "logic/math-gini-class-usage": {
41123
42645
  recall: 13e-4,
41124
- fpRate: 7e-4,
41125
- ratio: 1.72,
41126
- precision: 0.6899,
41127
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41128
- verdict: "OK",
41129
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. OK \u2014 TP=307, FP=138, P=69.0%, FPR=0.07%, lift=1.7. aiSpecific=True.",
41130
- aiSpecific: true
41131
- },
41132
- "visual/radius-scale-violation": {
41133
- recall: 4e-4,
41134
- fpRate: 0,
41135
- ratio: 24.7,
41136
- precision: 0.9697,
41137
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41138
- verdict: "HYGIENE",
41139
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=96, FP=3, P=97.0%, FPR=0.00%, lift=24.7. aiSpecific=False.",
41140
- aiSpecific: false
41141
- },
41142
- "test/fake-placeholder": {
41143
- recall: 53e-4,
41144
- fpRate: 19e-4,
41145
- ratio: 2.82,
41146
- precision: 0.7854,
41147
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42646
+ fpRate: 2e-4,
42647
+ ratio: 4648.6,
42648
+ precision: 0.8852,
42649
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41148
42650
  verdict: "USEFUL",
41149
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=1259, FP=344, P=78.5%, FPR=0.19%, lift=2.8. aiSpecific=True.",
41150
- aiSpecific: true
41151
- },
41152
- "security/exposed-env-var": {
41153
- recall: 6e-4,
41154
- fpRate: 7e-4,
41155
- ratio: 0.9,
41156
- precision: 0.5387,
41157
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41158
- verdict: "HYGIENE",
41159
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=146, FP=125, P=53.9%, FPR=0.07%, lift=0.9. aiSpecific=False.",
41160
- aiSpecific: false
41161
- },
41162
- "perf/cls-image": {
41163
- recall: 2e-4,
41164
- fpRate: 3e-4,
41165
- ratio: 0.8,
41166
- precision: 0.5104,
41167
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41168
- verdict: "HYGIENE",
41169
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=49, FP=47, P=51.0%, FPR=0.03%, lift=0.8. aiSpecific=False.",
41170
- aiSpecific: false
42651
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=370, FP=48, P=88.5%, FPR=0.02%, lift=4648.60. v7 was USEFUL (TP=310, FP=47, lift=3388.64). v8 was USEFUL (TP=60, FP=1).",
42652
+ aiSpecific: true,
42653
+ _v7Verdict: "USEFUL",
42654
+ _v7Lift: 3388.64,
42655
+ _v7Recall: 13e-4,
42656
+ _v7FpRate: 3e-4,
42657
+ _v7Precision: 0.8683,
42658
+ _v8Verdict: "USEFUL",
42659
+ _v8Lift: 67541.31
41171
42660
  },
41172
- "layout/gap-monopoly": {
41173
- recall: 4e-4,
41174
- fpRate: 1e-4,
41175
- ratio: 2.95,
41176
- precision: 0.7928,
41177
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41178
- verdict: "HYGIENE",
41179
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=88, FP=23, P=79.3%, FPR=0.01%, lift=3.0. aiSpecific=False.",
41180
- aiSpecific: false
41181
- },
41182
- "visual/spacing-scale-violation": {
41183
- recall: 83e-4,
41184
- fpRate: 39e-4,
41185
- ratio: 2.13,
41186
- precision: 0.7342,
41187
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41188
- verdict: "HYGIENE",
41189
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=1981, FP=717, P=73.4%, FPR=0.39%, lift=2.1. aiSpecific=False.",
41190
- aiSpecific: false
41191
- },
41192
- "visual/inline-style-dominance": {
41193
- recall: 96e-4,
41194
- fpRate: 66e-4,
41195
- ratio: 1.46,
41196
- precision: 0.6535,
41197
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41198
- verdict: "HYGIENE",
41199
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=2303, FP=1221, P=65.4%, FPR=0.66%, lift=1.5. aiSpecific=False.",
41200
- aiSpecific: false
41201
- },
41202
- "layout/spacing-grid": {
42661
+ "logic/math-variable-name-entropy": {
41203
42662
  recall: 2e-4,
41204
42663
  fpRate: 1e-4,
41205
- ratio: 2.01,
41206
- precision: 0.7222,
41207
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41208
- verdict: "HYGIENE",
41209
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=39, FP=15, P=72.2%, FPR=0.01%, lift=2.0. aiSpecific=False.",
41210
- aiSpecific: false
41211
- },
41212
- "wcag/dragging-movements": {
41213
- recall: 0,
41214
- fpRate: 0,
41215
- ratio: 0.51,
41216
- precision: 0.4,
41217
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41218
- verdict: "HYGIENE",
41219
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=2, FP=3, P=40.0%, FPR=0.00%, lift=0.5. aiSpecific=False.",
41220
- aiSpecific: false
42664
+ ratio: 4548.81,
42665
+ precision: 0.6316,
42666
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42667
+ verdict: "USEFUL",
42668
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=60, FP=35, P=63.2%, FPR=0.01%, lift=4548.81. v7 was USEFUL (TP=36, FP=26, lift=4096.07). v8 was USEFUL (TP=24, FP=9).",
42669
+ aiSpecific: false,
42670
+ _v7Verdict: "USEFUL",
42671
+ _v7Lift: 4096.07,
42672
+ _v7Recall: 2e-4,
42673
+ _v7FpRate: 1e-4,
42674
+ _v7Precision: 0.5806,
42675
+ _v8Verdict: "USEFUL",
42676
+ _v8Lift: 5548.85
41221
42677
  },
41222
- "test/weak-assertion": {
41223
- recall: 0.0414,
41224
- fpRate: 86e-4,
41225
- ratio: 4.83,
41226
- precision: 0.8622,
41227
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42678
+ "logic/optimistic-no-rollback": {
42679
+ recall: 12e-4,
42680
+ fpRate: 2e-4,
42681
+ ratio: 3523.57,
42682
+ precision: 0.8527,
42683
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41228
42684
  verdict: "USEFUL",
41229
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=9906, FP=1583, P=86.2%, FPR=0.86%, lift=4.8. aiSpecific=True.",
41230
- aiSpecific: true
42685
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=353, FP=61, P=85.3%, FPR=0.02%, lift=3523.57. v7 was USEFUL (TP=281, FP=60, lift=2519.02). v8 was USEFUL (TP=72, FP=1).",
42686
+ aiSpecific: true,
42687
+ _v7Verdict: "USEFUL",
42688
+ _v7Lift: 2519.02,
42689
+ _v7Recall: 12e-4,
42690
+ _v7FpRate: 3e-4,
42691
+ _v7Precision: 0.824,
42692
+ _v8Verdict: "USEFUL",
42693
+ _v8Lift: 67726.36
41231
42694
  },
41232
- "logic/bayesian-conditional": {
42695
+ "logic/qwik-hook-leak": {
41233
42696
  recall: 0,
41234
42697
  fpRate: 0,
41235
42698
  ratio: 0,
41236
42699
  precision: 0,
41237
- lastCalibratedAt: "2026-06-27T00:00:00Z",
42700
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41238
42701
  verdict: "DORMANT",
41239
- defaultOff: true,
41240
- _calibrationNote: "v0.12.0 ship \u2014 new Bayesian LR-combiner rule (Bento et al. 2024 *Neurocomputing*). Default-off until v0.12 corpus re-calibration lands. Threshold P(AI|fires) \u2265 0.7; posterior computed from per-rule likelihood ratios.",
41241
- aiSpecific: true
41242
- },
41243
- "logic/heaps-deviation": {
41244
- recall: 0.0122,
41245
- fpRate: 0.0132,
41246
- ratio: 0.93,
41247
- precision: 0.5461,
41248
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41249
- verdict: "HYGIENE",
41250
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=2924, FP=2430, P=54.6%, FPR=1.32%, lift=0.9. aiSpecific=False.",
41251
- aiSpecific: false
42702
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
42703
+ aiSpecific: true,
42704
+ _v7Verdict: "DORMANT",
42705
+ _v7Lift: 0,
42706
+ _v7Recall: 0,
42707
+ _v7FpRate: 0,
42708
+ _v7Precision: 0,
42709
+ _v8Verdict: "DORMANT",
42710
+ _v8Lift: 1,
42711
+ defaultOff: true
41252
42712
  },
41253
- "logic/ks-distribution-shift": {
41254
- recall: 0.6375,
41255
- fpRate: 0.338,
41256
- ratio: 1.89,
41257
- precision: 0.7096,
41258
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41259
- verdict: "HYGIENE",
41260
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=152391, FP=62358, P=71.0%, FPR=33.80%, lift=1.9. aiSpecific=False.",
41261
- aiSpecific: false
42713
+ "logic/reactive-hook-soup": {
42714
+ recall: 41e-4,
42715
+ fpRate: 6e-4,
42716
+ ratio: 1370.15,
42717
+ precision: 0.8805,
42718
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42719
+ verdict: "USEFUL",
42720
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=1194, FP=162, P=88.1%, FPR=0.06%, lift=1370.15. v7 was USEFUL (TP=901, FP=162, lift=959.64). v8 was USEFUL (TP=293, FP=0).",
42721
+ aiSpecific: true,
42722
+ _v7Verdict: "USEFUL",
42723
+ _v7Lift: 959.64,
42724
+ _v7Recall: 38e-4,
42725
+ _v7FpRate: 9e-4,
42726
+ _v7Precision: 0.8476,
42727
+ _v8Verdict: "USEFUL",
42728
+ _v8Lift: 99999
41262
42729
  },
41263
42730
  "logic/zipf-slope-anomaly": {
41264
- recall: 0.0156,
41265
- fpRate: 87e-4,
41266
- ratio: 1.79,
41267
- precision: 0.6983,
41268
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41269
- verdict: "HYGIENE",
41270
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. HYGIENE \u2014 TP=3718, FP=1606, P=69.8%, FPR=0.87%, lift=1.8. aiSpecific=False.",
41271
- aiSpecific: false
42731
+ recall: 0.0168,
42732
+ fpRate: 0.0111,
42733
+ ratio: 57.13,
42734
+ precision: 0.6369,
42735
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42736
+ verdict: "USEFUL",
42737
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=4928, FP=2810, P=63.7%, FPR=1.11%, lift=57.13. v7 was USEFUL (TP=3718, FP=1606, lift=79.75). v8 was USEFUL (TP=1210, FP=1204).",
42738
+ aiSpecific: false,
42739
+ _v7Verdict: "USEFUL",
42740
+ _v7Lift: 79.75,
42741
+ _v7Recall: 0.0157,
42742
+ _v7FpRate: 88e-4,
42743
+ _v7Precision: 0.6983,
42744
+ _v8Verdict: "USEFUL",
42745
+ _v8Lift: 28.59
41272
42746
  },
41273
- "ai/markdown-leakage": {
41274
- recall: 0,
42747
+ "logic/zombie-state": {
42748
+ recall: 1e-4,
41275
42749
  fpRate: 0,
41276
- ratio: 1.93,
41277
- precision: 0.7143,
41278
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41279
- verdict: "OK",
41280
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. OK \u2014 TP=5, FP=2, P=71.4%, FPR=0.00%, lift=1.9. aiSpecific=True.",
41281
- aiSpecific: true
42750
+ ratio: 119891.71,
42751
+ precision: 0.9512,
42752
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42753
+ verdict: "USEFUL",
42754
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=39, FP=2, P=95.1%, FPR=0.00%, lift=119891.71. v7 was USEFUL (TP=24, FP=2, lift=84652.15). v8 was USEFUL (TP=15, FP=0).",
42755
+ aiSpecific: true,
42756
+ _v7Verdict: "USEFUL",
42757
+ _v7Lift: 84652.15,
42758
+ _v7Recall: 1e-4,
42759
+ _v7FpRate: 0,
42760
+ _v7Precision: 0.9231,
42761
+ _v8Verdict: "USEFUL",
42762
+ _v8Lift: 99999
41282
42763
  },
41283
- "ai/comment-ratio": {
41284
- recall: 0.2523,
41285
- fpRate: 0.1619,
41286
- ratio: 1.56,
41287
- precision: 0.6687,
41288
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41289
- verdict: "OK",
41290
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. OK \u2014 TP=60308, FP=29876, P=66.9%, FPR=16.19%, lift=1.6. aiSpecific=True.",
41291
- aiSpecific: true
42764
+ "perf/cls-image": {
42765
+ recall: 2e-4,
42766
+ fpRate: 2e-4,
42767
+ ratio: 2895.78,
42768
+ precision: 0.5514,
42769
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42770
+ verdict: "USEFUL",
42771
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=59, FP=48, P=55.1%, FPR=0.02%, lift=2895.78. v7 was USEFUL (TP=49, FP=47, lift=1991.85). v8 was USEFUL (TP=10, FP=1).",
42772
+ aiSpecific: false,
42773
+ _v7Verdict: "USEFUL",
42774
+ _v7Lift: 1991.85,
42775
+ _v7Recall: 2e-4,
42776
+ _v7FpRate: 3e-4,
42777
+ _v7Precision: 0.5104,
42778
+ _v8Verdict: "USEFUL",
42779
+ _v8Lift: 62424.55
41292
42780
  },
41293
- "ai/whitespace-regularity": {
41294
- recall: 0.0731,
41295
- fpRate: 0.0728,
41296
- ratio: 1,
41297
- precision: 0.5652,
41298
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41299
- verdict: "NOISY",
41300
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. NOISY \u2014 TP=17466, FP=13438, P=56.5%, FPR=7.28%, lift=1.0. aiSpecific=True.",
41301
- defaultOff: true,
41302
- aiSpecific: true
42781
+ "perf/css-bloat": {
42782
+ recall: 0.0126,
42783
+ fpRate: 24e-4,
42784
+ ratio: 365.63,
42785
+ precision: 0.8616,
42786
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42787
+ verdict: "USEFUL",
42788
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=3697, FP=594, P=86.2%, FPR=0.24%, lift=365.63. v7 was USEFUL (TP=2790, FP=591, lift=256.10). v8 was USEFUL (TP=907, FP=3).",
42789
+ aiSpecific: false,
42790
+ _v7Verdict: "USEFUL",
42791
+ _v7Lift: 256.1,
42792
+ _v7Recall: 0.0118,
42793
+ _v7FpRate: 32e-4,
42794
+ _v7Precision: 0.8252,
42795
+ _v8Verdict: "USEFUL",
42796
+ _v8Lift: 22813.54
41303
42797
  },
41304
- "ai/text-like-ratio": {
42798
+ "perf/halstead-anomaly": {
41305
42799
  recall: 0,
41306
42800
  fpRate: 0,
41307
- ratio: 2.32,
41308
- precision: 0.75,
41309
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42801
+ ratio: 75624,
42802
+ precision: 0.6,
42803
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41310
42804
  verdict: "USEFUL",
41311
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=3, FP=1, P=75.0%, FPR=0.00%, lift=2.3. aiSpecific=True.",
41312
- aiSpecific: true
42805
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=3, FP=2, P=60.0%, FPR=0.00%, lift=75624.00. v7 was USEFUL (TP=3, FP=1, lift=137559.75). v8 was INVERTED (TP=0, FP=1).",
42806
+ aiSpecific: true,
42807
+ _v7Verdict: "USEFUL",
42808
+ _v7Lift: 137559.75,
42809
+ _v7Recall: 0,
42810
+ _v7FpRate: 0,
42811
+ _v7Precision: 0.75,
42812
+ _v8Verdict: "INVERTED",
42813
+ _v8Lift: 0
41313
42814
  },
41314
- "ai/errors-near-eof": {
41315
- recall: 0.0697,
41316
- fpRate: 0.0548,
41317
- ratio: 1.27,
41318
- precision: 0.6225,
41319
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41320
- verdict: "NOISY",
41321
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. NOISY \u2014 TP=16673, FP=10112, P=62.2%, FPR=5.48%, lift=1.3. aiSpecific=True.",
41322
- defaultOff: true,
41323
- aiSpecific: true
42815
+ "product/terminology-drift": {
42816
+ recall: 91e-4,
42817
+ fpRate: 21e-4,
42818
+ ratio: 397.75,
42819
+ precision: 0.8347,
42820
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42821
+ verdict: "USEFUL",
42822
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=2671, FP=529, P=83.5%, FPR=0.21%, lift=397.75. v7 was USEFUL (TP=2028, FP=521, lift=280.09). v8 was USEFUL (TP=643, FP=8).",
42823
+ aiSpecific: false,
42824
+ _v7Verdict: "USEFUL",
42825
+ _v7Lift: 280.09,
42826
+ _v7Recall: 86e-4,
42827
+ _v7FpRate: 28e-4,
42828
+ _v7Precision: 0.7956,
42829
+ _v8Verdict: "USEFUL",
42830
+ _v8Lift: 8477.9
41324
42831
  },
41325
- "ai/any-density": {
41326
- recall: 55e-4,
41327
- fpRate: 41e-4,
41328
- ratio: 1.34,
41329
- precision: 0.634,
41330
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41331
- verdict: "NOISY",
41332
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. NOISY \u2014 TP=1313, FP=758, P=63.4%, FPR=0.41%, lift=1.3. aiSpecific=True.",
41333
- defaultOff: true,
41334
- aiSpecific: true
42832
+ "product/ux-pattern-fragmentation": {
42833
+ recall: 1e-4,
42834
+ fpRate: 0,
42835
+ ratio: 22864.4,
42836
+ precision: 0.8163,
42837
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42838
+ verdict: "USEFUL",
42839
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=40, FP=9, P=81.6%, FPR=0.00%, lift=22864.40. v7 was USEFUL (TP=32, FP=8, lift=18341.30). v8 was USEFUL (TP=8, FP=1).",
42840
+ aiSpecific: true,
42841
+ _v7Verdict: "USEFUL",
42842
+ _v7Lift: 18341.3,
42843
+ _v7Recall: 1e-4,
42844
+ _v7FpRate: 0,
42845
+ _v7Precision: 0.8,
42846
+ _v8Verdict: "USEFUL",
42847
+ _v8Lift: 61037.33
41335
42848
  },
41336
- "ai/renyi-profile": {
41337
- recall: 0,
42849
+ "rust/stringly-typed": {
42850
+ recall: 2e-4,
41338
42851
  fpRate: 0,
41339
- ratio: 0.26,
41340
- precision: 0.25,
41341
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41342
- verdict: "INVERTED",
41343
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. INVERTED \u2014 TP=3, FP=9, P=25.0%, FPR=0.00%, lift=0.3. aiSpecific=True.",
41344
- defaultOff: true,
41345
- aiSpecific: true
42852
+ ratio: 24735.12,
42853
+ precision: 0.8831,
42854
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42855
+ verdict: "USEFUL",
42856
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=68, FP=9, P=88.3%, FPR=0.00%, lift=24735.12. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=68, FP=9).",
42857
+ aiSpecific: true,
42858
+ _v7Verdict: "DORMANT",
42859
+ _v7Lift: 1,
42860
+ _v7Recall: 0,
42861
+ _v7FpRate: 0,
42862
+ _v7Precision: 0,
42863
+ _v8Verdict: "USEFUL",
42864
+ _v8Lift: 6737.89
41346
42865
  },
41347
- "ai/log-rank-histogram": {
42866
+ "rust/todo-macro": {
42867
+ recall: 1e-4,
42868
+ fpRate: 7e-4,
42869
+ ratio: 210.08,
42870
+ precision: 0.1392,
42871
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42872
+ verdict: "OK",
42873
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=27, FP=167, P=13.9%, FPR=0.07%, lift=210.08. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was OK (TP=27, FP=167).",
42874
+ aiSpecific: true,
42875
+ _v7Verdict: "DORMANT",
42876
+ _v7Lift: 1,
42877
+ _v7Recall: 0,
42878
+ _v7FpRate: 0,
42879
+ _v7Precision: 0,
42880
+ _v8Verdict: "OK",
42881
+ _v8Lift: 57.23
42882
+ },
42883
+ "rust/unused-pub-fn": {
41348
42884
  recall: 0,
41349
42885
  fpRate: 0,
41350
- ratio: 0,
41351
- precision: 0,
41352
- lastCalibratedAt: "2026-06-27T00:00:00Z",
42886
+ ratio: 10803.43,
42887
+ precision: 0.3,
42888
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41353
42889
  verdict: "OK",
41354
- _calibrationNote: "v0.13.0 stub: rule implemented per Gehrmann 2019 GLTR; calibration on v7 corpus pending. v0.13.0: marked OK (peer-reviewed math backing; lift=0 because v7 calibration has not been run yet \u2014 will be re-evaluated).",
41355
- aiSpecific: true
42890
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=3, FP=7, P=30.0%, FPR=0.00%, lift=10803.43. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was OK (TP=3, FP=7).",
42891
+ aiSpecific: true,
42892
+ _v7Verdict: "DORMANT",
42893
+ _v7Lift: 1,
42894
+ _v7Recall: 0,
42895
+ _v7FpRate: 0,
42896
+ _v7Precision: 0,
42897
+ _v8Verdict: "OK",
42898
+ _v8Lift: 2942.87
41356
42899
  },
41357
- "ai/segment-surprisal-cv": {
41358
- recall: 0.182,
41359
- fpRate: 0.0812,
41360
- ratio: 2.24,
41361
- precision: 0.7438,
41362
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42900
+ "rust/unwrap-in-production": {
42901
+ recall: 8e-3,
42902
+ fpRate: 77e-4,
42903
+ ratio: 70.81,
42904
+ precision: 0.5475,
42905
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41363
42906
  verdict: "USEFUL",
41364
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=43498, FP=14983, P=74.4%, FPR=8.12%, lift=2.2. aiSpecific=True.",
41365
- aiSpecific: true
42907
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=2358, FP=1949, P=54.7%, FPR=0.77%, lift=70.81. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=2358, FP=1949).",
42908
+ aiSpecific: true,
42909
+ _v7Verdict: "DORMANT",
42910
+ _v7Lift: 1,
42911
+ _v7Recall: 0,
42912
+ _v7FpRate: 0,
42913
+ _v7Precision: 0,
42914
+ _v8Verdict: "USEFUL",
42915
+ _v8Lift: 19.29
41366
42916
  },
41367
- "ai/compression-profile": {
41368
- recall: 0.3139,
41369
- fpRate: 0.1489,
41370
- ratio: 2.11,
41371
- precision: 0.732,
41372
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42917
+ "security/dangerous-cors": {
42918
+ recall: 5e-4,
42919
+ fpRate: 4e-4,
42920
+ ratio: 1721.87,
42921
+ precision: 0.6079,
42922
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41373
42923
  verdict: "USEFUL",
41374
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=75031, FP=27473, P=73.2%, FPR=14.89%, lift=2.1. aiSpecific=True.",
41375
- aiSpecific: true
42924
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=138, FP=89, P=60.8%, FPR=0.04%, lift=1721.87. v7 was USEFUL (TP=114, FP=84, lift=1257.16). v8 was USEFUL (TP=24, FP=5).",
42925
+ aiSpecific: true,
42926
+ _v7Verdict: "USEFUL",
42927
+ _v7Lift: 1257.16,
42928
+ _v7Recall: 5e-4,
42929
+ _v7FpRate: 5e-4,
42930
+ _v7Precision: 0.5758,
42931
+ _v8Verdict: "USEFUL",
42932
+ _v8Lift: 11365.57
41376
42933
  },
41377
- "ai/tailwind-color-overuse": {
41378
- recall: 0.0216,
41379
- fpRate: 52e-4,
41380
- ratio: 4.16,
41381
- precision: 0.8436,
41382
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42934
+ "security/eval": {
42935
+ recall: 1e-4,
42936
+ fpRate: 2e-4,
42937
+ ratio: 1929.18,
42938
+ precision: 0.4286,
42939
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42940
+ verdict: "OK",
42941
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=42, FP=56, P=42.9%, FPR=0.02%, lift=1929.18. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was OK (TP=42, FP=56).",
42942
+ aiSpecific: false,
42943
+ _v7Verdict: "DORMANT",
42944
+ _v7Lift: 1,
42945
+ _v7Recall: 0,
42946
+ _v7FpRate: 0,
42947
+ _v7Precision: 0,
42948
+ _v8Verdict: "OK",
42949
+ _v8Lift: 525.51
42950
+ },
42951
+ "security/exposed-env-var": {
42952
+ recall: 6e-4,
42953
+ fpRate: 5e-4,
42954
+ ratio: 1055.81,
42955
+ precision: 0.5696,
42956
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41383
42957
  verdict: "USEFUL",
41384
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=5169, FP=958, P=84.4%, FPR=0.52%, lift=4.2. aiSpecific=True.",
41385
- aiSpecific: true
42958
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=180, FP=136, P=57.0%, FPR=0.05%, lift=1055.81. v7 was USEFUL (TP=146, FP=125, lift=790.50). v8 was USEFUL (TP=34, FP=11).",
42959
+ aiSpecific: false,
42960
+ _v7Verdict: "USEFUL",
42961
+ _v7Lift: 790.5,
42962
+ _v7Recall: 6e-4,
42963
+ _v7FpRate: 7e-4,
42964
+ _v7Precision: 0.5387,
42965
+ _v8Verdict: "USEFUL",
42966
+ _v8Lift: 4716.52
41386
42967
  },
41387
- "ai/default-react-stack": {
41388
- recall: 1e-3,
42968
+ "security/fail-open-auth": {
42969
+ recall: 0,
41389
42970
  fpRate: 0,
41390
- ratio: 99.99,
41391
- precision: 0.9957,
41392
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42971
+ ratio: 99999,
42972
+ precision: 1,
42973
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41393
42974
  verdict: "USEFUL",
41394
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=231, FP=1, P=99.6%, FPR=0.00%, lift=178.3. aiSpecific=True.",
41395
- aiSpecific: true
42975
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=1, FP=0, P=100.0%, FPR=0.00%, lift=inf. v7 was USEFUL (TP=1, FP=0, lift=inf). v8 was DORMANT (TP=0, FP=0). v0.19 default-on (explicit defaultOff: false): P 100% / inf lift \u2014 security must always be on.",
42976
+ aiSpecific: true,
42977
+ _v7Verdict: "USEFUL",
42978
+ _v7Lift: 99999,
42979
+ _v7Recall: 0,
42980
+ _v7FpRate: 0,
42981
+ _v7Precision: 1,
42982
+ _v8Verdict: "DORMANT",
42983
+ _v8Lift: 1,
42984
+ defaultOff: false
41396
42985
  },
41397
- "ai/library-reinvention": {
41398
- recall: 3e-4,
42986
+ "security/hardcoded-secret": {
42987
+ recall: 14e-4,
42988
+ fpRate: 6e-4,
42989
+ ratio: 1269.08,
42990
+ precision: 0.735,
42991
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42992
+ verdict: "USEFUL",
42993
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=405, FP=146, P=73.5%, FPR=0.06%, lift=1269.08. v7 was USEFUL (TP=307, FP=138, lift=916.92). v8 was USEFUL (TP=98, FP=8).",
42994
+ aiSpecific: true,
42995
+ _v7Verdict: "USEFUL",
42996
+ _v7Lift: 916.92,
42997
+ _v7Recall: 13e-4,
42998
+ _v7FpRate: 8e-4,
42999
+ _v7Precision: 0.6899,
43000
+ _v8Verdict: "USEFUL",
43001
+ _v8Lift: 7935.57
43002
+ },
43003
+ "security/localstorage-token": {
43004
+ recall: 1e-4,
41399
43005
  fpRate: 0,
41400
- ratio: 9.88,
41401
- precision: 0.9275,
41402
- lastCalibratedAt: "2026-06-27T12:00:00Z",
43006
+ ratio: 99999,
43007
+ precision: 1,
43008
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41403
43009
  verdict: "USEFUL",
41404
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=64, FP=5, P=92.8%, FPR=0.00%, lift=9.9. aiSpecific=True.",
41405
- aiSpecific: true
43010
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=17, FP=0, P=100.0%, FPR=0.00%, lift=inf. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=17, FP=0).",
43011
+ aiSpecific: false,
43012
+ _v7Verdict: "DORMANT",
43013
+ _v7Lift: 1,
43014
+ _v7Recall: 0,
43015
+ _v7FpRate: 0,
43016
+ _v7Precision: 0,
43017
+ _v8Verdict: "USEFUL",
43018
+ _v8Lift: 99999
41406
43019
  },
41407
- "ai/state-default-overuse": {
41408
- recall: 29e-4,
41409
- fpRate: 9e-4,
41410
- ratio: 3.42,
41411
- precision: 0.8161,
41412
- lastCalibratedAt: "2026-06-27T12:00:00Z",
43020
+ "security/missing-auth-check": {
43021
+ recall: 5e-4,
43022
+ fpRate: 0,
43023
+ ratio: 99999,
43024
+ precision: 1,
43025
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41413
43026
  verdict: "USEFUL",
41414
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=701, FP=158, P=81.6%, FPR=0.09%, lift=3.4. aiSpecific=True.",
41415
- aiSpecific: true
43027
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=157, FP=0, P=100.0%, FPR=0.00%, lift=inf. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=157, FP=0).",
43028
+ aiSpecific: false,
43029
+ _v7Verdict: "DORMANT",
43030
+ _v7Lift: 1,
43031
+ _v7Recall: 0,
43032
+ _v7FpRate: 0,
43033
+ _v7Precision: 0,
43034
+ _v8Verdict: "USEFUL",
43035
+ _v8Lift: 99999
41416
43036
  },
41417
- "ai/fetch-default-overuse": {
41418
- recall: 28e-4,
41419
- fpRate: 4e-4,
41420
- ratio: 6.76,
41421
- precision: 0.8976,
41422
- lastCalibratedAt: "2026-06-27T12:00:00Z",
43037
+ "security/public-admin-route": {
43038
+ recall: 38e-4,
43039
+ fpRate: 38e-4,
43040
+ ratio: 142.2,
43041
+ precision: 0.5376,
43042
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41423
43043
  verdict: "USEFUL",
41424
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=666, FP=76, P=89.8%, FPR=0.04%, lift=6.8. aiSpecific=True.",
41425
- aiSpecific: true
43044
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=1108, FP=953, P=53.8%, FPR=0.38%, lift=142.20. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=1108, FP=953).",
43045
+ aiSpecific: false,
43046
+ _v7Verdict: "DORMANT",
43047
+ _v7Lift: 1,
43048
+ _v7Recall: 0,
43049
+ _v7FpRate: 0,
43050
+ _v7Precision: 0,
43051
+ _v8Verdict: "USEFUL",
43052
+ _v8Lift: 38.74
41426
43053
  },
41427
- "ai/console-debug-storm": {
41428
- recall: 8e-3,
41429
- fpRate: 9e-4,
41430
- ratio: 8.43,
41431
- precision: 0.9161,
41432
- lastCalibratedAt: "2026-06-27T12:00:00Z",
43054
+ "security/sql-construction": {
43055
+ recall: 32e-4,
43056
+ fpRate: 15e-4,
43057
+ ratio: 485.42,
43058
+ precision: 0.7183,
43059
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41433
43060
  verdict: "USEFUL",
41434
- _calibrationNote: "v7 corpus re-calibration (2026-06-27, min-date=2025-01-01): 184488 neg + 239054 pos. USEFUL \u2014 TP=1912, FP=175, P=91.6%, FPR=0.09%, lift=8.4. aiSpecific=True.",
41435
- aiSpecific: true
43061
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=951, FP=373, P=71.8%, FPR=0.15%, lift=485.42. v7 was USEFUL (TP=710, FP=336, lift=370.52). v8 was USEFUL (TP=241, FP=37).",
43062
+ aiSpecific: true,
43063
+ _v7Verdict: "USEFUL",
43064
+ _v7Lift: 370.52,
43065
+ _v7Recall: 3e-3,
43066
+ _v7FpRate: 18e-4,
43067
+ _v7Precision: 0.6788,
43068
+ _v8Verdict: "USEFUL",
43069
+ _v8Lift: 1608.86
41436
43070
  },
41437
- "db/missing-fk-index": {
41438
- recall: 0,
43071
+ "security/target-blank-no-noopener": {
43072
+ recall: 4e-4,
41439
43073
  fpRate: 0,
41440
- ratio: 0,
41441
- precision: 0,
41442
- lastCalibratedAt: "2026-06-30T00:00:00Z",
41443
- verdict: "DORMANT",
41444
- defaultOff: true,
41445
- _calibrationNote: "v0.17.0 ship \u2014 not in v7 per-rule table. Default-off until calibration data lands. Backed by: PostgreSQL Global Development Group (2024), *PostgreSQL 16 Documentation \xA75.4 (Constraints)*, https://www.postgresql.org/docs/16/ddl-constraints.html; Squawk (2023), *Postgres linter rules*, https://github.com/sqllabs/squawk, rule `require-index-for-fk`. (Foreign key columns need a matching index \u2014 sequential scan on parent delete is a canonical Postgres anti-pattern.)",
41446
- aiSpecific: false
43074
+ ratio: 26141.63,
43075
+ precision: 0.9333,
43076
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43077
+ verdict: "USEFUL",
43078
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=126, FP=9, P=93.3%, FPR=0.00%, lift=26141.63. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=126, FP=9).",
43079
+ aiSpecific: false,
43080
+ _v7Verdict: "DORMANT",
43081
+ _v7Lift: 1,
43082
+ _v7Recall: 0,
43083
+ _v7FpRate: 0,
43084
+ _v7Precision: 0,
43085
+ _v8Verdict: "USEFUL",
43086
+ _v8Lift: 7121.02
41447
43087
  },
41448
- "db/duplicate-index": {
41449
- recall: 0,
43088
+ "security/unsafe-html-render": {
43089
+ recall: 13e-4,
43090
+ fpRate: 11e-4,
43091
+ ratio: 513.12,
43092
+ precision: 0.574,
43093
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43094
+ verdict: "USEFUL",
43095
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=380, FP=282, P=57.4%, FPR=0.11%, lift=513.12. v7 was USEFUL (TP=312, FP=160, lift=757.74). v8 was OK (TP=68, FP=122).",
43096
+ aiSpecific: false,
43097
+ _v7Verdict: "USEFUL",
43098
+ _v7Lift: 757.74,
43099
+ _v7Recall: 13e-4,
43100
+ _v7FpRate: 9e-4,
43101
+ _v7Precision: 0.661,
43102
+ _v8Verdict: "OK",
43103
+ _v8Lift: 201.44
43104
+ },
43105
+ "test/duplicate-setup": {
43106
+ recall: 1e-4,
41450
43107
  fpRate: 0,
41451
- ratio: 0,
41452
- precision: 0,
41453
- lastCalibratedAt: "2026-06-30T00:00:00Z",
41454
- verdict: "DORMANT",
41455
- defaultOff: true,
41456
- _calibrationNote: "v0.17.0 ship \u2014 not in v7 per-rule table. Default-off until calibration data lands. Backed by: PostgreSQL Global Development Group (2024), *PostgreSQL 16 Documentation \xA711.2 (Index Types)*; Heroku Postgres Team (2018), *Efficient Use of PostgreSQL Indexes*. (Duplicate indexes silently double write cost without read benefit \u2014 Postgres does not warn.)",
41457
- aiSpecific: false
43108
+ ratio: 51016.19,
43109
+ precision: 0.8095,
43110
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43111
+ verdict: "USEFUL",
43112
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=17, FP=4, P=81.0%, FPR=0.00%, lift=51016.19. v7 was USEFUL (TP=14, FP=3, lift=50348.67). v8 was USEFUL (TP=3, FP=1).",
43113
+ aiSpecific: true,
43114
+ _v7Verdict: "USEFUL",
43115
+ _v7Lift: 50348.67,
43116
+ _v7Recall: 1e-4,
43117
+ _v7FpRate: 0,
43118
+ _v7Precision: 0.8235,
43119
+ _v8Verdict: "USEFUL",
43120
+ _v8Lift: 51500.25
41458
43121
  },
41459
- "db/missing-not-null": {
43122
+ "test/fake-placeholder": {
43123
+ recall: 51e-4,
43124
+ fpRate: 15e-4,
43125
+ ratio: 547.47,
43126
+ precision: 0.8014,
43127
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43128
+ verdict: "USEFUL",
43129
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=1489, FP=369, P=80.1%, FPR=0.15%, lift=547.47. v7 was USEFUL (TP=1259, FP=344, lift=418.76). v8 was USEFUL (TP=230, FP=25).",
43130
+ aiSpecific: true,
43131
+ _v7Verdict: "USEFUL",
43132
+ _v7Lift: 418.76,
43133
+ _v7Recall: 53e-4,
43134
+ _v7FpRate: 19e-4,
43135
+ _v7Precision: 0.7854,
43136
+ _v8Verdict: "USEFUL",
43137
+ _v8Lift: 2477.4
43138
+ },
43139
+ "test/missing-edge-case": {
41460
43140
  recall: 0,
41461
43141
  fpRate: 0,
41462
43142
  ratio: 0,
41463
43143
  precision: 0,
41464
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43144
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41465
43145
  verdict: "DORMANT",
41466
- defaultOff: true,
41467
- _calibrationNote: "v0.17.0 ship \u2014 not in v7 per-rule table. Default-off until calibration data lands. Backed by: PostgreSQL Global Development Group (2024), *PostgreSQL 16 Documentation \xA75.4.1 (Check Constraints)*; Kleppmann, M. (2017), *Designing Data-Intensive Applications*, O'Reilly, ch.4 (NULL semantics in RDBMS). (Required-identifier columns without NOT NULL produce silent NULL inserts \u2014 canonical AI SQL smell.)",
41468
- aiSpecific: false
43146
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
43147
+ aiSpecific: true,
43148
+ _v7Verdict: "DORMANT",
43149
+ _v7Lift: 0,
43150
+ _v7Recall: 0,
43151
+ _v7FpRate: 0,
43152
+ _v7Precision: 0,
43153
+ _v8Verdict: "DORMANT",
43154
+ _v8Lift: 1,
43155
+ defaultOff: true
41469
43156
  },
41470
- "db/enum-sprawl": {
43157
+ "test/weak-assertion": {
43158
+ recall: 0.0417,
43159
+ fpRate: 67e-4,
43160
+ ratio: 131.62,
43161
+ precision: 0.8793,
43162
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43163
+ verdict: "USEFUL",
43164
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=12263, FP=1684, P=87.9%, FPR=0.67%, lift=131.62. v7 was USEFUL (TP=9906, FP=1583, lift=99.90). v8 was USEFUL (TP=2357, FP=101).",
43165
+ aiSpecific: true,
43166
+ _v7Verdict: "USEFUL",
43167
+ _v7Lift: 99.9,
43168
+ _v7Recall: 0.0418,
43169
+ _v7FpRate: 86e-4,
43170
+ _v7Precision: 0.8622,
43171
+ _v8Verdict: "USEFUL",
43172
+ _v8Lift: 651.94
43173
+ },
43174
+ "ts/enum-vs-as-const": {
41471
43175
  recall: 0,
41472
43176
  fpRate: 0,
41473
- ratio: 0,
43177
+ ratio: 1,
41474
43178
  precision: 0,
41475
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43179
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41476
43180
  verdict: "DORMANT",
41477
- defaultOff: true,
41478
- _calibrationNote: "v0.17.0 ship \u2014 not in v7 per-rule table. Default-off until calibration data lands. Backed by: PostgreSQL Global Development Group (2024), *PostgreSQL 16 Documentation \xA78.7 (Enumerated Types)*; Borkowski, A. (2022), *PostgreSQL enum types: when to use them and when not to*, pgconfig.org. (Enums with >12 values are brittle to extend and hard to localize \u2014 lookup table is the standard replacement.)",
41479
- aiSpecific: false
43181
+ _calibrationNote: "v0.19: new rule (Uses `enum` \u2014 modern TS prefers `as const`). Not yet calibrated. Scheduled for v9 calibration.",
43182
+ aiSpecific: true,
43183
+ _v7Verdict: "DORMANT",
43184
+ _v7Lift: 1,
43185
+ _v7Recall: 0,
43186
+ _v7FpRate: 0,
43187
+ _v7Precision: 0,
43188
+ _v8Verdict: "DORMANT",
43189
+ _v8Lift: 1,
43190
+ defaultOff: true
41480
43191
  },
41481
- "db/naming-inconsistency": {
43192
+ "ts/excessive-type-assertion": {
41482
43193
  recall: 0,
41483
43194
  fpRate: 0,
41484
- ratio: 0,
43195
+ ratio: 1,
41485
43196
  precision: 0,
41486
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43197
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41487
43198
  verdict: "DORMANT",
41488
- defaultOff: true,
41489
- _calibrationNote: "v0.17.0 ship \u2014 not in v7 per-rule table. Default-off until calibration data lands. Backed by: PostgreSQL Global Development Group (2024), *PostgreSQL 16 Documentation \xA74.1.1 (Identifiers and Key Words)*; pgsql-hackers (2018), *Re: snake_case vs camelCase in Postgres identifiers*. (snake_case is the Postgres convention; mixing styles in the same schema breaks ORM generators.)",
41490
- aiSpecific: false
43199
+ _calibrationNote: "v0.19: new rule (Function with >3 `as` assertions \u2014 AI fighting the type system). Not yet calibrated. Scheduled for v9 calibration.",
43200
+ aiSpecific: true,
43201
+ _v7Verdict: "DORMANT",
43202
+ _v7Lift: 1,
43203
+ _v7Recall: 0,
43204
+ _v7FpRate: 0,
43205
+ _v7Precision: 0,
43206
+ _v8Verdict: "DORMANT",
43207
+ _v8Lift: 1,
43208
+ defaultOff: true
41491
43209
  },
41492
- "db/sql-concat": {
43210
+ "ts/import-type-misuse": {
41493
43211
  recall: 0,
41494
43212
  fpRate: 0,
41495
- ratio: 0,
43213
+ ratio: 1,
41496
43214
  precision: 0,
41497
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43215
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41498
43216
  verdict: "DORMANT",
41499
- defaultOff: true,
41500
- _calibrationNote: "v0.17.0 ship \u2014 not in v7 per-rule table. Default-off until calibration data lands. Backed by: OWASP Foundation (2021), *OWASP Top 10 \u2014 A03:2021 Injection*, https://owasp.org/Top10/A03_2021-Injection/; OWASP Foundation (2017), *SQL Injection Prevention Cheat Sheet*. (Template-literal SQL with ${...} interpolation is the #1 SQL injection vector in AI-generated TypeScript code.)",
41501
- aiSpecific: true
43217
+ _calibrationNote: "v0.19: new rule (Inline `import { type X }` \u2014 prefer separate `import type`). Not yet calibrated. Scheduled for v9 calibration.",
43218
+ aiSpecific: true,
43219
+ _v7Verdict: "DORMANT",
43220
+ _v7Lift: 1,
43221
+ _v7Recall: 0,
43222
+ _v7FpRate: 0,
43223
+ _v7Precision: 0,
43224
+ _v8Verdict: "DORMANT",
43225
+ _v8Lift: 1,
43226
+ defaultOff: true
41502
43227
  },
41503
- "dead/unused-import": {
43228
+ "ts/never-vs-unknown": {
41504
43229
  recall: 0,
41505
43230
  fpRate: 0,
41506
- ratio: 0,
43231
+ ratio: 1,
41507
43232
  precision: 0,
41508
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43233
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41509
43234
  verdict: "DORMANT",
41510
- defaultOff: true,
41511
- _calibrationNote: "v0.18.5 ship \u2014 not in v7 per-rule table. Default-off until v8 calibration data lands. The first of 5 planned `dead/*` rules (this one + dead/unused-local + dead/unused-parameter + dead/dead-branch + dead/unreachable). The pattern is the canonical AI-iteration rot: the model adds an import when introducing a feature, then rewrites the function later without cleaning up. Most real-world tsconfig.json files have `noUnusedLocals: false`, so tsc never fires.",
41512
- aiSpecific: true
43235
+ _calibrationNote: "v0.19: new rule (Return type `never` but body has no throw/loop/exit). Not yet calibrated. Scheduled for v9 calibration.",
43236
+ aiSpecific: true,
43237
+ _v7Verdict: "DORMANT",
43238
+ _v7Lift: 1,
43239
+ _v7Recall: 0,
43240
+ _v7FpRate: 0,
43241
+ _v7Precision: 0,
43242
+ _v8Verdict: "DORMANT",
43243
+ _v8Lift: 1,
43244
+ defaultOff: true
41513
43245
  },
41514
- "dead/unused-local": {
43246
+ "ts/optional-chain-overuse": {
41515
43247
  recall: 0,
41516
43248
  fpRate: 0,
41517
- ratio: 0,
43249
+ ratio: 1,
41518
43250
  precision: 0,
41519
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43251
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41520
43252
  verdict: "DORMANT",
41521
- defaultOff: true,
41522
- _calibrationNote: "v0.18.5b ship \u2014 not in v7 per-rule table. Default-off until v8 calibration data lands. The second of 5 planned `dead/*` rules. Muchnick 1997 Ch. 13 'liveness analysis' (textbook compiler optimization).",
41523
- aiSpecific: true
43253
+ _calibrationNote: "v0.19: new rule (Optional chain depth >= 5 \u2014 AI chains ?. rather than narrowing). Not yet calibrated. Scheduled for v9 calibration.",
43254
+ aiSpecific: true,
43255
+ _v7Verdict: "DORMANT",
43256
+ _v7Lift: 1,
43257
+ _v7Recall: 0,
43258
+ _v7FpRate: 0,
43259
+ _v7Precision: 0,
43260
+ _v8Verdict: "DORMANT",
43261
+ _v8Lift: 1,
43262
+ defaultOff: true
41524
43263
  },
41525
- "dead/unused-parameter": {
43264
+ "typo/calc-fontsize": {
41526
43265
  recall: 0,
41527
43266
  fpRate: 0,
41528
43267
  ratio: 0,
41529
43268
  precision: 0,
41530
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43269
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41531
43270
  verdict: "DORMANT",
41532
- defaultOff: true,
41533
- _calibrationNote: "v0.18.5b ship \u2014 not in v7 per-rule table. Default-off until v8 calibration data lands. The third of 5 planned `dead/*` rules. AI agents add parameters when introducing features, then rewrite the function without removing parameters the new code does not need.",
41534
- aiSpecific: true
43271
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
43272
+ aiSpecific: false,
43273
+ _v7Verdict: "DORMANT",
43274
+ _v7Lift: 0,
43275
+ _v7Recall: 0,
43276
+ _v7FpRate: 0,
43277
+ _v7Precision: 0,
43278
+ _v8Verdict: "DORMANT",
43279
+ _v8Lift: 1,
43280
+ defaultOff: true
41535
43281
  },
41536
- "dead/dead-branch": {
43282
+ "typo/calc-raw-px": {
41537
43283
  recall: 0,
41538
43284
  fpRate: 0,
41539
- ratio: 0,
41540
- precision: 0,
41541
- lastCalibratedAt: "2026-06-30T00:00:00Z",
41542
- verdict: "DORMANT",
41543
- defaultOff: true,
41544
- _calibrationNote: "v0.18.5b ship \u2014 not in v7 per-rule table. Default-off until v8 calibration data lands. The fourth of 5 planned `dead/*` rules. AI-iteration signature: feature flag toggled to a constant, or wrapper from a previous refactor.",
41545
- aiSpecific: true
43285
+ ratio: 210066.67,
43286
+ precision: 0.8333,
43287
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43288
+ verdict: "USEFUL",
43289
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=5, FP=1, P=83.3%, FPR=0.00%, lift=210066.67. v7 was USEFUL (TP=3, FP=1, lift=137559.75). v8 was USEFUL (TP=2, FP=0).",
43290
+ aiSpecific: false,
43291
+ _v7Verdict: "USEFUL",
43292
+ _v7Lift: 137559.75,
43293
+ _v7Recall: 0,
43294
+ _v7FpRate: 0,
43295
+ _v7Precision: 0.75,
43296
+ _v8Verdict: "USEFUL",
43297
+ _v8Lift: 99999
41546
43298
  },
41547
- "dead/unreachable": {
43299
+ "typo/clamp-offscale": {
41548
43300
  recall: 0,
41549
43301
  fpRate: 0,
41550
43302
  ratio: 0,
41551
43303
  precision: 0,
41552
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43304
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41553
43305
  verdict: "DORMANT",
41554
- defaultOff: true,
41555
- _calibrationNote: "v0.18.5b ship \u2014 not in v7 per-rule table. Default-off until v8 calibration data lands. The fifth of 5 planned `dead/*` rules. AI-iteration signature: model added an early return for a new error path, then forgot the rest of the function body was still sitting below it.",
41556
- aiSpecific: true
43306
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
43307
+ aiSpecific: false,
43308
+ _v7Verdict: "DORMANT",
43309
+ _v7Lift: 0,
43310
+ _v7Recall: 0,
43311
+ _v7FpRate: 0,
43312
+ _v7Precision: 0,
43313
+ _v8Verdict: "DORMANT",
43314
+ _v8Lift: 1,
43315
+ defaultOff: true
41557
43316
  },
41558
- "docs/stale-package-reference": {
43317
+ "typo/math-button-label-uniformity": {
43318
+ recall: 1e-4,
43319
+ fpRate: 1e-4,
43320
+ ratio: 6894.19,
43321
+ precision: 0.629,
43322
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43323
+ verdict: "USEFUL",
43324
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=39, FP=23, P=62.9%, FPR=0.01%, lift=6894.19. v7 was USEFUL (TP=37, FP=21, lift=5571.66). v8 was USEFUL (TP=2, FP=2).",
43325
+ aiSpecific: false,
43326
+ _v7Verdict: "USEFUL",
43327
+ _v7Lift: 5571.66,
43328
+ _v7Recall: 2e-4,
43329
+ _v7FpRate: 1e-4,
43330
+ _v7Precision: 0.6379,
43331
+ _v8Verdict: "USEFUL",
43332
+ _v8Lift: 17166.75
43333
+ },
43334
+ "typo/math-cta-vocabulary": {
41559
43335
  recall: 0,
41560
43336
  fpRate: 0,
41561
43337
  ratio: 0,
41562
43338
  precision: 0,
41563
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43339
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41564
43340
  verdict: "DORMANT",
41565
- defaultOff: true,
41566
- _calibrationNote: "v0.17.0 ship \u2014 not in v7 per-rule table. Default-off until calibration data lands. Backed by: Meng, M. et al. (2020), *The Cost of Fixing Code Documentation: An Empirical Study on Open-Source Software*, ICSE 2020; Aghajani, E. et al. (2019), *Software documentation: a practitioners' perspective*, ICSE 2019. (Doc references to undeclared packages are copy-paste rot from previous projects \u2014 high-signal doc drift.)",
41567
- aiSpecific: false
43341
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
43342
+ aiSpecific: true,
43343
+ _v7Verdict: "DORMANT",
43344
+ _v7Lift: 0,
43345
+ _v7Recall: 0,
43346
+ _v7FpRate: 0,
43347
+ _v7Precision: 0,
43348
+ _v8Verdict: "DORMANT",
43349
+ _v8Lift: 1,
43350
+ defaultOff: true
41568
43351
  },
41569
- "docs/stale-function-reference": {
41570
- recall: 0,
43352
+ "typo/placeholder-text": {
43353
+ recall: 1e-4,
41571
43354
  fpRate: 0,
41572
- ratio: 0,
41573
- precision: 0,
41574
- lastCalibratedAt: "2026-06-30T00:00:00Z",
41575
- verdict: "DORMANT",
41576
- defaultOff: true,
41577
- _calibrationNote: "v0.17.0 ship \u2014 not in v7 per-rule table. Default-off until calibration data lands. Backed by: Meng, M. et al. (2020), *The Cost of Fixing Code Documentation*; Chen, Z. et al. (2022), *An Empirical Study on Code Documentation Adequacy*, MSR 2022. (Doc callouts to non-existent exports \u2014 readers copy-paste and hit a runtime error.)",
41578
- aiSpecific: false
43355
+ ratio: 17330.5,
43356
+ precision: 0.6875,
43357
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43358
+ verdict: "USEFUL",
43359
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=22, FP=10, P=68.8%, FPR=0.00%, lift=17330.50. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=22, FP=10).",
43360
+ aiSpecific: false,
43361
+ _v7Verdict: "DORMANT",
43362
+ _v7Lift: 1,
43363
+ _v7Recall: 0,
43364
+ _v7FpRate: 0,
43365
+ _v7Precision: 0,
43366
+ _v8Verdict: "USEFUL",
43367
+ _v8Lift: 4720.86
41579
43368
  },
41580
- "docs/expired-code-example": {
43369
+ "visual/arbitrary-escape": {
43370
+ recall: 26e-4,
43371
+ fpRate: 7e-4,
43372
+ ratio: 1219.67,
43373
+ precision: 0.8177,
43374
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43375
+ verdict: "USEFUL",
43376
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=758, FP=169, P=81.8%, FPR=0.07%, lift=1219.67. v7 was USEFUL (TP=600, FP=169, lift=846.78). v8 was USEFUL (TP=158, FP=0).",
43377
+ aiSpecific: true,
43378
+ _v7Verdict: "USEFUL",
43379
+ _v7Lift: 846.78,
43380
+ _v7Recall: 25e-4,
43381
+ _v7FpRate: 9e-4,
43382
+ _v7Precision: 0.7802,
43383
+ _v8Verdict: "USEFUL",
43384
+ _v8Lift: 99999
43385
+ },
43386
+ "visual/clamp-soup": {
41581
43387
  recall: 0,
41582
43388
  fpRate: 0,
41583
43389
  ratio: 0,
41584
43390
  precision: 0,
41585
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43391
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41586
43392
  verdict: "DORMANT",
41587
- defaultOff: true,
41588
- _calibrationNote: "v0.17.0 ship \u2014 not in v7 per-rule table. Default-off until calibration data lands. Backed by: Parnas, D.L. (2010), *Precise Documentation: The Key to Better Software*, Springer (canonical doc-correctness argument); Chen, Z. et al. (2022). (Fenced code examples with broken imports erode trust in the entire docs site.)",
41589
- aiSpecific: false
43393
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
43394
+ aiSpecific: true,
43395
+ _v7Verdict: "DORMANT",
43396
+ _v7Lift: 0,
43397
+ _v7Recall: 0,
43398
+ _v7FpRate: 0,
43399
+ _v7Precision: 0,
43400
+ _v8Verdict: "DORMANT",
43401
+ _v8Lift: 1,
43402
+ defaultOff: true
41590
43403
  },
41591
- "docs/broken-link": {
43404
+ "visual/generic-centering": {
41592
43405
  recall: 0,
41593
43406
  fpRate: 0,
41594
43407
  ratio: 0,
41595
43408
  precision: 0,
41596
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43409
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41597
43410
  verdict: "DORMANT",
41598
- defaultOff: true,
41599
- _calibrationNote: "v0.17.0 ship \u2014 not in v7 per-rule table. Default-off until calibration data lands. Backed by: Nielsen, J. (2000), *Designing Web Usability*, New Riders (broken links as a top-5 trust erosion signal); Google Search Central (2024), *Crawl errors documentation*, https://developers.google.com/search/docs/crawling-indexing. (Broken internal links cost SEO crawl budget and reader trust.)",
41600
- aiSpecific: false
43411
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
43412
+ aiSpecific: true,
43413
+ _v7Verdict: "DORMANT",
43414
+ _v7Lift: 0,
43415
+ _v7Recall: 0,
43416
+ _v7FpRate: 0,
43417
+ _v7Precision: 0,
43418
+ _v8Verdict: "DORMANT",
43419
+ _v8Lift: 1,
43420
+ defaultOff: true
41601
43421
  },
41602
- "security/eval": {
41603
- recall: 0,
43422
+ "visual/inline-style-dominance": {
43423
+ recall: 0.0103,
43424
+ fpRate: 52e-4,
43425
+ ratio: 134.59,
43426
+ precision: 0.6983,
43427
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43428
+ verdict: "USEFUL",
43429
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=3028, FP=1308, P=69.8%, FPR=0.52%, lift=134.59. v7 was USEFUL (TP=2303, FP=1221, lift=98.17). v8 was USEFUL (TP=725, FP=87).",
43430
+ aiSpecific: false,
43431
+ _v7Verdict: "USEFUL",
43432
+ _v7Lift: 98.17,
43433
+ _v7Recall: 97e-4,
43434
+ _v7FpRate: 67e-4,
43435
+ _v7Precision: 0.6535,
43436
+ _v8Verdict: "USEFUL",
43437
+ _v8Lift: 704.71
43438
+ },
43439
+ "visual/math-color-cluster": {
43440
+ recall: 2e-4,
41604
43441
  fpRate: 0,
41605
- ratio: 0,
41606
- precision: 0,
41607
- lastCalibratedAt: "2026-06-30T00:00:00Z",
41608
- verdict: "DORMANT",
41609
- defaultOff: true,
41610
- _calibrationNote: "v0.16.0 ship \u2014 not in v7 per-rule table. Default-off until calibration data lands. Backed by: OWASP Foundation (2021), *OWASP Top 10 \u2014 A03:2021 Injection*; Mozilla Developer Network (2024), *eval() \u2014 MDN Web Docs*, https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval (Security Considerations). (eval() and new Function() are RCE vectors if the input is ever attacker-controlled.)",
41611
- aiSpecific: false
43442
+ ratio: 46814.86,
43443
+ precision: 0.9286,
43444
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43445
+ verdict: "USEFUL",
43446
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=65, FP=5, P=92.9%, FPR=0.00%, lift=46814.86. v7 was USEFUL (TP=58, FP=5, lift=33771.28). v8 was USEFUL (TP=7, FP=0).",
43447
+ aiSpecific: true,
43448
+ _v7Verdict: "USEFUL",
43449
+ _v7Lift: 33771.28,
43450
+ _v7Recall: 2e-4,
43451
+ _v7FpRate: 0,
43452
+ _v7Precision: 0.9206,
43453
+ _v8Verdict: "USEFUL",
43454
+ _v8Lift: 99999
41612
43455
  },
41613
- "security/localstorage-token": {
43456
+ "visual/math-default-font": {
43457
+ recall: 16e-4,
43458
+ fpRate: 3e-4,
43459
+ ratio: 3035.16,
43460
+ precision: 0.8669,
43461
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43462
+ verdict: "USEFUL",
43463
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=469, FP=72, P=86.7%, FPR=0.03%, lift=3035.16. v7 was USEFUL (TP=313, FP=71, lift=2105.64). v8 was USEFUL (TP=156, FP=1).",
43464
+ aiSpecific: true,
43465
+ _v7Verdict: "USEFUL",
43466
+ _v7Lift: 2105.64,
43467
+ _v7Recall: 13e-4,
43468
+ _v7FpRate: 4e-4,
43469
+ _v7Precision: 0.8151,
43470
+ _v8Verdict: "USEFUL",
43471
+ _v8Lift: 68229.63
43472
+ },
43473
+ "visual/math-font-entropy": {
43474
+ recall: 52e-4,
43475
+ fpRate: 1e-3,
43476
+ ratio: 869.95,
43477
+ precision: 0.8593,
43478
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43479
+ verdict: "USEFUL",
43480
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=1521, FP=249, P=85.9%, FPR=0.10%, lift=869.95. v7 was USEFUL (TP=1067, FP=248, lift=600.09). v8 was USEFUL (TP=454, FP=1).",
43481
+ aiSpecific: true,
43482
+ _v7Verdict: "USEFUL",
43483
+ _v7Lift: 600.09,
43484
+ _v7Recall: 45e-4,
43485
+ _v7FpRate: 14e-4,
43486
+ _v7Precision: 0.8114,
43487
+ _v8Verdict: "USEFUL",
43488
+ _v8Lift: 68516.08
43489
+ },
43490
+ "visual/math-gradient-hue-rotation": {
41614
43491
  recall: 0,
41615
43492
  fpRate: 0,
41616
43493
  ratio: 0,
41617
43494
  precision: 0,
41618
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43495
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41619
43496
  verdict: "DORMANT",
41620
- defaultOff: true,
41621
- _calibrationNote: "v0.16.0 ship \u2014 not in v7 per-rule table. Default-off until calibration data lands. Backed by: OWASP Foundation (2021), *OWASP Top 10 \u2014 A07:2021 Identification and Authentication Failures*; OWASP Foundation (2022), *HTML5 Security Cheat Sheet \xA72.1 (Local Storage)*. (JWT/access/refresh tokens in localStorage are readable by any XSS payload \u2014 issue as httpOnly cookies instead.)",
41622
- aiSpecific: false
43497
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
43498
+ aiSpecific: true,
43499
+ _v7Verdict: "DORMANT",
43500
+ _v7Lift: 0,
43501
+ _v7Recall: 0,
43502
+ _v7FpRate: 0,
43503
+ _v7Precision: 0,
43504
+ _v8Verdict: "DORMANT",
43505
+ _v8Lift: 1,
43506
+ defaultOff: true
41623
43507
  },
41624
- "security/target-blank-no-noopener": {
41625
- recall: 0,
43508
+ "visual/math-rounded-entropy": {
43509
+ recall: 38e-4,
43510
+ fpRate: 2e-4,
43511
+ ratio: 3785.45,
43512
+ precision: 0.9461,
43513
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43514
+ verdict: "USEFUL",
43515
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=1105, FP=63, P=94.6%, FPR=0.02%, lift=3785.45. v7 was USEFUL (TP=876, FP=62, lift=2762.74). v8 was USEFUL (TP=229, FP=1).",
43516
+ aiSpecific: true,
43517
+ _v7Verdict: "USEFUL",
43518
+ _v7Lift: 2762.74,
43519
+ _v7Recall: 37e-4,
43520
+ _v7FpRate: 3e-4,
43521
+ _v7Precision: 0.9339,
43522
+ _v8Verdict: "USEFUL",
43523
+ _v8Lift: 68368.45
43524
+ },
43525
+ "visual/math-spacing-entropy": {
43526
+ recall: 18e-4,
43527
+ fpRate: 4e-4,
43528
+ ratio: 1898.99,
43529
+ precision: 0.8287,
43530
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43531
+ verdict: "USEFUL",
43532
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=532, FP=110, P=82.9%, FPR=0.04%, lift=1898.99. v7 was USEFUL (TP=425, FP=109, lift=1339.22). v8 was USEFUL (TP=107, FP=1).",
43533
+ aiSpecific: true,
43534
+ _v7Verdict: "USEFUL",
43535
+ _v7Lift: 1339.22,
43536
+ _v7Recall: 18e-4,
43537
+ _v7FpRate: 6e-4,
43538
+ _v7Precision: 0.7959,
43539
+ _v8Verdict: "USEFUL",
43540
+ _v8Lift: 68031.19
43541
+ },
43542
+ "visual/naturalness-anomaly": {
43543
+ recall: 0.1729,
43544
+ fpRate: 0.0687,
43545
+ ratio: 10.86,
43546
+ precision: 0.746,
43547
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43548
+ verdict: "USEFUL",
43549
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=50852, FP=17316, P=74.6%, FPR=6.87%, lift=10.86. v7 was USEFUL (TP=39319, FP=11382, lift=12.50). v8 was USEFUL (TP=11533, FP=5934).",
43550
+ aiSpecific: true,
43551
+ _v7Verdict: "USEFUL",
43552
+ _v7Lift: 12.5,
43553
+ _v7Recall: 0.1659,
43554
+ _v7FpRate: 0.0621,
43555
+ _v7Precision: 0.7755,
43556
+ _v8Verdict: "USEFUL",
43557
+ _v8Lift: 7.64
43558
+ },
43559
+ "visual/radius-scale-violation": {
43560
+ recall: 4e-4,
41626
43561
  fpRate: 0,
41627
- ratio: 0,
41628
- precision: 0,
41629
- lastCalibratedAt: "2026-06-30T00:00:00Z",
41630
- verdict: "DORMANT",
41631
- defaultOff: true,
41632
- _calibrationNote: 'v0.16.0 ship \u2014 not in v7 per-rule table. Default-off until calibration data lands. Backed by: OWASP Foundation (2022), *HTML5 Security Cheat Sheet \xA72.3 (Tabnabbing)*; WHATWG (2024), *HTML Living Standard \u2014 Link types: noopener*. (target="_blank" without rel="noopener" lets the linked page control window.opener \u2014 reverse tabnabbing.)',
41633
- aiSpecific: false
43562
+ ratio: 82131.33,
43563
+ precision: 0.9774,
43564
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43565
+ verdict: "USEFUL",
43566
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=130, FP=3, P=97.7%, FPR=0.00%, lift=82131.33. v7 was USEFUL (TP=96, FP=3, lift=59285.01). v8 was USEFUL (TP=34, FP=0). v0.19 default-on (explicit defaultOff: false): P 97.7% / 82k lift \u2014 UI consistency.",
43567
+ aiSpecific: false,
43568
+ _v7Verdict: "USEFUL",
43569
+ _v7Lift: 59285.01,
43570
+ _v7Recall: 4e-4,
43571
+ _v7FpRate: 0,
43572
+ _v7Precision: 0.9697,
43573
+ _v8Verdict: "USEFUL",
43574
+ _v8Lift: 99999,
43575
+ defaultOff: false
41634
43576
  },
41635
- "wcag/missing-alt": {
43577
+ "visual/spacing-scale-violation": {
43578
+ recall: 86e-4,
43579
+ fpRate: 28e-4,
43580
+ ratio: 273.97,
43581
+ precision: 0.7792,
43582
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43583
+ verdict: "USEFUL",
43584
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=2531, FP=717, P=77.9%, FPR=0.28%, lift=273.97. v7 was USEFUL (TP=1981, FP=717, lift=187.83). v8 was USEFUL (TP=550, FP=0).",
43585
+ aiSpecific: false,
43586
+ _v7Verdict: "USEFUL",
43587
+ _v7Lift: 187.83,
43588
+ _v7Recall: 84e-4,
43589
+ _v7FpRate: 39e-4,
43590
+ _v7Precision: 0.7342,
43591
+ _v8Verdict: "USEFUL",
43592
+ _v8Lift: 99999
43593
+ },
43594
+ "wcag/dragging-movements": {
41636
43595
  recall: 0,
41637
43596
  fpRate: 0,
41638
- ratio: 0,
41639
- precision: 0,
41640
- lastCalibratedAt: "2026-06-30T00:00:00Z",
41641
- verdict: "DORMANT",
41642
- defaultOff: true,
41643
- _calibrationNote: 'v0.16.0 ship \u2014 not in v7 per-rule table. Default-off until calibration data lands. Backed by: W3C (2023), *Web Content Accessibility Guidelines (WCAG) 2.2 \u2014 1.1.1 Non-text Content*, https://www.w3.org/TR/WCAG22/. (Every <img> needs alt text. Decorative: alt="". Informative: describe the image.)',
41644
- aiSpecific: false
43597
+ ratio: 33610.67,
43598
+ precision: 0.4,
43599
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43600
+ verdict: "OK",
43601
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=2, FP=3, P=40.0%, FPR=0.00%, lift=33610.67. v7 was OK (TP=2, FP=3, lift=24455.07). v8 was DORMANT (TP=0, FP=0).",
43602
+ aiSpecific: false,
43603
+ _v7Verdict: "OK",
43604
+ _v7Lift: 24455.07,
43605
+ _v7Recall: 0,
43606
+ _v7FpRate: 0,
43607
+ _v7Precision: 0.4,
43608
+ _v8Verdict: "DORMANT",
43609
+ _v8Lift: 1
41645
43610
  },
41646
- "typo/placeholder-text": {
43611
+ "wcag/focus-appearance": {
43612
+ recall: 28e-4,
43613
+ fpRate: 1e-4,
43614
+ ratio: 8397.24,
43615
+ precision: 0.966,
43616
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43617
+ verdict: "USEFUL",
43618
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=825, FP=29, P=96.6%, FPR=0.01%, lift=8397.24. v7 was USEFUL (TP=612, FP=24, lift=7353.82). v8 was USEFUL (TP=213, FP=5).",
43619
+ aiSpecific: false,
43620
+ _v7Verdict: "USEFUL",
43621
+ _v7Lift: 7353.82,
43622
+ _v7Recall: 26e-4,
43623
+ _v7FpRate: 1e-4,
43624
+ _v7Precision: 0.9623,
43625
+ _v8Verdict: "USEFUL",
43626
+ _v8Lift: 13418.41
43627
+ },
43628
+ "wcag/focus-obscured": {
43629
+ recall: 33e-4,
43630
+ fpRate: 7e-4,
43631
+ ratio: 1214.21,
43632
+ precision: 0.8478,
43633
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43634
+ verdict: "USEFUL",
43635
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=980, FP=176, P=84.8%, FPR=0.07%, lift=1214.21. v7 was USEFUL (TP=797, FP=175, lift=859.38). v8 was USEFUL (TP=183, FP=1).",
43636
+ aiSpecific: false,
43637
+ _v7Verdict: "USEFUL",
43638
+ _v7Lift: 859.38,
43639
+ _v7Recall: 34e-4,
43640
+ _v7FpRate: 1e-3,
43641
+ _v7Precision: 0.82,
43642
+ _v8Verdict: "USEFUL",
43643
+ _v8Lift: 68293.81
43644
+ },
43645
+ "wcag/missing-alt": {
43646
+ recall: 11e-4,
43647
+ fpRate: 7e-4,
43648
+ ratio: 935.33,
43649
+ precision: 0.6456,
43650
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43651
+ verdict: "USEFUL",
43652
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=317, FP=174, P=64.6%, FPR=0.07%, lift=935.33. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=317, FP=174).",
43653
+ aiSpecific: false,
43654
+ _v7Verdict: "DORMANT",
43655
+ _v7Lift: 1,
43656
+ _v7Recall: 0,
43657
+ _v7FpRate: 0,
43658
+ _v7Precision: 0,
43659
+ _v8Verdict: "USEFUL",
43660
+ _v8Lift: 254.79
43661
+ },
43662
+ "wcag/target-size": {
41647
43663
  recall: 0,
41648
43664
  fpRate: 0,
41649
43665
  ratio: 0,
41650
43666
  precision: 0,
41651
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43667
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41652
43668
  verdict: "DORMANT",
41653
- defaultOff: true,
41654
- _calibrationNote: "v0.16.0 ship \u2014 not in v7 per-rule table. Default-off until calibration data lands. Backed by: Nielsen, J. (2000), *Designing Web Usability* (placeholder copy as a top-10 trust erosion signal); Krug, S. (2000), *Don't Make Me Think*, 2nd ed. (TODO/placeholder text in shipped UI signals incomplete work.)",
41655
- aiSpecific: false
43669
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
43670
+ aiSpecific: false,
43671
+ _v7Verdict: "DORMANT",
43672
+ _v7Lift: 0,
43673
+ _v7Recall: 0,
43674
+ _v7FpRate: 0,
43675
+ _v7Precision: 0,
43676
+ _v8Verdict: "DORMANT",
43677
+ _v8Lift: 1,
43678
+ defaultOff: true
41656
43679
  }
41657
43680
  };
41658
43681
 
@@ -41691,7 +43714,6 @@ async function scanFile(filePath, config, registry, cwd = process.cwd()) {
41691
43714
  ".kt",
41692
43715
  ".kts",
41693
43716
  ".dart",
41694
- ".rs",
41695
43717
  ".cpp",
41696
43718
  ".cc",
41697
43719
  ".cxx",