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,14 @@
1
1
  const __importMetaUrl = require("url").pathToFileURL(__filename).href;
2
2
  "use strict";
3
+ var __create = Object.create;
3
4
  var __defProp = Object.defineProperty;
4
5
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
6
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
7
12
  var __export = (target, all) => {
8
13
  for (var name in all)
9
14
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -16,8 +21,418 @@ var __copyProps = (to, from, except, desc) => {
16
21
  }
17
22
  return to;
18
23
  };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
19
32
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
33
 
34
+ // src/engine/parser-rust.ts
35
+ function getRustParser() {
36
+ if (cachedParser) return { ok: true, parser: cachedParser };
37
+ if (loadError) return { ok: false, error: loadError };
38
+ try {
39
+ rustLanguage = import_tree_sitter_rust.default;
40
+ if (!rustLanguage || typeof rustLanguage !== "object") {
41
+ throw new Error("tree-sitter-rust: language export is missing or malformed");
42
+ }
43
+ const parser = new import_tree_sitter.default();
44
+ parser.setLanguage(rustLanguage);
45
+ cachedParser = parser;
46
+ return { ok: true, parser };
47
+ } catch (err) {
48
+ loadError = err instanceof Error ? err : new Error(String(err));
49
+ return { ok: false, error: loadError };
50
+ }
51
+ }
52
+ function effectiveParser() {
53
+ if (forcedFailure) return { ok: false, error: forcedFailure };
54
+ return getRustParser();
55
+ }
56
+ function parseRust(source) {
57
+ const result = effectiveParser();
58
+ if (!result.ok) return null;
59
+ if (!source || source.trim() === "") return null;
60
+ try {
61
+ const rawTree = result.parser.parse(source);
62
+ if (!rawTree) return null;
63
+ const tree = rawTree;
64
+ if (!tree || !tree.rootNode) return null;
65
+ if (tree.rootNode.type === "ERROR" && tree.rootNode.childCount === 0) {
66
+ return null;
67
+ }
68
+ return tree;
69
+ } catch {
70
+ return null;
71
+ }
72
+ }
73
+ function isRustParserAvailable() {
74
+ const result = getRustParser();
75
+ return result.ok;
76
+ }
77
+ var import_tree_sitter, import_tree_sitter_rust, cachedParser, rustLanguage, loadError, forcedFailure;
78
+ var init_parser_rust = __esm({
79
+ "src/engine/parser-rust.ts"() {
80
+ "use strict";
81
+ import_tree_sitter = __toESM(require("tree-sitter"), 1);
82
+ import_tree_sitter_rust = __toESM(require("tree-sitter-rust"), 1);
83
+ cachedParser = null;
84
+ rustLanguage = null;
85
+ loadError = null;
86
+ forcedFailure = null;
87
+ }
88
+ });
89
+
90
+ // src/engine/visitors/rust.ts
91
+ function parseRustFile(filePath, source, options = {}) {
92
+ const empty = {
93
+ imports: [],
94
+ functions: [],
95
+ structs: [],
96
+ traits: [],
97
+ impls: []
98
+ };
99
+ if (!isRustParserAvailable() || options.forceFallback) {
100
+ return empty;
101
+ }
102
+ const tree = parseRust(source);
103
+ if (!tree) return empty;
104
+ return walkRustTree(tree);
105
+ }
106
+ function walkRustTree(tree) {
107
+ const ctx = { inTestConfig: false };
108
+ const out = {
109
+ imports: [],
110
+ functions: [],
111
+ structs: [],
112
+ traits: [],
113
+ impls: []
114
+ };
115
+ walkChildren(tree.rootNode, ctx, out);
116
+ return out;
117
+ }
118
+ function walkChildren(node, ctx, out) {
119
+ for (let i = 0; i < node.namedChildCount; i++) {
120
+ const child = node.namedChild(i);
121
+ if (!child) continue;
122
+ visitNode(child, ctx, out);
123
+ }
124
+ }
125
+ function visitNode(node, ctx, out) {
126
+ const innerCtx = { ...ctx };
127
+ const attrState = readPrecedingAttributes(node);
128
+ switch (node.type) {
129
+ case "use_declaration": {
130
+ out.imports.push(extractUse(node));
131
+ return;
132
+ }
133
+ case "function_item": {
134
+ const isMethod = isInImplBlock(node);
135
+ out.functions.push(extractFunction(node, attrState, innerCtx.inTestConfig, isMethod));
136
+ walkChildren(getField(node, "body") ?? node, innerCtx, out);
137
+ return;
138
+ }
139
+ case "struct_item": {
140
+ out.structs.push(extractStruct(node, attrState));
141
+ const body = getField(node, "body");
142
+ if (body) walkChildren(body, innerCtx, out);
143
+ return;
144
+ }
145
+ case "trait_item": {
146
+ out.traits.push(extractTrait(node, attrState));
147
+ const body = getField(node, "body");
148
+ if (body) walkChildren(body, innerCtx, out);
149
+ return;
150
+ }
151
+ case "impl_item": {
152
+ const implEntry = extractImpl(node, attrState, innerCtx);
153
+ out.impls.push(implEntry.entry);
154
+ const body = getField(node, "body");
155
+ if (body) walkChildren(body, innerCtx, out);
156
+ return;
157
+ }
158
+ case "mod_item": {
159
+ const modIsTest = innerCtx.inTestConfig || attrState.isTestCfg;
160
+ const modCtx = { ...innerCtx, inTestConfig: modIsTest };
161
+ const body = getField(node, "body");
162
+ if (body) walkChildren(body, modCtx, out);
163
+ return;
164
+ }
165
+ default: {
166
+ for (let i = 0; i < node.namedChildCount; i++) {
167
+ const child = node.namedChild(i);
168
+ if (child) visitNode(child, innerCtx, out);
169
+ }
170
+ }
171
+ }
172
+ }
173
+ function readPrecedingAttributes(node) {
174
+ const state = {
175
+ isTestCfg: false,
176
+ isTest: false,
177
+ isPub: false,
178
+ derives: []
179
+ };
180
+ const parent = node.parent;
181
+ if (!parent) return state;
182
+ for (let i = 0; i < parent.namedChildCount; i++) {
183
+ const sibling = parent.namedChild(i);
184
+ if (!sibling || sibling === node) continue;
185
+ if (sibling.endIndex > node.startIndex) continue;
186
+ if (sibling.type !== "attribute_item") continue;
187
+ decodeAttribute(sibling, state);
188
+ }
189
+ return state;
190
+ }
191
+ function decodeAttribute(attr, state) {
192
+ for (let i = 0; i < attr.namedChildCount; i++) {
193
+ const child = attr.namedChild(i);
194
+ if (!child || child.type !== "attribute") continue;
195
+ const name = firstIdentifier(child);
196
+ if (!name) continue;
197
+ if (name === "cfg") {
198
+ const cfgText = child.text;
199
+ if (/\btest\b/.test(cfgText) && !/\bnot\(test\)/.test(cfgText)) {
200
+ state.isTestCfg = true;
201
+ }
202
+ } else if (name === "test") {
203
+ state.isTest = true;
204
+ } else if (name === "derive") {
205
+ for (let j = 0; j < child.namedChildCount; j++) {
206
+ const inner = child.namedChild(j);
207
+ if (inner) {
208
+ const matches = inner.text.matchAll(/\b([A-Z][A-Za-z0-9_]*)\b/g);
209
+ for (const m of matches) state.derives.push(m[1]);
210
+ }
211
+ }
212
+ }
213
+ }
214
+ }
215
+ function firstIdentifier(node) {
216
+ const text = node.text;
217
+ const idMatch = text.match(/^([a-zA-Z_][a-zA-Z0-9_]*)/);
218
+ return idMatch ? idMatch[1] : null;
219
+ }
220
+ function extractUse(node) {
221
+ const text = node.text;
222
+ const argument = node.namedChild(0);
223
+ const argField = node.childForFieldName("argument");
224
+ const path = argField?.text ?? argument?.text ?? "";
225
+ const names = [];
226
+ let isGlob = false;
227
+ const useListNode = findUseListNode(argument);
228
+ if (useListNode) {
229
+ for (let i = 0; i < useListNode.namedChildCount; i++) {
230
+ const item = useListNode.namedChild(i);
231
+ if (item.type === "use_wildcard") {
232
+ isGlob = true;
233
+ } else if (item.type === "identifier") {
234
+ names.push({ name: item.text });
235
+ } else if (item.type === "use_as_clause") {
236
+ const alias = item.childForFieldName("alias");
237
+ const binding = item.childForFieldName("path");
238
+ if (binding) {
239
+ names.push({ name: binding.text, alias: alias?.text });
240
+ } else {
241
+ names.push({ name: item.text });
242
+ }
243
+ } else if (item.type === "scoped_identifier") {
244
+ const idents = collectIdentifiers(item);
245
+ names.push({ name: idents[idents.length - 1] ?? item.text });
246
+ } else if (item.text.includes(" as ")) {
247
+ const [head, alias] = item.text.split(/\s+as\s+/);
248
+ names.push({ name: (head ?? "").trim(), alias: alias?.trim() });
249
+ } else {
250
+ names.push({ name: item.text });
251
+ }
252
+ }
253
+ } else if (argument?.type === "use_wildcard") {
254
+ isGlob = true;
255
+ } else if (argument) {
256
+ const idents = collectIdentifiers(argument);
257
+ const last = idents[idents.length - 1] ?? argument.text;
258
+ names.push({ name: last });
259
+ const asMatch = text.match(/\s+as\s+(\w+)\s*;?\s*$/);
260
+ if (asMatch) names[0].alias = asMatch[1];
261
+ }
262
+ return {
263
+ path: path.trim(),
264
+ names,
265
+ isGlob,
266
+ line: node.startPosition.row + 1,
267
+ column: node.startPosition.column
268
+ };
269
+ }
270
+ function extractFunction(node, attrs, inheritedTestConfig, isMethod) {
271
+ const nameNode = node.childForFieldName("name");
272
+ const name = nameNode?.text ?? "<anon>";
273
+ const params = node.childForFieldName("parameters");
274
+ const body = node.childForFieldName("body");
275
+ const visibilityMod = node.namedChild(0);
276
+ const isPublic = visibilityMod?.type === "visibility_modifier";
277
+ let receiver;
278
+ if (isMethod && params) {
279
+ const selfParam = findSelfParameter(params);
280
+ if (selfParam) receiver = selfParam.text;
281
+ }
282
+ const bodyLines = body ? body.endPosition.row - body.startPosition.row + 1 : 0;
283
+ const inTestConfig = inheritedTestConfig || attrs.isTest || attrs.isTestCfg || isFunctionAttrTest(node);
284
+ return {
285
+ name,
286
+ line: node.startPosition.row + 1,
287
+ column: node.startPosition.column,
288
+ isPublic,
289
+ isMethod,
290
+ receiver,
291
+ bodyLines,
292
+ inTestConfig
293
+ };
294
+ }
295
+ function extractStruct(node, attrs) {
296
+ const nameNode = node.childForFieldName("name");
297
+ return {
298
+ name: nameNode?.text ?? "<anon>",
299
+ line: node.startPosition.row + 1,
300
+ column: node.startPosition.column,
301
+ isPublic: hasVisibility(node),
302
+ isDerive: attrs.derives.length > 0,
303
+ derives: [...attrs.derives]
304
+ };
305
+ }
306
+ function extractTrait(node, _attrs) {
307
+ const nameNode = node.childForFieldName("name");
308
+ return {
309
+ name: nameNode?.text ?? "<anon>",
310
+ line: node.startPosition.row + 1,
311
+ column: node.startPosition.column,
312
+ isPublic: hasVisibility(node)
313
+ };
314
+ }
315
+ function extractImpl(node, _attrs, _ctx) {
316
+ const traitNode = node.childForFieldName("trait");
317
+ const typeNode = node.childForFieldName("type");
318
+ const typeText = typeNode?.text ?? "<anon>";
319
+ const traitText = traitNode?.text;
320
+ const body = node.childForFieldName("body");
321
+ const methods = [];
322
+ if (body) {
323
+ for (let i = 0; i < body.namedChildCount; i++) {
324
+ const child = body.namedChild(i);
325
+ if (child?.type === "function_item") {
326
+ const m = child.childForFieldName("name");
327
+ if (m) methods.push(m.text);
328
+ }
329
+ }
330
+ }
331
+ return {
332
+ entry: {
333
+ type: typeText,
334
+ trait: traitText ?? void 0,
335
+ methods,
336
+ line: node.startPosition.row + 1,
337
+ column: node.startPosition.column
338
+ }
339
+ };
340
+ }
341
+ function findUseListNode(argument) {
342
+ if (!argument) return null;
343
+ if (argument.type === "use_list") return argument;
344
+ if (argument.type === "scoped_use_list") {
345
+ for (let i = 0; i < argument.namedChildCount; i++) {
346
+ const c = argument.namedChild(i);
347
+ if (c?.type === "use_list") return c;
348
+ }
349
+ }
350
+ return null;
351
+ }
352
+ function getField(node, fieldName) {
353
+ return node.childForFieldName(fieldName);
354
+ }
355
+ function collectIdentifiers(node) {
356
+ const out = [];
357
+ for (let i = 0; i < node.namedChildCount; i++) {
358
+ const child = node.namedChild(i);
359
+ if (!child) continue;
360
+ if (child.type === "identifier" || child.type === "type_identifier") {
361
+ out.push(child.text);
362
+ } else if (child.type === "scoped_identifier" || child.type === "nested_identifier") {
363
+ out.push(...collectIdentifiers(child));
364
+ }
365
+ }
366
+ return out;
367
+ }
368
+ function hasVisibility(node) {
369
+ return node.namedChild(0)?.type === "visibility_modifier";
370
+ }
371
+ function isInImplBlock(node) {
372
+ for (let p = node.parent; p; p = p.parent) {
373
+ if (p.type === "impl_item") return true;
374
+ if (p.type === "function_item" || p.type === "source_file") return false;
375
+ }
376
+ return false;
377
+ }
378
+ function findSelfParameter(params) {
379
+ for (let i = 0; i < params.namedChildCount; i++) {
380
+ const child = params.namedChild(i);
381
+ if (child?.type === "self_parameter") return child;
382
+ }
383
+ return null;
384
+ }
385
+ function isFunctionAttrTest(node) {
386
+ void node;
387
+ return false;
388
+ }
389
+ var SERVICE_SUFFIXES, SERVICE_SUFFIX_GROUP, RUST_SERVICE_STRUCT_RE, RUST_SERVICE_IMPL_RE;
390
+ var init_rust = __esm({
391
+ "src/engine/visitors/rust.ts"() {
392
+ "use strict";
393
+ init_parser_rust();
394
+ SERVICE_SUFFIXES = [
395
+ "Service",
396
+ "Manager",
397
+ "Handler",
398
+ "Repository",
399
+ "Controller",
400
+ "Helper",
401
+ "Factory",
402
+ "Provider",
403
+ "Store",
404
+ "API",
405
+ "Client",
406
+ "Adapter",
407
+ "Resolver",
408
+ "Mapper",
409
+ "Transformer",
410
+ "Serializer",
411
+ "Validator",
412
+ "Strategy",
413
+ "Facade",
414
+ "Decorator",
415
+ "Observer",
416
+ "Builder",
417
+ "Command",
418
+ "Processor",
419
+ "Worker",
420
+ "Job",
421
+ "Actor",
422
+ "Executor"
423
+ ];
424
+ SERVICE_SUFFIX_GROUP = `(?:${SERVICE_SUFFIXES.join("|")})`;
425
+ RUST_SERVICE_STRUCT_RE = new RegExp(
426
+ `^(?:pub(?:\\(crate\\)|\\(super\\))?\\s+)?struct\\s+(\\w+?)${SERVICE_SUFFIX_GROUP}?\\b`,
427
+ "gm"
428
+ );
429
+ RUST_SERVICE_IMPL_RE = new RegExp(
430
+ `^impl(?:<[^>]+>)?\\s+(?:${SERVICE_SUFFIX_GROUP}\\s+for\\s+)?(\\w+?)${SERVICE_SUFFIX_GROUP}?\\b`,
431
+ "gm"
432
+ );
433
+ }
434
+ });
435
+
21
436
  // src/engine/worker.ts
22
437
  var worker_exports = {};
23
438
  __export(worker_exports, {
@@ -4258,7 +4673,7 @@ function parseBlankModule(source) {
4258
4673
  tsx: false,
4259
4674
  target: "es2022"
4260
4675
  });
4261
- return { ast, source: replaced };
4676
+ return { ast, source };
4262
4677
  }
4263
4678
  function parseScriptContent(content, isTypeScript) {
4264
4679
  if (isTypeScript) {
@@ -4344,8 +4759,16 @@ function parseSource(source, filePath) {
4344
4759
  // but no SWC support. Return a blank-padded empty module so
4345
4760
  // regex-only rules can still fire (markdown-leakage, comment-
4346
4761
  // ratio, etc.) without burning the parseError path.
4762
+ // v0.18.9: `.rs` is in the same bucket. The visitor layer
4763
+ // (`engine/visitors/rust.ts`) carries the tree-sitter-backed
4764
+ // parse + extractFacts attaches the result to `facts.v2.rustFile`.
4765
+ // The rule layer (`rules/rust/*.ts`) reads that field. parseBlankModule
4766
+ // lets the worker continue past the parser — without this, parseWithSwc
4767
+ // would throw on every .rs file, the worker would count it as a
4768
+ // parseError, and the v2-build's buildRustFileRecord would never run.
4347
4769
  case "py":
4348
4770
  case "go":
4771
+ case "rs":
4349
4772
  return parseBlankModule(source);
4350
4773
  default:
4351
4774
  return parseWithSwc(source, filePath);
@@ -5040,76 +5463,6 @@ function tokenizeIdentifiers(source) {
5040
5463
  return tokens;
5041
5464
  }
5042
5465
  var SQRT_2_TIMES_LN_2 = Math.sqrt(2 * Math.LN2);
5043
- function ecdfAt(sortedSamples, x) {
5044
- let lo = 0;
5045
- let hi = sortedSamples.length;
5046
- while (lo < hi) {
5047
- const mid = lo + hi >>> 1;
5048
- if (sortedSamples[mid] <= x) lo = mid + 1;
5049
- else hi = mid;
5050
- }
5051
- return lo / sortedSamples.length;
5052
- }
5053
- function ksStatistic(sampleA, sampleB) {
5054
- if (sampleA.length === 0 || sampleB.length === 0) return 1;
5055
- const sortedA = [...sampleA].sort((a, b) => a - b);
5056
- const sortedB = [...sampleB].sort((a, b) => a - b);
5057
- const allPoints = [...sortedA, ...sortedB].sort((a, b) => a - b);
5058
- let maxDiff = 0;
5059
- for (const x of allPoints) {
5060
- const fa = ecdfAt(sortedA, x);
5061
- const fb = ecdfAt(sortedB, x);
5062
- const diff = Math.abs(fa - fb);
5063
- if (diff > maxDiff) maxDiff = diff;
5064
- }
5065
- return maxDiff;
5066
- }
5067
- function ksPValue(statistic, n, m) {
5068
- if (n === 0 || m === 0) return 1;
5069
- if (statistic < 0) return 1;
5070
- if (statistic > 1) return 0;
5071
- const lambda = Math.sqrt(n * m / (n + m)) * statistic;
5072
- if (lambda > 3.6) return 0;
5073
- let p = 0;
5074
- for (let j = 1; j < 1e3; j++) {
5075
- const term = 2 * Math.pow(-1, j - 1) * Math.exp(-2 * j * j * lambda * lambda);
5076
- p += term;
5077
- if (Math.abs(term) < 1e-15) break;
5078
- }
5079
- return Math.max(0, Math.min(1, p));
5080
- }
5081
- function ksTest(sampleA, sampleB, alpha = 0.05) {
5082
- const statistic = ksStatistic(sampleA, sampleB);
5083
- const pValue = ksPValue(statistic, sampleA.length, sampleB.length);
5084
- return {
5085
- statistic,
5086
- pValue,
5087
- significant: pValue < alpha,
5088
- n: sampleA.length,
5089
- m: sampleB.length
5090
- };
5091
- }
5092
- function multiFeatureKsTest(features, baselines, alpha = 0.05) {
5093
- const featureNames = [...features.keys()];
5094
- const k = featureNames.length;
5095
- const bonferroniAlpha = k > 0 ? alpha / k : alpha;
5096
- const perFeature = /* @__PURE__ */ new Map();
5097
- const significantFeatures = [];
5098
- for (const name of featureNames) {
5099
- const sample = features.get(name);
5100
- const baseline = baselines.get(name);
5101
- if (!sample || !baseline) continue;
5102
- const result = ksTest(sample, baseline, bonferroniAlpha);
5103
- perFeature.set(name, result);
5104
- if (result.significant) significantFeatures.push(name);
5105
- }
5106
- return {
5107
- perFeature,
5108
- bonferroniAlpha,
5109
- anySignificant: significantFeatures.length > 0,
5110
- significantFeatures
5111
- };
5112
- }
5113
5466
 
5114
5467
  // src/engine/visitors/react.ts
5115
5468
  function isObject(node) {
@@ -6910,6 +7263,7 @@ function dispatchNode(node, parent, path, vctx) {
6910
7263
  }
6911
7264
 
6912
7265
  // src/engine/visitors/v2-build.ts
7266
+ init_rust();
6913
7267
  var TAILWIND_COLOR_RE = /^(?:bg|text|border|ring|from|to|via|fill|stroke)-([a-z]+-\d+|white|black|transparent|current|\[.+?\])$/;
6914
7268
  var TAILWIND_SPACING_RE = /^(?:[pm][xytrbl]?|gap|space-[xy])-(\d+(?:\.\d+)?)$/;
6915
7269
  var TAILWIND_RADIUS_RE = /^(?:rounded(?:-[a-z]+)?)-(.+)$/;
@@ -7090,9 +7444,60 @@ function buildV2Facts(facts, source, ext, framework, config, templateClassNames
7090
7444
  })),
7091
7445
  disabledRules: extractDisabledRules(source),
7092
7446
  templateClassNames,
7447
+ // v0.18.9 — populate the Rust AST record when the file is `.rs`.
7448
+ // Calling `parseRustFile` here keeps the dead-code detector's
7449
+ // import-binding pass a pure function over the same source the
7450
+ // walker saw. The native-binding guard lives inside
7451
+ // `parseRustFile` (returns an empty record when tree-sitter is
7452
+ // unavailable).
7453
+ rustFile: buildRustFileRecord(facts.filePath, source),
7093
7454
  _source: source
7094
7455
  };
7095
7456
  }
