slopbrick 0.18.5 → 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.5";
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",
@@ -29747,6 +30137,9 @@ var init_expired_code_example = __esm({
29747
30137
  const issues = [];
29748
30138
  const source = facts.v2?._source;
29749
30139
  if (!source) return issues;
30140
+ const packages = declaredPackages(context.cwd);
30141
+ const packageName = context.packageName;
30142
+ if (packageName) packages.add(packageName);
29750
30143
  const blocks = extractFencedCodeBlocks(source);
29751
30144
  for (const block of blocks) {
29752
30145
  if (!CODE_LANGS.has(block.lang)) continue;
@@ -29754,7 +30147,7 @@ var init_expired_code_example = __esm({
29754
30147
  const imports = extractImports(block.body);
29755
30148
  for (const imp of imports) {
29756
30149
  const pkgName = stripSubpath(imp);
29757
- if (context.packages.has(pkgName)) continue;
30150
+ if (packages.has(pkgName)) continue;
29758
30151
  issues.push({
29759
30152
  ruleId: "docs/expired-code-example",
29760
30153
  category: "docs",
@@ -29809,7 +30202,12 @@ function collectExports(cwd) {
29809
30202
  /\bexport\s+class\s+([A-Za-z_$][\w$]*)/g,
29810
30203
  /\bexport\s+interface\s+([A-Za-z_$][\w$]*)/g,
29811
30204
  /\bexport\s+type\s+([A-Za-z_$][\w$]*)/g,
29812
- /\bexport\s+default\s+(?:function\s+|class\s+)?([A-Za-z_$][\w$]*)/g
30205
+ /\bexport\s+default\s+(?:function\s+|class\s+)?([A-Za-z_$][\w$]*)/g,
30206
+ // v0.18.6: also collect field names from `export interface` and
30207
+ // `export type` declarations. Without this, fields like
30208
+ // `crossFileDrift`, `aiQuality`, `engineeringHygiene` are
30209
+ // flagged as stale even though they're valid type fields.
30210
+ /^\s*(?:readonly\s+)?([A-Za-z_$][\w$]*)\s*[?:]/gm
29813
30211
  ]) {
29814
30212
  let m;
29815
30213
  while ((m = re.exec(source)) !== null) {
@@ -29820,6 +30218,21 @@ function collectExports(cwd) {
29820
30218
  }
29821
30219
  return out;
29822
30220
  }
30221
+ function looksLikeProseLabel(inside) {
30222
+ const trimmed = inside.trim();
30223
+ if (trimmed.length === 0) return false;
30224
+ if (trimmed.startsWith("`") || trimmed.startsWith("/")) return true;
30225
+ if (trimmed.includes("`")) return true;
30226
+ if (/\d+\s+[a-z]/i.test(trimmed)) return true;
30227
+ const parts = trimmed.split(",").map((s) => s.trim());
30228
+ if (parts.length >= 3) {
30229
+ const allNumeric = parts.every((p) => /^\d+\.?\d*$/.test(p));
30230
+ if (!allNumeric) return true;
30231
+ }
30232
+ if (trimmed.length > 40 && !trimmed.includes(",")) return true;
30233
+ if (trimmed.includes("\u2014") || trimmed.includes("\u2013")) return true;
30234
+ return false;
30235
+ }
29823
30236
  var RESERVED, SOURCE_EXTS, SOURCE_ROOTS, CAP, staleFunctionReferenceRule;
29824
30237
  var init_stale_function_reference = __esm({
29825
30238
  "src/rules/docs/stale-function-reference.ts"() {
@@ -29827,6 +30240,7 @@ var init_stale_function_reference = __esm({
29827
30240
  init_rule();
29828
30241
  init_doc_freshness();
29829
30242
  RESERVED = /* @__PURE__ */ new Set([
30243
+ // JS reserved words
29830
30244
  "true",
29831
30245
  "false",
29832
30246
  "null",
@@ -29926,7 +30340,472 @@ var init_stale_function_reference = __esm({
29926
30340
  "next",
29927
30341
  "vue",
29928
30342
  "angular",
29929
- "svelte"
30343
+ "svelte",
30344
+ // Framework / runtime names
30345
+ "html",
30346
+ "astro",
30347
+ "python",
30348
+ "jvm",
30349
+ "kotlin",
30350
+ "swift",
30351
+ "dart",
30352
+ "ruby",
30353
+ "rust",
30354
+ "cpp",
30355
+ "go",
30356
+ "java",
30357
+ "php",
30358
+ "php-html",
30359
+ "csharp",
30360
+ "typescript",
30361
+ "javascript",
30362
+ "jsx",
30363
+ "tsx",
30364
+ "mjs",
30365
+ "cjs",
30366
+ "esnext",
30367
+ "es6",
30368
+ "es2022",
30369
+ "es2023",
30370
+ "esm",
30371
+ "cjs",
30372
+ "umd",
30373
+ "amd",
30374
+ "commonjs",
30375
+ "require",
30376
+ "module",
30377
+ "exports",
30378
+ "define",
30379
+ "global",
30380
+ "window",
30381
+ "document",
30382
+ "process",
30383
+ "console",
30384
+ "buffer",
30385
+ "stream",
30386
+ "fetch",
30387
+ "axios",
30388
+ "express",
30389
+ "fastify",
30390
+ "koa",
30391
+ "hapi",
30392
+ "nextjs",
30393
+ "nuxt",
30394
+ "remix",
30395
+ "gatsby",
30396
+ "sveltekit",
30397
+ "solid",
30398
+ "preact",
30399
+ "qwik",
30400
+ "lit",
30401
+ "stencil",
30402
+ "marko",
30403
+ "alpine",
30404
+ "stimulus",
30405
+ "turbo",
30406
+ "hotwire",
30407
+ // Models / providers
30408
+ "gpt",
30409
+ "claude",
30410
+ "gpt-3",
30411
+ "gpt-3.5",
30412
+ "gpt-4",
30413
+ "gpt-oss",
30414
+ "haiku",
30415
+ "sonnet",
30416
+ "opus",
30417
+ "aider",
30418
+ "tabby",
30419
+ "copilot",
30420
+ "cursor",
30421
+ "windsurf",
30422
+ "devin",
30423
+ "claude-code",
30424
+ // LLM-detection lingo
30425
+ "heuristic",
30426
+ "heuristics",
30427
+ "calibrate",
30428
+ "calibration",
30429
+ "calibrator",
30430
+ "corpus",
30431
+ "baseline",
30432
+ "baselines",
30433
+ "corpus-baselines",
30434
+ "lift",
30435
+ "recall",
30436
+ "precision",
30437
+ "fpRate",
30438
+ "ratio",
30439
+ "verdict",
30440
+ "USEFUL",
30441
+ "NOISY",
30442
+ "INVERTED",
30443
+ "HYGIENE",
30444
+ "DORMANT",
30445
+ "OK",
30446
+ "aiSpecific",
30447
+ "defaultOff",
30448
+ // Common slop-audit verbs/nouns
30449
+ "commit",
30450
+ "push",
30451
+ "reset",
30452
+ "rebase",
30453
+ "merge",
30454
+ "cherry-pick",
30455
+ "revert",
30456
+ "scan",
30457
+ "parse",
30458
+ "build",
30459
+ "test",
30460
+ "lint",
30461
+ "format",
30462
+ "check",
30463
+ "audit",
30464
+ "fix",
30465
+ "patch",
30466
+ "diff",
30467
+ "pr",
30468
+ "ci",
30469
+ "cd",
30470
+ "gh",
30471
+ "npm",
30472
+ "npx",
30473
+ "pnpm",
30474
+ "yaml",
30475
+ "json",
30476
+ "toml",
30477
+ "csv",
30478
+ "md",
30479
+ "mdx",
30480
+ "sh",
30481
+ "bash",
30482
+ "zsh",
30483
+ "fish",
30484
+ "ascii",
30485
+ "utf8",
30486
+ "utf-8",
30487
+ "base64",
30488
+ "hex",
30489
+ "binary",
30490
+ "text",
30491
+ // Common design / ui terms
30492
+ "flex",
30493
+ "grid",
30494
+ "auto",
30495
+ "min",
30496
+ "max",
30497
+ "fill",
30498
+ "stretch",
30499
+ "wrap",
30500
+ "nowrap",
30501
+ "inline",
30502
+ "block",
30503
+ "hidden",
30504
+ "visible",
30505
+ "static",
30506
+ "fixed",
30507
+ "absolute",
30508
+ "relative",
30509
+ "sticky",
30510
+ "pointer",
30511
+ "cursor",
30512
+ "focus",
30513
+ "hover",
30514
+ "active",
30515
+ "disabled",
30516
+ "readonly",
30517
+ "primary",
30518
+ "secondary",
30519
+ "tertiary",
30520
+ "success",
30521
+ "warning",
30522
+ "danger",
30523
+ "info",
30524
+ "muted",
30525
+ "sm",
30526
+ "md",
30527
+ "lg",
30528
+ "xl",
30529
+ "xxl",
30530
+ "xs",
30531
+ "2xl",
30532
+ "3xl",
30533
+ "4xl",
30534
+ // Math / types
30535
+ "array",
30536
+ "map",
30537
+ "set",
30538
+ "weakmap",
30539
+ "weakset",
30540
+ "object",
30541
+ "string",
30542
+ "number",
30543
+ "boolean",
30544
+ "bigint",
30545
+ "symbol",
30546
+ "null",
30547
+ "undefined",
30548
+ "any",
30549
+ "unknown",
30550
+ "never",
30551
+ "void",
30552
+ "readonly",
30553
+ "private",
30554
+ "public",
30555
+ "protected",
30556
+ "static",
30557
+ "abstract",
30558
+ "async",
30559
+ "generator",
30560
+ "iterator",
30561
+ "iterable",
30562
+ "promise",
30563
+ "observable",
30564
+ // Auth / domain
30565
+ "admin",
30566
+ "user",
30567
+ "guest",
30568
+ "anonymous",
30569
+ "authenticated",
30570
+ "unauthenticated",
30571
+ "jwt",
30572
+ "oauth",
30573
+ "oidc",
30574
+ "saml",
30575
+ "csrf",
30576
+ "xss",
30577
+ "sql",
30578
+ "nosql",
30579
+ "orm",
30580
+ "prisma",
30581
+ "drizzle",
30582
+ "sequelize",
30583
+ "mongoose",
30584
+ "redis",
30585
+ "postgres",
30586
+ "mysql",
30587
+ "sqlite",
30588
+ "kafka",
30589
+ "rabbitmq",
30590
+ "graphql",
30591
+ "rest",
30592
+ "grpc",
30593
+ "websocket",
30594
+ // slop-audit specific
30595
+ "slopbrick",
30596
+ "usebrick",
30597
+ "deadcode",
30598
+ "unused",
30599
+ "orphan",
30600
+ "zombie",
30601
+ "blocker",
30602
+ "warning",
30603
+ "info",
30604
+ "error",
30605
+ "verbose",
30606
+ "debug",
30607
+ "silly",
30608
+ "p50",
30609
+ "p90",
30610
+ "p95",
30611
+ "p99",
30612
+ "min",
30613
+ "max",
30614
+ "avg",
30615
+ "mean",
30616
+ "median",
30617
+ "ratchet",
30618
+ "tier",
30619
+ "composite",
30620
+ "fitness",
30621
+ "fpr",
30622
+ "tpr",
30623
+ "roc",
30624
+ "should",
30625
+ "could",
30626
+ "would",
30627
+ "might",
30628
+ "must",
30629
+ "shall",
30630
+ "may",
30631
+ "can",
30632
+ "todo",
30633
+ "fixme",
30634
+ "xxx",
30635
+ "hack",
30636
+ "note",
30637
+ "warning",
30638
+ "attention",
30639
+ "h1",
30640
+ "h2",
30641
+ "h3",
30642
+ "h4",
30643
+ "h5",
30644
+ "h6",
30645
+ "strong",
30646
+ "em",
30647
+ "b",
30648
+ "i",
30649
+ "u",
30650
+ "true",
30651
+ "false",
30652
+ "yes",
30653
+ "no",
30654
+ "on",
30655
+ "off",
30656
+ "enable",
30657
+ "disable",
30658
+ "ltr",
30659
+ "rtl",
30660
+ "auto",
30661
+ "start",
30662
+ "end",
30663
+ "center",
30664
+ "baseline",
30665
+ "stretch",
30666
+ "rounded",
30667
+ "sharp",
30668
+ "outline",
30669
+ "ghost",
30670
+ "link",
30671
+ "filled",
30672
+ "row",
30673
+ "col",
30674
+ "gap",
30675
+ "pad",
30676
+ "margin",
30677
+ "padding",
30678
+ "border",
30679
+ "shadow",
30680
+ "transparent",
30681
+ "currentcolor",
30682
+ "inherit",
30683
+ "initial",
30684
+ "unset",
30685
+ "revert",
30686
+ "hover",
30687
+ "focus",
30688
+ "active",
30689
+ "disabled",
30690
+ "checked",
30691
+ "indeterminate",
30692
+ "open",
30693
+ "close",
30694
+ "expanded",
30695
+ "collapsed",
30696
+ "selected",
30697
+ "pressed",
30698
+ // Web/CSS
30699
+ "div",
30700
+ "span",
30701
+ "p",
30702
+ "a",
30703
+ "img",
30704
+ "ul",
30705
+ "ol",
30706
+ "li",
30707
+ "table",
30708
+ "tr",
30709
+ "td",
30710
+ "th",
30711
+ "thead",
30712
+ "tbody",
30713
+ "tfoot",
30714
+ "caption",
30715
+ "figure",
30716
+ "figcaption",
30717
+ "main",
30718
+ "section",
30719
+ "article",
30720
+ "aside",
30721
+ "header",
30722
+ "footer",
30723
+ "nav",
30724
+ "form",
30725
+ "input",
30726
+ "button",
30727
+ "select",
30728
+ "option",
30729
+ "textarea",
30730
+ "label",
30731
+ "fieldset",
30732
+ "legend",
30733
+ "details",
30734
+ "summary",
30735
+ "dialog",
30736
+ "menu",
30737
+ "menuitem",
30738
+ "template",
30739
+ "slot",
30740
+ "picture",
30741
+ "source",
30742
+ "track",
30743
+ "video",
30744
+ "audio",
30745
+ "canvas",
30746
+ "svg",
30747
+ "iframe",
30748
+ "embed",
30749
+ "object",
30750
+ "portal",
30751
+ // Common business terms
30752
+ "api",
30753
+ "cli",
30754
+ "ui",
30755
+ "ux",
30756
+ "sdk",
30757
+ "ide",
30758
+ "cli",
30759
+ "docs",
30760
+ "doc",
30761
+ "blog",
30762
+ "post",
30763
+ "page",
30764
+ "view",
30765
+ "tab",
30766
+ "panel",
30767
+ "card",
30768
+ "list",
30769
+ "grid",
30770
+ "form",
30771
+ "modal",
30772
+ "menu",
30773
+ "button",
30774
+ "icon",
30775
+ "avatar",
30776
+ "badge",
30777
+ "chip",
30778
+ "tooltip",
30779
+ "popover",
30780
+ "dropdown",
30781
+ "banner",
30782
+ "alert",
30783
+ "toast",
30784
+ "notification",
30785
+ "drawer",
30786
+ "sidebar",
30787
+ "navbar",
30788
+ "header",
30789
+ "footer",
30790
+ "hero",
30791
+ "cta",
30792
+ "cta-primary",
30793
+ "cta-secondary",
30794
+ "pricing",
30795
+ "price",
30796
+ "cost",
30797
+ "rate",
30798
+ "percent",
30799
+ "pct",
30800
+ "count",
30801
+ "total",
30802
+ "small",
30803
+ "medium",
30804
+ "large",
30805
+ "xl",
30806
+ "xxl",
30807
+ "tiny",
30808
+ "huge"
29930
30809
  ]);
29931
30810
  SOURCE_EXTS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
29932
30811
  SOURCE_ROOTS = ["src", "lib", "app", "components"];
@@ -29950,8 +30829,39 @@ var init_stale_function_reference = __esm({
29950
30829
  if (text.length < 3) continue;
29951
30830
  if (RESERVED.has(text.toLowerCase())) continue;
29952
30831
  if (context.exports.has(text)) continue;
29953
- const end = Math.min(source.length, span.index + text.length + 50);
29954
- if (!/\(/.test(source.slice(span.index, end))) continue;
30832
+ const lineEnd = source.indexOf("\n", span.index);
30833
+ const restOfLine = source.slice(
30834
+ span.index,
30835
+ lineEnd === -1 ? source.length : lineEnd
30836
+ );
30837
+ const closeTick = restOfLine.indexOf("`", 1);
30838
+ if (closeTick === -1) continue;
30839
+ const afterTick = restOfLine.slice(closeTick + 1);
30840
+ const directCall = /^\s*\(/.test(afterTick);
30841
+ let identifierRepeats = false;
30842
+ if (!directCall) {
30843
+ const afterSpan = restOfLine.slice(closeTick + 1);
30844
+ const needle = text + "(";
30845
+ identifierRepeats = afterSpan.indexOf(needle) !== -1;
30846
+ }
30847
+ if (!directCall && !identifierRepeats) continue;
30848
+ const beforeTickIdx = span.index - 1;
30849
+ const beforeChar = beforeTickIdx >= 0 ? source[beforeTickIdx] : "";
30850
+ if (beforeChar === "." || beforeChar === "|") continue;
30851
+ const parenStart = restOfLine.indexOf("(", closeTick);
30852
+ const parenEnd = restOfLine.indexOf(")", parenStart);
30853
+ if (parenStart !== -1 && parenEnd !== -1) {
30854
+ const inside = restOfLine.slice(parenStart + 1, parenEnd);
30855
+ const trimmed = inside.trim();
30856
+ if (looksLikeProseLabel(inside)) continue;
30857
+ const looksLikeTypeAnnotation = !inside.includes(":") && (/\b(string|number|boolean|null|undefined|object|array|required|optional|categorical|direct|n\/a|\bmapped\b|0[\-–][0-9]+|v[0-9]|higher is better|lower is better|added in|deprecated|pr-[0-9])\b/i.test(
30858
+ inside
30859
+ ) || // Short single-word label (≤ 24 chars, no `,`,
30860
+ // doesn't look like a function arg). Real function
30861
+ // calls are usually longer or contain commas.
30862
+ trimmed.length > 0 && trimmed.length <= 24 && !trimmed.includes(",") && /[a-zA-Z]/.test(trimmed));
30863
+ if (looksLikeTypeAnnotation) continue;
30864
+ }
29955
30865
  issues.push({
29956
30866
  ruleId: "docs/stale-function-reference",
29957
30867
  category: "docs",
@@ -30031,7 +30941,33 @@ var init_stale_package_reference = __esm({
30031
30941
  "jsx",
30032
30942
  "ok",
30033
30943
  "no",
30034
- "yes"
30944
+ "yes",
30945
+ // v0.18.6: common English adjectives / adverbs that frequently
30946
+ // appear in backticked prose but are not package names.
30947
+ "aspirational",
30948
+ "concrete",
30949
+ "abstract",
30950
+ "inline",
30951
+ "exposed",
30952
+ "deprecated",
30953
+ "experimental",
30954
+ "stable",
30955
+ "beta",
30956
+ "alpha",
30957
+ "wip",
30958
+ "draft",
30959
+ "final",
30960
+ "shim",
30961
+ "polyfill",
30962
+ "stub",
30963
+ "mock",
30964
+ "fake",
30965
+ "real",
30966
+ "false",
30967
+ "true",
30968
+ "optional",
30969
+ "required",
30970
+ "default"
30035
30971
  ]);
30036
30972
  stalePackageReferenceRule = createRule({
30037
30973
  id: "docs/stale-package-reference",
@@ -30256,7 +31192,15 @@ async function buildDocFreshness(cwd, config, options = {}) {
30256
31192
  continue;
30257
31193
  }
30258
31194
  const relPath = relative2(cwd, abs);
30259
- const context = { config, filePath: relPath, cwd };
31195
+ let packageName;
31196
+ try {
31197
+ const pkg = JSON.parse(
31198
+ readFileSync8(join7(cwd, "package.json"), "utf-8")
31199
+ );
31200
+ packageName = pkg.name;
31201
+ } catch {
31202
+ }
31203
+ const context = { config, filePath: relPath, cwd, packageName };
30260
31204
  const facts = { filePath: relPath, v2: { _source: source } };
30261
31205
  const ruleConfigs = [
30262
31206
  { rule: stalePackageReferenceRule, ruleId: "docs/stale-package-reference" },
@@ -30369,7 +31313,9 @@ var init_broken_link = __esm({
30369
31313
  if (target.startsWith("#")) continue;
30370
31314
  if (target.startsWith("//")) continue;
30371
31315
  if (target.startsWith("/")) continue;
30372
- const resolved = join8(docDir, target);
31316
+ const filePart = target.split("#")[0] ?? target;
31317
+ if (filePart === "") continue;
31318
+ const resolved = join8(docDir, filePart);
30373
31319
  if (existsSync7(resolved)) continue;
30374
31320
  issues.push({
30375
31321
  ruleId: "docs/broken-link",
@@ -35495,7 +36441,7 @@ function parseBlankModule(source) {
35495
36441
  tsx: false,
35496
36442
  target: "es2022"
35497
36443
  });
35498
- return { ast, source: replaced };
36444
+ return { ast, source };
35499
36445
  }
35500
36446
  function parseScriptContent(content, isTypeScript) {
35501
36447
  if (isTypeScript) {
@@ -35581,8 +36527,16 @@ function parseSource(source, filePath) {
35581
36527
  // but no SWC support. Return a blank-padded empty module so
35582
36528
  // regex-only rules can still fire (markdown-leakage, comment-
35583
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.
35584
36537
  case "py":
35585
36538
  case "go":
36539
+ case "rs":
35586
36540
  return parseBlankModule(source);
35587
36541
  default:
35588
36542
  return parseWithSwc(source, filePath);
@@ -38760,6 +39714,354 @@ var init_ux_pattern_fragmentation = __esm({
38760
39714
  }
38761
39715
  });
38762
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
+
38763
40065
  // src/rules/security/dangerous-cors.ts
38764
40066
  function scanForWildcardCors(source) {
38765
40067
  const hits = [];
@@ -41454,7 +42756,7 @@ function spanEnd(node) {
41454
42756
  }
41455
42757
  return void 0;
41456
42758
  }
41457
- function buildLineOffsets(source) {
42759
+ function buildLineOffsets2(source) {
41458
42760
  const offsets = [0];
41459
42761
  let byteOffset = 0;
41460
42762
  for (let i = 0; i < source.length; i++) {
@@ -43455,9 +44757,60 @@ function buildV2Facts(facts, source, ext, framework, config, templateClassNames
43455
44757
  })),
43456
44758
  disabledRules: extractDisabledRules(source),
43457
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),
43458
44767
  _source: source
43459
44768
  };
43460
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
+ }
43461
44814
  function splitFilePath(filePath) {
43462
44815
  const baseName2 = filePath.split("/").pop() ?? filePath;
43463
44816
  const dotIdx = baseName2.lastIndexOf(".");
@@ -43472,6 +44825,7 @@ var init_v2_build = __esm({
43472
44825
  "src/engine/visitors/v2-build.ts"() {
43473
44826
  "use strict";
43474
44827
  init_scan_helpers();
44828
+ init_rust();
43475
44829
  TAILWIND_COLOR_RE = /^(?:bg|text|border|ring|from|to|via|fill|stroke)-([a-z]+-\d+|white|black|transparent|current|\[.+?\])$/;
43476
44830
  TAILWIND_SPACING_RE = /^(?:[pm][xytrbl]?|gap|space-[xy])-(\d+(?:\.\d+)?)$/;
43477
44831
  TAILWIND_RADIUS_RE = /^(?:rounded(?:-[a-z]+)?)-(.+)$/;
@@ -43504,7 +44858,7 @@ function mergeTemplateClassNames(filePath, source, facts, templateClassNames) {
43504
44858
  }
43505
44859
  }
43506
44860
  function extractFacts(filePath, ast, source, supportsRsc = true, framework = "react", config) {
43507
- const lineOffsets = buildLineOffsets(source);
44861
+ const lineOffsets = buildLineOffsets2(source);
43508
44862
  const isTypeScript = /\.tsx?$/i.test(filePath);
43509
44863
  const NON_JSX_FRAMEWORKS = /* @__PURE__ */ new Set(["vue", "svelte", "astro"]);
43510
44864
  const facts = {
@@ -43792,7 +45146,7 @@ var init_naturalness_anomaly = __esm({
43792
45146
  const issues = [];
43793
45147
  const source = facts.v2?._source;
43794
45148
  if (!source) return issues;
43795
- const lineOffsets = buildLineOffsets(source);
45149
+ const lineOffsets = buildLineOffsets2(source);
43796
45150
  const components = facts.v2?.components ?? [];
43797
45151
  const perComponentMetrics = components.filter((c) => c.loc > 0).map(
43798
45152
  (c) => computeNaturalnessForRange(source, lineOffsets, c.line, c.line + c.loc - 1, context.model)
@@ -44463,6 +45817,10 @@ var init_builtins = __esm({
44463
45817
  init_halstead_anomaly();
44464
45818
  init_terminology_drift();
44465
45819
  init_ux_pattern_fragmentation();
45820
+ init_stringly_typed();
45821
+ init_todo_macro();
45822
+ init_unused_pub_fn();
45823
+ init_unwrap_in_production();
44466
45824
  init_dangerous_cors();
44467
45825
  init_eval();
44468
45826
  init_exposed_env_var();
@@ -44564,6 +45922,10 @@ var init_builtins = __esm({
44564
45922
  halsteadAnomalyRule,
44565
45923
  terminologyDriftRule,
44566
45924
  uxPatternFragmentationRule,
45925
+ rustStringlyTypedRule,
45926
+ rustTodoMacroRule,
45927
+ rustUnusedPubFnRule,
45928
+ rustUnwrapInProductionRule,
44567
45929
  dangerousCorsRule,
44568
45930
  evalRule,
44569
45931
  exposedEnvVarRule,
@@ -46541,6 +47903,22 @@ var init_registry = __esm({
46541
47903
  if (!filter) return list;
46542
47904
  return list.filter((r) => filter.kind === "ai" ? r.aiSpecific : !r.aiSpecific);
46543
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
+ }
46544
47922
  createContexts(config, filePath, cwd, hotspotIssues = []) {
46545
47923
  const context = {
46546
47924
  config,
@@ -46566,1044 +47944,1793 @@ var signal_strength_default;
46566
47944
  var init_signal_strength = __esm({
46567
47945
  "src/rules/signal-strength.json"() {
46568
47946
  signal_strength_default = {
46569
- "logic/math-console-log-storm": {
46570
- recall: 7e-3,
46571
- fpRate: 1e-3,
46572
- ratio: 6.71,
46573
- precision: 0.8968,
46574
- 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",
46575
47953
  verdict: "USEFUL",
46576
- _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.",
46577
- 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
46578
47963
  },
46579
- "logic/math-any-density": {
46580
- recall: 16e-4,
46581
- fpRate: 13e-4,
46582
- ratio: 1.17,
46583
- precision: 0.6035,
46584
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46585
- verdict: "NOISY",
46586
- _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.",
46587
- defaultOff: true,
46588
- 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
46589
47980
  },
46590
- "logic/boundary-violation": {
46591
- recall: 0.0263,
46592
- fpRate: 0.0175,
46593
- ratio: 1.5,
46594
- precision: 0.6601,
46595
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46596
- verdict: "HYGIENE",
46597
- _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.",
46598
- 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
46599
47997
  },
46600
- "logic/reactive-hook-soup": {
46601
- recall: 38e-4,
47998
+ "ai/console-debug-storm": {
47999
+ recall: 73e-4,
46602
48000
  fpRate: 9e-4,
46603
- ratio: 4.29,
46604
- precision: 0.8476,
46605
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48001
+ ratio: 949.21,
48002
+ precision: 0.9,
48003
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46606
48004
  verdict: "USEFUL",
46607
- _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.",
46608
- 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
46609
48014
  },
46610
- "logic/optimistic-no-rollback": {
46611
- recall: 12e-4,
46612
- fpRate: 3e-4,
46613
- ratio: 3.61,
46614
- precision: 0.824,
46615
- 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",
46616
48021
  verdict: "USEFUL",
46617
- _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.",
46618
- 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
46619
48031
  },
46620
- "logic/zombie-state": {
46621
- recall: 1e-4,
46622
- fpRate: 0,
46623
- ratio: 9.26,
46624
- precision: 0.9231,
46625
- 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",
46626
48038
  verdict: "USEFUL",
46627
- _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.",
46628
- 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
46629
48048
  },
46630
- "logic/math-gini-class-usage": {
46631
- recall: 13e-4,
48049
+ "ai/fetch-default-overuse": {
48050
+ recall: 27e-4,
46632
48051
  fpRate: 3e-4,
46633
- ratio: 5.09,
46634
- precision: 0.8683,
46635
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48052
+ ratio: 2679.84,
48053
+ precision: 0.9036,
48054
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46636
48055
  verdict: "USEFUL",
46637
- _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.",
46638
- 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
46639
48065
  },
46640
- "visual/math-color-cluster": {
46641
- recall: 2e-4,
48066
+ "ai/library-reinvention": {
48067
+ recall: 3e-4,
46642
48068
  fpRate: 0,
46643
- ratio: 8.95,
46644
- precision: 0.9206,
46645
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48069
+ ratio: 47415.05,
48070
+ precision: 0.9405,
48071
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46646
48072
  verdict: "USEFUL",
46647
- _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.",
46648
- 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
46649
48082
  },
46650
- "visual/math-default-font": {
46651
- recall: 13e-4,
46652
- fpRate: 4e-4,
46653
- ratio: 3.4,
46654
- precision: 0.8151,
46655
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46656
- verdict: "USEFUL",
46657
- _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.",
46658
- aiSpecific: true
46659
- },
46660
- "visual/math-gradient-hue-rotation": {
48083
+ "ai/log-rank-histogram": {
46661
48084
  recall: 0,
46662
48085
  fpRate: 0,
46663
48086
  ratio: 0,
46664
48087
  precision: 0,
46665
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48088
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46666
48089
  verdict: "DORMANT",
46667
- defaultOff: true,
46668
- _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.)",
46669
- 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
46670
48100
  },
46671
- "visual/math-rounded-entropy": {
46672
- recall: 37e-4,
46673
- fpRate: 3e-4,
46674
- ratio: 10.9,
46675
- precision: 0.9339,
46676
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46677
- verdict: "USEFUL",
46678
- _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.",
46679
- aiSpecific: true
46680
- },
46681
- "visual/math-font-entropy": {
46682
- recall: 45e-4,
46683
- fpRate: 13e-4,
46684
- ratio: 3.32,
46685
- precision: 0.8114,
46686
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46687
- verdict: "USEFUL",
46688
- _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.",
46689
- aiSpecific: true
46690
- },
46691
- "visual/math-spacing-entropy": {
46692
- recall: 18e-4,
46693
- fpRate: 6e-4,
46694
- ratio: 3.01,
46695
- precision: 0.7959,
46696
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46697
- verdict: "USEFUL",
46698
- _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.",
46699
- 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
46700
48117
  },
46701
- "visual/clamp-soup": {
48118
+ "ai/renyi-profile": {
46702
48119
  recall: 0,
46703
48120
  fpRate: 0,
46704
- ratio: 0,
46705
- precision: 0,
46706
- lastCalibratedAt: "2026-06-25T00:00:00Z",
46707
- verdict: "DORMANT",
46708
- defaultOff: true,
46709
- _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.)",
46710
- 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
46711
48134
  },
46712
- "component/giant-component": {
46713
- recall: 0.0176,
46714
- fpRate: 77e-4,
46715
- ratio: 2.3,
46716
- precision: 0.7485,
46717
- 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",
46718
48141
  verdict: "USEFUL",
46719
- _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.",
46720
- 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
46721
48151
  },
46722
- "component/shadcn-prop-mismatch": {
46723
- recall: 13e-4,
46724
- fpRate: 1e-4,
46725
- ratio: 10.1,
46726
- precision: 0.929,
46727
- 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",
46728
48158
  verdict: "USEFUL",
46729
- _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.",
46730
- aiSpecific: true
46731
- },
46732
- "layout/math-grid-uniformity": {
46733
- recall: 3e-4,
46734
- fpRate: 2e-4,
46735
- ratio: 1.72,
46736
- precision: 0.6907,
46737
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46738
- verdict: "OK",
46739
- _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.",
46740
- 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
46741
48168
  },
46742
- "layout/math-element-uniformity": {
46743
- recall: 28e-4,
46744
- fpRate: 12e-4,
46745
- ratio: 2.28,
46746
- precision: 0.7475,
46747
- 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",
46748
48175
  verdict: "USEFUL",
46749
- _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.",
46750
- 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
46751
48185
  },
46752
- "typo/math-button-label-uniformity": {
46753
- recall: 2e-4,
46754
- fpRate: 1e-4,
46755
- ratio: 1.36,
46756
- precision: 0.6379,
46757
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46758
- verdict: "HYGIENE",
46759
- _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.",
46760
- aiSpecific: false
46761
- },
46762
- "perf/css-bloat": {
46763
- recall: 0.0117,
46764
- fpRate: 32e-4,
46765
- ratio: 3.64,
46766
- precision: 0.8252,
46767
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46768
- verdict: "HYGIENE",
46769
- _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.",
46770
- 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
46771
48202
  },
46772
- "wcag/focus-appearance": {
46773
- recall: 26e-4,
46774
- fpRate: 1e-4,
46775
- ratio: 19.68,
46776
- precision: 0.9623,
46777
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46778
- verdict: "HYGIENE",
46779
- _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.",
46780
- 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
46781
48219
  },
46782
- "wcag/target-size": {
48220
+ "arch/astro-island-leak": {
46783
48221
  recall: 0,
46784
48222
  fpRate: 0,
46785
48223
  ratio: 0,
46786
48224
  precision: 0,
46787
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48225
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46788
48226
  verdict: "DORMANT",
46789
- defaultOff: true,
46790
- _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.)",
46791
- 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
46792
48237
  },
46793
- "component/multiple-components-per-file": {
46794
- recall: 0.0681,
46795
- fpRate: 0.052,
46796
- ratio: 1.31,
46797
- precision: 0.6294,
46798
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46799
- verdict: "HYGIENE",
46800
- _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.",
46801
- aiSpecific: false
46802
- },
46803
- "context/import-path-mismatch": {
46804
- recall: 0.0739,
46805
- fpRate: 0.0228,
46806
- ratio: 3.25,
46807
- precision: 0.8079,
46808
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46809
- verdict: "HYGIENE",
46810
- _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.",
46811
- 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
46812
48254
  },
46813
- "logic/key-prop-missing": {
46814
- recall: 17e-4,
46815
- fpRate: 14e-4,
46816
- ratio: 1.28,
46817
- precision: 0.6246,
46818
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46819
- verdict: "HYGIENE",
46820
- _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.",
46821
- 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
46822
48271
  },
46823
- "logic/math-variable-name-entropy": {
46824
- recall: 2e-4,
48272
+ "component/shadcn-prop-mismatch": {
48273
+ recall: 16e-4,
46825
48274
  fpRate: 1e-4,
46826
- ratio: 1.07,
46827
- precision: 0.5806,
46828
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46829
- verdict: "HYGIENE",
46830
- _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.",
46831
- aiSpecific: false
46832
- },
46833
- "security/public-admin-route": {
46834
- recall: 28e-4,
46835
- fpRate: 78e-4,
46836
- ratio: 0.4,
46837
- precision: 0.2251,
46838
- lastCalibratedAt: "2026-06-26T22:30:00Z",
46839
- verdict: "HYGIENE",
46840
- _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]",
46841
- defaultOff: true,
46842
- aiSpecific: false
46843
- },
46844
- "security/unsafe-html-render": {
46845
- recall: 13e-4,
46846
- fpRate: 9e-4,
46847
- ratio: 1.5,
46848
- precision: 0.661,
46849
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46850
- verdict: "HYGIENE",
46851
- _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.",
46852
- aiSpecific: false
46853
- },
46854
- "visual/naturalness-anomaly": {
46855
- recall: 0.1645,
46856
- fpRate: 0.0617,
46857
- ratio: 2.67,
46858
- precision: 0.7755,
46859
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48275
+ ratio: 9990.98,
48276
+ precision: 0.9512,
48277
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46860
48278
  verdict: "USEFUL",
46861
- _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.",
46862
- 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
46863
48288
  },
46864
- "perf/halstead-anomaly": {
46865
- recall: 0,
46866
- fpRate: 0,
46867
- ratio: 2.32,
46868
- precision: 0.75,
46869
- 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",
46870
48295
  verdict: "USEFUL",
46871
- _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.",
46872
- 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
46873
48305
  },
46874
- "arch/astro-island-leak": {
48306
+ "db/duplicate-index": {
46875
48307
  recall: 0,
46876
48308
  fpRate: 0,
46877
48309
  ratio: 0,
46878
48310
  precision: 0,
46879
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48311
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46880
48312
  verdict: "DORMANT",
46881
- defaultOff: true,
46882
- _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.)",
46883
- 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
46884
48323
  },
46885
- "logic/qwik-hook-leak": {
48324
+ "db/enum-sprawl": {
46886
48325
  recall: 0,
46887
48326
  fpRate: 0,
46888
48327
  ratio: 0,
46889
48328
  precision: 0,
46890
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48329
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46891
48330
  verdict: "DORMANT",
46892
- defaultOff: true,
46893
- _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.)",
46894
- 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
46895
48341
  },
46896
- "test/missing-edge-case": {
48342
+ "db/missing-fk-index": {
46897
48343
  recall: 0,
46898
48344
  fpRate: 0,
46899
48345
  ratio: 0,
46900
48346
  precision: 0,
46901
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48347
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46902
48348
  verdict: "DORMANT",
46903
- defaultOff: true,
46904
- _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.)",
46905
- 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
46906
48359
  },
46907
- "typo/calc-fontsize": {
48360
+ "db/missing-not-null": {
46908
48361
  recall: 0,
46909
48362
  fpRate: 0,
46910
48363
  ratio: 0,
46911
48364
  precision: 0,
46912
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48365
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46913
48366
  verdict: "DORMANT",
46914
- defaultOff: true,
46915
- _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).)",
46916
- 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
46917
48377
  },
46918
- "typo/clamp-offscale": {
48378
+ "db/naming-inconsistency": {
46919
48379
  recall: 0,
46920
48380
  fpRate: 0,
46921
48381
  ratio: 0,
46922
48382
  precision: 0,
46923
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48383
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46924
48384
  verdict: "DORMANT",
46925
- defaultOff: true,
46926
- _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.)",
46927
- 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
46928
48395
  },
46929
- "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": {
46930
48516
  recall: 0,
46931
48517
  fpRate: 0,
46932
48518
  ratio: 0,
46933
48519
  precision: 0,
46934
- lastCalibratedAt: "2026-06-25T00:00:00Z",
46935
- verdict: "DORMANT",
46936
- defaultOff: true,
46937
- _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.)",
46938
- 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
46939
48566
  },
46940
48567
  "layout/forced-layout": {
46941
48568
  recall: 0,
46942
48569
  fpRate: 0,
46943
48570
  ratio: 0,
46944
48571
  precision: 0,
46945
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48572
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46946
48573
  verdict: "DORMANT",
46947
- defaultOff: true,
46948
- _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.)",
46949
- 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
46950
48584
  },
46951
- "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": {
46952
48654
  recall: 0,
46953
48655
  fpRate: 0,
46954
48656
  ratio: 0,
46955
48657
  precision: 0,
46956
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48658
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46957
48659
  verdict: "DORMANT",
46958
- defaultOff: true,
46959
- _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.)",
46960
- 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
46961
48670
  },
46962
- "product/terminology-drift": {
46963
- recall: 85e-4,
46964
- fpRate: 28e-4,
46965
- ratio: 3,
46966
- precision: 0.7956,
46967
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46968
- verdict: "HYGIENE",
46969
- _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.",
46970
- 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
46971
48687
  },
46972
- "product/ux-pattern-fragmentation": {
48688
+ "logic/ghost-defensive": {
46973
48689
  recall: 1e-4,
46974
48690
  fpRate: 0,
46975
- ratio: 3.09,
46976
- precision: 0.8,
46977
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48691
+ ratio: 112035.56,
48692
+ precision: 0.8889,
48693
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46978
48694
  verdict: "USEFUL",
46979
- _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.",
46980
- 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
46981
48704
  },
46982
- "security/sql-construction": {
46983
- recall: 3e-3,
46984
- fpRate: 18e-4,
46985
- ratio: 1.63,
46986
- precision: 0.6788,
46987
- 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",
46988
48711
  verdict: "OK",
46989
- _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.",
46990
- 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
46991
48721
  },
46992
- "security/missing-auth-check": {
46993
- recall: 63e-4,
46994
- fpRate: 4e-4,
46995
- ratio: 15.3,
46996
- precision: 0.9247,
46997
- 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",
46998
48728
  verdict: "USEFUL",
46999
- _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.",
47000
- 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
47001
48738
  },
47002
- "security/dangerous-cors": {
47003
- recall: 5e-4,
47004
- fpRate: 5e-4,
47005
- ratio: 1.05,
47006
- precision: 0.5758,
47007
- 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",
47008
48745
  verdict: "NOISY",
47009
- _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.",
47010
- defaultOff: true,
47011
- 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
47012
48756
  },
47013
- "test/duplicate-setup": {
47014
- recall: 1e-4,
47015
- fpRate: 0,
47016
- ratio: 3.6,
47017
- precision: 0.8235,
47018
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47019
- verdict: "USEFUL",
47020
- _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.",
47021
- aiSpecific: true
47022
- },
47023
- "logic/ghost-defensive": {
47024
- recall: 1e-4,
47025
- fpRate: 0,
47026
- ratio: 5.79,
47027
- precision: 0.8824,
47028
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47029
- verdict: "USEFUL",
47030
- _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.",
47031
- aiSpecific: true
47032
- },
47033
- "typo/calc-raw-px": {
47034
- recall: 0,
47035
- fpRate: 0,
47036
- ratio: 2.32,
47037
- precision: 0.75,
47038
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47039
- verdict: "HYGIENE",
47040
- _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.",
47041
- aiSpecific: false
47042
- },
47043
- "security/fail-open-auth": {
47044
- recall: 0,
47045
- fpRate: 0,
47046
- ratio: 99.99,
47047
- precision: 1,
47048
- 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",
47049
48763
  verdict: "USEFUL",
47050
- _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.",
47051
- aiSpecific: true
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
47052
48773
  },
47053
- "wcag/focus-obscured": {
47054
- recall: 33e-4,
47055
- fpRate: 9e-4,
47056
- ratio: 3.51,
47057
- precision: 0.82,
47058
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47059
- verdict: "HYGIENE",
47060
- _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.",
47061
- aiSpecific: false
47062
- },
47063
- "visual/arbitrary-escape": {
47064
- recall: 25e-4,
47065
- fpRate: 9e-4,
47066
- ratio: 2.74,
47067
- precision: 0.7802,
47068
- 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",
47069
48780
  verdict: "USEFUL",
47070
- _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.",
47071
- 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
47072
48790
  },
47073
- "security/hardcoded-secret": {
48791
+ "logic/math-gini-class-usage": {
47074
48792
  recall: 13e-4,
47075
- fpRate: 7e-4,
47076
- ratio: 1.72,
47077
- precision: 0.6899,
47078
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47079
- verdict: "OK",
47080
- _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.",
47081
- aiSpecific: true
47082
- },
47083
- "visual/radius-scale-violation": {
47084
- recall: 4e-4,
47085
- fpRate: 0,
47086
- ratio: 24.7,
47087
- precision: 0.9697,
47088
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47089
- verdict: "HYGIENE",
47090
- _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.",
47091
- aiSpecific: false
47092
- },
47093
- "test/fake-placeholder": {
47094
- recall: 53e-4,
47095
- fpRate: 19e-4,
47096
- ratio: 2.82,
47097
- precision: 0.7854,
47098
- 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",
47099
48797
  verdict: "USEFUL",
47100
- _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.",
47101
- aiSpecific: true
47102
- },
47103
- "security/exposed-env-var": {
47104
- recall: 6e-4,
47105
- fpRate: 7e-4,
47106
- ratio: 0.9,
47107
- precision: 0.5387,
47108
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47109
- verdict: "HYGIENE",
47110
- _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.",
47111
- aiSpecific: false
47112
- },
47113
- "perf/cls-image": {
47114
- recall: 2e-4,
47115
- fpRate: 3e-4,
47116
- ratio: 0.8,
47117
- precision: 0.5104,
47118
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47119
- verdict: "HYGIENE",
47120
- _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.",
47121
- aiSpecific: false
47122
- },
47123
- "layout/gap-monopoly": {
47124
- recall: 4e-4,
47125
- fpRate: 1e-4,
47126
- ratio: 2.95,
47127
- precision: 0.7928,
47128
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47129
- verdict: "HYGIENE",
47130
- _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.",
47131
- 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
47132
48807
  },
47133
- "visual/spacing-scale-violation": {
47134
- recall: 83e-4,
47135
- fpRate: 39e-4,
47136
- ratio: 2.13,
47137
- precision: 0.7342,
47138
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47139
- verdict: "HYGIENE",
47140
- _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.",
47141
- aiSpecific: false
47142
- },
47143
- "visual/inline-style-dominance": {
47144
- recall: 96e-4,
47145
- fpRate: 66e-4,
47146
- ratio: 1.46,
47147
- precision: 0.6535,
47148
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47149
- verdict: "HYGIENE",
47150
- _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.",
47151
- aiSpecific: false
47152
- },
47153
- "layout/spacing-grid": {
48808
+ "logic/math-variable-name-entropy": {
47154
48809
  recall: 2e-4,
47155
48810
  fpRate: 1e-4,
47156
- ratio: 2.01,
47157
- precision: 0.7222,
47158
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47159
- verdict: "HYGIENE",
47160
- _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.",
47161
- aiSpecific: false
47162
- },
47163
- "wcag/dragging-movements": {
47164
- recall: 0,
47165
- fpRate: 0,
47166
- ratio: 0.51,
47167
- precision: 0.4,
47168
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47169
- verdict: "HYGIENE",
47170
- _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.",
47171
- 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
47172
48824
  },
47173
- "test/weak-assertion": {
47174
- recall: 0.0414,
47175
- fpRate: 86e-4,
47176
- ratio: 4.83,
47177
- precision: 0.8622,
47178
- 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",
47179
48831
  verdict: "USEFUL",
47180
- _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.",
47181
- 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
47182
48841
  },
47183
- "logic/bayesian-conditional": {
48842
+ "logic/qwik-hook-leak": {
47184
48843
  recall: 0,
47185
48844
  fpRate: 0,
47186
48845
  ratio: 0,
47187
48846
  precision: 0,
47188
- lastCalibratedAt: "2026-06-27T00:00:00Z",
48847
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47189
48848
  verdict: "DORMANT",
47190
- defaultOff: true,
47191
- _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.",
47192
- aiSpecific: true
47193
- },
47194
- "logic/heaps-deviation": {
47195
- recall: 0.0122,
47196
- fpRate: 0.0132,
47197
- ratio: 0.93,
47198
- precision: 0.5461,
47199
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47200
- verdict: "HYGIENE",
47201
- _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.",
47202
- 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
47203
48859
  },
47204
- "logic/ks-distribution-shift": {
47205
- recall: 0.6375,
47206
- fpRate: 0.338,
47207
- ratio: 1.89,
47208
- precision: 0.7096,
47209
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47210
- verdict: "HYGIENE",
47211
- _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.",
47212
- 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
47213
48876
  },
47214
48877
  "logic/zipf-slope-anomaly": {
47215
- recall: 0.0156,
47216
- fpRate: 87e-4,
47217
- ratio: 1.79,
47218
- precision: 0.6983,
47219
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47220
- verdict: "HYGIENE",
47221
- _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.",
47222
- 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
47223
48893
  },
47224
- "ai/markdown-leakage": {
47225
- recall: 0,
48894
+ "logic/zombie-state": {
48895
+ recall: 1e-4,
47226
48896
  fpRate: 0,
47227
- ratio: 1.93,
47228
- precision: 0.7143,
47229
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47230
- verdict: "OK",
47231
- _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.",
47232
- 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
47233
48910
  },
47234
- "ai/comment-ratio": {
47235
- recall: 0.2523,
47236
- fpRate: 0.1619,
47237
- ratio: 1.56,
47238
- precision: 0.6687,
47239
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47240
- verdict: "OK",
47241
- _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.",
47242
- 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
47243
48927
  },
47244
- "ai/whitespace-regularity": {
47245
- recall: 0.0731,
47246
- fpRate: 0.0728,
47247
- ratio: 1,
47248
- precision: 0.5652,
47249
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47250
- verdict: "NOISY",
47251
- _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.",
47252
- defaultOff: true,
47253
- 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
47254
48944
  },
47255
- "ai/text-like-ratio": {
48945
+ "perf/halstead-anomaly": {
47256
48946
  recall: 0,
47257
48947
  fpRate: 0,
47258
- ratio: 2.32,
47259
- precision: 0.75,
47260
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48948
+ ratio: 75624,
48949
+ precision: 0.6,
48950
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47261
48951
  verdict: "USEFUL",
47262
- _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.",
47263
- 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
47264
48961
  },
47265
- "ai/errors-near-eof": {
47266
- recall: 0.0697,
47267
- fpRate: 0.0548,
47268
- ratio: 1.27,
47269
- precision: 0.6225,
47270
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47271
- verdict: "NOISY",
47272
- _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.",
47273
- defaultOff: true,
47274
- 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
47275
48978
  },
47276
- "ai/any-density": {
47277
- recall: 55e-4,
47278
- fpRate: 41e-4,
47279
- ratio: 1.34,
47280
- precision: 0.634,
47281
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47282
- verdict: "NOISY",
47283
- _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.",
47284
- defaultOff: true,
47285
- 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
47286
48995
  },
47287
- "ai/renyi-profile": {
47288
- recall: 0,
48996
+ "rust/stringly-typed": {
48997
+ recall: 2e-4,
47289
48998
  fpRate: 0,
47290
- ratio: 0.26,
47291
- precision: 0.25,
47292
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47293
- verdict: "INVERTED",
47294
- _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.",
47295
- defaultOff: true,
47296
- 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
47297
49012
  },
47298
- "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": {
47299
49031
  recall: 0,
47300
49032
  fpRate: 0,
47301
- ratio: 0,
47302
- precision: 0,
47303
- lastCalibratedAt: "2026-06-27T00:00:00Z",
49033
+ ratio: 10803.43,
49034
+ precision: 0.3,
49035
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47304
49036
  verdict: "OK",
47305
- _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).",
47306
- 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
47307
49046
  },
47308
- "ai/segment-surprisal-cv": {
47309
- recall: 0.182,
47310
- fpRate: 0.0812,
47311
- ratio: 2.24,
47312
- precision: 0.7438,
47313
- 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",
47314
49053
  verdict: "USEFUL",
47315
- _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.",
47316
- 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
47317
49063
  },
47318
- "ai/compression-profile": {
47319
- recall: 0.3139,
47320
- fpRate: 0.1489,
47321
- ratio: 2.11,
47322
- precision: 0.732,
47323
- 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",
47324
49070
  verdict: "USEFUL",
47325
- _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.",
47326
- 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
47327
49080
  },
47328
- "ai/tailwind-color-overuse": {
47329
- recall: 0.0216,
47330
- fpRate: 52e-4,
47331
- ratio: 4.16,
47332
- precision: 0.8436,
47333
- 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",
47334
49104
  verdict: "USEFUL",
47335
- _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.",
47336
- 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
47337
49114
  },
47338
- "ai/default-react-stack": {
47339
- recall: 1e-3,
49115
+ "security/fail-open-auth": {
49116
+ recall: 0,
47340
49117
  fpRate: 0,
47341
- ratio: 99.99,
47342
- precision: 0.9957,
47343
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49118
+ ratio: 99999,
49119
+ precision: 1,
49120
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47344
49121
  verdict: "USEFUL",
47345
- _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.",
47346
- 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
47347
49131
  },
47348
- "ai/library-reinvention": {
47349
- 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,
47350
49151
  fpRate: 0,
47351
- ratio: 9.88,
47352
- precision: 0.9275,
47353
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49152
+ ratio: 99999,
49153
+ precision: 1,
49154
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47354
49155
  verdict: "USEFUL",
47355
- _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.",
47356
- 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
47357
49165
  },
47358
- "ai/state-default-overuse": {
47359
- recall: 29e-4,
47360
- fpRate: 9e-4,
47361
- ratio: 3.42,
47362
- precision: 0.8161,
47363
- 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",
47364
49172
  verdict: "USEFUL",
47365
- _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.",
47366
- 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
47367
49182
  },
47368
- "ai/fetch-default-overuse": {
47369
- recall: 28e-4,
47370
- fpRate: 4e-4,
47371
- ratio: 6.76,
47372
- precision: 0.8976,
47373
- 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",
47374
49189
  verdict: "USEFUL",
47375
- _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.",
47376
- 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
47377
49199
  },
47378
- "ai/console-debug-storm": {
47379
- recall: 8e-3,
47380
- fpRate: 9e-4,
47381
- ratio: 8.43,
47382
- precision: 0.9161,
47383
- 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",
47384
49206
  verdict: "USEFUL",
47385
- _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.",
47386
- 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
47387
49216
  },
47388
- "db/missing-fk-index": {
47389
- recall: 0,
49217
+ "security/target-blank-no-noopener": {
49218
+ recall: 4e-4,
47390
49219
  fpRate: 0,
47391
- ratio: 0,
47392
- precision: 0,
47393
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47394
- verdict: "DORMANT",
47395
- defaultOff: true,
47396
- _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.)",
47397
- 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
47398
49233
  },
47399
- "db/duplicate-index": {
47400
- recall: 0,
47401
- fpRate: 0,
47402
- ratio: 0,
47403
- precision: 0,
47404
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47405
- verdict: "DORMANT",
47406
- defaultOff: true,
47407
- _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.)",
47408
- 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
47409
49250
  },
47410
- "db/missing-not-null": {
47411
- recall: 0,
49251
+ "test/duplicate-setup": {
49252
+ recall: 1e-4,
47412
49253
  fpRate: 0,
47413
- ratio: 0,
47414
- precision: 0,
47415
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47416
- verdict: "DORMANT",
47417
- defaultOff: true,
47418
- _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.)",
47419
- 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
47420
49267
  },
47421
- "db/enum-sprawl": {
47422
- recall: 0,
47423
- fpRate: 0,
47424
- ratio: 0,
47425
- precision: 0,
47426
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47427
- verdict: "DORMANT",
47428
- defaultOff: true,
47429
- _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.)",
47430
- 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
47431
49284
  },
47432
- "db/naming-inconsistency": {
49285
+ "test/missing-edge-case": {
47433
49286
  recall: 0,
47434
49287
  fpRate: 0,
47435
49288
  ratio: 0,
47436
49289
  precision: 0,
47437
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49290
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47438
49291
  verdict: "DORMANT",
47439
- defaultOff: true,
47440
- _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.)",
47441
- 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
47442
49302
  },
47443
- "db/sql-concat": {
47444
- recall: 0,
47445
- fpRate: 0,
47446
- ratio: 0,
47447
- precision: 0,
47448
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47449
- verdict: "DORMANT",
47450
- defaultOff: true,
47451
- _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.)",
47452
- 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
47453
49319
  },
47454
- "dead/unused-import": {
49320
+ "typo/calc-fontsize": {
47455
49321
  recall: 0,
47456
49322
  fpRate: 0,
47457
49323
  ratio: 0,
47458
49324
  precision: 0,
47459
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49325
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47460
49326
  verdict: "DORMANT",
47461
- defaultOff: true,
47462
- _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.",
47463
- 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
47464
49337
  },
47465
- "dead/unused-local": {
49338
+ "typo/calc-raw-px": {
47466
49339
  recall: 0,
47467
49340
  fpRate: 0,
47468
- ratio: 0,
47469
- precision: 0,
47470
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47471
- verdict: "DORMANT",
47472
- defaultOff: true,
47473
- _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).",
47474
- 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
47475
49354
  },
47476
- "dead/unused-parameter": {
49355
+ "typo/clamp-offscale": {
47477
49356
  recall: 0,
47478
49357
  fpRate: 0,
47479
49358
  ratio: 0,
47480
49359
  precision: 0,
47481
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49360
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47482
49361
  verdict: "DORMANT",
47483
- defaultOff: true,
47484
- _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.",
47485
- 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
47486
49372
  },
47487
- "dead/dead-branch": {
47488
- recall: 0,
47489
- fpRate: 0,
47490
- ratio: 0,
47491
- precision: 0,
47492
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47493
- verdict: "DORMANT",
47494
- defaultOff: true,
47495
- _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.",
47496
- 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
47497
49389
  },
47498
- "dead/unreachable": {
49390
+ "typo/math-cta-vocabulary": {
47499
49391
  recall: 0,
47500
49392
  fpRate: 0,
47501
49393
  ratio: 0,
47502
49394
  precision: 0,
47503
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49395
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47504
49396
  verdict: "DORMANT",
47505
- defaultOff: true,
47506
- _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.",
47507
- 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
47508
49407
  },
47509
- "docs/stale-package-reference": {
47510
- recall: 0,
49408
+ "typo/placeholder-text": {
49409
+ recall: 1e-4,
47511
49410
  fpRate: 0,
47512
- ratio: 0,
47513
- precision: 0,
47514
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47515
- verdict: "DORMANT",
47516
- defaultOff: true,
47517
- _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.)",
47518
- 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
47519
49424
  },
47520
- "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": {
47521
49443
  recall: 0,
47522
49444
  fpRate: 0,
47523
49445
  ratio: 0,
47524
49446
  precision: 0,
47525
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49447
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47526
49448
  verdict: "DORMANT",
47527
- defaultOff: true,
47528
- _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.)",
47529
- 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
47530
49459
  },
47531
- "docs/expired-code-example": {
49460
+ "visual/generic-centering": {
47532
49461
  recall: 0,
47533
49462
  fpRate: 0,
47534
49463
  ratio: 0,
47535
49464
  precision: 0,
47536
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49465
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47537
49466
  verdict: "DORMANT",
47538
- defaultOff: true,
47539
- _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.)",
47540
- 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
47541
49477
  },
47542
- "docs/broken-link": {
47543
- 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,
47544
49497
  fpRate: 0,
47545
- ratio: 0,
47546
- precision: 0,
47547
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47548
- verdict: "DORMANT",
47549
- defaultOff: true,
47550
- _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.)",
47551
- 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
47552
49511
  },
47553
- "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": {
47554
49547
  recall: 0,
47555
49548
  fpRate: 0,
47556
49549
  ratio: 0,
47557
49550
  precision: 0,
47558
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49551
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47559
49552
  verdict: "DORMANT",
47560
- defaultOff: true,
47561
- _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.)",
47562
- 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
47563
49563
  },
47564
- "security/localstorage-token": {
47565
- 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,
47566
49617
  fpRate: 0,
47567
- ratio: 0,
47568
- precision: 0,
47569
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47570
- verdict: "DORMANT",
47571
- defaultOff: true,
47572
- _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.)",
47573
- 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
47574
49631
  },
47575
- "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": {
47576
49650
  recall: 0,
47577
49651
  fpRate: 0,
47578
- ratio: 0,
47579
- precision: 0,
47580
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47581
- verdict: "DORMANT",
47582
- defaultOff: true,
47583
- _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.)',
47584
- 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
47585
49699
  },
47586
49700
  "wcag/missing-alt": {
47587
- recall: 0,
47588
- fpRate: 0,
47589
- ratio: 0,
47590
- precision: 0,
47591
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47592
- verdict: "DORMANT",
47593
- defaultOff: true,
47594
- _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.)',
47595
- 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
47596
49716
  },
47597
- "typo/placeholder-text": {
49717
+ "wcag/target-size": {
47598
49718
  recall: 0,
47599
49719
  fpRate: 0,
47600
49720
  ratio: 0,
47601
49721
  precision: 0,
47602
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49722
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47603
49723
  verdict: "DORMANT",
47604
- defaultOff: true,
47605
- _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.)",
47606
- 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
47607
49734
  }
47608
49735
  };
47609
49736
  }
@@ -47673,7 +49800,6 @@ async function scanFile(filePath, config, registry, cwd = process.cwd()) {
47673
49800
  ".kt",
47674
49801
  ".kts",
47675
49802
  ".dart",
47676
- ".rs",
47677
49803
  ".cpp",
47678
49804
  ".cc",
47679
49805
  ".cxx",
@@ -54502,7 +56628,12 @@ var RULE_HINTS = {
54502
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.",
54503
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.",
54504
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.",
54505
- "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.'
54506
56637
  };
54507
56638
 
54508
56639
  // src/cli/commands/explain.ts