slopbrick 0.18.7 → 0.18.9

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.
package/dist/index.cjs CHANGED
@@ -36,7 +36,7 @@ var VERSION;
36
36
  var init_header = __esm({
37
37
  "src/types/_header.ts"() {
38
38
  "use strict";
39
- VERSION = "0.18.7";
39
+ VERSION = "0.18.9";
40
40
  }
41
41
  });
42
42
 
@@ -28238,6 +28238,20 @@ var init_unreachable = __esm({
28238
28238
  });
28239
28239
 
28240
28240
  // src/rules/dead/unused-import.ts
28241
+ function collectRustReferencedNames(source) {
28242
+ const out = /* @__PURE__ */ new Set();
28243
+ for (const m of source.matchAll(/\b([A-Za-z_][A-Za-z0-9_]*)\b/g)) {
28244
+ out.add(m[1]);
28245
+ }
28246
+ return out;
28247
+ }
28248
+ function stripUseDeclarations(source) {
28249
+ let out = source;
28250
+ out = out.replace(/^\s*use\s+[\s\S]*?;\s*$/gm, "");
28251
+ out = out.replace(/\/\/[^\n]*/g, "");
28252
+ out = out.replace(/\/\*[\s\S]*?\*\//g, "");
28253
+ return out;
28254
+ }
28241
28255
  var unusedImportRule;
28242
28256
  var init_unused_import = __esm({
28243
28257
  "src/rules/dead/unused-import.ts"() {
@@ -28273,6 +28287,26 @@ var init_unused_import = __esm({
28273
28287
  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.`
28274
28288
  });
28275
28289
  }
28290
+ if (facts.v2.rustFile) {
28291
+ const strippedSource = stripUseDeclarations(facts.v2._source ?? "");
28292
+ const referenced = collectRustReferencedNames(strippedSource);
28293
+ for (const imp of facts.v2.rustFile.imports) {
28294
+ for (const nameEntry of imp.names) {
28295
+ if (referenced.has(nameEntry.name)) continue;
28296
+ const source = ` from '${imp.path}'`;
28297
+ issues.push({
28298
+ ruleId: "dead/unused-import",
28299
+ category: "logic",
28300
+ severity: "low",
28301
+ aiSpecific: true,
28302
+ message: `Unused import: '${nameEntry.name}'${source}`,
28303
+ line: imp.line,
28304
+ column: imp.column,
28305
+ 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)].`
28306
+ });
28307
+ }
28308
+ }
28309
+ }
28276
28310
  return issues;
28277
28311
  }
28278
28312
  });
@@ -29015,10 +29049,67 @@ var init_dart = __esm({
29015
29049
  }
29016
29050
  });
29017
29051
 
29052
+ // src/engine/parser-rust.ts
29053
+ function getRustParser() {
29054
+ if (cachedParser) return { ok: true, parser: cachedParser };
29055
+ if (loadError) return { ok: false, error: loadError };
29056
+ try {
29057
+ rustLanguage = import_tree_sitter_rust.default;
29058
+ if (!rustLanguage || typeof rustLanguage !== "object") {
29059
+ throw new Error("tree-sitter-rust: language export is missing or malformed");
29060
+ }
29061
+ const parser = new import_tree_sitter.default();
29062
+ parser.setLanguage(rustLanguage);
29063
+ cachedParser = parser;
29064
+ return { ok: true, parser };
29065
+ } catch (err) {
29066
+ loadError = err instanceof Error ? err : new Error(String(err));
29067
+ return { ok: false, error: loadError };
29068
+ }
29069
+ }
29070
+ function effectiveParser() {
29071
+ if (forcedFailure) return { ok: false, error: forcedFailure };
29072
+ return getRustParser();
29073
+ }
29074
+ function parseRust(source) {
29075
+ const result = effectiveParser();
29076
+ if (!result.ok) return null;
29077
+ if (!source || source.trim() === "") return null;
29078
+ try {
29079
+ const rawTree = result.parser.parse(source);
29080
+ if (!rawTree) return null;
29081
+ const tree = rawTree;
29082
+ if (!tree || !tree.rootNode) return null;
29083
+ if (tree.rootNode.type === "ERROR" && tree.rootNode.childCount === 0) {
29084
+ return null;
29085
+ }
29086
+ return tree;
29087
+ } catch {
29088
+ return null;
29089
+ }
29090
+ }
29091
+ function isRustParserAvailable() {
29092
+ const result = getRustParser();
29093
+ return result.ok;
29094
+ }
29095
+ var import_tree_sitter, import_tree_sitter_rust, cachedParser, rustLanguage, loadError, forcedFailure;
29096
+ var init_parser_rust = __esm({
29097
+ "src/engine/parser-rust.ts"() {
29098
+ "use strict";
29099
+ import_tree_sitter = __toESM(require("tree-sitter"), 1);
29100
+ import_tree_sitter_rust = __toESM(require("tree-sitter-rust"), 1);
29101
+ cachedParser = null;
29102
+ rustLanguage = null;
29103
+ loadError = null;
29104
+ forcedFailure = null;
29105
+ }
29106
+ });
29107
+
29018
29108
  // src/engine/visitors/rust.ts
29019
29109
  var rust_exports = {};
29020
29110
  __export(rust_exports, {
29021
- extractRustPatterns: () => extractRustPatterns
29111
+ extractRustPatterns: () => extractRustPatterns,
29112
+ parseRustFile: () => parseRustFile
29022
29113
  });
29023
29114
  function extractRustPatterns(filePath, source) {
29024
29115
  const service = [];
@@ -29071,188 +29162,487 @@ function extractRustPatterns(filePath, source) {
29071
29162
  }
29072
29163
  return { service, route, ormModel };
29073
29164
  }