7457
+ function buildRustFileRecord(filePath, source) {
7458
+ if (!filePath.toLowerCase().endsWith(".rs")) return void 0;
7459
+ const structure = parseRustFile(filePath, source);
7460
+ return {
7461
+ imports: structure.imports.map((i) => ({
7462
+ path: i.path,
7463
+ names: i.names.map((n) => ({ name: n.name, ...n.alias ? { alias: n.alias } : {} })),
7464
+ isGlob: i.isGlob,
7465
+ line: i.line,
7466
+ column: i.column
7467
+ })),
7468
+ functions: structure.functions.map((f) => ({
7469
+ name: f.name,
7470
+ line: f.line,
7471
+ column: f.column,
7472
+ isPublic: f.isPublic,
7473
+ isMethod: f.isMethod,
7474
+ ...f.receiver ? { receiver: f.receiver } : {},
7475
+ bodyLines: f.bodyLines,
7476
+ inTestConfig: f.inTestConfig
7477
+ })),
7478
+ structs: structure.structs.map((s) => ({
7479
+ name: s.name,
7480
+ line: s.line,
7481
+ column: s.column,
7482
+ isPublic: s.isPublic,
7483
+ isDerive: s.isDerive,
7484
+ derives: [...s.derives]
7485
+ })),
7486
+ traits: structure.traits.map((t) => ({
7487
+ name: t.name,
7488
+ line: t.line,
7489
+ column: t.column,
7490
+ isPublic: t.isPublic
7491
+ })),
7492
+ impls: structure.impls.map((ip) => ({
7493
+ ...ip.trait ? { trait: ip.trait } : {},
7494
+ type: ip.type,
7495
+ methods: [...ip.methods],
7496
+ line: ip.line,
7497
+ column: ip.column
7498
+ }))
7499
+ };
7500
+ }
7096
7501
  function splitFilePath(filePath) {
7097
7502
  const baseName = filePath.split("/").pop() ?? filePath;
7098
7503
  const dotIdx = baseName.lastIndexOf(".");
@@ -34594,9 +34999,43 @@ var unusedImportRule = createRule({
34594
34999
  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.`
34595
35000
  });
34596
35001
  }
35002
+ if (facts.v2.rustFile) {
35003
+ const strippedSource = stripUseDeclarations(facts.v2._source ?? "");
35004
+ const referenced = collectRustReferencedNames(strippedSource);
35005
+ for (const imp of facts.v2.rustFile.imports) {
35006
+ for (const nameEntry of imp.names) {
35007
+ if (referenced.has(nameEntry.name)) continue;
35008
+ const source = ` from '${imp.path}'`;
35009
+ issues.push({
35010
+ ruleId: "dead/unused-import",
35011
+ category: "logic",
35012
+ severity: "low",
35013
+ aiSpecific: true,
35014
+ message: `Unused import: '${nameEntry.name}'${source}`,
35015
+ line: imp.line,
35016
+ column: imp.column,
35017
+ 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)].`
35018
+ });
35019
+ }
35020
+ }
35021
+ }
34597
35022
  return issues;
34598
35023
  }
34599
35024
  });
35025
+ function collectRustReferencedNames(source) {
35026
+ const out = /* @__PURE__ */ new Set();
35027
+ for (const m of source.matchAll(/\b([A-Za-z_][A-Za-z0-9_]*)\b/g)) {
35028
+ out.add(m[1]);
35029
+ }
35030
+ return out;
35031
+ }
35032
+ function stripUseDeclarations(source) {
35033
+ let out = source;
35034
+ out = out.replace(/^\s*use\s+[\s\S]*?;\s*$/gm, "");
35035
+ out = out.replace(/\/\/[^\n]*/g, "");
35036
+ out = out.replace(/\/\*[\s\S]*?\*\//g, "");
35037
+ return out;
35038
+ }
34600
35039
 
34601
35040
  // src/rules/dead/unused-local.ts
34602
35041
  var SKIP_NAMES = /* @__PURE__ */ new Set(["React", "_"]);
@@ -35753,6 +36192,218 @@ var brokenLinkRule = createRule({
35753
36192
  }
35754
36193
  });
35755
36194
 
