slopbrick 0.34.1 → 0.34.3

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.
@@ -34436,7 +34436,8 @@ var importPathMismatchRule = createRule({
34436
34436
 
34437
34437
  // src/rules/cpp/c-style-cast.ts
34438
34438
  var 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;
34439
- var NAMED_CAST_PREFIX_REGEX = /\b(?:static|reinterpret|const|dynamic)_cast\s*<[^>]*>\s*\($/;
34439
+ var NAMED_CAST_PREFIX_REGEX = /\b(?:static|reinterpret|const|dynamic)_cast\s*<[^>]*>\s*$/;
34440
+ var VOID_CAST_REGEX = /^\s*void\s*$/;
34440
34441
  var cppCStyleCastRule = createRule({
34441
34442
  id: "cpp/c-style-cast",
34442
34443
  category: "typo",
@@ -34456,9 +34457,10 @@ var cppCStyleCastRule = createRule({
34456
34457
  while ((m = C_STYLE_CAST_REGEX.exec(source)) !== null) {
34457
34458
  const innerMatch = /\(\s*([^)]+?)\s*\)/.exec(m[0]) ?? [];
34458
34459
  const inner = (innerMatch[1] ?? "").trim();
34460
+ if (VOID_CAST_REGEX.test(inner)) continue;
34459
34461
  const looksLikeCast = /\b(?:int|long|short|char|float|double|bool|unsigned|signed|size_t)\b/.test(inner) || /[*&]/.test(inner);
34460
34462
  if (!looksLikeCast) continue;
34461
- const before = source.slice(Math.max(0, m.index - 40), m.index);
34463
+ const before = source.slice(Math.max(0, m.index - 60), m.index);
34462
34464
  if (NAMED_CAST_PREFIX_REGEX.test(before)) continue;
34463
34465
  const line = source.slice(0, m.index).split("\n").length;
34464
34466
  issues.push({
@@ -34469,7 +34471,7 @@ var cppCStyleCastRule = createRule({
34469
34471
  message: `C-style cast at line ${line} \u2014 use static_cast / reinterpret_cast / const_cast`,
34470
34472
  line,
34471
34473
  column: 1,
34472
- 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."
34474
+ 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)."
34473
34475
  });
34474
34476
  }
34475
34477
  return issues;
@@ -40514,6 +40516,7 @@ var swiftImplicitlyUnwrappedOptionalRule = createRule({
40514
40516
  // src/rules/swift/print-debug.ts
40515
40517
  var PRINT_REGEX = /\bprint\s*\(/g;
40516
40518
  var DEFAULT_THRESHOLD2 = 1;
40519
+ var TEST_FILE_REGEX = /(?:\/Tests\/|\/Tests\.swift|\/Test\.swift|Tests\.swift$|Test\.swift$)/;
40517
40520
  var swiftPrintDebugRule = createRule({
40518
40521
  id: "swift/print-debug",
40519
40522
  category: "typo",
@@ -40528,6 +40531,7 @@ var swiftPrintDebugRule = createRule({
40528
40531
  const source = facts.v2?._source;
40529
40532
  if (!source) return issues;
40530
40533
  if (!/\.swift$/i.test(facts.filePath)) return issues;
40534
+ if (TEST_FILE_REGEX.test(facts.filePath)) return issues;
40531
40535
  const matches = [];
40532
40536
  let m;
40533
40537
  PRINT_REGEX.lastIndex = 0;
@@ -40547,7 +40551,7 @@ var swiftPrintDebugRule = createRule({
40547
40551
  message: `print(...) at line ${line} \u2014 use Logger (os.log) for production output`,
40548
40552
  line,
40549
40553
  column: 1,
40550
- advice: 'Replace with `Logger(subsystem: "...", category: "...").info("...")` (Unified Logging System, os.log). `print` writes to stdout with no level, no redaction, and no way to silence in release builds. The `Logger` API integrates with Console.app and respects the device\'s privacy settings. Multiple `print` calls in one Swift file is an AI fingerprint \u2014 agents reach for `print` because of training-data examples. Reference: swift/print-debug v0.24.'
40554
+ advice: 'Replace with `Logger(subsystem: "...", category: "...").info("...")` (Unified Logging System, os.log). `print` writes to stdout with no level, no redaction, and no way to silence in release builds. The `Logger` API integrates with Console.app and respects the device\'s privacy settings. Multiple `print` calls in one Swift file is an AI fingerprint \u2014 agents reach for `print` because of training-data examples. Reference: swift/print-debug v0.34.2 (refined to skip test files for higher precision).'
40551
40555
  });
40552
40556
  }
40553
40557
  return issues;
@@ -45598,7 +45602,7 @@ var signal_strength_default = {
45598
45602
  precision: 0.3305,
45599
45603
  lastCalibratedAt: "2026-07-03T00:00:00Z",
45600
45604
  verdict: "OK",
45601
- _calibrationNote: "v0.32: v9 Swift calibration (1300 neg, 568 pos). Per-file unique: 39 TP files, 79 FP files, ratio=1.13 (\u22651.0, OK). Total-fires measurement was ratio=1.78 (1.6x higher) but per-file is more conservative. precision=33.05% (below 50% USEFUL threshold); verdict=OK. The direction is positive: post-2024 Swift (especially AI-generated examples in OpenAI Swift, WhisperKit) uses print() for output; pre-2022 production Swift (Alamofire, Vapor, Moya) uses os.Logger / OSLog. Same direction as kotlin/println-as-log (1.84) and java/system-out-println (1.73 refined, 3.29 unrefined). INSUFFICIENT_DATA: pos arm 568 files (below 10k floor).",
45605
+ _calibrationNote: "v0.34.2: REFINED \u2014 rule now skips test files (XCTest naming: *Tests.swift, *Test.swift, Tests/ dir). Per-file unique v9 Swift calibration (1300 neg, 568 pos): 39 TP files, 79 FP files, ratio=1.13 (OK). The refinement is expected to push precision from 33% to 50%+ by removing XCTest output and snapshot test fires (which were ~49% of FPs in the v0.32.0 measurement). The full v9 re-calibration is part of the v0.34.5/v0.34.7 pipeline (same refinement applied to kotlin/println-as-log and cpp/printf-debug); see v0.34.1's Four-language validation section. v0.32.0 baseline: 39 TP files / 568 = 6.87% recall, 79 FP files / 1300 = 6.08% fpRate, ratio 1.13, precision 33.05% (just below 50% USEFUL threshold). Same direction as kotlin/println-as-log (1.84) and java/system-out-println (1.73 refined, 3.29 unrefined). INSUFFICIENT_DATA: pos arm 568 files (below 10k floor).",
45602
45606
  aiSpecific: true,
45603
45607
  _v7Verdict: "DORMANT",
45604
45608
  _v7Lift: 1,
@@ -45736,7 +45740,7 @@ var signal_strength_default = {
45736
45740
  precision: 0.2325,
45737
45741
  lastCalibratedAt: "2026-07-03T00:00:00Z",
45738
45742
  verdict: "DORMANT",
45739
- _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.",
45743
+ _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.",
45740
45744
  aiSpecific: true,
45741
45745
  _v7Verdict: "DORMANT",
45742
45746
  _v7Lift: 1,
@@ -34407,7 +34407,8 @@ var importPathMismatchRule = createRule({
34407
34407
 
34408
34408
  // src/rules/cpp/c-style-cast.ts
34409
34409
  var 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;
34410
- var NAMED_CAST_PREFIX_REGEX = /\b(?:static|reinterpret|const|dynamic)_cast\s*<[^>]*>\s*\($/;
34410
+ var NAMED_CAST_PREFIX_REGEX = /\b(?:static|reinterpret|const|dynamic)_cast\s*<[^>]*>\s*$/;
34411
+ var VOID_CAST_REGEX = /^\s*void\s*$/;
34411
34412
  var cppCStyleCastRule = createRule({
34412
34413
  id: "cpp/c-style-cast",
34413
34414
  category: "typo",
@@ -34427,9 +34428,10 @@ var cppCStyleCastRule = createRule({
34427
34428
  while ((m = C_STYLE_CAST_REGEX.exec(source)) !== null) {
34428
34429
  const innerMatch = /\(\s*([^)]+?)\s*\)/.exec(m[0]) ?? [];
34429
34430
  const inner = (innerMatch[1] ?? "").trim();
34431
+ if (VOID_CAST_REGEX.test(inner)) continue;
34430
34432
  const looksLikeCast = /\b(?:int|long|short|char|float|double|bool|unsigned|signed|size_t)\b/.test(inner) || /[*&]/.test(inner);
34431
34433
  if (!looksLikeCast) continue;
34432
- const before = source.slice(Math.max(0, m.index - 40), m.index);
34434
+ const before = source.slice(Math.max(0, m.index - 60), m.index);
34433
34435
  if (NAMED_CAST_PREFIX_REGEX.test(before)) continue;
34434
34436
  const line = source.slice(0, m.index).split("\n").length;
34435
34437
  issues.push({
@@ -34440,7 +34442,7 @@ var cppCStyleCastRule = createRule({
34440
34442
  message: `C-style cast at line ${line} \u2014 use static_cast / reinterpret_cast / const_cast`,
34441
34443
  line,
34442
34444
  column: 1,
34443
- 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."
34445
+ 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)."
34444
34446
  });
34445
34447
  }
34446
34448
  return issues;
@@ -40485,6 +40487,7 @@ var swiftImplicitlyUnwrappedOptionalRule = createRule({
40485
40487
  // src/rules/swift/print-debug.ts
40486
40488
  var PRINT_REGEX = /\bprint\s*\(/g;
40487
40489
  var DEFAULT_THRESHOLD2 = 1;
40490
+ var TEST_FILE_REGEX = /(?:\/Tests\/|\/Tests\.swift|\/Test\.swift|Tests\.swift$|Test\.swift$)/;
40488
40491
  var swiftPrintDebugRule = createRule({
40489
40492
  id: "swift/print-debug",
40490
40493
  category: "typo",
@@ -40499,6 +40502,7 @@ var swiftPrintDebugRule = createRule({
40499
40502
  const source = facts.v2?._source;
40500
40503
  if (!source) return issues;
40501
40504
  if (!/\.swift$/i.test(facts.filePath)) return issues;
40505
+ if (TEST_FILE_REGEX.test(facts.filePath)) return issues;
40502
40506
  const matches = [];
40503
40507
  let m;
40504
40508
  PRINT_REGEX.lastIndex = 0;
@@ -40518,7 +40522,7 @@ var swiftPrintDebugRule = createRule({
40518
40522
  message: `print(...) at line ${line} \u2014 use Logger (os.log) for production output`,
40519
40523
  line,
40520
40524
  column: 1,
40521
- advice: 'Replace with `Logger(subsystem: "...", category: "...").info("...")` (Unified Logging System, os.log). `print` writes to stdout with no level, no redaction, and no way to silence in release builds. The `Logger` API integrates with Console.app and respects the device\'s privacy settings. Multiple `print` calls in one Swift file is an AI fingerprint \u2014 agents reach for `print` because of training-data examples. Reference: swift/print-debug v0.24.'
40525
+ advice: 'Replace with `Logger(subsystem: "...", category: "...").info("...")` (Unified Logging System, os.log). `print` writes to stdout with no level, no redaction, and no way to silence in release builds. The `Logger` API integrates with Console.app and respects the device\'s privacy settings. Multiple `print` calls in one Swift file is an AI fingerprint \u2014 agents reach for `print` because of training-data examples. Reference: swift/print-debug v0.34.2 (refined to skip test files for higher precision).'
40522
40526
  });
40523
40527
  }
40524
40528
  return issues;
@@ -45569,7 +45573,7 @@ var signal_strength_default = {
45569
45573
  precision: 0.3305,
45570
45574
  lastCalibratedAt: "2026-07-03T00:00:00Z",
45571
45575
  verdict: "OK",
45572
- _calibrationNote: "v0.32: v9 Swift calibration (1300 neg, 568 pos). Per-file unique: 39 TP files, 79 FP files, ratio=1.13 (\u22651.0, OK). Total-fires measurement was ratio=1.78 (1.6x higher) but per-file is more conservative. precision=33.05% (below 50% USEFUL threshold); verdict=OK. The direction is positive: post-2024 Swift (especially AI-generated examples in OpenAI Swift, WhisperKit) uses print() for output; pre-2022 production Swift (Alamofire, Vapor, Moya) uses os.Logger / OSLog. Same direction as kotlin/println-as-log (1.84) and java/system-out-println (1.73 refined, 3.29 unrefined). INSUFFICIENT_DATA: pos arm 568 files (below 10k floor).",
45576
+ _calibrationNote: "v0.34.2: REFINED \u2014 rule now skips test files (XCTest naming: *Tests.swift, *Test.swift, Tests/ dir). Per-file unique v9 Swift calibration (1300 neg, 568 pos): 39 TP files, 79 FP files, ratio=1.13 (OK). The refinement is expected to push precision from 33% to 50%+ by removing XCTest output and snapshot test fires (which were ~49% of FPs in the v0.32.0 measurement). The full v9 re-calibration is part of the v0.34.5/v0.34.7 pipeline (same refinement applied to kotlin/println-as-log and cpp/printf-debug); see v0.34.1's Four-language validation section. v0.32.0 baseline: 39 TP files / 568 = 6.87% recall, 79 FP files / 1300 = 6.08% fpRate, ratio 1.13, precision 33.05% (just below 50% USEFUL threshold). Same direction as kotlin/println-as-log (1.84) and java/system-out-println (1.73 refined, 3.29 unrefined). INSUFFICIENT_DATA: pos arm 568 files (below 10k floor).",
45573
45577
  aiSpecific: true,
45574
45578
  _v7Verdict: "DORMANT",
45575
45579
  _v7Lift: 1,
@@ -45707,7 +45711,7 @@ var signal_strength_default = {
45707
45711
  precision: 0.2325,
45708
45712
  lastCalibratedAt: "2026-07-03T00:00:00Z",
45709
45713
  verdict: "DORMANT",
45710
- _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.",
45714
+ _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.",
45711
45715
  aiSpecific: true,
45712
45716
  _v7Verdict: "DORMANT",
45713
45717
  _v7Lift: 1,
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.1";
39
+ VERSION = "0.34.3";
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;
@@ -41055,13 +41057,14 @@ var init_implicitly_unwrapped_optional = __esm({
41055
41057
  });
41056
41058
 
41057
41059
  // src/rules/swift/print-debug.ts
41058
- var PRINT_REGEX, DEFAULT_THRESHOLD2, swiftPrintDebugRule;
41060
+ var PRINT_REGEX, DEFAULT_THRESHOLD2, TEST_FILE_REGEX, swiftPrintDebugRule;
41059
41061
  var init_print_debug = __esm({
41060
41062
  "src/rules/swift/print-debug.ts"() {
41061
41063
  "use strict";
41062
41064
  init_rule();
41063
41065
  PRINT_REGEX = /\bprint\s*\(/g;
41064
41066
  DEFAULT_THRESHOLD2 = 1;
41067
+ TEST_FILE_REGEX = /(?:\/Tests\/|\/Tests\.swift|\/Test\.swift|Tests\.swift$|Test\.swift$)/;
41065
41068
  swiftPrintDebugRule = createRule({
41066
41069
  id: "swift/print-debug",
41067
41070
  category: "typo",
@@ -41076,6 +41079,7 @@ var init_print_debug = __esm({
41076
41079
  const source = facts.v2?._source;
41077
41080
  if (!source) return issues;
41078
41081
  if (!/\.swift$/i.test(facts.filePath)) return issues;
41082
+ if (TEST_FILE_REGEX.test(facts.filePath)) return issues;
41079
41083
  const matches = [];
41080
41084
  let m;
41081
41085
  PRINT_REGEX.lastIndex = 0;
@@ -41095,7 +41099,7 @@ var init_print_debug = __esm({
41095
41099
  message: `print(...) at line ${line} \u2014 use Logger (os.log) for production output`,
41096
41100
  line,
41097
41101
  column: 1,
41098
- advice: 'Replace with `Logger(subsystem: "...", category: "...").info("...")` (Unified Logging System, os.log). `print` writes to stdout with no level, no redaction, and no way to silence in release builds. The `Logger` API integrates with Console.app and respects the device\'s privacy settings. Multiple `print` calls in one Swift file is an AI fingerprint \u2014 agents reach for `print` because of training-data examples. Reference: swift/print-debug v0.24.'
41102
+ advice: 'Replace with `Logger(subsystem: "...", category: "...").info("...")` (Unified Logging System, os.log). `print` writes to stdout with no level, no redaction, and no way to silence in release builds. The `Logger` API integrates with Console.app and respects the device\'s privacy settings. Multiple `print` calls in one Swift file is an AI fingerprint \u2014 agents reach for `print` because of training-data examples. Reference: swift/print-debug v0.34.2 (refined to skip test files for higher precision).'
41099
41103
  });
41100
41104
  }
41101
41105
  return issues;
@@ -51685,7 +51689,7 @@ var init_signal_strength = __esm({
51685
51689
  precision: 0.3305,
51686
51690
  lastCalibratedAt: "2026-07-03T00:00:00Z",
51687
51691
  verdict: "OK",
51688
- _calibrationNote: "v0.32: v9 Swift calibration (1300 neg, 568 pos). Per-file unique: 39 TP files, 79 FP files, ratio=1.13 (\u22651.0, OK). Total-fires measurement was ratio=1.78 (1.6x higher) but per-file is more conservative. precision=33.05% (below 50% USEFUL threshold); verdict=OK. The direction is positive: post-2024 Swift (especially AI-generated examples in OpenAI Swift, WhisperKit) uses print() for output; pre-2022 production Swift (Alamofire, Vapor, Moya) uses os.Logger / OSLog. Same direction as kotlin/println-as-log (1.84) and java/system-out-println (1.73 refined, 3.29 unrefined). INSUFFICIENT_DATA: pos arm 568 files (below 10k floor).",
51692
+ _calibrationNote: "v0.34.2: REFINED \u2014 rule now skips test files (XCTest naming: *Tests.swift, *Test.swift, Tests/ dir). Per-file unique v9 Swift calibration (1300 neg, 568 pos): 39 TP files, 79 FP files, ratio=1.13 (OK). The refinement is expected to push precision from 33% to 50%+ by removing XCTest output and snapshot test fires (which were ~49% of FPs in the v0.32.0 measurement). The full v9 re-calibration is part of the v0.34.5/v0.34.7 pipeline (same refinement applied to kotlin/println-as-log and cpp/printf-debug); see v0.34.1's Four-language validation section. v0.32.0 baseline: 39 TP files / 568 = 6.87% recall, 79 FP files / 1300 = 6.08% fpRate, ratio 1.13, precision 33.05% (just below 50% USEFUL threshold). Same direction as kotlin/println-as-log (1.84) and java/system-out-println (1.73 refined, 3.29 unrefined). INSUFFICIENT_DATA: pos arm 568 files (below 10k floor).",
51689
51693
  aiSpecific: true,
51690
51694
  _v7Verdict: "DORMANT",
51691
51695
  _v7Lift: 1,
@@ -51823,7 +51827,7 @@ var init_signal_strength = __esm({
51823
51827
  precision: 0.2325,
51824
51828
  lastCalibratedAt: "2026-07-03T00:00:00Z",
51825
51829
  verdict: "DORMANT",
51826
- _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.",
51830
+ _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.",
51827
51831
  aiSpecific: true,
51828
51832
  _v7Verdict: "DORMANT",
51829
51833
  _v7Lift: 1,
package/dist/index.js CHANGED
@@ -19,7 +19,7 @@ var VERSION;
19
19
  var init_header = __esm({
20
20
  "src/types/_header.ts"() {
21
21
  "use strict";
22
- VERSION = "0.34.1";
22
+ VERSION = "0.34.3";
23
23
  }
24
24
  });
25
25
 
@@ -27642,13 +27642,14 @@ var init_import_path_mismatch = __esm({
27642
27642
  });
27643
27643
 
27644
27644
  // src/rules/cpp/c-style-cast.ts
27645
- var C_STYLE_CAST_REGEX, NAMED_CAST_PREFIX_REGEX, cppCStyleCastRule;
27645
+ var C_STYLE_CAST_REGEX, NAMED_CAST_PREFIX_REGEX, VOID_CAST_REGEX, cppCStyleCastRule;
27646
27646
  var init_c_style_cast = __esm({
27647
27647
  "src/rules/cpp/c-style-cast.ts"() {
27648
27648
  "use strict";
27649
27649
  init_rule();
27650
27650
  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;
27651
- NAMED_CAST_PREFIX_REGEX = /\b(?:static|reinterpret|const|dynamic)_cast\s*<[^>]*>\s*\($/;
27651
+ NAMED_CAST_PREFIX_REGEX = /\b(?:static|reinterpret|const|dynamic)_cast\s*<[^>]*>\s*$/;
27652
+ VOID_CAST_REGEX = /^\s*void\s*$/;
27652
27653
  cppCStyleCastRule = createRule({
27653
27654
  id: "cpp/c-style-cast",
27654
27655
  category: "typo",
@@ -27668,9 +27669,10 @@ var init_c_style_cast = __esm({
27668
27669
  while ((m = C_STYLE_CAST_REGEX.exec(source)) !== null) {
27669
27670
  const innerMatch = /\(\s*([^)]+?)\s*\)/.exec(m[0]) ?? [];
27670
27671
  const inner = (innerMatch[1] ?? "").trim();
27672
+ if (VOID_CAST_REGEX.test(inner)) continue;
27671
27673
  const looksLikeCast = /\b(?:int|long|short|char|float|double|bool|unsigned|signed|size_t)\b/.test(inner) || /[*&]/.test(inner);
27672
27674
  if (!looksLikeCast) continue;
27673
- const before = source.slice(Math.max(0, m.index - 40), m.index);
27675
+ const before = source.slice(Math.max(0, m.index - 60), m.index);
27674
27676
  if (NAMED_CAST_PREFIX_REGEX.test(before)) continue;
27675
27677
  const line = source.slice(0, m.index).split("\n").length;
27676
27678
  issues.push({
@@ -27681,7 +27683,7 @@ var init_c_style_cast = __esm({
27681
27683
  message: `C-style cast at line ${line} \u2014 use static_cast / reinterpret_cast / const_cast`,
27682
27684
  line,
27683
27685
  column: 1,
27684
- 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."
27686
+ 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)."
27685
27687
  });
27686
27688
  }
27687
27689
  return issues;
@@ -41036,13 +41038,14 @@ var init_implicitly_unwrapped_optional = __esm({
41036
41038
  });
41037
41039
 
41038
41040
  // src/rules/swift/print-debug.ts
41039
- var PRINT_REGEX, DEFAULT_THRESHOLD2, swiftPrintDebugRule;
41041
+ var PRINT_REGEX, DEFAULT_THRESHOLD2, TEST_FILE_REGEX, swiftPrintDebugRule;
41040
41042
  var init_print_debug = __esm({
41041
41043
  "src/rules/swift/print-debug.ts"() {
41042
41044
  "use strict";
41043
41045
  init_rule();
41044
41046
  PRINT_REGEX = /\bprint\s*\(/g;
41045
41047
  DEFAULT_THRESHOLD2 = 1;
41048
+ TEST_FILE_REGEX = /(?:\/Tests\/|\/Tests\.swift|\/Test\.swift|Tests\.swift$|Test\.swift$)/;
41046
41049
  swiftPrintDebugRule = createRule({
41047
41050
  id: "swift/print-debug",
41048
41051
  category: "typo",
@@ -41057,6 +41060,7 @@ var init_print_debug = __esm({
41057
41060
  const source = facts.v2?._source;
41058
41061
  if (!source) return issues;
41059
41062
  if (!/\.swift$/i.test(facts.filePath)) return issues;
41063
+ if (TEST_FILE_REGEX.test(facts.filePath)) return issues;
41060
41064
  const matches = [];
41061
41065
  let m;
41062
41066
  PRINT_REGEX.lastIndex = 0;
@@ -41076,7 +41080,7 @@ var init_print_debug = __esm({
41076
41080
  message: `print(...) at line ${line} \u2014 use Logger (os.log) for production output`,
41077
41081
  line,
41078
41082
  column: 1,
41079
- advice: 'Replace with `Logger(subsystem: "...", category: "...").info("...")` (Unified Logging System, os.log). `print` writes to stdout with no level, no redaction, and no way to silence in release builds. The `Logger` API integrates with Console.app and respects the device\'s privacy settings. Multiple `print` calls in one Swift file is an AI fingerprint \u2014 agents reach for `print` because of training-data examples. Reference: swift/print-debug v0.24.'
41083
+ advice: 'Replace with `Logger(subsystem: "...", category: "...").info("...")` (Unified Logging System, os.log). `print` writes to stdout with no level, no redaction, and no way to silence in release builds. The `Logger` API integrates with Console.app and respects the device\'s privacy settings. Multiple `print` calls in one Swift file is an AI fingerprint \u2014 agents reach for `print` because of training-data examples. Reference: swift/print-debug v0.34.2 (refined to skip test files for higher precision).'
41080
41084
  });
41081
41085
  }
41082
41086
  return issues;
@@ -51663,7 +51667,7 @@ var init_signal_strength = __esm({
51663
51667
  precision: 0.3305,
51664
51668
  lastCalibratedAt: "2026-07-03T00:00:00Z",
51665
51669
  verdict: "OK",
51666
- _calibrationNote: "v0.32: v9 Swift calibration (1300 neg, 568 pos). Per-file unique: 39 TP files, 79 FP files, ratio=1.13 (\u22651.0, OK). Total-fires measurement was ratio=1.78 (1.6x higher) but per-file is more conservative. precision=33.05% (below 50% USEFUL threshold); verdict=OK. The direction is positive: post-2024 Swift (especially AI-generated examples in OpenAI Swift, WhisperKit) uses print() for output; pre-2022 production Swift (Alamofire, Vapor, Moya) uses os.Logger / OSLog. Same direction as kotlin/println-as-log (1.84) and java/system-out-println (1.73 refined, 3.29 unrefined). INSUFFICIENT_DATA: pos arm 568 files (below 10k floor).",
51670
+ _calibrationNote: "v0.34.2: REFINED \u2014 rule now skips test files (XCTest naming: *Tests.swift, *Test.swift, Tests/ dir). Per-file unique v9 Swift calibration (1300 neg, 568 pos): 39 TP files, 79 FP files, ratio=1.13 (OK). The refinement is expected to push precision from 33% to 50%+ by removing XCTest output and snapshot test fires (which were ~49% of FPs in the v0.32.0 measurement). The full v9 re-calibration is part of the v0.34.5/v0.34.7 pipeline (same refinement applied to kotlin/println-as-log and cpp/printf-debug); see v0.34.1's Four-language validation section. v0.32.0 baseline: 39 TP files / 568 = 6.87% recall, 79 FP files / 1300 = 6.08% fpRate, ratio 1.13, precision 33.05% (just below 50% USEFUL threshold). Same direction as kotlin/println-as-log (1.84) and java/system-out-println (1.73 refined, 3.29 unrefined). INSUFFICIENT_DATA: pos arm 568 files (below 10k floor).",
51667
51671
  aiSpecific: true,
51668
51672
  _v7Verdict: "DORMANT",
51669
51673
  _v7Lift: 1,
@@ -51801,7 +51805,7 @@ var init_signal_strength = __esm({
51801
51805
  precision: 0.2325,
51802
51806
  lastCalibratedAt: "2026-07-03T00:00:00Z",
51803
51807
  verdict: "DORMANT",
51804
- _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.",
51808
+ _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.",
51805
51809
  aiSpecific: true,
51806
51810
  _v7Verdict: "DORMANT",
51807
51811
  _v7Lift: 1,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slopbrick",
3
- "version": "0.34.1",
3
+ "version": "0.34.3",
4
4
  "description": "Discovered, modeled, and governed repository structure. SlopBrick scans source code, classifies it against 95+ rules in 15 categories, computes 4 scores (aiSlopScore: lower=cleaner, engineeringHygiene, security, repositoryHealth composite), and persists the structure for AI agents and CI.",
5
5
  "type": "module",
6
6
  "bin": {