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