36195
+ // src/rules/dup/identical-block.ts
36196
+ var crypto = __toESM(require("crypto"), 1);
36197
+ var WINDOW_SIZE = 10;
36198
+ var MIN_NORMALIZED_LENGTH = 40;
36199
+ var HASH_PREFIX_LENGTH = 16;
36200
+ var DEDUP_CACHE = /* @__PURE__ */ new Map();
36201
+ function normalizeAndHash(lines) {
36202
+ const normalized = lines.map(
36203
+ (line) => line.replace(/\/\/.*$/, "").replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s+/g, " ").trim()
36204
+ ).filter((line) => line.length > 0).join("\n");
36205
+ if (normalized.length < MIN_NORMALIZED_LENGTH) return void 0;
36206
+ return crypto.createHash("sha1").update(normalized).digest("hex").slice(0, HASH_PREFIX_LENGTH);
36207
+ }
36208
+ var dupIdenticalBlockRule = createRule({
36209
+ id: "dup/identical-block",
36210
+ category: "logic",
36211
+ severity: "medium",
36212
+ aiSpecific: false,
36213
+ description: "Block of >=10 lines is identical across >=2 files (Type-1 clone detector)",
36214
+ create(_context) {
36215
+ return {};
36216
+ },
36217
+ analyze(_context, facts) {
36218
+ const issues = [];
36219
+ const source = facts.v2?._source;
36220
+ if (!source) return issues;
36221
+ const filePath = facts.filePath;
36222
+ const lines = source.split("\n");
36223
+ for (let i = 0; i <= lines.length - WINDOW_SIZE; i++) {
36224
+ const window = lines.slice(i, i + WINDOW_SIZE);
36225
+ const hash = normalizeAndHash(window);
36226
+ if (!hash) continue;
36227
+ const existing = DEDUP_CACHE.get(hash) ?? [];
36228
+ const matches = existing.filter((m) => m.file !== filePath);
36229
+ for (const match of matches) {
36230
+ issues.push({
36231
+ ruleId: "dup/identical-block",
36232
+ category: "logic",
36233
+ severity: "medium",
36234
+ aiSpecific: false,
36235
+ message: `Identical ${WINDOW_SIZE}-line block at line ${i + 1} also appears in ${match.file}:${match.line + 1}`,
36236
+ line: i + 1,
36237
+ column: 0,
36238
+ 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.",
36239
+ extras: {
36240
+ duplicateOf: {
36241
+ file: match.file,
36242
+ line: match.line + 1,
36243
+ hash
36244
+ }
36245
+ }
36246
+ });
36247
+ }
36248
+ existing.push({ file: filePath, line: i });
36249
+ DEDUP_CACHE.set(hash, existing);
36250
+ }
36251
+ return issues;
36252
+ }
36253
+ });
36254
+
36255
+ // src/rules/go/error-wrap-without-context.ts
36256
+ var ERR_WRAP_REGEX = /fmt\.Errorf\(\s*"((?:[^"\\]|\\.)*)"\s*,\s*([^)]+)\)/g;
36257
+ var GENERIC_PREFIX_REGEX = /^\s*(?:error|err|failed|wrap(?:ping)?|invalid)\s*(?::\s*)?%w\b/i;
36258
+ var goErrorWrapWithoutContextRule = createRule({
36259
+ id: "go/error-wrap-without-context",
36260
+ category: "typo",
36261
+ severity: "low",
36262
+ aiSpecific: true,
36263
+ description: 'fmt.Errorf wrap without operation context \u2014 AI defaults to generic "error: %w"',
36264
+ create(_context) {
36265
+ return {};
36266
+ },
36267
+ analyze(_context, facts) {
36268
+ const issues = [];
36269
+ const source = facts.v2?._source;
36270
+ if (!source) return issues;
36271
+ let match;
36272
+ ERR_WRAP_REGEX.lastIndex = 0;
36273
+ while ((match = ERR_WRAP_REGEX.exec(source)) !== null) {
36274
+ const formatString = match[1];
36275
+ if (!formatString.includes("%w")) continue;
36276
+ if (formatString.length >= 30) continue;
36277
+ if (!GENERIC_PREFIX_REGEX.test(formatString)) continue;
36278
+ const line = source.slice(0, match.index).split("\n").length;
36279
+ issues.push({
36280
+ ruleId: "go/error-wrap-without-context",
36281
+ category: "typo",
36282
+ severity: "low",
36283
+ aiSpecific: true,
36284
+ message: `fmt.Errorf wrap with generic message "${formatString}" \u2014 include the failing operation`,
36285
+ line,
36286
+ column: match[0].indexOf("fmt") + 1,
36287
+ 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'
36288
+ });
36289
+ }
36290
+ return issues;
36291
+ }
36292
+ });
36293
+
36294
+ // src/rules/go/nil-slice-vs-empty.ts
36295
+ var NIL_SLICE_DECL_REGEX = /^[\t ]*var\s+([A-Za-z_][A-Za-z0-9_]*)\s+\[\][\w.*]+\b/gm;
36296
+ var EMPTY_SLICE_ASSIGN_REGEX = /^[\t ]*([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(?:\[\][\w.*]*\{\}|make\(\[\][\w.*]*)/gm;
36297
+ var goNilSliceVsEmptyRule = createRule({
36298
+ id: "go/nil-slice-vs-empty",
36299
+ category: "typo",
36300
+ severity: "low",
36301
+ aiSpecific: true,
36302
+ description: "Variable declared `var x []int` but later assigned `x = []int{}` or `make([]int, n)` \u2014 pick one form",
36303
+ create(_context) {
36304
+ return {};
36305
+ },
36306
+ analyze(_context, facts) {
36307
+ const issues = [];
36308
+ const source = facts.v2?._source;
36309
+ if (!source) return issues;
36310
+ const nilDecls = /* @__PURE__ */ new Map();
36311
+ let m;
36312
+ NIL_SLICE_DECL_REGEX.lastIndex = 0;
36313
+ while ((m = NIL_SLICE_DECL_REGEX.exec(source)) !== null) {
36314
+ nilDecls.set(m[1], source.slice(0, m.index).split("\n").length);
36315
+ }
36316
+ if (nilDecls.size === 0) return issues;
36317
+ EMPTY_SLICE_ASSIGN_REGEX.lastIndex = 0;
36318
+ while ((m = EMPTY_SLICE_ASSIGN_REGEX.exec(source)) !== null) {
36319
+ const name = m[1];
36320
+ if (!nilDecls.has(name)) continue;
36321
+ const declLine = nilDecls.get(name);
36322
+ const assignLine = source.slice(0, m.index).split("\n").length;
36323
+ if (assignLine <= declLine) continue;
36324
+ issues.push({
36325
+ ruleId: "go/nil-slice-vs-empty",
36326
+ category: "typo",
36327
+ severity: "low",
36328
+ aiSpecific: true,
36329
+ message: `Variable '${name}' declared as nil slice (line ${declLine}) but assigned an empty slice (line ${assignLine}) \u2014 pick one form`,
36330
+ line: declLine,
36331
+ column: 1,
36332
+ 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."
36333
+ });
36334
+ }
36335
+ return issues;
36336
+ }
36337
+ });
36338
+
36339
+ // src/rules/go/struct-tag-inconsistency.ts
36340
+ var JSON_TAG_REGEX = /`json:"([^",]+)(?:,([^"]+))?"`/g;
36341
+ var goStructTagInconsistencyRule = createRule({
36342
+ id: "go/struct-tag-inconsistency",
36343
+ category: "typo",
36344
+ severity: "low",
36345
+ aiSpecific: true,
36346
+ description: 'Struct fields mix json:"foo" and json:"foo,omitempty" \u2014 pick one convention per struct',
36347
+ create(_context) {
36348
+ return {};
36349
+ },
36350
+ analyze(_context, facts) {
36351
+ const issues = [];
36352
+ const source = facts.v2?._source;
36353
+ if (!source) return issues;
36354
+ const structRegex = /type\s+[A-Z][A-Za-z0-9_]*\s+struct\s*\{/g;
36355
+ let structMatch;
36356
+ while ((structMatch = structRegex.exec(source)) !== null) {
36357
+ const startIdx = structMatch.index;
36358
+ const openBrace = source.indexOf("{", startIdx);
36359
+ if (openBrace < 0) continue;
36360
+ let depth = 1;
36361
+ let i = openBrace + 1;
36362
+ while (i < source.length && depth > 0) {
36363
+ const ch = source[i];
36364
+ if (ch === "{") depth++;
36365
+ else if (ch === "}") depth--;
36366
+ i++;
36367
+ }
36368
+ const structBody = source.slice(openBrace, i);
36369
+ const structLine = source.slice(0, startIdx).split("\n").length;
36370
+ const styleCount = {};
36371
+ const tagMatches = [];
36372
+ let m;
36373
+ JSON_TAG_REGEX.lastIndex = 0;
36374
+ while ((m = JSON_TAG_REGEX.exec(structBody)) !== null) {
36375
+ const tag = m[1];
36376
+ const options = m[2] ?? "";
36377
+ const style = options ? "with-options" : "no-options";
36378
+ styleCount[style] = (styleCount[style] ?? 0) + 1;
36379
+ tagMatches.push({ tag, style, idx: openBrace + m.index });
36380
+ }
36381
+ const styles = Object.keys(styleCount);
36382
+ if (styles.length < 2 || tagMatches.length < 2) continue;
36383
+ const dominant = styles.reduce(
36384
+ (a, b) => (styleCount[a] ?? 0) >= (styleCount[b] ?? 0) ? a : b
36385
+ );
36386
+ const minority = tagMatches.filter((t) => t.style !== dominant);
36387
+ if (minority.length === 0) continue;
36388
+ for (const m2 of minority) {
36389
+ const line = source.slice(0, m2.idx).split("\n").length;
36390
+ issues.push({
36391
+ ruleId: "go/struct-tag-inconsistency",
36392
+ category: "typo",
36393
+ severity: "low",
36394
+ aiSpecific: true,
36395
+ 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"}`,
36396
+ line,
36397
+ column: 1,
36398
+ 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.'
36399
+ });
36400
+ }
36401
+ if (issues.length > 0) break;
36402
+ }
36403
+ return issues;
36404
+ }
36405
+ });
36406
+
35756
36407
  // src/rules/layout/gap-monopoly.ts
35757
36408
  var GAP_RE = /\bgap(?:-x|-y)?-(\d+)\b/g;
35758
36409
  var gapMonopolyRule = createRule({
@@ -36540,82 +37191,6 @@ var keyPropMissingRule = createRule({
36540
37191
  }
36541
37192
  });
36542
37193
 
36543
- // src/rules/logic/ks-distribution-shift.ts
36544
- var MIN_SAMPLES_PER_FEATURE = 20;
36545
- function extractFileFeatures(source) {
36546
- const lines = source.split("\n");
36547
- const lineLengths = lines.map((l) => l.length);
36548
- const identifierLengths = [];
36549
- const idRe = /[A-Za-z_$][A-Za-z0-9_$]*/g;
36550
- let m;
36551
- while ((m = idRe.exec(source)) !== null) {
36552
- identifierLengths.push(m[0].length);
36553
- }
36554
- const commentDensity = lines.map((l) => {
36555
- const trimmed = l.trim();
36556
- if (trimmed.length === 0) return 0;
36557
- const commentChars = (trimmed.match(/^\/\/.*$/)?.[0]?.length ?? 0) + (trimmed.match(/^\s*\/\*.*?\*\/\s*$/)?.at(0)?.length ?? 0);
36558
- return commentChars / trimmed.length;
36559
- });
36560
- return { lineLengths, identifierLengths, commentDensity };
36561
- }
36562
- var ksDistributionShiftRule = createRule({
36563
- id: "logic/ks-distribution-shift",
36564
- category: "logic",
36565
- severity: "medium",
36566
- aiSpecific: false,
36567
- description: "Multi-feature Kolmogorov\u2013Smirnov distribution-shift vs corpus baseline (Bonferroni-corrected). Peer-reviewed ML distribution-shift detector (arXiv:2510.15996, Oct 2025).",
36568
- create(context) {
36569
- return context;
36570
- },
36571
- analyze(_context, facts) {
36572
- const issues = [];
36573
- if (!facts.v2) return issues;
36574
- const source = facts.v2._source ?? "";
36575
- if (source.length < 200) return issues;
36576
- const features = extractFileFeatures(source);
36577
- const samples = /* @__PURE__ */ new Map([
36578
- ["lineLengths", features.lineLengths],
36579
- ["identifierLengths", features.identifierLengths],
36580
- ["commentDensity", features.commentDensity]
36581
- ]);
36582
- const baselines = getCorpusBaselines();
36583
- const baselinesMap = /* @__PURE__ */ new Map();
36584
- if (baselines) {
36585
- baselinesMap.set("lineLengths", baselines.features.lineLengths.sample);
36586
- baselinesMap.set("identifierLengths", baselines.features.identifierLengths.sample);
36587
- baselinesMap.set("commentDensity", baselines.features.commentDensity.sample);
36588
- } else {
36589
- baselinesMap.set("lineLengths", [20, 25, 30, 32, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]);
36590
- baselinesMap.set("identifierLengths", [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 24, 28]);
36591
- baselinesMap.set("commentDensity", [0, 0, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.4, 0.5]);
36592
- }
36593
- for (const [name, vals] of samples) {
36594
- if (vals.length < MIN_SAMPLES_PER_FEATURE) samples.delete(name);
36595
- }
36596
- if (samples.size === 0) return issues;
36597
- const result = multiFeatureKsTest(samples, baselinesMap, 0.05);
36598
- if (!result.anySignificant) return issues;
36599
- const shifted = result.significantFeatures.join(", ");
36600
- const details = result.significantFeatures.map((name) => {
36601
- const r = result.perFeature.get(name);
36602
- if (!r) return name;
36603
- return `${name} (D=${r.statistic.toFixed(3)}, p=${r.pValue.toExponential(2)})`;
36604
- }).join("; ");
36605
- issues.push({
36606
- ruleId: "logic/ks-distribution-shift",
36607
- category: "logic",
36608
- severity: "medium",
36609
- aiSpecific: true,
36610
- message: `Distribution shift detected on ${result.significantFeatures.length} of ${result.perFeature.size} features (Bonferroni \u03B1=${result.bonferroniAlpha.toExponential(2)}). Features: ${shifted}. Detail: ${details}.`,
36611
- line: 1,
36612
- column: 1,
36613
- 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."
36614
- });
36615
- return issues;
36616
- }
36617
- });
36618
-
36619
37194
  // src/rules/logic/math-any-density.ts
36620
37195
  var ANY_PER_100_LINES = 5;
36621
37196
  var MIN_ABSOLUTE = 6;
@@ -36677,7 +37252,7 @@ var mathAnyDensityRule = createRule({
36677
37252
  });
36678
37253
 
36679
37254
  // src/rules/logic/math-console-log-storm.ts
36680
- var WINDOW_SIZE = 30;
37255
+ var WINDOW_SIZE2 = 30;
36681
37256
  var STORM_THRESHOLD = 5;
36682
37257
  var CONSOLE_LOG_RE = /\bconsole\.log\s*\(/g;
36683
37258
  var mathConsoleLogStormRule = createRule({
@@ -36708,7 +37283,7 @@ var mathConsoleLogStormRule = createRule({
36708
37283
  let maxEndLine = 0;
36709
37284
  let i = 0;
36710
37285
  for (let j = 0; j < lines.length; j++) {
36711
- while (lines[j] - lines[i] > WINDOW_SIZE) i++;
37286
+ while (lines[j] - lines[i] > WINDOW_SIZE2) i++;
36712
37287
  const count = j - i + 1;
36713
37288
  if (count > maxCount) {
36714
37289
  maxCount = count;
@@ -36722,7 +37297,7 @@ var mathConsoleLogStormRule = createRule({
36722
37297
  category: "logic",
36723
37298
  severity: "high",
36724
37299
  aiSpecific: true,
36725
- 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.`,
37300
+ 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.`,
36726
37301
  line: firstIdx >= 0 ? lines[firstIdx] : 1,
36727
37302
  column: firstIdx >= 0 ? columns[firstIdx] : 1,
36728
37303
  advice: "Replace debug logs with a proper debugger or logger.debug() \u2014 remove all console.log before shipping."
@@ -37509,6 +38084,326 @@ var uxPatternFragmentationRule = createRule({
37509
38084
  }
37510
38085
  });
37511
38086
 
38087
+ // src/rules/rust/stringly-typed.ts
38088
+ var SUSPECT_PARAM_NAMES = /* @__PURE__ */ new Set([
38089
+ "kind",
38090
+ "type",
38091
+ "mode",
38092
+ "event",
38093
+ "status",
38094
+ "category",
38095
+ "action",
38096
+ "state",
38097
+ "level",
38098
+ "role",
38099
+ "tier",
38100
+ "phase",
38101
+ "tag",
38102
+ "format",
38103
+ "shape",
38104
+ "direction",
38105
+ "side",
38106
+ "method"
38107
+ ]);
38108
+ var MAX_VARIANT_COUNT = 32;
38109
+ var rustStringlyTypedRule = createRule({
38110
+ id: "rust/stringly-typed",
38111
+ category: "logic",
38112
+ severity: "medium",
38113
+ aiSpecific: true,
38114
+ description: "String / &str parameter where a typed enum exists in the same file",
38115
+ create(_context) {
38116
+ return {};
38117
+ },
38118
+ analyze(_context, facts) {
38119
+ const issues = [];
38120
+ if (!facts.v2?.rustFile) return issues;
38121
+ const source = facts.v2._source ?? "";
38122
+ if (!source) return issues;
38123
+ const lineOffsets = buildLineOffsets2(source);
38124
+ const enumCandidates = collectEnumCandidates(source);
38125
+ if (enumCandidates.length === 0) return issues;
38126
+ for (const fn of facts.v2.rustFile.functions) {
38127
+ const paramText = extractParameterText(source, lineOffsets, fn);
38128
+ if (!paramText) continue;
38129
+ const matches = scanForStringlyParams(paramText);
38130
+ if (matches.length === 0) continue;
38131
+ issues.push({
38132
+ ruleId: "rust/stringly-typed",
38133
+ category: "logic",
38134
+ severity: "medium",
38135
+ aiSpecific: true,
38136
+ 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`,
38137
+ line: fn.line,
38138
+ column: fn.column,
38139
+ 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.`
38140
+ });
38141
+ }
38142
+ return issues;
38143
+ }
38144
+ });
38145
+ function collectEnumCandidates(source) {
38146
+ const out = [];
38147
+ const enumRe = /^(?:pub(?:\([^)]+\))?\s+)?enum\s+(\w+)\s*\{([^}]*)\}/gm;
38148
+ for (const m of source.matchAll(enumRe)) {
38149
+ const body = m[2] ?? "";
38150
+ const variants = body.split(/,(?![^()]*\))/).map((s) => s.trim()).filter((s) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(s.split(/\s+/)[0] ?? ""));
38151
+ if (variants.length > MAX_VARIANT_COUNT) continue;
38152
+ if (variants.length < 2) continue;
38153
+ out.push({ name: m[1], variantCount: variants.length, line: lineOfMatch(source, m.index ?? 0) });
38154
+ }
38155
+ return out;
38156
+ }
38157
+ function lineOfMatch(source, index) {
38158
+ let line = 1;
38159
+ for (let i = 0; i < index && i < source.length; i++) {
38160
+ if (source[i] === "\n") line++;
38161
+ }
38162
+ return line;
38163
+ }
38164
+ function buildLineOffsets2(source) {
38165
+ const out = [0];
38166
+ for (let i = 0; i < source.length; i++) {
38167
+ if (source[i] === "\n") out.push(i + 1);
38168
+ }
38169
+ return out;
38170
+ }
38171
+ function extractParameterText(source, lineOffsets, fn) {
38172
+ const start = lineOffsets[Math.max(0, fn.line - 1)] ?? 0;
38173
+ const head = source.slice(start, start + 400);
38174
+ const openIdx = head.indexOf("(");
38175
+ if (openIdx < 0) return "";
38176
+ let closeIdx = -1;
38177
+ let depth = 0;
38178
+ for (let i = openIdx; i < head.length; i++) {
38179
+ if (head[i] === "(") depth++;
38180
+ else if (head[i] === ")") {
38181
+ depth--;
38182
+ if (depth === 0) {
38183
+ closeIdx = i;
38184
+ break;
38185
+ }
38186
+ }
38187
+ }
38188
+ if (closeIdx < 0) return "";
38189
+ return head.slice(openIdx + 1, closeIdx);
38190
+ }
38191
+ function scanForStringlyParams(paramText) {
38192
+ const out = [];
38193
+ for (const m of paramText.matchAll(
38194
+ /\b([a-z_][a-zA-Z0-9_]*)\s*:\s*(&\s*(?:mut\s+)?(?:str|String)\b)/g
38195
+ )) {
38196
+ const name = m[1];
38197
+ const type = m[2];
38198
+ if (!SUSPECT_PARAM_NAMES.has(name)) continue;
38199
+ out.push({ name, type });
38200
+ }
38201
+ return out;
38202
+ }
38203
+
38204
+ // src/rules/rust/todo-macro.ts
38205
+ init_parser_rust();
38206
+ var TODO_MACROS = /* @__PURE__ */ new Set(["todo", "unimplemented", "todo_unimplemented"]);
38207
+ var rustTodoMacroRule = createRule({
38208
+ id: "rust/todo-macro",
38209
+ category: "logic",
38210
+ severity: "medium",
38211
+ aiSpecific: true,
38212
+ description: "todo!() / unimplemented!() macro invocation in production code",
38213
+ create(_context) {
38214
+ return {};
38215
+ },
38216
+ analyze(_context, facts) {
38217
+ const issues = [];
38218
+ if (!facts.v2?.rustFile) return issues;
38219
+ const source = facts.v2._source ?? "";
38220
+ if (!source) return issues;
38221
+ const tree = parseRust(source);
38222
+ if (!tree) return issues;
38223
+ const testScopes = /* @__PURE__ */ new Set();
38224
+ for (const fn of facts.v2.rustFile.functions) {
38225
+ if (fn.inTestConfig && fn.name) testScopes.add(fn.name);
38226
+ }
38227
+ collectMacroIssues(tree.rootNode, testScopes, issues);
38228
+ return issues;
38229
+ }
38230
+ });
38231
+ function collectMacroIssues(node, testScopes, issues) {
38232
+ if (node.type === "macro_invocation") {
38233
+ const text = node.text;
38234
+ const m = text.match(/^([A-Za-z_][A-Za-z0-9_]*)/);
38235
+ const macroName = m?.[1] ?? "";
38236
+ if (TODO_MACROS.has(macroName)) {
38237
+ if (!isInsideMacroDefinition(node) && !isInsideTestFunction(node, testScopes)) {
38238
+ issues.push({
38239
+ ruleId: "rust/todo-macro",
38240
+ category: "logic",
38241
+ severity: "medium",
38242
+ aiSpecific: true,
38243
+ message: `'${macroName}!()' in production code \u2014 both expand to panic!()`,
38244
+ line: node.startPosition.row + 1,
38245
+ column: node.startPosition.column,
38246
+ 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.`
38247
+ });
38248
+ }
38249
+ }
38250
+ }
38251
+ for (let i = 0; i < node.namedChildCount; i++) {
38252
+ const child = node.namedChild(i);
38253
+ if (child) collectMacroIssues(child, testScopes, issues);
38254
+ }
38255
+ }
38256
+ function isInsideMacroDefinition(node) {
38257
+ for (let p = node.parent; p; p = p.parent) {
38258
+ if (p.type === "macro_definition") return true;
38259
+ if (p.type === "source_file") return false;
38260
+ }
38261
+ return false;
38262
+ }
38263
+ function isInsideTestFunction(node, testScopes) {
38264
+ for (let p = node.parent; p; p = p.parent) {
38265
+ if (p.type === "function_item") {
38266
+ const nameField = p.childForFieldName("name");
38267
+ const name = nameField?.text;
38268
+ if (name && testScopes.has(name)) return true;
38269
+ if (p.text.startsWith("#[test]") || p.text.startsWith("#[cfg(test)]")) return true;
38270
+ return false;
38271
+ }
38272
+ if (p.type === "source_file") return false;
38273
+ }
38274
+ return false;
38275
+ }
38276
+
38277
+ // src/rules/rust/unused-pub-fn.ts
38278
+ var API_CONVENTION_NAMES = /* @__PURE__ */ new Set([
38279
+ "new",
38280
+ "default",
38281
+ "from",
38282
+ "from_str",
38283
+ "from_iter",
38284
+ "try_from",
38285
+ "into",
38286
+ "into_iter",
38287
+ "try_into",
38288
+ "as_ref",
38289
+ "as_mut",
38290
+ "clone",
38291
+ "fmt",
38292
+ "eq",
38293
+ "hash",
38294
+ "partial_cmp",
38295
+ "cmp",
38296
+ "ord",
38297
+ "partial_eq"
38298
+ ]);
38299
+ var rustUnusedPubFnRule = createRule({
38300
+ id: "rust/unused-pub-fn",
38301
+ category: "logic",
38302
+ severity: "low",
38303
+ aiSpecific: true,
38304
+ description: "Public function in a Rust file that has no in-file references",
38305
+ create(_context) {
38306
+ return {};
38307
+ },
38308
+ analyze(_context, facts) {
38309
+ const issues = [];
38310
+ if (!facts.v2?.rustFile) return issues;
38311
+ const rust = facts.v2.rustFile;
38312
+ const referenced = collectReferencedNames(facts.v2._source ?? "");
38313
+ for (const fn of rust.functions) {
38314
+ if (!fn.isPublic) continue;
38315
+ if (API_CONVENTION_NAMES.has(fn.name)) continue;
38316
+ if (fn.inTestConfig) continue;
38317
+ if (referenced.has(fn.name)) continue;
38318
+ issues.push({
38319
+ ruleId: "rust/unused-pub-fn",
38320
+ category: "logic",
38321
+ severity: "low",
38322
+ aiSpecific: true,
38323
+ message: `Public function '${fn.name}' is not referenced anywhere in the file`,
38324
+ line: fn.line,
38325
+ column: fn.column,
38326
+ 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.`
38327
+ });
38328
+ }
38329
+ return issues;
38330
+ }
38331
+ });
38332
+ function collectReferencedNames(source) {
38333
+ const out = /* @__PURE__ */ new Set();
38334
+ for (const m of source.matchAll(/\b([A-Za-z_][A-Za-z0-9_]*)\b/g)) {
38335
+ out.add(m[1]);
38336
+ }
38337
+ return out;
38338
+ }
38339
+
38340
+ // src/rules/rust/unwrap-in-production.ts
38341
+ init_parser_rust();
38342
+ var UNWRAP_METHODS = /* @__PURE__ */ new Set(["unwrap", "expect", "unwrap_or_else"]);
38343
+ var rustUnwrapInProductionRule = createRule({
38344
+ id: "rust/unwrap-in-production",
38345
+ category: "logic",
38346
+ severity: "medium",
38347
+ aiSpecific: true,
38348
+ description: ".unwrap() / .expect() called outside of #[cfg(test)] / #[test] scope",
38349
+ create(_context) {
38350
+ return {};
38351
+ },
38352
+ analyze(_context, facts) {
38353
+ const issues = [];
38354
+ if (!facts.v2?.rustFile) return issues;
38355
+ const source = facts.v2._source ?? "";
38356
+ if (!source) return issues;
38357
+ const tree = parseRust(source);
38358
+ if (!tree) return issues;
38359
+ const testScopes = /* @__PURE__ */ new Set();
38360
+ for (const fn of facts.v2.rustFile.functions) {
38361
+ if (fn.inTestConfig && fn.name) testScopes.add(fn.name);
38362
+ }
38363
+ collectUnwrapIssues(tree.rootNode, testScopes, issues);
38364
+ return issues;
38365
+ }
38366
+ });
38367
+ function collectUnwrapIssues(node, testScopes, issues) {
38368
+ if (node.type === "call_expression") {
38369
+ const fn = node.childForFieldName("function");
38370
+ if (fn && fn.type === "field_expression") {
38371
+ const field = fn.childForFieldName("field");
38372
+ if (field && field.type === "field_identifier" && UNWRAP_METHODS.has(field.text)) {
38373
+ if (!isInsideTestFunction2(node, testScopes)) {
38374
+ issues.push({
38375
+ ruleId: "rust/unwrap-in-production",
38376
+ category: "logic",
38377
+ severity: "medium",
38378
+ aiSpecific: true,
38379
+ message: `'.${field.text}()' called in production code \u2014 panic risk on Err/None`,
38380
+ line: node.startPosition.row + 1,
38381
+ column: node.startPosition.column,
38382
+ 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.`
38383
+ });
38384
+ }
38385
+ }
38386
+ }
38387
+ }
38388
+ for (let i = 0; i < node.namedChildCount; i++) {
38389
+ const child = node.namedChild(i);
38390
+ if (child) collectUnwrapIssues(child, testScopes, issues);
38391
+ }
38392
+ }
38393
+ function isInsideTestFunction2(node, testScopes) {
38394
+ for (let p = node.parent; p; p = p.parent) {
38395
+ if (p.type === "function_item") {
38396
+ const nameField = p.childForFieldName("name");
38397
+ const name = nameField?.text;
38398
+ if (name && testScopes.has(name)) return true;
38399
+ if (p.text.startsWith("#[test]") || p.text.startsWith("#[cfg(test)]")) return true;
38400
+ return false;
38401
+ }
38402
+ if (p.type === "source_file") return false;
38403
+ }
38404
+ return false;
38405
+ }
38406
+
37512
38407
  // src/rules/security/dangerous-cors.ts
37513
38408
  var HEADER_LITERAL_RE = /['"]Access-Control-Allow-Origin['"]\s*[,:=]\s*['"]\*['"]/g;
37514
38409
  var CORS_BLOCK_RE = /\bcors\s*\(\s*\{([^}]*)\}\s*\)/g;
@@ -38976,6 +39871,216 @@ function isTautologicalAssertion(hit) {
38976
39871
  return false;
38977
39872
  }
38978
39873
 
39874
+ // src/rules/ts/enum-vs-as-const.ts
39875
+ var ENUM_DECL_REGEX = /^[ \t]*(?:export\s+)?(?:const\s+)?enum\s+[A-Z_][A-Za-z0-9_]*\s*\{/gm;
39876
+ var tsEnumVsAsConstRule = createRule({
39877
+ id: "ts/enum-vs-as-const",
39878
+ category: "typo",
39879
+ severity: "low",
39880
+ aiSpecific: true,
39881
+ description: "Uses `enum` \u2014 modern TS prefers `as const` objects",
39882
+ create(_context) {
39883
+ return {};
39884
+ },
39885
+ analyze(_context, facts) {
39886
+ const issues = [];
39887
+ const source = facts.v2?._source;
39888
+ if (!source) return issues;
39889
+ let match;
39890
+ ENUM_DECL_REGEX.lastIndex = 0;
39891
+ while ((match = ENUM_DECL_REGEX.exec(source)) !== null) {
39892
+ const line = source.slice(0, match.index).split("\n").length;
39893
+ issues.push({
39894
+ ruleId: "ts/enum-vs-as-const",
39895
+ category: "typo",
39896
+ severity: "low",
39897
+ aiSpecific: true,
39898
+ message: `'enum' is an AI / older-TS pattern \u2014 prefer 'as const' for a frozen object literal`,
39899
+ line,
39900
+ column: match[0].indexOf("enum") + 1,
39901
+ 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.'
39902
+ });
39903
+ }
39904
+ return issues;
39905
+ }
39906
+ });
39907
+
39908
+ // src/rules/ts/excessive-type-assertion.ts
39909
+ var DEFAULT_MAX = 3;
39910
+ 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;
39911
+ var AS_REGEX = /(?<![\w$])as\s+(?!const)([A-Z][\w$.,<>\[\]|&]*)/g;
39912
+ var tsExcessiveTypeAssertionRule = createRule({
39913
+ id: "ts/excessive-type-assertion",
39914
+ category: "typo",
39915
+ severity: "low",
39916
+ aiSpecific: true,
39917
+ description: "Function with >3 `as` type assertions \u2014 likely AI fighting the type system",
39918
+ create(_context) {
39919
+ return { maxAssertionsPerFunction: DEFAULT_MAX };
39920
+ },
39921
+ analyze(context, facts) {
39922
+ const issues = [];
39923
+ const source = facts.v2?._source;
39924
+ if (!source) return issues;
39925
+ let match;
39926
+ FN_DECL_REGEX.lastIndex = 0;
39927
+ while ((match = FN_DECL_REGEX.exec(source)) !== null) {
39928
+ const startIdx = match.index;
39929
+ const openBraceIdx = source.indexOf("{", startIdx);
39930
+ if (openBraceIdx < 0) continue;
39931
+ let depth = 1;
39932
+ let i = openBraceIdx + 1;
39933
+ while (i < source.length && depth > 0) {
39934
+ const ch = source[i];
39935
+ if (ch === "{") depth++;
39936
+ else if (ch === "}") depth--;
39937
+ i++;
39938
+ }
39939
+ const body = source.slice(openBraceIdx, i);
39940
+ const line = source.slice(0, startIdx).split("\n").length;
39941
+ let asCount = 0;
39942
+ const seen = /* @__PURE__ */ new Set();
39943
+ let asMatch;
39944
+ AS_REGEX.lastIndex = 0;
39945
+ while ((asMatch = AS_REGEX.exec(body)) !== null) {
39946
+ const captured = asMatch[1];
39947
+ if (seen.has(captured)) continue;
39948
+ seen.add(captured);
39949
+ asCount++;
39950
+ }
39951
+ if (asCount > context.maxAssertionsPerFunction) {
39952
+ issues.push({
39953
+ ruleId: "ts/excessive-type-assertion",
39954
+ category: "typo",
39955
+ severity: "low",
39956
+ aiSpecific: true,
39957
+ message: `Function has ${asCount} 'as' assertions (max ${context.maxAssertionsPerFunction}) \u2014 likely AI fighting the type system`,
39958
+ line,
39959
+ column: 1,
39960
+ 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."
39961
+ });
39962
+ }
39963
+ }
39964
+ return issues;
39965
+ }
39966
+ });
39967
+
39968
+ // src/rules/ts/import-type-misuse.ts
39969
+ var INLINE_TYPE_IMPORT_REGEX = /^[ \t]*import\s*\{[^}]*\btype\s+[A-Za-z_]/gm;
39970
+ var tsImportTypeMisuseRule = createRule({
39971
+ id: "ts/import-type-misuse",
39972
+ category: "typo",
39973
+ severity: "low",
39974
+ aiSpecific: true,
39975
+ description: "Inline `import { type X }` \u2014 prefer `import type { X }` for clarity",
39976
+ create(_context) {
39977
+ return {};
39978
+ },
39979
+ analyze(_context, facts) {
39980
+ const issues = [];
39981
+ const source = facts.v2?._source;
39982
+ if (!source) return issues;
39983
+ let match;
39984
+ INLINE_TYPE_IMPORT_REGEX.lastIndex = 0;
39985
+ while ((match = INLINE_TYPE_IMPORT_REGEX.exec(source)) !== null) {
39986
+ const line = source.slice(0, match.index).split("\n").length;
39987
+ issues.push({
39988
+ ruleId: "ts/import-type-misuse",
39989
+ category: "typo",
39990
+ severity: "low",
39991
+ aiSpecific: true,
39992
+ message: "Inline `type` in a value import \u2014 split into a separate `import type` statement",
39993
+ line,
39994
+ column: match[0].indexOf("type") + 1,
39995
+ 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.'
39996
+ });
39997
+ }
39998
+ return issues;
39999
+ }
40000
+ });
40001
+
40002
+ // src/rules/ts/never-vs-unknown.ts
40003
+ var NEVER_RETURN_REGEX = /^[ \t]*(?:export\s+)?(?:async\s+)?function\s+([A-Za-z_$][\w$]*)[^{]*:\s*(?:Promise<)?never\b[^{]*\{/gm;
40004
+ var THROW_OR_LOOP_REGEX = /\b(?:throw\b|while\s*\(|for\s*\(|process\.exit\b|System\.exit\b)/;
40005
+ var tsNeverVsUnknownRule = createRule({
40006
+ id: "ts/never-vs-unknown",
40007
+ category: "typo",
40008
+ severity: "low",
40009
+ aiSpecific: true,
40010
+ description: "Return type `: never` but body has no throw / loop / exit \u2014 likely AI misuse",
40011
+ create(_context) {
40012
+ return {};
40013
+ },
40014
+ analyze(_context, facts) {
40015
+ const issues = [];
40016
+ const source = facts.v2?._source;
40017
+ if (!source) return issues;
40018
+ let match;
40019
+ NEVER_RETURN_REGEX.lastIndex = 0;
40020
+ while ((match = NEVER_RETURN_REGEX.exec(source)) !== null) {
40021
+ const fnName = match[1];
40022
+ const startIdx = match.index;
40023
+ const line = source.slice(0, startIdx).split("\n").length;
40024
+ const openBraceIdx = source.indexOf("{", startIdx);
40025
+ if (openBraceIdx < 0) continue;
40026
+ let depth = 1;
40027
+ let i = openBraceIdx + 1;
40028
+ while (i < source.length && depth > 0) {
40029
+ const ch = source[i];
40030
+ if (ch === "{") depth++;
40031
+ else if (ch === "}") depth--;
40032
+ i++;
40033
+ }
40034
+ const body = source.slice(openBraceIdx, i);
40035
+ if (THROW_OR_LOOP_REGEX.test(body)) continue;
40036
+ issues.push({
40037
+ ruleId: "ts/never-vs-unknown",
40038
+ category: "typo",
40039
+ severity: "low",
40040
+ aiSpecific: true,
40041
+ message: `Function '${fnName}' returns 'never' but its body has no throw, loop, or exit \u2014 likely AI misuse`,
40042
+ line,
40043
+ column: match[0].indexOf("never") + 1,
40044
+ 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.'
40045
+ });
40046
+ }
40047
+ return issues;
40048
+ }
40049
+ });
40050
+
40051
+ // src/rules/ts/optional-chain-overuse.ts
40052
+ var DEFAULT_MIN_CHAIN_LENGTH = 5;
40053
+ var tsOptionalChainOveruseRule = createRule({
40054
+ id: "ts/optional-chain-overuse",
40055
+ category: "logic",
40056
+ severity: "low",
40057
+ aiSpecific: true,
40058
+ description: "Optional chaining (?.) used 5+ times in a single chain \u2014 AI tends to chain rather than narrow",
40059
+ create(_context) {
40060
+ return { minChainLength: DEFAULT_MIN_CHAIN_LENGTH };
40061
+ },
40062
+ analyze(context, facts) {
40063
+ const issues = [];
40064
+ const expressions = facts.v2.logic?.logicalExpressions;
40065
+ if (!expressions) return issues;
40066
+ for (const expression of expressions) {
40067
+ if (expression.depth >= context.minChainLength && expression.isOptionalChainLike) {
40068
+ issues.push({
40069
+ ruleId: "ts/optional-chain-overuse",
40070
+ category: "logic",
40071
+ severity: "low",
40072
+ aiSpecific: true,
40073
+ message: `Optional chain depth ${expression.depth} \u2014 break with an intermediate variable or guard clause`,
40074
+ line: expression.line,
40075
+ column: expression.column,
40076
+ 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."
40077
+ });
40078
+ }
40079
+ }
40080
+ return issues;
40081
+ }
40082
+ });
40083
+
38979
40084
  // src/rules/typo/calc-fontsize.ts
38980
40085
  var FONT_SIZE_RE = /\bfont-size\s*:\s*[^;]*\bcalc\s*\(/i;
38981
40086
  var calcFontsizeRule = createRule({
@@ -40516,6 +41621,10 @@ var builtinRules = [
40516
41621
  expiredCodeExampleRule,
40517
41622
  staleFunctionReferenceRule,
40518
41623
  stalePackageReferenceRule,
41624
+ dupIdenticalBlockRule,
41625
+ goErrorWrapWithoutContextRule,
41626
+ goNilSliceVsEmptyRule,
41627
+ goStructTagInconsistencyRule,
40519
41628
  gapMonopolyRule,
40520
41629
  mathElementUniformityRule,
40521
41630
  mathGridUniformityRule,
@@ -40525,7 +41634,6 @@ var builtinRules = [
40525
41634
  ghostDefensiveRule,
40526
41635
  heapsDeviationRule,
40527
41636
  keyPropMissingRule,
40528
- ksDistributionShiftRule,
40529
41637
  mathAnyDensityRule,
40530
41638
  mathConsoleLogStormRule,
40531
41639
  mathGiniClassUsageRule,
@@ -40540,6 +41648,10 @@ var builtinRules = [
40540
41648
  halsteadAnomalyRule,
40541
41649
  terminologyDriftRule,
40542
41650
  uxPatternFragmentationRule,
41651
+ rustStringlyTypedRule,
41652
+ rustTodoMacroRule,
41653
+ rustUnusedPubFnRule,
41654
+ rustUnwrapInProductionRule,
40543
41655
  dangerousCorsRule,
40544
41656
  evalRule,
40545
41657
  exposedEnvVarRule,
@@ -40555,6 +41667,11 @@ var builtinRules = [
40555
41667
  fakePlaceholderRule,
40556
41668
  missingEdgeCaseRule,
40557
41669
  weakAssertionRule,
41670
+ tsEnumVsAsConstRule,
41671
+ tsExcessiveTypeAssertionRule,
41672
+ tsImportTypeMisuseRule,
41673
+ tsNeverVsUnknownRule,
41674
+ tsOptionalChainOveruseRule,
40558
41675
  calcFontsizeRule,
40559
41676
  calcRawPxRule,
40560
41677
  clampOffscaleRule,
@@ -40614,6 +41731,22 @@ var RuleRegistry = class {
40614
41731
  if (!filter) return list;
40615
41732
  return list.filter((r) => filter.kind === "ai" ? r.aiSpecific : !r.aiSpecific);
40616
41733
  }
41734
+ /** v0.18.8: remove every rule where `predicate(rule)` returns true.
41735
+ * Used by focused calibration scripts to scan a single category
41736
+ * without instantiating all 99 rules. */
41737
+ removeWhere(predicate) {
41738
+ let removed = 0;
41739
+ for (const [id, rule] of this.rules) {
41740
+ if (predicate(rule)) {
41741
+ this.rules.delete(id);
41742
+ removed++;
41743
+ }
41744
+ }
41745
+ return removed;
41746
+ }
41747
+ all() {
41748
+ return Array.from(this.rules.values());
41749
+ }
40617
41750
  createContexts(config, filePath, cwd, hotspotIssues = []) {
40618
41751
  const context = {
40619
41752
  config,
@@ -40634,1044 +41767,1943 @@ var RuleRegistry = class {
40634
41767
 
40635
41768
  // src/rules/signal-strength.json
40636
41769
  var signal_strength_default = {
40637
- "logic/math-console-log-storm": {
40638
- recall: 7e-3,
40639
- fpRate: 1e-3,
40640
- ratio: 6.71,
40641
- precision: 0.8968,
40642
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41770
+ "ai/any-density": {
41771
+ recall: 6e-3,
41772
+ fpRate: 37e-4,
41773
+ ratio: 175.31,
41774
+ precision: 0.6523,
41775
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40643
41776
  verdict: "USEFUL",
40644
- _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.",
40645
- aiSpecific: true
41777
+ _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).",
41778
+ aiSpecific: true,
41779
+ _v7Verdict: "USEFUL",
41780
+ _v7Lift: 153.41,
41781
+ _v7Recall: 55e-4,
41782
+ _v7FpRate: 41e-4,
41783
+ _v7Precision: 0.634,
41784
+ _v8Verdict: "USEFUL",
41785
+ _v8Lift: 271.97
40646
41786
  },
40647
- "logic/math-any-density": {
40648
- recall: 16e-4,
40649
- fpRate: 13e-4,
40650
- ratio: 1.17,
40651
- precision: 0.6035,
40652
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40653
- verdict: "NOISY",
40654
- _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.",
40655
- defaultOff: true,
40656
- aiSpecific: true
41787
+ "ai/comment-ratio": {
41788
+ recall: 0.2771,
41789
+ fpRate: 0.1578,
41790
+ ratio: 4.26,
41791
+ precision: 0.6721,
41792
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41793
+ verdict: "USEFUL",
41794
+ _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).",
41795
+ aiSpecific: true,
41796
+ _v7Verdict: "USEFUL",
41797
+ _v7Lift: 4.11,
41798
+ _v7Recall: 0.2545,
41799
+ _v7FpRate: 0.1629,
41800
+ _v7Precision: 0.6687,
41801
+ _v8Verdict: "USEFUL",
41802
+ _v8Lift: 4.73
40657
41803
  },
40658
- "logic/boundary-violation": {
40659
- recall: 0.0263,
40660
- fpRate: 0.0175,
40661
- ratio: 1.5,
40662
- precision: 0.6601,
40663
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40664
- verdict: "HYGIENE",
40665
- _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.",
40666
- aiSpecific: false
41804
+ "ai/compression-profile": {
41805
+ recall: 0.3478,
41806
+ fpRate: 0.1488,
41807
+ ratio: 4.92,
41808
+ precision: 0.7318,
41809
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41810
+ verdict: "USEFUL",
41811
+ _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).",
41812
+ aiSpecific: true,
41813
+ _v7Verdict: "USEFUL",
41814
+ _v7Lift: 4.89,
41815
+ _v7Recall: 0.3166,
41816
+ _v7FpRate: 0.1498,
41817
+ _v7Precision: 0.732,
41818
+ _v8Verdict: "USEFUL",
41819
+ _v8Lift: 5
40667
41820
  },
40668
- "logic/reactive-hook-soup": {
40669
- recall: 38e-4,
41821
+ "ai/console-debug-storm": {
41822
+ recall: 73e-4,
40670
41823
  fpRate: 9e-4,
40671
- ratio: 4.29,
40672
- precision: 0.8476,
40673
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41824
+ ratio: 949.21,
41825
+ precision: 0.9,
41826
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40674
41827
  verdict: "USEFUL",
40675
- _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.",
40676
- aiSpecific: true
41828
+ _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).",
41829
+ aiSpecific: true,
41830
+ _v7Verdict: "USEFUL",
41831
+ _v7Lift: 960.19,
41832
+ _v7Recall: 81e-4,
41833
+ _v7FpRate: 1e-3,
41834
+ _v7Precision: 0.9161,
41835
+ _v8Verdict: "USEFUL",
41836
+ _v8Lift: 845.55
40677
41837
  },
40678
- "logic/optimistic-no-rollback": {
40679
- recall: 12e-4,
40680
- fpRate: 3e-4,
40681
- ratio: 3.61,
40682
- precision: 0.824,
40683
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41838
+ "ai/default-react-stack": {
41839
+ recall: 1e-3,
41840
+ fpRate: 0,
41841
+ ratio: 251225.49,
41842
+ precision: 0.9966,
41843
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40684
41844
  verdict: "USEFUL",
40685
- _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.",
40686
- aiSpecific: true
41845
+ _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.",
41846
+ aiSpecific: true,
41847
+ _v7Verdict: "USEFUL",
41848
+ _v7Lift: 182622.43,
41849
+ _v7Recall: 1e-3,
41850
+ _v7FpRate: 0,
41851
+ _v7Precision: 0.9957,
41852
+ _v8Verdict: "USEFUL",
41853
+ _v8Lift: 99999,
41854
+ defaultOff: false
40687
41855
  },
40688
- "logic/zombie-state": {
40689
- recall: 1e-4,
40690
- fpRate: 0,
40691
- ratio: 9.26,
40692
- precision: 0.9231,
40693
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41856
+ "ai/errors-near-eof": {
41857
+ recall: 0.0948,
41858
+ fpRate: 0.052,
41859
+ ratio: 13.09,
41860
+ precision: 0.6803,
41861
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40694
41862
  verdict: "USEFUL",
40695
- _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.",
40696
- aiSpecific: true
41863
+ _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).",
41864
+ aiSpecific: true,
41865
+ _v7Verdict: "USEFUL",
41866
+ _v7Lift: 11.29,
41867
+ _v7Recall: 0.0704,
41868
+ _v7FpRate: 0.0551,
41869
+ _v7Precision: 0.6225,
41870
+ _v8Verdict: "USEFUL",
41871
+ _v8Lift: 18.16
40697
41872
  },
40698
- "logic/math-gini-class-usage": {
40699
- recall: 13e-4,
41873
+ "ai/fetch-default-overuse": {
41874
+ recall: 27e-4,
40700
41875
  fpRate: 3e-4,
40701
- ratio: 5.09,
40702
- precision: 0.8683,
40703
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41876
+ ratio: 2679.84,
41877
+ precision: 0.9036,
41878
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40704
41879
  verdict: "USEFUL",
40705
- _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.",
40706
- aiSpecific: true
41880
+ _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).",
41881
+ aiSpecific: true,
41882
+ _v7Verdict: "USEFUL",
41883
+ _v7Lift: 2166.14,
41884
+ _v7Recall: 28e-4,
41885
+ _v7FpRate: 4e-4,
41886
+ _v7Precision: 0.8976,
41887
+ _v8Verdict: "USEFUL",
41888
+ _v8Lift: 7139.19
40707
41889
  },
40708
- "visual/math-color-cluster": {
40709
- recall: 2e-4,
41890
+ "ai/library-reinvention": {
41891
+ recall: 3e-4,
40710
41892
  fpRate: 0,
40711
- ratio: 8.95,
40712
- precision: 0.9206,
40713
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41893
+ ratio: 47415.05,
41894
+ precision: 0.9405,
41895
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40714
41896
  verdict: "USEFUL",
40715
- _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.",
40716
- aiSpecific: true
41897
+ _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).",
41898
+ aiSpecific: true,
41899
+ _v7Verdict: "USEFUL",
41900
+ _v7Lift: 34024.44,
41901
+ _v7Recall: 3e-4,
41902
+ _v7FpRate: 0,
41903
+ _v7Precision: 0.9275,
41904
+ _v8Verdict: "USEFUL",
41905
+ _v8Lift: 99999
40717
41906
  },
40718
- "visual/math-default-font": {
40719
- recall: 13e-4,
40720
- fpRate: 4e-4,
40721
- ratio: 3.4,
40722
- precision: 0.8151,
40723
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40724
- verdict: "USEFUL",
40725
- _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.",
40726
- aiSpecific: true
40727
- },
40728
- "visual/math-gradient-hue-rotation": {
41907
+ "ai/log-rank-histogram": {
40729
41908
  recall: 0,
40730
41909
  fpRate: 0,
40731
41910
  ratio: 0,
40732
41911
  precision: 0,
40733
- lastCalibratedAt: "2026-06-25T00:00:00Z",
41912
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40734
41913
  verdict: "DORMANT",
40735
- defaultOff: true,
40736
- _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.)",
40737
- aiSpecific: true
41914
+ _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.",
41915
+ aiSpecific: true,
41916
+ _v7Verdict: "OK",
41917
+ _v7Lift: 0,
41918
+ _v7Recall: 0,
41919
+ _v7FpRate: 0,
41920
+ _v7Precision: 0,
41921
+ _v8Verdict: "DORMANT",
41922
+ _v8Lift: 1,
41923
+ defaultOff: true
40738
41924
  },
40739
- "visual/math-rounded-entropy": {
40740
- recall: 37e-4,
40741
- fpRate: 3e-4,
40742
- ratio: 10.9,
40743
- precision: 0.9339,
40744
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40745
- verdict: "USEFUL",
40746
- _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.",
40747
- aiSpecific: true
41925
+ "ai/markdown-leakage": {
41926
+ recall: 0,
41927
+ fpRate: 0,
41928
+ ratio: 10003.17,
41929
+ precision: 0.3571,
41930
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41931
+ verdict: "OK",
41932
+ _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).",
41933
+ aiSpecific: true,
41934
+ _v7Verdict: "USEFUL",
41935
+ _v7Lift: 65504.64,
41936
+ _v7Recall: 0,
41937
+ _v7FpRate: 0,
41938
+ _v7Precision: 0.7143,
41939
+ _v8Verdict: "INVERTED",
41940
+ _v8Lift: 0
40748
41941
  },
40749
- "visual/math-font-entropy": {
40750
- recall: 45e-4,
40751
- fpRate: 13e-4,
40752
- ratio: 3.32,
40753
- precision: 0.8114,
40754
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41942
+ "ai/renyi-profile": {
41943
+ recall: 0,
41944
+ fpRate: 0,
41945
+ ratio: 5251.67,
41946
+ precision: 0.25,
41947
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41948
+ verdict: "OK",
41949
+ _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).",
41950
+ aiSpecific: true,
41951
+ _v7Verdict: "OK",
41952
+ _v7Lift: 5094.81,
41953
+ _v7Recall: 0,
41954
+ _v7FpRate: 0,
41955
+ _v7Precision: 0.25,
41956
+ _v8Verdict: "OK",
41957
+ _v8Lift: 5722.25
41958
+ },
41959
+ "ai/segment-surprisal-cv": {
41960
+ recall: 0.2019,
41961
+ fpRate: 0.0787,
41962
+ ratio: 9.52,
41963
+ precision: 0.7495,
41964
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40755
41965
  verdict: "USEFUL",
40756
- _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.",
40757
- aiSpecific: true
41966
+ _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).",
41967
+ aiSpecific: true,
41968
+ _v7Verdict: "USEFUL",
41969
+ _v7Lift: 9.11,
41970
+ _v7Recall: 0.1836,
41971
+ _v7FpRate: 0.0817,
41972
+ _v7Precision: 0.7438,
41973
+ _v8Verdict: "USEFUL",
41974
+ _v8Lift: 10.8
40758
41975
  },
40759
- "visual/math-spacing-entropy": {
40760
- recall: 18e-4,
41976
+ "ai/state-default-overuse": {
41977
+ recall: 3e-3,
40761
41978
  fpRate: 6e-4,
40762
- ratio: 3.01,
40763
- precision: 0.7959,
40764
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41979
+ ratio: 1315.06,
41980
+ precision: 0.8451,
41981
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40765
41982
  verdict: "USEFUL",
40766
- _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.",
40767
- aiSpecific: true
41983
+ _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).",
41984
+ aiSpecific: true,
41985
+ _v7Verdict: "USEFUL",
41986
+ _v7Lift: 947.32,
41987
+ _v7Recall: 3e-3,
41988
+ _v7FpRate: 9e-4,
41989
+ _v7Precision: 0.8161,
41990
+ _v8Verdict: "USEFUL",
41991
+ _v8Lift: 16799.55
40768
41992
  },
40769
- "visual/clamp-soup": {
41993
+ "ai/tailwind-color-overuse": {
41994
+ recall: 0.0264,
41995
+ fpRate: 38e-4,
41996
+ ratio: 230.97,
41997
+ precision: 0.8888,
41998
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41999
+ verdict: "USEFUL",
42000
+ _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).",
42001
+ aiSpecific: true,
42002
+ _v7Verdict: "USEFUL",
42003
+ _v7Lift: 161.52,
42004
+ _v7Recall: 0.0218,
42005
+ _v7FpRate: 52e-4,
42006
+ _v7Precision: 0.8436,
42007
+ _v8Verdict: "USEFUL",
42008
+ _v8Lift: 5695.79
42009
+ },
42010
+ "ai/text-like-ratio": {
42011
+ recall: 0,
42012
+ fpRate: 0,
42013
+ ratio: 201664,
42014
+ precision: 0.8,
42015
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42016
+ verdict: "USEFUL",
42017
+ _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).",
42018
+ aiSpecific: true,
42019
+ _v7Verdict: "USEFUL",
42020
+ _v7Lift: 137559.75,
42021
+ _v7Recall: 0,
42022
+ _v7FpRate: 0,
42023
+ _v7Precision: 0.75,
42024
+ _v8Verdict: "USEFUL",
42025
+ _v8Lift: 99999
42026
+ },
42027
+ "ai/whitespace-regularity": {
42028
+ recall: 0.0733,
42029
+ fpRate: 0.0677,
42030
+ ratio: 8.25,
42031
+ precision: 0.5583,
42032
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42033
+ verdict: "USEFUL",
42034
+ _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).",
42035
+ aiSpecific: true,
42036
+ _v7Verdict: "USEFUL",
42037
+ _v7Lift: 7.71,
42038
+ _v7Recall: 0.0737,
42039
+ _v7FpRate: 0.0733,
42040
+ _v7Precision: 0.5652,
42041
+ _v8Verdict: "USEFUL",
42042
+ _v8Lift: 10.06
42043
+ },
42044
+ "arch/astro-island-leak": {
40770
42045
  recall: 0,
40771
42046
  fpRate: 0,
40772
42047
  ratio: 0,
40773
42048
  precision: 0,
40774
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42049
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40775
42050
  verdict: "DORMANT",
40776
- defaultOff: true,
40777
- _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.)",
40778
- aiSpecific: true
42051
+ _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.",
42052
+ aiSpecific: true,
42053
+ _v7Verdict: "DORMANT",
42054
+ _v7Lift: 0,
42055
+ _v7Recall: 0,
42056
+ _v7FpRate: 0,
42057
+ _v7Precision: 0,
42058
+ _v8Verdict: "DORMANT",
42059
+ _v8Lift: 1,
42060
+ defaultOff: true
40779
42061
  },
40780
42062
  "component/giant-component": {
40781
- recall: 0.0176,
40782
- fpRate: 77e-4,
40783
- ratio: 2.3,
40784
- precision: 0.7485,
40785
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42063
+ recall: 0.0181,
42064
+ fpRate: 59e-4,
42065
+ ratio: 132.31,
42066
+ precision: 0.7815,
42067
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40786
42068
  verdict: "USEFUL",
40787
- _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.",
40788
- aiSpecific: true
42069
+ _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).",
42070
+ aiSpecific: true,
42071
+ _v7Verdict: "USEFUL",
42072
+ _v7Lift: 97.16,
42073
+ _v7Recall: 0.0177,
42074
+ _v7FpRate: 77e-4,
42075
+ _v7Precision: 0.7485,
42076
+ _v8Verdict: "USEFUL",
42077
+ _v8Lift: 846.15
42078
+ },
42079
+ "component/multiple-components-per-file": {
42080
+ recall: 0.0751,
42081
+ fpRate: 0.0423,
42082
+ ratio: 15.96,
42083
+ precision: 0.6747,
42084
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42085
+ verdict: "USEFUL",
42086
+ _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).",
42087
+ aiSpecific: false,
42088
+ _v7Verdict: "USEFUL",
42089
+ _v7Lift: 12.04,
42090
+ _v7Recall: 0.0687,
42091
+ _v7FpRate: 0.0523,
42092
+ _v7Precision: 0.6294,
42093
+ _v8Verdict: "USEFUL",
42094
+ _v8Lift: 54.44
40789
42095
  },
40790
42096
  "component/shadcn-prop-mismatch": {
40791
- recall: 13e-4,
42097
+ recall: 16e-4,
40792
42098
  fpRate: 1e-4,
40793
- ratio: 10.1,
40794
- precision: 0.929,
40795
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42099
+ ratio: 9990.98,
42100
+ precision: 0.9512,
42101
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40796
42102
  verdict: "USEFUL",
40797
- _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.",
40798
- aiSpecific: true
42103
+ _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.",
42104
+ aiSpecific: true,
42105
+ _v7Verdict: "USEFUL",
42106
+ _v7Lift: 7099.57,
42107
+ _v7Recall: 13e-4,
42108
+ _v7FpRate: 1e-4,
42109
+ _v7Precision: 0.929,
42110
+ _v8Verdict: "USEFUL",
42111
+ _v8Lift: 99999,
42112
+ defaultOff: false
40799
42113
  },
40800
- "layout/math-grid-uniformity": {
40801
- recall: 3e-4,
40802
- fpRate: 2e-4,
40803
- ratio: 1.72,
40804
- precision: 0.6907,
40805
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40806
- verdict: "OK",
40807
- _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.",
40808
- aiSpecific: true
40809
- },
40810
- "layout/math-element-uniformity": {
40811
- recall: 28e-4,
40812
- fpRate: 12e-4,
40813
- ratio: 2.28,
40814
- precision: 0.7475,
40815
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42114
+ "context/import-path-mismatch": {
42115
+ recall: 0.0681,
42116
+ fpRate: 0.0167,
42117
+ ratio: 49.48,
42118
+ precision: 0.8263,
42119
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40816
42120
  verdict: "USEFUL",
40817
- _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.",
40818
- aiSpecific: true
40819
- },
40820
- "typo/math-button-label-uniformity": {
40821
- recall: 2e-4,
40822
- fpRate: 1e-4,
40823
- ratio: 1.36,
40824
- precision: 0.6379,
40825
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40826
- verdict: "HYGIENE",
40827
- _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.",
40828
- aiSpecific: false
40829
- },
40830
- "perf/css-bloat": {
40831
- recall: 0.0117,
40832
- fpRate: 32e-4,
40833
- ratio: 3.64,
40834
- precision: 0.8252,
40835
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40836
- verdict: "HYGIENE",
40837
- _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.",
40838
- aiSpecific: false
40839
- },
40840
- "wcag/focus-appearance": {
40841
- recall: 26e-4,
40842
- fpRate: 1e-4,
40843
- ratio: 19.68,
40844
- precision: 0.9623,
40845
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40846
- verdict: "HYGIENE",
40847
- _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.",
40848
- aiSpecific: false
42121
+ _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).",
42122
+ aiSpecific: false,
42123
+ _v7Verdict: "USEFUL",
42124
+ _v7Lift: 35.26,
42125
+ _v7Recall: 0.0746,
42126
+ _v7FpRate: 0.0229,
42127
+ _v7Precision: 0.8079,
42128
+ _v8Verdict: "USEFUL",
42129
+ _v8Lift: 8554.38
40849
42130
  },
40850
- "wcag/target-size": {
42131
+ "db/duplicate-index": {
40851
42132
  recall: 0,
40852
42133
  fpRate: 0,
40853
42134
  ratio: 0,
40854
42135
  precision: 0,
40855
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42136
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40856
42137
  verdict: "DORMANT",
40857
- defaultOff: true,
40858
- _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.)",
40859
- aiSpecific: false
40860
- },
40861
- "component/multiple-components-per-file": {
40862
- recall: 0.0681,
40863
- fpRate: 0.052,
40864
- ratio: 1.31,
40865
- precision: 0.6294,
40866
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40867
- verdict: "HYGIENE",
40868
- _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.",
40869
- aiSpecific: false
40870
- },
40871
- "context/import-path-mismatch": {
40872
- recall: 0.0739,
40873
- fpRate: 0.0228,
40874
- ratio: 3.25,
40875
- precision: 0.8079,
40876
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40877
- verdict: "HYGIENE",
40878
- _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.",
40879
- aiSpecific: false
40880
- },
40881
- "logic/key-prop-missing": {
40882
- recall: 17e-4,
40883
- fpRate: 14e-4,
40884
- ratio: 1.28,
40885
- precision: 0.6246,
40886
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40887
- verdict: "HYGIENE",
40888
- _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.",
40889
- aiSpecific: false
40890
- },
40891
- "logic/math-variable-name-entropy": {
40892
- recall: 2e-4,
40893
- fpRate: 1e-4,
40894
- ratio: 1.07,
40895
- precision: 0.5806,
40896
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40897
- verdict: "HYGIENE",
40898
- _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.",
40899
- aiSpecific: false
40900
- },
40901
- "security/public-admin-route": {
40902
- recall: 28e-4,
40903
- fpRate: 78e-4,
40904
- ratio: 0.4,
40905
- precision: 0.2251,
40906
- lastCalibratedAt: "2026-06-26T22:30:00Z",
40907
- verdict: "HYGIENE",
40908
- _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]",
40909
- defaultOff: true,
40910
- aiSpecific: false
40911
- },
40912
- "security/unsafe-html-render": {
40913
- recall: 13e-4,
40914
- fpRate: 9e-4,
40915
- ratio: 1.5,
40916
- precision: 0.661,
40917
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40918
- verdict: "HYGIENE",
40919
- _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.",
40920
- aiSpecific: false
40921
- },
40922
- "visual/naturalness-anomaly": {
40923
- recall: 0.1645,
40924
- fpRate: 0.0617,
40925
- ratio: 2.67,
40926
- precision: 0.7755,
40927
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40928
- verdict: "USEFUL",
40929
- _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.",
40930
- aiSpecific: true
42138
+ _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.",
42139
+ aiSpecific: false,
42140
+ _v7Verdict: "DORMANT",
42141
+ _v7Lift: 0,
42142
+ _v7Recall: 0,
42143
+ _v7FpRate: 0,
42144
+ _v7Precision: 0,
42145
+ _v8Verdict: "DORMANT",
42146
+ _v8Lift: 1,
42147
+ defaultOff: true
40931
42148
  },
40932
- "perf/halstead-anomaly": {
42149
+ "db/enum-sprawl": {
40933
42150
  recall: 0,
40934
42151
  fpRate: 0,
40935
- ratio: 2.32,
40936
- precision: 0.75,
40937
- lastCalibratedAt: "2026-06-27T12:00:00Z",
40938
- verdict: "USEFUL",
40939
- _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.",
40940
- aiSpecific: true
42152
+ ratio: 0,
42153
+ precision: 0,
42154
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42155
+ verdict: "DORMANT",
42156
+ _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.",
42157
+ aiSpecific: false,
42158
+ _v7Verdict: "DORMANT",
42159
+ _v7Lift: 0,
42160
+ _v7Recall: 0,
42161
+ _v7FpRate: 0,
42162
+ _v7Precision: 0,
42163
+ _v8Verdict: "DORMANT",
42164
+ _v8Lift: 1,
42165
+ defaultOff: true
40941
42166
  },
40942
- "arch/astro-island-leak": {
42167
+ "db/missing-fk-index": {
40943
42168
  recall: 0,
40944
42169
  fpRate: 0,
40945
42170
  ratio: 0,
40946
42171
  precision: 0,
40947
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42172
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40948
42173
  verdict: "DORMANT",
40949
- defaultOff: true,
40950
- _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.)",
40951
- aiSpecific: true
42174
+ _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.",
42175
+ aiSpecific: false,
42176
+ _v7Verdict: "DORMANT",
42177
+ _v7Lift: 0,
42178
+ _v7Recall: 0,
42179
+ _v7FpRate: 0,
42180
+ _v7Precision: 0,
42181
+ _v8Verdict: "DORMANT",
42182
+ _v8Lift: 1,
42183
+ defaultOff: true
40952
42184
  },
40953
- "logic/qwik-hook-leak": {
42185
+ "db/missing-not-null": {
40954
42186
  recall: 0,
40955
42187
  fpRate: 0,
40956
42188
  ratio: 0,
40957
42189
  precision: 0,
40958
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42190
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40959
42191
  verdict: "DORMANT",
40960
- defaultOff: true,
40961
- _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.)",
40962
- aiSpecific: true
42192
+ _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.",
42193
+ aiSpecific: false,
42194
+ _v7Verdict: "DORMANT",
42195
+ _v7Lift: 0,
42196
+ _v7Recall: 0,
42197
+ _v7FpRate: 0,
42198
+ _v7Precision: 0,
42199
+ _v8Verdict: "DORMANT",
42200
+ _v8Lift: 1,
42201
+ defaultOff: true
40963
42202
  },
40964
- "test/missing-edge-case": {
42203
+ "db/naming-inconsistency": {
40965
42204
  recall: 0,
40966
42205
  fpRate: 0,
40967
42206
  ratio: 0,
40968
42207
  precision: 0,
40969
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42208
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40970
42209
  verdict: "DORMANT",
40971
- defaultOff: true,
40972
- _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.)",
40973
- aiSpecific: true
42210
+ _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.",
42211
+ aiSpecific: false,
42212
+ _v7Verdict: "DORMANT",
42213
+ _v7Lift: 0,
42214
+ _v7Recall: 0,
42215
+ _v7FpRate: 0,
42216
+ _v7Precision: 0,
42217
+ _v8Verdict: "DORMANT",
42218
+ _v8Lift: 1,
42219
+ defaultOff: true
40974
42220
  },
40975
- "typo/calc-fontsize": {
42221
+ "db/sql-concat": {
42222
+ recall: 5e-4,
42223
+ fpRate: 1e-4,
42224
+ ratio: 7511.26,
42225
+ precision: 0.8343,
42226
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42227
+ verdict: "USEFUL",
42228
+ _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).",
42229
+ aiSpecific: true,
42230
+ _v7Verdict: "DORMANT",
42231
+ _v7Lift: 1,
42232
+ _v7Recall: 0,
42233
+ _v7FpRate: 0,
42234
+ _v7Precision: 0,
42235
+ _v8Verdict: "USEFUL",
42236
+ _v8Lift: 2046.08
42237
+ },
42238
+ "dead/dead-branch": {
42239
+ recall: 2e-4,
42240
+ fpRate: 4e-4,
42241
+ ratio: 1080.68,
42242
+ precision: 0.4244,
42243
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42244
+ verdict: "OK",
42245
+ _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.",
42246
+ aiSpecific: true,
42247
+ _v7Verdict: "DORMANT",
42248
+ _v7Lift: 1,
42249
+ _v7Recall: 0,
42250
+ _v7FpRate: 0,
42251
+ _v7Precision: 0,
42252
+ _v8Verdict: "OK",
42253
+ _v8Lift: 294.38
42254
+ },
42255
+ "dead/unreachable": {
42256
+ recall: 1e-4,
42257
+ fpRate: 6e-4,
42258
+ ratio: 153.14,
42259
+ precision: 0.0966,
42260
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42261
+ verdict: "OK",
42262
+ _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.",
42263
+ aiSpecific: true,
42264
+ _v7Verdict: "DORMANT",
42265
+ _v7Lift: 1,
42266
+ _v7Recall: 0,
42267
+ _v7FpRate: 0,
42268
+ _v7Precision: 0,
42269
+ _v8Verdict: "OK",
42270
+ _v8Lift: 41.71
42271
+ },
42272
+ "dead/unused-import": {
42273
+ recall: 0.0379,
42274
+ fpRate: 0.0222,
42275
+ ratio: 30.06,
42276
+ precision: 0.6662,
42277
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42278
+ verdict: "USEFUL",
42279
+ _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.",
42280
+ aiSpecific: true,
42281
+ _v7Verdict: "DORMANT",
42282
+ _v7Lift: 1,
42283
+ _v7Recall: 0,
42284
+ _v7FpRate: 0,
42285
+ _v7Precision: 0,
42286
+ _v8Verdict: "USEFUL",
42287
+ _v8Lift: 8.19
42288
+ },
42289
+ "dead/unused-local": {
42290
+ recall: 0.0477,
42291
+ fpRate: 74e-4,
42292
+ ratio: 120.18,
42293
+ precision: 0.8834,
42294
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42295
+ verdict: "USEFUL",
42296
+ _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.",
42297
+ aiSpecific: true,
42298
+ _v7Verdict: "DORMANT",
42299
+ _v7Lift: 1,
42300
+ _v7Recall: 0,
42301
+ _v7FpRate: 0,
42302
+ _v7Precision: 0,
42303
+ _v8Verdict: "USEFUL",
42304
+ _v8Lift: 32.74,
42305
+ defaultOff: false
42306
+ },
42307
+ "dead/unused-parameter": {
42308
+ recall: 8e-4,
42309
+ fpRate: 27e-4,
42310
+ ratio: 98,
42311
+ precision: 0.2628,
42312
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42313
+ verdict: "OK",
42314
+ _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.",
42315
+ aiSpecific: true,
42316
+ _v7Verdict: "DORMANT",
42317
+ _v7Lift: 1,
42318
+ _v7Recall: 0,
42319
+ _v7FpRate: 0,
42320
+ _v7Precision: 0,
42321
+ _v8Verdict: "OK",
42322
+ _v8Lift: 26.7
42323
+ },
42324
+ "docs/broken-link": {
42325
+ recall: 14e-4,
42326
+ fpRate: 23e-4,
42327
+ ratio: 178.13,
42328
+ precision: 0.4155,
42329
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42330
+ verdict: "OK",
42331
+ _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).",
42332
+ aiSpecific: false,
42333
+ _v7Verdict: "DORMANT",
42334
+ _v7Lift: 1,
42335
+ _v7Recall: 0,
42336
+ _v7FpRate: 0,
42337
+ _v7Precision: 0,
42338
+ _v8Verdict: "OK",
42339
+ _v8Lift: 48.52
42340
+ },
42341
+ "docs/expired-code-example": {
40976
42342
  recall: 0,
40977
42343
  fpRate: 0,
40978
42344
  ratio: 0,
40979
42345
  precision: 0,
40980
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42346
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42347
+ verdict: "INVERTED",
42348
+ _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).",
42349
+ aiSpecific: false,
42350
+ _v7Verdict: "DORMANT",
42351
+ _v7Lift: 1,
42352
+ _v7Recall: 0,
42353
+ _v7FpRate: 0,
42354
+ _v7Precision: 0,
42355
+ _v8Verdict: "INVERTED",
42356
+ _v8Lift: 0,
42357
+ defaultOff: true
42358
+ },
42359
+ "docs/stale-function-reference": {
42360
+ recall: 26e-4,
42361
+ fpRate: 5e-4,
42362
+ ratio: 1638.47,
42363
+ precision: 0.8515,
42364
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42365
+ verdict: "USEFUL",
42366
+ _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).",
42367
+ aiSpecific: false,
42368
+ _v7Verdict: "DORMANT",
42369
+ _v7Lift: 1,
42370
+ _v7Recall: 0,
42371
+ _v7FpRate: 0,
42372
+ _v7Precision: 0,
42373
+ _v8Verdict: "USEFUL",
42374
+ _v8Lift: 446.32
42375
+ },
42376
+ "docs/stale-package-reference": {
42377
+ recall: 2e-4,
42378
+ fpRate: 4e-4,
42379
+ ratio: 939.43,
42380
+ precision: 0.3429,
42381
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42382
+ verdict: "OK",
42383
+ _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).",
42384
+ aiSpecific: false,
42385
+ _v7Verdict: "DORMANT",
42386
+ _v7Lift: 1,
42387
+ _v7Recall: 0,
42388
+ _v7FpRate: 0,
42389
+ _v7Precision: 0,
42390
+ _v8Verdict: "OK",
42391
+ _v8Lift: 255.9
42392
+ },
42393
+ "dup/identical-block": {
42394
+ recall: 0,
42395
+ fpRate: 0,
42396
+ ratio: 1,
42397
+ precision: 0,
42398
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40981
42399
  verdict: "DORMANT",
40982
- defaultOff: true,
40983
- _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).)",
40984
- aiSpecific: false
42400
+ _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.",
42401
+ aiSpecific: false,
42402
+ _v7Verdict: "DORMANT",
42403
+ _v7Lift: 1,
42404
+ _v7Recall: 0,
42405
+ _v7FpRate: 0,
42406
+ _v7Precision: 0,
42407
+ _v8Verdict: "DORMANT",
42408
+ _v8Lift: 1,
42409
+ defaultOff: true
40985
42410
  },
40986
- "typo/clamp-offscale": {
42411
+ "go/error-wrap-without-context": {
40987
42412
  recall: 0,
40988
42413
  fpRate: 0,
40989
- ratio: 0,
42414
+ ratio: 1,
40990
42415
  precision: 0,
40991
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42416
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
40992
42417
  verdict: "DORMANT",
40993
- defaultOff: true,
40994
- _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.)",
40995
- aiSpecific: false
42418
+ _calibrationNote: "v0.19: new rule (fmt.Errorf wrap with generic message \u2014 needs operation context). Not yet calibrated. Scheduled for v9 calibration.",
42419
+ aiSpecific: true,
42420
+ _v7Verdict: "DORMANT",
42421
+ _v7Lift: 1,
42422
+ _v7Recall: 0,
42423
+ _v7FpRate: 0,
42424
+ _v7Precision: 0,
42425
+ _v8Verdict: "DORMANT",
42426
+ _v8Lift: 1,
42427
+ defaultOff: true
40996
42428
  },
40997
- "typo/math-cta-vocabulary": {
42429
+ "go/nil-slice-vs-empty": {
40998
42430
  recall: 0,
40999
42431
  fpRate: 0,
41000
- ratio: 0,
42432
+ ratio: 1,
41001
42433
  precision: 0,
41002
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42434
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41003
42435
  verdict: "DORMANT",
41004
- defaultOff: true,
41005
- _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.)",
41006
- aiSpecific: true
42436
+ _calibrationNote: "v0.19: new rule (Variable declared nil slice but assigned empty slice). Not yet calibrated. Scheduled for v9 calibration.",
42437
+ aiSpecific: true,
42438
+ _v7Verdict: "DORMANT",
42439
+ _v7Lift: 1,
42440
+ _v7Recall: 0,
42441
+ _v7FpRate: 0,
42442
+ _v7Precision: 0,
42443
+ _v8Verdict: "DORMANT",
42444
+ _v8Lift: 1,
42445
+ defaultOff: true
41007
42446
  },
41008
- "layout/forced-layout": {
42447
+ "go/struct-tag-inconsistency": {
41009
42448
  recall: 0,
41010
42449
  fpRate: 0,
41011
- ratio: 0,
42450
+ ratio: 1,
41012
42451
  precision: 0,
41013
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42452
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41014
42453
  verdict: "DORMANT",
41015
- defaultOff: true,
41016
- _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.)",
41017
- aiSpecific: true
42454
+ _calibrationNote: "v0.19: new rule (Struct fields mix json tag styles). Not yet calibrated. Scheduled for v9 calibration.",
42455
+ aiSpecific: true,
42456
+ _v7Verdict: "DORMANT",
42457
+ _v7Lift: 1,
42458
+ _v7Recall: 0,
42459
+ _v7FpRate: 0,
42460
+ _v7Precision: 0,
42461
+ _v8Verdict: "DORMANT",
42462
+ _v8Lift: 1,
42463
+ defaultOff: true
41018
42464
  },
41019
- "visual/generic-centering": {
42465
+ "layout/forced-layout": {
41020
42466
  recall: 0,
41021
42467
  fpRate: 0,
41022
42468
  ratio: 0,
41023
42469
  precision: 0,
41024
- lastCalibratedAt: "2026-06-25T00:00:00Z",
42470
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41025
42471
  verdict: "DORMANT",
41026
- defaultOff: true,
41027
- _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.)",
41028
- aiSpecific: true
41029
- },
41030
- "product/terminology-drift": {
41031
- recall: 85e-4,
41032
- fpRate: 28e-4,
41033
- ratio: 3,
41034
- precision: 0.7956,
41035
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41036
- verdict: "HYGIENE",
41037
- _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.",
41038
- aiSpecific: false
42472
+ _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.",
42473
+ aiSpecific: true,
42474
+ _v7Verdict: "DORMANT",
42475
+ _v7Lift: 0,
42476
+ _v7Recall: 0,
42477
+ _v7FpRate: 0,
42478
+ _v7Precision: 0,
42479
+ _v8Verdict: "DORMANT",
42480
+ _v8Lift: 1,
42481
+ defaultOff: true
41039
42482
  },
41040
- "product/ux-pattern-fragmentation": {
41041
- recall: 1e-4,
41042
- fpRate: 0,
41043
- ratio: 3.09,
41044
- precision: 0.8,
41045
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42483
+ "layout/gap-monopoly": {
42484
+ recall: 3e-4,
42485
+ fpRate: 1e-4,
42486
+ ratio: 8859.33,
42487
+ precision: 0.8083,
42488
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41046
42489
  verdict: "USEFUL",
41047
- _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.",
41048
- aiSpecific: true
42490
+ _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).",
42491
+ aiSpecific: false,
42492
+ _v7Verdict: "USEFUL",
42493
+ _v7Lift: 6322.11,
42494
+ _v7Recall: 4e-4,
42495
+ _v7FpRate: 1e-4,
42496
+ _v7Precision: 0.7928,
42497
+ _v8Verdict: "USEFUL",
42498
+ _v8Lift: 99999
41049
42499
  },
41050
- "security/sql-construction": {
41051
- recall: 3e-3,
41052
- fpRate: 18e-4,
41053
- ratio: 1.63,
41054
- precision: 0.6788,
41055
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41056
- verdict: "OK",
41057
- _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.",
41058
- aiSpecific: true
42500
+ "layout/math-element-uniformity": {
42501
+ recall: 29e-4,
42502
+ fpRate: 1e-3,
42503
+ ratio: 770.74,
42504
+ precision: 0.7705,
42505
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42506
+ verdict: "USEFUL",
42507
+ _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).",
42508
+ aiSpecific: true,
42509
+ _v7Verdict: "USEFUL",
42510
+ _v7Lift: 609.32,
42511
+ _v7Recall: 28e-4,
42512
+ _v7FpRate: 12e-4,
42513
+ _v7Precision: 0.7475,
42514
+ _v8Verdict: "USEFUL",
42515
+ _v8Lift: 2211.5
41059
42516
  },
41060
- "security/missing-auth-check": {
41061
- recall: 63e-4,
41062
- fpRate: 4e-4,
41063
- ratio: 15.3,
41064
- precision: 0.9247,
41065
- lastCalibratedAt: "2026-06-26T22:30:00Z",
42517
+ "layout/math-grid-uniformity": {
42518
+ recall: 3e-4,
42519
+ fpRate: 1e-4,
42520
+ ratio: 5839.98,
42521
+ precision: 0.7182,
42522
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41066
42523
  verdict: "USEFUL",
41067
- _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.",
41068
- aiSpecific: false
42524
+ _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).",
42525
+ aiSpecific: true,
42526
+ _v7Verdict: "USEFUL",
42527
+ _v7Lift: 4222.91,
42528
+ _v7Recall: 3e-4,
42529
+ _v7FpRate: 2e-4,
42530
+ _v7Precision: 0.6907,
42531
+ _v8Verdict: "USEFUL",
42532
+ _v8Lift: 63384.92
41069
42533
  },
41070
- "security/dangerous-cors": {
41071
- recall: 5e-4,
41072
- fpRate: 5e-4,
41073
- ratio: 1.05,
41074
- precision: 0.5758,
41075
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41076
- verdict: "NOISY",
41077
- _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.",
41078
- defaultOff: true,
41079
- aiSpecific: true
42534
+ "layout/spacing-grid": {
42535
+ recall: 2e-4,
42536
+ fpRate: 2e-4,
42537
+ ratio: 4051.29,
42538
+ precision: 0.6429,
42539
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42540
+ verdict: "USEFUL",
42541
+ _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).",
42542
+ aiSpecific: false,
42543
+ _v7Verdict: "USEFUL",
42544
+ _v7Lift: 8831,
42545
+ _v7Recall: 2e-4,
42546
+ _v7FpRate: 1e-4,
42547
+ _v7Precision: 0.7222,
42548
+ _v8Verdict: "USEFUL",
42549
+ _v8Lift: 1562.77
41080
42550
  },
41081
- "test/duplicate-setup": {
41082
- recall: 1e-4,
42551
+ "logic/bayesian-conditional": {
42552
+ recall: 0,
41083
42553
  fpRate: 0,
41084
- ratio: 3.6,
41085
- precision: 0.8235,
41086
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42554
+ ratio: 0,
42555
+ precision: 0,
42556
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42557
+ verdict: "DORMANT",
42558
+ _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.",
42559
+ aiSpecific: true,
42560
+ _v7Verdict: "DORMANT",
42561
+ _v7Lift: 0,
42562
+ _v7Recall: 0,
42563
+ _v7FpRate: 0,
42564
+ _v7Precision: 0,
42565
+ _v8Verdict: "DORMANT",
42566
+ _v8Lift: 1,
42567
+ defaultOff: true
42568
+ },
42569
+ "logic/boundary-violation": {
42570
+ recall: 0.0274,
42571
+ fpRate: 0.0137,
42572
+ ratio: 51.32,
42573
+ precision: 0.7006,
42574
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41087
42575
  verdict: "USEFUL",
41088
- _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.",
41089
- aiSpecific: true
42576
+ _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).",
42577
+ aiSpecific: false,
42578
+ _v7Verdict: "USEFUL",
42579
+ _v7Lift: 37.42,
42580
+ _v7Recall: 0.0265,
42581
+ _v7FpRate: 0.0176,
42582
+ _v7Precision: 0.6601,
42583
+ _v8Verdict: "USEFUL",
42584
+ _v8Lift: 298.57
41090
42585
  },
41091
42586
  "logic/ghost-defensive": {
41092
42587
  recall: 1e-4,
41093
42588
  fpRate: 0,
41094
- ratio: 5.79,
41095
- precision: 0.8824,
41096
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42589
+ ratio: 112035.56,
42590
+ precision: 0.8889,
42591
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41097
42592
  verdict: "USEFUL",
41098
- _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.",
41099
- aiSpecific: true
42593
+ _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.",
42594
+ aiSpecific: true,
42595
+ _v7Verdict: "USEFUL",
42596
+ _v7Lift: 80917.5,
42597
+ _v7Recall: 1e-4,
42598
+ _v7FpRate: 0,
42599
+ _v7Precision: 0.8824,
42600
+ _v8Verdict: "USEFUL",
42601
+ _v8Lift: 99999,
42602
+ defaultOff: false
41100
42603
  },
41101
- "typo/calc-raw-px": {
41102
- recall: 0,
41103
- fpRate: 0,
41104
- ratio: 2.32,
41105
- precision: 0.75,
41106
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41107
- verdict: "HYGIENE",
41108
- _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.",
41109
- aiSpecific: false
42604
+ "logic/heaps-deviation": {
42605
+ recall: 0.0126,
42606
+ fpRate: 0.0178,
42607
+ ratio: 25.54,
42608
+ precision: 0.4536,
42609
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42610
+ verdict: "OK",
42611
+ _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).",
42612
+ aiSpecific: false,
42613
+ _v7Verdict: "USEFUL",
42614
+ _v7Lift: 41.22,
42615
+ _v7Recall: 0.0123,
42616
+ _v7FpRate: 0.0132,
42617
+ _v7Precision: 0.5461,
42618
+ _v8Verdict: "OK",
42619
+ _v8Lift: 9.36
41110
42620
  },
41111
- "security/fail-open-auth": {
41112
- recall: 0,
41113
- fpRate: 0,
41114
- ratio: 99.99,
41115
- precision: 1,
41116
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42621
+ "logic/key-prop-missing": {
42622
+ recall: 16e-4,
42623
+ fpRate: 11e-4,
42624
+ ratio: 574.52,
42625
+ precision: 0.629,
42626
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41117
42627
  verdict: "USEFUL",
41118
- _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.",
41119
- aiSpecific: true
42628
+ _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).",
42629
+ aiSpecific: false,
42630
+ _v7Verdict: "USEFUL",
42631
+ _v7Lift: 458.26,
42632
+ _v7Recall: 18e-4,
42633
+ _v7FpRate: 14e-4,
42634
+ _v7Precision: 0.6246,
42635
+ _v8Verdict: "USEFUL",
42636
+ _v8Lift: 1760.69
41120
42637
  },
41121
- "wcag/focus-obscured": {
41122
- recall: 33e-4,
41123
- fpRate: 9e-4,
41124
- ratio: 3.51,
41125
- precision: 0.82,
41126
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41127
- verdict: "HYGIENE",
41128
- _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.",
41129
- aiSpecific: false
42638
+ "logic/math-any-density": {
42639
+ recall: 17e-4,
42640
+ fpRate: 13e-4,
42641
+ ratio: 464.59,
42642
+ precision: 0.6027,
42643
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42644
+ verdict: "USEFUL",
42645
+ _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).",
42646
+ aiSpecific: true,
42647
+ _v7Verdict: "USEFUL",
42648
+ _v7Lift: 448.16,
42649
+ _v7Recall: 16e-4,
42650
+ _v7FpRate: 13e-4,
42651
+ _v7Precision: 0.6035,
42652
+ _v8Verdict: "USEFUL",
42653
+ _v8Lift: 515
41130
42654
  },
41131
- "visual/arbitrary-escape": {
41132
- recall: 25e-4,
41133
- fpRate: 9e-4,
41134
- ratio: 2.74,
41135
- precision: 0.7802,
41136
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42655
+ "logic/math-console-log-storm": {
42656
+ recall: 65e-4,
42657
+ fpRate: 11e-4,
42658
+ ratio: 794.4,
42659
+ precision: 0.8729,
42660
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41137
42661
  verdict: "USEFUL",
41138
- _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.",
41139
- aiSpecific: true
42662
+ _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).",
42663
+ aiSpecific: true,
42664
+ _v7Verdict: "USEFUL",
42665
+ _v7Lift: 852.3,
42666
+ _v7Recall: 71e-4,
42667
+ _v7FpRate: 11e-4,
42668
+ _v7Precision: 0.8968,
42669
+ _v8Verdict: "USEFUL",
42670
+ _v8Lift: 595.24
41140
42671
  },
41141
- "security/hardcoded-secret": {
42672
+ "logic/math-gini-class-usage": {
41142
42673
  recall: 13e-4,
41143
- fpRate: 7e-4,
41144
- ratio: 1.72,
41145
- precision: 0.6899,
41146
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41147
- verdict: "OK",
41148
- _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.",
41149
- aiSpecific: true
41150
- },
41151
- "visual/radius-scale-violation": {
41152
- recall: 4e-4,
41153
- fpRate: 0,
41154
- ratio: 24.7,
41155
- precision: 0.9697,
41156
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41157
- verdict: "HYGIENE",
41158
- _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.",
41159
- aiSpecific: false
41160
- },
41161
- "test/fake-placeholder": {
41162
- recall: 53e-4,
41163
- fpRate: 19e-4,
41164
- ratio: 2.82,
41165
- precision: 0.7854,
41166
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42674
+ fpRate: 2e-4,
42675
+ ratio: 4648.6,
42676
+ precision: 0.8852,
42677
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41167
42678
  verdict: "USEFUL",
41168
- _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.",
41169
- aiSpecific: true
41170
- },
41171
- "security/exposed-env-var": {
41172
- recall: 6e-4,
41173
- fpRate: 7e-4,
41174
- ratio: 0.9,
41175
- precision: 0.5387,
41176
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41177
- verdict: "HYGIENE",
41178
- _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.",
41179
- aiSpecific: false
41180
- },
41181
- "perf/cls-image": {
41182
- recall: 2e-4,
41183
- fpRate: 3e-4,
41184
- ratio: 0.8,
41185
- precision: 0.5104,
41186
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41187
- verdict: "HYGIENE",
41188
- _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.",
41189
- aiSpecific: false
42679
+ _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).",
42680
+ aiSpecific: true,
42681
+ _v7Verdict: "USEFUL",
42682
+ _v7Lift: 3388.64,
42683
+ _v7Recall: 13e-4,
42684
+ _v7FpRate: 3e-4,
42685
+ _v7Precision: 0.8683,
42686
+ _v8Verdict: "USEFUL",
42687
+ _v8Lift: 67541.31
41190
42688
  },
41191
- "layout/gap-monopoly": {
41192
- recall: 4e-4,
41193
- fpRate: 1e-4,
41194
- ratio: 2.95,
41195
- precision: 0.7928,
41196
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41197
- verdict: "HYGIENE",
41198
- _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.",
41199
- aiSpecific: false
41200
- },
41201
- "visual/spacing-scale-violation": {
41202
- recall: 83e-4,
41203
- fpRate: 39e-4,
41204
- ratio: 2.13,
41205
- precision: 0.7342,
41206
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41207
- verdict: "HYGIENE",
41208
- _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.",
41209
- aiSpecific: false
41210
- },
41211
- "visual/inline-style-dominance": {
41212
- recall: 96e-4,
41213
- fpRate: 66e-4,
41214
- ratio: 1.46,
41215
- precision: 0.6535,
41216
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41217
- verdict: "HYGIENE",
41218
- _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.",
41219
- aiSpecific: false
41220
- },
41221
- "layout/spacing-grid": {
42689
+ "logic/math-variable-name-entropy": {
41222
42690
  recall: 2e-4,
41223
42691
  fpRate: 1e-4,
41224
- ratio: 2.01,
41225
- precision: 0.7222,
41226
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41227
- verdict: "HYGIENE",
41228
- _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.",
41229
- aiSpecific: false
41230
- },
41231
- "wcag/dragging-movements": {
41232
- recall: 0,
41233
- fpRate: 0,
41234
- ratio: 0.51,
41235
- precision: 0.4,
41236
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41237
- verdict: "HYGIENE",
41238
- _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.",
41239
- aiSpecific: false
42692
+ ratio: 4548.81,
42693
+ precision: 0.6316,
42694
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42695
+ verdict: "USEFUL",
42696
+ _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).",
42697
+ aiSpecific: false,
42698
+ _v7Verdict: "USEFUL",
42699
+ _v7Lift: 4096.07,
42700
+ _v7Recall: 2e-4,
42701
+ _v7FpRate: 1e-4,
42702
+ _v7Precision: 0.5806,
42703
+ _v8Verdict: "USEFUL",
42704
+ _v8Lift: 5548.85
41240
42705
  },
41241
- "test/weak-assertion": {
41242
- recall: 0.0414,
41243
- fpRate: 86e-4,
41244
- ratio: 4.83,
41245
- precision: 0.8622,
41246
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42706
+ "logic/optimistic-no-rollback": {
42707
+ recall: 12e-4,
42708
+ fpRate: 2e-4,
42709
+ ratio: 3523.57,
42710
+ precision: 0.8527,
42711
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41247
42712
  verdict: "USEFUL",
41248
- _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.",
41249
- aiSpecific: true
42713
+ _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).",
42714
+ aiSpecific: true,
42715
+ _v7Verdict: "USEFUL",
42716
+ _v7Lift: 2519.02,
42717
+ _v7Recall: 12e-4,
42718
+ _v7FpRate: 3e-4,
42719
+ _v7Precision: 0.824,
42720
+ _v8Verdict: "USEFUL",
42721
+ _v8Lift: 67726.36
41250
42722
  },
41251
- "logic/bayesian-conditional": {
42723
+ "logic/qwik-hook-leak": {
41252
42724
  recall: 0,
41253
42725
  fpRate: 0,
41254
42726
  ratio: 0,
41255
42727
  precision: 0,
41256
- lastCalibratedAt: "2026-06-27T00:00:00Z",
42728
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41257
42729
  verdict: "DORMANT",
41258
- defaultOff: true,
41259
- _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.",
41260
- aiSpecific: true
41261
- },
41262
- "logic/heaps-deviation": {
41263
- recall: 0.0122,
41264
- fpRate: 0.0132,
41265
- ratio: 0.93,
41266
- precision: 0.5461,
41267
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41268
- verdict: "HYGIENE",
41269
- _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.",
41270
- aiSpecific: false
42730
+ _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.",
42731
+ aiSpecific: true,
42732
+ _v7Verdict: "DORMANT",
42733
+ _v7Lift: 0,
42734
+ _v7Recall: 0,
42735
+ _v7FpRate: 0,
42736
+ _v7Precision: 0,
42737
+ _v8Verdict: "DORMANT",
42738
+ _v8Lift: 1,
42739
+ defaultOff: true
41271
42740
  },
41272
- "logic/ks-distribution-shift": {
41273
- recall: 0.6375,
41274
- fpRate: 0.338,
41275
- ratio: 1.89,
41276
- precision: 0.7096,
41277
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41278
- verdict: "HYGIENE",
41279
- _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.",
41280
- aiSpecific: false
42741
+ "logic/reactive-hook-soup": {
42742
+ recall: 41e-4,
42743
+ fpRate: 6e-4,
42744
+ ratio: 1370.15,
42745
+ precision: 0.8805,
42746
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42747
+ verdict: "USEFUL",
42748
+ _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).",
42749
+ aiSpecific: true,
42750
+ _v7Verdict: "USEFUL",
42751
+ _v7Lift: 959.64,
42752
+ _v7Recall: 38e-4,
42753
+ _v7FpRate: 9e-4,
42754
+ _v7Precision: 0.8476,
42755
+ _v8Verdict: "USEFUL",
42756
+ _v8Lift: 99999
41281
42757
  },
41282
42758
  "logic/zipf-slope-anomaly": {
41283
- recall: 0.0156,
41284
- fpRate: 87e-4,
41285
- ratio: 1.79,
41286
- precision: 0.6983,
41287
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41288
- verdict: "HYGIENE",
41289
- _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.",
41290
- aiSpecific: false
42759
+ recall: 0.0168,
42760
+ fpRate: 0.0111,
42761
+ ratio: 57.13,
42762
+ precision: 0.6369,
42763
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42764
+ verdict: "USEFUL",
42765
+ _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).",
42766
+ aiSpecific: false,
42767
+ _v7Verdict: "USEFUL",
42768
+ _v7Lift: 79.75,
42769
+ _v7Recall: 0.0157,
42770
+ _v7FpRate: 88e-4,
42771
+ _v7Precision: 0.6983,
42772
+ _v8Verdict: "USEFUL",
42773
+ _v8Lift: 28.59
41291
42774
  },
41292
- "ai/markdown-leakage": {
41293
- recall: 0,
42775
+ "logic/zombie-state": {
42776
+ recall: 1e-4,
41294
42777
  fpRate: 0,
41295
- ratio: 1.93,
41296
- precision: 0.7143,
41297
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41298
- verdict: "OK",
41299
- _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.",
41300
- aiSpecific: true
42778
+ ratio: 119891.71,
42779
+ precision: 0.9512,
42780
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42781
+ verdict: "USEFUL",
42782
+ _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).",
42783
+ aiSpecific: true,
42784
+ _v7Verdict: "USEFUL",
42785
+ _v7Lift: 84652.15,
42786
+ _v7Recall: 1e-4,
42787
+ _v7FpRate: 0,
42788
+ _v7Precision: 0.9231,
42789
+ _v8Verdict: "USEFUL",
42790
+ _v8Lift: 99999
41301
42791
  },
41302
- "ai/comment-ratio": {
41303
- recall: 0.2523,
41304
- fpRate: 0.1619,
41305
- ratio: 1.56,
41306
- precision: 0.6687,
41307
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41308
- verdict: "OK",
41309
- _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.",
41310
- aiSpecific: true
42792
+ "perf/cls-image": {
42793
+ recall: 2e-4,
42794
+ fpRate: 2e-4,
42795
+ ratio: 2895.78,
42796
+ precision: 0.5514,
42797
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42798
+ verdict: "USEFUL",
42799
+ _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).",
42800
+ aiSpecific: false,
42801
+ _v7Verdict: "USEFUL",
42802
+ _v7Lift: 1991.85,
42803
+ _v7Recall: 2e-4,
42804
+ _v7FpRate: 3e-4,
42805
+ _v7Precision: 0.5104,
42806
+ _v8Verdict: "USEFUL",
42807
+ _v8Lift: 62424.55
41311
42808
  },
41312
- "ai/whitespace-regularity": {
41313
- recall: 0.0731,
41314
- fpRate: 0.0728,
41315
- ratio: 1,
41316
- precision: 0.5652,
41317
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41318
- verdict: "NOISY",
41319
- _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.",
41320
- defaultOff: true,
41321
- aiSpecific: true
42809
+ "perf/css-bloat": {
42810
+ recall: 0.0126,
42811
+ fpRate: 24e-4,
42812
+ ratio: 365.63,
42813
+ precision: 0.8616,
42814
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42815
+ verdict: "USEFUL",
42816
+ _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).",
42817
+ aiSpecific: false,
42818
+ _v7Verdict: "USEFUL",
42819
+ _v7Lift: 256.1,
42820
+ _v7Recall: 0.0118,
42821
+ _v7FpRate: 32e-4,
42822
+ _v7Precision: 0.8252,
42823
+ _v8Verdict: "USEFUL",
42824
+ _v8Lift: 22813.54
41322
42825
  },
41323
- "ai/text-like-ratio": {
42826
+ "perf/halstead-anomaly": {
41324
42827
  recall: 0,
41325
42828
  fpRate: 0,
41326
- ratio: 2.32,
41327
- precision: 0.75,
41328
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42829
+ ratio: 75624,
42830
+ precision: 0.6,
42831
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41329
42832
  verdict: "USEFUL",
41330
- _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.",
41331
- aiSpecific: true
42833
+ _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).",
42834
+ aiSpecific: true,
42835
+ _v7Verdict: "USEFUL",
42836
+ _v7Lift: 137559.75,
42837
+ _v7Recall: 0,
42838
+ _v7FpRate: 0,
42839
+ _v7Precision: 0.75,
42840
+ _v8Verdict: "INVERTED",
42841
+ _v8Lift: 0
41332
42842
  },
41333
- "ai/errors-near-eof": {
41334
- recall: 0.0697,
41335
- fpRate: 0.0548,
41336
- ratio: 1.27,
41337
- precision: 0.6225,
41338
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41339
- verdict: "NOISY",
41340
- _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.",
41341
- defaultOff: true,
41342
- aiSpecific: true
42843
+ "product/terminology-drift": {
42844
+ recall: 91e-4,
42845
+ fpRate: 21e-4,
42846
+ ratio: 397.75,
42847
+ precision: 0.8347,
42848
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42849
+ verdict: "USEFUL",
42850
+ _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).",
42851
+ aiSpecific: false,
42852
+ _v7Verdict: "USEFUL",
42853
+ _v7Lift: 280.09,
42854
+ _v7Recall: 86e-4,
42855
+ _v7FpRate: 28e-4,
42856
+ _v7Precision: 0.7956,
42857
+ _v8Verdict: "USEFUL",
42858
+ _v8Lift: 8477.9
41343
42859
  },
41344
- "ai/any-density": {
41345
- recall: 55e-4,
41346
- fpRate: 41e-4,
41347
- ratio: 1.34,
41348
- precision: 0.634,
41349
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41350
- verdict: "NOISY",
41351
- _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.",
41352
- defaultOff: true,
41353
- aiSpecific: true
42860
+ "product/ux-pattern-fragmentation": {
42861
+ recall: 1e-4,
42862
+ fpRate: 0,
42863
+ ratio: 22864.4,
42864
+ precision: 0.8163,
42865
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42866
+ verdict: "USEFUL",
42867
+ _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).",
42868
+ aiSpecific: true,
42869
+ _v7Verdict: "USEFUL",
42870
+ _v7Lift: 18341.3,
42871
+ _v7Recall: 1e-4,
42872
+ _v7FpRate: 0,
42873
+ _v7Precision: 0.8,
42874
+ _v8Verdict: "USEFUL",
42875
+ _v8Lift: 61037.33
41354
42876
  },
41355
- "ai/renyi-profile": {
41356
- recall: 0,
42877
+ "rust/stringly-typed": {
42878
+ recall: 2e-4,
41357
42879
  fpRate: 0,
41358
- ratio: 0.26,
41359
- precision: 0.25,
41360
- lastCalibratedAt: "2026-06-27T12:00:00Z",
41361
- verdict: "INVERTED",
41362
- _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.",
41363
- defaultOff: true,
41364
- aiSpecific: true
42880
+ ratio: 24735.12,
42881
+ precision: 0.8831,
42882
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42883
+ verdict: "USEFUL",
42884
+ _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).",
42885
+ aiSpecific: true,
42886
+ _v7Verdict: "DORMANT",
42887
+ _v7Lift: 1,
42888
+ _v7Recall: 0,
42889
+ _v7FpRate: 0,
42890
+ _v7Precision: 0,
42891
+ _v8Verdict: "USEFUL",
42892
+ _v8Lift: 6737.89
41365
42893
  },
41366
- "ai/log-rank-histogram": {
42894
+ "rust/todo-macro": {
42895
+ recall: 1e-4,
42896
+ fpRate: 7e-4,
42897
+ ratio: 210.08,
42898
+ precision: 0.1392,
42899
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42900
+ verdict: "OK",
42901
+ _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).",
42902
+ aiSpecific: true,
42903
+ _v7Verdict: "DORMANT",
42904
+ _v7Lift: 1,
42905
+ _v7Recall: 0,
42906
+ _v7FpRate: 0,
42907
+ _v7Precision: 0,
42908
+ _v8Verdict: "OK",
42909
+ _v8Lift: 57.23
42910
+ },
42911
+ "rust/unused-pub-fn": {
41367
42912
  recall: 0,
41368
42913
  fpRate: 0,
41369
- ratio: 0,
41370
- precision: 0,
41371
- lastCalibratedAt: "2026-06-27T00:00:00Z",
42914
+ ratio: 10803.43,
42915
+ precision: 0.3,
42916
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41372
42917
  verdict: "OK",
41373
- _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).",
41374
- aiSpecific: true
42918
+ _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).",
42919
+ aiSpecific: true,
42920
+ _v7Verdict: "DORMANT",
42921
+ _v7Lift: 1,
42922
+ _v7Recall: 0,
42923
+ _v7FpRate: 0,
42924
+ _v7Precision: 0,
42925
+ _v8Verdict: "OK",
42926
+ _v8Lift: 2942.87
41375
42927
  },
41376
- "ai/segment-surprisal-cv": {
41377
- recall: 0.182,
41378
- fpRate: 0.0812,
41379
- ratio: 2.24,
41380
- precision: 0.7438,
41381
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42928
+ "rust/unwrap-in-production": {
42929
+ recall: 8e-3,
42930
+ fpRate: 77e-4,
42931
+ ratio: 70.81,
42932
+ precision: 0.5475,
42933
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41382
42934
  verdict: "USEFUL",
41383
- _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.",
41384
- aiSpecific: true
42935
+ _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).",
42936
+ aiSpecific: true,
42937
+ _v7Verdict: "DORMANT",
42938
+ _v7Lift: 1,
42939
+ _v7Recall: 0,
42940
+ _v7FpRate: 0,
42941
+ _v7Precision: 0,
42942
+ _v8Verdict: "USEFUL",
42943
+ _v8Lift: 19.29
41385
42944
  },
41386
- "ai/compression-profile": {
41387
- recall: 0.3139,
41388
- fpRate: 0.1489,
41389
- ratio: 2.11,
41390
- precision: 0.732,
41391
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42945
+ "security/dangerous-cors": {
42946
+ recall: 5e-4,
42947
+ fpRate: 4e-4,
42948
+ ratio: 1721.87,
42949
+ precision: 0.6079,
42950
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41392
42951
  verdict: "USEFUL",
41393
- _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.",
41394
- aiSpecific: true
42952
+ _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).",
42953
+ aiSpecific: true,
42954
+ _v7Verdict: "USEFUL",
42955
+ _v7Lift: 1257.16,
42956
+ _v7Recall: 5e-4,
42957
+ _v7FpRate: 5e-4,
42958
+ _v7Precision: 0.5758,
42959
+ _v8Verdict: "USEFUL",
42960
+ _v8Lift: 11365.57
41395
42961
  },
41396
- "ai/tailwind-color-overuse": {
41397
- recall: 0.0216,
41398
- fpRate: 52e-4,
41399
- ratio: 4.16,
41400
- precision: 0.8436,
41401
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42962
+ "security/eval": {
42963
+ recall: 1e-4,
42964
+ fpRate: 2e-4,
42965
+ ratio: 1929.18,
42966
+ precision: 0.4286,
42967
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
42968
+ verdict: "OK",
42969
+ _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).",
42970
+ aiSpecific: false,
42971
+ _v7Verdict: "DORMANT",
42972
+ _v7Lift: 1,
42973
+ _v7Recall: 0,
42974
+ _v7FpRate: 0,
42975
+ _v7Precision: 0,
42976
+ _v8Verdict: "OK",
42977
+ _v8Lift: 525.51
42978
+ },
42979
+ "security/exposed-env-var": {
42980
+ recall: 6e-4,
42981
+ fpRate: 5e-4,
42982
+ ratio: 1055.81,
42983
+ precision: 0.5696,
42984
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41402
42985
  verdict: "USEFUL",
41403
- _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.",
41404
- aiSpecific: true
42986
+ _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).",
42987
+ aiSpecific: false,
42988
+ _v7Verdict: "USEFUL",
42989
+ _v7Lift: 790.5,
42990
+ _v7Recall: 6e-4,
42991
+ _v7FpRate: 7e-4,
42992
+ _v7Precision: 0.5387,
42993
+ _v8Verdict: "USEFUL",
42994
+ _v8Lift: 4716.52
41405
42995
  },
41406
- "ai/default-react-stack": {
41407
- recall: 1e-3,
42996
+ "security/fail-open-auth": {
42997
+ recall: 0,
41408
42998
  fpRate: 0,
41409
- ratio: 99.99,
41410
- precision: 0.9957,
41411
- lastCalibratedAt: "2026-06-27T12:00:00Z",
42999
+ ratio: 99999,
43000
+ precision: 1,
43001
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41412
43002
  verdict: "USEFUL",
41413
- _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.",
41414
- aiSpecific: true
43003
+ _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.",
43004
+ aiSpecific: true,
43005
+ _v7Verdict: "USEFUL",
43006
+ _v7Lift: 99999,
43007
+ _v7Recall: 0,
43008
+ _v7FpRate: 0,
43009
+ _v7Precision: 1,
43010
+ _v8Verdict: "DORMANT",
43011
+ _v8Lift: 1,
43012
+ defaultOff: false
41415
43013
  },
41416
- "ai/library-reinvention": {
41417
- recall: 3e-4,
43014
+ "security/hardcoded-secret": {
43015
+ recall: 14e-4,
43016
+ fpRate: 6e-4,
43017
+ ratio: 1269.08,
43018
+ precision: 0.735,
43019
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43020
+ verdict: "USEFUL",
43021
+ _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).",
43022
+ aiSpecific: true,
43023
+ _v7Verdict: "USEFUL",
43024
+ _v7Lift: 916.92,
43025
+ _v7Recall: 13e-4,
43026
+ _v7FpRate: 8e-4,
43027
+ _v7Precision: 0.6899,
43028
+ _v8Verdict: "USEFUL",
43029
+ _v8Lift: 7935.57
43030
+ },
43031
+ "security/localstorage-token": {
43032
+ recall: 1e-4,
41418
43033
  fpRate: 0,
41419
- ratio: 9.88,
41420
- precision: 0.9275,
41421
- lastCalibratedAt: "2026-06-27T12:00:00Z",
43034
+ ratio: 99999,
43035
+ precision: 1,
43036
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41422
43037
  verdict: "USEFUL",
41423
- _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.",
41424
- aiSpecific: true
43038
+ _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).",
43039
+ aiSpecific: false,
43040
+ _v7Verdict: "DORMANT",
43041
+ _v7Lift: 1,
43042
+ _v7Recall: 0,
43043
+ _v7FpRate: 0,
43044
+ _v7Precision: 0,
43045
+ _v8Verdict: "USEFUL",
43046
+ _v8Lift: 99999
41425
43047
  },
41426
- "ai/state-default-overuse": {
41427
- recall: 29e-4,
41428
- fpRate: 9e-4,
41429
- ratio: 3.42,
41430
- precision: 0.8161,
41431
- lastCalibratedAt: "2026-06-27T12:00:00Z",
43048
+ "security/missing-auth-check": {
43049
+ recall: 5e-4,
43050
+ fpRate: 0,
43051
+ ratio: 99999,
43052
+ precision: 1,
43053
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41432
43054
  verdict: "USEFUL",
41433
- _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.",
41434
- aiSpecific: true
43055
+ _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).",
43056
+ aiSpecific: false,
43057
+ _v7Verdict: "DORMANT",
43058
+ _v7Lift: 1,
43059
+ _v7Recall: 0,
43060
+ _v7FpRate: 0,
43061
+ _v7Precision: 0,
43062
+ _v8Verdict: "USEFUL",
43063
+ _v8Lift: 99999
41435
43064
  },
41436
- "ai/fetch-default-overuse": {
41437
- recall: 28e-4,
41438
- fpRate: 4e-4,
41439
- ratio: 6.76,
41440
- precision: 0.8976,
41441
- lastCalibratedAt: "2026-06-27T12:00:00Z",
43065
+ "security/public-admin-route": {
43066
+ recall: 38e-4,
43067
+ fpRate: 38e-4,
43068
+ ratio: 142.2,
43069
+ precision: 0.5376,
43070
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41442
43071
  verdict: "USEFUL",
41443
- _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.",
41444
- aiSpecific: true
43072
+ _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).",
43073
+ aiSpecific: false,
43074
+ _v7Verdict: "DORMANT",
43075
+ _v7Lift: 1,
43076
+ _v7Recall: 0,
43077
+ _v7FpRate: 0,
43078
+ _v7Precision: 0,
43079
+ _v8Verdict: "USEFUL",
43080
+ _v8Lift: 38.74
41445
43081
  },
41446
- "ai/console-debug-storm": {
41447
- recall: 8e-3,
41448
- fpRate: 9e-4,
41449
- ratio: 8.43,
41450
- precision: 0.9161,
41451
- lastCalibratedAt: "2026-06-27T12:00:00Z",
43082
+ "security/sql-construction": {
43083
+ recall: 32e-4,
43084
+ fpRate: 15e-4,
43085
+ ratio: 485.42,
43086
+ precision: 0.7183,
43087
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41452
43088
  verdict: "USEFUL",
41453
- _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.",
41454
- aiSpecific: true
43089
+ _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).",
43090
+ aiSpecific: true,
43091
+ _v7Verdict: "USEFUL",
43092
+ _v7Lift: 370.52,
43093
+ _v7Recall: 3e-3,
43094
+ _v7FpRate: 18e-4,
43095
+ _v7Precision: 0.6788,
43096
+ _v8Verdict: "USEFUL",
43097
+ _v8Lift: 1608.86
41455
43098
  },
41456
- "db/missing-fk-index": {
41457
- recall: 0,
43099
+ "security/target-blank-no-noopener": {
43100
+ recall: 4e-4,
41458
43101
  fpRate: 0,
41459
- ratio: 0,
41460
- precision: 0,
41461
- lastCalibratedAt: "2026-06-30T00:00:00Z",
41462
- verdict: "DORMANT",
41463
- defaultOff: true,
41464
- _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.)",
41465
- aiSpecific: false
43102
+ ratio: 26141.63,
43103
+ precision: 0.9333,
43104
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43105
+ verdict: "USEFUL",
43106
+ _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).",
43107
+ aiSpecific: false,
43108
+ _v7Verdict: "DORMANT",
43109
+ _v7Lift: 1,
43110
+ _v7Recall: 0,
43111
+ _v7FpRate: 0,
43112
+ _v7Precision: 0,
43113
+ _v8Verdict: "USEFUL",
43114
+ _v8Lift: 7121.02
41466
43115
  },
41467
- "db/duplicate-index": {
41468
- recall: 0,
43116
+ "security/unsafe-html-render": {
43117
+ recall: 13e-4,
43118
+ fpRate: 11e-4,
43119
+ ratio: 513.12,
43120
+ precision: 0.574,
43121
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43122
+ verdict: "USEFUL",
43123
+ _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).",
43124
+ aiSpecific: false,
43125
+ _v7Verdict: "USEFUL",
43126
+ _v7Lift: 757.74,
43127
+ _v7Recall: 13e-4,
43128
+ _v7FpRate: 9e-4,
43129
+ _v7Precision: 0.661,
43130
+ _v8Verdict: "OK",
43131
+ _v8Lift: 201.44
43132
+ },
43133
+ "test/duplicate-setup": {
43134
+ recall: 1e-4,
41469
43135
  fpRate: 0,
41470
- ratio: 0,
41471
- precision: 0,
41472
- lastCalibratedAt: "2026-06-30T00:00:00Z",
41473
- verdict: "DORMANT",
41474
- defaultOff: true,
41475
- _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.)",
41476
- aiSpecific: false
43136
+ ratio: 51016.19,
43137
+ precision: 0.8095,
43138
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43139
+ verdict: "USEFUL",
43140
+ _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).",
43141
+ aiSpecific: true,
43142
+ _v7Verdict: "USEFUL",
43143
+ _v7Lift: 50348.67,
43144
+ _v7Recall: 1e-4,
43145
+ _v7FpRate: 0,
43146
+ _v7Precision: 0.8235,
43147
+ _v8Verdict: "USEFUL",
43148
+ _v8Lift: 51500.25
41477
43149
  },
41478
- "db/missing-not-null": {
43150
+ "test/fake-placeholder": {
43151
+ recall: 51e-4,
43152
+ fpRate: 15e-4,
43153
+ ratio: 547.47,
43154
+ precision: 0.8014,
43155
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43156
+ verdict: "USEFUL",
43157
+ _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).",
43158
+ aiSpecific: true,
43159
+ _v7Verdict: "USEFUL",
43160
+ _v7Lift: 418.76,
43161
+ _v7Recall: 53e-4,
43162
+ _v7FpRate: 19e-4,
43163
+ _v7Precision: 0.7854,
43164
+ _v8Verdict: "USEFUL",
43165
+ _v8Lift: 2477.4
43166
+ },
43167
+ "test/missing-edge-case": {
41479
43168
  recall: 0,
41480
43169
  fpRate: 0,
41481
43170
  ratio: 0,
41482
43171
  precision: 0,
41483
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43172
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41484
43173
  verdict: "DORMANT",
41485
- defaultOff: true,
41486
- _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.)",
41487
- aiSpecific: false
43174
+ _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.",
43175
+ aiSpecific: true,
43176
+ _v7Verdict: "DORMANT",
43177
+ _v7Lift: 0,
43178
+ _v7Recall: 0,
43179
+ _v7FpRate: 0,
43180
+ _v7Precision: 0,
43181
+ _v8Verdict: "DORMANT",
43182
+ _v8Lift: 1,
43183
+ defaultOff: true
41488
43184
  },
41489
- "db/enum-sprawl": {
43185
+ "test/weak-assertion": {
43186
+ recall: 0.0417,
43187
+ fpRate: 67e-4,
43188
+ ratio: 131.62,
43189
+ precision: 0.8793,
43190
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43191
+ verdict: "USEFUL",
43192
+ _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).",
43193
+ aiSpecific: true,
43194
+ _v7Verdict: "USEFUL",
43195
+ _v7Lift: 99.9,
43196
+ _v7Recall: 0.0418,
43197
+ _v7FpRate: 86e-4,
43198
+ _v7Precision: 0.8622,
43199
+ _v8Verdict: "USEFUL",
43200
+ _v8Lift: 651.94
43201
+ },
43202
+ "ts/enum-vs-as-const": {
41490
43203
  recall: 0,
41491
43204
  fpRate: 0,
41492
- ratio: 0,
43205
+ ratio: 1,
41493
43206
  precision: 0,
41494
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43207
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41495
43208
  verdict: "DORMANT",
41496
- defaultOff: true,
41497
- _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.)",
41498
- aiSpecific: false
43209
+ _calibrationNote: "v0.19: new rule (Uses `enum` \u2014 modern TS prefers `as const`). Not yet calibrated. Scheduled for v9 calibration.",
43210
+ aiSpecific: true,
43211
+ _v7Verdict: "DORMANT",
43212
+ _v7Lift: 1,
43213
+ _v7Recall: 0,
43214
+ _v7FpRate: 0,
43215
+ _v7Precision: 0,
43216
+ _v8Verdict: "DORMANT",
43217
+ _v8Lift: 1,
43218
+ defaultOff: true
41499
43219
  },
41500
- "db/naming-inconsistency": {
43220
+ "ts/excessive-type-assertion": {
41501
43221
  recall: 0,
41502
43222
  fpRate: 0,
41503
- ratio: 0,
43223
+ ratio: 1,
41504
43224
  precision: 0,
41505
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43225
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41506
43226
  verdict: "DORMANT",
41507
- defaultOff: true,
41508
- _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.)",
41509
- aiSpecific: false
43227
+ _calibrationNote: "v0.19: new rule (Function with >3 `as` assertions \u2014 AI fighting the type system). Not yet calibrated. Scheduled for v9 calibration.",
43228
+ aiSpecific: true,
43229
+ _v7Verdict: "DORMANT",
43230
+ _v7Lift: 1,
43231
+ _v7Recall: 0,
43232
+ _v7FpRate: 0,
43233
+ _v7Precision: 0,
43234
+ _v8Verdict: "DORMANT",
43235
+ _v8Lift: 1,
43236
+ defaultOff: true
41510
43237
  },
41511
- "db/sql-concat": {
43238
+ "ts/import-type-misuse": {
41512
43239
  recall: 0,
41513
43240
  fpRate: 0,
41514
- ratio: 0,
43241
+ ratio: 1,
41515
43242
  precision: 0,
41516
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43243
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41517
43244
  verdict: "DORMANT",
41518
- defaultOff: true,
41519
- _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.)",
41520
- aiSpecific: true
43245
+ _calibrationNote: "v0.19: new rule (Inline `import { type X }` \u2014 prefer separate `import type`). Not yet calibrated. Scheduled for v9 calibration.",
43246
+ aiSpecific: true,
43247
+ _v7Verdict: "DORMANT",
43248
+ _v7Lift: 1,
43249
+ _v7Recall: 0,
43250
+ _v7FpRate: 0,
43251
+ _v7Precision: 0,
43252
+ _v8Verdict: "DORMANT",
43253
+ _v8Lift: 1,
43254
+ defaultOff: true
41521
43255
  },
41522
- "dead/unused-import": {
43256
+ "ts/never-vs-unknown": {
41523
43257
  recall: 0,
41524
43258
  fpRate: 0,
41525
- ratio: 0,
43259
+ ratio: 1,
41526
43260
  precision: 0,
41527
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43261
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41528
43262
  verdict: "DORMANT",
41529
- defaultOff: true,
41530
- _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.",
41531
- aiSpecific: true
43263
+ _calibrationNote: "v0.19: new rule (Return type `never` but body has no throw/loop/exit). Not yet calibrated. Scheduled for v9 calibration.",
43264
+ aiSpecific: true,
43265
+ _v7Verdict: "DORMANT",
43266
+ _v7Lift: 1,
43267
+ _v7Recall: 0,
43268
+ _v7FpRate: 0,
43269
+ _v7Precision: 0,
43270
+ _v8Verdict: "DORMANT",
43271
+ _v8Lift: 1,
43272
+ defaultOff: true
41532
43273
  },
41533
- "dead/unused-local": {
43274
+ "ts/optional-chain-overuse": {
41534
43275
  recall: 0,
41535
43276
  fpRate: 0,
41536
- ratio: 0,
43277
+ ratio: 1,
41537
43278
  precision: 0,
41538
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43279
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41539
43280
  verdict: "DORMANT",
41540
- defaultOff: true,
41541
- _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).",
41542
- aiSpecific: true
43281
+ _calibrationNote: "v0.19: new rule (Optional chain depth >= 5 \u2014 AI chains ?. rather than narrowing). Not yet calibrated. Scheduled for v9 calibration.",
43282
+ aiSpecific: true,
43283
+ _v7Verdict: "DORMANT",
43284
+ _v7Lift: 1,
43285
+ _v7Recall: 0,
43286
+ _v7FpRate: 0,
43287
+ _v7Precision: 0,
43288
+ _v8Verdict: "DORMANT",
43289
+ _v8Lift: 1,
43290
+ defaultOff: true
41543
43291
  },
41544
- "dead/unused-parameter": {
43292
+ "typo/calc-fontsize": {
41545
43293
  recall: 0,
41546
43294
  fpRate: 0,
41547
43295
  ratio: 0,
41548
43296
  precision: 0,
41549
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43297
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41550
43298
  verdict: "DORMANT",
41551
- defaultOff: true,
41552
- _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.",
41553
- aiSpecific: true
43299
+ _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.",
43300
+ aiSpecific: false,
43301
+ _v7Verdict: "DORMANT",
43302
+ _v7Lift: 0,
43303
+ _v7Recall: 0,
43304
+ _v7FpRate: 0,
43305
+ _v7Precision: 0,
43306
+ _v8Verdict: "DORMANT",
43307
+ _v8Lift: 1,
43308
+ defaultOff: true
41554
43309
  },
41555
- "dead/dead-branch": {
43310
+ "typo/calc-raw-px": {
41556
43311
  recall: 0,
41557
43312
  fpRate: 0,
41558
- ratio: 0,
41559
- precision: 0,
41560
- lastCalibratedAt: "2026-06-30T00:00:00Z",
41561
- verdict: "DORMANT",
41562
- defaultOff: true,
41563
- _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.",
41564
- aiSpecific: true
43313
+ ratio: 210066.67,
43314
+ precision: 0.8333,
43315
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43316
+ verdict: "USEFUL",
43317
+ _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).",
43318
+ aiSpecific: false,
43319
+ _v7Verdict: "USEFUL",
43320
+ _v7Lift: 137559.75,
43321
+ _v7Recall: 0,
43322
+ _v7FpRate: 0,
43323
+ _v7Precision: 0.75,
43324
+ _v8Verdict: "USEFUL",
43325
+ _v8Lift: 99999
41565
43326
  },
41566
- "dead/unreachable": {
43327
+ "typo/clamp-offscale": {
41567
43328
  recall: 0,
41568
43329
  fpRate: 0,
41569
43330
  ratio: 0,
41570
43331
  precision: 0,
41571
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43332
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41572
43333
  verdict: "DORMANT",
41573
- defaultOff: true,
41574
- _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.",
41575
- aiSpecific: true
43334
+ _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.",
43335
+ aiSpecific: false,
43336
+ _v7Verdict: "DORMANT",
43337
+ _v7Lift: 0,
43338
+ _v7Recall: 0,
43339
+ _v7FpRate: 0,
43340
+ _v7Precision: 0,
43341
+ _v8Verdict: "DORMANT",
43342
+ _v8Lift: 1,
43343
+ defaultOff: true
41576
43344
  },
41577
- "docs/stale-package-reference": {
43345
+ "typo/math-button-label-uniformity": {
43346
+ recall: 1e-4,
43347
+ fpRate: 1e-4,
43348
+ ratio: 6894.19,
43349
+ precision: 0.629,
43350
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43351
+ verdict: "USEFUL",
43352
+ _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).",
43353
+ aiSpecific: false,
43354
+ _v7Verdict: "USEFUL",
43355
+ _v7Lift: 5571.66,
43356
+ _v7Recall: 2e-4,
43357
+ _v7FpRate: 1e-4,
43358
+ _v7Precision: 0.6379,
43359
+ _v8Verdict: "USEFUL",
43360
+ _v8Lift: 17166.75
43361
+ },
43362
+ "typo/math-cta-vocabulary": {
41578
43363
  recall: 0,
41579
43364
  fpRate: 0,
41580
43365
  ratio: 0,
41581
43366
  precision: 0,
41582
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43367
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41583
43368
  verdict: "DORMANT",
41584
- defaultOff: true,
41585
- _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.)",
41586
- aiSpecific: false
43369
+ _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.",
43370
+ aiSpecific: true,
43371
+ _v7Verdict: "DORMANT",
43372
+ _v7Lift: 0,
43373
+ _v7Recall: 0,
43374
+ _v7FpRate: 0,
43375
+ _v7Precision: 0,
43376
+ _v8Verdict: "DORMANT",
43377
+ _v8Lift: 1,
43378
+ defaultOff: true
41587
43379
  },
41588
- "docs/stale-function-reference": {
41589
- recall: 0,
43380
+ "typo/placeholder-text": {
43381
+ recall: 1e-4,
41590
43382
  fpRate: 0,
41591
- ratio: 0,
41592
- precision: 0,
41593
- lastCalibratedAt: "2026-06-30T00:00:00Z",
41594
- verdict: "DORMANT",
41595
- defaultOff: true,
41596
- _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.)",
41597
- aiSpecific: false
43383
+ ratio: 17330.5,
43384
+ precision: 0.6875,
43385
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43386
+ verdict: "USEFUL",
43387
+ _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).",
43388
+ aiSpecific: false,
43389
+ _v7Verdict: "DORMANT",
43390
+ _v7Lift: 1,
43391
+ _v7Recall: 0,
43392
+ _v7FpRate: 0,
43393
+ _v7Precision: 0,
43394
+ _v8Verdict: "USEFUL",
43395
+ _v8Lift: 4720.86
41598
43396
  },
41599
- "docs/expired-code-example": {
43397
+ "visual/arbitrary-escape": {
43398
+ recall: 26e-4,
43399
+ fpRate: 7e-4,
43400
+ ratio: 1219.67,
43401
+ precision: 0.8177,
43402
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43403
+ verdict: "USEFUL",
43404
+ _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).",
43405
+ aiSpecific: true,
43406
+ _v7Verdict: "USEFUL",
43407
+ _v7Lift: 846.78,
43408
+ _v7Recall: 25e-4,
43409
+ _v7FpRate: 9e-4,
43410
+ _v7Precision: 0.7802,
43411
+ _v8Verdict: "USEFUL",
43412
+ _v8Lift: 99999
43413
+ },
43414
+ "visual/clamp-soup": {
41600
43415
  recall: 0,
41601
43416
  fpRate: 0,
41602
43417
  ratio: 0,
41603
43418
  precision: 0,
41604
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43419
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41605
43420
  verdict: "DORMANT",
41606
- defaultOff: true,
41607
- _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.)",
41608
- aiSpecific: false
43421
+ _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.",
43422
+ aiSpecific: true,
43423
+ _v7Verdict: "DORMANT",
43424
+ _v7Lift: 0,
43425
+ _v7Recall: 0,
43426
+ _v7FpRate: 0,
43427
+ _v7Precision: 0,
43428
+ _v8Verdict: "DORMANT",
43429
+ _v8Lift: 1,
43430
+ defaultOff: true
41609
43431
  },
41610
- "docs/broken-link": {
43432
+ "visual/generic-centering": {
41611
43433
  recall: 0,
41612
43434
  fpRate: 0,
41613
43435
  ratio: 0,
41614
43436
  precision: 0,
41615
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43437
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41616
43438
  verdict: "DORMANT",
41617
- defaultOff: true,
41618
- _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.)",
41619
- aiSpecific: false
43439
+ _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.",
43440
+ aiSpecific: true,
43441
+ _v7Verdict: "DORMANT",
43442
+ _v7Lift: 0,
43443
+ _v7Recall: 0,
43444
+ _v7FpRate: 0,
43445
+ _v7Precision: 0,
43446
+ _v8Verdict: "DORMANT",
43447
+ _v8Lift: 1,
43448
+ defaultOff: true
41620
43449
  },
41621
- "security/eval": {
41622
- recall: 0,
43450
+ "visual/inline-style-dominance": {
43451
+ recall: 0.0103,
43452
+ fpRate: 52e-4,
43453
+ ratio: 134.59,
43454
+ precision: 0.6983,
43455
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43456
+ verdict: "USEFUL",
43457
+ _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).",
43458
+ aiSpecific: false,
43459
+ _v7Verdict: "USEFUL",
43460
+ _v7Lift: 98.17,
43461
+ _v7Recall: 97e-4,
43462
+ _v7FpRate: 67e-4,
43463
+ _v7Precision: 0.6535,
43464
+ _v8Verdict: "USEFUL",
43465
+ _v8Lift: 704.71
43466
+ },
43467
+ "visual/math-color-cluster": {
43468
+ recall: 2e-4,
41623
43469
  fpRate: 0,
41624
- ratio: 0,
41625
- precision: 0,
41626
- lastCalibratedAt: "2026-06-30T00:00:00Z",
41627
- verdict: "DORMANT",
41628
- defaultOff: true,
41629
- _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.)",
41630
- aiSpecific: false
43470
+ ratio: 46814.86,
43471
+ precision: 0.9286,
43472
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43473
+ verdict: "USEFUL",
43474
+ _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).",
43475
+ aiSpecific: true,
43476
+ _v7Verdict: "USEFUL",
43477
+ _v7Lift: 33771.28,
43478
+ _v7Recall: 2e-4,
43479
+ _v7FpRate: 0,
43480
+ _v7Precision: 0.9206,
43481
+ _v8Verdict: "USEFUL",
43482
+ _v8Lift: 99999
41631
43483
  },
41632
- "security/localstorage-token": {
43484
+ "visual/math-default-font": {
43485
+ recall: 16e-4,
43486
+ fpRate: 3e-4,
43487
+ ratio: 3035.16,
43488
+ precision: 0.8669,
43489
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43490
+ verdict: "USEFUL",
43491
+ _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).",
43492
+ aiSpecific: true,
43493
+ _v7Verdict: "USEFUL",
43494
+ _v7Lift: 2105.64,
43495
+ _v7Recall: 13e-4,
43496
+ _v7FpRate: 4e-4,
43497
+ _v7Precision: 0.8151,
43498
+ _v8Verdict: "USEFUL",
43499
+ _v8Lift: 68229.63
43500
+ },
43501
+ "visual/math-font-entropy": {
43502
+ recall: 52e-4,
43503
+ fpRate: 1e-3,
43504
+ ratio: 869.95,
43505
+ precision: 0.8593,
43506
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43507
+ verdict: "USEFUL",
43508
+ _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).",
43509
+ aiSpecific: true,
43510
+ _v7Verdict: "USEFUL",
43511
+ _v7Lift: 600.09,
43512
+ _v7Recall: 45e-4,
43513
+ _v7FpRate: 14e-4,
43514
+ _v7Precision: 0.8114,
43515
+ _v8Verdict: "USEFUL",
43516
+ _v8Lift: 68516.08
43517
+ },
43518
+ "visual/math-gradient-hue-rotation": {
41633
43519
  recall: 0,
41634
43520
  fpRate: 0,
41635
43521
  ratio: 0,
41636
43522
  precision: 0,
41637
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43523
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41638
43524
  verdict: "DORMANT",
41639
- defaultOff: true,
41640
- _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.)",
41641
- aiSpecific: false
43525
+ _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.",
43526
+ aiSpecific: true,
43527
+ _v7Verdict: "DORMANT",
43528
+ _v7Lift: 0,
43529
+ _v7Recall: 0,
43530
+ _v7FpRate: 0,
43531
+ _v7Precision: 0,
43532
+ _v8Verdict: "DORMANT",
43533
+ _v8Lift: 1,
43534
+ defaultOff: true
41642
43535
  },
41643
- "security/target-blank-no-noopener": {
41644
- recall: 0,
43536
+ "visual/math-rounded-entropy": {
43537
+ recall: 38e-4,
43538
+ fpRate: 2e-4,
43539
+ ratio: 3785.45,
43540
+ precision: 0.9461,
43541
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43542
+ verdict: "USEFUL",
43543
+ _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).",
43544
+ aiSpecific: true,
43545
+ _v7Verdict: "USEFUL",
43546
+ _v7Lift: 2762.74,
43547
+ _v7Recall: 37e-4,
43548
+ _v7FpRate: 3e-4,
43549
+ _v7Precision: 0.9339,
43550
+ _v8Verdict: "USEFUL",
43551
+ _v8Lift: 68368.45
43552
+ },
43553
+ "visual/math-spacing-entropy": {
43554
+ recall: 18e-4,
43555
+ fpRate: 4e-4,
43556
+ ratio: 1898.99,
43557
+ precision: 0.8287,
43558
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43559
+ verdict: "USEFUL",
43560
+ _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).",
43561
+ aiSpecific: true,
43562
+ _v7Verdict: "USEFUL",
43563
+ _v7Lift: 1339.22,
43564
+ _v7Recall: 18e-4,
43565
+ _v7FpRate: 6e-4,
43566
+ _v7Precision: 0.7959,
43567
+ _v8Verdict: "USEFUL",
43568
+ _v8Lift: 68031.19
43569
+ },
43570
+ "visual/naturalness-anomaly": {
43571
+ recall: 0.1729,
43572
+ fpRate: 0.0687,
43573
+ ratio: 10.86,
43574
+ precision: 0.746,
43575
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43576
+ verdict: "USEFUL",
43577
+ _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).",
43578
+ aiSpecific: true,
43579
+ _v7Verdict: "USEFUL",
43580
+ _v7Lift: 12.5,
43581
+ _v7Recall: 0.1659,
43582
+ _v7FpRate: 0.0621,
43583
+ _v7Precision: 0.7755,
43584
+ _v8Verdict: "USEFUL",
43585
+ _v8Lift: 7.64
43586
+ },
43587
+ "visual/radius-scale-violation": {
43588
+ recall: 4e-4,
41645
43589
  fpRate: 0,
41646
- ratio: 0,
41647
- precision: 0,
41648
- lastCalibratedAt: "2026-06-30T00:00:00Z",
41649
- verdict: "DORMANT",
41650
- defaultOff: true,
41651
- _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.)',
41652
- aiSpecific: false
43590
+ ratio: 82131.33,
43591
+ precision: 0.9774,
43592
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43593
+ verdict: "USEFUL",
43594
+ _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.",
43595
+ aiSpecific: false,
43596
+ _v7Verdict: "USEFUL",
43597
+ _v7Lift: 59285.01,
43598
+ _v7Recall: 4e-4,
43599
+ _v7FpRate: 0,
43600
+ _v7Precision: 0.9697,
43601
+ _v8Verdict: "USEFUL",
43602
+ _v8Lift: 99999,
43603
+ defaultOff: false
41653
43604
  },
41654
- "wcag/missing-alt": {
43605
+ "visual/spacing-scale-violation": {
43606
+ recall: 86e-4,
43607
+ fpRate: 28e-4,
43608
+ ratio: 273.97,
43609
+ precision: 0.7792,
43610
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43611
+ verdict: "USEFUL",
43612
+ _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).",
43613
+ aiSpecific: false,
43614
+ _v7Verdict: "USEFUL",
43615
+ _v7Lift: 187.83,
43616
+ _v7Recall: 84e-4,
43617
+ _v7FpRate: 39e-4,
43618
+ _v7Precision: 0.7342,
43619
+ _v8Verdict: "USEFUL",
43620
+ _v8Lift: 99999
43621
+ },
43622
+ "wcag/dragging-movements": {
41655
43623
  recall: 0,
41656
43624
  fpRate: 0,
41657
- ratio: 0,
41658
- precision: 0,
41659
- lastCalibratedAt: "2026-06-30T00:00:00Z",
41660
- verdict: "DORMANT",
41661
- defaultOff: true,
41662
- _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.)',
41663
- aiSpecific: false
43625
+ ratio: 33610.67,
43626
+ precision: 0.4,
43627
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43628
+ verdict: "OK",
43629
+ _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).",
43630
+ aiSpecific: false,
43631
+ _v7Verdict: "OK",
43632
+ _v7Lift: 24455.07,
43633
+ _v7Recall: 0,
43634
+ _v7FpRate: 0,
43635
+ _v7Precision: 0.4,
43636
+ _v8Verdict: "DORMANT",
43637
+ _v8Lift: 1
41664
43638
  },
41665
- "typo/placeholder-text": {
43639
+ "wcag/focus-appearance": {
43640
+ recall: 28e-4,
43641
+ fpRate: 1e-4,
43642
+ ratio: 8397.24,
43643
+ precision: 0.966,
43644
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43645
+ verdict: "USEFUL",
43646
+ _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).",
43647
+ aiSpecific: false,
43648
+ _v7Verdict: "USEFUL",
43649
+ _v7Lift: 7353.82,
43650
+ _v7Recall: 26e-4,
43651
+ _v7FpRate: 1e-4,
43652
+ _v7Precision: 0.9623,
43653
+ _v8Verdict: "USEFUL",
43654
+ _v8Lift: 13418.41
43655
+ },
43656
+ "wcag/focus-obscured": {
43657
+ recall: 33e-4,
43658
+ fpRate: 7e-4,
43659
+ ratio: 1214.21,
43660
+ precision: 0.8478,
43661
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43662
+ verdict: "USEFUL",
43663
+ _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).",
43664
+ aiSpecific: false,
43665
+ _v7Verdict: "USEFUL",
43666
+ _v7Lift: 859.38,
43667
+ _v7Recall: 34e-4,
43668
+ _v7FpRate: 1e-3,
43669
+ _v7Precision: 0.82,
43670
+ _v8Verdict: "USEFUL",
43671
+ _v8Lift: 68293.81
43672
+ },
43673
+ "wcag/missing-alt": {
43674
+ recall: 11e-4,
43675
+ fpRate: 7e-4,
43676
+ ratio: 935.33,
43677
+ precision: 0.6456,
43678
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
43679
+ verdict: "USEFUL",
43680
+ _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).",
43681
+ aiSpecific: false,
43682
+ _v7Verdict: "DORMANT",
43683
+ _v7Lift: 1,
43684
+ _v7Recall: 0,
43685
+ _v7FpRate: 0,
43686
+ _v7Precision: 0,
43687
+ _v8Verdict: "USEFUL",
43688
+ _v8Lift: 254.79
43689
+ },
43690
+ "wcag/target-size": {
41666
43691
  recall: 0,
41667
43692
  fpRate: 0,
41668
43693
  ratio: 0,
41669
43694
  precision: 0,
41670
- lastCalibratedAt: "2026-06-30T00:00:00Z",
43695
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
41671
43696
  verdict: "DORMANT",
41672
- defaultOff: true,
41673
- _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.)",
41674
- aiSpecific: false
43697
+ _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.",
43698
+ aiSpecific: false,
43699
+ _v7Verdict: "DORMANT",
43700
+ _v7Lift: 0,
43701
+ _v7Recall: 0,
43702
+ _v7FpRate: 0,
43703
+ _v7Precision: 0,
43704
+ _v8Verdict: "DORMANT",
43705
+ _v8Lift: 1,
43706
+ defaultOff: true
41675
43707
  }
41676
43708
  };
41677
43709
 
@@ -41710,7 +43742,6 @@ async function scanFile(filePath, config, registry, cwd = process.cwd()) {
41710
43742
  ".kt",
41711
43743
  ".kts",
41712
43744
  ".dart",
41713
- ".rs",
41714
43745
  ".cpp",
41715
43746
  ".cc",
41716
43747
  ".cxx",