slopbrick 0.34.2 → 0.34.6

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.34.2";
39
+ VERSION = "0.34.6";
40
40
  }
41
41
  });
42
42
 
@@ -27660,13 +27660,14 @@ var init_import_path_mismatch = __esm({
27660
27660
  });
27661
27661
 
27662
27662
  // src/rules/cpp/c-style-cast.ts
27663
- var C_STYLE_CAST_REGEX, NAMED_CAST_PREFIX_REGEX, cppCStyleCastRule;
27663
+ var C_STYLE_CAST_REGEX, NAMED_CAST_PREFIX_REGEX, VOID_CAST_REGEX, cppCStyleCastRule;
27664
27664
  var init_c_style_cast = __esm({
27665
27665
  "src/rules/cpp/c-style-cast.ts"() {
27666
27666
  "use strict";
27667
27667
  init_rule();
27668
27668
  C_STYLE_CAST_REGEX = /\(\s*(?:int|long|short|char|float|double|bool|unsigned\s+\w+|signed\s+\w+|size_t|[A-Za-z_]\w*(?:\s*[*,&][^)]*)?)\s*\)\s*(\w+|[^a-zA-Z_])/g;
27669
- NAMED_CAST_PREFIX_REGEX = /\b(?:static|reinterpret|const|dynamic)_cast\s*<[^>]*>\s*\($/;
27669
+ NAMED_CAST_PREFIX_REGEX = /\b(?:static|reinterpret|const|dynamic)_cast\s*<[^>]*>\s*$/;
27670
+ VOID_CAST_REGEX = /^\s*void\s*$/;
27670
27671
  cppCStyleCastRule = createRule({
27671
27672
  id: "cpp/c-style-cast",
27672
27673
  category: "typo",
@@ -27686,9 +27687,10 @@ var init_c_style_cast = __esm({
27686
27687
  while ((m = C_STYLE_CAST_REGEX.exec(source)) !== null) {
27687
27688
  const innerMatch = /\(\s*([^)]+?)\s*\)/.exec(m[0]) ?? [];
27688
27689
  const inner = (innerMatch[1] ?? "").trim();
27690
+ if (VOID_CAST_REGEX.test(inner)) continue;
27689
27691
  const looksLikeCast = /\b(?:int|long|short|char|float|double|bool|unsigned|signed|size_t)\b/.test(inner) || /[*&]/.test(inner);
27690
27692
  if (!looksLikeCast) continue;
27691
- const before = source.slice(Math.max(0, m.index - 40), m.index);
27693
+ const before = source.slice(Math.max(0, m.index - 60), m.index);
27692
27694
  if (NAMED_CAST_PREFIX_REGEX.test(before)) continue;
27693
27695
  const line = source.slice(0, m.index).split("\n").length;
27694
27696
  issues.push({
@@ -27699,7 +27701,7 @@ var init_c_style_cast = __esm({
27699
27701
  message: `C-style cast at line ${line} \u2014 use static_cast / reinterpret_cast / const_cast`,
27700
27702
  line,
27701
27703
  column: 1,
27702
- advice: "Use the named cast that matches the intent: `static_cast<int>(x)`, `reinterpret_cast<MyClass*>(p)`, `const_cast<...>(ref)`, or `dynamic_cast<Derived*>(base)` for runtime-checked downcasts. C-style casts silently pick whichever the compiler needs \u2014 `static_cast`, `reinterpret_cast`, OR `const_cast` \u2014 which makes them impossible to grep for and impossible to review. The C++ Core Guidelines (ES.49) call this out by name. AI agents reach for `(int)x` because of training-data C textbooks. Reference: cpp/c-style-cast v0.24."
27704
+ advice: "Use the named cast that matches the intent: `static_cast<int>(x)`, `reinterpret_cast<MyClass*>(p)`, `const_cast<...>(ref)`, or `dynamic_cast<Derived*>(base)` for runtime-checked downcasts. C-style casts silently pick whichever the compiler needs \u2014 `static_cast`, `reinterpret_cast`, OR `const_cast` \u2014 which makes them impossible to grep for and impossible to review. The C++ Core Guidelines (ES.49) call this out by name. AI agents reach for `(int)x` because of training-data C textbooks. Reference: cpp/c-style-cast v0.34.3 (refined regex selectivity)."
27703
27705
  });
27704
27706
  }
27705
27707
  return issues;
@@ -27732,6 +27734,7 @@ var init_magic_numbers = __esm({
27732
27734
  if (!/\.(cpp|cc|cxx|h|hpp|hh|hxx|H)$/i.test(facts.filePath)) return issues;
27733
27735
  const lines = source.split("\n");
27734
27736
  const allowSet = /* @__PURE__ */ new Set([
27737
+ // v0.24 originals
27735
27738
  "1024",
27736
27739
  "65535",
27737
27740
  "65536",
@@ -27750,17 +27753,42 @@ var init_magic_numbers = __esm({
27750
27753
  "2",
27751
27754
  "3",
27752
27755
  "4",
27753
- "5"
27756
+ "5",
27757
+ // v0.34.4 additions
27758
+ "-1",
27759
+ // sentinel value for "not found" / "all bits set"
27760
+ "100",
27761
+ // percent literal, very common
27762
+ "0.0",
27763
+ "0.5",
27764
+ "1.0",
27765
+ "2.0",
27766
+ // common probability / ratio
27767
+ "4096",
27768
+ // page size, hash bucket count
27769
+ "2048",
27770
+ "512",
27771
+ // power-of-2 sizes
27772
+ "32",
27773
+ "64",
27774
+ "128",
27775
+ // bit widths, byte sizes
27776
+ "16",
27777
+ "8",
27778
+ // common small constants
27779
+ "50"
27780
+ // percentile literal
27754
27781
  ]);
27755
27782
  for (let i = 0; i < lines.length; i++) {
27756
27783
  const line = lines[i] ?? "";
27757
27784
  if (!COMPARE_OR_RETURN_REGEX.test(line)) continue;
27785
+ const codeLine = line.replace(/\/\/.*$/, "").replace(/"(?:[^"\\]|\\.)*"/g, '""').replace(/'(?:[^'\\]|\\.)*'/g, "''");
27758
27786
  let m;
27759
27787
  MAGIC_NUMBER_REGEX.lastIndex = 0;
27760
- while ((m = MAGIC_NUMBER_REGEX.exec(line)) !== null) {
27788
+ while ((m = MAGIC_NUMBER_REGEX.exec(codeLine)) !== null) {
27761
27789
  const literal = m[0] ?? "";
27762
27790
  if (allowSet.has(literal)) continue;
27763
- if (/\b(?:constexpr|const)\s+\w+\s*=\s*$/.test(line.slice(0, m.index).trimEnd())) continue;
27791
+ if (/\b(?:constexpr|const)\s+\w+\s*=\s*$/.test(codeLine.slice(0, m.index).trimEnd())) continue;
27764
27792
  const prevLine = i > 0 ? lines[i - 1] ?? "" : "";
27765
27793
  if (/\b(?:constexpr|const)\s+\w+\s*=\s*$/.test(prevLine.trim())) continue;
27766
27794
  issues.push({
@@ -27771,7 +27799,7 @@ var init_magic_numbers = __esm({
27771
27799
  message: `magic number ${literal} at line ${i + 1} \u2014 name it: constexpr int MAX = ${literal};`,
27772
27800
  line: i + 1,
27773
27801
  column: 1,
27774
- advice: 'Replace the bare literal with a named constant declared as `constexpr int MAX_SIZE = 1024;` (or `static constexpr`). The named constant lives next to its value, can be searched, and forces the reader to mean what they say. Magic numbers in comparisons hide intent ("7" against what?). AI agents produce magic-number-heavy code because their training-data examples rarely bother to name the constant. Reference: cpp/magic-numbers v0.24.'
27802
+ advice: 'Replace the bare literal with a named constant declared as `constexpr int MAX_SIZE = 1024;` (or `static constexpr`). The named constant lives next to its value, can be searched, and forces the reader to mean what they say. Magic numbers in comparisons hide intent ("7" against what?). AI agents produce magic-number-heavy code because their training-data examples rarely bother to name the constant. Reference: cpp/magic-numbers v0.34.4 (expanded allowSet + string/comment exclusion).'
27775
27803
  });
27776
27804
  }
27777
27805
  }
@@ -30859,12 +30887,11 @@ var init_system_out_println = __esm({
30859
30887
  });
30860
30888
 
30861
30889
  // src/rules/java/thread-sleep-in-loop.ts
30862
- var THREAD_SLEEP_REGEX, javaThreadSleepInLoopRule;
30890
+ var javaThreadSleepInLoopRule;
30863
30891
  var init_thread_sleep_in_loop = __esm({
30864
30892
  "src/rules/java/thread-sleep-in-loop.ts"() {
30865
30893
  "use strict";
30866
30894
  init_rule();
30867
- THREAD_SLEEP_REGEX = /\bThread\.sleep\s*\(/g;
30868
30895
  javaThreadSleepInLoopRule = createRule({
30869
30896
  id: "java/thread-sleep-in-loop",
30870
30897
  category: "perf",
@@ -30880,11 +30907,104 @@ var init_thread_sleep_in_loop = __esm({
30880
30907
  if (!source) return issues;
30881
30908
  if (!/\.java$/i.test(facts.filePath)) return issues;
30882
30909
  if (!/\bThread\.sleep\s*\(/.test(source)) return issues;
30883
- if (!/\b(?:for|while|do)\b/.test(source)) return issues;
30884
- let m;
30885
- THREAD_SLEEP_REGEX.lastIndex = 0;
30886
- while ((m = THREAD_SLEEP_REGEX.exec(source)) !== null) {
30887
- const line = source.slice(0, m.index).split("\n").length;
30910
+ const braceStack = [];
30911
+ const loopSet = /* @__PURE__ */ new Set();
30912
+ let pendingLoopKeyword = null;
30913
+ let parenDepth = 0;
30914
+ const sleepEvents = [];
30915
+ let inString = false;
30916
+ let inLineComment = false;
30917
+ let inBlockComment = false;
30918
+ for (let i = 0; i < source.length; i++) {
30919
+ const c = source[i] ?? "";
30920
+ const next = source[i + 1] ?? "";
30921
+ const prev = source[i - 1] ?? "";
30922
+ if (inLineComment) {
30923
+ if (c === "\n") inLineComment = false;
30924
+ continue;
30925
+ }
30926
+ if (inBlockComment) {
30927
+ if (c === "*" && next === "/") {
30928
+ inBlockComment = false;
30929
+ i++;
30930
+ }
30931
+ continue;
30932
+ }
30933
+ if (inString) {
30934
+ if (c === "\\") {
30935
+ i++;
30936
+ continue;
30937
+ }
30938
+ if (c === inString) inString = false;
30939
+ continue;
30940
+ }
30941
+ if (c === "/" && next === "/") {
30942
+ inLineComment = true;
30943
+ i++;
30944
+ continue;
30945
+ }
30946
+ if (c === "/" && next === "*") {
30947
+ inBlockComment = true;
30948
+ i++;
30949
+ continue;
30950
+ }
30951
+ if (c === '"' || c === "'") {
30952
+ inString = c;
30953
+ continue;
30954
+ }
30955
+ if (c === "(") {
30956
+ parenDepth++;
30957
+ continue;
30958
+ }
30959
+ if (c === ")") {
30960
+ parenDepth = Math.max(0, parenDepth - 1);
30961
+ continue;
30962
+ }
30963
+ if (/[A-Za-z_]/.test(c) && !/[A-Za-z0-9_]/.test(prev)) {
30964
+ const next3 = source.slice(i, i + 3);
30965
+ const next5 = source.slice(i, i + 5);
30966
+ const next2 = source.slice(i, i + 2);
30967
+ const after3 = source[i + 3] ?? "";
30968
+ const after5 = source[i + 5] ?? "";
30969
+ const after2 = source[i + 2] ?? "";
30970
+ if (next3 === "for" && !/[A-Za-z0-9_]/.test(after3)) {
30971
+ pendingLoopKeyword = { kind: "for", idx: i };
30972
+ i += 2;
30973
+ continue;
30974
+ }
30975
+ if (next5 === "while" && !/[A-Za-z0-9_]/.test(after5)) {
30976
+ pendingLoopKeyword = { kind: "while", idx: i };
30977
+ i += 4;
30978
+ continue;
30979
+ }
30980
+ if (next2 === "do" && !/[A-Za-z0-9_]/.test(after2)) {
30981
+ pendingLoopKeyword = { kind: "do", idx: i };
30982
+ i += 1;
30983
+ continue;
30984
+ }
30985
+ }
30986
+ if (c === "{") {
30987
+ braceStack.push(i);
30988
+ if (pendingLoopKeyword && parenDepth === 0) {
30989
+ loopSet.add(i);
30990
+ pendingLoopKeyword = null;
30991
+ }
30992
+ } else if (c === "}") {
30993
+ const popped = braceStack.pop();
30994
+ if (popped !== void 0 && loopSet.has(popped)) {
30995
+ loopSet.delete(popped);
30996
+ }
30997
+ if (pendingLoopKeyword) {
30998
+ pendingLoopKeyword = null;
30999
+ }
31000
+ } else if (c === "T" && source.slice(i, i + 13) === "Thread.sleep(") {
31001
+ sleepEvents.push({ idx: i, loopDepth: loopSet.size });
31002
+ i += 12;
31003
+ }
31004
+ }
31005
+ for (const ev of sleepEvents) {
31006
+ if (ev.loopDepth === 0) continue;
31007
+ const line = source.slice(0, ev.idx).split("\n").length;
30888
31008
  issues.push({
30889
31009
  ruleId: "java/thread-sleep-in-loop",
30890
31010
  category: "perf",
@@ -30893,7 +31013,7 @@ var init_thread_sleep_in_loop = __esm({
30893
31013
  message: `Thread.sleep() at line ${line}`,
30894
31014
  line,
30895
31015
  column: 1,
30896
- advice: 'Use ScheduledExecutorService for periodic work, or BlockingQueue.take() for event-driven work. Thread.sleep in a loop is the classic "polling with sleep" anti-pattern \u2014 the thread blocks for the sleep duration each iteration. In server contexts this ties up Tomcat/Jetty/Netty threads. Reference: java/thread-sleep-in-loop v0.30.'
31016
+ advice: 'Use ScheduledExecutorService for periodic work, or BlockingQueue.take() for event-driven work. Thread.sleep in a loop is the classic "polling with sleep" anti-pattern \u2014 the thread blocks for the sleep duration each iteration. In server contexts this ties up Tomcat/Jetty/Netty threads. Reference: java/thread-sleep-in-loop v0.34.6 (refined to require Thread.sleep inside the loop block, not just in the file).'
30897
31017
  });
30898
31018
  }
30899
31019
  return issues;
@@ -31175,13 +31295,14 @@ var init_object_singleton_misuse = __esm({
31175
31295
  });
31176
31296
 
31177
31297
  // src/rules/kotlin/println-as-log.ts
31178
- var PRINTLN_REGEX, REAL_LOGGING_IMPORT_REGEX2, kotlinPrintlnAsLogRule;
31298
+ var PRINTLN_REGEX, REAL_LOGGING_IMPORT_REGEX2, TEST_FILE_REGEX, kotlinPrintlnAsLogRule;
31179
31299
  var init_println_as_log = __esm({
31180
31300
  "src/rules/kotlin/println-as-log.ts"() {
31181
31301
  "use strict";
31182
31302
  init_rule();
31183
31303
  PRINTLN_REGEX = /\bprintln\s*\(/g;
31184
31304
  REAL_LOGGING_IMPORT_REGEX2 = /\bimport\s+(?:android\.util\.Log|org\.slf4j\.|io\.github\.oshai\.kotlinlogging|kotlin\.logging|co\.touchlab\.kermit|com\.github\.ajalt\.timber|org\.apache\.logging\.log4j)/;
31305
+ TEST_FILE_REGEX = /(?:\/src\/test\/|\/test\/|\/Tests\/|\/Test\.kt|\/Tests\.kt|Tests\.kt$|Test\.kt$)/;
31185
31306
  kotlinPrintlnAsLogRule = createRule({
31186
31307
  id: "kotlin/println-as-log",
31187
31308
  category: "logic",
@@ -31196,7 +31317,7 @@ var init_println_as_log = __esm({
31196
31317
  const source = facts.v2?._source;
31197
31318
  if (!source) return issues;
31198
31319
  if (!/\.kts?$/i.test(facts.filePath)) return issues;
31199
- if (/\/test\//i.test(facts.filePath) || /\.test\.kts?$/i.test(facts.filePath)) return issues;
31320
+ if (TEST_FILE_REGEX.test(facts.filePath)) return issues;
31200
31321
  if (REAL_LOGGING_IMPORT_REGEX2.test(source)) return issues;
31201
31322
  let m;
31202
31323
  PRINTLN_REGEX.lastIndex = 0;
@@ -31210,7 +31331,7 @@ var init_println_as_log = __esm({
31210
31331
  message: `println() as logger at line ${line}`,
31211
31332
  line,
31212
31333
  column: 1,
31213
- advice: "Use a real logging library: slf4j (JVM), android.util.Log (Android), Timber (Android), kermit (multiplatform), or kotlin-logging. println() has no log level, no timestamp, no correlation ID, and cannot be filtered. Reference: kotlin/println-as-log v0.29."
31334
+ advice: "Use a real logging library: slf4j (JVM), android.util.Log (Android), Timber (Android), kermit (multiplatform), or kotlin-logging. println() has no log level, no timestamp, no correlation ID, and cannot be filtered. Reference: kotlin/println-as-log v0.34.5 (refined to skip test files for higher precision)."
31214
31335
  });
31215
31336
  }
31216
31337
  return issues;
@@ -41055,14 +41176,14 @@ var init_implicitly_unwrapped_optional = __esm({
41055
41176
  });
41056
41177
 
41057
41178
  // src/rules/swift/print-debug.ts
41058
- var PRINT_REGEX, DEFAULT_THRESHOLD2, TEST_FILE_REGEX, swiftPrintDebugRule;
41179
+ var PRINT_REGEX, DEFAULT_THRESHOLD2, TEST_FILE_REGEX2, swiftPrintDebugRule;
41059
41180
  var init_print_debug = __esm({
41060
41181
  "src/rules/swift/print-debug.ts"() {
41061
41182
  "use strict";
41062
41183
  init_rule();
41063
41184
  PRINT_REGEX = /\bprint\s*\(/g;
41064
41185
  DEFAULT_THRESHOLD2 = 1;
41065
- TEST_FILE_REGEX = /(?:\/Tests\/|\/Tests\.swift|\/Test\.swift|Tests\.swift$|Test\.swift$)/;
41186
+ TEST_FILE_REGEX2 = /(?:\/Tests\/|\/Tests\.swift|\/Test\.swift|Tests\.swift$|Test\.swift$)/;
41066
41187
  swiftPrintDebugRule = createRule({
41067
41188
  id: "swift/print-debug",
41068
41189
  category: "typo",
@@ -41077,7 +41198,7 @@ var init_print_debug = __esm({
41077
41198
  const source = facts.v2?._source;
41078
41199
  if (!source) return issues;
41079
41200
  if (!/\.swift$/i.test(facts.filePath)) return issues;
41080
- if (TEST_FILE_REGEX.test(facts.filePath)) return issues;
41201
+ if (TEST_FILE_REGEX2.test(facts.filePath)) return issues;
41081
41202
  const matches = [];
41082
41203
  let m;
41083
41204
  PRINT_REGEX.lastIndex = 0;
@@ -51552,7 +51673,7 @@ var init_signal_strength = __esm({
51552
51673
  precision: 0.1268,
51553
51674
  lastCalibratedAt: "2026-07-03T00:00:00Z",
51554
51675
  verdict: "OK",
51555
- _calibrationNote: "v0.29: v9 Kotlin calibration (2698 neg, 213 pos). ratio=1.84 (\u22651.5) \u2014 first rule in this entire session with a positive direction! Fires 1.84x more on post-2024 AI/demos than pre-2022 production. Precision=12.7% (below 50% USEFUL threshold); verdict=OK. The signal is real: post-2024 Kotlin code (especially AI-generated examples) uses println for output; pre-2022 production code uses slf4j/kermit. INSUFFICIENT_DATA: pos arm only 213 files. defaultOff: still set to true (verdict is OK but precision is below 50% \u2014 the guardrail expects OK/USEFUL rules to be defaultOff:false only when calibrated with a meaningful pos arm).",
51676
+ _calibrationNote: "v0.34.5: REFINED \u2014 rule now skips test files (JUnit4/5 + Android: *Tests.kt, *Test.kt, src/test/, test/ dirs). Per-file unique v9 Kotlin calibration (2698 neg, 213 pos): ratio=1.84 (\u22651.5, OK). The refinement mirrors v0.34.2's swift/print-debug fix: the previous exclusion only matched `\\/test\\/` and `.test.kts?$`, missing JUnit5's `FooTests.kt` naming. Expected post-refinement precision: 12.7% \u2192 25%+ by removing the JUnit assertion / debug-output fires that were ~50% of the FPs. Same direction as java/system-out-println (1.73 refined) and the v0.34.2 swift/print-debug pipeline. Full v9 re-calibration is part of the v0.35.0 re-measurement. v0.29: v9 Kotlin calibration (2698 neg, 213 pos). ratio=1.84 (\u22651.5) \u2014 first rule in this entire session with a positive direction! Fires 1.84x more on post-2024 AI/demos than pre-2022 production. Precision=12.7% (below 50% USEFUL threshold); verdict=OK. The signal is real: post-2024 Kotlin code (especially AI-generated examples) uses println for output; pre-2022 production code uses slf4j/kermit. INSUFFICIENT_DATA: pos arm only 213 files. defaultOff: still set to true (verdict is OK but precision is below 50% \u2014 the guardrail expects OK/USEFUL rules to be defaultOff:false only when calibrated with a meaningful pos arm).",
51556
51677
  aiSpecific: false,
51557
51678
  _v9Verdict: "OK",
51558
51679
  _v9Lift: 1.84,
@@ -51616,7 +51737,7 @@ var init_signal_strength = __esm({
51616
51737
  precision: 0.1091,
51617
51738
  lastCalibratedAt: "2026-07-03T00:00:00Z",
51618
51739
  verdict: "DORMANT",
51619
- _calibrationNote: "v0.30: v9 Java calibration (81891 neg, 10305 pos). ratio=0.97 (just below 1.0) \u2014 fires equally on both arms. Borderline era-confound: pre-2022 Java had more Thread.sleep in loops (less mature concurrency APIs); modern Java uses ScheduledExecutorService. Same direction as kotlin/runblocking-misuse (0.50). 2154 total fires \u2014 high absolute count, meaningful measurement. defaultOff.",
51740
+ _calibrationNote: "v0.34.6: REFINED \u2014 rule now requires Thread.sleep to be INSIDE the loop block (verified via brace-counting), not just in a file that happens to contain a for/while/do keyword. v0.30 baseline: 2154 total fires, ratio 0.97 (DORMANT). The refinement targets: (1) Thread.sleep in `main()` no longer fires if a different method has a `for` loop (the v0.30 heuristic fired on every Thread.sleep in the file); (2) Thread.sleep before/after a loop block (not inside it) no longer fires; (3) string literals containing `Thread.sleep(...)` are skipped via the string-state-machine. Expected post-refinement ratio: 1.5+ (positive-signal OK verdict) by removing the cross-method over-fires. Full v9 re-calibration is part of the v0.35.0 re-measurement. v0.30: v9 Java calibration (81891 neg, 10305 pos). ratio=0.97 (just below 1.0) \u2014 fires equally on both arms. Borderline era-confound: pre-2022 Java had more Thread.sleep in loops (less mature concurrency APIs); modern Java uses ScheduledExecutorService. Same direction as kotlin/runblocking-misuse (0.50). 2154 total fires \u2014 high absolute count, meaningful measurement. defaultOff.",
51620
51741
  aiSpecific: false,
51621
51742
  _v9Verdict: "DORMANT",
51622
51743
  _v9Lift: 0.97,
@@ -51825,7 +51946,7 @@ var init_signal_strength = __esm({
51825
51946
  precision: 0.2325,
51826
51947
  lastCalibratedAt: "2026-07-03T00:00:00Z",
51827
51948
  verdict: "DORMANT",
51828
- _calibrationNote: "v0.33: v9 C++ calibration (5107 neg, 1655 pos). Per-file unique: 874 TP, 2885 FP, ratio=0.93. Total fires were 32265 TP, 39954 FP \u2014 the regex is too broad and fires on every C-style cast including static_cast in template code. The per-file measurement (874/1655 = 53%) is more meaningful \u2014 both arms have similar proportions of files using C-style casts. INSUFFICIENT_DATA: pos arm 1655 files.",
51949
+ _calibrationNote: "v0.34.3: REFINED \u2014 NAMED_CAST_PREFIX_REGEX tightened (the old version required the lookback slice to end with `>(`, which never matched because the slice ends with `>`). Lookback increased 40\u219260 chars. Added `(void)x` discard-idom exclusion. v0.33 baseline: 874 TP / 2885 FP per-file (ratio 0.93, DORMANT). The refinement targets: (1) static_cast/const_cast/reinterpret_cast/dynamic_cast no longer fire when followed by whitespace before `(`; (2) class-type named casts like `static_cast<MyClass*>(p)` now correctly excluded (60-char lookback reaches the long typename); (3) `(void)x` deliberate discards are no longer flagged. Expected post-refinement ratio: 1.0-1.2 (still DORMANT but better-targeted). Full v9 re-calibration is part of the v0.35.0 re-measurement. v0.33: v9 C++ calibration (5107 neg, 1655 pos). Per-file unique: 874 TP, 2885 FP, ratio=0.93. Total fires were 32265 TP, 39954 FP \u2014 the regex is too broad and fires on every C-style cast including static_cast in template code. The per-file measurement (874/1655 = 53%) is more meaningful \u2014 both arms have similar proportions of files using C-style casts. INSUFFICIENT_DATA: pos arm 1655 files.",
51829
51950
  aiSpecific: true,
51830
51951
  _v7Verdict: "DORMANT",
51831
51952
  _v7Lift: 1,
@@ -51871,7 +51992,7 @@ var init_signal_strength = __esm({
51871
51992
  precision: 0.2187,
51872
51993
  lastCalibratedAt: "2026-07-03T00:00:00Z",
51873
51994
  verdict: "DORMANT",
51874
- _calibrationNote: "v0.33: v9 C++ calibration (5107 neg, 1655 pos). Per-file unique: 220 TP, 786 FP, ratio=0.86. Both arms have similar proportions of files with magic numbers \u2014 this is a general C++ anti-pattern that hasn't been eradicated. INSUFFICIENT_DATA: pos arm 1655 files.",
51995
+ _calibrationNote: "v0.34.4: REFINED \u2014 expanded allowSet with common constants (-1 sentinel, 100 percent literal, 0.5/1.0/2.0 ratios, 4096/2048/512/128/64/32/16/8 power-of-2 sizes, 50 percentile). Added string-literal and `//` comment stripping so substrings like `\"got 42 errors\"` and `// ticket #4242` no longer fire. v0.33 baseline: 220 TP / 786 FP per-file (ratio 0.86, DORMANT). The refinement targets: (1) sentinel `-1` literals are skipped because `1` is allowlisted and the `-` doesn't match MAGIC_NUMBER_REGEX anyway; (2) hex literals (`0xFF`) are skipped because the digit-only regex requires a word-boundary after digits, and `0x...` has none; (3) literals inside string/comment contexts no longer fire. Expected post-refinement ratio: 1.0-1.2 (still DORMANT but better-targeted). Full v9 re-calibration is part of the v0.35.0 re-measurement. v0.33: v9 C++ calibration (5107 neg, 1655 pos). Per-file unique: 220 TP, 786 FP, ratio=0.86. Both arms have similar proportions of files with magic numbers \u2014 this is a general C++ anti-pattern that hasn't been eradicated. INSUFFICIENT_DATA: pos arm 1655 files.",
51875
51996
  aiSpecific: true,
51876
51997
  _v7Verdict: "DORMANT",
51877
51998
  _v7Lift: 1,