29074
- var SERVICE_SUFFIXES4, SERVICE_SUFFIX_GROUP4, RUST_SERVICE_STRUCT_RE, RUST_SERVICE_IMPL_RE, RUST_ACTIX_ROUTE_RE, RUST_AXUM_ROUTE_RE, RUST_DIESEL_RE, RUST_SEAORM_RE, RUST_SQLX_RE;
29075
- var init_rust = __esm({
29076
- "src/engine/visitors/rust.ts"() {
29077
- "use strict";
29078
- SERVICE_SUFFIXES4 = [
29079
- "Service",
29080
- "Manager",
29081
- "Handler",
29082
- "Repository",
29083
- "Controller",
29084
- "Helper",
29085
- "Factory",
29086
- "Provider",
29087
- "Store",
29088
- "API",
29089
- "Client",
29090
- "Adapter",
29091
- "Resolver",
29092
- "Mapper",
29093
- "Transformer",
29094
- "Serializer",
29095
- "Validator",
29096
- "Strategy",
29097
- "Facade",
29098
- "Decorator",
29099
- "Observer",
29100
- "Builder",
29101
- "Command",
29102
- "Processor",
29103
- "Worker",
29104
- "Job",
29105
- "Actor",
29106
- "Executor"
29107
- ];
29108
- SERVICE_SUFFIX_GROUP4 = `(?:${SERVICE_SUFFIXES4.join("|")})`;
29109
- RUST_SERVICE_STRUCT_RE = new RegExp(
29110
- `^(?:pub(?:\\(crate\\)|\\(super\\))?\\s+)?struct\\s+(\\w+?)${SERVICE_SUFFIX_GROUP4}?\\b`,
29111
- "gm"
29112
- );
29113
- RUST_SERVICE_IMPL_RE = new RegExp(
29114
- `^impl(?:<[^>]+>)?\\s+(?:${SERVICE_SUFFIX_GROUP4}\\s+for\\s+)?(\\w+?)${SERVICE_SUFFIX_GROUP4}?\\b`,
29115
- "gm"
29116
- );
29117
- RUST_ACTIX_ROUTE_RE = /#\[(?:get|post|put|delete|patch|head|route)\(\s*"(\/[^"]+)"\s*[\),]/g;
29118
- RUST_AXUM_ROUTE_RE = /\.route\(\s*"(\/[^"]+)"\s*,\s*(?:get|post|put|delete|patch)/g;
29119
- RUST_DIESEL_RE = /#\[derive\([^\]]*Queryable[^\]]*\)\][\s\S]{0,200}?struct\s+(\w+)/g;
29120
- RUST_SEAORM_RE = /#\[derive\([^\]]*DeriveEntityModel[^\]]*\)\][\s\S]{0,200}?struct\s+(\w+)/g;
29121
- RUST_SQLX_RE = /#\[derive\([^\]]*sqlx::FromRow[^\]]*\)\][\s\S]{0,200}?struct\s+(\w+)/g;
29165
+ function parseRustFile(filePath, source, options = {}) {
29166
+ const empty = {
29167
+ imports: [],
29168
+ functions: [],
29169
+ structs: [],
29170
+ traits: [],
29171
+ impls: []
29172
+ };
29173
+ if (!isRustParserAvailable() || options.forceFallback) {
29174
+ return empty;
29122
29175
  }
29123
- });
29124
-
29125
- // src/engine/visitors/cpp.ts
29126
- var cpp_exports = {};
29127
- __export(cpp_exports, {
29128
- extractCppPatterns: () => extractCppPatterns
29129
- });
29130
- function extractCppPatterns(filePath, source) {
29131
- const service = [];
29132
- const route = [];
29133
- const ormModel = [];
29134
- const seenService = /* @__PURE__ */ new Set();
29135
- for (const m of source.matchAll(CPP_SERVICE_RE)) {
29136
- const name = m[1];
29137
- if (seenService.has(name)) continue;
29138
- seenService.add(name);
29139
- service.push({ name, files: [filePath], imports: [] });
29176
+ const tree = parseRust(source);
29177
+ if (!tree) return empty;
29178
+ return walkRustTree(tree);
29179
+ }
29180
+ function walkRustTree(tree) {
29181
+ const ctx = { inTestConfig: false };
29182
+ const out = {
29183
+ imports: [],
29184
+ functions: [],
29185
+ structs: [],
29186
+ traits: [],
29187
+ impls: []
29188
+ };
29189
+ walkChildren(tree.rootNode, ctx, out);
29190
+ return out;
29191
+ }
29192
+ function walkChildren(node, ctx, out) {
29193
+ for (let i = 0; i < node.namedChildCount; i++) {
29194
+ const child = node.namedChild(i);
29195
+ if (!child) continue;
29196
+ visitNode(child, ctx, out);
29140
29197
  }
29141
- const seenRoute = /* @__PURE__ */ new Set();
29142
- for (const m of source.matchAll(CPP_CROW_ROUTE_RE)) {
29143
- const name = m[1];
29144
- if (seenRoute.has(name)) continue;
29145
- seenRoute.add(name);
29146
- route.push({ name, files: [filePath], imports: [] });
29198
+ }
29199
+ function visitNode(node, ctx, out) {
29200
+ const innerCtx = { ...ctx };
29201
+ const attrState = readPrecedingAttributes(node);
29202
+ switch (node.type) {
29203
+ case "use_declaration": {
29204
+ out.imports.push(extractUse(node));
29205
+ return;
29206
+ }
29207
+ case "function_item": {
29208
+ const isMethod = isInImplBlock(node);
29209
+ out.functions.push(extractFunction(node, attrState, innerCtx.inTestConfig, isMethod));
29210
+ walkChildren(getField(node, "body") ?? node, innerCtx, out);
29211
+ return;
29212
+ }
29213
+ case "struct_item": {
29214
+ out.structs.push(extractStruct(node, attrState));
29215
+ const body = getField(node, "body");
29216
+ if (body) walkChildren(body, innerCtx, out);
29217
+ return;
29218
+ }
29219
+ case "trait_item": {
29220
+ out.traits.push(extractTrait(node, attrState));
29221
+ const body = getField(node, "body");
29222
+ if (body) walkChildren(body, innerCtx, out);
29223
+ return;
29224
+ }
29225
+ case "impl_item": {
29226
+ const implEntry = extractImpl(node, attrState, innerCtx);
29227
+ out.impls.push(implEntry.entry);
29228
+ const body = getField(node, "body");
29229
+ if (body) walkChildren(body, innerCtx, out);
29230
+ return;
29231
+ }
29232
+ case "mod_item": {
29233
+ const modIsTest = innerCtx.inTestConfig || attrState.isTestCfg;
29234
+ const modCtx = { ...innerCtx, inTestConfig: modIsTest };
29235
+ const body = getField(node, "body");
29236
+ if (body) walkChildren(body, modCtx, out);
29237
+ return;
29238
+ }
29239
+ default: {
29240
+ for (let i = 0; i < node.namedChildCount; i++) {
29241
+ const child = node.namedChild(i);
29242
+ if (child) visitNode(child, innerCtx, out);
29243
+ }
29244
+ }
29147
29245
  }
29148
- for (const m of source.matchAll(CPP_DROGON_ROUTE_RE)) {
29149
- const name = m[1] || m[2];
29246
+ }
29247
+ function readPrecedingAttributes(node) {
29248
+ const state = {
29249
+ isTestCfg: false,
29250
+ isTest: false,
29251
+ isPub: false,
29252
+ derives: []
29253
+ };
29254
+ const parent = node.parent;
29255
+ if (!parent) return state;
29256
+ for (let i = 0; i < parent.namedChildCount; i++) {
29257
+ const sibling = parent.namedChild(i);
29258
+ if (!sibling || sibling === node) continue;
29259
+ if (sibling.endIndex > node.startIndex) continue;
29260
+ if (sibling.type !== "attribute_item") continue;
29261
+ decodeAttribute(sibling, state);
29262
+ }
29263
+ return state;
29264
+ }
29265
+ function decodeAttribute(attr, state) {
29266
+ for (let i = 0; i < attr.namedChildCount; i++) {
29267
+ const child = attr.namedChild(i);
29268
+ if (!child || child.type !== "attribute") continue;
29269
+ const name = firstIdentifier(child);
29150
29270
  if (!name) continue;
29151
- if (seenRoute.has(name)) continue;
29152
- seenRoute.add(name);
29153
- route.push({ name, files: [filePath], imports: [] });
29154
- }
29155
- for (const m of source.matchAll(CPP_PISTACHE_ROUTE_RE)) {
29156
- const name = m[1];
29157
- if (seenRoute.has(name)) continue;
29158
- seenRoute.add(name);
29159
- route.push({ name, files: [filePath], imports: [] });
29271
+ if (name === "cfg") {
29272
+ const cfgText = child.text;
29273
+ if (/\btest\b/.test(cfgText) && !/\bnot\(test\)/.test(cfgText)) {
29274
+ state.isTestCfg = true;
29275
+ }
29276
+ } else if (name === "test") {
29277
+ state.isTest = true;
29278
+ } else if (name === "derive") {
29279
+ for (let j = 0; j < child.namedChildCount; j++) {
29280
+ const inner = child.namedChild(j);
29281
+ if (inner) {
29282
+ const matches = inner.text.matchAll(/\b([A-Z][A-Za-z0-9_]*)\b/g);
29283
+ for (const m of matches) state.derives.push(m[1]);
29284
+ }
29285
+ }
29286
+ }
29160
29287
  }
29161
- return { service, route, ormModel };
29162
29288
  }
29163
- var SERVICE_SUFFIXES5, SERVICE_SUFFIX_GROUP5, CPP_SERVICE_RE, CPP_CROW_ROUTE_RE, CPP_DROGON_ROUTE_RE, CPP_PISTACHE_ROUTE_RE;
29164
- var init_cpp = __esm({
29165
- "src/engine/visitors/cpp.ts"() {
29166
- "use strict";
29167
- SERVICE_SUFFIXES5 = [
29168
- "Service",
29169
- "Manager",
29170
- "Handler",
29171
- "Repository",
29172
- "Controller",
29173
- "Helper",
29174
- "Factory",
29175
- "Provider",
29176
- "Store",
29177
- "API",
29178
- "Client",
29179
- "Adapter",
29180
- "Resolver",
29181
- "Mapper",
29182
- "Transformer",
29183
- "Serializer",
29184
- "Validator",
29185
- "Strategy",
29186
- "Facade",
29187
- "Decorator",
29188
- "Observer",
29189
- "Builder",
29190
- "Command",
29191
- "Processor",
29192
- "Worker",
29193
- "Job"
29194
- ];
29195
- SERVICE_SUFFIX_GROUP5 = `(?:${SERVICE_SUFFIXES5.join("|")})`;
29196
- CPP_SERVICE_RE = new RegExp(
29197
- `^(?:public\\s+|private\\s+|protected\\s+|virtual\\s+|abstract\\s+|static\\s+|inline\\s+|constexpr\\s+|explicit\\s+|final\\s+|extern\\s+)*(?:class|struct)\\s+(\\w+?)${SERVICE_SUFFIX_GROUP5}?\\b`,
29198
- "gm"
29199
- );
29200
- CPP_CROW_ROUTE_RE = /CROW_ROUTE\s*\(\s*\w+\s*,\s*"(\/[^"]+)"/g;
29201
- CPP_DROGON_ROUTE_RE = /\.registerHandler\(\s*"(\/[^"]+)"[\s,)]|\.\b(?:get|post|put|delete|patch)\(\s*"(\/[^"]+)"/g;
29202
- CPP_PISTACHE_ROUTE_RE = /Routes::(?:get|post|put|delete|patch)\s*\(\s*[^,]+,\s*"(\/[^"]+)"/g;
29289
+ function firstIdentifier(node) {
29290
+ const text = node.text;
29291
+ const idMatch = text.match(/^([a-zA-Z_][a-zA-Z0-9_]*)/);
29292
+ return idMatch ? idMatch[1] : null;
29293
+ }
29294
+ function extractUse(node) {
29295
+ const text = node.text;
29296
+ const argument = node.namedChild(0);
29297
+ const argField = node.childForFieldName("argument");
29298
+ const path = argField?.text ?? argument?.text ?? "";
29299
+ const names = [];
29300
+ let isGlob = false;
29301
+ const useListNode = findUseListNode(argument);
29302
+ if (useListNode) {
29303
+ for (let i = 0; i < useListNode.namedChildCount; i++) {
29304
+ const item = useListNode.namedChild(i);
29305
+ if (item.type === "use_wildcard") {
29306
+ isGlob = true;
29307
+ } else if (item.type === "identifier") {
29308
+ names.push({ name: item.text });
29309
+ } else if (item.type === "use_as_clause") {
29310
+ const alias = item.childForFieldName("alias");
29311
+ const binding = item.childForFieldName("path");
29312
+ if (binding) {
29313
+ names.push({ name: binding.text, alias: alias?.text });
29314
+ } else {
29315
+ names.push({ name: item.text });
29316
+ }
29317
+ } else if (item.type === "scoped_identifier") {
29318
+ const idents = collectIdentifiers(item);
29319
+ names.push({ name: idents[idents.length - 1] ?? item.text });
29320
+ } else if (item.text.includes(" as ")) {
29321
+ const [head, alias] = item.text.split(/\s+as\s+/);
29322
+ names.push({ name: (head ?? "").trim(), alias: alias?.trim() });
29323
+ } else {
29324
+ names.push({ name: item.text });
29325
+ }
29326
+ }
29327
+ } else if (argument?.type === "use_wildcard") {
29328
+ isGlob = true;
29329
+ } else if (argument) {
29330
+ const idents = collectIdentifiers(argument);
29331
+ const last = idents[idents.length - 1] ?? argument.text;
29332
+ names.push({ name: last });
29333
+ const asMatch = text.match(/\s+as\s+(\w+)\s*;?\s*$/);
29334
+ if (asMatch) names[0].alias = asMatch[1];
29203
29335
  }
29204
- });
29205
-
29206
- // src/engine/visitors/java.ts
29207
- var java_exports = {};
29208
- __export(java_exports, {
29209
- extractJavaPatterns: () => extractJavaPatterns
29210
- });
29211
- function extractJavaPatterns(filePath, source) {
29212
- const service = [];
29213
- const route = [];
29214
- const ormModel = [];
29215
- const seenService = /* @__PURE__ */ new Set();
29216
- for (const m of source.matchAll(JAVA_SERVICE_RE)) {
29217
- const name = m[1];
29218
- if (seenService.has(name)) continue;
29219
- seenService.add(name);
29220
- service.push({ name, files: [filePath], imports: [] });
29336
+ return {
29337
+ path: path.trim(),
29338
+ names,
29339
+ isGlob,
29340
+ line: node.startPosition.row + 1,
29341
+ column: node.startPosition.column
29342
+ };
29343
+ }
29344
+ function extractFunction(node, attrs, inheritedTestConfig, isMethod) {
29345
+ const nameNode = node.childForFieldName("name");
29346
+ const name = nameNode?.text ?? "<anon>";
29347
+ const params = node.childForFieldName("parameters");
29348
+ const body = node.childForFieldName("body");
29349
+ const visibilityMod = node.namedChild(0);
29350
+ const isPublic = visibilityMod?.type === "visibility_modifier";
29351
+ let receiver;
29352
+ if (isMethod && params) {
29353
+ const selfParam = findSelfParameter(params);
29354
+ if (selfParam) receiver = selfParam.text;
29355
+ }
29356
+ const bodyLines = body ? body.endPosition.row - body.startPosition.row + 1 : 0;
29357
+ const inTestConfig = inheritedTestConfig || attrs.isTest || attrs.isTestCfg || isFunctionAttrTest(node);
29358
+ return {
29359
+ name,
29360
+ line: node.startPosition.row + 1,
29361
+ column: node.startPosition.column,
29362
+ isPublic,
29363
+ isMethod,
29364
+ receiver,
29365
+ bodyLines,
29366
+ inTestConfig
29367
+ };
29368
+ }
29369
+ function extractStruct(node, attrs) {
29370
+ const nameNode = node.childForFieldName("name");
29371
+ return {
29372
+ name: nameNode?.text ?? "<anon>",
29373
+ line: node.startPosition.row + 1,
29374
+ column: node.startPosition.column,
29375
+ isPublic: hasVisibility(node),
29376
+ isDerive: attrs.derives.length > 0,
29377
+ derives: [...attrs.derives]
29378
+ };
29379
+ }
29380
+ function extractTrait(node, _attrs) {
29381
+ const nameNode = node.childForFieldName("name");
29382
+ return {
29383
+ name: nameNode?.text ?? "<anon>",
29384
+ line: node.startPosition.row + 1,
29385
+ column: node.startPosition.column,
29386
+ isPublic: hasVisibility(node)
29387
+ };
29388
+ }
29389
+ function extractImpl(node, _attrs, _ctx) {
29390
+ const traitNode = node.childForFieldName("trait");
29391
+ const typeNode = node.childForFieldName("type");
29392
+ const typeText = typeNode?.text ?? "<anon>";
29393
+ const traitText = traitNode?.text;
29394
+ const body = node.childForFieldName("body");
29395
+ const methods = [];
29396
+ if (body) {
29397
+ for (let i = 0; i < body.namedChildCount; i++) {
29398
+ const child = body.namedChild(i);
29399
+ if (child?.type === "function_item") {
29400
+ const m = child.childForFieldName("name");
29401
+ if (m) methods.push(m.text);
29402
+ }
29403
+ }
29221
29404
  }
29222
- const seenRoute = /* @__PURE__ */ new Set();
29223
- for (const m of source.matchAll(JAVA_SPRING_ROUTE_RE)) {
29224
- const name = m[1];
29225
- if (seenRoute.has(name)) continue;
29226
- seenRoute.add(name);
29227
- route.push({ name, files: [filePath], imports: [] });
29405
+ return {
29406
+ entry: {
29407
+ type: typeText,
29408
+ trait: traitText ?? void 0,
29409
+ methods,
29410
+ line: node.startPosition.row + 1,
29411
+ column: node.startPosition.column
29412
+ }
29413
+ };
29414
+ }
29415
+ function findUseListNode(argument) {
29416
+ if (!argument) return null;
29417
+ if (argument.type === "use_list") return argument;
29418
+ if (argument.type === "scoped_use_list") {
29419
+ for (let i = 0; i < argument.namedChildCount; i++) {
29420
+ const c = argument.namedChild(i);
29421
+ if (c?.type === "use_list") return c;
29422
+ }
29228
29423
  }
29229
- for (const m of source.matchAll(JAVA_JAXRS_CLASS_PATH_RE)) {
29230
- const name = m[1];
29231
- if (name === "" || name === "/") continue;
29232
- if (seenRoute.has(name)) continue;
29233
- seenRoute.add(name);
29234
- route.push({ name, files: [filePath], imports: [] });
29424
+ return null;
29425
+ }
29426
+ function getField(node, fieldName) {
29427
+ return node.childForFieldName(fieldName);
29428
+ }
29429
+ function collectIdentifiers(node) {
29430
+ const out = [];
29431
+ for (let i = 0; i < node.namedChildCount; i++) {
29432
+ const child = node.namedChild(i);
29433
+ if (!child) continue;
29434
+ if (child.type === "identifier" || child.type === "type_identifier") {
29435
+ out.push(child.text);
29436
+ } else if (child.type === "scoped_identifier" || child.type === "nested_identifier") {
29437
+ out.push(...collectIdentifiers(child));
29438
+ }
29235
29439
  }
29236
- const seenOrm = /* @__PURE__ */ new Set();
29237
- for (const m of source.matchAll(JAVA_ORM_ANNOTATION_RE)) {
29238
- const name = m[1];
29239
- if (seenOrm.has(name)) continue;
29240
- seenOrm.add(name);
29241
- ormModel.push({ name, files: [filePath], imports: [] });
29440
+ return out;
29441
+ }
29442
+ function hasVisibility(node) {
29443
+ return node.namedChild(0)?.type === "visibility_modifier";
29444
+ }
29445
+ function isInImplBlock(node) {
29446
+ for (let p = node.parent; p; p = p.parent) {
29447
+ if (p.type === "impl_item") return true;
29448
+ if (p.type === "function_item" || p.type === "source_file") return false;
29242
29449
  }
29243
- for (const m of source.matchAll(JAVA_ORM_INHERIT_RE)) {
29244
- const name = m[1];
29245
- if (seenOrm.has(name)) continue;
29246
- seenOrm.add(name);
29247
- ormModel.push({ name, files: [filePath], imports: [] });
29450
+ return false;
29451
+ }
29452
+ function findSelfParameter(params) {
29453
+ for (let i = 0; i < params.namedChildCount; i++) {
29454
+ const child = params.namedChild(i);
29455
+ if (child?.type === "self_parameter") return child;
29248
29456
  }
29249
- return { service, route, ormModel };
29457
+ return null;
29250
29458
  }
29251
- var SERVICE_SUFFIXES6, SERVICE_SUFFIX_GROUP6, JAVA_SERVICE_RE, JAVA_SPRING_ROUTE_RE, JAVA_JAXRS_CLASS_PATH_RE, JAVA_ORM_ANNOTATION_RE, JAVA_ORM_INHERIT_RE;
29252
- var init_java = __esm({
29253
- "src/engine/visitors/java.ts"() {
29459
+ function isFunctionAttrTest(node) {
29460
+ void node;
29461
+ return false;
29462
+ }
29463
+ var SERVICE_SUFFIXES4, SERVICE_SUFFIX_GROUP4, RUST_SERVICE_STRUCT_RE, RUST_SERVICE_IMPL_RE, RUST_ACTIX_ROUTE_RE, RUST_AXUM_ROUTE_RE, RUST_DIESEL_RE, RUST_SEAORM_RE, RUST_SQLX_RE;
29464
+ var init_rust = __esm({
29465
+ "src/engine/visitors/rust.ts"() {
29254
29466
  "use strict";
29255
- SERVICE_SUFFIXES6 = [
29467
+ init_parser_rust();
29468
+ SERVICE_SUFFIXES4 = [
29469
+ "Service",
29470
+ "Manager",
29471
+ "Handler",
29472
+ "Repository",
29473
+ "Controller",
29474
+ "Helper",
29475
+ "Factory",
29476
+ "Provider",
29477
+ "Store",
29478
+ "API",
29479
+ "Client",
29480
+ "Adapter",
29481
+ "Resolver",
29482
+ "Mapper",
29483
+ "Transformer",
29484
+ "Serializer",
29485
+ "Validator",
29486
+ "Strategy",
29487
+ "Facade",
29488
+ "Decorator",
29489
+ "Observer",
29490
+ "Builder",
29491
+ "Command",
29492
+ "Processor",
29493
+ "Worker",
29494
+ "Job",
29495
+ "Actor",
29496
+ "Executor"
29497
+ ];
29498
+ SERVICE_SUFFIX_GROUP4 = `(?:${SERVICE_SUFFIXES4.join("|")})`;
29499
+ RUST_SERVICE_STRUCT_RE = new RegExp(
29500
+ `^(?:pub(?:\\(crate\\)|\\(super\\))?\\s+)?struct\\s+(\\w+?)${SERVICE_SUFFIX_GROUP4}?\\b`,
29501
+ "gm"
29502
+ );
29503
+ RUST_SERVICE_IMPL_RE = new RegExp(
29504
+ `^impl(?:<[^>]+>)?\\s+(?:${SERVICE_SUFFIX_GROUP4}\\s+for\\s+)?(\\w+?)${SERVICE_SUFFIX_GROUP4}?\\b`,
29505
+ "gm"
29506
+ );
29507
+ RUST_ACTIX_ROUTE_RE = /#\[(?:get|post|put|delete|patch|head|route)\(\s*"(\/[^"]+)"\s*[\),]/g;
29508
+ RUST_AXUM_ROUTE_RE = /\.route\(\s*"(\/[^"]+)"\s*,\s*(?:get|post|put|delete|patch)/g;
29509
+ RUST_DIESEL_RE = /#\[derive\([^\]]*Queryable[^\]]*\)\][\s\S]{0,200}?struct\s+(\w+)/g;
29510
+ RUST_SEAORM_RE = /#\[derive\([^\]]*DeriveEntityModel[^\]]*\)\][\s\S]{0,200}?struct\s+(\w+)/g;
29511
+ RUST_SQLX_RE = /#\[derive\([^\]]*sqlx::FromRow[^\]]*\)\][\s\S]{0,200}?struct\s+(\w+)/g;
29512
+ }
29513
+ });
29514
+
29515
+ // src/engine/visitors/cpp.ts
29516
+ var cpp_exports = {};
29517
+ __export(cpp_exports, {
29518
+ extractCppPatterns: () => extractCppPatterns
29519
+ });
29520
+ function extractCppPatterns(filePath, source) {
29521
+ const service = [];
29522
+ const route = [];
29523
+ const ormModel = [];
29524
+ const seenService = /* @__PURE__ */ new Set();
29525
+ for (const m of source.matchAll(CPP_SERVICE_RE)) {
29526
+ const name = m[1];
29527
+ if (seenService.has(name)) continue;
29528
+ seenService.add(name);
29529
+ service.push({ name, files: [filePath], imports: [] });
29530
+ }
29531
+ const seenRoute = /* @__PURE__ */ new Set();
29532
+ for (const m of source.matchAll(CPP_CROW_ROUTE_RE)) {
29533
+ const name = m[1];
29534
+ if (seenRoute.has(name)) continue;
29535
+ seenRoute.add(name);
29536
+ route.push({ name, files: [filePath], imports: [] });
29537
+ }
29538
+ for (const m of source.matchAll(CPP_DROGON_ROUTE_RE)) {
29539
+ const name = m[1] || m[2];
29540
+ if (!name) continue;
29541
+ if (seenRoute.has(name)) continue;
29542
+ seenRoute.add(name);
29543
+ route.push({ name, files: [filePath], imports: [] });
29544
+ }
29545
+ for (const m of source.matchAll(CPP_PISTACHE_ROUTE_RE)) {
29546
+ const name = m[1];
29547
+ if (seenRoute.has(name)) continue;
29548
+ seenRoute.add(name);
29549
+ route.push({ name, files: [filePath], imports: [] });
29550
+ }
29551
+ return { service, route, ormModel };
29552
+ }
29553
+ var SERVICE_SUFFIXES5, SERVICE_SUFFIX_GROUP5, CPP_SERVICE_RE, CPP_CROW_ROUTE_RE, CPP_DROGON_ROUTE_RE, CPP_PISTACHE_ROUTE_RE;
29554
+ var init_cpp = __esm({
29555
+ "src/engine/visitors/cpp.ts"() {
29556
+ "use strict";
29557
+ SERVICE_SUFFIXES5 = [
29558
+ "Service",
29559
+ "Manager",
29560
+ "Handler",
29561
+ "Repository",
29562
+ "Controller",
29563
+ "Helper",
29564
+ "Factory",
29565
+ "Provider",
29566
+ "Store",
29567
+ "API",
29568
+ "Client",
29569
+ "Adapter",
29570
+ "Resolver",
29571
+ "Mapper",
29572
+ "Transformer",
29573
+ "Serializer",
29574
+ "Validator",
29575
+ "Strategy",
29576
+ "Facade",
29577
+ "Decorator",
29578
+ "Observer",
29579
+ "Builder",
29580
+ "Command",
29581
+ "Processor",
29582
+ "Worker",
29583
+ "Job"
29584
+ ];
29585
+ SERVICE_SUFFIX_GROUP5 = `(?:${SERVICE_SUFFIXES5.join("|")})`;
29586
+ CPP_SERVICE_RE = new RegExp(
29587
+ `^(?:public\\s+|private\\s+|protected\\s+|virtual\\s+|abstract\\s+|static\\s+|inline\\s+|constexpr\\s+|explicit\\s+|final\\s+|extern\\s+)*(?:class|struct)\\s+(\\w+?)${SERVICE_SUFFIX_GROUP5}?\\b`,
29588
+ "gm"
29589
+ );
29590
+ CPP_CROW_ROUTE_RE = /CROW_ROUTE\s*\(\s*\w+\s*,\s*"(\/[^"]+)"/g;
29591
+ CPP_DROGON_ROUTE_RE = /\.registerHandler\(\s*"(\/[^"]+)"[\s,)]|\.\b(?:get|post|put|delete|patch)\(\s*"(\/[^"]+)"/g;
29592
+ CPP_PISTACHE_ROUTE_RE = /Routes::(?:get|post|put|delete|patch)\s*\(\s*[^,]+,\s*"(\/[^"]+)"/g;
29593
+ }
29594
+ });
29595
+
29596
+ // src/engine/visitors/java.ts
29597
+ var java_exports = {};
29598
+ __export(java_exports, {
29599
+ extractJavaPatterns: () => extractJavaPatterns
29600
+ });
29601
+ function extractJavaPatterns(filePath, source) {
29602
+ const service = [];
29603
+ const route = [];
29604
+ const ormModel = [];
29605
+ const seenService = /* @__PURE__ */ new Set();
29606
+ for (const m of source.matchAll(JAVA_SERVICE_RE)) {
29607
+ const name = m[1];
29608
+ if (seenService.has(name)) continue;
29609
+ seenService.add(name);
29610
+ service.push({ name, files: [filePath], imports: [] });
29611
+ }
29612
+ const seenRoute = /* @__PURE__ */ new Set();
29613
+ for (const m of source.matchAll(JAVA_SPRING_ROUTE_RE)) {
29614
+ const name = m[1];
29615
+ if (seenRoute.has(name)) continue;
29616
+ seenRoute.add(name);
29617
+ route.push({ name, files: [filePath], imports: [] });
29618
+ }
29619
+ for (const m of source.matchAll(JAVA_JAXRS_CLASS_PATH_RE)) {
29620
+ const name = m[1];
29621
+ if (name === "" || name === "/") continue;
29622
+ if (seenRoute.has(name)) continue;
29623
+ seenRoute.add(name);
29624
+ route.push({ name, files: [filePath], imports: [] });
29625
+ }
29626
+ const seenOrm = /* @__PURE__ */ new Set();
29627
+ for (const m of source.matchAll(JAVA_ORM_ANNOTATION_RE)) {
29628
+ const name = m[1];
29629
+ if (seenOrm.has(name)) continue;
29630
+ seenOrm.add(name);
29631
+ ormModel.push({ name, files: [filePath], imports: [] });
29632
+ }
29633
+ for (const m of source.matchAll(JAVA_ORM_INHERIT_RE)) {
29634
+ const name = m[1];
29635
+ if (seenOrm.has(name)) continue;
29636
+ seenOrm.add(name);
29637
+ ormModel.push({ name, files: [filePath], imports: [] });
29638
+ }
29639
+ return { service, route, ormModel };
29640
+ }
29641
+ var SERVICE_SUFFIXES6, SERVICE_SUFFIX_GROUP6, JAVA_SERVICE_RE, JAVA_SPRING_ROUTE_RE, JAVA_JAXRS_CLASS_PATH_RE, JAVA_ORM_ANNOTATION_RE, JAVA_ORM_INHERIT_RE;
29642
+ var init_java = __esm({
29643
+ "src/engine/visitors/java.ts"() {
29644
+ "use strict";
29645
+ SERVICE_SUFFIXES6 = [
29256
29646
  "Service",
29257
29647
  "Manager",
29258
29648
  "Handler",
@@ -36060,7 +36450,7 @@ function parseBlankModule(source) {
36060
36450
  tsx: false,
36061
36451
  target: "es2022"
36062
36452
  });
36063
- return { ast, source: replaced };
36453
+ return { ast, source };
36064
36454
  }
36065
36455
  function parseScriptContent(content, isTypeScript) {
36066
36456
  if (isTypeScript) {
@@ -36146,8 +36536,16 @@ function parseSource(source, filePath) {
36146
36536
  // but no SWC support. Return a blank-padded empty module so
36147
36537
  // regex-only rules can still fire (markdown-leakage, comment-
36148
36538
  // ratio, etc.) without burning the parseError path.
36539
+ // v0.18.9: `.rs` is in the same bucket. The visitor layer
36540
+ // (`engine/visitors/rust.ts`) carries the tree-sitter-backed
36541
+ // parse + extractFacts attaches the result to `facts.v2.rustFile`.
36542
+ // The rule layer (`rules/rust/*.ts`) reads that field. parseBlankModule
36543
+ // lets the worker continue past the parser — without this, parseWithSwc
36544
+ // would throw on every .rs file, the worker would count it as a
36545
+ // parseError, and the v2-build's buildRustFileRecord would never run.
36149
36546
  case "py":
36150
36547
  case "go":
36548
+ case "rs":
36151
36549
  return parseBlankModule(source);
36152
36550
  default:
36153
36551
  return parseWithSwc(source, filePath);
@@ -39334,6 +39732,354 @@ var init_ux_pattern_fragmentation = __esm({
39334
39732
  }
39335
39733
  });
39336
39734
 
39735
+ // src/rules/rust/stringly-typed.ts
39736
+ function collectEnumCandidates(source) {
39737
+ const out = [];
39738
+ const enumRe = /^(?:pub(?:\([^)]+\))?\s+)?enum\s+(\w+)\s*\{([^}]*)\}/gm;
39739
+ for (const m of source.matchAll(enumRe)) {
39740
+ const body = m[2] ?? "";
39741
+ const variants = body.split(/,(?![^()]*\))/).map((s) => s.trim()).filter((s) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(s.split(/\s+/)[0] ?? ""));
39742
+ if (variants.length > MAX_VARIANT_COUNT) continue;
39743
+ if (variants.length < 2) continue;
39744
+ out.push({ name: m[1], variantCount: variants.length, line: lineOfMatch(source, m.index ?? 0) });
39745
+ }
39746
+ return out;
39747
+ }
39748
+ function lineOfMatch(source, index) {
39749
+ let line = 1;
39750
+ for (let i = 0; i < index && i < source.length; i++) {
39751
+ if (source[i] === "\n") line++;
39752
+ }
39753
+ return line;
39754
+ }
39755
+ function buildLineOffsets(source) {
39756
+ const out = [0];
39757
+ for (let i = 0; i < source.length; i++) {
39758
+ if (source[i] === "\n") out.push(i + 1);
39759
+ }
39760
+ return out;
39761
+ }
39762
+ function extractParameterText(source, lineOffsets, fn) {
39763
+ const start = lineOffsets[Math.max(0, fn.line - 1)] ?? 0;
39764
+ const head = source.slice(start, start + 400);
39765
+ const openIdx = head.indexOf("(");
39766
+ if (openIdx < 0) return "";
39767
+ let closeIdx = -1;
39768
+ let depth = 0;
39769
+ for (let i = openIdx; i < head.length; i++) {
39770
+ if (head[i] === "(") depth++;
39771
+ else if (head[i] === ")") {
39772
+ depth--;
39773
+ if (depth === 0) {
39774
+ closeIdx = i;
39775
+ break;
39776
+ }
39777
+ }
39778
+ }
39779
+ if (closeIdx < 0) return "";
39780
+ return head.slice(openIdx + 1, closeIdx);
39781
+ }
39782
+ function scanForStringlyParams(paramText) {
39783
+ const out = [];
39784
+ for (const m of paramText.matchAll(
39785
+ /\b([a-z_][a-zA-Z0-9_]*)\s*:\s*(&\s*(?:mut\s+)?(?:str|String)\b)/g
39786
+ )) {
39787
+ const name = m[1];
39788
+ const type = m[2];
39789
+ if (!SUSPECT_PARAM_NAMES.has(name)) continue;
39790
+ out.push({ name, type });
39791
+ }
39792
+ return out;
39793
+ }
39794
+ var SUSPECT_PARAM_NAMES, MAX_VARIANT_COUNT, rustStringlyTypedRule;
39795
+ var init_stringly_typed = __esm({
39796
+ "src/rules/rust/stringly-typed.ts"() {
39797
+ "use strict";
39798
+ init_rule();
39799
+ SUSPECT_PARAM_NAMES = /* @__PURE__ */ new Set([
39800
+ "kind",
39801
+ "type",
39802
+ "mode",
39803
+ "event",
39804
+ "status",
39805
+ "category",
39806
+ "action",
39807
+ "state",
39808
+ "level",
39809
+ "role",
39810
+ "tier",
39811
+ "phase",
39812
+ "tag",
39813
+ "format",
39814
+ "shape",
39815
+ "direction",
39816
+ "side",
39817
+ "method"
39818
+ ]);
39819
+ MAX_VARIANT_COUNT = 32;
39820
+ rustStringlyTypedRule = createRule({
39821
+ id: "rust/stringly-typed",
39822
+ category: "logic",
39823
+ severity: "medium",
39824
+ aiSpecific: true,
39825
+ description: "String / &str parameter where a typed enum exists in the same file",
39826
+ create(_context) {
39827
+ return {};
39828
+ },
39829
+ analyze(_context, facts) {
39830
+ const issues = [];
39831
+ if (!facts.v2?.rustFile) return issues;
39832
+ const source = facts.v2._source ?? "";
39833
+ if (!source) return issues;
39834
+ const lineOffsets = buildLineOffsets(source);
39835
+ const enumCandidates = collectEnumCandidates(source);
39836
+ if (enumCandidates.length === 0) return issues;
39837
+ for (const fn of facts.v2.rustFile.functions) {
39838
+ const paramText = extractParameterText(source, lineOffsets, fn);
39839
+ if (!paramText) continue;
39840
+ const matches = scanForStringlyParams(paramText);
39841
+ if (matches.length === 0) continue;
39842
+ issues.push({
39843
+ ruleId: "rust/stringly-typed",
39844
+ category: "logic",
39845
+ severity: "medium",
39846
+ aiSpecific: true,
39847
+ 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`,
39848
+ line: fn.line,
39849
+ column: fn.column,
39850
+ 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.`
39851
+ });
39852
+ }
39853
+ return issues;
39854
+ }
39855
+ });
39856
+ }
39857
+ });
39858
+
39859
+ // src/rules/rust/todo-macro.ts
39860
+ function collectMacroIssues(node, testScopes, issues) {
39861
+ if (node.type === "macro_invocation") {
39862
+ const text = node.text;
39863
+ const m = text.match(/^([A-Za-z_][A-Za-z0-9_]*)/);
39864
+ const macroName = m?.[1] ?? "";
39865
+ if (TODO_MACROS.has(macroName)) {
39866
+ if (!isInsideMacroDefinition(node) && !isInsideTestFunction(node, testScopes)) {
39867
+ issues.push({
39868
+ ruleId: "rust/todo-macro",
39869
+ category: "logic",
39870
+ severity: "medium",
39871
+ aiSpecific: true,
39872
+ message: `'${macroName}!()' in production code \u2014 both expand to panic!()`,
39873
+ line: node.startPosition.row + 1,
39874
+ column: node.startPosition.column,
39875
+ 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.`
39876
+ });
39877
+ }
39878
+ }
39879
+ }
39880
+ for (let i = 0; i < node.namedChildCount; i++) {
39881
+ const child = node.namedChild(i);
39882
+ if (child) collectMacroIssues(child, testScopes, issues);
39883
+ }
39884
+ }
39885
+ function isInsideMacroDefinition(node) {
39886
+ for (let p = node.parent; p; p = p.parent) {
39887
+ if (p.type === "macro_definition") return true;
39888
+ if (p.type === "source_file") return false;
39889
+ }
39890
+ return false;
39891
+ }
39892
+ function isInsideTestFunction(node, testScopes) {
39893
+ for (let p = node.parent; p; p = p.parent) {
39894
+ if (p.type === "function_item") {
39895
+ const nameField = p.childForFieldName("name");
39896
+ const name = nameField?.text;
39897
+ if (name && testScopes.has(name)) return true;
39898
+ if (p.text.startsWith("#[test]") || p.text.startsWith("#[cfg(test)]")) return true;
39899
+ return false;
39900
+ }
39901
+ if (p.type === "source_file") return false;
39902
+ }
39903
+ return false;
39904
+ }
39905
+ var TODO_MACROS, rustTodoMacroRule;
39906
+ var init_todo_macro = __esm({
39907
+ "src/rules/rust/todo-macro.ts"() {
39908
+ "use strict";
39909
+ init_rule();
39910
+ init_parser_rust();
39911
+ TODO_MACROS = /* @__PURE__ */ new Set(["todo", "unimplemented", "todo_unimplemented"]);
39912
+ rustTodoMacroRule = createRule({
39913
+ id: "rust/todo-macro",
39914
+ category: "logic",
39915
+ severity: "medium",
39916
+ aiSpecific: true,
39917
+ description: "todo!() / unimplemented!() macro invocation in production code",
39918
+ create(_context) {
39919
+ return {};
39920
+ },
39921
+ analyze(_context, facts) {
39922
+ const issues = [];
39923
+ if (!facts.v2?.rustFile) return issues;
39924
+ const source = facts.v2._source ?? "";
39925
+ if (!source) return issues;
39926
+ const tree = parseRust(source);
39927
+ if (!tree) return issues;
39928
+ const testScopes = /* @__PURE__ */ new Set();
39929
+ for (const fn of facts.v2.rustFile.functions) {
39930
+ if (fn.inTestConfig && fn.name) testScopes.add(fn.name);
39931
+ }
39932
+ collectMacroIssues(tree.rootNode, testScopes, issues);
39933
+ return issues;
39934
+ }
39935
+ });
39936
+ }
39937
+ });
39938
+
39939
+ // src/rules/rust/unused-pub-fn.ts
39940
+ function collectReferencedNames(source) {
39941
+ const out = /* @__PURE__ */ new Set();
39942
+ for (const m of source.matchAll(/\b([A-Za-z_][A-Za-z0-9_]*)\b/g)) {
39943
+ out.add(m[1]);
39944
+ }
39945
+ return out;
39946
+ }
39947
+ var API_CONVENTION_NAMES, rustUnusedPubFnRule;
39948
+ var init_unused_pub_fn = __esm({
39949
+ "src/rules/rust/unused-pub-fn.ts"() {
39950
+ "use strict";
39951
+ init_rule();
39952
+ API_CONVENTION_NAMES = /* @__PURE__ */ new Set([
39953
+ "new",
39954
+ "default",
39955
+ "from",
39956
+ "from_str",
39957
+ "from_iter",
39958
+ "try_from",
39959
+ "into",
39960
+ "into_iter",
39961
+ "try_into",
39962
+ "as_ref",
39963
+ "as_mut",
39964
+ "clone",
39965
+ "fmt",
39966
+ "eq",
39967
+ "hash",
39968
+ "partial_cmp",
39969
+ "cmp",
39970
+ "ord",
39971
+ "partial_eq"
39972
+ ]);
39973
+ rustUnusedPubFnRule = createRule({
39974
+ id: "rust/unused-pub-fn",
39975
+ category: "logic",
39976
+ severity: "low",
39977
+ aiSpecific: true,
39978
+ description: "Public function in a Rust file that has no in-file references",
39979
+ create(_context) {
39980
+ return {};
39981
+ },
39982
+ analyze(_context, facts) {
39983
+ const issues = [];
39984
+ if (!facts.v2?.rustFile) return issues;
39985
+ const rust = facts.v2.rustFile;
39986
+ const referenced = collectReferencedNames(facts.v2._source ?? "");
39987
+ for (const fn of rust.functions) {
39988
+ if (!fn.isPublic) continue;
39989
+ if (API_CONVENTION_NAMES.has(fn.name)) continue;
39990
+ if (fn.inTestConfig) continue;
39991
+ if (referenced.has(fn.name)) continue;
39992
+ issues.push({
39993
+ ruleId: "rust/unused-pub-fn",
39994
+ category: "logic",
39995
+ severity: "low",
39996
+ aiSpecific: true,
39997
+ message: `Public function '${fn.name}' is not referenced anywhere in the file`,
39998
+ line: fn.line,
39999
+ column: fn.column,
40000
+ 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.`
40001
+ });
40002
+ }
40003
+ return issues;
40004
+ }
40005
+ });
40006
+ }
40007
+ });
40008
+
40009
+ // src/rules/rust/unwrap-in-production.ts
40010
+ function collectUnwrapIssues(node, testScopes, issues) {
40011
+ if (node.type === "call_expression") {
40012
+ const fn = node.childForFieldName("function");
40013
+ if (fn && fn.type === "field_expression") {
40014
+ const field = fn.childForFieldName("field");
40015
+ if (field && field.type === "field_identifier" && UNWRAP_METHODS.has(field.text)) {
40016
+ if (!isInsideTestFunction2(node, testScopes)) {
40017
+ issues.push({
40018
+ ruleId: "rust/unwrap-in-production",
40019
+ category: "logic",
40020
+ severity: "medium",
40021
+ aiSpecific: true,
40022
+ message: `'.${field.text}()' called in production code \u2014 panic risk on Err/None`,
40023
+ line: node.startPosition.row + 1,
40024
+ column: node.startPosition.column,
40025
+ 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.`
40026
+ });
40027
+ }
40028
+ }
40029
+ }
40030
+ }
40031
+ for (let i = 0; i < node.namedChildCount; i++) {
40032
+ const child = node.namedChild(i);
40033
+ if (child) collectUnwrapIssues(child, testScopes, issues);
40034
+ }
40035
+ }
40036
+ function isInsideTestFunction2(node, testScopes) {
40037
+ for (let p = node.parent; p; p = p.parent) {
40038
+ if (p.type === "function_item") {
40039
+ const nameField = p.childForFieldName("name");
40040
+ const name = nameField?.text;
40041
+ if (name && testScopes.has(name)) return true;
40042
+ if (p.text.startsWith("#[test]") || p.text.startsWith("#[cfg(test)]")) return true;
40043
+ return false;
40044
+ }
40045
+ if (p.type === "source_file") return false;
40046
+ }
40047
+ return false;
40048
+ }
40049
+ var UNWRAP_METHODS, rustUnwrapInProductionRule;
40050
+ var init_unwrap_in_production = __esm({
40051
+ "src/rules/rust/unwrap-in-production.ts"() {
40052
+ "use strict";
40053
+ init_rule();
40054
+ init_parser_rust();
40055
+ UNWRAP_METHODS = /* @__PURE__ */ new Set(["unwrap", "expect", "unwrap_or_else"]);
40056
+ rustUnwrapInProductionRule = createRule({
40057
+ id: "rust/unwrap-in-production",
40058
+ category: "logic",
40059
+ severity: "medium",
40060
+ aiSpecific: true,
40061
+ description: ".unwrap() / .expect() called outside of #[cfg(test)] / #[test] scope",
40062
+ create(_context) {
40063
+ return {};
40064
+ },
40065
+ analyze(_context, facts) {
40066
+ const issues = [];
40067
+ if (!facts.v2?.rustFile) return issues;
40068
+ const source = facts.v2._source ?? "";
40069
+ if (!source) return issues;
40070
+ const tree = parseRust(source);
40071
+ if (!tree) return issues;
40072
+ const testScopes = /* @__PURE__ */ new Set();
40073
+ for (const fn of facts.v2.rustFile.functions) {
40074
+ if (fn.inTestConfig && fn.name) testScopes.add(fn.name);
40075
+ }
40076
+ collectUnwrapIssues(tree.rootNode, testScopes, issues);
40077
+ return issues;
40078
+ }
40079
+ });
40080
+ }
40081
+ });
40082
+
39337
40083
  // src/rules/security/dangerous-cors.ts
39338
40084
  function scanForWildcardCors(source) {
39339
40085
  const hits = [];
@@ -42028,7 +42774,7 @@ function spanEnd(node) {
42028
42774
  }
42029
42775
  return void 0;
42030
42776
  }
42031
- function buildLineOffsets(source) {
42777
+ function buildLineOffsets2(source) {
42032
42778
  const offsets = [0];
42033
42779
  let byteOffset = 0;
42034
42780
  for (let i = 0; i < source.length; i++) {
@@ -44029,9 +44775,60 @@ function buildV2Facts(facts, source, ext, framework, config, templateClassNames
44029
44775
  })),
44030
44776
  disabledRules: extractDisabledRules(source),
44031
44777
  templateClassNames,
44778
+ // v0.18.9 — populate the Rust AST record when the file is `.rs`.
44779
+ // Calling `parseRustFile` here keeps the dead-code detector's
44780
+ // import-binding pass a pure function over the same source the
44781
+ // walker saw. The native-binding guard lives inside
44782
+ // `parseRustFile` (returns an empty record when tree-sitter is
44783
+ // unavailable).
44784
+ rustFile: buildRustFileRecord(facts.filePath, source),
44032
44785
  _source: source
44033
44786
  };
44034
44787
  }
44788
+ function buildRustFileRecord(filePath, source) {
44789
+ if (!filePath.toLowerCase().endsWith(".rs")) return void 0;
44790
+ const structure = parseRustFile(filePath, source);
44791
+ return {
44792
+ imports: structure.imports.map((i) => ({
44793
+ path: i.path,
44794
+ names: i.names.map((n) => ({ name: n.name, ...n.alias ? { alias: n.alias } : {} })),
44795
+ isGlob: i.isGlob,
44796
+ line: i.line,
44797
+ column: i.column
44798
+ })),
44799
+ functions: structure.functions.map((f) => ({
44800
+ name: f.name,
44801
+ line: f.line,
44802
+ column: f.column,
44803
+ isPublic: f.isPublic,
44804
+ isMethod: f.isMethod,
44805
+ ...f.receiver ? { receiver: f.receiver } : {},
44806
+ bodyLines: f.bodyLines,
44807
+ inTestConfig: f.inTestConfig
44808
+ })),
44809
+ structs: structure.structs.map((s) => ({
44810
+ name: s.name,
44811
+ line: s.line,
44812
+ column: s.column,
44813
+ isPublic: s.isPublic,
44814
+ isDerive: s.isDerive,
44815
+ derives: [...s.derives]
44816
+ })),
44817
+ traits: structure.traits.map((t) => ({
44818
+ name: t.name,
44819
+ line: t.line,
44820
+ column: t.column,
44821
+ isPublic: t.isPublic
44822
+ })),
44823
+ impls: structure.impls.map((ip) => ({
44824
+ ...ip.trait ? { trait: ip.trait } : {},
44825
+ type: ip.type,
44826
+ methods: [...ip.methods],
44827
+ line: ip.line,
44828
+ column: ip.column
44829
+ }))
44830
+ };
44831
+ }
44035
44832
  function splitFilePath(filePath) {
44036
44833
  const baseName2 = filePath.split("/").pop() ?? filePath;
44037
44834
  const dotIdx = baseName2.lastIndexOf(".");
@@ -44046,6 +44843,7 @@ var init_v2_build = __esm({
44046
44843
  "src/engine/visitors/v2-build.ts"() {
44047
44844
  "use strict";
44048
44845
  init_scan_helpers();
44846
+ init_rust();
44049
44847
  TAILWIND_COLOR_RE = /^(?:bg|text|border|ring|from|to|via|fill|stroke)-([a-z]+-\d+|white|black|transparent|current|\[.+?\])$/;
44050
44848
  TAILWIND_SPACING_RE = /^(?:[pm][xytrbl]?|gap|space-[xy])-(\d+(?:\.\d+)?)$/;
44051
44849
  TAILWIND_RADIUS_RE = /^(?:rounded(?:-[a-z]+)?)-(.+)$/;
@@ -44078,7 +44876,7 @@ function mergeTemplateClassNames(filePath, source, facts, templateClassNames) {
44078
44876
  }
44079
44877
  }
44080
44878
  function extractFacts(filePath, ast, source, supportsRsc = true, framework = "react", config) {
44081
- const lineOffsets = buildLineOffsets(source);
44879
+ const lineOffsets = buildLineOffsets2(source);
44082
44880
  const isTypeScript = /\.tsx?$/i.test(filePath);
44083
44881
  const NON_JSX_FRAMEWORKS = /* @__PURE__ */ new Set(["vue", "svelte", "astro"]);
44084
44882
  const facts = {
@@ -44366,7 +45164,7 @@ var init_naturalness_anomaly = __esm({
44366
45164
  const issues = [];
44367
45165
  const source = facts.v2?._source;
44368
45166
  if (!source) return issues;
44369
- const lineOffsets = buildLineOffsets(source);
45167
+ const lineOffsets = buildLineOffsets2(source);
44370
45168
  const components = facts.v2?.components ?? [];
44371
45169
  const perComponentMetrics = components.filter((c) => c.loc > 0).map(
44372
45170
  (c) => computeNaturalnessForRange(source, lineOffsets, c.line, c.line + c.loc - 1, context.model)
@@ -45037,6 +45835,10 @@ var init_builtins = __esm({
45037
45835
  init_halstead_anomaly();
45038
45836
  init_terminology_drift();
45039
45837
  init_ux_pattern_fragmentation();
45838
+ init_stringly_typed();
45839
+ init_todo_macro();
45840
+ init_unused_pub_fn();
45841
+ init_unwrap_in_production();
45040
45842
  init_dangerous_cors();
45041
45843
  init_eval();
45042
45844
  init_exposed_env_var();
@@ -45138,6 +45940,10 @@ var init_builtins = __esm({
45138
45940
  halsteadAnomalyRule,
45139
45941
  terminologyDriftRule,
45140
45942
  uxPatternFragmentationRule,
45943
+ rustStringlyTypedRule,
45944
+ rustTodoMacroRule,
45945
+ rustUnusedPubFnRule,
45946
+ rustUnwrapInProductionRule,
45141
45947
  dangerousCorsRule,
45142
45948
  evalRule,
45143
45949
  exposedEnvVarRule,
@@ -47118,6 +47924,22 @@ var init_registry = __esm({
47118
47924
  if (!filter) return list;
47119
47925
  return list.filter((r) => filter.kind === "ai" ? r.aiSpecific : !r.aiSpecific);
47120
47926
  }
47927
+ /** v0.18.8: remove every rule where `predicate(rule)` returns true.
47928
+ * Used by focused calibration scripts to scan a single category
47929
+ * without instantiating all 99 rules. */
47930
+ removeWhere(predicate) {
47931
+ let removed = 0;
47932
+ for (const [id, rule] of this.rules) {
47933
+ if (predicate(rule)) {
47934
+ this.rules.delete(id);
47935
+ removed++;
47936
+ }
47937
+ }
47938
+ return removed;
47939
+ }
47940
+ all() {
47941
+ return Array.from(this.rules.values());
47942
+ }
47121
47943
  createContexts(config, filePath, cwd, hotspotIssues = []) {
47122
47944
  const context = {
47123
47945
  config,
@@ -47143,1044 +47965,1793 @@ var signal_strength_default;
47143
47965
  var init_signal_strength = __esm({
47144
47966
  "src/rules/signal-strength.json"() {
47145
47967
  signal_strength_default = {
47146
- "logic/math-console-log-storm": {
47147
- recall: 7e-3,
47148
- fpRate: 1e-3,
47149
- ratio: 6.71,
47150
- precision: 0.8968,
47151
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47968
+ "ai/any-density": {
47969
+ recall: 6e-3,
47970
+ fpRate: 37e-4,
47971
+ ratio: 175.31,
47972
+ precision: 0.6523,
47973
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47152
47974
  verdict: "USEFUL",
47153
- _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.",
47154
- aiSpecific: true
47975
+ _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).",
47976
+ aiSpecific: true,
47977
+ _v7Verdict: "USEFUL",
47978
+ _v7Lift: 153.41,
47979
+ _v7Recall: 55e-4,
47980
+ _v7FpRate: 41e-4,
47981
+ _v7Precision: 0.634,
47982
+ _v8Verdict: "USEFUL",
47983
+ _v8Lift: 271.97
47155
47984
  },
47156
- "logic/math-any-density": {
47157
- recall: 16e-4,
47158
- fpRate: 13e-4,
47159
- ratio: 1.17,
47160
- precision: 0.6035,
47161
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47162
- verdict: "NOISY",
47163
- _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.",
47164
- defaultOff: true,
47165
- aiSpecific: true
47985
+ "ai/comment-ratio": {
47986
+ recall: 0.2771,
47987
+ fpRate: 0.1578,
47988
+ ratio: 4.26,
47989
+ precision: 0.6721,
47990
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47991
+ verdict: "USEFUL",
47992
+ _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).",
47993
+ aiSpecific: true,
47994
+ _v7Verdict: "USEFUL",
47995
+ _v7Lift: 4.11,
47996
+ _v7Recall: 0.2545,
47997
+ _v7FpRate: 0.1629,
47998
+ _v7Precision: 0.6687,
47999
+ _v8Verdict: "USEFUL",
48000
+ _v8Lift: 4.73
47166
48001
  },
47167
- "logic/boundary-violation": {
47168
- recall: 0.0263,
47169
- fpRate: 0.0175,
47170
- ratio: 1.5,
47171
- precision: 0.6601,
47172
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47173
- verdict: "HYGIENE",
47174
- _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.",
47175
- aiSpecific: false
48002
+ "ai/compression-profile": {
48003
+ recall: 0.3478,
48004
+ fpRate: 0.1488,
48005
+ ratio: 4.92,
48006
+ precision: 0.7318,
48007
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48008
+ verdict: "USEFUL",
48009
+ _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).",
48010
+ aiSpecific: true,
48011
+ _v7Verdict: "USEFUL",
48012
+ _v7Lift: 4.89,
48013
+ _v7Recall: 0.3166,
48014
+ _v7FpRate: 0.1498,
48015
+ _v7Precision: 0.732,
48016
+ _v8Verdict: "USEFUL",
48017
+ _v8Lift: 5
47176
48018
  },
47177
- "logic/reactive-hook-soup": {
47178
- recall: 38e-4,
48019
+ "ai/console-debug-storm": {
48020
+ recall: 73e-4,
47179
48021
  fpRate: 9e-4,
47180
- ratio: 4.29,
47181
- precision: 0.8476,
47182
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48022
+ ratio: 949.21,
48023
+ precision: 0.9,
48024
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47183
48025
  verdict: "USEFUL",
47184
- _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.",
47185
- aiSpecific: true
48026
+ _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).",
48027
+ aiSpecific: true,
48028
+ _v7Verdict: "USEFUL",
48029
+ _v7Lift: 960.19,
48030
+ _v7Recall: 81e-4,
48031
+ _v7FpRate: 1e-3,
48032
+ _v7Precision: 0.9161,
48033
+ _v8Verdict: "USEFUL",
48034
+ _v8Lift: 845.55
47186
48035
  },
47187
- "logic/optimistic-no-rollback": {
47188
- recall: 12e-4,
47189
- fpRate: 3e-4,
47190
- ratio: 3.61,
47191
- precision: 0.824,
47192
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48036
+ "ai/default-react-stack": {
48037
+ recall: 1e-3,
48038
+ fpRate: 0,
48039
+ ratio: 251225.49,
48040
+ precision: 0.9966,
48041
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47193
48042
  verdict: "USEFUL",
47194
- _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.",
47195
- aiSpecific: true
48043
+ _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).",
48044
+ aiSpecific: true,
48045
+ _v7Verdict: "USEFUL",
48046
+ _v7Lift: 182622.43,
48047
+ _v7Recall: 1e-3,
48048
+ _v7FpRate: 0,
48049
+ _v7Precision: 0.9957,
48050
+ _v8Verdict: "USEFUL",
48051
+ _v8Lift: 99999
47196
48052
  },
47197
- "logic/zombie-state": {
47198
- recall: 1e-4,
47199
- fpRate: 0,
47200
- ratio: 9.26,
47201
- precision: 0.9231,
47202
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48053
+ "ai/errors-near-eof": {
48054
+ recall: 0.0948,
48055
+ fpRate: 0.052,
48056
+ ratio: 13.09,
48057
+ precision: 0.6803,
48058
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47203
48059
  verdict: "USEFUL",
47204
- _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.",
47205
- aiSpecific: true
48060
+ _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).",
48061
+ aiSpecific: true,
48062
+ _v7Verdict: "USEFUL",
48063
+ _v7Lift: 11.29,
48064
+ _v7Recall: 0.0704,
48065
+ _v7FpRate: 0.0551,
48066
+ _v7Precision: 0.6225,
48067
+ _v8Verdict: "USEFUL",
48068
+ _v8Lift: 18.16
47206
48069
  },
47207
- "logic/math-gini-class-usage": {
47208
- recall: 13e-4,
48070
+ "ai/fetch-default-overuse": {
48071
+ recall: 27e-4,
47209
48072
  fpRate: 3e-4,
47210
- ratio: 5.09,
47211
- precision: 0.8683,
47212
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48073
+ ratio: 2679.84,
48074
+ precision: 0.9036,
48075
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47213
48076
  verdict: "USEFUL",
47214
- _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.",
47215
- aiSpecific: true
48077
+ _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).",
48078
+ aiSpecific: true,
48079
+ _v7Verdict: "USEFUL",
48080
+ _v7Lift: 2166.14,
48081
+ _v7Recall: 28e-4,
48082
+ _v7FpRate: 4e-4,
48083
+ _v7Precision: 0.8976,
48084
+ _v8Verdict: "USEFUL",
48085
+ _v8Lift: 7139.19
47216
48086
  },
47217
- "visual/math-color-cluster": {
47218
- recall: 2e-4,
48087
+ "ai/library-reinvention": {
48088
+ recall: 3e-4,
47219
48089
  fpRate: 0,
47220
- ratio: 8.95,
47221
- precision: 0.9206,
47222
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47223
- verdict: "USEFUL",
47224
- _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.",
47225
- aiSpecific: true
47226
- },
47227
- "visual/math-default-font": {
47228
- recall: 13e-4,
47229
- fpRate: 4e-4,
47230
- ratio: 3.4,
47231
- precision: 0.8151,
47232
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48090
+ ratio: 47415.05,
48091
+ precision: 0.9405,
48092
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47233
48093
  verdict: "USEFUL",
47234
- _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.",
47235
- aiSpecific: true
48094
+ _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).",
48095
+ aiSpecific: true,
48096
+ _v7Verdict: "USEFUL",
48097
+ _v7Lift: 34024.44,
48098
+ _v7Recall: 3e-4,
48099
+ _v7FpRate: 0,
48100
+ _v7Precision: 0.9275,
48101
+ _v8Verdict: "USEFUL",
48102
+ _v8Lift: 99999
47236
48103
  },
47237
- "visual/math-gradient-hue-rotation": {
48104
+ "ai/log-rank-histogram": {
47238
48105
  recall: 0,
47239
48106
  fpRate: 0,
47240
48107
  ratio: 0,
47241
48108
  precision: 0,
47242
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48109
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47243
48110
  verdict: "DORMANT",
47244
- defaultOff: true,
47245
- _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.)",
47246
- aiSpecific: true
48111
+ _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.",
48112
+ aiSpecific: true,
48113
+ _v7Verdict: "OK",
48114
+ _v7Lift: 0,
48115
+ _v7Recall: 0,
48116
+ _v7FpRate: 0,
48117
+ _v7Precision: 0,
48118
+ _v8Verdict: "DORMANT",
48119
+ _v8Lift: 1,
48120
+ defaultOff: true
47247
48121
  },
47248
- "visual/math-rounded-entropy": {
47249
- recall: 37e-4,
47250
- fpRate: 3e-4,
47251
- ratio: 10.9,
47252
- precision: 0.9339,
47253
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47254
- verdict: "USEFUL",
47255
- _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.",
47256
- aiSpecific: true
47257
- },
47258
- "visual/math-font-entropy": {
47259
- recall: 45e-4,
47260
- fpRate: 13e-4,
47261
- ratio: 3.32,
47262
- precision: 0.8114,
47263
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47264
- verdict: "USEFUL",
47265
- _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.",
47266
- aiSpecific: true
47267
- },
47268
- "visual/math-spacing-entropy": {
47269
- recall: 18e-4,
47270
- fpRate: 6e-4,
47271
- ratio: 3.01,
47272
- precision: 0.7959,
47273
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47274
- verdict: "USEFUL",
47275
- _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.",
47276
- aiSpecific: true
48122
+ "ai/markdown-leakage": {
48123
+ recall: 0,
48124
+ fpRate: 0,
48125
+ ratio: 10003.17,
48126
+ precision: 0.3571,
48127
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48128
+ verdict: "OK",
48129
+ _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).",
48130
+ aiSpecific: true,
48131
+ _v7Verdict: "USEFUL",
48132
+ _v7Lift: 65504.64,
48133
+ _v7Recall: 0,
48134
+ _v7FpRate: 0,
48135
+ _v7Precision: 0.7143,
48136
+ _v8Verdict: "INVERTED",
48137
+ _v8Lift: 0
47277
48138
  },
47278
- "visual/clamp-soup": {
48139
+ "ai/renyi-profile": {
47279
48140
  recall: 0,
47280
48141
  fpRate: 0,
47281
- ratio: 0,
47282
- precision: 0,
47283
- lastCalibratedAt: "2026-06-25T00:00:00Z",
47284
- verdict: "DORMANT",
47285
- defaultOff: true,
47286
- _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.)",
47287
- aiSpecific: true
48142
+ ratio: 5251.67,
48143
+ precision: 0.25,
48144
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48145
+ verdict: "OK",
48146
+ _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).",
48147
+ aiSpecific: true,
48148
+ _v7Verdict: "OK",
48149
+ _v7Lift: 5094.81,
48150
+ _v7Recall: 0,
48151
+ _v7FpRate: 0,
48152
+ _v7Precision: 0.25,
48153
+ _v8Verdict: "OK",
48154
+ _v8Lift: 5722.25
47288
48155
  },
47289
- "component/giant-component": {
47290
- recall: 0.0176,
47291
- fpRate: 77e-4,
47292
- ratio: 2.3,
47293
- precision: 0.7485,
47294
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48156
+ "ai/segment-surprisal-cv": {
48157
+ recall: 0.2019,
48158
+ fpRate: 0.0787,
48159
+ ratio: 9.52,
48160
+ precision: 0.7495,
48161
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47295
48162
  verdict: "USEFUL",
47296
- _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.",
47297
- aiSpecific: true
48163
+ _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).",
48164
+ aiSpecific: true,
48165
+ _v7Verdict: "USEFUL",
48166
+ _v7Lift: 9.11,
48167
+ _v7Recall: 0.1836,
48168
+ _v7FpRate: 0.0817,
48169
+ _v7Precision: 0.7438,
48170
+ _v8Verdict: "USEFUL",
48171
+ _v8Lift: 10.8
47298
48172
  },
47299
- "component/shadcn-prop-mismatch": {
47300
- recall: 13e-4,
47301
- fpRate: 1e-4,
47302
- ratio: 10.1,
47303
- precision: 0.929,
47304
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48173
+ "ai/state-default-overuse": {
48174
+ recall: 3e-3,
48175
+ fpRate: 6e-4,
48176
+ ratio: 1315.06,
48177
+ precision: 0.8451,
48178
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47305
48179
  verdict: "USEFUL",
47306
- _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.",
47307
- aiSpecific: true
48180
+ _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).",
48181
+ aiSpecific: true,
48182
+ _v7Verdict: "USEFUL",
48183
+ _v7Lift: 947.32,
48184
+ _v7Recall: 3e-3,
48185
+ _v7FpRate: 9e-4,
48186
+ _v7Precision: 0.8161,
48187
+ _v8Verdict: "USEFUL",
48188
+ _v8Lift: 16799.55
47308
48189
  },
47309
- "layout/math-grid-uniformity": {
47310
- recall: 3e-4,
47311
- fpRate: 2e-4,
47312
- ratio: 1.72,
47313
- precision: 0.6907,
47314
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47315
- verdict: "OK",
47316
- _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.",
47317
- aiSpecific: true
47318
- },
47319
- "layout/math-element-uniformity": {
47320
- recall: 28e-4,
47321
- fpRate: 12e-4,
47322
- ratio: 2.28,
47323
- precision: 0.7475,
47324
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48190
+ "ai/tailwind-color-overuse": {
48191
+ recall: 0.0264,
48192
+ fpRate: 38e-4,
48193
+ ratio: 230.97,
48194
+ precision: 0.8888,
48195
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47325
48196
  verdict: "USEFUL",
47326
- _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.",
47327
- aiSpecific: true
48197
+ _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).",
48198
+ aiSpecific: true,
48199
+ _v7Verdict: "USEFUL",
48200
+ _v7Lift: 161.52,
48201
+ _v7Recall: 0.0218,
48202
+ _v7FpRate: 52e-4,
48203
+ _v7Precision: 0.8436,
48204
+ _v8Verdict: "USEFUL",
48205
+ _v8Lift: 5695.79
47328
48206
  },
47329
- "typo/math-button-label-uniformity": {
47330
- recall: 2e-4,
47331
- fpRate: 1e-4,
47332
- ratio: 1.36,
47333
- precision: 0.6379,
47334
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47335
- verdict: "HYGIENE",
47336
- _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.",
47337
- aiSpecific: false
47338
- },
47339
- "perf/css-bloat": {
47340
- recall: 0.0117,
47341
- fpRate: 32e-4,
47342
- ratio: 3.64,
47343
- precision: 0.8252,
47344
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47345
- verdict: "HYGIENE",
47346
- _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.",
47347
- aiSpecific: false
48207
+ "ai/text-like-ratio": {
48208
+ recall: 0,
48209
+ fpRate: 0,
48210
+ ratio: 201664,
48211
+ precision: 0.8,
48212
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48213
+ verdict: "USEFUL",
48214
+ _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).",
48215
+ aiSpecific: true,
48216
+ _v7Verdict: "USEFUL",
48217
+ _v7Lift: 137559.75,
48218
+ _v7Recall: 0,
48219
+ _v7FpRate: 0,
48220
+ _v7Precision: 0.75,
48221
+ _v8Verdict: "USEFUL",
48222
+ _v8Lift: 99999
47348
48223
  },
47349
- "wcag/focus-appearance": {
47350
- recall: 26e-4,
47351
- fpRate: 1e-4,
47352
- ratio: 19.68,
47353
- precision: 0.9623,
47354
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47355
- verdict: "HYGIENE",
47356
- _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.",
47357
- aiSpecific: false
48224
+ "ai/whitespace-regularity": {
48225
+ recall: 0.0733,
48226
+ fpRate: 0.0677,
48227
+ ratio: 8.25,
48228
+ precision: 0.5583,
48229
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48230
+ verdict: "USEFUL",
48231
+ _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).",
48232
+ aiSpecific: true,
48233
+ _v7Verdict: "USEFUL",
48234
+ _v7Lift: 7.71,
48235
+ _v7Recall: 0.0737,
48236
+ _v7FpRate: 0.0733,
48237
+ _v7Precision: 0.5652,
48238
+ _v8Verdict: "USEFUL",
48239
+ _v8Lift: 10.06
47358
48240
  },
47359
- "wcag/target-size": {
48241
+ "arch/astro-island-leak": {
47360
48242
  recall: 0,
47361
48243
  fpRate: 0,
47362
48244
  ratio: 0,
47363
48245
  precision: 0,
47364
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48246
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47365
48247
  verdict: "DORMANT",
47366
- defaultOff: true,
47367
- _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.)",
47368
- aiSpecific: false
48248
+ _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.",
48249
+ aiSpecific: true,
48250
+ _v7Verdict: "DORMANT",
48251
+ _v7Lift: 0,
48252
+ _v7Recall: 0,
48253
+ _v7FpRate: 0,
48254
+ _v7Precision: 0,
48255
+ _v8Verdict: "DORMANT",
48256
+ _v8Lift: 1,
48257
+ defaultOff: true
47369
48258
  },
47370
- "component/multiple-components-per-file": {
47371
- recall: 0.0681,
47372
- fpRate: 0.052,
47373
- ratio: 1.31,
47374
- precision: 0.6294,
47375
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47376
- verdict: "HYGIENE",
47377
- _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.",
47378
- aiSpecific: false
47379
- },
47380
- "context/import-path-mismatch": {
47381
- recall: 0.0739,
47382
- fpRate: 0.0228,
47383
- ratio: 3.25,
47384
- precision: 0.8079,
47385
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47386
- verdict: "HYGIENE",
47387
- _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.",
47388
- aiSpecific: false
48259
+ "component/giant-component": {
48260
+ recall: 0.0181,
48261
+ fpRate: 59e-4,
48262
+ ratio: 132.31,
48263
+ precision: 0.7815,
48264
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48265
+ verdict: "USEFUL",
48266
+ _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).",
48267
+ aiSpecific: true,
48268
+ _v7Verdict: "USEFUL",
48269
+ _v7Lift: 97.16,
48270
+ _v7Recall: 0.0177,
48271
+ _v7FpRate: 77e-4,
48272
+ _v7Precision: 0.7485,
48273
+ _v8Verdict: "USEFUL",
48274
+ _v8Lift: 846.15
47389
48275
  },
47390
- "logic/key-prop-missing": {
47391
- recall: 17e-4,
47392
- fpRate: 14e-4,
47393
- ratio: 1.28,
47394
- precision: 0.6246,
47395
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47396
- verdict: "HYGIENE",
47397
- _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.",
47398
- aiSpecific: false
48276
+ "component/multiple-components-per-file": {
48277
+ recall: 0.0751,
48278
+ fpRate: 0.0423,
48279
+ ratio: 15.96,
48280
+ precision: 0.6747,
48281
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48282
+ verdict: "USEFUL",
48283
+ _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).",
48284
+ aiSpecific: false,
48285
+ _v7Verdict: "USEFUL",
48286
+ _v7Lift: 12.04,
48287
+ _v7Recall: 0.0687,
48288
+ _v7FpRate: 0.0523,
48289
+ _v7Precision: 0.6294,
48290
+ _v8Verdict: "USEFUL",
48291
+ _v8Lift: 54.44
47399
48292
  },
47400
- "logic/math-variable-name-entropy": {
47401
- recall: 2e-4,
48293
+ "component/shadcn-prop-mismatch": {
48294
+ recall: 16e-4,
47402
48295
  fpRate: 1e-4,
47403
- ratio: 1.07,
47404
- precision: 0.5806,
47405
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47406
- verdict: "HYGIENE",
47407
- _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.",
47408
- aiSpecific: false
47409
- },
47410
- "security/public-admin-route": {
47411
- recall: 28e-4,
47412
- fpRate: 78e-4,
47413
- ratio: 0.4,
47414
- precision: 0.2251,
47415
- lastCalibratedAt: "2026-06-26T22:30:00Z",
47416
- verdict: "HYGIENE",
47417
- _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]",
47418
- defaultOff: true,
47419
- aiSpecific: false
47420
- },
47421
- "security/unsafe-html-render": {
47422
- recall: 13e-4,
47423
- fpRate: 9e-4,
47424
- ratio: 1.5,
47425
- precision: 0.661,
47426
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47427
- verdict: "HYGIENE",
47428
- _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.",
47429
- aiSpecific: false
47430
- },
47431
- "visual/naturalness-anomaly": {
47432
- recall: 0.1645,
47433
- fpRate: 0.0617,
47434
- ratio: 2.67,
47435
- precision: 0.7755,
47436
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48296
+ ratio: 9990.98,
48297
+ precision: 0.9512,
48298
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47437
48299
  verdict: "USEFUL",
47438
- _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.",
47439
- aiSpecific: true
48300
+ _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).",
48301
+ aiSpecific: true,
48302
+ _v7Verdict: "USEFUL",
48303
+ _v7Lift: 7099.57,
48304
+ _v7Recall: 13e-4,
48305
+ _v7FpRate: 1e-4,
48306
+ _v7Precision: 0.929,
48307
+ _v8Verdict: "USEFUL",
48308
+ _v8Lift: 99999
47440
48309
  },
47441
- "perf/halstead-anomaly": {
47442
- recall: 0,
47443
- fpRate: 0,
47444
- ratio: 2.32,
47445
- precision: 0.75,
47446
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48310
+ "context/import-path-mismatch": {
48311
+ recall: 0.0681,
48312
+ fpRate: 0.0167,
48313
+ ratio: 49.48,
48314
+ precision: 0.8263,
48315
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47447
48316
  verdict: "USEFUL",
47448
- _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.",
47449
- aiSpecific: true
48317
+ _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).",
48318
+ aiSpecific: false,
48319
+ _v7Verdict: "USEFUL",
48320
+ _v7Lift: 35.26,
48321
+ _v7Recall: 0.0746,
48322
+ _v7FpRate: 0.0229,
48323
+ _v7Precision: 0.8079,
48324
+ _v8Verdict: "USEFUL",
48325
+ _v8Lift: 8554.38
47450
48326
  },
47451
- "arch/astro-island-leak": {
48327
+ "db/duplicate-index": {
47452
48328
  recall: 0,
47453
48329
  fpRate: 0,
47454
48330
  ratio: 0,
47455
48331
  precision: 0,
47456
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48332
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47457
48333
  verdict: "DORMANT",
47458
- defaultOff: true,
47459
- _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.)",
47460
- aiSpecific: true
48334
+ _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.",
48335
+ aiSpecific: false,
48336
+ _v7Verdict: "DORMANT",
48337
+ _v7Lift: 0,
48338
+ _v7Recall: 0,
48339
+ _v7FpRate: 0,
48340
+ _v7Precision: 0,
48341
+ _v8Verdict: "DORMANT",
48342
+ _v8Lift: 1,
48343
+ defaultOff: true
47461
48344
  },
47462
- "logic/qwik-hook-leak": {
48345
+ "db/enum-sprawl": {
47463
48346
  recall: 0,
47464
48347
  fpRate: 0,
47465
48348
  ratio: 0,
47466
48349
  precision: 0,
47467
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48350
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47468
48351
  verdict: "DORMANT",
47469
- defaultOff: true,
47470
- _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.)",
47471
- aiSpecific: true
48352
+ _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.",
48353
+ aiSpecific: false,
48354
+ _v7Verdict: "DORMANT",
48355
+ _v7Lift: 0,
48356
+ _v7Recall: 0,
48357
+ _v7FpRate: 0,
48358
+ _v7Precision: 0,
48359
+ _v8Verdict: "DORMANT",
48360
+ _v8Lift: 1,
48361
+ defaultOff: true
47472
48362
  },
47473
- "test/missing-edge-case": {
48363
+ "db/missing-fk-index": {
47474
48364
  recall: 0,
47475
48365
  fpRate: 0,
47476
48366
  ratio: 0,
47477
48367
  precision: 0,
47478
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48368
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47479
48369
  verdict: "DORMANT",
47480
- defaultOff: true,
47481
- _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.)",
47482
- aiSpecific: true
48370
+ _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.",
48371
+ aiSpecific: false,
48372
+ _v7Verdict: "DORMANT",
48373
+ _v7Lift: 0,
48374
+ _v7Recall: 0,
48375
+ _v7FpRate: 0,
48376
+ _v7Precision: 0,
48377
+ _v8Verdict: "DORMANT",
48378
+ _v8Lift: 1,
48379
+ defaultOff: true
47483
48380
  },
47484
- "typo/calc-fontsize": {
48381
+ "db/missing-not-null": {
47485
48382
  recall: 0,
47486
48383
  fpRate: 0,
47487
48384
  ratio: 0,
47488
48385
  precision: 0,
47489
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48386
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47490
48387
  verdict: "DORMANT",
47491
- defaultOff: true,
47492
- _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).)",
47493
- aiSpecific: false
48388
+ _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.",
48389
+ aiSpecific: false,
48390
+ _v7Verdict: "DORMANT",
48391
+ _v7Lift: 0,
48392
+ _v7Recall: 0,
48393
+ _v7FpRate: 0,
48394
+ _v7Precision: 0,
48395
+ _v8Verdict: "DORMANT",
48396
+ _v8Lift: 1,
48397
+ defaultOff: true
47494
48398
  },
47495
- "typo/clamp-offscale": {
48399
+ "db/naming-inconsistency": {
47496
48400
  recall: 0,
47497
48401
  fpRate: 0,
47498
48402
  ratio: 0,
47499
48403
  precision: 0,
47500
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48404
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47501
48405
  verdict: "DORMANT",
47502
- defaultOff: true,
47503
- _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.)",
47504
- aiSpecific: false
48406
+ _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.",
48407
+ aiSpecific: false,
48408
+ _v7Verdict: "DORMANT",
48409
+ _v7Lift: 0,
48410
+ _v7Recall: 0,
48411
+ _v7FpRate: 0,
48412
+ _v7Precision: 0,
48413
+ _v8Verdict: "DORMANT",
48414
+ _v8Lift: 1,
48415
+ defaultOff: true
47505
48416
  },
47506
- "typo/math-cta-vocabulary": {
48417
+ "db/sql-concat": {
48418
+ recall: 5e-4,
48419
+ fpRate: 1e-4,
48420
+ ratio: 7511.26,
48421
+ precision: 0.8343,
48422
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48423
+ verdict: "USEFUL",
48424
+ _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).",
48425
+ aiSpecific: true,
48426
+ _v7Verdict: "DORMANT",
48427
+ _v7Lift: 1,
48428
+ _v7Recall: 0,
48429
+ _v7FpRate: 0,
48430
+ _v7Precision: 0,
48431
+ _v8Verdict: "USEFUL",
48432
+ _v8Lift: 2046.08
48433
+ },
48434
+ "dead/dead-branch": {
48435
+ recall: 2e-4,
48436
+ fpRate: 4e-4,
48437
+ ratio: 1080.68,
48438
+ precision: 0.4244,
48439
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48440
+ verdict: "OK",
48441
+ _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.",
48442
+ aiSpecific: true,
48443
+ _v7Verdict: "DORMANT",
48444
+ _v7Lift: 1,
48445
+ _v7Recall: 0,
48446
+ _v7FpRate: 0,
48447
+ _v7Precision: 0,
48448
+ _v8Verdict: "OK",
48449
+ _v8Lift: 294.38
48450
+ },
48451
+ "dead/unreachable": {
48452
+ recall: 1e-4,
48453
+ fpRate: 6e-4,
48454
+ ratio: 153.14,
48455
+ precision: 0.0966,
48456
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48457
+ verdict: "OK",
48458
+ _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.",
48459
+ aiSpecific: true,
48460
+ _v7Verdict: "DORMANT",
48461
+ _v7Lift: 1,
48462
+ _v7Recall: 0,
48463
+ _v7FpRate: 0,
48464
+ _v7Precision: 0,
48465
+ _v8Verdict: "OK",
48466
+ _v8Lift: 41.71
48467
+ },
48468
+ "dead/unused-import": {
48469
+ recall: 0.0379,
48470
+ fpRate: 0.0222,
48471
+ ratio: 30.06,
48472
+ precision: 0.6662,
48473
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48474
+ verdict: "USEFUL",
48475
+ _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.",
48476
+ aiSpecific: true,
48477
+ _v7Verdict: "DORMANT",
48478
+ _v7Lift: 1,
48479
+ _v7Recall: 0,
48480
+ _v7FpRate: 0,
48481
+ _v7Precision: 0,
48482
+ _v8Verdict: "USEFUL",
48483
+ _v8Lift: 8.19
48484
+ },
48485
+ "dead/unused-local": {
48486
+ recall: 0.0477,
48487
+ fpRate: 74e-4,
48488
+ ratio: 120.18,
48489
+ precision: 0.8834,
48490
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48491
+ verdict: "USEFUL",
48492
+ _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.",
48493
+ aiSpecific: true,
48494
+ _v7Verdict: "DORMANT",
48495
+ _v7Lift: 1,
48496
+ _v7Recall: 0,
48497
+ _v7FpRate: 0,
48498
+ _v7Precision: 0,
48499
+ _v8Verdict: "USEFUL",
48500
+ _v8Lift: 32.74
48501
+ },
48502
+ "dead/unused-parameter": {
48503
+ recall: 8e-4,
48504
+ fpRate: 27e-4,
48505
+ ratio: 98,
48506
+ precision: 0.2628,
48507
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48508
+ verdict: "OK",
48509
+ _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.",
48510
+ aiSpecific: true,
48511
+ _v7Verdict: "DORMANT",
48512
+ _v7Lift: 1,
48513
+ _v7Recall: 0,
48514
+ _v7FpRate: 0,
48515
+ _v7Precision: 0,
48516
+ _v8Verdict: "OK",
48517
+ _v8Lift: 26.7
48518
+ },
48519
+ "docs/broken-link": {
48520
+ recall: 14e-4,
48521
+ fpRate: 23e-4,
48522
+ ratio: 178.13,
48523
+ precision: 0.4155,
48524
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48525
+ verdict: "OK",
48526
+ _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).",
48527
+ aiSpecific: false,
48528
+ _v7Verdict: "DORMANT",
48529
+ _v7Lift: 1,
48530
+ _v7Recall: 0,
48531
+ _v7FpRate: 0,
48532
+ _v7Precision: 0,
48533
+ _v8Verdict: "OK",
48534
+ _v8Lift: 48.52
48535
+ },
48536
+ "docs/expired-code-example": {
47507
48537
  recall: 0,
47508
48538
  fpRate: 0,
47509
48539
  ratio: 0,
47510
48540
  precision: 0,
47511
- lastCalibratedAt: "2026-06-25T00:00:00Z",
47512
- verdict: "DORMANT",
47513
- defaultOff: true,
47514
- _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.)",
47515
- aiSpecific: true
48541
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48542
+ verdict: "INVERTED",
48543
+ _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).",
48544
+ aiSpecific: false,
48545
+ _v7Verdict: "DORMANT",
48546
+ _v7Lift: 1,
48547
+ _v7Recall: 0,
48548
+ _v7FpRate: 0,
48549
+ _v7Precision: 0,
48550
+ _v8Verdict: "INVERTED",
48551
+ _v8Lift: 0,
48552
+ defaultOff: true
48553
+ },
48554
+ "docs/stale-function-reference": {
48555
+ recall: 26e-4,
48556
+ fpRate: 5e-4,
48557
+ ratio: 1638.47,
48558
+ precision: 0.8515,
48559
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48560
+ verdict: "USEFUL",
48561
+ _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).",
48562
+ aiSpecific: false,
48563
+ _v7Verdict: "DORMANT",
48564
+ _v7Lift: 1,
48565
+ _v7Recall: 0,
48566
+ _v7FpRate: 0,
48567
+ _v7Precision: 0,
48568
+ _v8Verdict: "USEFUL",
48569
+ _v8Lift: 446.32
48570
+ },
48571
+ "docs/stale-package-reference": {
48572
+ recall: 2e-4,
48573
+ fpRate: 4e-4,
48574
+ ratio: 939.43,
48575
+ precision: 0.3429,
48576
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48577
+ verdict: "OK",
48578
+ _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).",
48579
+ aiSpecific: false,
48580
+ _v7Verdict: "DORMANT",
48581
+ _v7Lift: 1,
48582
+ _v7Recall: 0,
48583
+ _v7FpRate: 0,
48584
+ _v7Precision: 0,
48585
+ _v8Verdict: "OK",
48586
+ _v8Lift: 255.9
47516
48587
  },
47517
48588
  "layout/forced-layout": {
47518
48589
  recall: 0,
47519
48590
  fpRate: 0,
47520
48591
  ratio: 0,
47521
48592
  precision: 0,
47522
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48593
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47523
48594
  verdict: "DORMANT",
47524
- defaultOff: true,
47525
- _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.)",
47526
- aiSpecific: true
48595
+ _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.",
48596
+ aiSpecific: true,
48597
+ _v7Verdict: "DORMANT",
48598
+ _v7Lift: 0,
48599
+ _v7Recall: 0,
48600
+ _v7FpRate: 0,
48601
+ _v7Precision: 0,
48602
+ _v8Verdict: "DORMANT",
48603
+ _v8Lift: 1,
48604
+ defaultOff: true
47527
48605
  },
47528
- "visual/generic-centering": {
48606
+ "layout/gap-monopoly": {
48607
+ recall: 3e-4,
48608
+ fpRate: 1e-4,
48609
+ ratio: 8859.33,
48610
+ precision: 0.8083,
48611
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48612
+ verdict: "USEFUL",
48613
+ _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).",
48614
+ aiSpecific: false,
48615
+ _v7Verdict: "USEFUL",
48616
+ _v7Lift: 6322.11,
48617
+ _v7Recall: 4e-4,
48618
+ _v7FpRate: 1e-4,
48619
+ _v7Precision: 0.7928,
48620
+ _v8Verdict: "USEFUL",
48621
+ _v8Lift: 99999
48622
+ },
48623
+ "layout/math-element-uniformity": {
48624
+ recall: 29e-4,
48625
+ fpRate: 1e-3,
48626
+ ratio: 770.74,
48627
+ precision: 0.7705,
48628
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48629
+ verdict: "USEFUL",
48630
+ _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).",
48631
+ aiSpecific: true,
48632
+ _v7Verdict: "USEFUL",
48633
+ _v7Lift: 609.32,
48634
+ _v7Recall: 28e-4,
48635
+ _v7FpRate: 12e-4,
48636
+ _v7Precision: 0.7475,
48637
+ _v8Verdict: "USEFUL",
48638
+ _v8Lift: 2211.5
48639
+ },
48640
+ "layout/math-grid-uniformity": {
48641
+ recall: 3e-4,
48642
+ fpRate: 1e-4,
48643
+ ratio: 5839.98,
48644
+ precision: 0.7182,
48645
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48646
+ verdict: "USEFUL",
48647
+ _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).",
48648
+ aiSpecific: true,
48649
+ _v7Verdict: "USEFUL",
48650
+ _v7Lift: 4222.91,
48651
+ _v7Recall: 3e-4,
48652
+ _v7FpRate: 2e-4,
48653
+ _v7Precision: 0.6907,
48654
+ _v8Verdict: "USEFUL",
48655
+ _v8Lift: 63384.92
48656
+ },
48657
+ "layout/spacing-grid": {
48658
+ recall: 2e-4,
48659
+ fpRate: 2e-4,
48660
+ ratio: 4051.29,
48661
+ precision: 0.6429,
48662
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48663
+ verdict: "USEFUL",
48664
+ _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).",
48665
+ aiSpecific: false,
48666
+ _v7Verdict: "USEFUL",
48667
+ _v7Lift: 8831,
48668
+ _v7Recall: 2e-4,
48669
+ _v7FpRate: 1e-4,
48670
+ _v7Precision: 0.7222,
48671
+ _v8Verdict: "USEFUL",
48672
+ _v8Lift: 1562.77
48673
+ },
48674
+ "logic/bayesian-conditional": {
47529
48675
  recall: 0,
47530
48676
  fpRate: 0,
47531
48677
  ratio: 0,
47532
48678
  precision: 0,
47533
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48679
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47534
48680
  verdict: "DORMANT",
47535
- defaultOff: true,
47536
- _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.)",
47537
- aiSpecific: true
48681
+ _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.",
48682
+ aiSpecific: true,
48683
+ _v7Verdict: "DORMANT",
48684
+ _v7Lift: 0,
48685
+ _v7Recall: 0,
48686
+ _v7FpRate: 0,
48687
+ _v7Precision: 0,
48688
+ _v8Verdict: "DORMANT",
48689
+ _v8Lift: 1,
48690
+ defaultOff: true
47538
48691
  },
47539
- "product/terminology-drift": {
47540
- recall: 85e-4,
47541
- fpRate: 28e-4,
47542
- ratio: 3,
47543
- precision: 0.7956,
47544
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47545
- verdict: "HYGIENE",
47546
- _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.",
47547
- aiSpecific: false
48692
+ "logic/boundary-violation": {
48693
+ recall: 0.0274,
48694
+ fpRate: 0.0137,
48695
+ ratio: 51.32,
48696
+ precision: 0.7006,
48697
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48698
+ verdict: "USEFUL",
48699
+ _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).",
48700
+ aiSpecific: false,
48701
+ _v7Verdict: "USEFUL",
48702
+ _v7Lift: 37.42,
48703
+ _v7Recall: 0.0265,
48704
+ _v7FpRate: 0.0176,
48705
+ _v7Precision: 0.6601,
48706
+ _v8Verdict: "USEFUL",
48707
+ _v8Lift: 298.57
47548
48708
  },
47549
- "product/ux-pattern-fragmentation": {
48709
+ "logic/ghost-defensive": {
47550
48710
  recall: 1e-4,
47551
48711
  fpRate: 0,
47552
- ratio: 3.09,
47553
- precision: 0.8,
47554
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48712
+ ratio: 112035.56,
48713
+ precision: 0.8889,
48714
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47555
48715
  verdict: "USEFUL",
47556
- _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.",
47557
- aiSpecific: true
48716
+ _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).",
48717
+ aiSpecific: true,
48718
+ _v7Verdict: "USEFUL",
48719
+ _v7Lift: 80917.5,
48720
+ _v7Recall: 1e-4,
48721
+ _v7FpRate: 0,
48722
+ _v7Precision: 0.8824,
48723
+ _v8Verdict: "USEFUL",
48724
+ _v8Lift: 99999
47558
48725
  },
47559
- "security/sql-construction": {
47560
- recall: 3e-3,
47561
- fpRate: 18e-4,
47562
- ratio: 1.63,
47563
- precision: 0.6788,
47564
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48726
+ "logic/heaps-deviation": {
48727
+ recall: 0.0126,
48728
+ fpRate: 0.0178,
48729
+ ratio: 25.54,
48730
+ precision: 0.4536,
48731
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47565
48732
  verdict: "OK",
47566
- _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.",
47567
- aiSpecific: true
48733
+ _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).",
48734
+ aiSpecific: false,
48735
+ _v7Verdict: "USEFUL",
48736
+ _v7Lift: 41.22,
48737
+ _v7Recall: 0.0123,
48738
+ _v7FpRate: 0.0132,
48739
+ _v7Precision: 0.5461,
48740
+ _v8Verdict: "OK",
48741
+ _v8Lift: 9.36
47568
48742
  },
47569
- "security/missing-auth-check": {
47570
- recall: 63e-4,
47571
- fpRate: 4e-4,
47572
- ratio: 15.3,
47573
- precision: 0.9247,
47574
- lastCalibratedAt: "2026-06-26T22:30:00Z",
48743
+ "logic/key-prop-missing": {
48744
+ recall: 16e-4,
48745
+ fpRate: 11e-4,
48746
+ ratio: 574.52,
48747
+ precision: 0.629,
48748
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47575
48749
  verdict: "USEFUL",
47576
- _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.",
47577
- aiSpecific: false
48750
+ _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).",
48751
+ aiSpecific: false,
48752
+ _v7Verdict: "USEFUL",
48753
+ _v7Lift: 458.26,
48754
+ _v7Recall: 18e-4,
48755
+ _v7FpRate: 14e-4,
48756
+ _v7Precision: 0.6246,
48757
+ _v8Verdict: "USEFUL",
48758
+ _v8Lift: 1760.69
47578
48759
  },
47579
- "security/dangerous-cors": {
47580
- recall: 5e-4,
47581
- fpRate: 5e-4,
47582
- ratio: 1.05,
47583
- precision: 0.5758,
47584
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48760
+ "logic/ks-distribution-shift": {
48761
+ recall: 0.6889,
48762
+ fpRate: 0.4411,
48763
+ ratio: 1.46,
48764
+ precision: 0.6457,
48765
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47585
48766
  verdict: "NOISY",
47586
- _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.",
47587
- defaultOff: true,
47588
- aiSpecific: true
48767
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=202658, FP=111193, P=64.6%, FPR=44.11%, lift=1.46. v7 was USEFUL (TP=152391, FP=62358, lift=2.09). v8 was INVERTED (TP=50267, FP=48835).",
48768
+ aiSpecific: false,
48769
+ _v7Verdict: "USEFUL",
48770
+ _v7Lift: 2.09,
48771
+ _v7Recall: 0.6431,
48772
+ _v7FpRate: 0.34,
48773
+ _v7Precision: 0.7096,
48774
+ _v8Verdict: "INVERTED",
48775
+ _v8Lift: 0.71,
48776
+ defaultOff: true
47589
48777
  },
47590
- "test/duplicate-setup": {
47591
- recall: 1e-4,
47592
- fpRate: 0,
47593
- ratio: 3.6,
47594
- precision: 0.8235,
47595
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47596
- verdict: "USEFUL",
47597
- _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.",
47598
- aiSpecific: true
47599
- },
47600
- "logic/ghost-defensive": {
47601
- recall: 1e-4,
47602
- fpRate: 0,
47603
- ratio: 5.79,
47604
- precision: 0.8824,
47605
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47606
- verdict: "USEFUL",
47607
- _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.",
47608
- aiSpecific: true
47609
- },
47610
- "typo/calc-raw-px": {
47611
- recall: 0,
47612
- fpRate: 0,
47613
- ratio: 2.32,
47614
- precision: 0.75,
47615
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47616
- verdict: "HYGIENE",
47617
- _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.",
47618
- aiSpecific: false
47619
- },
47620
- "security/fail-open-auth": {
47621
- recall: 0,
47622
- fpRate: 0,
47623
- ratio: 99.99,
47624
- precision: 1,
47625
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48778
+ "logic/math-any-density": {
48779
+ recall: 17e-4,
48780
+ fpRate: 13e-4,
48781
+ ratio: 464.59,
48782
+ precision: 0.6027,
48783
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47626
48784
  verdict: "USEFUL",
47627
- _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.",
47628
- aiSpecific: true
47629
- },
47630
- "wcag/focus-obscured": {
47631
- recall: 33e-4,
47632
- fpRate: 9e-4,
47633
- ratio: 3.51,
47634
- precision: 0.82,
47635
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47636
- verdict: "HYGIENE",
47637
- _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.",
47638
- aiSpecific: false
48785
+ _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).",
48786
+ aiSpecific: true,
48787
+ _v7Verdict: "USEFUL",
48788
+ _v7Lift: 448.16,
48789
+ _v7Recall: 16e-4,
48790
+ _v7FpRate: 13e-4,
48791
+ _v7Precision: 0.6035,
48792
+ _v8Verdict: "USEFUL",
48793
+ _v8Lift: 515
47639
48794
  },
47640
- "visual/arbitrary-escape": {
47641
- recall: 25e-4,
47642
- fpRate: 9e-4,
47643
- ratio: 2.74,
47644
- precision: 0.7802,
47645
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48795
+ "logic/math-console-log-storm": {
48796
+ recall: 65e-4,
48797
+ fpRate: 11e-4,
48798
+ ratio: 794.4,
48799
+ precision: 0.8729,
48800
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47646
48801
  verdict: "USEFUL",
47647
- _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.",
47648
- aiSpecific: true
48802
+ _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).",
48803
+ aiSpecific: true,
48804
+ _v7Verdict: "USEFUL",
48805
+ _v7Lift: 852.3,
48806
+ _v7Recall: 71e-4,
48807
+ _v7FpRate: 11e-4,
48808
+ _v7Precision: 0.8968,
48809
+ _v8Verdict: "USEFUL",
48810
+ _v8Lift: 595.24
47649
48811
  },
47650
- "security/hardcoded-secret": {
48812
+ "logic/math-gini-class-usage": {
47651
48813
  recall: 13e-4,
47652
- fpRate: 7e-4,
47653
- ratio: 1.72,
47654
- precision: 0.6899,
47655
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47656
- verdict: "OK",
47657
- _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.",
47658
- aiSpecific: true
47659
- },
47660
- "visual/radius-scale-violation": {
47661
- recall: 4e-4,
47662
- fpRate: 0,
47663
- ratio: 24.7,
47664
- precision: 0.9697,
47665
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47666
- verdict: "HYGIENE",
47667
- _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.",
47668
- aiSpecific: false
47669
- },
47670
- "test/fake-placeholder": {
47671
- recall: 53e-4,
47672
- fpRate: 19e-4,
47673
- ratio: 2.82,
47674
- precision: 0.7854,
47675
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48814
+ fpRate: 2e-4,
48815
+ ratio: 4648.6,
48816
+ precision: 0.8852,
48817
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47676
48818
  verdict: "USEFUL",
47677
- _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.",
47678
- aiSpecific: true
47679
- },
47680
- "security/exposed-env-var": {
47681
- recall: 6e-4,
47682
- fpRate: 7e-4,
47683
- ratio: 0.9,
47684
- precision: 0.5387,
47685
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47686
- verdict: "HYGIENE",
47687
- _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.",
47688
- aiSpecific: false
47689
- },
47690
- "perf/cls-image": {
47691
- recall: 2e-4,
47692
- fpRate: 3e-4,
47693
- ratio: 0.8,
47694
- precision: 0.5104,
47695
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47696
- verdict: "HYGIENE",
47697
- _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.",
47698
- aiSpecific: false
47699
- },
47700
- "layout/gap-monopoly": {
47701
- recall: 4e-4,
47702
- fpRate: 1e-4,
47703
- ratio: 2.95,
47704
- precision: 0.7928,
47705
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47706
- verdict: "HYGIENE",
47707
- _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.",
47708
- aiSpecific: false
47709
- },
47710
- "visual/spacing-scale-violation": {
47711
- recall: 83e-4,
47712
- fpRate: 39e-4,
47713
- ratio: 2.13,
47714
- precision: 0.7342,
47715
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47716
- verdict: "HYGIENE",
47717
- _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.",
47718
- aiSpecific: false
47719
- },
47720
- "visual/inline-style-dominance": {
47721
- recall: 96e-4,
47722
- fpRate: 66e-4,
47723
- ratio: 1.46,
47724
- precision: 0.6535,
47725
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47726
- verdict: "HYGIENE",
47727
- _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.",
47728
- aiSpecific: false
48819
+ _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).",
48820
+ aiSpecific: true,
48821
+ _v7Verdict: "USEFUL",
48822
+ _v7Lift: 3388.64,
48823
+ _v7Recall: 13e-4,
48824
+ _v7FpRate: 3e-4,
48825
+ _v7Precision: 0.8683,
48826
+ _v8Verdict: "USEFUL",
48827
+ _v8Lift: 67541.31
47729
48828
  },
47730
- "layout/spacing-grid": {
48829
+ "logic/math-variable-name-entropy": {
47731
48830
  recall: 2e-4,
47732
48831
  fpRate: 1e-4,
47733
- ratio: 2.01,
47734
- precision: 0.7222,
47735
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47736
- verdict: "HYGIENE",
47737
- _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.",
47738
- aiSpecific: false
47739
- },
47740
- "wcag/dragging-movements": {
47741
- recall: 0,
47742
- fpRate: 0,
47743
- ratio: 0.51,
47744
- precision: 0.4,
47745
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47746
- verdict: "HYGIENE",
47747
- _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.",
47748
- aiSpecific: false
48832
+ ratio: 4548.81,
48833
+ precision: 0.6316,
48834
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48835
+ verdict: "USEFUL",
48836
+ _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).",
48837
+ aiSpecific: false,
48838
+ _v7Verdict: "USEFUL",
48839
+ _v7Lift: 4096.07,
48840
+ _v7Recall: 2e-4,
48841
+ _v7FpRate: 1e-4,
48842
+ _v7Precision: 0.5806,
48843
+ _v8Verdict: "USEFUL",
48844
+ _v8Lift: 5548.85
47749
48845
  },
47750
- "test/weak-assertion": {
47751
- recall: 0.0414,
47752
- fpRate: 86e-4,
47753
- ratio: 4.83,
47754
- precision: 0.8622,
47755
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48846
+ "logic/optimistic-no-rollback": {
48847
+ recall: 12e-4,
48848
+ fpRate: 2e-4,
48849
+ ratio: 3523.57,
48850
+ precision: 0.8527,
48851
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47756
48852
  verdict: "USEFUL",
47757
- _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.",
47758
- aiSpecific: true
48853
+ _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).",
48854
+ aiSpecific: true,
48855
+ _v7Verdict: "USEFUL",
48856
+ _v7Lift: 2519.02,
48857
+ _v7Recall: 12e-4,
48858
+ _v7FpRate: 3e-4,
48859
+ _v7Precision: 0.824,
48860
+ _v8Verdict: "USEFUL",
48861
+ _v8Lift: 67726.36
47759
48862
  },
47760
- "logic/bayesian-conditional": {
48863
+ "logic/qwik-hook-leak": {
47761
48864
  recall: 0,
47762
48865
  fpRate: 0,
47763
48866
  ratio: 0,
47764
48867
  precision: 0,
47765
- lastCalibratedAt: "2026-06-27T00:00:00Z",
48868
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47766
48869
  verdict: "DORMANT",
47767
- defaultOff: true,
47768
- _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.",
47769
- aiSpecific: true
47770
- },
47771
- "logic/heaps-deviation": {
47772
- recall: 0.0122,
47773
- fpRate: 0.0132,
47774
- ratio: 0.93,
47775
- precision: 0.5461,
47776
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47777
- verdict: "HYGIENE",
47778
- _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.",
47779
- aiSpecific: false
48870
+ _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.",
48871
+ aiSpecific: true,
48872
+ _v7Verdict: "DORMANT",
48873
+ _v7Lift: 0,
48874
+ _v7Recall: 0,
48875
+ _v7FpRate: 0,
48876
+ _v7Precision: 0,
48877
+ _v8Verdict: "DORMANT",
48878
+ _v8Lift: 1,
48879
+ defaultOff: true
47780
48880
  },
47781
- "logic/ks-distribution-shift": {
47782
- recall: 0.6375,
47783
- fpRate: 0.338,
47784
- ratio: 1.89,
47785
- precision: 0.7096,
47786
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47787
- verdict: "HYGIENE",
47788
- _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.",
47789
- aiSpecific: false
48881
+ "logic/reactive-hook-soup": {
48882
+ recall: 41e-4,
48883
+ fpRate: 6e-4,
48884
+ ratio: 1370.15,
48885
+ precision: 0.8805,
48886
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48887
+ verdict: "USEFUL",
48888
+ _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).",
48889
+ aiSpecific: true,
48890
+ _v7Verdict: "USEFUL",
48891
+ _v7Lift: 959.64,
48892
+ _v7Recall: 38e-4,
48893
+ _v7FpRate: 9e-4,
48894
+ _v7Precision: 0.8476,
48895
+ _v8Verdict: "USEFUL",
48896
+ _v8Lift: 99999
47790
48897
  },
47791
48898
  "logic/zipf-slope-anomaly": {
47792
- recall: 0.0156,
47793
- fpRate: 87e-4,
47794
- ratio: 1.79,
47795
- precision: 0.6983,
47796
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47797
- verdict: "HYGIENE",
47798
- _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.",
47799
- aiSpecific: false
48899
+ recall: 0.0168,
48900
+ fpRate: 0.0111,
48901
+ ratio: 57.13,
48902
+ precision: 0.6369,
48903
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48904
+ verdict: "USEFUL",
48905
+ _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).",
48906
+ aiSpecific: false,
48907
+ _v7Verdict: "USEFUL",
48908
+ _v7Lift: 79.75,
48909
+ _v7Recall: 0.0157,
48910
+ _v7FpRate: 88e-4,
48911
+ _v7Precision: 0.6983,
48912
+ _v8Verdict: "USEFUL",
48913
+ _v8Lift: 28.59
47800
48914
  },
47801
- "ai/markdown-leakage": {
47802
- recall: 0,
48915
+ "logic/zombie-state": {
48916
+ recall: 1e-4,
47803
48917
  fpRate: 0,
47804
- ratio: 1.93,
47805
- precision: 0.7143,
47806
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47807
- verdict: "OK",
47808
- _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.",
47809
- aiSpecific: true
48918
+ ratio: 119891.71,
48919
+ precision: 0.9512,
48920
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48921
+ verdict: "USEFUL",
48922
+ _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).",
48923
+ aiSpecific: true,
48924
+ _v7Verdict: "USEFUL",
48925
+ _v7Lift: 84652.15,
48926
+ _v7Recall: 1e-4,
48927
+ _v7FpRate: 0,
48928
+ _v7Precision: 0.9231,
48929
+ _v8Verdict: "USEFUL",
48930
+ _v8Lift: 99999
47810
48931
  },
47811
- "ai/comment-ratio": {
47812
- recall: 0.2523,
47813
- fpRate: 0.1619,
47814
- ratio: 1.56,
47815
- precision: 0.6687,
47816
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47817
- verdict: "OK",
47818
- _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.",
47819
- aiSpecific: true
48932
+ "perf/cls-image": {
48933
+ recall: 2e-4,
48934
+ fpRate: 2e-4,
48935
+ ratio: 2895.78,
48936
+ precision: 0.5514,
48937
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48938
+ verdict: "USEFUL",
48939
+ _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).",
48940
+ aiSpecific: false,
48941
+ _v7Verdict: "USEFUL",
48942
+ _v7Lift: 1991.85,
48943
+ _v7Recall: 2e-4,
48944
+ _v7FpRate: 3e-4,
48945
+ _v7Precision: 0.5104,
48946
+ _v8Verdict: "USEFUL",
48947
+ _v8Lift: 62424.55
47820
48948
  },
47821
- "ai/whitespace-regularity": {
47822
- recall: 0.0731,
47823
- fpRate: 0.0728,
47824
- ratio: 1,
47825
- precision: 0.5652,
47826
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47827
- verdict: "NOISY",
47828
- _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.",
47829
- defaultOff: true,
47830
- aiSpecific: true
48949
+ "perf/css-bloat": {
48950
+ recall: 0.0126,
48951
+ fpRate: 24e-4,
48952
+ ratio: 365.63,
48953
+ precision: 0.8616,
48954
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48955
+ verdict: "USEFUL",
48956
+ _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).",
48957
+ aiSpecific: false,
48958
+ _v7Verdict: "USEFUL",
48959
+ _v7Lift: 256.1,
48960
+ _v7Recall: 0.0118,
48961
+ _v7FpRate: 32e-4,
48962
+ _v7Precision: 0.8252,
48963
+ _v8Verdict: "USEFUL",
48964
+ _v8Lift: 22813.54
47831
48965
  },
47832
- "ai/text-like-ratio": {
48966
+ "perf/halstead-anomaly": {
47833
48967
  recall: 0,
47834
48968
  fpRate: 0,
47835
- ratio: 2.32,
47836
- precision: 0.75,
47837
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48969
+ ratio: 75624,
48970
+ precision: 0.6,
48971
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47838
48972
  verdict: "USEFUL",
47839
- _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.",
47840
- aiSpecific: true
48973
+ _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).",
48974
+ aiSpecific: true,
48975
+ _v7Verdict: "USEFUL",
48976
+ _v7Lift: 137559.75,
48977
+ _v7Recall: 0,
48978
+ _v7FpRate: 0,
48979
+ _v7Precision: 0.75,
48980
+ _v8Verdict: "INVERTED",
48981
+ _v8Lift: 0
47841
48982
  },
47842
- "ai/errors-near-eof": {
47843
- recall: 0.0697,
47844
- fpRate: 0.0548,
47845
- ratio: 1.27,
47846
- precision: 0.6225,
47847
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47848
- verdict: "NOISY",
47849
- _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.",
47850
- defaultOff: true,
47851
- aiSpecific: true
48983
+ "product/terminology-drift": {
48984
+ recall: 91e-4,
48985
+ fpRate: 21e-4,
48986
+ ratio: 397.75,
48987
+ precision: 0.8347,
48988
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48989
+ verdict: "USEFUL",
48990
+ _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).",
48991
+ aiSpecific: false,
48992
+ _v7Verdict: "USEFUL",
48993
+ _v7Lift: 280.09,
48994
+ _v7Recall: 86e-4,
48995
+ _v7FpRate: 28e-4,
48996
+ _v7Precision: 0.7956,
48997
+ _v8Verdict: "USEFUL",
48998
+ _v8Lift: 8477.9
47852
48999
  },
47853
- "ai/any-density": {
47854
- recall: 55e-4,
47855
- fpRate: 41e-4,
47856
- ratio: 1.34,
47857
- precision: 0.634,
47858
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47859
- verdict: "NOISY",
47860
- _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.",
47861
- defaultOff: true,
47862
- aiSpecific: true
49000
+ "product/ux-pattern-fragmentation": {
49001
+ recall: 1e-4,
49002
+ fpRate: 0,
49003
+ ratio: 22864.4,
49004
+ precision: 0.8163,
49005
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49006
+ verdict: "USEFUL",
49007
+ _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).",
49008
+ aiSpecific: true,
49009
+ _v7Verdict: "USEFUL",
49010
+ _v7Lift: 18341.3,
49011
+ _v7Recall: 1e-4,
49012
+ _v7FpRate: 0,
49013
+ _v7Precision: 0.8,
49014
+ _v8Verdict: "USEFUL",
49015
+ _v8Lift: 61037.33
47863
49016
  },
47864
- "ai/renyi-profile": {
47865
- recall: 0,
49017
+ "rust/stringly-typed": {
49018
+ recall: 2e-4,
47866
49019
  fpRate: 0,
47867
- ratio: 0.26,
47868
- precision: 0.25,
47869
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47870
- verdict: "INVERTED",
47871
- _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.",
47872
- defaultOff: true,
47873
- aiSpecific: true
49020
+ ratio: 24735.12,
49021
+ precision: 0.8831,
49022
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49023
+ verdict: "USEFUL",
49024
+ _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).",
49025
+ aiSpecific: true,
49026
+ _v7Verdict: "DORMANT",
49027
+ _v7Lift: 1,
49028
+ _v7Recall: 0,
49029
+ _v7FpRate: 0,
49030
+ _v7Precision: 0,
49031
+ _v8Verdict: "USEFUL",
49032
+ _v8Lift: 6737.89
47874
49033
  },
47875
- "ai/log-rank-histogram": {
49034
+ "rust/todo-macro": {
49035
+ recall: 1e-4,
49036
+ fpRate: 7e-4,
49037
+ ratio: 210.08,
49038
+ precision: 0.1392,
49039
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49040
+ verdict: "OK",
49041
+ _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).",
49042
+ aiSpecific: true,
49043
+ _v7Verdict: "DORMANT",
49044
+ _v7Lift: 1,
49045
+ _v7Recall: 0,
49046
+ _v7FpRate: 0,
49047
+ _v7Precision: 0,
49048
+ _v8Verdict: "OK",
49049
+ _v8Lift: 57.23
49050
+ },
49051
+ "rust/unused-pub-fn": {
47876
49052
  recall: 0,
47877
49053
  fpRate: 0,
47878
- ratio: 0,
47879
- precision: 0,
47880
- lastCalibratedAt: "2026-06-27T00:00:00Z",
49054
+ ratio: 10803.43,
49055
+ precision: 0.3,
49056
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47881
49057
  verdict: "OK",
47882
- _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).",
47883
- aiSpecific: true
49058
+ _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).",
49059
+ aiSpecific: true,
49060
+ _v7Verdict: "DORMANT",
49061
+ _v7Lift: 1,
49062
+ _v7Recall: 0,
49063
+ _v7FpRate: 0,
49064
+ _v7Precision: 0,
49065
+ _v8Verdict: "OK",
49066
+ _v8Lift: 2942.87
47884
49067
  },
47885
- "ai/segment-surprisal-cv": {
47886
- recall: 0.182,
47887
- fpRate: 0.0812,
47888
- ratio: 2.24,
47889
- precision: 0.7438,
47890
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49068
+ "rust/unwrap-in-production": {
49069
+ recall: 8e-3,
49070
+ fpRate: 77e-4,
49071
+ ratio: 70.81,
49072
+ precision: 0.5475,
49073
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47891
49074
  verdict: "USEFUL",
47892
- _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.",
47893
- aiSpecific: true
49075
+ _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).",
49076
+ aiSpecific: true,
49077
+ _v7Verdict: "DORMANT",
49078
+ _v7Lift: 1,
49079
+ _v7Recall: 0,
49080
+ _v7FpRate: 0,
49081
+ _v7Precision: 0,
49082
+ _v8Verdict: "USEFUL",
49083
+ _v8Lift: 19.29
47894
49084
  },
47895
- "ai/compression-profile": {
47896
- recall: 0.3139,
47897
- fpRate: 0.1489,
47898
- ratio: 2.11,
47899
- precision: 0.732,
47900
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49085
+ "security/dangerous-cors": {
49086
+ recall: 5e-4,
49087
+ fpRate: 4e-4,
49088
+ ratio: 1721.87,
49089
+ precision: 0.6079,
49090
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47901
49091
  verdict: "USEFUL",
47902
- _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.",
47903
- aiSpecific: true
49092
+ _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).",
49093
+ aiSpecific: true,
49094
+ _v7Verdict: "USEFUL",
49095
+ _v7Lift: 1257.16,
49096
+ _v7Recall: 5e-4,
49097
+ _v7FpRate: 5e-4,
49098
+ _v7Precision: 0.5758,
49099
+ _v8Verdict: "USEFUL",
49100
+ _v8Lift: 11365.57
47904
49101
  },
47905
- "ai/tailwind-color-overuse": {
47906
- recall: 0.0216,
47907
- fpRate: 52e-4,
47908
- ratio: 4.16,
47909
- precision: 0.8436,
47910
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49102
+ "security/eval": {
49103
+ recall: 1e-4,
49104
+ fpRate: 2e-4,
49105
+ ratio: 1929.18,
49106
+ precision: 0.4286,
49107
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49108
+ verdict: "OK",
49109
+ _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).",
49110
+ aiSpecific: false,
49111
+ _v7Verdict: "DORMANT",
49112
+ _v7Lift: 1,
49113
+ _v7Recall: 0,
49114
+ _v7FpRate: 0,
49115
+ _v7Precision: 0,
49116
+ _v8Verdict: "OK",
49117
+ _v8Lift: 525.51
49118
+ },
49119
+ "security/exposed-env-var": {
49120
+ recall: 6e-4,
49121
+ fpRate: 5e-4,
49122
+ ratio: 1055.81,
49123
+ precision: 0.5696,
49124
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47911
49125
  verdict: "USEFUL",
47912
- _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.",
47913
- aiSpecific: true
49126
+ _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).",
49127
+ aiSpecific: false,
49128
+ _v7Verdict: "USEFUL",
49129
+ _v7Lift: 790.5,
49130
+ _v7Recall: 6e-4,
49131
+ _v7FpRate: 7e-4,
49132
+ _v7Precision: 0.5387,
49133
+ _v8Verdict: "USEFUL",
49134
+ _v8Lift: 4716.52
47914
49135
  },
47915
- "ai/default-react-stack": {
47916
- recall: 1e-3,
49136
+ "security/fail-open-auth": {
49137
+ recall: 0,
47917
49138
  fpRate: 0,
47918
- ratio: 99.99,
47919
- precision: 0.9957,
47920
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49139
+ ratio: 99999,
49140
+ precision: 1,
49141
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47921
49142
  verdict: "USEFUL",
47922
- _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.",
47923
- aiSpecific: true
49143
+ _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).",
49144
+ aiSpecific: true,
49145
+ _v7Verdict: "USEFUL",
49146
+ _v7Lift: 99999,
49147
+ _v7Recall: 0,
49148
+ _v7FpRate: 0,
49149
+ _v7Precision: 1,
49150
+ _v8Verdict: "DORMANT",
49151
+ _v8Lift: 1
47924
49152
  },
47925
- "ai/library-reinvention": {
47926
- recall: 3e-4,
49153
+ "security/hardcoded-secret": {
49154
+ recall: 14e-4,
49155
+ fpRate: 6e-4,
49156
+ ratio: 1269.08,
49157
+ precision: 0.735,
49158
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49159
+ verdict: "USEFUL",
49160
+ _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).",
49161
+ aiSpecific: true,
49162
+ _v7Verdict: "USEFUL",
49163
+ _v7Lift: 916.92,
49164
+ _v7Recall: 13e-4,
49165
+ _v7FpRate: 8e-4,
49166
+ _v7Precision: 0.6899,
49167
+ _v8Verdict: "USEFUL",
49168
+ _v8Lift: 7935.57
49169
+ },
49170
+ "security/localstorage-token": {
49171
+ recall: 1e-4,
47927
49172
  fpRate: 0,
47928
- ratio: 9.88,
47929
- precision: 0.9275,
47930
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49173
+ ratio: 99999,
49174
+ precision: 1,
49175
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47931
49176
  verdict: "USEFUL",
47932
- _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.",
47933
- aiSpecific: true
49177
+ _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).",
49178
+ aiSpecific: false,
49179
+ _v7Verdict: "DORMANT",
49180
+ _v7Lift: 1,
49181
+ _v7Recall: 0,
49182
+ _v7FpRate: 0,
49183
+ _v7Precision: 0,
49184
+ _v8Verdict: "USEFUL",
49185
+ _v8Lift: 99999
47934
49186
  },
47935
- "ai/state-default-overuse": {
47936
- recall: 29e-4,
47937
- fpRate: 9e-4,
47938
- ratio: 3.42,
47939
- precision: 0.8161,
47940
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49187
+ "security/missing-auth-check": {
49188
+ recall: 5e-4,
49189
+ fpRate: 0,
49190
+ ratio: 99999,
49191
+ precision: 1,
49192
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47941
49193
  verdict: "USEFUL",
47942
- _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.",
47943
- aiSpecific: true
49194
+ _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).",
49195
+ aiSpecific: false,
49196
+ _v7Verdict: "DORMANT",
49197
+ _v7Lift: 1,
49198
+ _v7Recall: 0,
49199
+ _v7FpRate: 0,
49200
+ _v7Precision: 0,
49201
+ _v8Verdict: "USEFUL",
49202
+ _v8Lift: 99999
47944
49203
  },
47945
- "ai/fetch-default-overuse": {
47946
- recall: 28e-4,
47947
- fpRate: 4e-4,
47948
- ratio: 6.76,
47949
- precision: 0.8976,
47950
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49204
+ "security/public-admin-route": {
49205
+ recall: 38e-4,
49206
+ fpRate: 38e-4,
49207
+ ratio: 142.2,
49208
+ precision: 0.5376,
49209
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47951
49210
  verdict: "USEFUL",
47952
- _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.",
47953
- aiSpecific: true
49211
+ _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).",
49212
+ aiSpecific: false,
49213
+ _v7Verdict: "DORMANT",
49214
+ _v7Lift: 1,
49215
+ _v7Recall: 0,
49216
+ _v7FpRate: 0,
49217
+ _v7Precision: 0,
49218
+ _v8Verdict: "USEFUL",
49219
+ _v8Lift: 38.74
47954
49220
  },
47955
- "ai/console-debug-storm": {
47956
- recall: 8e-3,
47957
- fpRate: 9e-4,
47958
- ratio: 8.43,
47959
- precision: 0.9161,
47960
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49221
+ "security/sql-construction": {
49222
+ recall: 32e-4,
49223
+ fpRate: 15e-4,
49224
+ ratio: 485.42,
49225
+ precision: 0.7183,
49226
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47961
49227
  verdict: "USEFUL",
47962
- _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.",
47963
- aiSpecific: true
49228
+ _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).",
49229
+ aiSpecific: true,
49230
+ _v7Verdict: "USEFUL",
49231
+ _v7Lift: 370.52,
49232
+ _v7Recall: 3e-3,
49233
+ _v7FpRate: 18e-4,
49234
+ _v7Precision: 0.6788,
49235
+ _v8Verdict: "USEFUL",
49236
+ _v8Lift: 1608.86
47964
49237
  },
47965
- "db/missing-fk-index": {
47966
- recall: 0,
49238
+ "security/target-blank-no-noopener": {
49239
+ recall: 4e-4,
47967
49240
  fpRate: 0,
47968
- ratio: 0,
47969
- precision: 0,
47970
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47971
- verdict: "DORMANT",
47972
- defaultOff: true,
47973
- _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.)",
47974
- aiSpecific: false
49241
+ ratio: 26141.63,
49242
+ precision: 0.9333,
49243
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49244
+ verdict: "USEFUL",
49245
+ _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).",
49246
+ aiSpecific: false,
49247
+ _v7Verdict: "DORMANT",
49248
+ _v7Lift: 1,
49249
+ _v7Recall: 0,
49250
+ _v7FpRate: 0,
49251
+ _v7Precision: 0,
49252
+ _v8Verdict: "USEFUL",
49253
+ _v8Lift: 7121.02
47975
49254
  },
47976
- "db/duplicate-index": {
47977
- recall: 0,
47978
- fpRate: 0,
47979
- ratio: 0,
47980
- precision: 0,
47981
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47982
- verdict: "DORMANT",
47983
- defaultOff: true,
47984
- _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.)",
47985
- aiSpecific: false
49255
+ "security/unsafe-html-render": {
49256
+ recall: 13e-4,
49257
+ fpRate: 11e-4,
49258
+ ratio: 513.12,
49259
+ precision: 0.574,
49260
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49261
+ verdict: "USEFUL",
49262
+ _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).",
49263
+ aiSpecific: false,
49264
+ _v7Verdict: "USEFUL",
49265
+ _v7Lift: 757.74,
49266
+ _v7Recall: 13e-4,
49267
+ _v7FpRate: 9e-4,
49268
+ _v7Precision: 0.661,
49269
+ _v8Verdict: "OK",
49270
+ _v8Lift: 201.44
47986
49271
  },
47987
- "db/missing-not-null": {
47988
- recall: 0,
49272
+ "test/duplicate-setup": {
49273
+ recall: 1e-4,
47989
49274
  fpRate: 0,
47990
- ratio: 0,
47991
- precision: 0,
47992
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47993
- verdict: "DORMANT",
47994
- defaultOff: true,
47995
- _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.)",
47996
- aiSpecific: false
49275
+ ratio: 51016.19,
49276
+ precision: 0.8095,
49277
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49278
+ verdict: "USEFUL",
49279
+ _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).",
49280
+ aiSpecific: true,
49281
+ _v7Verdict: "USEFUL",
49282
+ _v7Lift: 50348.67,
49283
+ _v7Recall: 1e-4,
49284
+ _v7FpRate: 0,
49285
+ _v7Precision: 0.8235,
49286
+ _v8Verdict: "USEFUL",
49287
+ _v8Lift: 51500.25
47997
49288
  },
47998
- "db/enum-sprawl": {
47999
- recall: 0,
48000
- fpRate: 0,
48001
- ratio: 0,
48002
- precision: 0,
48003
- lastCalibratedAt: "2026-06-30T00:00:00Z",
48004
- verdict: "DORMANT",
48005
- defaultOff: true,
48006
- _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.)",
48007
- aiSpecific: false
49289
+ "test/fake-placeholder": {
49290
+ recall: 51e-4,
49291
+ fpRate: 15e-4,
49292
+ ratio: 547.47,
49293
+ precision: 0.8014,
49294
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49295
+ verdict: "USEFUL",
49296
+ _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).",
49297
+ aiSpecific: true,
49298
+ _v7Verdict: "USEFUL",
49299
+ _v7Lift: 418.76,
49300
+ _v7Recall: 53e-4,
49301
+ _v7FpRate: 19e-4,
49302
+ _v7Precision: 0.7854,
49303
+ _v8Verdict: "USEFUL",
49304
+ _v8Lift: 2477.4
48008
49305
  },
48009
- "db/naming-inconsistency": {
49306
+ "test/missing-edge-case": {
48010
49307
  recall: 0,
48011
49308
  fpRate: 0,
48012
49309
  ratio: 0,
48013
49310
  precision: 0,
48014
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49311
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48015
49312
  verdict: "DORMANT",
48016
- defaultOff: true,
48017
- _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.)",
48018
- aiSpecific: false
49313
+ _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.",
49314
+ aiSpecific: true,
49315
+ _v7Verdict: "DORMANT",
49316
+ _v7Lift: 0,
49317
+ _v7Recall: 0,
49318
+ _v7FpRate: 0,
49319
+ _v7Precision: 0,
49320
+ _v8Verdict: "DORMANT",
49321
+ _v8Lift: 1,
49322
+ defaultOff: true
48019
49323
  },
48020
- "db/sql-concat": {
48021
- recall: 0,
48022
- fpRate: 0,
48023
- ratio: 0,
48024
- precision: 0,
48025
- lastCalibratedAt: "2026-06-30T00:00:00Z",
48026
- verdict: "DORMANT",
48027
- defaultOff: true,
48028
- _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.)",
48029
- aiSpecific: true
49324
+ "test/weak-assertion": {
49325
+ recall: 0.0417,
49326
+ fpRate: 67e-4,
49327
+ ratio: 131.62,
49328
+ precision: 0.8793,
49329
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49330
+ verdict: "USEFUL",
49331
+ _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).",
49332
+ aiSpecific: true,
49333
+ _v7Verdict: "USEFUL",
49334
+ _v7Lift: 99.9,
49335
+ _v7Recall: 0.0418,
49336
+ _v7FpRate: 86e-4,
49337
+ _v7Precision: 0.8622,
49338
+ _v8Verdict: "USEFUL",
49339
+ _v8Lift: 651.94
48030
49340
  },
48031
- "dead/unused-import": {
49341
+ "typo/calc-fontsize": {
48032
49342
  recall: 0,
48033
49343
  fpRate: 0,
48034
49344
  ratio: 0,
48035
49345
  precision: 0,
48036
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49346
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48037
49347
  verdict: "DORMANT",
48038
- defaultOff: true,
48039
- _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.",
48040
- aiSpecific: true
49348
+ _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.",
49349
+ aiSpecific: false,
49350
+ _v7Verdict: "DORMANT",
49351
+ _v7Lift: 0,
49352
+ _v7Recall: 0,
49353
+ _v7FpRate: 0,
49354
+ _v7Precision: 0,
49355
+ _v8Verdict: "DORMANT",
49356
+ _v8Lift: 1,
49357
+ defaultOff: true
48041
49358
  },
48042
- "dead/unused-local": {
49359
+ "typo/calc-raw-px": {
48043
49360
  recall: 0,
48044
49361
  fpRate: 0,
48045
- ratio: 0,
48046
- precision: 0,
48047
- lastCalibratedAt: "2026-06-30T00:00:00Z",
48048
- verdict: "DORMANT",
48049
- defaultOff: true,
48050
- _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).",
48051
- aiSpecific: true
49362
+ ratio: 210066.67,
49363
+ precision: 0.8333,
49364
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49365
+ verdict: "USEFUL",
49366
+ _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).",
49367
+ aiSpecific: false,
49368
+ _v7Verdict: "USEFUL",
49369
+ _v7Lift: 137559.75,
49370
+ _v7Recall: 0,
49371
+ _v7FpRate: 0,
49372
+ _v7Precision: 0.75,
49373
+ _v8Verdict: "USEFUL",
49374
+ _v8Lift: 99999
48052
49375
  },
48053
- "dead/unused-parameter": {
49376
+ "typo/clamp-offscale": {
48054
49377
  recall: 0,
48055
49378
  fpRate: 0,
48056
49379
  ratio: 0,
48057
49380
  precision: 0,
48058
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49381
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48059
49382
  verdict: "DORMANT",
48060
- defaultOff: true,
48061
- _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.",
48062
- aiSpecific: true
49383
+ _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.",
49384
+ aiSpecific: false,
49385
+ _v7Verdict: "DORMANT",
49386
+ _v7Lift: 0,
49387
+ _v7Recall: 0,
49388
+ _v7FpRate: 0,
49389
+ _v7Precision: 0,
49390
+ _v8Verdict: "DORMANT",
49391
+ _v8Lift: 1,
49392
+ defaultOff: true
48063
49393
  },
48064
- "dead/dead-branch": {
48065
- recall: 0,
48066
- fpRate: 0,
48067
- ratio: 0,
48068
- precision: 0,
48069
- lastCalibratedAt: "2026-06-30T00:00:00Z",
48070
- verdict: "DORMANT",
48071
- defaultOff: true,
48072
- _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.",
48073
- aiSpecific: true
49394
+ "typo/math-button-label-uniformity": {
49395
+ recall: 1e-4,
49396
+ fpRate: 1e-4,
49397
+ ratio: 6894.19,
49398
+ precision: 0.629,
49399
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49400
+ verdict: "USEFUL",
49401
+ _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).",
49402
+ aiSpecific: false,
49403
+ _v7Verdict: "USEFUL",
49404
+ _v7Lift: 5571.66,
49405
+ _v7Recall: 2e-4,
49406
+ _v7FpRate: 1e-4,
49407
+ _v7Precision: 0.6379,
49408
+ _v8Verdict: "USEFUL",
49409
+ _v8Lift: 17166.75
48074
49410
  },
48075
- "dead/unreachable": {
49411
+ "typo/math-cta-vocabulary": {
48076
49412
  recall: 0,
48077
49413
  fpRate: 0,
48078
49414
  ratio: 0,
48079
49415
  precision: 0,
48080
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49416
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48081
49417
  verdict: "DORMANT",
48082
- defaultOff: true,
48083
- _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.",
48084
- aiSpecific: true
49418
+ _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.",
49419
+ aiSpecific: true,
49420
+ _v7Verdict: "DORMANT",
49421
+ _v7Lift: 0,
49422
+ _v7Recall: 0,
49423
+ _v7FpRate: 0,
49424
+ _v7Precision: 0,
49425
+ _v8Verdict: "DORMANT",
49426
+ _v8Lift: 1,
49427
+ defaultOff: true
48085
49428
  },
48086
- "docs/stale-package-reference": {
48087
- recall: 0,
49429
+ "typo/placeholder-text": {
49430
+ recall: 1e-4,
48088
49431
  fpRate: 0,
48089
- ratio: 0,
48090
- precision: 0,
48091
- lastCalibratedAt: "2026-06-30T00:00:00Z",
48092
- verdict: "DORMANT",
48093
- defaultOff: true,
48094
- _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.)",
48095
- aiSpecific: false
49432
+ ratio: 17330.5,
49433
+ precision: 0.6875,
49434
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49435
+ verdict: "USEFUL",
49436
+ _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).",
49437
+ aiSpecific: false,
49438
+ _v7Verdict: "DORMANT",
49439
+ _v7Lift: 1,
49440
+ _v7Recall: 0,
49441
+ _v7FpRate: 0,
49442
+ _v7Precision: 0,
49443
+ _v8Verdict: "USEFUL",
49444
+ _v8Lift: 4720.86
48096
49445
  },
48097
- "docs/stale-function-reference": {
49446
+ "visual/arbitrary-escape": {
49447
+ recall: 26e-4,
49448
+ fpRate: 7e-4,
49449
+ ratio: 1219.67,
49450
+ precision: 0.8177,
49451
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49452
+ verdict: "USEFUL",
49453
+ _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).",
49454
+ aiSpecific: true,
49455
+ _v7Verdict: "USEFUL",
49456
+ _v7Lift: 846.78,
49457
+ _v7Recall: 25e-4,
49458
+ _v7FpRate: 9e-4,
49459
+ _v7Precision: 0.7802,
49460
+ _v8Verdict: "USEFUL",
49461
+ _v8Lift: 99999
49462
+ },
49463
+ "visual/clamp-soup": {
48098
49464
  recall: 0,
48099
49465
  fpRate: 0,
48100
49466
  ratio: 0,
48101
49467
  precision: 0,
48102
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49468
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48103
49469
  verdict: "DORMANT",
48104
- defaultOff: true,
48105
- _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.)",
48106
- aiSpecific: false
49470
+ _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.",
49471
+ aiSpecific: true,
49472
+ _v7Verdict: "DORMANT",
49473
+ _v7Lift: 0,
49474
+ _v7Recall: 0,
49475
+ _v7FpRate: 0,
49476
+ _v7Precision: 0,
49477
+ _v8Verdict: "DORMANT",
49478
+ _v8Lift: 1,
49479
+ defaultOff: true
48107
49480
  },
48108
- "docs/expired-code-example": {
49481
+ "visual/generic-centering": {
48109
49482
  recall: 0,
48110
49483
  fpRate: 0,
48111
49484
  ratio: 0,
48112
49485
  precision: 0,
48113
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49486
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48114
49487
  verdict: "DORMANT",
48115
- defaultOff: true,
48116
- _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.)",
48117
- aiSpecific: false
49488
+ _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.",
49489
+ aiSpecific: true,
49490
+ _v7Verdict: "DORMANT",
49491
+ _v7Lift: 0,
49492
+ _v7Recall: 0,
49493
+ _v7FpRate: 0,
49494
+ _v7Precision: 0,
49495
+ _v8Verdict: "DORMANT",
49496
+ _v8Lift: 1,
49497
+ defaultOff: true
48118
49498
  },
48119
- "docs/broken-link": {
48120
- recall: 0,
49499
+ "visual/inline-style-dominance": {
49500
+ recall: 0.0103,
49501
+ fpRate: 52e-4,
49502
+ ratio: 134.59,
49503
+ precision: 0.6983,
49504
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49505
+ verdict: "USEFUL",
49506
+ _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).",
49507
+ aiSpecific: false,
49508
+ _v7Verdict: "USEFUL",
49509
+ _v7Lift: 98.17,
49510
+ _v7Recall: 97e-4,
49511
+ _v7FpRate: 67e-4,
49512
+ _v7Precision: 0.6535,
49513
+ _v8Verdict: "USEFUL",
49514
+ _v8Lift: 704.71
49515
+ },
49516
+ "visual/math-color-cluster": {
49517
+ recall: 2e-4,
48121
49518
  fpRate: 0,
48122
- ratio: 0,
48123
- precision: 0,
48124
- lastCalibratedAt: "2026-06-30T00:00:00Z",
48125
- verdict: "DORMANT",
48126
- defaultOff: true,
48127
- _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.)",
48128
- aiSpecific: false
49519
+ ratio: 46814.86,
49520
+ precision: 0.9286,
49521
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49522
+ verdict: "USEFUL",
49523
+ _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).",
49524
+ aiSpecific: true,
49525
+ _v7Verdict: "USEFUL",
49526
+ _v7Lift: 33771.28,
49527
+ _v7Recall: 2e-4,
49528
+ _v7FpRate: 0,
49529
+ _v7Precision: 0.9206,
49530
+ _v8Verdict: "USEFUL",
49531
+ _v8Lift: 99999
48129
49532
  },
48130
- "security/eval": {
49533
+ "visual/math-default-font": {
49534
+ recall: 16e-4,
49535
+ fpRate: 3e-4,
49536
+ ratio: 3035.16,
49537
+ precision: 0.8669,
49538
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49539
+ verdict: "USEFUL",
49540
+ _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).",
49541
+ aiSpecific: true,
49542
+ _v7Verdict: "USEFUL",
49543
+ _v7Lift: 2105.64,
49544
+ _v7Recall: 13e-4,
49545
+ _v7FpRate: 4e-4,
49546
+ _v7Precision: 0.8151,
49547
+ _v8Verdict: "USEFUL",
49548
+ _v8Lift: 68229.63
49549
+ },
49550
+ "visual/math-font-entropy": {
49551
+ recall: 52e-4,
49552
+ fpRate: 1e-3,
49553
+ ratio: 869.95,
49554
+ precision: 0.8593,
49555
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49556
+ verdict: "USEFUL",
49557
+ _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).",
49558
+ aiSpecific: true,
49559
+ _v7Verdict: "USEFUL",
49560
+ _v7Lift: 600.09,
49561
+ _v7Recall: 45e-4,
49562
+ _v7FpRate: 14e-4,
49563
+ _v7Precision: 0.8114,
49564
+ _v8Verdict: "USEFUL",
49565
+ _v8Lift: 68516.08
49566
+ },
49567
+ "visual/math-gradient-hue-rotation": {
48131
49568
  recall: 0,
48132
49569
  fpRate: 0,
48133
49570
  ratio: 0,
48134
49571
  precision: 0,
48135
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49572
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48136
49573
  verdict: "DORMANT",
48137
- defaultOff: true,
48138
- _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.)",
48139
- aiSpecific: false
49574
+ _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.",
49575
+ aiSpecific: true,
49576
+ _v7Verdict: "DORMANT",
49577
+ _v7Lift: 0,
49578
+ _v7Recall: 0,
49579
+ _v7FpRate: 0,
49580
+ _v7Precision: 0,
49581
+ _v8Verdict: "DORMANT",
49582
+ _v8Lift: 1,
49583
+ defaultOff: true
48140
49584
  },
48141
- "security/localstorage-token": {
48142
- recall: 0,
49585
+ "visual/math-rounded-entropy": {
49586
+ recall: 38e-4,
49587
+ fpRate: 2e-4,
49588
+ ratio: 3785.45,
49589
+ precision: 0.9461,
49590
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49591
+ verdict: "USEFUL",
49592
+ _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).",
49593
+ aiSpecific: true,
49594
+ _v7Verdict: "USEFUL",
49595
+ _v7Lift: 2762.74,
49596
+ _v7Recall: 37e-4,
49597
+ _v7FpRate: 3e-4,
49598
+ _v7Precision: 0.9339,
49599
+ _v8Verdict: "USEFUL",
49600
+ _v8Lift: 68368.45
49601
+ },
49602
+ "visual/math-spacing-entropy": {
49603
+ recall: 18e-4,
49604
+ fpRate: 4e-4,
49605
+ ratio: 1898.99,
49606
+ precision: 0.8287,
49607
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49608
+ verdict: "USEFUL",
49609
+ _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).",
49610
+ aiSpecific: true,
49611
+ _v7Verdict: "USEFUL",
49612
+ _v7Lift: 1339.22,
49613
+ _v7Recall: 18e-4,
49614
+ _v7FpRate: 6e-4,
49615
+ _v7Precision: 0.7959,
49616
+ _v8Verdict: "USEFUL",
49617
+ _v8Lift: 68031.19
49618
+ },
49619
+ "visual/naturalness-anomaly": {
49620
+ recall: 0.1729,
49621
+ fpRate: 0.0687,
49622
+ ratio: 10.86,
49623
+ precision: 0.746,
49624
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49625
+ verdict: "USEFUL",
49626
+ _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).",
49627
+ aiSpecific: true,
49628
+ _v7Verdict: "USEFUL",
49629
+ _v7Lift: 12.5,
49630
+ _v7Recall: 0.1659,
49631
+ _v7FpRate: 0.0621,
49632
+ _v7Precision: 0.7755,
49633
+ _v8Verdict: "USEFUL",
49634
+ _v8Lift: 7.64
49635
+ },
49636
+ "visual/radius-scale-violation": {
49637
+ recall: 4e-4,
48143
49638
  fpRate: 0,
48144
- ratio: 0,
48145
- precision: 0,
48146
- lastCalibratedAt: "2026-06-30T00:00:00Z",
48147
- verdict: "DORMANT",
48148
- defaultOff: true,
48149
- _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.)",
48150
- aiSpecific: false
49639
+ ratio: 82131.33,
49640
+ precision: 0.9774,
49641
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49642
+ verdict: "USEFUL",
49643
+ _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).",
49644
+ aiSpecific: false,
49645
+ _v7Verdict: "USEFUL",
49646
+ _v7Lift: 59285.01,
49647
+ _v7Recall: 4e-4,
49648
+ _v7FpRate: 0,
49649
+ _v7Precision: 0.9697,
49650
+ _v8Verdict: "USEFUL",
49651
+ _v8Lift: 99999
48151
49652
  },
48152
- "security/target-blank-no-noopener": {
49653
+ "visual/spacing-scale-violation": {
49654
+ recall: 86e-4,
49655
+ fpRate: 28e-4,
49656
+ ratio: 273.97,
49657
+ precision: 0.7792,
49658
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49659
+ verdict: "USEFUL",
49660
+ _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).",
49661
+ aiSpecific: false,
49662
+ _v7Verdict: "USEFUL",
49663
+ _v7Lift: 187.83,
49664
+ _v7Recall: 84e-4,
49665
+ _v7FpRate: 39e-4,
49666
+ _v7Precision: 0.7342,
49667
+ _v8Verdict: "USEFUL",
49668
+ _v8Lift: 99999
49669
+ },
49670
+ "wcag/dragging-movements": {
48153
49671
  recall: 0,
48154
49672
  fpRate: 0,
48155
- ratio: 0,
48156
- precision: 0,
48157
- lastCalibratedAt: "2026-06-30T00:00:00Z",
48158
- verdict: "DORMANT",
48159
- defaultOff: true,
48160
- _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.)',
48161
- aiSpecific: false
49673
+ ratio: 33610.67,
49674
+ precision: 0.4,
49675
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49676
+ verdict: "OK",
49677
+ _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).",
49678
+ aiSpecific: false,
49679
+ _v7Verdict: "OK",
49680
+ _v7Lift: 24455.07,
49681
+ _v7Recall: 0,
49682
+ _v7FpRate: 0,
49683
+ _v7Precision: 0.4,
49684
+ _v8Verdict: "DORMANT",
49685
+ _v8Lift: 1
49686
+ },
49687
+ "wcag/focus-appearance": {
49688
+ recall: 28e-4,
49689
+ fpRate: 1e-4,
49690
+ ratio: 8397.24,
49691
+ precision: 0.966,
49692
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49693
+ verdict: "USEFUL",
49694
+ _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).",
49695
+ aiSpecific: false,
49696
+ _v7Verdict: "USEFUL",
49697
+ _v7Lift: 7353.82,
49698
+ _v7Recall: 26e-4,
49699
+ _v7FpRate: 1e-4,
49700
+ _v7Precision: 0.9623,
49701
+ _v8Verdict: "USEFUL",
49702
+ _v8Lift: 13418.41
49703
+ },
49704
+ "wcag/focus-obscured": {
49705
+ recall: 33e-4,
49706
+ fpRate: 7e-4,
49707
+ ratio: 1214.21,
49708
+ precision: 0.8478,
49709
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49710
+ verdict: "USEFUL",
49711
+ _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).",
49712
+ aiSpecific: false,
49713
+ _v7Verdict: "USEFUL",
49714
+ _v7Lift: 859.38,
49715
+ _v7Recall: 34e-4,
49716
+ _v7FpRate: 1e-3,
49717
+ _v7Precision: 0.82,
49718
+ _v8Verdict: "USEFUL",
49719
+ _v8Lift: 68293.81
48162
49720
  },
48163
49721
  "wcag/missing-alt": {
48164
- recall: 0,
48165
- fpRate: 0,
48166
- ratio: 0,
48167
- precision: 0,
48168
- lastCalibratedAt: "2026-06-30T00:00:00Z",
48169
- verdict: "DORMANT",
48170
- defaultOff: true,
48171
- _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.)',
48172
- aiSpecific: false
49722
+ recall: 11e-4,
49723
+ fpRate: 7e-4,
49724
+ ratio: 935.33,
49725
+ precision: 0.6456,
49726
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49727
+ verdict: "USEFUL",
49728
+ _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).",
49729
+ aiSpecific: false,
49730
+ _v7Verdict: "DORMANT",
49731
+ _v7Lift: 1,
49732
+ _v7Recall: 0,
49733
+ _v7FpRate: 0,
49734
+ _v7Precision: 0,
49735
+ _v8Verdict: "USEFUL",
49736
+ _v8Lift: 254.79
48173
49737
  },
48174
- "typo/placeholder-text": {
49738
+ "wcag/target-size": {
48175
49739
  recall: 0,
48176
49740
  fpRate: 0,
48177
49741
  ratio: 0,
48178
49742
  precision: 0,
48179
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49743
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48180
49744
  verdict: "DORMANT",
48181
- defaultOff: true,
48182
- _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.)",
48183
- aiSpecific: false
49745
+ _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.",
49746
+ aiSpecific: false,
49747
+ _v7Verdict: "DORMANT",
49748
+ _v7Lift: 0,
49749
+ _v7Recall: 0,
49750
+ _v7FpRate: 0,
49751
+ _v7Precision: 0,
49752
+ _v8Verdict: "DORMANT",
49753
+ _v8Lift: 1,
49754
+ defaultOff: true
48184
49755
  }
48185
49756
  };
48186
49757
  }
@@ -48247,7 +49818,6 @@ async function scanFile(filePath, config, registry, cwd = process.cwd()) {
48247
49818
  ".kt",
48248
49819
  ".kts",
48249
49820
  ".dart",
48250
- ".rs",
48251
49821
  ".cpp",
48252
49822
  ".cc",
48253
49823
  ".cxx",
@@ -55155,7 +56725,12 @@ var RULE_HINTS = {
55155
56725
  "docs/stale-package-reference": "Update the doc to reference an installed package, or add the package to package.json. Copy-pasted install commands from a previous project are the #1 doc-drift failure mode.",
55156
56726
  "docs/stale-function-reference": "Rename the doc reference to match a current export, or add a wrapper export. Stale function callouts in tutorials cost readers 10+ minutes of debugging.",
55157
56727
  "docs/expired-code-example": "Update the example to use a declared dependency, or add the package to package.json. A copy-pasteable example that does not install erodes trust in the whole docs site.",
55158
- "docs/broken-link": "Create the file or fix the link target. On a public docs site, broken links erode trust more than stale copy."
56728
+ "docs/broken-link": "Create the file or fix the link target. On a public docs site, broken links erode trust more than stale copy.",
56729
+ // v0.18.9 — Rust-specific rules (tree-sitter-backed)
56730
+ "rust/unused-pub-fn": "Remove the function or call it. Rust's compiler doesn't warn on `pub fn` references unless `#![warn(dead_code)]` is set at the crate root. AI agents leave these behind during iterative refactors.",
56731
+ "rust/unwrap-in-production": "Replace `.unwrap()` / `.expect()` with `?` (early-return on Err), `.map_err(...)` for error conversion, or an explicit `match`. They panic in production; reserve them for `#[cfg(test)]` or `#[test]` scopes.",
56732
+ "rust/todo-macro": "Implement the function body or remove the stub. `todo!()` / `unimplemented!()` both expand to `panic!()`, so a hit at runtime crashes the program. Move them into a `#[cfg(test)] mod tests` block to suppress.",
56733
+ "rust/stringly-typed": 'Replace the `String` / `&str` parameter with the typed enum that already exists in the file. Stringly-typed APIs lose type information at the boundary \u2014 typos (`"Click"` vs `"click"`) only fail at runtime.'
55159
56734
  };
55160
56735
 
55161
56736
  // src/cli/commands/explain.ts