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.cjs CHANGED
@@ -36,7 +36,7 @@ var VERSION;
36
36
  var init_header = __esm({
37
37
  "src/types/_header.ts"() {
38
38
  "use strict";
39
- VERSION = "0.18.5";
39
+ VERSION = "0.18.9";
40
40
  }
41
41
  });
42
42
 
@@ -28238,6 +28238,20 @@ var init_unreachable = __esm({
28238
28238
  });
28239
28239
 
28240
28240
  // src/rules/dead/unused-import.ts
28241
+ function collectRustReferencedNames(source) {
28242
+ const out = /* @__PURE__ */ new Set();
28243
+ for (const m of source.matchAll(/\b([A-Za-z_][A-Za-z0-9_]*)\b/g)) {
28244
+ out.add(m[1]);
28245
+ }
28246
+ return out;
28247
+ }
28248
+ function stripUseDeclarations(source) {
28249
+ let out = source;
28250
+ out = out.replace(/^\s*use\s+[\s\S]*?;\s*$/gm, "");
28251
+ out = out.replace(/\/\/[^\n]*/g, "");
28252
+ out = out.replace(/\/\*[\s\S]*?\*\//g, "");
28253
+ return out;
28254
+ }
28241
28255
  var unusedImportRule;
28242
28256
  var init_unused_import = __esm({
28243
28257
  "src/rules/dead/unused-import.ts"() {
@@ -28273,6 +28287,26 @@ var init_unused_import = __esm({
28273
28287
  advice: `Remove the import or use '${binding.name}' somewhere in the file. This is the most common AI-iteration rot \u2014 the model added the import when it introduced a feature, then rewrote the function without cleaning up.`
28274
28288
  });
28275
28289
  }
28290
+ if (facts.v2.rustFile) {
28291
+ const strippedSource = stripUseDeclarations(facts.v2._source ?? "");
28292
+ const referenced = collectRustReferencedNames(strippedSource);
28293
+ for (const imp of facts.v2.rustFile.imports) {
28294
+ for (const nameEntry of imp.names) {
28295
+ if (referenced.has(nameEntry.name)) continue;
28296
+ const source = ` from '${imp.path}'`;
28297
+ issues.push({
28298
+ ruleId: "dead/unused-import",
28299
+ category: "logic",
28300
+ severity: "low",
28301
+ aiSpecific: true,
28302
+ message: `Unused import: '${nameEntry.name}'${source}`,
28303
+ line: imp.line,
28304
+ column: imp.column,
28305
+ advice: `Remove the '${imp.path}' import or use '${nameEntry.name}' somewhere in the file. Rust's compiler only flags unused imports per module \u2014 the tree-sitter-backed walker here surfaces them for slopbrick's dead-code rules regardless of #[allow(unused_imports)].`
28306
+ });
28307
+ }
28308
+ }
28309
+ }
28276
28310
  return issues;
28277
28311
  }
28278
28312
  });
@@ -29015,10 +29049,67 @@ var init_dart = __esm({
29015
29049
  }
29016
29050
  });
29017
29051
 
29052
+ // src/engine/parser-rust.ts
29053
+ function getRustParser() {
29054
+ if (cachedParser) return { ok: true, parser: cachedParser };
29055
+ if (loadError) return { ok: false, error: loadError };
29056
+ try {
29057
+ rustLanguage = import_tree_sitter_rust.default;
29058
+ if (!rustLanguage || typeof rustLanguage !== "object") {
29059
+ throw new Error("tree-sitter-rust: language export is missing or malformed");
29060
+ }
29061
+ const parser = new import_tree_sitter.default();
29062
+ parser.setLanguage(rustLanguage);
29063
+ cachedParser = parser;
29064
+ return { ok: true, parser };
29065
+ } catch (err) {
29066
+ loadError = err instanceof Error ? err : new Error(String(err));
29067
+ return { ok: false, error: loadError };
29068
+ }
29069
+ }
29070
+ function effectiveParser() {
29071
+ if (forcedFailure) return { ok: false, error: forcedFailure };
29072
+ return getRustParser();
29073
+ }
29074
+ function parseRust(source) {
29075
+ const result = effectiveParser();
29076
+ if (!result.ok) return null;
29077
+ if (!source || source.trim() === "") return null;
29078
+ try {
29079
+ const rawTree = result.parser.parse(source);
29080
+ if (!rawTree) return null;
29081
+ const tree = rawTree;
29082
+ if (!tree || !tree.rootNode) return null;
29083
+ if (tree.rootNode.type === "ERROR" && tree.rootNode.childCount === 0) {
29084
+ return null;
29085
+ }
29086
+ return tree;
29087
+ } catch {
29088
+ return null;
29089
+ }
29090
+ }
29091
+ function isRustParserAvailable() {
29092
+ const result = getRustParser();
29093
+ return result.ok;
29094
+ }
29095
+ var import_tree_sitter, import_tree_sitter_rust, cachedParser, rustLanguage, loadError, forcedFailure;
29096
+ var init_parser_rust = __esm({
29097
+ "src/engine/parser-rust.ts"() {
29098
+ "use strict";
29099
+ import_tree_sitter = __toESM(require("tree-sitter"), 1);
29100
+ import_tree_sitter_rust = __toESM(require("tree-sitter-rust"), 1);
29101
+ cachedParser = null;
29102
+ rustLanguage = null;
29103
+ loadError = null;
29104
+ forcedFailure = null;
29105
+ }
29106
+ });
29107
+
29018
29108
  // src/engine/visitors/rust.ts
29019
29109
  var rust_exports = {};
29020
29110
  __export(rust_exports, {
29021
- extractRustPatterns: () => extractRustPatterns
29111
+ extractRustPatterns: () => extractRustPatterns,
29112
+ parseRustFile: () => parseRustFile
29022
29113
  });
29023
29114
  function extractRustPatterns(filePath, source) {
29024
29115
  const service = [];
@@ -29071,188 +29162,487 @@ function extractRustPatterns(filePath, source) {
29071
29162
  }
29072
29163
  return { service, route, ormModel };
29073
29164
  }
29074
- var SERVICE_SUFFIXES4, SERVICE_SUFFIX_GROUP4, RUST_SERVICE_STRUCT_RE, RUST_SERVICE_IMPL_RE, RUST_ACTIX_ROUTE_RE, RUST_AXUM_ROUTE_RE, RUST_DIESEL_RE, RUST_SEAORM_RE, RUST_SQLX_RE;
29075
- var init_rust = __esm({
29076
- "src/engine/visitors/rust.ts"() {
29077
- "use strict";
29078
- SERVICE_SUFFIXES4 = [
29079
- "Service",
29080
- "Manager",
29081
- "Handler",
29082
- "Repository",
29083
- "Controller",
29084
- "Helper",
29085
- "Factory",
29086
- "Provider",
29087
- "Store",
29088
- "API",
29089
- "Client",
29090
- "Adapter",
29091
- "Resolver",
29092
- "Mapper",
29093
- "Transformer",
29094
- "Serializer",
29095
- "Validator",
29096
- "Strategy",
29097
- "Facade",
29098
- "Decorator",
29099
- "Observer",
29100
- "Builder",
29101
- "Command",
29102
- "Processor",
29103
- "Worker",
29104
- "Job",
29105
- "Actor",
29106
- "Executor"
29107
- ];
29108
- SERVICE_SUFFIX_GROUP4 = `(?:${SERVICE_SUFFIXES4.join("|")})`;
29109
- RUST_SERVICE_STRUCT_RE = new RegExp(
29110
- `^(?:pub(?:\\(crate\\)|\\(super\\))?\\s+)?struct\\s+(\\w+?)${SERVICE_SUFFIX_GROUP4}?\\b`,
29111
- "gm"
29112
- );
29113
- RUST_SERVICE_IMPL_RE = new RegExp(
29114
- `^impl(?:<[^>]+>)?\\s+(?:${SERVICE_SUFFIX_GROUP4}\\s+for\\s+)?(\\w+?)${SERVICE_SUFFIX_GROUP4}?\\b`,
29115
- "gm"
29116
- );
29117
- RUST_ACTIX_ROUTE_RE = /#\[(?:get|post|put|delete|patch|head|route)\(\s*"(\/[^"]+)"\s*[\),]/g;
29118
- RUST_AXUM_ROUTE_RE = /\.route\(\s*"(\/[^"]+)"\s*,\s*(?:get|post|put|delete|patch)/g;
29119
- RUST_DIESEL_RE = /#\[derive\([^\]]*Queryable[^\]]*\)\][\s\S]{0,200}?struct\s+(\w+)/g;
29120
- RUST_SEAORM_RE = /#\[derive\([^\]]*DeriveEntityModel[^\]]*\)\][\s\S]{0,200}?struct\s+(\w+)/g;
29121
- RUST_SQLX_RE = /#\[derive\([^\]]*sqlx::FromRow[^\]]*\)\][\s\S]{0,200}?struct\s+(\w+)/g;
29165
+ function parseRustFile(filePath, source, options = {}) {
29166
+ const empty = {
29167
+ imports: [],
29168
+ functions: [],
29169
+ structs: [],
29170
+ traits: [],
29171
+ impls: []
29172
+ };
29173
+ if (!isRustParserAvailable() || options.forceFallback) {
29174
+ return empty;
29122
29175
  }
29123
- });
29124
-
29125
- // src/engine/visitors/cpp.ts
29126
- var cpp_exports = {};
29127
- __export(cpp_exports, {
29128
- extractCppPatterns: () => extractCppPatterns
29129
- });
29130
- function extractCppPatterns(filePath, source) {
29131
- const service = [];
29132
- const route = [];
29133
- const ormModel = [];
29134
- const seenService = /* @__PURE__ */ new Set();
29135
- for (const m of source.matchAll(CPP_SERVICE_RE)) {
29136
- const name = m[1];
29137
- if (seenService.has(name)) continue;
29138
- seenService.add(name);
29139
- service.push({ name, files: [filePath], imports: [] });
29176
+ const tree = parseRust(source);
29177
+ if (!tree) return empty;
29178
+ return walkRustTree(tree);
29179
+ }
29180
+ function walkRustTree(tree) {
29181
+ const ctx = { inTestConfig: false };
29182
+ const out = {
29183
+ imports: [],
29184
+ functions: [],
29185
+ structs: [],
29186
+ traits: [],
29187
+ impls: []
29188
+ };
29189
+ walkChildren(tree.rootNode, ctx, out);
29190
+ return out;
29191
+ }
29192
+ function walkChildren(node, ctx, out) {
29193
+ for (let i = 0; i < node.namedChildCount; i++) {
29194
+ const child = node.namedChild(i);
29195
+ if (!child) continue;
29196
+ visitNode(child, ctx, out);
29140
29197
  }
29141
- const seenRoute = /* @__PURE__ */ new Set();
29142
- for (const m of source.matchAll(CPP_CROW_ROUTE_RE)) {
29143
- const name = m[1];
29144
- if (seenRoute.has(name)) continue;
29145
- seenRoute.add(name);
29146
- route.push({ name, files: [filePath], imports: [] });
29198
+ }
29199
+ function visitNode(node, ctx, out) {
29200
+ const innerCtx = { ...ctx };
29201
+ const attrState = readPrecedingAttributes(node);
29202
+ switch (node.type) {
29203
+ case "use_declaration": {
29204
+ out.imports.push(extractUse(node));
29205
+ return;
29206
+ }
29207
+ case "function_item": {
29208
+ const isMethod = isInImplBlock(node);
29209
+ out.functions.push(extractFunction(node, attrState, innerCtx.inTestConfig, isMethod));
29210
+ walkChildren(getField(node, "body") ?? node, innerCtx, out);
29211
+ return;
29212
+ }
29213
+ case "struct_item": {
29214
+ out.structs.push(extractStruct(node, attrState));
29215
+ const body = getField(node, "body");
29216
+ if (body) walkChildren(body, innerCtx, out);
29217
+ return;
29218
+ }
29219
+ case "trait_item": {
29220
+ out.traits.push(extractTrait(node, attrState));
29221
+ const body = getField(node, "body");
29222
+ if (body) walkChildren(body, innerCtx, out);
29223
+ return;
29224
+ }
29225
+ case "impl_item": {
29226
+ const implEntry = extractImpl(node, attrState, innerCtx);
29227
+ out.impls.push(implEntry.entry);
29228
+ const body = getField(node, "body");
29229
+ if (body) walkChildren(body, innerCtx, out);
29230
+ return;
29231
+ }
29232
+ case "mod_item": {
29233
+ const modIsTest = innerCtx.inTestConfig || attrState.isTestCfg;
29234
+ const modCtx = { ...innerCtx, inTestConfig: modIsTest };
29235
+ const body = getField(node, "body");
29236
+ if (body) walkChildren(body, modCtx, out);
29237
+ return;
29238
+ }
29239
+ default: {
29240
+ for (let i = 0; i < node.namedChildCount; i++) {
29241
+ const child = node.namedChild(i);
29242
+ if (child) visitNode(child, innerCtx, out);
29243
+ }
29244
+ }
29147
29245
  }
29148
- for (const m of source.matchAll(CPP_DROGON_ROUTE_RE)) {
29149
- const name = m[1] || m[2];
29246
+ }
29247
+ function readPrecedingAttributes(node) {
29248
+ const state = {
29249
+ isTestCfg: false,
29250
+ isTest: false,
29251
+ isPub: false,
29252
+ derives: []
29253
+ };
29254
+ const parent = node.parent;
29255
+ if (!parent) return state;
29256
+ for (let i = 0; i < parent.namedChildCount; i++) {
29257
+ const sibling = parent.namedChild(i);
29258
+ if (!sibling || sibling === node) continue;
29259
+ if (sibling.endIndex > node.startIndex) continue;
29260
+ if (sibling.type !== "attribute_item") continue;
29261
+ decodeAttribute(sibling, state);
29262
+ }
29263
+ return state;
29264
+ }
29265
+ function decodeAttribute(attr, state) {
29266
+ for (let i = 0; i < attr.namedChildCount; i++) {
29267
+ const child = attr.namedChild(i);
29268
+ if (!child || child.type !== "attribute") continue;
29269
+ const name = firstIdentifier(child);
29150
29270
  if (!name) continue;
29151
- if (seenRoute.has(name)) continue;
29152
- seenRoute.add(name);
29153
- route.push({ name, files: [filePath], imports: [] });
29154
- }
29155
- for (const m of source.matchAll(CPP_PISTACHE_ROUTE_RE)) {
29156
- const name = m[1];
29157
- if (seenRoute.has(name)) continue;
29158
- seenRoute.add(name);
29159
- route.push({ name, files: [filePath], imports: [] });
29271
+ if (name === "cfg") {
29272
+ const cfgText = child.text;
29273
+ if (/\btest\b/.test(cfgText) && !/\bnot\(test\)/.test(cfgText)) {
29274
+ state.isTestCfg = true;
29275
+ }
29276
+ } else if (name === "test") {
29277
+ state.isTest = true;
29278
+ } else if (name === "derive") {
29279
+ for (let j = 0; j < child.namedChildCount; j++) {
29280
+ const inner = child.namedChild(j);
29281
+ if (inner) {
29282
+ const matches = inner.text.matchAll(/\b([A-Z][A-Za-z0-9_]*)\b/g);
29283
+ for (const m of matches) state.derives.push(m[1]);
29284
+ }
29285
+ }
29286
+ }
29160
29287
  }
29161
- return { service, route, ormModel };
29162
29288
  }
29163
- var SERVICE_SUFFIXES5, SERVICE_SUFFIX_GROUP5, CPP_SERVICE_RE, CPP_CROW_ROUTE_RE, CPP_DROGON_ROUTE_RE, CPP_PISTACHE_ROUTE_RE;
29164
- var init_cpp = __esm({
29165
- "src/engine/visitors/cpp.ts"() {
29166
- "use strict";
29167
- SERVICE_SUFFIXES5 = [
29168
- "Service",
29169
- "Manager",
29170
- "Handler",
29171
- "Repository",
29172
- "Controller",
29173
- "Helper",
29174
- "Factory",
29175
- "Provider",
29176
- "Store",
29177
- "API",
29178
- "Client",
29179
- "Adapter",
29180
- "Resolver",
29181
- "Mapper",
29182
- "Transformer",
29183
- "Serializer",
29184
- "Validator",
29185
- "Strategy",
29186
- "Facade",
29187
- "Decorator",
29188
- "Observer",
29189
- "Builder",
29190
- "Command",
29191
- "Processor",
29192
- "Worker",
29193
- "Job"
29194
- ];
29195
- SERVICE_SUFFIX_GROUP5 = `(?:${SERVICE_SUFFIXES5.join("|")})`;
29196
- CPP_SERVICE_RE = new RegExp(
29197
- `^(?:public\\s+|private\\s+|protected\\s+|virtual\\s+|abstract\\s+|static\\s+|inline\\s+|constexpr\\s+|explicit\\s+|final\\s+|extern\\s+)*(?:class|struct)\\s+(\\w+?)${SERVICE_SUFFIX_GROUP5}?\\b`,
29198
- "gm"
29199
- );
29200
- CPP_CROW_ROUTE_RE = /CROW_ROUTE\s*\(\s*\w+\s*,\s*"(\/[^"]+)"/g;
29201
- CPP_DROGON_ROUTE_RE = /\.registerHandler\(\s*"(\/[^"]+)"[\s,)]|\.\b(?:get|post|put|delete|patch)\(\s*"(\/[^"]+)"/g;
29202
- CPP_PISTACHE_ROUTE_RE = /Routes::(?:get|post|put|delete|patch)\s*\(\s*[^,]+,\s*"(\/[^"]+)"/g;
29289
+ function firstIdentifier(node) {
29290
+ const text = node.text;
29291
+ const idMatch = text.match(/^([a-zA-Z_][a-zA-Z0-9_]*)/);
29292
+ return idMatch ? idMatch[1] : null;
29293
+ }
29294
+ function extractUse(node) {
29295
+ const text = node.text;
29296
+ const argument = node.namedChild(0);
29297
+ const argField = node.childForFieldName("argument");
29298
+ const path = argField?.text ?? argument?.text ?? "";
29299
+ const names = [];
29300
+ let isGlob = false;
29301
+ const useListNode = findUseListNode(argument);
29302
+ if (useListNode) {
29303
+ for (let i = 0; i < useListNode.namedChildCount; i++) {
29304
+ const item = useListNode.namedChild(i);
29305
+ if (item.type === "use_wildcard") {
29306
+ isGlob = true;
29307
+ } else if (item.type === "identifier") {
29308
+ names.push({ name: item.text });
29309
+ } else if (item.type === "use_as_clause") {
29310
+ const alias = item.childForFieldName("alias");
29311
+ const binding = item.childForFieldName("path");
29312
+ if (binding) {
29313
+ names.push({ name: binding.text, alias: alias?.text });
29314
+ } else {
29315
+ names.push({ name: item.text });
29316
+ }
29317
+ } else if (item.type === "scoped_identifier") {
29318
+ const idents = collectIdentifiers(item);
29319
+ names.push({ name: idents[idents.length - 1] ?? item.text });
29320
+ } else if (item.text.includes(" as ")) {
29321
+ const [head, alias] = item.text.split(/\s+as\s+/);
29322
+ names.push({ name: (head ?? "").trim(), alias: alias?.trim() });
29323
+ } else {
29324
+ names.push({ name: item.text });
29325
+ }
29326
+ }
29327
+ } else if (argument?.type === "use_wildcard") {
29328
+ isGlob = true;
29329
+ } else if (argument) {
29330
+ const idents = collectIdentifiers(argument);
29331
+ const last = idents[idents.length - 1] ?? argument.text;
29332
+ names.push({ name: last });
29333
+ const asMatch = text.match(/\s+as\s+(\w+)\s*;?\s*$/);
29334
+ if (asMatch) names[0].alias = asMatch[1];
29203
29335
  }
29204
- });
29205
-
29206
- // src/engine/visitors/java.ts
29207
- var java_exports = {};
29208
- __export(java_exports, {
29209
- extractJavaPatterns: () => extractJavaPatterns
29210
- });
29211
- function extractJavaPatterns(filePath, source) {
29212
- const service = [];
29213
- const route = [];
29214
- const ormModel = [];
29215
- const seenService = /* @__PURE__ */ new Set();
29216
- for (const m of source.matchAll(JAVA_SERVICE_RE)) {
29217
- const name = m[1];
29218
- if (seenService.has(name)) continue;
29219
- seenService.add(name);
29220
- service.push({ name, files: [filePath], imports: [] });
29336
+ return {
29337
+ path: path.trim(),
29338
+ names,
29339
+ isGlob,
29340
+ line: node.startPosition.row + 1,
29341
+ column: node.startPosition.column
29342
+ };
29343
+ }
29344
+ function extractFunction(node, attrs, inheritedTestConfig, isMethod) {
29345
+ const nameNode = node.childForFieldName("name");
29346
+ const name = nameNode?.text ?? "<anon>";
29347
+ const params = node.childForFieldName("parameters");
29348
+ const body = node.childForFieldName("body");
29349
+ const visibilityMod = node.namedChild(0);
29350
+ const isPublic = visibilityMod?.type === "visibility_modifier";
29351
+ let receiver;
29352
+ if (isMethod && params) {
29353
+ const selfParam = findSelfParameter(params);
29354
+ if (selfParam) receiver = selfParam.text;
29355
+ }
29356
+ const bodyLines = body ? body.endPosition.row - body.startPosition.row + 1 : 0;
29357
+ const inTestConfig = inheritedTestConfig || attrs.isTest || attrs.isTestCfg || isFunctionAttrTest(node);
29358
+ return {
29359
+ name,
29360
+ line: node.startPosition.row + 1,
29361
+ column: node.startPosition.column,
29362
+ isPublic,
29363
+ isMethod,
29364
+ receiver,
29365
+ bodyLines,
29366
+ inTestConfig
29367
+ };
29368
+ }
29369
+ function extractStruct(node, attrs) {
29370
+ const nameNode = node.childForFieldName("name");
29371
+ return {
29372
+ name: nameNode?.text ?? "<anon>",
29373
+ line: node.startPosition.row + 1,
29374
+ column: node.startPosition.column,
29375
+ isPublic: hasVisibility(node),
29376
+ isDerive: attrs.derives.length > 0,
29377
+ derives: [...attrs.derives]
29378
+ };
29379
+ }
29380
+ function extractTrait(node, _attrs) {
29381
+ const nameNode = node.childForFieldName("name");
29382
+ return {
29383
+ name: nameNode?.text ?? "<anon>",
29384
+ line: node.startPosition.row + 1,
29385
+ column: node.startPosition.column,
29386
+ isPublic: hasVisibility(node)
29387
+ };
29388
+ }
29389
+ function extractImpl(node, _attrs, _ctx) {
29390
+ const traitNode = node.childForFieldName("trait");
29391
+ const typeNode = node.childForFieldName("type");
29392
+ const typeText = typeNode?.text ?? "<anon>";
29393
+ const traitText = traitNode?.text;
29394
+ const body = node.childForFieldName("body");
29395
+ const methods = [];
29396
+ if (body) {
29397
+ for (let i = 0; i < body.namedChildCount; i++) {
29398
+ const child = body.namedChild(i);
29399
+ if (child?.type === "function_item") {
29400
+ const m = child.childForFieldName("name");
29401
+ if (m) methods.push(m.text);
29402
+ }
29403
+ }
29221
29404
  }
29222
- const seenRoute = /* @__PURE__ */ new Set();
29223
- for (const m of source.matchAll(JAVA_SPRING_ROUTE_RE)) {
29224
- const name = m[1];
29225
- if (seenRoute.has(name)) continue;
29226
- seenRoute.add(name);
29227
- route.push({ name, files: [filePath], imports: [] });
29405
+ return {
29406
+ entry: {
29407
+ type: typeText,
29408
+ trait: traitText ?? void 0,
29409
+ methods,
29410
+ line: node.startPosition.row + 1,
29411
+ column: node.startPosition.column
29412
+ }
29413
+ };
29414
+ }
29415
+ function findUseListNode(argument) {
29416
+ if (!argument) return null;
29417
+ if (argument.type === "use_list") return argument;
29418
+ if (argument.type === "scoped_use_list") {
29419
+ for (let i = 0; i < argument.namedChildCount; i++) {
29420
+ const c = argument.namedChild(i);
29421
+ if (c?.type === "use_list") return c;
29422
+ }
29228
29423
  }
29229
- for (const m of source.matchAll(JAVA_JAXRS_CLASS_PATH_RE)) {
29230
- const name = m[1];
29231
- if (name === "" || name === "/") continue;
29232
- if (seenRoute.has(name)) continue;
29233
- seenRoute.add(name);
29234
- route.push({ name, files: [filePath], imports: [] });
29424
+ return null;
29425
+ }
29426
+ function getField(node, fieldName) {
29427
+ return node.childForFieldName(fieldName);
29428
+ }
29429
+ function collectIdentifiers(node) {
29430
+ const out = [];
29431
+ for (let i = 0; i < node.namedChildCount; i++) {
29432
+ const child = node.namedChild(i);
29433
+ if (!child) continue;
29434
+ if (child.type === "identifier" || child.type === "type_identifier") {
29435
+ out.push(child.text);
29436
+ } else if (child.type === "scoped_identifier" || child.type === "nested_identifier") {
29437
+ out.push(...collectIdentifiers(child));
29438
+ }
29235
29439
  }
29236
- const seenOrm = /* @__PURE__ */ new Set();
29237
- for (const m of source.matchAll(JAVA_ORM_ANNOTATION_RE)) {
29238
- const name = m[1];
29239
- if (seenOrm.has(name)) continue;
29240
- seenOrm.add(name);
29241
- ormModel.push({ name, files: [filePath], imports: [] });
29440
+ return out;
29441
+ }
29442
+ function hasVisibility(node) {
29443
+ return node.namedChild(0)?.type === "visibility_modifier";
29444
+ }
29445
+ function isInImplBlock(node) {
29446
+ for (let p = node.parent; p; p = p.parent) {
29447
+ if (p.type === "impl_item") return true;
29448
+ if (p.type === "function_item" || p.type === "source_file") return false;
29242
29449
  }
29243
- for (const m of source.matchAll(JAVA_ORM_INHERIT_RE)) {
29244
- const name = m[1];
29245
- if (seenOrm.has(name)) continue;
29246
- seenOrm.add(name);
29247
- ormModel.push({ name, files: [filePath], imports: [] });
29450
+ return false;
29451
+ }
29452
+ function findSelfParameter(params) {
29453
+ for (let i = 0; i < params.namedChildCount; i++) {
29454
+ const child = params.namedChild(i);
29455
+ if (child?.type === "self_parameter") return child;
29248
29456
  }
29249
- return { service, route, ormModel };
29457
+ return null;
29250
29458
  }
29251
- var SERVICE_SUFFIXES6, SERVICE_SUFFIX_GROUP6, JAVA_SERVICE_RE, JAVA_SPRING_ROUTE_RE, JAVA_JAXRS_CLASS_PATH_RE, JAVA_ORM_ANNOTATION_RE, JAVA_ORM_INHERIT_RE;
29252
- var init_java = __esm({
29253
- "src/engine/visitors/java.ts"() {
29459
+ function isFunctionAttrTest(node) {
29460
+ void node;
29461
+ return false;
29462
+ }
29463
+ var SERVICE_SUFFIXES4, SERVICE_SUFFIX_GROUP4, RUST_SERVICE_STRUCT_RE, RUST_SERVICE_IMPL_RE, RUST_ACTIX_ROUTE_RE, RUST_AXUM_ROUTE_RE, RUST_DIESEL_RE, RUST_SEAORM_RE, RUST_SQLX_RE;
29464
+ var init_rust = __esm({
29465
+ "src/engine/visitors/rust.ts"() {
29254
29466
  "use strict";
29255
- SERVICE_SUFFIXES6 = [
29467
+ init_parser_rust();
29468
+ SERVICE_SUFFIXES4 = [
29469
+ "Service",
29470
+ "Manager",
29471
+ "Handler",
29472
+ "Repository",
29473
+ "Controller",
29474
+ "Helper",
29475
+ "Factory",
29476
+ "Provider",
29477
+ "Store",
29478
+ "API",
29479
+ "Client",
29480
+ "Adapter",
29481
+ "Resolver",
29482
+ "Mapper",
29483
+ "Transformer",
29484
+ "Serializer",
29485
+ "Validator",
29486
+ "Strategy",
29487
+ "Facade",
29488
+ "Decorator",
29489
+ "Observer",
29490
+ "Builder",
29491
+ "Command",
29492
+ "Processor",
29493
+ "Worker",
29494
+ "Job",
29495
+ "Actor",
29496
+ "Executor"
29497
+ ];
29498
+ SERVICE_SUFFIX_GROUP4 = `(?:${SERVICE_SUFFIXES4.join("|")})`;
29499
+ RUST_SERVICE_STRUCT_RE = new RegExp(
29500
+ `^(?:pub(?:\\(crate\\)|\\(super\\))?\\s+)?struct\\s+(\\w+?)${SERVICE_SUFFIX_GROUP4}?\\b`,
29501
+ "gm"
29502
+ );
29503
+ RUST_SERVICE_IMPL_RE = new RegExp(
29504
+ `^impl(?:<[^>]+>)?\\s+(?:${SERVICE_SUFFIX_GROUP4}\\s+for\\s+)?(\\w+?)${SERVICE_SUFFIX_GROUP4}?\\b`,
29505
+ "gm"
29506
+ );
29507
+ RUST_ACTIX_ROUTE_RE = /#\[(?:get|post|put|delete|patch|head|route)\(\s*"(\/[^"]+)"\s*[\),]/g;
29508
+ RUST_AXUM_ROUTE_RE = /\.route\(\s*"(\/[^"]+)"\s*,\s*(?:get|post|put|delete|patch)/g;
29509
+ RUST_DIESEL_RE = /#\[derive\([^\]]*Queryable[^\]]*\)\][\s\S]{0,200}?struct\s+(\w+)/g;
29510
+ RUST_SEAORM_RE = /#\[derive\([^\]]*DeriveEntityModel[^\]]*\)\][\s\S]{0,200}?struct\s+(\w+)/g;
29511
+ RUST_SQLX_RE = /#\[derive\([^\]]*sqlx::FromRow[^\]]*\)\][\s\S]{0,200}?struct\s+(\w+)/g;
29512
+ }
29513
+ });
29514
+
29515
+ // src/engine/visitors/cpp.ts
29516
+ var cpp_exports = {};
29517
+ __export(cpp_exports, {
29518
+ extractCppPatterns: () => extractCppPatterns
29519
+ });
29520
+ function extractCppPatterns(filePath, source) {
29521
+ const service = [];
29522
+ const route = [];
29523
+ const ormModel = [];
29524
+ const seenService = /* @__PURE__ */ new Set();
29525
+ for (const m of source.matchAll(CPP_SERVICE_RE)) {
29526
+ const name = m[1];
29527
+ if (seenService.has(name)) continue;
29528
+ seenService.add(name);
29529
+ service.push({ name, files: [filePath], imports: [] });
29530
+ }
29531
+ const seenRoute = /* @__PURE__ */ new Set();
29532
+ for (const m of source.matchAll(CPP_CROW_ROUTE_RE)) {
29533
+ const name = m[1];
29534
+ if (seenRoute.has(name)) continue;
29535
+ seenRoute.add(name);
29536
+ route.push({ name, files: [filePath], imports: [] });
29537
+ }
29538
+ for (const m of source.matchAll(CPP_DROGON_ROUTE_RE)) {
29539
+ const name = m[1] || m[2];
29540
+ if (!name) continue;
29541
+ if (seenRoute.has(name)) continue;
29542
+ seenRoute.add(name);
29543
+ route.push({ name, files: [filePath], imports: [] });
29544
+ }
29545
+ for (const m of source.matchAll(CPP_PISTACHE_ROUTE_RE)) {
29546
+ const name = m[1];
29547
+ if (seenRoute.has(name)) continue;
29548
+ seenRoute.add(name);
29549
+ route.push({ name, files: [filePath], imports: [] });
29550
+ }
29551
+ return { service, route, ormModel };
29552
+ }
29553
+ var SERVICE_SUFFIXES5, SERVICE_SUFFIX_GROUP5, CPP_SERVICE_RE, CPP_CROW_ROUTE_RE, CPP_DROGON_ROUTE_RE, CPP_PISTACHE_ROUTE_RE;
29554
+ var init_cpp = __esm({
29555
+ "src/engine/visitors/cpp.ts"() {
29556
+ "use strict";
29557
+ SERVICE_SUFFIXES5 = [
29558
+ "Service",
29559
+ "Manager",
29560
+ "Handler",
29561
+ "Repository",
29562
+ "Controller",
29563
+ "Helper",
29564
+ "Factory",
29565
+ "Provider",
29566
+ "Store",
29567
+ "API",
29568
+ "Client",
29569
+ "Adapter",
29570
+ "Resolver",
29571
+ "Mapper",
29572
+ "Transformer",
29573
+ "Serializer",
29574
+ "Validator",
29575
+ "Strategy",
29576
+ "Facade",
29577
+ "Decorator",
29578
+ "Observer",
29579
+ "Builder",
29580
+ "Command",
29581
+ "Processor",
29582
+ "Worker",
29583
+ "Job"
29584
+ ];
29585
+ SERVICE_SUFFIX_GROUP5 = `(?:${SERVICE_SUFFIXES5.join("|")})`;
29586
+ CPP_SERVICE_RE = new RegExp(
29587
+ `^(?:public\\s+|private\\s+|protected\\s+|virtual\\s+|abstract\\s+|static\\s+|inline\\s+|constexpr\\s+|explicit\\s+|final\\s+|extern\\s+)*(?:class|struct)\\s+(\\w+?)${SERVICE_SUFFIX_GROUP5}?\\b`,
29588
+ "gm"
29589
+ );
29590
+ CPP_CROW_ROUTE_RE = /CROW_ROUTE\s*\(\s*\w+\s*,\s*"(\/[^"]+)"/g;
29591
+ CPP_DROGON_ROUTE_RE = /\.registerHandler\(\s*"(\/[^"]+)"[\s,)]|\.\b(?:get|post|put|delete|patch)\(\s*"(\/[^"]+)"/g;
29592
+ CPP_PISTACHE_ROUTE_RE = /Routes::(?:get|post|put|delete|patch)\s*\(\s*[^,]+,\s*"(\/[^"]+)"/g;
29593
+ }
29594
+ });
29595
+
29596
+ // src/engine/visitors/java.ts
29597
+ var java_exports = {};
29598
+ __export(java_exports, {
29599
+ extractJavaPatterns: () => extractJavaPatterns
29600
+ });
29601
+ function extractJavaPatterns(filePath, source) {
29602
+ const service = [];
29603
+ const route = [];
29604
+ const ormModel = [];
29605
+ const seenService = /* @__PURE__ */ new Set();
29606
+ for (const m of source.matchAll(JAVA_SERVICE_RE)) {
29607
+ const name = m[1];
29608
+ if (seenService.has(name)) continue;
29609
+ seenService.add(name);
29610
+ service.push({ name, files: [filePath], imports: [] });
29611
+ }
29612
+ const seenRoute = /* @__PURE__ */ new Set();
29613
+ for (const m of source.matchAll(JAVA_SPRING_ROUTE_RE)) {
29614
+ const name = m[1];
29615
+ if (seenRoute.has(name)) continue;
29616
+ seenRoute.add(name);
29617
+ route.push({ name, files: [filePath], imports: [] });
29618
+ }
29619
+ for (const m of source.matchAll(JAVA_JAXRS_CLASS_PATH_RE)) {
29620
+ const name = m[1];
29621
+ if (name === "" || name === "/") continue;
29622
+ if (seenRoute.has(name)) continue;
29623
+ seenRoute.add(name);
29624
+ route.push({ name, files: [filePath], imports: [] });
29625
+ }
29626
+ const seenOrm = /* @__PURE__ */ new Set();
29627
+ for (const m of source.matchAll(JAVA_ORM_ANNOTATION_RE)) {
29628
+ const name = m[1];
29629
+ if (seenOrm.has(name)) continue;
29630
+ seenOrm.add(name);
29631
+ ormModel.push({ name, files: [filePath], imports: [] });
29632
+ }
29633
+ for (const m of source.matchAll(JAVA_ORM_INHERIT_RE)) {
29634
+ const name = m[1];
29635
+ if (seenOrm.has(name)) continue;
29636
+ seenOrm.add(name);
29637
+ ormModel.push({ name, files: [filePath], imports: [] });
29638
+ }
29639
+ return { service, route, ormModel };
29640
+ }
29641
+ var SERVICE_SUFFIXES6, SERVICE_SUFFIX_GROUP6, JAVA_SERVICE_RE, JAVA_SPRING_ROUTE_RE, JAVA_JAXRS_CLASS_PATH_RE, JAVA_ORM_ANNOTATION_RE, JAVA_ORM_INHERIT_RE;
29642
+ var init_java = __esm({
29643
+ "src/engine/visitors/java.ts"() {
29644
+ "use strict";
29645
+ SERVICE_SUFFIXES6 = [
29256
29646
  "Service",
29257
29647
  "Manager",
29258
29648
  "Handler",
@@ -29765,6 +30155,9 @@ var init_expired_code_example = __esm({
29765
30155
  const issues = [];
29766
30156
  const source = facts.v2?._source;
29767
30157
  if (!source) return issues;
30158
+ const packages = declaredPackages(context.cwd);
30159
+ const packageName = context.packageName;
30160
+ if (packageName) packages.add(packageName);
29768
30161
  const blocks = extractFencedCodeBlocks(source);
29769
30162
  for (const block of blocks) {
29770
30163
  if (!CODE_LANGS.has(block.lang)) continue;
@@ -29772,7 +30165,7 @@ var init_expired_code_example = __esm({
29772
30165
  const imports = extractImports(block.body);
29773
30166
  for (const imp of imports) {
29774
30167
  const pkgName = stripSubpath(imp);
29775
- if (context.packages.has(pkgName)) continue;
30168
+ if (packages.has(pkgName)) continue;
29776
30169
  issues.push({
29777
30170
  ruleId: "docs/expired-code-example",
29778
30171
  category: "docs",
@@ -29825,7 +30218,12 @@ function collectExports(cwd) {
29825
30218
  /\bexport\s+class\s+([A-Za-z_$][\w$]*)/g,
29826
30219
  /\bexport\s+interface\s+([A-Za-z_$][\w$]*)/g,
29827
30220
  /\bexport\s+type\s+([A-Za-z_$][\w$]*)/g,
29828
- /\bexport\s+default\s+(?:function\s+|class\s+)?([A-Za-z_$][\w$]*)/g
30221
+ /\bexport\s+default\s+(?:function\s+|class\s+)?([A-Za-z_$][\w$]*)/g,
30222
+ // v0.18.6: also collect field names from `export interface` and
30223
+ // `export type` declarations. Without this, fields like
30224
+ // `crossFileDrift`, `aiQuality`, `engineeringHygiene` are
30225
+ // flagged as stale even though they're valid type fields.
30226
+ /^\s*(?:readonly\s+)?([A-Za-z_$][\w$]*)\s*[?:]/gm
29829
30227
  ]) {
29830
30228
  let m;
29831
30229
  while ((m = re.exec(source)) !== null) {
@@ -29836,6 +30234,21 @@ function collectExports(cwd) {
29836
30234
  }
29837
30235
  return out;
29838
30236
  }
30237
+ function looksLikeProseLabel(inside) {
30238
+ const trimmed = inside.trim();
30239
+ if (trimmed.length === 0) return false;
30240
+ if (trimmed.startsWith("`") || trimmed.startsWith("/")) return true;
30241
+ if (trimmed.includes("`")) return true;
30242
+ if (/\d+\s+[a-z]/i.test(trimmed)) return true;
30243
+ const parts = trimmed.split(",").map((s) => s.trim());
30244
+ if (parts.length >= 3) {
30245
+ const allNumeric = parts.every((p) => /^\d+\.?\d*$/.test(p));
30246
+ if (!allNumeric) return true;
30247
+ }
30248
+ if (trimmed.length > 40 && !trimmed.includes(",")) return true;
30249
+ if (trimmed.includes("\u2014") || trimmed.includes("\u2013")) return true;
30250
+ return false;
30251
+ }
29839
30252
  var import_node_fs7, import_node_path7, RESERVED, SOURCE_EXTS, SOURCE_ROOTS, CAP, staleFunctionReferenceRule;
29840
30253
  var init_stale_function_reference = __esm({
29841
30254
  "src/rules/docs/stale-function-reference.ts"() {
@@ -29845,6 +30258,7 @@ var init_stale_function_reference = __esm({
29845
30258
  init_rule();
29846
30259
  init_doc_freshness();
29847
30260
  RESERVED = /* @__PURE__ */ new Set([
30261
+ // JS reserved words
29848
30262
  "true",
29849
30263
  "false",
29850
30264
  "null",
@@ -29944,7 +30358,472 @@ var init_stale_function_reference = __esm({
29944
30358
  "next",
29945
30359
  "vue",
29946
30360
  "angular",
29947
- "svelte"
30361
+ "svelte",
30362
+ // Framework / runtime names
30363
+ "html",
30364
+ "astro",
30365
+ "python",
30366
+ "jvm",
30367
+ "kotlin",
30368
+ "swift",
30369
+ "dart",
30370
+ "ruby",
30371
+ "rust",
30372
+ "cpp",
30373
+ "go",
30374
+ "java",
30375
+ "php",
30376
+ "php-html",
30377
+ "csharp",
30378
+ "typescript",
30379
+ "javascript",
30380
+ "jsx",
30381
+ "tsx",
30382
+ "mjs",
30383
+ "cjs",
30384
+ "esnext",
30385
+ "es6",
30386
+ "es2022",
30387
+ "es2023",
30388
+ "esm",
30389
+ "cjs",
30390
+ "umd",
30391
+ "amd",
30392
+ "commonjs",
30393
+ "require",
30394
+ "module",
30395
+ "exports",
30396
+ "define",
30397
+ "global",
30398
+ "window",
30399
+ "document",
30400
+ "process",
30401
+ "console",
30402
+ "buffer",
30403
+ "stream",
30404
+ "fetch",
30405
+ "axios",
30406
+ "express",
30407
+ "fastify",
30408
+ "koa",
30409
+ "hapi",
30410
+ "nextjs",
30411
+ "nuxt",
30412
+ "remix",
30413
+ "gatsby",
30414
+ "sveltekit",
30415
+ "solid",
30416
+ "preact",
30417
+ "qwik",
30418
+ "lit",
30419
+ "stencil",
30420
+ "marko",
30421
+ "alpine",
30422
+ "stimulus",
30423
+ "turbo",
30424
+ "hotwire",
30425
+ // Models / providers
30426
+ "gpt",
30427
+ "claude",
30428
+ "gpt-3",
30429
+ "gpt-3.5",
30430
+ "gpt-4",
30431
+ "gpt-oss",
30432
+ "haiku",
30433
+ "sonnet",
30434
+ "opus",
30435
+ "aider",
30436
+ "tabby",
30437
+ "copilot",
30438
+ "cursor",
30439
+ "windsurf",
30440
+ "devin",
30441
+ "claude-code",
30442
+ // LLM-detection lingo
30443
+ "heuristic",
30444
+ "heuristics",
30445
+ "calibrate",
30446
+ "calibration",
30447
+ "calibrator",
30448
+ "corpus",
30449
+ "baseline",
30450
+ "baselines",
30451
+ "corpus-baselines",
30452
+ "lift",
30453
+ "recall",
30454
+ "precision",
30455
+ "fpRate",
30456
+ "ratio",
30457
+ "verdict",
30458
+ "USEFUL",
30459
+ "NOISY",
30460
+ "INVERTED",
30461
+ "HYGIENE",
30462
+ "DORMANT",
30463
+ "OK",
30464
+ "aiSpecific",
30465
+ "defaultOff",
30466
+ // Common slop-audit verbs/nouns
30467
+ "commit",
30468
+ "push",
30469
+ "reset",
30470
+ "rebase",
30471
+ "merge",
30472
+ "cherry-pick",
30473
+ "revert",
30474
+ "scan",
30475
+ "parse",
30476
+ "build",
30477
+ "test",
30478
+ "lint",
30479
+ "format",
30480
+ "check",
30481
+ "audit",
30482
+ "fix",
30483
+ "patch",
30484
+ "diff",
30485
+ "pr",
30486
+ "ci",
30487
+ "cd",
30488
+ "gh",
30489
+ "npm",
30490
+ "npx",
30491
+ "pnpm",
30492
+ "yaml",
30493
+ "json",
30494
+ "toml",
30495
+ "csv",
30496
+ "md",
30497
+ "mdx",
30498
+ "sh",
30499
+ "bash",
30500
+ "zsh",
30501
+ "fish",
30502
+ "ascii",
30503
+ "utf8",
30504
+ "utf-8",
30505
+ "base64",
30506
+ "hex",
30507
+ "binary",
30508
+ "text",
30509
+ // Common design / ui terms
30510
+ "flex",
30511
+ "grid",
30512
+ "auto",
30513
+ "min",
30514
+ "max",
30515
+ "fill",
30516
+ "stretch",
30517
+ "wrap",
30518
+ "nowrap",
30519
+ "inline",
30520
+ "block",
30521
+ "hidden",
30522
+ "visible",
30523
+ "static",
30524
+ "fixed",
30525
+ "absolute",
30526
+ "relative",
30527
+ "sticky",
30528
+ "pointer",
30529
+ "cursor",
30530
+ "focus",
30531
+ "hover",
30532
+ "active",
30533
+ "disabled",
30534
+ "readonly",
30535
+ "primary",
30536
+ "secondary",
30537
+ "tertiary",
30538
+ "success",
30539
+ "warning",
30540
+ "danger",
30541
+ "info",
30542
+ "muted",
30543
+ "sm",
30544
+ "md",
30545
+ "lg",
30546
+ "xl",
30547
+ "xxl",
30548
+ "xs",
30549
+ "2xl",
30550
+ "3xl",
30551
+ "4xl",
30552
+ // Math / types
30553
+ "array",
30554
+ "map",
30555
+ "set",
30556
+ "weakmap",
30557
+ "weakset",
30558
+ "object",
30559
+ "string",
30560
+ "number",
30561
+ "boolean",
30562
+ "bigint",
30563
+ "symbol",
30564
+ "null",
30565
+ "undefined",
30566
+ "any",
30567
+ "unknown",
30568
+ "never",
30569
+ "void",
30570
+ "readonly",
30571
+ "private",
30572
+ "public",
30573
+ "protected",
30574
+ "static",
30575
+ "abstract",
30576
+ "async",
30577
+ "generator",
30578
+ "iterator",
30579
+ "iterable",
30580
+ "promise",
30581
+ "observable",
30582
+ // Auth / domain
30583
+ "admin",
30584
+ "user",
30585
+ "guest",
30586
+ "anonymous",
30587
+ "authenticated",
30588
+ "unauthenticated",
30589
+ "jwt",
30590
+ "oauth",
30591
+ "oidc",
30592
+ "saml",
30593
+ "csrf",
30594
+ "xss",
30595
+ "sql",
30596
+ "nosql",
30597
+ "orm",
30598
+ "prisma",
30599
+ "drizzle",
30600
+ "sequelize",
30601
+ "mongoose",
30602
+ "redis",
30603
+ "postgres",
30604
+ "mysql",
30605
+ "sqlite",
30606
+ "kafka",
30607
+ "rabbitmq",
30608
+ "graphql",
30609
+ "rest",
30610
+ "grpc",
30611
+ "websocket",
30612
+ // slop-audit specific
30613
+ "slopbrick",
30614
+ "usebrick",
30615
+ "deadcode",
30616
+ "unused",
30617
+ "orphan",
30618
+ "zombie",
30619
+ "blocker",
30620
+ "warning",
30621
+ "info",
30622
+ "error",
30623
+ "verbose",
30624
+ "debug",
30625
+ "silly",
30626
+ "p50",
30627
+ "p90",
30628
+ "p95",
30629
+ "p99",
30630
+ "min",
30631
+ "max",
30632
+ "avg",
30633
+ "mean",
30634
+ "median",
30635
+ "ratchet",
30636
+ "tier",
30637
+ "composite",
30638
+ "fitness",
30639
+ "fpr",
30640
+ "tpr",
30641
+ "roc",
30642
+ "should",
30643
+ "could",
30644
+ "would",
30645
+ "might",
30646
+ "must",
30647
+ "shall",
30648
+ "may",
30649
+ "can",
30650
+ "todo",
30651
+ "fixme",
30652
+ "xxx",
30653
+ "hack",
30654
+ "note",
30655
+ "warning",
30656
+ "attention",
30657
+ "h1",
30658
+ "h2",
30659
+ "h3",
30660
+ "h4",
30661
+ "h5",
30662
+ "h6",
30663
+ "strong",
30664
+ "em",
30665
+ "b",
30666
+ "i",
30667
+ "u",
30668
+ "true",
30669
+ "false",
30670
+ "yes",
30671
+ "no",
30672
+ "on",
30673
+ "off",
30674
+ "enable",
30675
+ "disable",
30676
+ "ltr",
30677
+ "rtl",
30678
+ "auto",
30679
+ "start",
30680
+ "end",
30681
+ "center",
30682
+ "baseline",
30683
+ "stretch",
30684
+ "rounded",
30685
+ "sharp",
30686
+ "outline",
30687
+ "ghost",
30688
+ "link",
30689
+ "filled",
30690
+ "row",
30691
+ "col",
30692
+ "gap",
30693
+ "pad",
30694
+ "margin",
30695
+ "padding",
30696
+ "border",
30697
+ "shadow",
30698
+ "transparent",
30699
+ "currentcolor",
30700
+ "inherit",
30701
+ "initial",
30702
+ "unset",
30703
+ "revert",
30704
+ "hover",
30705
+ "focus",
30706
+ "active",
30707
+ "disabled",
30708
+ "checked",
30709
+ "indeterminate",
30710
+ "open",
30711
+ "close",
30712
+ "expanded",
30713
+ "collapsed",
30714
+ "selected",
30715
+ "pressed",
30716
+ // Web/CSS
30717
+ "div",
30718
+ "span",
30719
+ "p",
30720
+ "a",
30721
+ "img",
30722
+ "ul",
30723
+ "ol",
30724
+ "li",
30725
+ "table",
30726
+ "tr",
30727
+ "td",
30728
+ "th",
30729
+ "thead",
30730
+ "tbody",
30731
+ "tfoot",
30732
+ "caption",
30733
+ "figure",
30734
+ "figcaption",
30735
+ "main",
30736
+ "section",
30737
+ "article",
30738
+ "aside",
30739
+ "header",
30740
+ "footer",
30741
+ "nav",
30742
+ "form",
30743
+ "input",
30744
+ "button",
30745
+ "select",
30746
+ "option",
30747
+ "textarea",
30748
+ "label",
30749
+ "fieldset",
30750
+ "legend",
30751
+ "details",
30752
+ "summary",
30753
+ "dialog",
30754
+ "menu",
30755
+ "menuitem",
30756
+ "template",
30757
+ "slot",
30758
+ "picture",
30759
+ "source",
30760
+ "track",
30761
+ "video",
30762
+ "audio",
30763
+ "canvas",
30764
+ "svg",
30765
+ "iframe",
30766
+ "embed",
30767
+ "object",
30768
+ "portal",
30769
+ // Common business terms
30770
+ "api",
30771
+ "cli",
30772
+ "ui",
30773
+ "ux",
30774
+ "sdk",
30775
+ "ide",
30776
+ "cli",
30777
+ "docs",
30778
+ "doc",
30779
+ "blog",
30780
+ "post",
30781
+ "page",
30782
+ "view",
30783
+ "tab",
30784
+ "panel",
30785
+ "card",
30786
+ "list",
30787
+ "grid",
30788
+ "form",
30789
+ "modal",
30790
+ "menu",
30791
+ "button",
30792
+ "icon",
30793
+ "avatar",
30794
+ "badge",
30795
+ "chip",
30796
+ "tooltip",
30797
+ "popover",
30798
+ "dropdown",
30799
+ "banner",
30800
+ "alert",
30801
+ "toast",
30802
+ "notification",
30803
+ "drawer",
30804
+ "sidebar",
30805
+ "navbar",
30806
+ "header",
30807
+ "footer",
30808
+ "hero",
30809
+ "cta",
30810
+ "cta-primary",
30811
+ "cta-secondary",
30812
+ "pricing",
30813
+ "price",
30814
+ "cost",
30815
+ "rate",
30816
+ "percent",
30817
+ "pct",
30818
+ "count",
30819
+ "total",
30820
+ "small",
30821
+ "medium",
30822
+ "large",
30823
+ "xl",
30824
+ "xxl",
30825
+ "tiny",
30826
+ "huge"
29948
30827
  ]);
29949
30828
  SOURCE_EXTS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
29950
30829
  SOURCE_ROOTS = ["src", "lib", "app", "components"];
@@ -29968,8 +30847,39 @@ var init_stale_function_reference = __esm({
29968
30847
  if (text.length < 3) continue;
29969
30848
  if (RESERVED.has(text.toLowerCase())) continue;
29970
30849
  if (context.exports.has(text)) continue;
29971
- const end = Math.min(source.length, span.index + text.length + 50);
29972
- if (!/\(/.test(source.slice(span.index, end))) continue;
30850
+ const lineEnd = source.indexOf("\n", span.index);
30851
+ const restOfLine = source.slice(
30852
+ span.index,
30853
+ lineEnd === -1 ? source.length : lineEnd
30854
+ );
30855
+ const closeTick = restOfLine.indexOf("`", 1);
30856
+ if (closeTick === -1) continue;
30857
+ const afterTick = restOfLine.slice(closeTick + 1);
30858
+ const directCall = /^\s*\(/.test(afterTick);
30859
+ let identifierRepeats = false;
30860
+ if (!directCall) {
30861
+ const afterSpan = restOfLine.slice(closeTick + 1);
30862
+ const needle = text + "(";
30863
+ identifierRepeats = afterSpan.indexOf(needle) !== -1;
30864
+ }
30865
+ if (!directCall && !identifierRepeats) continue;
30866
+ const beforeTickIdx = span.index - 1;
30867
+ const beforeChar = beforeTickIdx >= 0 ? source[beforeTickIdx] : "";
30868
+ if (beforeChar === "." || beforeChar === "|") continue;
30869
+ const parenStart = restOfLine.indexOf("(", closeTick);
30870
+ const parenEnd = restOfLine.indexOf(")", parenStart);
30871
+ if (parenStart !== -1 && parenEnd !== -1) {
30872
+ const inside = restOfLine.slice(parenStart + 1, parenEnd);
30873
+ const trimmed = inside.trim();
30874
+ if (looksLikeProseLabel(inside)) continue;
30875
+ 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(
30876
+ inside
30877
+ ) || // Short single-word label (≤ 24 chars, no `,`,
30878
+ // doesn't look like a function arg). Real function
30879
+ // calls are usually longer or contain commas.
30880
+ trimmed.length > 0 && trimmed.length <= 24 && !trimmed.includes(",") && /[a-zA-Z]/.test(trimmed));
30881
+ if (looksLikeTypeAnnotation) continue;
30882
+ }
29973
30883
  issues.push({
29974
30884
  ruleId: "docs/stale-function-reference",
29975
30885
  category: "docs",
@@ -30049,7 +30959,33 @@ var init_stale_package_reference = __esm({
30049
30959
  "jsx",
30050
30960
  "ok",
30051
30961
  "no",
30052
- "yes"
30962
+ "yes",
30963
+ // v0.18.6: common English adjectives / adverbs that frequently
30964
+ // appear in backticked prose but are not package names.
30965
+ "aspirational",
30966
+ "concrete",
30967
+ "abstract",
30968
+ "inline",
30969
+ "exposed",
30970
+ "deprecated",
30971
+ "experimental",
30972
+ "stable",
30973
+ "beta",
30974
+ "alpha",
30975
+ "wip",
30976
+ "draft",
30977
+ "final",
30978
+ "shim",
30979
+ "polyfill",
30980
+ "stub",
30981
+ "mock",
30982
+ "fake",
30983
+ "real",
30984
+ "false",
30985
+ "true",
30986
+ "optional",
30987
+ "required",
30988
+ "default"
30053
30989
  ]);
30054
30990
  stalePackageReferenceRule = createRule({
30055
30991
  id: "docs/stale-package-reference",
@@ -30271,7 +31207,15 @@ async function buildDocFreshness(cwd, config, options = {}) {
30271
31207
  continue;
30272
31208
  }
30273
31209
  const relPath = (0, import_node_path8.relative)(cwd, abs);
30274
- const context = { config, filePath: relPath, cwd };
31210
+ let packageName;
31211
+ try {
31212
+ const pkg = JSON.parse(
31213
+ (0, import_node_fs8.readFileSync)((0, import_node_path8.join)(cwd, "package.json"), "utf-8")
31214
+ );
31215
+ packageName = pkg.name;
31216
+ } catch {
31217
+ }
31218
+ const context = { config, filePath: relPath, cwd, packageName };
30275
31219
  const facts = { filePath: relPath, v2: { _source: source } };
30276
31220
  const ruleConfigs = [
30277
31221
  { rule: stalePackageReferenceRule, ruleId: "docs/stale-package-reference" },
@@ -30387,7 +31331,9 @@ var init_broken_link = __esm({
30387
31331
  if (target.startsWith("#")) continue;
30388
31332
  if (target.startsWith("//")) continue;
30389
31333
  if (target.startsWith("/")) continue;
30390
- const resolved = (0, import_node_path9.join)(docDir, target);
31334
+ const filePart = target.split("#")[0] ?? target;
31335
+ if (filePart === "") continue;
31336
+ const resolved = (0, import_node_path9.join)(docDir, filePart);
30391
31337
  if ((0, import_node_fs9.existsSync)(resolved)) continue;
30392
31338
  issues.push({
30393
31339
  ruleId: "docs/broken-link",
@@ -35504,7 +36450,7 @@ function parseBlankModule(source) {
35504
36450
  tsx: false,
35505
36451
  target: "es2022"
35506
36452
  });
35507
- return { ast, source: replaced };
36453
+ return { ast, source };
35508
36454
  }
35509
36455
  function parseScriptContent(content, isTypeScript) {
35510
36456
  if (isTypeScript) {
@@ -35590,8 +36536,16 @@ function parseSource(source, filePath) {
35590
36536
  // but no SWC support. Return a blank-padded empty module so
35591
36537
  // regex-only rules can still fire (markdown-leakage, comment-
35592
36538
  // ratio, etc.) without burning the parseError path.
36539
+ // v0.18.9: `.rs` is in the same bucket. The visitor layer
36540
+ // (`engine/visitors/rust.ts`) carries the tree-sitter-backed
36541
+ // parse + extractFacts attaches the result to `facts.v2.rustFile`.
36542
+ // The rule layer (`rules/rust/*.ts`) reads that field. parseBlankModule
36543
+ // lets the worker continue past the parser — without this, parseWithSwc
36544
+ // would throw on every .rs file, the worker would count it as a
36545
+ // parseError, and the v2-build's buildRustFileRecord would never run.
35593
36546
  case "py":
35594
36547
  case "go":
36548
+ case "rs":
35595
36549
  return parseBlankModule(source);
35596
36550
  default:
35597
36551
  return parseWithSwc(source, filePath);
@@ -38778,6 +39732,354 @@ var init_ux_pattern_fragmentation = __esm({
38778
39732
  }
38779
39733
  });
38780
39734
 
39735
+ // src/rules/rust/stringly-typed.ts
39736
+ function collectEnumCandidates(source) {
39737
+ const out = [];
39738
+ const enumRe = /^(?:pub(?:\([^)]+\))?\s+)?enum\s+(\w+)\s*\{([^}]*)\}/gm;
39739
+ for (const m of source.matchAll(enumRe)) {
39740
+ const body = m[2] ?? "";
39741
+ const variants = body.split(/,(?![^()]*\))/).map((s) => s.trim()).filter((s) => /^[A-Za-z_][A-Za-z0-9_]*$/.test(s.split(/\s+/)[0] ?? ""));
39742
+ if (variants.length > MAX_VARIANT_COUNT) continue;
39743
+ if (variants.length < 2) continue;
39744
+ out.push({ name: m[1], variantCount: variants.length, line: lineOfMatch(source, m.index ?? 0) });
39745
+ }
39746
+ return out;
39747
+ }
39748
+ function lineOfMatch(source, index) {
39749
+ let line = 1;
39750
+ for (let i = 0; i < index && i < source.length; i++) {
39751
+ if (source[i] === "\n") line++;
39752
+ }
39753
+ return line;
39754
+ }
39755
+ function buildLineOffsets(source) {
39756
+ const out = [0];
39757
+ for (let i = 0; i < source.length; i++) {
39758
+ if (source[i] === "\n") out.push(i + 1);
39759
+ }
39760
+ return out;
39761
+ }
39762
+ function extractParameterText(source, lineOffsets, fn) {
39763
+ const start = lineOffsets[Math.max(0, fn.line - 1)] ?? 0;
39764
+ const head = source.slice(start, start + 400);
39765
+ const openIdx = head.indexOf("(");
39766
+ if (openIdx < 0) return "";
39767
+ let closeIdx = -1;
39768
+ let depth = 0;
39769
+ for (let i = openIdx; i < head.length; i++) {
39770
+ if (head[i] === "(") depth++;
39771
+ else if (head[i] === ")") {
39772
+ depth--;
39773
+ if (depth === 0) {
39774
+ closeIdx = i;
39775
+ break;
39776
+ }
39777
+ }
39778
+ }
39779
+ if (closeIdx < 0) return "";
39780
+ return head.slice(openIdx + 1, closeIdx);
39781
+ }
39782
+ function scanForStringlyParams(paramText) {
39783
+ const out = [];
39784
+ for (const m of paramText.matchAll(
39785
+ /\b([a-z_][a-zA-Z0-9_]*)\s*:\s*(&\s*(?:mut\s+)?(?:str|String)\b)/g
39786
+ )) {
39787
+ const name = m[1];
39788
+ const type = m[2];
39789
+ if (!SUSPECT_PARAM_NAMES.has(name)) continue;
39790
+ out.push({ name, type });
39791
+ }
39792
+ return out;
39793
+ }
39794
+ var SUSPECT_PARAM_NAMES, MAX_VARIANT_COUNT, rustStringlyTypedRule;
39795
+ var init_stringly_typed = __esm({
39796
+ "src/rules/rust/stringly-typed.ts"() {
39797
+ "use strict";
39798
+ init_rule();
39799
+ SUSPECT_PARAM_NAMES = /* @__PURE__ */ new Set([
39800
+ "kind",
39801
+ "type",
39802
+ "mode",
39803
+ "event",
39804
+ "status",
39805
+ "category",
39806
+ "action",
39807
+ "state",
39808
+ "level",
39809
+ "role",
39810
+ "tier",
39811
+ "phase",
39812
+ "tag",
39813
+ "format",
39814
+ "shape",
39815
+ "direction",
39816
+ "side",
39817
+ "method"
39818
+ ]);
39819
+ MAX_VARIANT_COUNT = 32;
39820
+ rustStringlyTypedRule = createRule({
39821
+ id: "rust/stringly-typed",
39822
+ category: "logic",
39823
+ severity: "medium",
39824
+ aiSpecific: true,
39825
+ description: "String / &str parameter where a typed enum exists in the same file",
39826
+ create(_context) {
39827
+ return {};
39828
+ },
39829
+ analyze(_context, facts) {
39830
+ const issues = [];
39831
+ if (!facts.v2?.rustFile) return issues;
39832
+ const source = facts.v2._source ?? "";
39833
+ if (!source) return issues;
39834
+ const lineOffsets = buildLineOffsets(source);
39835
+ const enumCandidates = collectEnumCandidates(source);
39836
+ if (enumCandidates.length === 0) return issues;
39837
+ for (const fn of facts.v2.rustFile.functions) {
39838
+ const paramText = extractParameterText(source, lineOffsets, fn);
39839
+ if (!paramText) continue;
39840
+ const matches = scanForStringlyParams(paramText);
39841
+ if (matches.length === 0) continue;
39842
+ issues.push({
39843
+ ruleId: "rust/stringly-typed",
39844
+ category: "logic",
39845
+ severity: "medium",
39846
+ aiSpecific: true,
39847
+ message: matches.length === 1 ? `Parameter '${matches[0].name}' typed as '${matches[0].type}', but enum ${enumCandidates[0].name} exists in the file` : `Function has ${matches.length} stringly-typed parameters; enum ${enumCandidates[0].name} exists in the file`,
39848
+ line: fn.line,
39849
+ column: fn.column,
39850
+ advice: `Replace the String/&str parameter with the typed enum. Stringly-typed APIs lose type information at the boundary; a typo ('Click' vs 'click') only fails at runtime. AI agents introduce these during exploratory scaffolding, then never replace them with the existing enum.`
39851
+ });
39852
+ }
39853
+ return issues;
39854
+ }
39855
+ });
39856
+ }
39857
+ });
39858
+
39859
+ // src/rules/rust/todo-macro.ts
39860
+ function collectMacroIssues(node, testScopes, issues) {
39861
+ if (node.type === "macro_invocation") {
39862
+ const text = node.text;
39863
+ const m = text.match(/^([A-Za-z_][A-Za-z0-9_]*)/);
39864
+ const macroName = m?.[1] ?? "";
39865
+ if (TODO_MACROS.has(macroName)) {
39866
+ if (!isInsideMacroDefinition(node) && !isInsideTestFunction(node, testScopes)) {
39867
+ issues.push({
39868
+ ruleId: "rust/todo-macro",
39869
+ category: "logic",
39870
+ severity: "medium",
39871
+ aiSpecific: true,
39872
+ message: `'${macroName}!()' in production code \u2014 both expand to panic!()`,
39873
+ line: node.startPosition.row + 1,
39874
+ column: node.startPosition.column,
39875
+ advice: `Implement the function body or remove the stub. '${macroName}!()' is fine in test scaffolding (#[cfg(test)]); here it is a panic risk. AI agents commonly leave these behind after iterative refactors when the placeholder branch is never filled in.`
39876
+ });
39877
+ }
39878
+ }
39879
+ }
39880
+ for (let i = 0; i < node.namedChildCount; i++) {
39881
+ const child = node.namedChild(i);
39882
+ if (child) collectMacroIssues(child, testScopes, issues);
39883
+ }
39884
+ }
39885
+ function isInsideMacroDefinition(node) {
39886
+ for (let p = node.parent; p; p = p.parent) {
39887
+ if (p.type === "macro_definition") return true;
39888
+ if (p.type === "source_file") return false;
39889
+ }
39890
+ return false;
39891
+ }
39892
+ function isInsideTestFunction(node, testScopes) {
39893
+ for (let p = node.parent; p; p = p.parent) {
39894
+ if (p.type === "function_item") {
39895
+ const nameField = p.childForFieldName("name");
39896
+ const name = nameField?.text;
39897
+ if (name && testScopes.has(name)) return true;
39898
+ if (p.text.startsWith("#[test]") || p.text.startsWith("#[cfg(test)]")) return true;
39899
+ return false;
39900
+ }
39901
+ if (p.type === "source_file") return false;
39902
+ }
39903
+ return false;
39904
+ }
39905
+ var TODO_MACROS, rustTodoMacroRule;
39906
+ var init_todo_macro = __esm({
39907
+ "src/rules/rust/todo-macro.ts"() {
39908
+ "use strict";
39909
+ init_rule();
39910
+ init_parser_rust();
39911
+ TODO_MACROS = /* @__PURE__ */ new Set(["todo", "unimplemented", "todo_unimplemented"]);
39912
+ rustTodoMacroRule = createRule({
39913
+ id: "rust/todo-macro",
39914
+ category: "logic",
39915
+ severity: "medium",
39916
+ aiSpecific: true,
39917
+ description: "todo!() / unimplemented!() macro invocation in production code",
39918
+ create(_context) {
39919
+ return {};
39920
+ },
39921
+ analyze(_context, facts) {
39922
+ const issues = [];
39923
+ if (!facts.v2?.rustFile) return issues;
39924
+ const source = facts.v2._source ?? "";
39925
+ if (!source) return issues;
39926
+ const tree = parseRust(source);
39927
+ if (!tree) return issues;
39928
+ const testScopes = /* @__PURE__ */ new Set();
39929
+ for (const fn of facts.v2.rustFile.functions) {
39930
+ if (fn.inTestConfig && fn.name) testScopes.add(fn.name);
39931
+ }
39932
+ collectMacroIssues(tree.rootNode, testScopes, issues);
39933
+ return issues;
39934
+ }
39935
+ });
39936
+ }
39937
+ });
39938
+
39939
+ // src/rules/rust/unused-pub-fn.ts
39940
+ function collectReferencedNames(source) {
39941
+ const out = /* @__PURE__ */ new Set();
39942
+ for (const m of source.matchAll(/\b([A-Za-z_][A-Za-z0-9_]*)\b/g)) {
39943
+ out.add(m[1]);
39944
+ }
39945
+ return out;
39946
+ }
39947
+ var API_CONVENTION_NAMES, rustUnusedPubFnRule;
39948
+ var init_unused_pub_fn = __esm({
39949
+ "src/rules/rust/unused-pub-fn.ts"() {
39950
+ "use strict";
39951
+ init_rule();
39952
+ API_CONVENTION_NAMES = /* @__PURE__ */ new Set([
39953
+ "new",
39954
+ "default",
39955
+ "from",
39956
+ "from_str",
39957
+ "from_iter",
39958
+ "try_from",
39959
+ "into",
39960
+ "into_iter",
39961
+ "try_into",
39962
+ "as_ref",
39963
+ "as_mut",
39964
+ "clone",
39965
+ "fmt",
39966
+ "eq",
39967
+ "hash",
39968
+ "partial_cmp",
39969
+ "cmp",
39970
+ "ord",
39971
+ "partial_eq"
39972
+ ]);
39973
+ rustUnusedPubFnRule = createRule({
39974
+ id: "rust/unused-pub-fn",
39975
+ category: "logic",
39976
+ severity: "low",
39977
+ aiSpecific: true,
39978
+ description: "Public function in a Rust file that has no in-file references",
39979
+ create(_context) {
39980
+ return {};
39981
+ },
39982
+ analyze(_context, facts) {
39983
+ const issues = [];
39984
+ if (!facts.v2?.rustFile) return issues;
39985
+ const rust = facts.v2.rustFile;
39986
+ const referenced = collectReferencedNames(facts.v2._source ?? "");
39987
+ for (const fn of rust.functions) {
39988
+ if (!fn.isPublic) continue;
39989
+ if (API_CONVENTION_NAMES.has(fn.name)) continue;
39990
+ if (fn.inTestConfig) continue;
39991
+ if (referenced.has(fn.name)) continue;
39992
+ issues.push({
39993
+ ruleId: "rust/unused-pub-fn",
39994
+ category: "logic",
39995
+ severity: "low",
39996
+ aiSpecific: true,
39997
+ message: `Public function '${fn.name}' is not referenced anywhere in the file`,
39998
+ line: fn.line,
39999
+ column: fn.column,
40000
+ advice: `Remove the function or call it somewhere. Rust's compiler doesn't warn on pub fns missing consumers unless \`#![warn(dead_code)]\` is set at the crate root. AI agents that iterate on a file often leave these behind \u2014 the most common AI-rotation signature for Rust after unused-imports.`
40001
+ });
40002
+ }
40003
+ return issues;
40004
+ }
40005
+ });
40006
+ }
40007
+ });
40008
+
40009
+ // src/rules/rust/unwrap-in-production.ts
40010
+ function collectUnwrapIssues(node, testScopes, issues) {
40011
+ if (node.type === "call_expression") {
40012
+ const fn = node.childForFieldName("function");
40013
+ if (fn && fn.type === "field_expression") {
40014
+ const field = fn.childForFieldName("field");
40015
+ if (field && field.type === "field_identifier" && UNWRAP_METHODS.has(field.text)) {
40016
+ if (!isInsideTestFunction2(node, testScopes)) {
40017
+ issues.push({
40018
+ ruleId: "rust/unwrap-in-production",
40019
+ category: "logic",
40020
+ severity: "medium",
40021
+ aiSpecific: true,
40022
+ message: `'.${field.text}()' called in production code \u2014 panic risk on Err/None`,
40023
+ line: node.startPosition.row + 1,
40024
+ column: node.startPosition.column,
40025
+ advice: `Replace with '?' (early-return on Err), '.map_err(...)' for conversion, or an explicit 'match'. '.${field.text}()' is fine in tests \u2014 wrap with '#[cfg(test)]' or move into a '#[cfg(test)] mod tests' block to suppress.`
40026
+ });
40027
+ }
40028
+ }
40029
+ }
40030
+ }
40031
+ for (let i = 0; i < node.namedChildCount; i++) {
40032
+ const child = node.namedChild(i);
40033
+ if (child) collectUnwrapIssues(child, testScopes, issues);
40034
+ }
40035
+ }
40036
+ function isInsideTestFunction2(node, testScopes) {
40037
+ for (let p = node.parent; p; p = p.parent) {
40038
+ if (p.type === "function_item") {
40039
+ const nameField = p.childForFieldName("name");
40040
+ const name = nameField?.text;
40041
+ if (name && testScopes.has(name)) return true;
40042
+ if (p.text.startsWith("#[test]") || p.text.startsWith("#[cfg(test)]")) return true;
40043
+ return false;
40044
+ }
40045
+ if (p.type === "source_file") return false;
40046
+ }
40047
+ return false;
40048
+ }
40049
+ var UNWRAP_METHODS, rustUnwrapInProductionRule;
40050
+ var init_unwrap_in_production = __esm({
40051
+ "src/rules/rust/unwrap-in-production.ts"() {
40052
+ "use strict";
40053
+ init_rule();
40054
+ init_parser_rust();
40055
+ UNWRAP_METHODS = /* @__PURE__ */ new Set(["unwrap", "expect", "unwrap_or_else"]);
40056
+ rustUnwrapInProductionRule = createRule({
40057
+ id: "rust/unwrap-in-production",
40058
+ category: "logic",
40059
+ severity: "medium",
40060
+ aiSpecific: true,
40061
+ description: ".unwrap() / .expect() called outside of #[cfg(test)] / #[test] scope",
40062
+ create(_context) {
40063
+ return {};
40064
+ },
40065
+ analyze(_context, facts) {
40066
+ const issues = [];
40067
+ if (!facts.v2?.rustFile) return issues;
40068
+ const source = facts.v2._source ?? "";
40069
+ if (!source) return issues;
40070
+ const tree = parseRust(source);
40071
+ if (!tree) return issues;
40072
+ const testScopes = /* @__PURE__ */ new Set();
40073
+ for (const fn of facts.v2.rustFile.functions) {
40074
+ if (fn.inTestConfig && fn.name) testScopes.add(fn.name);
40075
+ }
40076
+ collectUnwrapIssues(tree.rootNode, testScopes, issues);
40077
+ return issues;
40078
+ }
40079
+ });
40080
+ }
40081
+ });
40082
+
38781
40083
  // src/rules/security/dangerous-cors.ts
38782
40084
  function scanForWildcardCors(source) {
38783
40085
  const hits = [];
@@ -41472,7 +42774,7 @@ function spanEnd(node) {
41472
42774
  }
41473
42775
  return void 0;
41474
42776
  }
41475
- function buildLineOffsets(source) {
42777
+ function buildLineOffsets2(source) {
41476
42778
  const offsets = [0];
41477
42779
  let byteOffset = 0;
41478
42780
  for (let i = 0; i < source.length; i++) {
@@ -43473,9 +44775,60 @@ function buildV2Facts(facts, source, ext, framework, config, templateClassNames
43473
44775
  })),
43474
44776
  disabledRules: extractDisabledRules(source),
43475
44777
  templateClassNames,
44778
+ // v0.18.9 — populate the Rust AST record when the file is `.rs`.
44779
+ // Calling `parseRustFile` here keeps the dead-code detector's
44780
+ // import-binding pass a pure function over the same source the
44781
+ // walker saw. The native-binding guard lives inside
44782
+ // `parseRustFile` (returns an empty record when tree-sitter is
44783
+ // unavailable).
44784
+ rustFile: buildRustFileRecord(facts.filePath, source),
43476
44785
  _source: source
43477
44786
  };
43478
44787
  }
44788
+ function buildRustFileRecord(filePath, source) {
44789
+ if (!filePath.toLowerCase().endsWith(".rs")) return void 0;
44790
+ const structure = parseRustFile(filePath, source);
44791
+ return {
44792
+ imports: structure.imports.map((i) => ({
44793
+ path: i.path,
44794
+ names: i.names.map((n) => ({ name: n.name, ...n.alias ? { alias: n.alias } : {} })),
44795
+ isGlob: i.isGlob,
44796
+ line: i.line,
44797
+ column: i.column
44798
+ })),
44799
+ functions: structure.functions.map((f) => ({
44800
+ name: f.name,
44801
+ line: f.line,
44802
+ column: f.column,
44803
+ isPublic: f.isPublic,
44804
+ isMethod: f.isMethod,
44805
+ ...f.receiver ? { receiver: f.receiver } : {},
44806
+ bodyLines: f.bodyLines,
44807
+ inTestConfig: f.inTestConfig
44808
+ })),
44809
+ structs: structure.structs.map((s) => ({
44810
+ name: s.name,
44811
+ line: s.line,
44812
+ column: s.column,
44813
+ isPublic: s.isPublic,
44814
+ isDerive: s.isDerive,
44815
+ derives: [...s.derives]
44816
+ })),
44817
+ traits: structure.traits.map((t) => ({
44818
+ name: t.name,
44819
+ line: t.line,
44820
+ column: t.column,
44821
+ isPublic: t.isPublic
44822
+ })),
44823
+ impls: structure.impls.map((ip) => ({
44824
+ ...ip.trait ? { trait: ip.trait } : {},
44825
+ type: ip.type,
44826
+ methods: [...ip.methods],
44827
+ line: ip.line,
44828
+ column: ip.column
44829
+ }))
44830
+ };
44831
+ }
43479
44832
  function splitFilePath(filePath) {
43480
44833
  const baseName2 = filePath.split("/").pop() ?? filePath;
43481
44834
  const dotIdx = baseName2.lastIndexOf(".");
@@ -43490,6 +44843,7 @@ var init_v2_build = __esm({
43490
44843
  "src/engine/visitors/v2-build.ts"() {
43491
44844
  "use strict";
43492
44845
  init_scan_helpers();
44846
+ init_rust();
43493
44847
  TAILWIND_COLOR_RE = /^(?:bg|text|border|ring|from|to|via|fill|stroke)-([a-z]+-\d+|white|black|transparent|current|\[.+?\])$/;
43494
44848
  TAILWIND_SPACING_RE = /^(?:[pm][xytrbl]?|gap|space-[xy])-(\d+(?:\.\d+)?)$/;
43495
44849
  TAILWIND_RADIUS_RE = /^(?:rounded(?:-[a-z]+)?)-(.+)$/;
@@ -43522,7 +44876,7 @@ function mergeTemplateClassNames(filePath, source, facts, templateClassNames) {
43522
44876
  }
43523
44877
  }
43524
44878
  function extractFacts(filePath, ast, source, supportsRsc = true, framework = "react", config) {
43525
- const lineOffsets = buildLineOffsets(source);
44879
+ const lineOffsets = buildLineOffsets2(source);
43526
44880
  const isTypeScript = /\.tsx?$/i.test(filePath);
43527
44881
  const NON_JSX_FRAMEWORKS = /* @__PURE__ */ new Set(["vue", "svelte", "astro"]);
43528
44882
  const facts = {
@@ -43810,7 +45164,7 @@ var init_naturalness_anomaly = __esm({
43810
45164
  const issues = [];
43811
45165
  const source = facts.v2?._source;
43812
45166
  if (!source) return issues;
43813
- const lineOffsets = buildLineOffsets(source);
45167
+ const lineOffsets = buildLineOffsets2(source);
43814
45168
  const components = facts.v2?.components ?? [];
43815
45169
  const perComponentMetrics = components.filter((c) => c.loc > 0).map(
43816
45170
  (c) => computeNaturalnessForRange(source, lineOffsets, c.line, c.line + c.loc - 1, context.model)
@@ -44481,6 +45835,10 @@ var init_builtins = __esm({
44481
45835
  init_halstead_anomaly();
44482
45836
  init_terminology_drift();
44483
45837
  init_ux_pattern_fragmentation();
45838
+ init_stringly_typed();
45839
+ init_todo_macro();
45840
+ init_unused_pub_fn();
45841
+ init_unwrap_in_production();
44484
45842
  init_dangerous_cors();
44485
45843
  init_eval();
44486
45844
  init_exposed_env_var();
@@ -44582,6 +45940,10 @@ var init_builtins = __esm({
44582
45940
  halsteadAnomalyRule,
44583
45941
  terminologyDriftRule,
44584
45942
  uxPatternFragmentationRule,
45943
+ rustStringlyTypedRule,
45944
+ rustTodoMacroRule,
45945
+ rustUnusedPubFnRule,
45946
+ rustUnwrapInProductionRule,
44585
45947
  dangerousCorsRule,
44586
45948
  evalRule,
44587
45949
  exposedEnvVarRule,
@@ -46562,6 +47924,22 @@ var init_registry = __esm({
46562
47924
  if (!filter) return list;
46563
47925
  return list.filter((r) => filter.kind === "ai" ? r.aiSpecific : !r.aiSpecific);
46564
47926
  }
47927
+ /** v0.18.8: remove every rule where `predicate(rule)` returns true.
47928
+ * Used by focused calibration scripts to scan a single category
47929
+ * without instantiating all 99 rules. */
47930
+ removeWhere(predicate) {
47931
+ let removed = 0;
47932
+ for (const [id, rule] of this.rules) {
47933
+ if (predicate(rule)) {
47934
+ this.rules.delete(id);
47935
+ removed++;
47936
+ }
47937
+ }
47938
+ return removed;
47939
+ }
47940
+ all() {
47941
+ return Array.from(this.rules.values());
47942
+ }
46565
47943
  createContexts(config, filePath, cwd, hotspotIssues = []) {
46566
47944
  const context = {
46567
47945
  config,
@@ -46587,1044 +47965,1793 @@ var signal_strength_default;
46587
47965
  var init_signal_strength = __esm({
46588
47966
  "src/rules/signal-strength.json"() {
46589
47967
  signal_strength_default = {
46590
- "logic/math-console-log-storm": {
46591
- recall: 7e-3,
46592
- fpRate: 1e-3,
46593
- ratio: 6.71,
46594
- precision: 0.8968,
46595
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47968
+ "ai/any-density": {
47969
+ recall: 6e-3,
47970
+ fpRate: 37e-4,
47971
+ ratio: 175.31,
47972
+ precision: 0.6523,
47973
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46596
47974
  verdict: "USEFUL",
46597
- _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.",
46598
- aiSpecific: true
47975
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=1760, FP=938, P=65.2%, FPR=0.37%, lift=175.31. v7 was USEFUL (TP=1313, FP=758, lift=153.41). v8 was USEFUL (TP=447, FP=180).",
47976
+ aiSpecific: true,
47977
+ _v7Verdict: "USEFUL",
47978
+ _v7Lift: 153.41,
47979
+ _v7Recall: 55e-4,
47980
+ _v7FpRate: 41e-4,
47981
+ _v7Precision: 0.634,
47982
+ _v8Verdict: "USEFUL",
47983
+ _v8Lift: 271.97
46599
47984
  },
46600
- "logic/math-any-density": {
46601
- recall: 16e-4,
46602
- fpRate: 13e-4,
46603
- ratio: 1.17,
46604
- precision: 0.6035,
46605
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46606
- verdict: "NOISY",
46607
- _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.",
46608
- defaultOff: true,
46609
- aiSpecific: true
47985
+ "ai/comment-ratio": {
47986
+ recall: 0.2771,
47987
+ fpRate: 0.1578,
47988
+ ratio: 4.26,
47989
+ precision: 0.6721,
47990
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47991
+ verdict: "USEFUL",
47992
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=81513, FP=39766, P=67.2%, FPR=15.78%, lift=4.26. v7 was USEFUL (TP=60308, FP=29876, lift=4.11). v8 was USEFUL (TP=21205, FP=9890).",
47993
+ aiSpecific: true,
47994
+ _v7Verdict: "USEFUL",
47995
+ _v7Lift: 4.11,
47996
+ _v7Recall: 0.2545,
47997
+ _v7FpRate: 0.1629,
47998
+ _v7Precision: 0.6687,
47999
+ _v8Verdict: "USEFUL",
48000
+ _v8Lift: 4.73
46610
48001
  },
46611
- "logic/boundary-violation": {
46612
- recall: 0.0263,
46613
- fpRate: 0.0175,
46614
- ratio: 1.5,
46615
- precision: 0.6601,
46616
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46617
- verdict: "HYGIENE",
46618
- _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.",
46619
- aiSpecific: false
48002
+ "ai/compression-profile": {
48003
+ recall: 0.3478,
48004
+ fpRate: 0.1488,
48005
+ ratio: 4.92,
48006
+ precision: 0.7318,
48007
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48008
+ verdict: "USEFUL",
48009
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=102328, FP=37511, P=73.2%, FPR=14.88%, lift=4.92. v7 was USEFUL (TP=75031, FP=27473, lift=4.89). v8 was USEFUL (TP=27297, FP=10038).",
48010
+ aiSpecific: true,
48011
+ _v7Verdict: "USEFUL",
48012
+ _v7Lift: 4.89,
48013
+ _v7Recall: 0.3166,
48014
+ _v7FpRate: 0.1498,
48015
+ _v7Precision: 0.732,
48016
+ _v8Verdict: "USEFUL",
48017
+ _v8Lift: 5
46620
48018
  },
46621
- "logic/reactive-hook-soup": {
46622
- recall: 38e-4,
48019
+ "ai/console-debug-storm": {
48020
+ recall: 73e-4,
46623
48021
  fpRate: 9e-4,
46624
- ratio: 4.29,
46625
- precision: 0.8476,
46626
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48022
+ ratio: 949.21,
48023
+ precision: 0.9,
48024
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46627
48025
  verdict: "USEFUL",
46628
- _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.",
46629
- aiSpecific: true
48026
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=2150, FP=239, P=90.0%, FPR=0.09%, lift=949.21. v7 was USEFUL (TP=1912, FP=175, lift=960.19). v8 was USEFUL (TP=238, FP=64).",
48027
+ aiSpecific: true,
48028
+ _v7Verdict: "USEFUL",
48029
+ _v7Lift: 960.19,
48030
+ _v7Recall: 81e-4,
48031
+ _v7FpRate: 1e-3,
48032
+ _v7Precision: 0.9161,
48033
+ _v8Verdict: "USEFUL",
48034
+ _v8Lift: 845.55
46630
48035
  },
46631
- "logic/optimistic-no-rollback": {
46632
- recall: 12e-4,
46633
- fpRate: 3e-4,
46634
- ratio: 3.61,
46635
- precision: 0.824,
46636
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48036
+ "ai/default-react-stack": {
48037
+ recall: 1e-3,
48038
+ fpRate: 0,
48039
+ ratio: 251225.49,
48040
+ precision: 0.9966,
48041
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46637
48042
  verdict: "USEFUL",
46638
- _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.",
46639
- aiSpecific: true
48043
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=294, FP=1, P=99.7%, FPR=0.00%, lift=251225.49. v7 was USEFUL (TP=231, FP=1, lift=182622.43). v8 was USEFUL (TP=63, FP=0).",
48044
+ aiSpecific: true,
48045
+ _v7Verdict: "USEFUL",
48046
+ _v7Lift: 182622.43,
48047
+ _v7Recall: 1e-3,
48048
+ _v7FpRate: 0,
48049
+ _v7Precision: 0.9957,
48050
+ _v8Verdict: "USEFUL",
48051
+ _v8Lift: 99999
46640
48052
  },
46641
- "logic/zombie-state": {
46642
- recall: 1e-4,
46643
- fpRate: 0,
46644
- ratio: 9.26,
46645
- precision: 0.9231,
46646
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48053
+ "ai/errors-near-eof": {
48054
+ recall: 0.0948,
48055
+ fpRate: 0.052,
48056
+ ratio: 13.09,
48057
+ precision: 0.6803,
48058
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46647
48059
  verdict: "USEFUL",
46648
- _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.",
46649
- aiSpecific: true
48060
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=27874, FP=13097, P=68.0%, FPR=5.20%, lift=13.09. v7 was USEFUL (TP=16673, FP=10112, lift=11.29). v8 was USEFUL (TP=11201, FP=2985).",
48061
+ aiSpecific: true,
48062
+ _v7Verdict: "USEFUL",
48063
+ _v7Lift: 11.29,
48064
+ _v7Recall: 0.0704,
48065
+ _v7FpRate: 0.0551,
48066
+ _v7Precision: 0.6225,
48067
+ _v8Verdict: "USEFUL",
48068
+ _v8Lift: 18.16
46650
48069
  },
46651
- "logic/math-gini-class-usage": {
46652
- recall: 13e-4,
48070
+ "ai/fetch-default-overuse": {
48071
+ recall: 27e-4,
46653
48072
  fpRate: 3e-4,
46654
- ratio: 5.09,
46655
- precision: 0.8683,
46656
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48073
+ ratio: 2679.84,
48074
+ precision: 0.9036,
48075
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46657
48076
  verdict: "USEFUL",
46658
- _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.",
46659
- aiSpecific: true
48077
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=797, FP=85, P=90.4%, FPR=0.03%, lift=2679.84. v7 was USEFUL (TP=666, FP=76, lift=2166.14). v8 was USEFUL (TP=131, FP=9).",
48078
+ aiSpecific: true,
48079
+ _v7Verdict: "USEFUL",
48080
+ _v7Lift: 2166.14,
48081
+ _v7Recall: 28e-4,
48082
+ _v7FpRate: 4e-4,
48083
+ _v7Precision: 0.8976,
48084
+ _v8Verdict: "USEFUL",
48085
+ _v8Lift: 7139.19
46660
48086
  },
46661
- "visual/math-color-cluster": {
46662
- recall: 2e-4,
48087
+ "ai/library-reinvention": {
48088
+ recall: 3e-4,
46663
48089
  fpRate: 0,
46664
- ratio: 8.95,
46665
- precision: 0.9206,
46666
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48090
+ ratio: 47415.05,
48091
+ precision: 0.9405,
48092
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46667
48093
  verdict: "USEFUL",
46668
- _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.",
46669
- aiSpecific: true
48094
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=79, FP=5, P=94.0%, FPR=0.00%, lift=47415.05. v7 was USEFUL (TP=64, FP=5, lift=34024.44). v8 was USEFUL (TP=15, FP=0).",
48095
+ aiSpecific: true,
48096
+ _v7Verdict: "USEFUL",
48097
+ _v7Lift: 34024.44,
48098
+ _v7Recall: 3e-4,
48099
+ _v7FpRate: 0,
48100
+ _v7Precision: 0.9275,
48101
+ _v8Verdict: "USEFUL",
48102
+ _v8Lift: 99999
46670
48103
  },
46671
- "visual/math-default-font": {
46672
- recall: 13e-4,
46673
- fpRate: 4e-4,
46674
- ratio: 3.4,
46675
- precision: 0.8151,
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=313, FP=71, P=81.5%, FPR=0.04%, lift=3.4. aiSpecific=True.",
46679
- aiSpecific: true
46680
- },
46681
- "visual/math-gradient-hue-rotation": {
48104
+ "ai/log-rank-histogram": {
46682
48105
  recall: 0,
46683
48106
  fpRate: 0,
46684
48107
  ratio: 0,
46685
48108
  precision: 0,
46686
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48109
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46687
48110
  verdict: "DORMANT",
46688
- defaultOff: true,
46689
- _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.)",
46690
- aiSpecific: true
48111
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=OK, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
48112
+ aiSpecific: true,
48113
+ _v7Verdict: "OK",
48114
+ _v7Lift: 0,
48115
+ _v7Recall: 0,
48116
+ _v7FpRate: 0,
48117
+ _v7Precision: 0,
48118
+ _v8Verdict: "DORMANT",
48119
+ _v8Lift: 1,
48120
+ defaultOff: true
46691
48121
  },
46692
- "visual/math-rounded-entropy": {
46693
- recall: 37e-4,
46694
- fpRate: 3e-4,
46695
- ratio: 10.9,
46696
- precision: 0.9339,
46697
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46698
- verdict: "USEFUL",
46699
- _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.",
46700
- aiSpecific: true
46701
- },
46702
- "visual/math-font-entropy": {
46703
- recall: 45e-4,
46704
- fpRate: 13e-4,
46705
- ratio: 3.32,
46706
- precision: 0.8114,
46707
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46708
- verdict: "USEFUL",
46709
- _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.",
46710
- aiSpecific: true
46711
- },
46712
- "visual/math-spacing-entropy": {
46713
- recall: 18e-4,
46714
- fpRate: 6e-4,
46715
- ratio: 3.01,
46716
- precision: 0.7959,
46717
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46718
- verdict: "USEFUL",
46719
- _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.",
46720
- aiSpecific: true
48122
+ "ai/markdown-leakage": {
48123
+ recall: 0,
48124
+ fpRate: 0,
48125
+ ratio: 10003.17,
48126
+ precision: 0.3571,
48127
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48128
+ verdict: "OK",
48129
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=5, FP=9, P=35.7%, FPR=0.00%, lift=10003.17. v7 was USEFUL (TP=5, FP=2, lift=65504.64). v8 was INVERTED (TP=0, FP=7).",
48130
+ aiSpecific: true,
48131
+ _v7Verdict: "USEFUL",
48132
+ _v7Lift: 65504.64,
48133
+ _v7Recall: 0,
48134
+ _v7FpRate: 0,
48135
+ _v7Precision: 0.7143,
48136
+ _v8Verdict: "INVERTED",
48137
+ _v8Lift: 0
46721
48138
  },
46722
- "visual/clamp-soup": {
48139
+ "ai/renyi-profile": {
46723
48140
  recall: 0,
46724
48141
  fpRate: 0,
46725
- ratio: 0,
46726
- precision: 0,
46727
- lastCalibratedAt: "2026-06-25T00:00:00Z",
46728
- verdict: "DORMANT",
46729
- defaultOff: true,
46730
- _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.)",
46731
- aiSpecific: true
48142
+ ratio: 5251.67,
48143
+ precision: 0.25,
48144
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48145
+ verdict: "OK",
48146
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=4, FP=12, P=25.0%, FPR=0.00%, lift=5251.67. v7 was OK (TP=3, FP=9, lift=5094.81). v8 was OK (TP=1, FP=3).",
48147
+ aiSpecific: true,
48148
+ _v7Verdict: "OK",
48149
+ _v7Lift: 5094.81,
48150
+ _v7Recall: 0,
48151
+ _v7FpRate: 0,
48152
+ _v7Precision: 0.25,
48153
+ _v8Verdict: "OK",
48154
+ _v8Lift: 5722.25
46732
48155
  },
46733
- "component/giant-component": {
46734
- recall: 0.0176,
46735
- fpRate: 77e-4,
46736
- ratio: 2.3,
46737
- precision: 0.7485,
46738
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48156
+ "ai/segment-surprisal-cv": {
48157
+ recall: 0.2019,
48158
+ fpRate: 0.0787,
48159
+ ratio: 9.52,
48160
+ precision: 0.7495,
48161
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46739
48162
  verdict: "USEFUL",
46740
- _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.",
46741
- aiSpecific: true
48163
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=59390, FP=19849, P=75.0%, FPR=7.87%, lift=9.52. v7 was USEFUL (TP=43498, FP=14983, lift=9.11). v8 was USEFUL (TP=15892, FP=4866).",
48164
+ aiSpecific: true,
48165
+ _v7Verdict: "USEFUL",
48166
+ _v7Lift: 9.11,
48167
+ _v7Recall: 0.1836,
48168
+ _v7FpRate: 0.0817,
48169
+ _v7Precision: 0.7438,
48170
+ _v8Verdict: "USEFUL",
48171
+ _v8Lift: 10.8
46742
48172
  },
46743
- "component/shadcn-prop-mismatch": {
46744
- recall: 13e-4,
46745
- fpRate: 1e-4,
46746
- ratio: 10.1,
46747
- precision: 0.929,
46748
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48173
+ "ai/state-default-overuse": {
48174
+ recall: 3e-3,
48175
+ fpRate: 6e-4,
48176
+ ratio: 1315.06,
48177
+ precision: 0.8451,
48178
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46749
48179
  verdict: "USEFUL",
46750
- _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.",
46751
- aiSpecific: true
46752
- },
46753
- "layout/math-grid-uniformity": {
46754
- recall: 3e-4,
46755
- fpRate: 2e-4,
46756
- ratio: 1.72,
46757
- precision: 0.6907,
46758
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46759
- verdict: "OK",
46760
- _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.",
46761
- aiSpecific: true
48180
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=884, FP=162, P=84.5%, FPR=0.06%, lift=1315.06. v7 was USEFUL (TP=701, FP=158, lift=947.32). v8 was USEFUL (TP=183, FP=4).",
48181
+ aiSpecific: true,
48182
+ _v7Verdict: "USEFUL",
48183
+ _v7Lift: 947.32,
48184
+ _v7Recall: 3e-3,
48185
+ _v7FpRate: 9e-4,
48186
+ _v7Precision: 0.8161,
48187
+ _v8Verdict: "USEFUL",
48188
+ _v8Lift: 16799.55
46762
48189
  },
46763
- "layout/math-element-uniformity": {
46764
- recall: 28e-4,
46765
- fpRate: 12e-4,
46766
- ratio: 2.28,
46767
- precision: 0.7475,
46768
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48190
+ "ai/tailwind-color-overuse": {
48191
+ recall: 0.0264,
48192
+ fpRate: 38e-4,
48193
+ ratio: 230.97,
48194
+ precision: 0.8888,
48195
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46769
48196
  verdict: "USEFUL",
46770
- _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.",
46771
- aiSpecific: true
48197
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=7752, FP=970, P=88.9%, FPR=0.38%, lift=230.97. v7 was USEFUL (TP=5169, FP=958, lift=161.52). v8 was USEFUL (TP=2583, FP=12).",
48198
+ aiSpecific: true,
48199
+ _v7Verdict: "USEFUL",
48200
+ _v7Lift: 161.52,
48201
+ _v7Recall: 0.0218,
48202
+ _v7FpRate: 52e-4,
48203
+ _v7Precision: 0.8436,
48204
+ _v8Verdict: "USEFUL",
48205
+ _v8Lift: 5695.79
46772
48206
  },
46773
- "typo/math-button-label-uniformity": {
46774
- recall: 2e-4,
46775
- fpRate: 1e-4,
46776
- ratio: 1.36,
46777
- precision: 0.6379,
46778
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46779
- verdict: "HYGIENE",
46780
- _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.",
46781
- aiSpecific: false
46782
- },
46783
- "perf/css-bloat": {
46784
- recall: 0.0117,
46785
- fpRate: 32e-4,
46786
- ratio: 3.64,
46787
- precision: 0.8252,
46788
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46789
- verdict: "HYGIENE",
46790
- _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.",
46791
- aiSpecific: false
48207
+ "ai/text-like-ratio": {
48208
+ recall: 0,
48209
+ fpRate: 0,
48210
+ ratio: 201664,
48211
+ precision: 0.8,
48212
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48213
+ verdict: "USEFUL",
48214
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=4, FP=1, P=80.0%, FPR=0.00%, lift=201664.00. v7 was USEFUL (TP=3, FP=1, lift=137559.75). v8 was USEFUL (TP=1, FP=0).",
48215
+ aiSpecific: true,
48216
+ _v7Verdict: "USEFUL",
48217
+ _v7Lift: 137559.75,
48218
+ _v7Recall: 0,
48219
+ _v7FpRate: 0,
48220
+ _v7Precision: 0.75,
48221
+ _v8Verdict: "USEFUL",
48222
+ _v8Lift: 99999
46792
48223
  },
46793
- "wcag/focus-appearance": {
46794
- recall: 26e-4,
46795
- fpRate: 1e-4,
46796
- ratio: 19.68,
46797
- precision: 0.9623,
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=612, FP=24, P=96.2%, FPR=0.01%, lift=19.7. aiSpecific=False.",
46801
- aiSpecific: false
48224
+ "ai/whitespace-regularity": {
48225
+ recall: 0.0733,
48226
+ fpRate: 0.0677,
48227
+ ratio: 8.25,
48228
+ precision: 0.5583,
48229
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48230
+ verdict: "USEFUL",
48231
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=21567, FP=17061, P=55.8%, FPR=6.77%, lift=8.25. v7 was USEFUL (TP=17466, FP=13438, lift=7.71). v8 was USEFUL (TP=4101, FP=3623).",
48232
+ aiSpecific: true,
48233
+ _v7Verdict: "USEFUL",
48234
+ _v7Lift: 7.71,
48235
+ _v7Recall: 0.0737,
48236
+ _v7FpRate: 0.0733,
48237
+ _v7Precision: 0.5652,
48238
+ _v8Verdict: "USEFUL",
48239
+ _v8Lift: 10.06
46802
48240
  },
46803
- "wcag/target-size": {
48241
+ "arch/astro-island-leak": {
46804
48242
  recall: 0,
46805
48243
  fpRate: 0,
46806
48244
  ratio: 0,
46807
48245
  precision: 0,
46808
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48246
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46809
48247
  verdict: "DORMANT",
46810
- defaultOff: true,
46811
- _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.)",
46812
- aiSpecific: false
48248
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
48249
+ aiSpecific: true,
48250
+ _v7Verdict: "DORMANT",
48251
+ _v7Lift: 0,
48252
+ _v7Recall: 0,
48253
+ _v7FpRate: 0,
48254
+ _v7Precision: 0,
48255
+ _v8Verdict: "DORMANT",
48256
+ _v8Lift: 1,
48257
+ defaultOff: true
46813
48258
  },
46814
- "component/multiple-components-per-file": {
46815
- recall: 0.0681,
46816
- fpRate: 0.052,
46817
- ratio: 1.31,
46818
- precision: 0.6294,
46819
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46820
- verdict: "HYGIENE",
46821
- _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.",
46822
- aiSpecific: false
46823
- },
46824
- "context/import-path-mismatch": {
46825
- recall: 0.0739,
46826
- fpRate: 0.0228,
46827
- ratio: 3.25,
46828
- precision: 0.8079,
46829
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46830
- verdict: "HYGIENE",
46831
- _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.",
46832
- aiSpecific: false
48259
+ "component/giant-component": {
48260
+ recall: 0.0181,
48261
+ fpRate: 59e-4,
48262
+ ratio: 132.31,
48263
+ precision: 0.7815,
48264
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48265
+ verdict: "USEFUL",
48266
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=5326, FP=1489, P=78.2%, FPR=0.59%, lift=132.31. v7 was USEFUL (TP=4205, FP=1413, lift=97.16). v8 was USEFUL (TP=1121, FP=76).",
48267
+ aiSpecific: true,
48268
+ _v7Verdict: "USEFUL",
48269
+ _v7Lift: 97.16,
48270
+ _v7Recall: 0.0177,
48271
+ _v7FpRate: 77e-4,
48272
+ _v7Precision: 0.7485,
48273
+ _v8Verdict: "USEFUL",
48274
+ _v8Lift: 846.15
46833
48275
  },
46834
- "logic/key-prop-missing": {
46835
- recall: 17e-4,
46836
- fpRate: 14e-4,
46837
- ratio: 1.28,
46838
- precision: 0.6246,
46839
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46840
- verdict: "HYGIENE",
46841
- _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.",
46842
- aiSpecific: false
48276
+ "component/multiple-components-per-file": {
48277
+ recall: 0.0751,
48278
+ fpRate: 0.0423,
48279
+ ratio: 15.96,
48280
+ precision: 0.6747,
48281
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48282
+ verdict: "USEFUL",
48283
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=22103, FP=10655, P=67.5%, FPR=4.23%, lift=15.96. v7 was USEFUL (TP=16288, FP=9589, lift=12.04). v8 was USEFUL (TP=5815, FP=1066).",
48284
+ aiSpecific: false,
48285
+ _v7Verdict: "USEFUL",
48286
+ _v7Lift: 12.04,
48287
+ _v7Recall: 0.0687,
48288
+ _v7FpRate: 0.0523,
48289
+ _v7Precision: 0.6294,
48290
+ _v8Verdict: "USEFUL",
48291
+ _v8Lift: 54.44
46843
48292
  },
46844
- "logic/math-variable-name-entropy": {
46845
- recall: 2e-4,
48293
+ "component/shadcn-prop-mismatch": {
48294
+ recall: 16e-4,
46846
48295
  fpRate: 1e-4,
46847
- ratio: 1.07,
46848
- precision: 0.5806,
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=36, FP=26, P=58.1%, FPR=0.01%, lift=1.1. aiSpecific=False.",
46852
- aiSpecific: false
46853
- },
46854
- "security/public-admin-route": {
46855
- recall: 28e-4,
46856
- fpRate: 78e-4,
46857
- ratio: 0.4,
46858
- precision: 0.2251,
46859
- lastCalibratedAt: "2026-06-26T22:30:00Z",
46860
- verdict: "HYGIENE",
46861
- _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]",
46862
- defaultOff: true,
46863
- aiSpecific: false
46864
- },
46865
- "security/unsafe-html-render": {
46866
- recall: 13e-4,
46867
- fpRate: 9e-4,
46868
- ratio: 1.5,
46869
- precision: 0.661,
46870
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46871
- verdict: "HYGIENE",
46872
- _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.",
46873
- aiSpecific: false
46874
- },
46875
- "visual/naturalness-anomaly": {
46876
- recall: 0.1645,
46877
- fpRate: 0.0617,
46878
- ratio: 2.67,
46879
- precision: 0.7755,
46880
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48296
+ ratio: 9990.98,
48297
+ precision: 0.9512,
48298
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46881
48299
  verdict: "USEFUL",
46882
- _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.",
46883
- aiSpecific: true
48300
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=468, FP=24, P=95.1%, FPR=0.01%, lift=9990.98. v7 was USEFUL (TP=314, FP=24, lift=7099.57). v8 was USEFUL (TP=154, FP=0).",
48301
+ aiSpecific: true,
48302
+ _v7Verdict: "USEFUL",
48303
+ _v7Lift: 7099.57,
48304
+ _v7Recall: 13e-4,
48305
+ _v7FpRate: 1e-4,
48306
+ _v7Precision: 0.929,
48307
+ _v8Verdict: "USEFUL",
48308
+ _v8Lift: 99999
46884
48309
  },
46885
- "perf/halstead-anomaly": {
46886
- recall: 0,
46887
- fpRate: 0,
46888
- ratio: 2.32,
46889
- precision: 0.75,
46890
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48310
+ "context/import-path-mismatch": {
48311
+ recall: 0.0681,
48312
+ fpRate: 0.0167,
48313
+ ratio: 49.48,
48314
+ precision: 0.8263,
48315
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46891
48316
  verdict: "USEFUL",
46892
- _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.",
46893
- aiSpecific: true
48317
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=20032, FP=4210, P=82.6%, FPR=1.67%, lift=49.48. v7 was USEFUL (TP=17672, FP=4202, lift=35.26). v8 was USEFUL (TP=2360, FP=8).",
48318
+ aiSpecific: false,
48319
+ _v7Verdict: "USEFUL",
48320
+ _v7Lift: 35.26,
48321
+ _v7Recall: 0.0746,
48322
+ _v7FpRate: 0.0229,
48323
+ _v7Precision: 0.8079,
48324
+ _v8Verdict: "USEFUL",
48325
+ _v8Lift: 8554.38
46894
48326
  },
46895
- "arch/astro-island-leak": {
48327
+ "db/duplicate-index": {
46896
48328
  recall: 0,
46897
48329
  fpRate: 0,
46898
48330
  ratio: 0,
46899
48331
  precision: 0,
46900
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48332
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46901
48333
  verdict: "DORMANT",
46902
- defaultOff: true,
46903
- _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.)",
46904
- aiSpecific: true
48334
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
48335
+ aiSpecific: false,
48336
+ _v7Verdict: "DORMANT",
48337
+ _v7Lift: 0,
48338
+ _v7Recall: 0,
48339
+ _v7FpRate: 0,
48340
+ _v7Precision: 0,
48341
+ _v8Verdict: "DORMANT",
48342
+ _v8Lift: 1,
48343
+ defaultOff: true
46905
48344
  },
46906
- "logic/qwik-hook-leak": {
48345
+ "db/enum-sprawl": {
46907
48346
  recall: 0,
46908
48347
  fpRate: 0,
46909
48348
  ratio: 0,
46910
48349
  precision: 0,
46911
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48350
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46912
48351
  verdict: "DORMANT",
46913
- defaultOff: true,
46914
- _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.)",
46915
- aiSpecific: true
48352
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
48353
+ aiSpecific: false,
48354
+ _v7Verdict: "DORMANT",
48355
+ _v7Lift: 0,
48356
+ _v7Recall: 0,
48357
+ _v7FpRate: 0,
48358
+ _v7Precision: 0,
48359
+ _v8Verdict: "DORMANT",
48360
+ _v8Lift: 1,
48361
+ defaultOff: true
46916
48362
  },
46917
- "test/missing-edge-case": {
48363
+ "db/missing-fk-index": {
46918
48364
  recall: 0,
46919
48365
  fpRate: 0,
46920
48366
  ratio: 0,
46921
48367
  precision: 0,
46922
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48368
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46923
48369
  verdict: "DORMANT",
46924
- defaultOff: true,
46925
- _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.)",
46926
- aiSpecific: true
48370
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
48371
+ aiSpecific: false,
48372
+ _v7Verdict: "DORMANT",
48373
+ _v7Lift: 0,
48374
+ _v7Recall: 0,
48375
+ _v7FpRate: 0,
48376
+ _v7Precision: 0,
48377
+ _v8Verdict: "DORMANT",
48378
+ _v8Lift: 1,
48379
+ defaultOff: true
46927
48380
  },
46928
- "typo/calc-fontsize": {
48381
+ "db/missing-not-null": {
46929
48382
  recall: 0,
46930
48383
  fpRate: 0,
46931
48384
  ratio: 0,
46932
48385
  precision: 0,
46933
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48386
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46934
48387
  verdict: "DORMANT",
46935
- defaultOff: true,
46936
- _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).)",
46937
- aiSpecific: false
48388
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
48389
+ aiSpecific: false,
48390
+ _v7Verdict: "DORMANT",
48391
+ _v7Lift: 0,
48392
+ _v7Recall: 0,
48393
+ _v7FpRate: 0,
48394
+ _v7Precision: 0,
48395
+ _v8Verdict: "DORMANT",
48396
+ _v8Lift: 1,
48397
+ defaultOff: true
46938
48398
  },
46939
- "typo/clamp-offscale": {
48399
+ "db/naming-inconsistency": {
46940
48400
  recall: 0,
46941
48401
  fpRate: 0,
46942
48402
  ratio: 0,
46943
48403
  precision: 0,
46944
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48404
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46945
48405
  verdict: "DORMANT",
46946
- defaultOff: true,
46947
- _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.)",
46948
- aiSpecific: false
48406
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
48407
+ aiSpecific: false,
48408
+ _v7Verdict: "DORMANT",
48409
+ _v7Lift: 0,
48410
+ _v7Recall: 0,
48411
+ _v7FpRate: 0,
48412
+ _v7Precision: 0,
48413
+ _v8Verdict: "DORMANT",
48414
+ _v8Lift: 1,
48415
+ defaultOff: true
46949
48416
  },
46950
- "typo/math-cta-vocabulary": {
48417
+ "db/sql-concat": {
48418
+ recall: 5e-4,
48419
+ fpRate: 1e-4,
48420
+ ratio: 7511.26,
48421
+ precision: 0.8343,
48422
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48423
+ verdict: "USEFUL",
48424
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=141, FP=28, P=83.4%, FPR=0.01%, lift=7511.26. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=141, FP=28).",
48425
+ aiSpecific: true,
48426
+ _v7Verdict: "DORMANT",
48427
+ _v7Lift: 1,
48428
+ _v7Recall: 0,
48429
+ _v7FpRate: 0,
48430
+ _v7Precision: 0,
48431
+ _v8Verdict: "USEFUL",
48432
+ _v8Lift: 2046.08
48433
+ },
48434
+ "dead/dead-branch": {
48435
+ recall: 2e-4,
48436
+ fpRate: 4e-4,
48437
+ ratio: 1080.68,
48438
+ precision: 0.4244,
48439
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48440
+ verdict: "OK",
48441
+ _calibrationNote: "v8.5 (v0.18.9): v85 verdict=OK, v7 was DORMANT, v8 was OK. v0.18.8 v8a first measurement (1000 files): see docs/research/v0.18.8-dead-rules-measurement.md.",
48442
+ aiSpecific: true,
48443
+ _v7Verdict: "DORMANT",
48444
+ _v7Lift: 1,
48445
+ _v7Recall: 0,
48446
+ _v7FpRate: 0,
48447
+ _v7Precision: 0,
48448
+ _v8Verdict: "OK",
48449
+ _v8Lift: 294.38
48450
+ },
48451
+ "dead/unreachable": {
48452
+ recall: 1e-4,
48453
+ fpRate: 6e-4,
48454
+ ratio: 153.14,
48455
+ precision: 0.0966,
48456
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48457
+ verdict: "OK",
48458
+ _calibrationNote: "v8.5 (v0.18.9): v85 verdict=OK, v7 was DORMANT, v8 was OK. v0.18.8 v8a first measurement (1000 files): see docs/research/v0.18.8-dead-rules-measurement.md.",
48459
+ aiSpecific: true,
48460
+ _v7Verdict: "DORMANT",
48461
+ _v7Lift: 1,
48462
+ _v7Recall: 0,
48463
+ _v7FpRate: 0,
48464
+ _v7Precision: 0,
48465
+ _v8Verdict: "OK",
48466
+ _v8Lift: 41.71
48467
+ },
48468
+ "dead/unused-import": {
48469
+ recall: 0.0379,
48470
+ fpRate: 0.0222,
48471
+ ratio: 30.06,
48472
+ precision: 0.6662,
48473
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48474
+ verdict: "USEFUL",
48475
+ _calibrationNote: "v8.5 (v0.18.9): v85 verdict=USEFUL, v7 was DORMANT, v8 was USEFUL. v0.18.8 v8a first measurement (1000 files): see docs/research/v0.18.8-dead-rules-measurement.md.",
48476
+ aiSpecific: true,
48477
+ _v7Verdict: "DORMANT",
48478
+ _v7Lift: 1,
48479
+ _v7Recall: 0,
48480
+ _v7FpRate: 0,
48481
+ _v7Precision: 0,
48482
+ _v8Verdict: "USEFUL",
48483
+ _v8Lift: 8.19
48484
+ },
48485
+ "dead/unused-local": {
48486
+ recall: 0.0477,
48487
+ fpRate: 74e-4,
48488
+ ratio: 120.18,
48489
+ precision: 0.8834,
48490
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48491
+ verdict: "USEFUL",
48492
+ _calibrationNote: "v8.5 (v0.18.9): v85 verdict=USEFUL, v7 was DORMANT, v8 was USEFUL. v0.18.8 v8a first measurement (1000 files): see docs/research/v0.18.8-dead-rules-measurement.md.",
48493
+ aiSpecific: true,
48494
+ _v7Verdict: "DORMANT",
48495
+ _v7Lift: 1,
48496
+ _v7Recall: 0,
48497
+ _v7FpRate: 0,
48498
+ _v7Precision: 0,
48499
+ _v8Verdict: "USEFUL",
48500
+ _v8Lift: 32.74
48501
+ },
48502
+ "dead/unused-parameter": {
48503
+ recall: 8e-4,
48504
+ fpRate: 27e-4,
48505
+ ratio: 98,
48506
+ precision: 0.2628,
48507
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48508
+ verdict: "OK",
48509
+ _calibrationNote: "v8.5 (v0.18.9): v85 verdict=OK, v7 was DORMANT, v8 was OK. v0.18.8 v8a first measurement (1000 files): see docs/research/v0.18.8-dead-rules-measurement.md.",
48510
+ aiSpecific: true,
48511
+ _v7Verdict: "DORMANT",
48512
+ _v7Lift: 1,
48513
+ _v7Recall: 0,
48514
+ _v7FpRate: 0,
48515
+ _v7Precision: 0,
48516
+ _v8Verdict: "OK",
48517
+ _v8Lift: 26.7
48518
+ },
48519
+ "docs/broken-link": {
48520
+ recall: 14e-4,
48521
+ fpRate: 23e-4,
48522
+ ratio: 178.13,
48523
+ precision: 0.4155,
48524
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48525
+ verdict: "OK",
48526
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=418, FP=588, P=41.6%, FPR=0.23%, lift=178.13. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was OK (TP=418, FP=588).",
48527
+ aiSpecific: false,
48528
+ _v7Verdict: "DORMANT",
48529
+ _v7Lift: 1,
48530
+ _v7Recall: 0,
48531
+ _v7FpRate: 0,
48532
+ _v7Precision: 0,
48533
+ _v8Verdict: "OK",
48534
+ _v8Lift: 48.52
48535
+ },
48536
+ "docs/expired-code-example": {
46951
48537
  recall: 0,
46952
48538
  fpRate: 0,
46953
48539
  ratio: 0,
46954
48540
  precision: 0,
46955
- lastCalibratedAt: "2026-06-25T00:00:00Z",
46956
- verdict: "DORMANT",
46957
- defaultOff: true,
46958
- _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.)",
46959
- aiSpecific: true
48541
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48542
+ verdict: "INVERTED",
48543
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=0, FP=3, P=0.0%, FPR=0.00%, lift=0.00. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was INVERTED (TP=0, FP=3).",
48544
+ aiSpecific: false,
48545
+ _v7Verdict: "DORMANT",
48546
+ _v7Lift: 1,
48547
+ _v7Recall: 0,
48548
+ _v7FpRate: 0,
48549
+ _v7Precision: 0,
48550
+ _v8Verdict: "INVERTED",
48551
+ _v8Lift: 0,
48552
+ defaultOff: true
48553
+ },
48554
+ "docs/stale-function-reference": {
48555
+ recall: 26e-4,
48556
+ fpRate: 5e-4,
48557
+ ratio: 1638.47,
48558
+ precision: 0.8515,
48559
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48560
+ verdict: "USEFUL",
48561
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=751, FP=131, P=85.1%, FPR=0.05%, lift=1638.47. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=751, FP=131).",
48562
+ aiSpecific: false,
48563
+ _v7Verdict: "DORMANT",
48564
+ _v7Lift: 1,
48565
+ _v7Recall: 0,
48566
+ _v7FpRate: 0,
48567
+ _v7Precision: 0,
48568
+ _v8Verdict: "USEFUL",
48569
+ _v8Lift: 446.32
48570
+ },
48571
+ "docs/stale-package-reference": {
48572
+ recall: 2e-4,
48573
+ fpRate: 4e-4,
48574
+ ratio: 939.43,
48575
+ precision: 0.3429,
48576
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48577
+ verdict: "OK",
48578
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=48, FP=92, P=34.3%, FPR=0.04%, lift=939.43. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was OK (TP=48, FP=92).",
48579
+ aiSpecific: false,
48580
+ _v7Verdict: "DORMANT",
48581
+ _v7Lift: 1,
48582
+ _v7Recall: 0,
48583
+ _v7FpRate: 0,
48584
+ _v7Precision: 0,
48585
+ _v8Verdict: "OK",
48586
+ _v8Lift: 255.9
46960
48587
  },
46961
48588
  "layout/forced-layout": {
46962
48589
  recall: 0,
46963
48590
  fpRate: 0,
46964
48591
  ratio: 0,
46965
48592
  precision: 0,
46966
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48593
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46967
48594
  verdict: "DORMANT",
46968
- defaultOff: true,
46969
- _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.)",
46970
- aiSpecific: true
48595
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
48596
+ aiSpecific: true,
48597
+ _v7Verdict: "DORMANT",
48598
+ _v7Lift: 0,
48599
+ _v7Recall: 0,
48600
+ _v7FpRate: 0,
48601
+ _v7Precision: 0,
48602
+ _v8Verdict: "DORMANT",
48603
+ _v8Lift: 1,
48604
+ defaultOff: true
46971
48605
  },
46972
- "visual/generic-centering": {
48606
+ "layout/gap-monopoly": {
48607
+ recall: 3e-4,
48608
+ fpRate: 1e-4,
48609
+ ratio: 8859.33,
48610
+ precision: 0.8083,
48611
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48612
+ verdict: "USEFUL",
48613
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=97, FP=23, P=80.8%, FPR=0.01%, lift=8859.33. v7 was USEFUL (TP=88, FP=23, lift=6322.11). v8 was USEFUL (TP=9, FP=0).",
48614
+ aiSpecific: false,
48615
+ _v7Verdict: "USEFUL",
48616
+ _v7Lift: 6322.11,
48617
+ _v7Recall: 4e-4,
48618
+ _v7FpRate: 1e-4,
48619
+ _v7Precision: 0.7928,
48620
+ _v8Verdict: "USEFUL",
48621
+ _v8Lift: 99999
48622
+ },
48623
+ "layout/math-element-uniformity": {
48624
+ recall: 29e-4,
48625
+ fpRate: 1e-3,
48626
+ ratio: 770.74,
48627
+ precision: 0.7705,
48628
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48629
+ verdict: "USEFUL",
48630
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=846, FP=252, P=77.0%, FPR=0.10%, lift=770.74. v7 was USEFUL (TP=666, FP=225, lift=609.32). v8 was USEFUL (TP=180, FP=27).",
48631
+ aiSpecific: true,
48632
+ _v7Verdict: "USEFUL",
48633
+ _v7Lift: 609.32,
48634
+ _v7Recall: 28e-4,
48635
+ _v7FpRate: 12e-4,
48636
+ _v7Precision: 0.7475,
48637
+ _v8Verdict: "USEFUL",
48638
+ _v8Lift: 2211.5
48639
+ },
48640
+ "layout/math-grid-uniformity": {
48641
+ recall: 3e-4,
48642
+ fpRate: 1e-4,
48643
+ ratio: 5839.98,
48644
+ precision: 0.7182,
48645
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48646
+ verdict: "USEFUL",
48647
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=79, FP=31, P=71.8%, FPR=0.01%, lift=5839.98. v7 was USEFUL (TP=67, FP=30, lift=4222.91). v8 was USEFUL (TP=12, FP=1).",
48648
+ aiSpecific: true,
48649
+ _v7Verdict: "USEFUL",
48650
+ _v7Lift: 4222.91,
48651
+ _v7Recall: 3e-4,
48652
+ _v7FpRate: 2e-4,
48653
+ _v7Precision: 0.6907,
48654
+ _v8Verdict: "USEFUL",
48655
+ _v8Lift: 63384.92
48656
+ },
48657
+ "layout/spacing-grid": {
48658
+ recall: 2e-4,
48659
+ fpRate: 2e-4,
48660
+ ratio: 4051.29,
48661
+ precision: 0.6429,
48662
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48663
+ verdict: "USEFUL",
48664
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=72, FP=40, P=64.3%, FPR=0.02%, lift=4051.29. v7 was USEFUL (TP=39, FP=15, lift=8831.00). v8 was USEFUL (TP=33, FP=25).",
48665
+ aiSpecific: false,
48666
+ _v7Verdict: "USEFUL",
48667
+ _v7Lift: 8831,
48668
+ _v7Recall: 2e-4,
48669
+ _v7FpRate: 1e-4,
48670
+ _v7Precision: 0.7222,
48671
+ _v8Verdict: "USEFUL",
48672
+ _v8Lift: 1562.77
48673
+ },
48674
+ "logic/bayesian-conditional": {
46973
48675
  recall: 0,
46974
48676
  fpRate: 0,
46975
48677
  ratio: 0,
46976
48678
  precision: 0,
46977
- lastCalibratedAt: "2026-06-25T00:00:00Z",
48679
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46978
48680
  verdict: "DORMANT",
46979
- defaultOff: true,
46980
- _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.)",
46981
- aiSpecific: true
48681
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
48682
+ aiSpecific: true,
48683
+ _v7Verdict: "DORMANT",
48684
+ _v7Lift: 0,
48685
+ _v7Recall: 0,
48686
+ _v7FpRate: 0,
48687
+ _v7Precision: 0,
48688
+ _v8Verdict: "DORMANT",
48689
+ _v8Lift: 1,
48690
+ defaultOff: true
46982
48691
  },
46983
- "product/terminology-drift": {
46984
- recall: 85e-4,
46985
- fpRate: 28e-4,
46986
- ratio: 3,
46987
- precision: 0.7956,
46988
- lastCalibratedAt: "2026-06-27T12:00:00Z",
46989
- verdict: "HYGIENE",
46990
- _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.",
46991
- aiSpecific: false
48692
+ "logic/boundary-violation": {
48693
+ recall: 0.0274,
48694
+ fpRate: 0.0137,
48695
+ ratio: 51.32,
48696
+ precision: 0.7006,
48697
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48698
+ verdict: "USEFUL",
48699
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=8051, FP=3441, P=70.1%, FPR=1.37%, lift=51.32. v7 was USEFUL (TP=6282, FP=3235, lift=37.42). v8 was USEFUL (TP=1769, FP=206).",
48700
+ aiSpecific: false,
48701
+ _v7Verdict: "USEFUL",
48702
+ _v7Lift: 37.42,
48703
+ _v7Recall: 0.0265,
48704
+ _v7FpRate: 0.0176,
48705
+ _v7Precision: 0.6601,
48706
+ _v8Verdict: "USEFUL",
48707
+ _v8Lift: 298.57
46992
48708
  },
46993
- "product/ux-pattern-fragmentation": {
48709
+ "logic/ghost-defensive": {
46994
48710
  recall: 1e-4,
46995
48711
  fpRate: 0,
46996
- ratio: 3.09,
46997
- precision: 0.8,
46998
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48712
+ ratio: 112035.56,
48713
+ precision: 0.8889,
48714
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
46999
48715
  verdict: "USEFUL",
47000
- _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.",
47001
- aiSpecific: true
48716
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=16, FP=2, P=88.9%, FPR=0.00%, lift=112035.56. v7 was USEFUL (TP=15, FP=2, lift=80917.50). v8 was USEFUL (TP=1, FP=0).",
48717
+ aiSpecific: true,
48718
+ _v7Verdict: "USEFUL",
48719
+ _v7Lift: 80917.5,
48720
+ _v7Recall: 1e-4,
48721
+ _v7FpRate: 0,
48722
+ _v7Precision: 0.8824,
48723
+ _v8Verdict: "USEFUL",
48724
+ _v8Lift: 99999
47002
48725
  },
47003
- "security/sql-construction": {
47004
- recall: 3e-3,
47005
- fpRate: 18e-4,
47006
- ratio: 1.63,
47007
- precision: 0.6788,
47008
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48726
+ "logic/heaps-deviation": {
48727
+ recall: 0.0126,
48728
+ fpRate: 0.0178,
48729
+ ratio: 25.54,
48730
+ precision: 0.4536,
48731
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47009
48732
  verdict: "OK",
47010
- _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.",
47011
- aiSpecific: true
48733
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=3716, FP=4477, P=45.4%, FPR=1.78%, lift=25.54. v7 was USEFUL (TP=2924, FP=2430, lift=41.22). v8 was OK (TP=792, FP=2047).",
48734
+ aiSpecific: false,
48735
+ _v7Verdict: "USEFUL",
48736
+ _v7Lift: 41.22,
48737
+ _v7Recall: 0.0123,
48738
+ _v7FpRate: 0.0132,
48739
+ _v7Precision: 0.5461,
48740
+ _v8Verdict: "OK",
48741
+ _v8Lift: 9.36
47012
48742
  },
47013
- "security/missing-auth-check": {
47014
- recall: 63e-4,
47015
- fpRate: 4e-4,
47016
- ratio: 15.3,
47017
- precision: 0.9247,
47018
- lastCalibratedAt: "2026-06-26T22:30:00Z",
48743
+ "logic/key-prop-missing": {
48744
+ recall: 16e-4,
48745
+ fpRate: 11e-4,
48746
+ ratio: 574.52,
48747
+ precision: 0.629,
48748
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47019
48749
  verdict: "USEFUL",
47020
- _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.",
47021
- aiSpecific: false
48750
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=468, FP=276, P=62.9%, FPR=0.11%, lift=574.52. v7 was USEFUL (TP=416, FP=250, lift=458.26). v8 was USEFUL (TP=52, FP=26).",
48751
+ aiSpecific: false,
48752
+ _v7Verdict: "USEFUL",
48753
+ _v7Lift: 458.26,
48754
+ _v7Recall: 18e-4,
48755
+ _v7FpRate: 14e-4,
48756
+ _v7Precision: 0.6246,
48757
+ _v8Verdict: "USEFUL",
48758
+ _v8Lift: 1760.69
47022
48759
  },
47023
- "security/dangerous-cors": {
47024
- recall: 5e-4,
47025
- fpRate: 5e-4,
47026
- ratio: 1.05,
47027
- precision: 0.5758,
47028
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48760
+ "logic/ks-distribution-shift": {
48761
+ recall: 0.6889,
48762
+ fpRate: 0.4411,
48763
+ ratio: 1.46,
48764
+ precision: 0.6457,
48765
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47029
48766
  verdict: "NOISY",
47030
- _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.",
47031
- defaultOff: true,
47032
- aiSpecific: true
48767
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=202658, FP=111193, P=64.6%, FPR=44.11%, lift=1.46. v7 was USEFUL (TP=152391, FP=62358, lift=2.09). v8 was INVERTED (TP=50267, FP=48835).",
48768
+ aiSpecific: false,
48769
+ _v7Verdict: "USEFUL",
48770
+ _v7Lift: 2.09,
48771
+ _v7Recall: 0.6431,
48772
+ _v7FpRate: 0.34,
48773
+ _v7Precision: 0.7096,
48774
+ _v8Verdict: "INVERTED",
48775
+ _v8Lift: 0.71,
48776
+ defaultOff: true
47033
48777
  },
47034
- "test/duplicate-setup": {
47035
- recall: 1e-4,
47036
- fpRate: 0,
47037
- ratio: 3.6,
47038
- precision: 0.8235,
47039
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47040
- verdict: "USEFUL",
47041
- _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.",
47042
- aiSpecific: true
47043
- },
47044
- "logic/ghost-defensive": {
47045
- recall: 1e-4,
47046
- fpRate: 0,
47047
- ratio: 5.79,
47048
- precision: 0.8824,
47049
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47050
- verdict: "USEFUL",
47051
- _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.",
47052
- aiSpecific: true
47053
- },
47054
- "typo/calc-raw-px": {
47055
- recall: 0,
47056
- fpRate: 0,
47057
- ratio: 2.32,
47058
- precision: 0.75,
47059
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47060
- verdict: "HYGIENE",
47061
- _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.",
47062
- aiSpecific: false
47063
- },
47064
- "security/fail-open-auth": {
47065
- recall: 0,
47066
- fpRate: 0,
47067
- ratio: 99.99,
47068
- precision: 1,
47069
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48778
+ "logic/math-any-density": {
48779
+ recall: 17e-4,
48780
+ fpRate: 13e-4,
48781
+ ratio: 464.59,
48782
+ precision: 0.6027,
48783
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47070
48784
  verdict: "USEFUL",
47071
- _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.",
47072
- aiSpecific: true
48785
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=496, FP=327, P=60.3%, FPR=0.13%, lift=464.59. v7 was USEFUL (TP=376, FP=247, lift=448.16). v8 was USEFUL (TP=120, FP=80).",
48786
+ aiSpecific: true,
48787
+ _v7Verdict: "USEFUL",
48788
+ _v7Lift: 448.16,
48789
+ _v7Recall: 16e-4,
48790
+ _v7FpRate: 13e-4,
48791
+ _v7Precision: 0.6035,
48792
+ _v8Verdict: "USEFUL",
48793
+ _v8Lift: 515
47073
48794
  },
47074
- "wcag/focus-obscured": {
47075
- recall: 33e-4,
47076
- fpRate: 9e-4,
47077
- ratio: 3.51,
47078
- precision: 0.82,
47079
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47080
- verdict: "HYGIENE",
47081
- _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.",
47082
- aiSpecific: false
47083
- },
47084
- "visual/arbitrary-escape": {
47085
- recall: 25e-4,
47086
- fpRate: 9e-4,
47087
- ratio: 2.74,
47088
- precision: 0.7802,
47089
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48795
+ "logic/math-console-log-storm": {
48796
+ recall: 65e-4,
48797
+ fpRate: 11e-4,
48798
+ ratio: 794.4,
48799
+ precision: 0.8729,
48800
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47090
48801
  verdict: "USEFUL",
47091
- _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.",
47092
- aiSpecific: true
48802
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=1903, FP=277, P=87.3%, FPR=0.11%, lift=794.40. v7 was USEFUL (TP=1678, FP=193, lift=852.30). v8 was USEFUL (TP=225, FP=84).",
48803
+ aiSpecific: true,
48804
+ _v7Verdict: "USEFUL",
48805
+ _v7Lift: 852.3,
48806
+ _v7Recall: 71e-4,
48807
+ _v7FpRate: 11e-4,
48808
+ _v7Precision: 0.8968,
48809
+ _v8Verdict: "USEFUL",
48810
+ _v8Lift: 595.24
47093
48811
  },
47094
- "security/hardcoded-secret": {
48812
+ "logic/math-gini-class-usage": {
47095
48813
  recall: 13e-4,
47096
- fpRate: 7e-4,
47097
- ratio: 1.72,
47098
- precision: 0.6899,
47099
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47100
- verdict: "OK",
47101
- _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.",
47102
- aiSpecific: true
47103
- },
47104
- "visual/radius-scale-violation": {
47105
- recall: 4e-4,
47106
- fpRate: 0,
47107
- ratio: 24.7,
47108
- precision: 0.9697,
47109
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47110
- verdict: "HYGIENE",
47111
- _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.",
47112
- aiSpecific: false
47113
- },
47114
- "test/fake-placeholder": {
47115
- recall: 53e-4,
47116
- fpRate: 19e-4,
47117
- ratio: 2.82,
47118
- precision: 0.7854,
47119
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48814
+ fpRate: 2e-4,
48815
+ ratio: 4648.6,
48816
+ precision: 0.8852,
48817
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47120
48818
  verdict: "USEFUL",
47121
- _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.",
47122
- aiSpecific: true
47123
- },
47124
- "security/exposed-env-var": {
47125
- recall: 6e-4,
47126
- fpRate: 7e-4,
47127
- ratio: 0.9,
47128
- precision: 0.5387,
47129
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47130
- verdict: "HYGIENE",
47131
- _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.",
47132
- aiSpecific: false
47133
- },
47134
- "perf/cls-image": {
47135
- recall: 2e-4,
47136
- fpRate: 3e-4,
47137
- ratio: 0.8,
47138
- precision: 0.5104,
47139
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47140
- verdict: "HYGIENE",
47141
- _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.",
47142
- aiSpecific: false
47143
- },
47144
- "layout/gap-monopoly": {
47145
- recall: 4e-4,
47146
- fpRate: 1e-4,
47147
- ratio: 2.95,
47148
- precision: 0.7928,
47149
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47150
- verdict: "HYGIENE",
47151
- _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.",
47152
- aiSpecific: false
48819
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=370, FP=48, P=88.5%, FPR=0.02%, lift=4648.60. v7 was USEFUL (TP=310, FP=47, lift=3388.64). v8 was USEFUL (TP=60, FP=1).",
48820
+ aiSpecific: true,
48821
+ _v7Verdict: "USEFUL",
48822
+ _v7Lift: 3388.64,
48823
+ _v7Recall: 13e-4,
48824
+ _v7FpRate: 3e-4,
48825
+ _v7Precision: 0.8683,
48826
+ _v8Verdict: "USEFUL",
48827
+ _v8Lift: 67541.31
47153
48828
  },
47154
- "visual/spacing-scale-violation": {
47155
- recall: 83e-4,
47156
- fpRate: 39e-4,
47157
- ratio: 2.13,
47158
- precision: 0.7342,
47159
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47160
- verdict: "HYGIENE",
47161
- _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.",
47162
- aiSpecific: false
47163
- },
47164
- "visual/inline-style-dominance": {
47165
- recall: 96e-4,
47166
- fpRate: 66e-4,
47167
- ratio: 1.46,
47168
- precision: 0.6535,
47169
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47170
- verdict: "HYGIENE",
47171
- _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.",
47172
- aiSpecific: false
47173
- },
47174
- "layout/spacing-grid": {
48829
+ "logic/math-variable-name-entropy": {
47175
48830
  recall: 2e-4,
47176
48831
  fpRate: 1e-4,
47177
- ratio: 2.01,
47178
- precision: 0.7222,
47179
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47180
- verdict: "HYGIENE",
47181
- _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.",
47182
- aiSpecific: false
47183
- },
47184
- "wcag/dragging-movements": {
47185
- recall: 0,
47186
- fpRate: 0,
47187
- ratio: 0.51,
47188
- precision: 0.4,
47189
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47190
- verdict: "HYGIENE",
47191
- _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.",
47192
- aiSpecific: false
48832
+ ratio: 4548.81,
48833
+ precision: 0.6316,
48834
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48835
+ verdict: "USEFUL",
48836
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=60, FP=35, P=63.2%, FPR=0.01%, lift=4548.81. v7 was USEFUL (TP=36, FP=26, lift=4096.07). v8 was USEFUL (TP=24, FP=9).",
48837
+ aiSpecific: false,
48838
+ _v7Verdict: "USEFUL",
48839
+ _v7Lift: 4096.07,
48840
+ _v7Recall: 2e-4,
48841
+ _v7FpRate: 1e-4,
48842
+ _v7Precision: 0.5806,
48843
+ _v8Verdict: "USEFUL",
48844
+ _v8Lift: 5548.85
47193
48845
  },
47194
- "test/weak-assertion": {
47195
- recall: 0.0414,
47196
- fpRate: 86e-4,
47197
- ratio: 4.83,
47198
- precision: 0.8622,
47199
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48846
+ "logic/optimistic-no-rollback": {
48847
+ recall: 12e-4,
48848
+ fpRate: 2e-4,
48849
+ ratio: 3523.57,
48850
+ precision: 0.8527,
48851
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47200
48852
  verdict: "USEFUL",
47201
- _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.",
47202
- aiSpecific: true
48853
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=353, FP=61, P=85.3%, FPR=0.02%, lift=3523.57. v7 was USEFUL (TP=281, FP=60, lift=2519.02). v8 was USEFUL (TP=72, FP=1).",
48854
+ aiSpecific: true,
48855
+ _v7Verdict: "USEFUL",
48856
+ _v7Lift: 2519.02,
48857
+ _v7Recall: 12e-4,
48858
+ _v7FpRate: 3e-4,
48859
+ _v7Precision: 0.824,
48860
+ _v8Verdict: "USEFUL",
48861
+ _v8Lift: 67726.36
47203
48862
  },
47204
- "logic/bayesian-conditional": {
48863
+ "logic/qwik-hook-leak": {
47205
48864
  recall: 0,
47206
48865
  fpRate: 0,
47207
48866
  ratio: 0,
47208
48867
  precision: 0,
47209
- lastCalibratedAt: "2026-06-27T00:00:00Z",
48868
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47210
48869
  verdict: "DORMANT",
47211
- defaultOff: true,
47212
- _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.",
47213
- aiSpecific: true
47214
- },
47215
- "logic/heaps-deviation": {
47216
- recall: 0.0122,
47217
- fpRate: 0.0132,
47218
- ratio: 0.93,
47219
- precision: 0.5461,
47220
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47221
- verdict: "HYGIENE",
47222
- _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.",
47223
- aiSpecific: false
48870
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
48871
+ aiSpecific: true,
48872
+ _v7Verdict: "DORMANT",
48873
+ _v7Lift: 0,
48874
+ _v7Recall: 0,
48875
+ _v7FpRate: 0,
48876
+ _v7Precision: 0,
48877
+ _v8Verdict: "DORMANT",
48878
+ _v8Lift: 1,
48879
+ defaultOff: true
47224
48880
  },
47225
- "logic/ks-distribution-shift": {
47226
- recall: 0.6375,
47227
- fpRate: 0.338,
47228
- ratio: 1.89,
47229
- precision: 0.7096,
47230
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47231
- verdict: "HYGIENE",
47232
- _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.",
47233
- aiSpecific: false
48881
+ "logic/reactive-hook-soup": {
48882
+ recall: 41e-4,
48883
+ fpRate: 6e-4,
48884
+ ratio: 1370.15,
48885
+ precision: 0.8805,
48886
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48887
+ verdict: "USEFUL",
48888
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=1194, FP=162, P=88.1%, FPR=0.06%, lift=1370.15. v7 was USEFUL (TP=901, FP=162, lift=959.64). v8 was USEFUL (TP=293, FP=0).",
48889
+ aiSpecific: true,
48890
+ _v7Verdict: "USEFUL",
48891
+ _v7Lift: 959.64,
48892
+ _v7Recall: 38e-4,
48893
+ _v7FpRate: 9e-4,
48894
+ _v7Precision: 0.8476,
48895
+ _v8Verdict: "USEFUL",
48896
+ _v8Lift: 99999
47234
48897
  },
47235
48898
  "logic/zipf-slope-anomaly": {
47236
- recall: 0.0156,
47237
- fpRate: 87e-4,
47238
- ratio: 1.79,
47239
- precision: 0.6983,
47240
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47241
- verdict: "HYGIENE",
47242
- _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.",
47243
- aiSpecific: false
48899
+ recall: 0.0168,
48900
+ fpRate: 0.0111,
48901
+ ratio: 57.13,
48902
+ precision: 0.6369,
48903
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48904
+ verdict: "USEFUL",
48905
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=4928, FP=2810, P=63.7%, FPR=1.11%, lift=57.13. v7 was USEFUL (TP=3718, FP=1606, lift=79.75). v8 was USEFUL (TP=1210, FP=1204).",
48906
+ aiSpecific: false,
48907
+ _v7Verdict: "USEFUL",
48908
+ _v7Lift: 79.75,
48909
+ _v7Recall: 0.0157,
48910
+ _v7FpRate: 88e-4,
48911
+ _v7Precision: 0.6983,
48912
+ _v8Verdict: "USEFUL",
48913
+ _v8Lift: 28.59
47244
48914
  },
47245
- "ai/markdown-leakage": {
47246
- recall: 0,
48915
+ "logic/zombie-state": {
48916
+ recall: 1e-4,
47247
48917
  fpRate: 0,
47248
- ratio: 1.93,
47249
- precision: 0.7143,
47250
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47251
- verdict: "OK",
47252
- _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.",
47253
- aiSpecific: true
48918
+ ratio: 119891.71,
48919
+ precision: 0.9512,
48920
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48921
+ verdict: "USEFUL",
48922
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=39, FP=2, P=95.1%, FPR=0.00%, lift=119891.71. v7 was USEFUL (TP=24, FP=2, lift=84652.15). v8 was USEFUL (TP=15, FP=0).",
48923
+ aiSpecific: true,
48924
+ _v7Verdict: "USEFUL",
48925
+ _v7Lift: 84652.15,
48926
+ _v7Recall: 1e-4,
48927
+ _v7FpRate: 0,
48928
+ _v7Precision: 0.9231,
48929
+ _v8Verdict: "USEFUL",
48930
+ _v8Lift: 99999
47254
48931
  },
47255
- "ai/comment-ratio": {
47256
- recall: 0.2523,
47257
- fpRate: 0.1619,
47258
- ratio: 1.56,
47259
- precision: 0.6687,
47260
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47261
- verdict: "OK",
47262
- _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.",
47263
- aiSpecific: true
48932
+ "perf/cls-image": {
48933
+ recall: 2e-4,
48934
+ fpRate: 2e-4,
48935
+ ratio: 2895.78,
48936
+ precision: 0.5514,
48937
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48938
+ verdict: "USEFUL",
48939
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=59, FP=48, P=55.1%, FPR=0.02%, lift=2895.78. v7 was USEFUL (TP=49, FP=47, lift=1991.85). v8 was USEFUL (TP=10, FP=1).",
48940
+ aiSpecific: false,
48941
+ _v7Verdict: "USEFUL",
48942
+ _v7Lift: 1991.85,
48943
+ _v7Recall: 2e-4,
48944
+ _v7FpRate: 3e-4,
48945
+ _v7Precision: 0.5104,
48946
+ _v8Verdict: "USEFUL",
48947
+ _v8Lift: 62424.55
47264
48948
  },
47265
- "ai/whitespace-regularity": {
47266
- recall: 0.0731,
47267
- fpRate: 0.0728,
47268
- ratio: 1,
47269
- precision: 0.5652,
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=17466, FP=13438, P=56.5%, FPR=7.28%, lift=1.0. aiSpecific=True.",
47273
- defaultOff: true,
47274
- aiSpecific: true
48949
+ "perf/css-bloat": {
48950
+ recall: 0.0126,
48951
+ fpRate: 24e-4,
48952
+ ratio: 365.63,
48953
+ precision: 0.8616,
48954
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48955
+ verdict: "USEFUL",
48956
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=3697, FP=594, P=86.2%, FPR=0.24%, lift=365.63. v7 was USEFUL (TP=2790, FP=591, lift=256.10). v8 was USEFUL (TP=907, FP=3).",
48957
+ aiSpecific: false,
48958
+ _v7Verdict: "USEFUL",
48959
+ _v7Lift: 256.1,
48960
+ _v7Recall: 0.0118,
48961
+ _v7FpRate: 32e-4,
48962
+ _v7Precision: 0.8252,
48963
+ _v8Verdict: "USEFUL",
48964
+ _v8Lift: 22813.54
47275
48965
  },
47276
- "ai/text-like-ratio": {
48966
+ "perf/halstead-anomaly": {
47277
48967
  recall: 0,
47278
48968
  fpRate: 0,
47279
- ratio: 2.32,
47280
- precision: 0.75,
47281
- lastCalibratedAt: "2026-06-27T12:00:00Z",
48969
+ ratio: 75624,
48970
+ precision: 0.6,
48971
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47282
48972
  verdict: "USEFUL",
47283
- _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.",
47284
- aiSpecific: true
48973
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=3, FP=2, P=60.0%, FPR=0.00%, lift=75624.00. v7 was USEFUL (TP=3, FP=1, lift=137559.75). v8 was INVERTED (TP=0, FP=1).",
48974
+ aiSpecific: true,
48975
+ _v7Verdict: "USEFUL",
48976
+ _v7Lift: 137559.75,
48977
+ _v7Recall: 0,
48978
+ _v7FpRate: 0,
48979
+ _v7Precision: 0.75,
48980
+ _v8Verdict: "INVERTED",
48981
+ _v8Lift: 0
47285
48982
  },
47286
- "ai/errors-near-eof": {
47287
- recall: 0.0697,
47288
- fpRate: 0.0548,
47289
- ratio: 1.27,
47290
- precision: 0.6225,
47291
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47292
- verdict: "NOISY",
47293
- _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.",
47294
- defaultOff: true,
47295
- aiSpecific: true
48983
+ "product/terminology-drift": {
48984
+ recall: 91e-4,
48985
+ fpRate: 21e-4,
48986
+ ratio: 397.75,
48987
+ precision: 0.8347,
48988
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
48989
+ verdict: "USEFUL",
48990
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=2671, FP=529, P=83.5%, FPR=0.21%, lift=397.75. v7 was USEFUL (TP=2028, FP=521, lift=280.09). v8 was USEFUL (TP=643, FP=8).",
48991
+ aiSpecific: false,
48992
+ _v7Verdict: "USEFUL",
48993
+ _v7Lift: 280.09,
48994
+ _v7Recall: 86e-4,
48995
+ _v7FpRate: 28e-4,
48996
+ _v7Precision: 0.7956,
48997
+ _v8Verdict: "USEFUL",
48998
+ _v8Lift: 8477.9
47296
48999
  },
47297
- "ai/any-density": {
47298
- recall: 55e-4,
47299
- fpRate: 41e-4,
47300
- ratio: 1.34,
47301
- precision: 0.634,
47302
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47303
- verdict: "NOISY",
47304
- _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.",
47305
- defaultOff: true,
47306
- aiSpecific: true
49000
+ "product/ux-pattern-fragmentation": {
49001
+ recall: 1e-4,
49002
+ fpRate: 0,
49003
+ ratio: 22864.4,
49004
+ precision: 0.8163,
49005
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49006
+ verdict: "USEFUL",
49007
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=40, FP=9, P=81.6%, FPR=0.00%, lift=22864.40. v7 was USEFUL (TP=32, FP=8, lift=18341.30). v8 was USEFUL (TP=8, FP=1).",
49008
+ aiSpecific: true,
49009
+ _v7Verdict: "USEFUL",
49010
+ _v7Lift: 18341.3,
49011
+ _v7Recall: 1e-4,
49012
+ _v7FpRate: 0,
49013
+ _v7Precision: 0.8,
49014
+ _v8Verdict: "USEFUL",
49015
+ _v8Lift: 61037.33
47307
49016
  },
47308
- "ai/renyi-profile": {
47309
- recall: 0,
49017
+ "rust/stringly-typed": {
49018
+ recall: 2e-4,
47310
49019
  fpRate: 0,
47311
- ratio: 0.26,
47312
- precision: 0.25,
47313
- lastCalibratedAt: "2026-06-27T12:00:00Z",
47314
- verdict: "INVERTED",
47315
- _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.",
47316
- defaultOff: true,
47317
- aiSpecific: true
49020
+ ratio: 24735.12,
49021
+ precision: 0.8831,
49022
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49023
+ verdict: "USEFUL",
49024
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=68, FP=9, P=88.3%, FPR=0.00%, lift=24735.12. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=68, FP=9).",
49025
+ aiSpecific: true,
49026
+ _v7Verdict: "DORMANT",
49027
+ _v7Lift: 1,
49028
+ _v7Recall: 0,
49029
+ _v7FpRate: 0,
49030
+ _v7Precision: 0,
49031
+ _v8Verdict: "USEFUL",
49032
+ _v8Lift: 6737.89
47318
49033
  },
47319
- "ai/log-rank-histogram": {
49034
+ "rust/todo-macro": {
49035
+ recall: 1e-4,
49036
+ fpRate: 7e-4,
49037
+ ratio: 210.08,
49038
+ precision: 0.1392,
49039
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49040
+ verdict: "OK",
49041
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=27, FP=167, P=13.9%, FPR=0.07%, lift=210.08. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was OK (TP=27, FP=167).",
49042
+ aiSpecific: true,
49043
+ _v7Verdict: "DORMANT",
49044
+ _v7Lift: 1,
49045
+ _v7Recall: 0,
49046
+ _v7FpRate: 0,
49047
+ _v7Precision: 0,
49048
+ _v8Verdict: "OK",
49049
+ _v8Lift: 57.23
49050
+ },
49051
+ "rust/unused-pub-fn": {
47320
49052
  recall: 0,
47321
49053
  fpRate: 0,
47322
- ratio: 0,
47323
- precision: 0,
47324
- lastCalibratedAt: "2026-06-27T00:00:00Z",
49054
+ ratio: 10803.43,
49055
+ precision: 0.3,
49056
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47325
49057
  verdict: "OK",
47326
- _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).",
47327
- aiSpecific: true
49058
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=3, FP=7, P=30.0%, FPR=0.00%, lift=10803.43. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was OK (TP=3, FP=7).",
49059
+ aiSpecific: true,
49060
+ _v7Verdict: "DORMANT",
49061
+ _v7Lift: 1,
49062
+ _v7Recall: 0,
49063
+ _v7FpRate: 0,
49064
+ _v7Precision: 0,
49065
+ _v8Verdict: "OK",
49066
+ _v8Lift: 2942.87
47328
49067
  },
47329
- "ai/segment-surprisal-cv": {
47330
- recall: 0.182,
47331
- fpRate: 0.0812,
47332
- ratio: 2.24,
47333
- precision: 0.7438,
47334
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49068
+ "rust/unwrap-in-production": {
49069
+ recall: 8e-3,
49070
+ fpRate: 77e-4,
49071
+ ratio: 70.81,
49072
+ precision: 0.5475,
49073
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47335
49074
  verdict: "USEFUL",
47336
- _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.",
47337
- aiSpecific: true
49075
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=2358, FP=1949, P=54.7%, FPR=0.77%, lift=70.81. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=2358, FP=1949).",
49076
+ aiSpecific: true,
49077
+ _v7Verdict: "DORMANT",
49078
+ _v7Lift: 1,
49079
+ _v7Recall: 0,
49080
+ _v7FpRate: 0,
49081
+ _v7Precision: 0,
49082
+ _v8Verdict: "USEFUL",
49083
+ _v8Lift: 19.29
47338
49084
  },
47339
- "ai/compression-profile": {
47340
- recall: 0.3139,
47341
- fpRate: 0.1489,
47342
- ratio: 2.11,
47343
- precision: 0.732,
47344
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49085
+ "security/dangerous-cors": {
49086
+ recall: 5e-4,
49087
+ fpRate: 4e-4,
49088
+ ratio: 1721.87,
49089
+ precision: 0.6079,
49090
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47345
49091
  verdict: "USEFUL",
47346
- _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.",
47347
- aiSpecific: true
49092
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=138, FP=89, P=60.8%, FPR=0.04%, lift=1721.87. v7 was USEFUL (TP=114, FP=84, lift=1257.16). v8 was USEFUL (TP=24, FP=5).",
49093
+ aiSpecific: true,
49094
+ _v7Verdict: "USEFUL",
49095
+ _v7Lift: 1257.16,
49096
+ _v7Recall: 5e-4,
49097
+ _v7FpRate: 5e-4,
49098
+ _v7Precision: 0.5758,
49099
+ _v8Verdict: "USEFUL",
49100
+ _v8Lift: 11365.57
47348
49101
  },
47349
- "ai/tailwind-color-overuse": {
47350
- recall: 0.0216,
47351
- fpRate: 52e-4,
47352
- ratio: 4.16,
47353
- precision: 0.8436,
47354
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49102
+ "security/eval": {
49103
+ recall: 1e-4,
49104
+ fpRate: 2e-4,
49105
+ ratio: 1929.18,
49106
+ precision: 0.4286,
49107
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49108
+ verdict: "OK",
49109
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=42, FP=56, P=42.9%, FPR=0.02%, lift=1929.18. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was OK (TP=42, FP=56).",
49110
+ aiSpecific: false,
49111
+ _v7Verdict: "DORMANT",
49112
+ _v7Lift: 1,
49113
+ _v7Recall: 0,
49114
+ _v7FpRate: 0,
49115
+ _v7Precision: 0,
49116
+ _v8Verdict: "OK",
49117
+ _v8Lift: 525.51
49118
+ },
49119
+ "security/exposed-env-var": {
49120
+ recall: 6e-4,
49121
+ fpRate: 5e-4,
49122
+ ratio: 1055.81,
49123
+ precision: 0.5696,
49124
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47355
49125
  verdict: "USEFUL",
47356
- _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.",
47357
- aiSpecific: true
49126
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=180, FP=136, P=57.0%, FPR=0.05%, lift=1055.81. v7 was USEFUL (TP=146, FP=125, lift=790.50). v8 was USEFUL (TP=34, FP=11).",
49127
+ aiSpecific: false,
49128
+ _v7Verdict: "USEFUL",
49129
+ _v7Lift: 790.5,
49130
+ _v7Recall: 6e-4,
49131
+ _v7FpRate: 7e-4,
49132
+ _v7Precision: 0.5387,
49133
+ _v8Verdict: "USEFUL",
49134
+ _v8Lift: 4716.52
47358
49135
  },
47359
- "ai/default-react-stack": {
47360
- recall: 1e-3,
49136
+ "security/fail-open-auth": {
49137
+ recall: 0,
47361
49138
  fpRate: 0,
47362
- ratio: 99.99,
47363
- precision: 0.9957,
47364
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49139
+ ratio: 99999,
49140
+ precision: 1,
49141
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47365
49142
  verdict: "USEFUL",
47366
- _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.",
47367
- aiSpecific: true
49143
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=1, FP=0, P=100.0%, FPR=0.00%, lift=inf. v7 was USEFUL (TP=1, FP=0, lift=inf). v8 was DORMANT (TP=0, FP=0).",
49144
+ aiSpecific: true,
49145
+ _v7Verdict: "USEFUL",
49146
+ _v7Lift: 99999,
49147
+ _v7Recall: 0,
49148
+ _v7FpRate: 0,
49149
+ _v7Precision: 1,
49150
+ _v8Verdict: "DORMANT",
49151
+ _v8Lift: 1
47368
49152
  },
47369
- "ai/library-reinvention": {
47370
- recall: 3e-4,
49153
+ "security/hardcoded-secret": {
49154
+ recall: 14e-4,
49155
+ fpRate: 6e-4,
49156
+ ratio: 1269.08,
49157
+ precision: 0.735,
49158
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49159
+ verdict: "USEFUL",
49160
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=405, FP=146, P=73.5%, FPR=0.06%, lift=1269.08. v7 was USEFUL (TP=307, FP=138, lift=916.92). v8 was USEFUL (TP=98, FP=8).",
49161
+ aiSpecific: true,
49162
+ _v7Verdict: "USEFUL",
49163
+ _v7Lift: 916.92,
49164
+ _v7Recall: 13e-4,
49165
+ _v7FpRate: 8e-4,
49166
+ _v7Precision: 0.6899,
49167
+ _v8Verdict: "USEFUL",
49168
+ _v8Lift: 7935.57
49169
+ },
49170
+ "security/localstorage-token": {
49171
+ recall: 1e-4,
47371
49172
  fpRate: 0,
47372
- ratio: 9.88,
47373
- precision: 0.9275,
47374
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49173
+ ratio: 99999,
49174
+ precision: 1,
49175
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47375
49176
  verdict: "USEFUL",
47376
- _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.",
47377
- aiSpecific: true
49177
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=17, FP=0, P=100.0%, FPR=0.00%, lift=inf. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=17, FP=0).",
49178
+ aiSpecific: false,
49179
+ _v7Verdict: "DORMANT",
49180
+ _v7Lift: 1,
49181
+ _v7Recall: 0,
49182
+ _v7FpRate: 0,
49183
+ _v7Precision: 0,
49184
+ _v8Verdict: "USEFUL",
49185
+ _v8Lift: 99999
47378
49186
  },
47379
- "ai/state-default-overuse": {
47380
- recall: 29e-4,
47381
- fpRate: 9e-4,
47382
- ratio: 3.42,
47383
- precision: 0.8161,
47384
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49187
+ "security/missing-auth-check": {
49188
+ recall: 5e-4,
49189
+ fpRate: 0,
49190
+ ratio: 99999,
49191
+ precision: 1,
49192
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47385
49193
  verdict: "USEFUL",
47386
- _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.",
47387
- aiSpecific: true
49194
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=157, FP=0, P=100.0%, FPR=0.00%, lift=inf. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=157, FP=0).",
49195
+ aiSpecific: false,
49196
+ _v7Verdict: "DORMANT",
49197
+ _v7Lift: 1,
49198
+ _v7Recall: 0,
49199
+ _v7FpRate: 0,
49200
+ _v7Precision: 0,
49201
+ _v8Verdict: "USEFUL",
49202
+ _v8Lift: 99999
47388
49203
  },
47389
- "ai/fetch-default-overuse": {
47390
- recall: 28e-4,
47391
- fpRate: 4e-4,
47392
- ratio: 6.76,
47393
- precision: 0.8976,
47394
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49204
+ "security/public-admin-route": {
49205
+ recall: 38e-4,
49206
+ fpRate: 38e-4,
49207
+ ratio: 142.2,
49208
+ precision: 0.5376,
49209
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47395
49210
  verdict: "USEFUL",
47396
- _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.",
47397
- aiSpecific: true
49211
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=1108, FP=953, P=53.8%, FPR=0.38%, lift=142.20. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=1108, FP=953).",
49212
+ aiSpecific: false,
49213
+ _v7Verdict: "DORMANT",
49214
+ _v7Lift: 1,
49215
+ _v7Recall: 0,
49216
+ _v7FpRate: 0,
49217
+ _v7Precision: 0,
49218
+ _v8Verdict: "USEFUL",
49219
+ _v8Lift: 38.74
47398
49220
  },
47399
- "ai/console-debug-storm": {
47400
- recall: 8e-3,
47401
- fpRate: 9e-4,
47402
- ratio: 8.43,
47403
- precision: 0.9161,
47404
- lastCalibratedAt: "2026-06-27T12:00:00Z",
49221
+ "security/sql-construction": {
49222
+ recall: 32e-4,
49223
+ fpRate: 15e-4,
49224
+ ratio: 485.42,
49225
+ precision: 0.7183,
49226
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47405
49227
  verdict: "USEFUL",
47406
- _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.",
47407
- aiSpecific: true
49228
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=951, FP=373, P=71.8%, FPR=0.15%, lift=485.42. v7 was USEFUL (TP=710, FP=336, lift=370.52). v8 was USEFUL (TP=241, FP=37).",
49229
+ aiSpecific: true,
49230
+ _v7Verdict: "USEFUL",
49231
+ _v7Lift: 370.52,
49232
+ _v7Recall: 3e-3,
49233
+ _v7FpRate: 18e-4,
49234
+ _v7Precision: 0.6788,
49235
+ _v8Verdict: "USEFUL",
49236
+ _v8Lift: 1608.86
47408
49237
  },
47409
- "db/missing-fk-index": {
47410
- recall: 0,
49238
+ "security/target-blank-no-noopener": {
49239
+ recall: 4e-4,
47411
49240
  fpRate: 0,
47412
- ratio: 0,
47413
- precision: 0,
47414
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47415
- verdict: "DORMANT",
47416
- defaultOff: true,
47417
- _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.)",
47418
- aiSpecific: false
49241
+ ratio: 26141.63,
49242
+ precision: 0.9333,
49243
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49244
+ verdict: "USEFUL",
49245
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=126, FP=9, P=93.3%, FPR=0.00%, lift=26141.63. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=126, FP=9).",
49246
+ aiSpecific: false,
49247
+ _v7Verdict: "DORMANT",
49248
+ _v7Lift: 1,
49249
+ _v7Recall: 0,
49250
+ _v7FpRate: 0,
49251
+ _v7Precision: 0,
49252
+ _v8Verdict: "USEFUL",
49253
+ _v8Lift: 7121.02
47419
49254
  },
47420
- "db/duplicate-index": {
47421
- recall: 0,
47422
- fpRate: 0,
47423
- ratio: 0,
47424
- precision: 0,
47425
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47426
- verdict: "DORMANT",
47427
- defaultOff: true,
47428
- _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.)",
47429
- aiSpecific: false
49255
+ "security/unsafe-html-render": {
49256
+ recall: 13e-4,
49257
+ fpRate: 11e-4,
49258
+ ratio: 513.12,
49259
+ precision: 0.574,
49260
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49261
+ verdict: "USEFUL",
49262
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=380, FP=282, P=57.4%, FPR=0.11%, lift=513.12. v7 was USEFUL (TP=312, FP=160, lift=757.74). v8 was OK (TP=68, FP=122).",
49263
+ aiSpecific: false,
49264
+ _v7Verdict: "USEFUL",
49265
+ _v7Lift: 757.74,
49266
+ _v7Recall: 13e-4,
49267
+ _v7FpRate: 9e-4,
49268
+ _v7Precision: 0.661,
49269
+ _v8Verdict: "OK",
49270
+ _v8Lift: 201.44
47430
49271
  },
47431
- "db/missing-not-null": {
47432
- recall: 0,
49272
+ "test/duplicate-setup": {
49273
+ recall: 1e-4,
47433
49274
  fpRate: 0,
47434
- ratio: 0,
47435
- precision: 0,
47436
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47437
- verdict: "DORMANT",
47438
- defaultOff: true,
47439
- _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.)",
47440
- aiSpecific: false
49275
+ ratio: 51016.19,
49276
+ precision: 0.8095,
49277
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49278
+ verdict: "USEFUL",
49279
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=17, FP=4, P=81.0%, FPR=0.00%, lift=51016.19. v7 was USEFUL (TP=14, FP=3, lift=50348.67). v8 was USEFUL (TP=3, FP=1).",
49280
+ aiSpecific: true,
49281
+ _v7Verdict: "USEFUL",
49282
+ _v7Lift: 50348.67,
49283
+ _v7Recall: 1e-4,
49284
+ _v7FpRate: 0,
49285
+ _v7Precision: 0.8235,
49286
+ _v8Verdict: "USEFUL",
49287
+ _v8Lift: 51500.25
47441
49288
  },
47442
- "db/enum-sprawl": {
47443
- recall: 0,
47444
- fpRate: 0,
47445
- ratio: 0,
47446
- precision: 0,
47447
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47448
- verdict: "DORMANT",
47449
- defaultOff: true,
47450
- _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.)",
47451
- aiSpecific: false
49289
+ "test/fake-placeholder": {
49290
+ recall: 51e-4,
49291
+ fpRate: 15e-4,
49292
+ ratio: 547.47,
49293
+ precision: 0.8014,
49294
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49295
+ verdict: "USEFUL",
49296
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=1489, FP=369, P=80.1%, FPR=0.15%, lift=547.47. v7 was USEFUL (TP=1259, FP=344, lift=418.76). v8 was USEFUL (TP=230, FP=25).",
49297
+ aiSpecific: true,
49298
+ _v7Verdict: "USEFUL",
49299
+ _v7Lift: 418.76,
49300
+ _v7Recall: 53e-4,
49301
+ _v7FpRate: 19e-4,
49302
+ _v7Precision: 0.7854,
49303
+ _v8Verdict: "USEFUL",
49304
+ _v8Lift: 2477.4
47452
49305
  },
47453
- "db/naming-inconsistency": {
49306
+ "test/missing-edge-case": {
47454
49307
  recall: 0,
47455
49308
  fpRate: 0,
47456
49309
  ratio: 0,
47457
49310
  precision: 0,
47458
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49311
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47459
49312
  verdict: "DORMANT",
47460
- defaultOff: true,
47461
- _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.)",
47462
- aiSpecific: false
49313
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
49314
+ aiSpecific: true,
49315
+ _v7Verdict: "DORMANT",
49316
+ _v7Lift: 0,
49317
+ _v7Recall: 0,
49318
+ _v7FpRate: 0,
49319
+ _v7Precision: 0,
49320
+ _v8Verdict: "DORMANT",
49321
+ _v8Lift: 1,
49322
+ defaultOff: true
47463
49323
  },
47464
- "db/sql-concat": {
47465
- recall: 0,
47466
- fpRate: 0,
47467
- ratio: 0,
47468
- precision: 0,
47469
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47470
- verdict: "DORMANT",
47471
- defaultOff: true,
47472
- _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.)",
47473
- aiSpecific: true
49324
+ "test/weak-assertion": {
49325
+ recall: 0.0417,
49326
+ fpRate: 67e-4,
49327
+ ratio: 131.62,
49328
+ precision: 0.8793,
49329
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49330
+ verdict: "USEFUL",
49331
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=12263, FP=1684, P=87.9%, FPR=0.67%, lift=131.62. v7 was USEFUL (TP=9906, FP=1583, lift=99.90). v8 was USEFUL (TP=2357, FP=101).",
49332
+ aiSpecific: true,
49333
+ _v7Verdict: "USEFUL",
49334
+ _v7Lift: 99.9,
49335
+ _v7Recall: 0.0418,
49336
+ _v7FpRate: 86e-4,
49337
+ _v7Precision: 0.8622,
49338
+ _v8Verdict: "USEFUL",
49339
+ _v8Lift: 651.94
47474
49340
  },
47475
- "dead/unused-import": {
49341
+ "typo/calc-fontsize": {
47476
49342
  recall: 0,
47477
49343
  fpRate: 0,
47478
49344
  ratio: 0,
47479
49345
  precision: 0,
47480
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49346
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47481
49347
  verdict: "DORMANT",
47482
- defaultOff: true,
47483
- _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.",
47484
- aiSpecific: true
49348
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
49349
+ aiSpecific: false,
49350
+ _v7Verdict: "DORMANT",
49351
+ _v7Lift: 0,
49352
+ _v7Recall: 0,
49353
+ _v7FpRate: 0,
49354
+ _v7Precision: 0,
49355
+ _v8Verdict: "DORMANT",
49356
+ _v8Lift: 1,
49357
+ defaultOff: true
47485
49358
  },
47486
- "dead/unused-local": {
49359
+ "typo/calc-raw-px": {
47487
49360
  recall: 0,
47488
49361
  fpRate: 0,
47489
- ratio: 0,
47490
- precision: 0,
47491
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47492
- verdict: "DORMANT",
47493
- defaultOff: true,
47494
- _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).",
47495
- aiSpecific: true
49362
+ ratio: 210066.67,
49363
+ precision: 0.8333,
49364
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49365
+ verdict: "USEFUL",
49366
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=5, FP=1, P=83.3%, FPR=0.00%, lift=210066.67. v7 was USEFUL (TP=3, FP=1, lift=137559.75). v8 was USEFUL (TP=2, FP=0).",
49367
+ aiSpecific: false,
49368
+ _v7Verdict: "USEFUL",
49369
+ _v7Lift: 137559.75,
49370
+ _v7Recall: 0,
49371
+ _v7FpRate: 0,
49372
+ _v7Precision: 0.75,
49373
+ _v8Verdict: "USEFUL",
49374
+ _v8Lift: 99999
47496
49375
  },
47497
- "dead/unused-parameter": {
49376
+ "typo/clamp-offscale": {
47498
49377
  recall: 0,
47499
49378
  fpRate: 0,
47500
49379
  ratio: 0,
47501
49380
  precision: 0,
47502
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49381
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47503
49382
  verdict: "DORMANT",
47504
- defaultOff: true,
47505
- _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.",
47506
- aiSpecific: true
49383
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
49384
+ aiSpecific: false,
49385
+ _v7Verdict: "DORMANT",
49386
+ _v7Lift: 0,
49387
+ _v7Recall: 0,
49388
+ _v7FpRate: 0,
49389
+ _v7Precision: 0,
49390
+ _v8Verdict: "DORMANT",
49391
+ _v8Lift: 1,
49392
+ defaultOff: true
47507
49393
  },
47508
- "dead/dead-branch": {
47509
- recall: 0,
47510
- fpRate: 0,
47511
- ratio: 0,
47512
- precision: 0,
47513
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47514
- verdict: "DORMANT",
47515
- defaultOff: true,
47516
- _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.",
47517
- aiSpecific: true
49394
+ "typo/math-button-label-uniformity": {
49395
+ recall: 1e-4,
49396
+ fpRate: 1e-4,
49397
+ ratio: 6894.19,
49398
+ precision: 0.629,
49399
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49400
+ verdict: "USEFUL",
49401
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=39, FP=23, P=62.9%, FPR=0.01%, lift=6894.19. v7 was USEFUL (TP=37, FP=21, lift=5571.66). v8 was USEFUL (TP=2, FP=2).",
49402
+ aiSpecific: false,
49403
+ _v7Verdict: "USEFUL",
49404
+ _v7Lift: 5571.66,
49405
+ _v7Recall: 2e-4,
49406
+ _v7FpRate: 1e-4,
49407
+ _v7Precision: 0.6379,
49408
+ _v8Verdict: "USEFUL",
49409
+ _v8Lift: 17166.75
47518
49410
  },
47519
- "dead/unreachable": {
49411
+ "typo/math-cta-vocabulary": {
47520
49412
  recall: 0,
47521
49413
  fpRate: 0,
47522
49414
  ratio: 0,
47523
49415
  precision: 0,
47524
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49416
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47525
49417
  verdict: "DORMANT",
47526
- defaultOff: true,
47527
- _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.",
47528
- aiSpecific: true
49418
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
49419
+ aiSpecific: true,
49420
+ _v7Verdict: "DORMANT",
49421
+ _v7Lift: 0,
49422
+ _v7Recall: 0,
49423
+ _v7FpRate: 0,
49424
+ _v7Precision: 0,
49425
+ _v8Verdict: "DORMANT",
49426
+ _v8Lift: 1,
49427
+ defaultOff: true
47529
49428
  },
47530
- "docs/stale-package-reference": {
47531
- recall: 0,
49429
+ "typo/placeholder-text": {
49430
+ recall: 1e-4,
47532
49431
  fpRate: 0,
47533
- ratio: 0,
47534
- precision: 0,
47535
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47536
- verdict: "DORMANT",
47537
- defaultOff: true,
47538
- _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.)",
47539
- aiSpecific: false
49432
+ ratio: 17330.5,
49433
+ precision: 0.6875,
49434
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49435
+ verdict: "USEFUL",
49436
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=22, FP=10, P=68.8%, FPR=0.00%, lift=17330.50. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=22, FP=10).",
49437
+ aiSpecific: false,
49438
+ _v7Verdict: "DORMANT",
49439
+ _v7Lift: 1,
49440
+ _v7Recall: 0,
49441
+ _v7FpRate: 0,
49442
+ _v7Precision: 0,
49443
+ _v8Verdict: "USEFUL",
49444
+ _v8Lift: 4720.86
47540
49445
  },
47541
- "docs/stale-function-reference": {
49446
+ "visual/arbitrary-escape": {
49447
+ recall: 26e-4,
49448
+ fpRate: 7e-4,
49449
+ ratio: 1219.67,
49450
+ precision: 0.8177,
49451
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49452
+ verdict: "USEFUL",
49453
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=758, FP=169, P=81.8%, FPR=0.07%, lift=1219.67. v7 was USEFUL (TP=600, FP=169, lift=846.78). v8 was USEFUL (TP=158, FP=0).",
49454
+ aiSpecific: true,
49455
+ _v7Verdict: "USEFUL",
49456
+ _v7Lift: 846.78,
49457
+ _v7Recall: 25e-4,
49458
+ _v7FpRate: 9e-4,
49459
+ _v7Precision: 0.7802,
49460
+ _v8Verdict: "USEFUL",
49461
+ _v8Lift: 99999
49462
+ },
49463
+ "visual/clamp-soup": {
47542
49464
  recall: 0,
47543
49465
  fpRate: 0,
47544
49466
  ratio: 0,
47545
49467
  precision: 0,
47546
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49468
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47547
49469
  verdict: "DORMANT",
47548
- defaultOff: true,
47549
- _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.)",
47550
- aiSpecific: false
49470
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
49471
+ aiSpecific: true,
49472
+ _v7Verdict: "DORMANT",
49473
+ _v7Lift: 0,
49474
+ _v7Recall: 0,
49475
+ _v7FpRate: 0,
49476
+ _v7Precision: 0,
49477
+ _v8Verdict: "DORMANT",
49478
+ _v8Lift: 1,
49479
+ defaultOff: true
47551
49480
  },
47552
- "docs/expired-code-example": {
49481
+ "visual/generic-centering": {
47553
49482
  recall: 0,
47554
49483
  fpRate: 0,
47555
49484
  ratio: 0,
47556
49485
  precision: 0,
47557
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49486
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47558
49487
  verdict: "DORMANT",
47559
- defaultOff: true,
47560
- _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.)",
47561
- aiSpecific: false
49488
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
49489
+ aiSpecific: true,
49490
+ _v7Verdict: "DORMANT",
49491
+ _v7Lift: 0,
49492
+ _v7Recall: 0,
49493
+ _v7FpRate: 0,
49494
+ _v7Precision: 0,
49495
+ _v8Verdict: "DORMANT",
49496
+ _v8Lift: 1,
49497
+ defaultOff: true
47562
49498
  },
47563
- "docs/broken-link": {
47564
- recall: 0,
49499
+ "visual/inline-style-dominance": {
49500
+ recall: 0.0103,
49501
+ fpRate: 52e-4,
49502
+ ratio: 134.59,
49503
+ precision: 0.6983,
49504
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49505
+ verdict: "USEFUL",
49506
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=3028, FP=1308, P=69.8%, FPR=0.52%, lift=134.59. v7 was USEFUL (TP=2303, FP=1221, lift=98.17). v8 was USEFUL (TP=725, FP=87).",
49507
+ aiSpecific: false,
49508
+ _v7Verdict: "USEFUL",
49509
+ _v7Lift: 98.17,
49510
+ _v7Recall: 97e-4,
49511
+ _v7FpRate: 67e-4,
49512
+ _v7Precision: 0.6535,
49513
+ _v8Verdict: "USEFUL",
49514
+ _v8Lift: 704.71
49515
+ },
49516
+ "visual/math-color-cluster": {
49517
+ recall: 2e-4,
47565
49518
  fpRate: 0,
47566
- ratio: 0,
47567
- precision: 0,
47568
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47569
- verdict: "DORMANT",
47570
- defaultOff: true,
47571
- _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.)",
47572
- aiSpecific: false
49519
+ ratio: 46814.86,
49520
+ precision: 0.9286,
49521
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49522
+ verdict: "USEFUL",
49523
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=65, FP=5, P=92.9%, FPR=0.00%, lift=46814.86. v7 was USEFUL (TP=58, FP=5, lift=33771.28). v8 was USEFUL (TP=7, FP=0).",
49524
+ aiSpecific: true,
49525
+ _v7Verdict: "USEFUL",
49526
+ _v7Lift: 33771.28,
49527
+ _v7Recall: 2e-4,
49528
+ _v7FpRate: 0,
49529
+ _v7Precision: 0.9206,
49530
+ _v8Verdict: "USEFUL",
49531
+ _v8Lift: 99999
47573
49532
  },
47574
- "security/eval": {
49533
+ "visual/math-default-font": {
49534
+ recall: 16e-4,
49535
+ fpRate: 3e-4,
49536
+ ratio: 3035.16,
49537
+ precision: 0.8669,
49538
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49539
+ verdict: "USEFUL",
49540
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=469, FP=72, P=86.7%, FPR=0.03%, lift=3035.16. v7 was USEFUL (TP=313, FP=71, lift=2105.64). v8 was USEFUL (TP=156, FP=1).",
49541
+ aiSpecific: true,
49542
+ _v7Verdict: "USEFUL",
49543
+ _v7Lift: 2105.64,
49544
+ _v7Recall: 13e-4,
49545
+ _v7FpRate: 4e-4,
49546
+ _v7Precision: 0.8151,
49547
+ _v8Verdict: "USEFUL",
49548
+ _v8Lift: 68229.63
49549
+ },
49550
+ "visual/math-font-entropy": {
49551
+ recall: 52e-4,
49552
+ fpRate: 1e-3,
49553
+ ratio: 869.95,
49554
+ precision: 0.8593,
49555
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49556
+ verdict: "USEFUL",
49557
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=1521, FP=249, P=85.9%, FPR=0.10%, lift=869.95. v7 was USEFUL (TP=1067, FP=248, lift=600.09). v8 was USEFUL (TP=454, FP=1).",
49558
+ aiSpecific: true,
49559
+ _v7Verdict: "USEFUL",
49560
+ _v7Lift: 600.09,
49561
+ _v7Recall: 45e-4,
49562
+ _v7FpRate: 14e-4,
49563
+ _v7Precision: 0.8114,
49564
+ _v8Verdict: "USEFUL",
49565
+ _v8Lift: 68516.08
49566
+ },
49567
+ "visual/math-gradient-hue-rotation": {
47575
49568
  recall: 0,
47576
49569
  fpRate: 0,
47577
49570
  ratio: 0,
47578
49571
  precision: 0,
47579
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49572
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47580
49573
  verdict: "DORMANT",
47581
- defaultOff: true,
47582
- _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.)",
47583
- aiSpecific: false
49574
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
49575
+ aiSpecific: true,
49576
+ _v7Verdict: "DORMANT",
49577
+ _v7Lift: 0,
49578
+ _v7Recall: 0,
49579
+ _v7FpRate: 0,
49580
+ _v7Precision: 0,
49581
+ _v8Verdict: "DORMANT",
49582
+ _v8Lift: 1,
49583
+ defaultOff: true
47584
49584
  },
47585
- "security/localstorage-token": {
47586
- recall: 0,
49585
+ "visual/math-rounded-entropy": {
49586
+ recall: 38e-4,
49587
+ fpRate: 2e-4,
49588
+ ratio: 3785.45,
49589
+ precision: 0.9461,
49590
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49591
+ verdict: "USEFUL",
49592
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=1105, FP=63, P=94.6%, FPR=0.02%, lift=3785.45. v7 was USEFUL (TP=876, FP=62, lift=2762.74). v8 was USEFUL (TP=229, FP=1).",
49593
+ aiSpecific: true,
49594
+ _v7Verdict: "USEFUL",
49595
+ _v7Lift: 2762.74,
49596
+ _v7Recall: 37e-4,
49597
+ _v7FpRate: 3e-4,
49598
+ _v7Precision: 0.9339,
49599
+ _v8Verdict: "USEFUL",
49600
+ _v8Lift: 68368.45
49601
+ },
49602
+ "visual/math-spacing-entropy": {
49603
+ recall: 18e-4,
49604
+ fpRate: 4e-4,
49605
+ ratio: 1898.99,
49606
+ precision: 0.8287,
49607
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49608
+ verdict: "USEFUL",
49609
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=532, FP=110, P=82.9%, FPR=0.04%, lift=1898.99. v7 was USEFUL (TP=425, FP=109, lift=1339.22). v8 was USEFUL (TP=107, FP=1).",
49610
+ aiSpecific: true,
49611
+ _v7Verdict: "USEFUL",
49612
+ _v7Lift: 1339.22,
49613
+ _v7Recall: 18e-4,
49614
+ _v7FpRate: 6e-4,
49615
+ _v7Precision: 0.7959,
49616
+ _v8Verdict: "USEFUL",
49617
+ _v8Lift: 68031.19
49618
+ },
49619
+ "visual/naturalness-anomaly": {
49620
+ recall: 0.1729,
49621
+ fpRate: 0.0687,
49622
+ ratio: 10.86,
49623
+ precision: 0.746,
49624
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49625
+ verdict: "USEFUL",
49626
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=50852, FP=17316, P=74.6%, FPR=6.87%, lift=10.86. v7 was USEFUL (TP=39319, FP=11382, lift=12.50). v8 was USEFUL (TP=11533, FP=5934).",
49627
+ aiSpecific: true,
49628
+ _v7Verdict: "USEFUL",
49629
+ _v7Lift: 12.5,
49630
+ _v7Recall: 0.1659,
49631
+ _v7FpRate: 0.0621,
49632
+ _v7Precision: 0.7755,
49633
+ _v8Verdict: "USEFUL",
49634
+ _v8Lift: 7.64
49635
+ },
49636
+ "visual/radius-scale-violation": {
49637
+ recall: 4e-4,
47587
49638
  fpRate: 0,
47588
- ratio: 0,
47589
- precision: 0,
47590
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47591
- verdict: "DORMANT",
47592
- defaultOff: true,
47593
- _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.)",
47594
- aiSpecific: false
49639
+ ratio: 82131.33,
49640
+ precision: 0.9774,
49641
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49642
+ verdict: "USEFUL",
49643
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=130, FP=3, P=97.7%, FPR=0.00%, lift=82131.33. v7 was USEFUL (TP=96, FP=3, lift=59285.01). v8 was USEFUL (TP=34, FP=0).",
49644
+ aiSpecific: false,
49645
+ _v7Verdict: "USEFUL",
49646
+ _v7Lift: 59285.01,
49647
+ _v7Recall: 4e-4,
49648
+ _v7FpRate: 0,
49649
+ _v7Precision: 0.9697,
49650
+ _v8Verdict: "USEFUL",
49651
+ _v8Lift: 99999
47595
49652
  },
47596
- "security/target-blank-no-noopener": {
49653
+ "visual/spacing-scale-violation": {
49654
+ recall: 86e-4,
49655
+ fpRate: 28e-4,
49656
+ ratio: 273.97,
49657
+ precision: 0.7792,
49658
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49659
+ verdict: "USEFUL",
49660
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=2531, FP=717, P=77.9%, FPR=0.28%, lift=273.97. v7 was USEFUL (TP=1981, FP=717, lift=187.83). v8 was USEFUL (TP=550, FP=0).",
49661
+ aiSpecific: false,
49662
+ _v7Verdict: "USEFUL",
49663
+ _v7Lift: 187.83,
49664
+ _v7Recall: 84e-4,
49665
+ _v7FpRate: 39e-4,
49666
+ _v7Precision: 0.7342,
49667
+ _v8Verdict: "USEFUL",
49668
+ _v8Lift: 99999
49669
+ },
49670
+ "wcag/dragging-movements": {
47597
49671
  recall: 0,
47598
49672
  fpRate: 0,
47599
- ratio: 0,
47600
- precision: 0,
47601
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47602
- verdict: "DORMANT",
47603
- defaultOff: true,
47604
- _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.)',
47605
- aiSpecific: false
49673
+ ratio: 33610.67,
49674
+ precision: 0.4,
49675
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49676
+ verdict: "OK",
49677
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=2, FP=3, P=40.0%, FPR=0.00%, lift=33610.67. v7 was OK (TP=2, FP=3, lift=24455.07). v8 was DORMANT (TP=0, FP=0).",
49678
+ aiSpecific: false,
49679
+ _v7Verdict: "OK",
49680
+ _v7Lift: 24455.07,
49681
+ _v7Recall: 0,
49682
+ _v7FpRate: 0,
49683
+ _v7Precision: 0.4,
49684
+ _v8Verdict: "DORMANT",
49685
+ _v8Lift: 1
49686
+ },
49687
+ "wcag/focus-appearance": {
49688
+ recall: 28e-4,
49689
+ fpRate: 1e-4,
49690
+ ratio: 8397.24,
49691
+ precision: 0.966,
49692
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49693
+ verdict: "USEFUL",
49694
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=825, FP=29, P=96.6%, FPR=0.01%, lift=8397.24. v7 was USEFUL (TP=612, FP=24, lift=7353.82). v8 was USEFUL (TP=213, FP=5).",
49695
+ aiSpecific: false,
49696
+ _v7Verdict: "USEFUL",
49697
+ _v7Lift: 7353.82,
49698
+ _v7Recall: 26e-4,
49699
+ _v7FpRate: 1e-4,
49700
+ _v7Precision: 0.9623,
49701
+ _v8Verdict: "USEFUL",
49702
+ _v8Lift: 13418.41
49703
+ },
49704
+ "wcag/focus-obscured": {
49705
+ recall: 33e-4,
49706
+ fpRate: 7e-4,
49707
+ ratio: 1214.21,
49708
+ precision: 0.8478,
49709
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49710
+ verdict: "USEFUL",
49711
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=980, FP=176, P=84.8%, FPR=0.07%, lift=1214.21. v7 was USEFUL (TP=797, FP=175, lift=859.38). v8 was USEFUL (TP=183, FP=1).",
49712
+ aiSpecific: false,
49713
+ _v7Verdict: "USEFUL",
49714
+ _v7Lift: 859.38,
49715
+ _v7Recall: 34e-4,
49716
+ _v7FpRate: 1e-3,
49717
+ _v7Precision: 0.82,
49718
+ _v8Verdict: "USEFUL",
49719
+ _v8Lift: 68293.81
47606
49720
  },
47607
49721
  "wcag/missing-alt": {
47608
- recall: 0,
47609
- fpRate: 0,
47610
- ratio: 0,
47611
- precision: 0,
47612
- lastCalibratedAt: "2026-06-30T00:00:00Z",
47613
- verdict: "DORMANT",
47614
- defaultOff: true,
47615
- _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.)',
47616
- aiSpecific: false
49722
+ recall: 11e-4,
49723
+ fpRate: 7e-4,
49724
+ ratio: 935.33,
49725
+ precision: 0.6456,
49726
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
49727
+ verdict: "USEFUL",
49728
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): v7+v8 combined corpus (252080 neg + 294178 pos). v8.5 TP=317, FP=174, P=64.6%, FPR=0.07%, lift=935.33. v7 was DORMANT (TP=0, FP=0, lift=1.00). v8 was USEFUL (TP=317, FP=174).",
49729
+ aiSpecific: false,
49730
+ _v7Verdict: "DORMANT",
49731
+ _v7Lift: 1,
49732
+ _v7Recall: 0,
49733
+ _v7FpRate: 0,
49734
+ _v7Precision: 0,
49735
+ _v8Verdict: "USEFUL",
49736
+ _v8Lift: 254.79
47617
49737
  },
47618
- "typo/placeholder-text": {
49738
+ "wcag/target-size": {
47619
49739
  recall: 0,
47620
49740
  fpRate: 0,
47621
49741
  ratio: 0,
47622
49742
  precision: 0,
47623
- lastCalibratedAt: "2026-06-30T00:00:00Z",
49743
+ lastCalibratedAt: "2026-07-01T00:00:00Z",
47624
49744
  verdict: "DORMANT",
47625
- defaultOff: true,
47626
- _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.)",
47627
- aiSpecific: false
49745
+ _calibrationNote: "v8.5 calibration (v0.18.9, 2026-07-01): rule did not fire on v8.5 corpus (252080 neg + 294178 pos = 546258 files). Preserved v7 data. v7 verdict=DORMANT, v7 lift=0, v7 recall=0, v7 FPR=0, v7 precision=0.",
49746
+ aiSpecific: false,
49747
+ _v7Verdict: "DORMANT",
49748
+ _v7Lift: 0,
49749
+ _v7Recall: 0,
49750
+ _v7FpRate: 0,
49751
+ _v7Precision: 0,
49752
+ _v8Verdict: "DORMANT",
49753
+ _v8Lift: 1,
49754
+ defaultOff: true
47628
49755
  }
47629
49756
  };
47630
49757
  }
@@ -47691,7 +49818,6 @@ async function scanFile(filePath, config, registry, cwd = process.cwd()) {
47691
49818
  ".kt",
47692
49819
  ".kts",
47693
49820
  ".dart",
47694
- ".rs",
47695
49821
  ".cpp",
47696
49822
  ".cc",
47697
49823
  ".cxx",
@@ -54599,7 +56725,12 @@ var RULE_HINTS = {
54599
56725
  "docs/stale-package-reference": "Update the doc to reference an installed package, or add the package to package.json. Copy-pasted install commands from a previous project are the #1 doc-drift failure mode.",
54600
56726
  "docs/stale-function-reference": "Rename the doc reference to match a current export, or add a wrapper export. Stale function callouts in tutorials cost readers 10+ minutes of debugging.",
54601
56727
  "docs/expired-code-example": "Update the example to use a declared dependency, or add the package to package.json. A copy-pasteable example that does not install erodes trust in the whole docs site.",
54602
- "docs/broken-link": "Create the file or fix the link target. On a public docs site, broken links erode trust more than stale copy."
56728
+ "docs/broken-link": "Create the file or fix the link target. On a public docs site, broken links erode trust more than stale copy.",
56729
+ // v0.18.9 — Rust-specific rules (tree-sitter-backed)
56730
+ "rust/unused-pub-fn": "Remove the function or call it. Rust's compiler doesn't warn on `pub fn` references unless `#![warn(dead_code)]` is set at the crate root. AI agents leave these behind during iterative refactors.",
56731
+ "rust/unwrap-in-production": "Replace `.unwrap()` / `.expect()` with `?` (early-return on Err), `.map_err(...)` for error conversion, or an explicit `match`. They panic in production; reserve them for `#[cfg(test)]` or `#[test]` scopes.",
56732
+ "rust/todo-macro": "Implement the function body or remove the stub. `todo!()` / `unimplemented!()` both expand to `panic!()`, so a hit at runtime crashes the program. Move them into a `#[cfg(test)] mod tests` block to suppress.",
56733
+ "rust/stringly-typed": 'Replace the `String` / `&str` parameter with the typed enum that already exists in the file. Stringly-typed APIs lose type information at the boundary \u2014 typos (`"Click"` vs `"click"`) only fail at runtime.'
54603
56734
  };
54604
56735
 
54605
56736
  // src/cli/commands/explain.ts