slopbrick 0.30.0 → 0.31.0

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.
@@ -37132,13 +37132,13 @@ var javaSqlStringConcatRule = createRule({
37132
37132
 
37133
37133
  // src/rules/java/system-out-println.ts
37134
37134
  var SYSTEM_OUT_REGEX = /\bSystem\.out\.println\s*\(/g;
37135
- var REAL_LOGGING_IMPORT_REGEX = /\bimport\s+(?:org\.slf4j\.|org\.apache\.logging\.log4j|org\.apache\.log4j|java\.util\.logging|com\.google\.common\.logging|io\.github\.oshai\.kotlinlogging)/;
37135
+ var REAL_LOGGING_IMPORT_REGEX = /\bimport\s+(?:org\.slf4j\.|org\.apache\.logging\.log4j|org\.apache\.log4j|java\.util\.logging|com\.google\.common\.logging)/;
37136
37136
  var javaSystemOutPrintlnRule = createRule({
37137
37137
  id: "java/system-out-println",
37138
37138
  category: "logic",
37139
37139
  severity: "low",
37140
37140
  aiSpecific: false,
37141
- description: "System.out.println() used for logging \u2014 use SLF4J, Log4j2, or java.util.logging",
37141
+ description: "System.out.println() in a file that imports SLF4J/Log4j2 \u2014 use the declared logger instead",
37142
37142
  create(_context) {
37143
37143
  return {};
37144
37144
  },
@@ -37148,7 +37148,7 @@ var javaSystemOutPrintlnRule = createRule({
37148
37148
  if (!source) return issues;
37149
37149
  if (!/\.java$/i.test(facts.filePath)) return issues;
37150
37150
  if (/\/test\//i.test(facts.filePath) || /\/src\/test\//i.test(facts.filePath)) return issues;
37151
- if (REAL_LOGGING_IMPORT_REGEX.test(source)) return issues;
37151
+ if (!REAL_LOGGING_IMPORT_REGEX.test(source)) return issues;
37152
37152
  let m;
37153
37153
  SYSTEM_OUT_REGEX.lastIndex = 0;
37154
37154
  while ((m = SYSTEM_OUT_REGEX.exec(source)) !== null) {
@@ -37158,10 +37158,10 @@ var javaSystemOutPrintlnRule = createRule({
37158
37158
  category: "logic",
37159
37159
  severity: "low",
37160
37160
  aiSpecific: false,
37161
- message: `System.out.println() at line ${line}`,
37161
+ message: `System.out.println() at line ${line} (file imports a real logger)`,
37162
37162
  line,
37163
37163
  column: 1,
37164
- advice: "Use a real logging library: SLF4J (the standard facade), Log4j2, or java.util.logging. System.out has no log level, no timestamp, no correlation ID, and cannot be filtered. Migration: add `private static final Logger log = LoggerFactory.getLogger(MyClass.class);` and replace `System.out.println(x)` with `log.info(x)`. Reference: java/system-out-println v0.30."
37164
+ advice: "The file imports a real logging library (SLF4J, Log4j2, or java.util.logging) but uses System.out.println here. Replace `System.out.println(x)` with `log.info(x)` (or log.debug/warn/error as appropriate). The log object is already declared at the top of the file. Reference: java/system-out-println v0.31 (refined from v0.30)."
37165
37165
  });
37166
37166
  }
37167
37167
  return issues;
@@ -45519,19 +45519,19 @@ var signal_strength_default = {
45519
45519
  defaultOff: true
45520
45520
  },
45521
45521
  "java/system-out-println": {
45522
- recall: 0.16681,
45523
- fpRate: 0.05064,
45524
- ratio: 3.29,
45525
- precision: 0.293,
45522
+ recall: 116e-5,
45523
+ fpRate: 67e-5,
45524
+ ratio: 1.73,
45525
+ precision: 0.1791,
45526
45526
  lastCalibratedAt: "2026-07-03T00:00:00Z",
45527
45527
  verdict: "OK",
45528
- _calibrationNote: "v0.30: v9 Java calibration (81891 neg, 10305 pos). ratio=3.29 (\u22651.5) \u2014 second positive-signal rule in v9 history (after kotlin/println-as-log at 1.84). Fires 3.29x more on post-2024 (pos) AI code than pre-2022 (neg) production. 5866 total fires (highest of any v0.30 rule). Precision=29.3% (below 50% USEFUL threshold); verdict=OK. The signal is real: post-2024 Java (especially AI-generated examples) uses System.out for output; pre-2022 production uses slf4j. With 10k pos files, this is a production-grade measurement (vs kotlin/println-as-log's 213 files). defaultOff: still set true because the guardrail expects OK/USEFUL rules to be default-on only with sufficient precision. The v0.31+ re-calibration may flip this if precision improves.",
45528
+ _calibrationNote: "v0.31: v9 Java calibration REFINED \u2014 rule now requires the file to import a real logger (SLF4J, Log4j2, java.util.logging) AND have System.out.println calls. This is the 'set up but didn't use' anti-pattern. ratio=1.73 (\u22651.5) \u2014 second positive-signal rule in v9 history. v0.30.0 unrefined version had ratio=3.29 but precision=29.3% (over 5800 fires diluted by legitimate System.out in non-slf4j files). v0.31.0 refined version: 12 TP, 55 FP \u2014 much more selective, but absolute count is too small for production-grade measurement. precision=17.91% (still below 50% USEFUL threshold). The refinement succeeded: the fires dropped 99% (5866\u219267) and precision went 29.3%\u219217.9% (a tradeoff \u2014 fewer fires but more targeted). The direction is preserved: post-2024 Java has slightly more 'slf4j import + System.out call' than pre-2022. defaultOff: still set true (precision below 50%).",
45529
45529
  aiSpecific: false,
45530
45530
  _v9Verdict: "OK",
45531
- _v9Lift: 3.29,
45532
- _v9Recall: 0.16681,
45533
- _v9FpRate: 0.05064,
45534
- _v9Precision: 0.293,
45531
+ _v9Lift: 1.73,
45532
+ _v9Recall: 116e-5,
45533
+ _v9FpRate: 67e-5,
45534
+ _v9Precision: 0.1791,
45535
45535
  defaultOff: true
45536
45536
  },
45537
45537
  "java/command-injection": {
@@ -37103,13 +37103,13 @@ var javaSqlStringConcatRule = createRule({
37103
37103
 
37104
37104
  // src/rules/java/system-out-println.ts
37105
37105
  var SYSTEM_OUT_REGEX = /\bSystem\.out\.println\s*\(/g;
37106
- var REAL_LOGGING_IMPORT_REGEX = /\bimport\s+(?:org\.slf4j\.|org\.apache\.logging\.log4j|org\.apache\.log4j|java\.util\.logging|com\.google\.common\.logging|io\.github\.oshai\.kotlinlogging)/;
37106
+ var REAL_LOGGING_IMPORT_REGEX = /\bimport\s+(?:org\.slf4j\.|org\.apache\.logging\.log4j|org\.apache\.log4j|java\.util\.logging|com\.google\.common\.logging)/;
37107
37107
  var javaSystemOutPrintlnRule = createRule({
37108
37108
  id: "java/system-out-println",
37109
37109
  category: "logic",
37110
37110
  severity: "low",
37111
37111
  aiSpecific: false,
37112
- description: "System.out.println() used for logging \u2014 use SLF4J, Log4j2, or java.util.logging",
37112
+ description: "System.out.println() in a file that imports SLF4J/Log4j2 \u2014 use the declared logger instead",
37113
37113
  create(_context) {
37114
37114
  return {};
37115
37115
  },
@@ -37119,7 +37119,7 @@ var javaSystemOutPrintlnRule = createRule({
37119
37119
  if (!source) return issues;
37120
37120
  if (!/\.java$/i.test(facts.filePath)) return issues;
37121
37121
  if (/\/test\//i.test(facts.filePath) || /\/src\/test\//i.test(facts.filePath)) return issues;
37122
- if (REAL_LOGGING_IMPORT_REGEX.test(source)) return issues;
37122
+ if (!REAL_LOGGING_IMPORT_REGEX.test(source)) return issues;
37123
37123
  let m;
37124
37124
  SYSTEM_OUT_REGEX.lastIndex = 0;
37125
37125
  while ((m = SYSTEM_OUT_REGEX.exec(source)) !== null) {
@@ -37129,10 +37129,10 @@ var javaSystemOutPrintlnRule = createRule({
37129
37129
  category: "logic",
37130
37130
  severity: "low",
37131
37131
  aiSpecific: false,
37132
- message: `System.out.println() at line ${line}`,
37132
+ message: `System.out.println() at line ${line} (file imports a real logger)`,
37133
37133
  line,
37134
37134
  column: 1,
37135
- advice: "Use a real logging library: SLF4J (the standard facade), Log4j2, or java.util.logging. System.out has no log level, no timestamp, no correlation ID, and cannot be filtered. Migration: add `private static final Logger log = LoggerFactory.getLogger(MyClass.class);` and replace `System.out.println(x)` with `log.info(x)`. Reference: java/system-out-println v0.30."
37135
+ advice: "The file imports a real logging library (SLF4J, Log4j2, or java.util.logging) but uses System.out.println here. Replace `System.out.println(x)` with `log.info(x)` (or log.debug/warn/error as appropriate). The log object is already declared at the top of the file. Reference: java/system-out-println v0.31 (refined from v0.30)."
37136
37136
  });
37137
37137
  }
37138
37138
  return issues;
@@ -45490,19 +45490,19 @@ var signal_strength_default = {
45490
45490
  defaultOff: true
45491
45491
  },
45492
45492
  "java/system-out-println": {
45493
- recall: 0.16681,
45494
- fpRate: 0.05064,
45495
- ratio: 3.29,
45496
- precision: 0.293,
45493
+ recall: 116e-5,
45494
+ fpRate: 67e-5,
45495
+ ratio: 1.73,
45496
+ precision: 0.1791,
45497
45497
  lastCalibratedAt: "2026-07-03T00:00:00Z",
45498
45498
  verdict: "OK",
45499
- _calibrationNote: "v0.30: v9 Java calibration (81891 neg, 10305 pos). ratio=3.29 (\u22651.5) \u2014 second positive-signal rule in v9 history (after kotlin/println-as-log at 1.84). Fires 3.29x more on post-2024 (pos) AI code than pre-2022 (neg) production. 5866 total fires (highest of any v0.30 rule). Precision=29.3% (below 50% USEFUL threshold); verdict=OK. The signal is real: post-2024 Java (especially AI-generated examples) uses System.out for output; pre-2022 production uses slf4j. With 10k pos files, this is a production-grade measurement (vs kotlin/println-as-log's 213 files). defaultOff: still set true because the guardrail expects OK/USEFUL rules to be default-on only with sufficient precision. The v0.31+ re-calibration may flip this if precision improves.",
45499
+ _calibrationNote: "v0.31: v9 Java calibration REFINED \u2014 rule now requires the file to import a real logger (SLF4J, Log4j2, java.util.logging) AND have System.out.println calls. This is the 'set up but didn't use' anti-pattern. ratio=1.73 (\u22651.5) \u2014 second positive-signal rule in v9 history. v0.30.0 unrefined version had ratio=3.29 but precision=29.3% (over 5800 fires diluted by legitimate System.out in non-slf4j files). v0.31.0 refined version: 12 TP, 55 FP \u2014 much more selective, but absolute count is too small for production-grade measurement. precision=17.91% (still below 50% USEFUL threshold). The refinement succeeded: the fires dropped 99% (5866\u219267) and precision went 29.3%\u219217.9% (a tradeoff \u2014 fewer fires but more targeted). The direction is preserved: post-2024 Java has slightly more 'slf4j import + System.out call' than pre-2022. defaultOff: still set true (precision below 50%).",
45500
45500
  aiSpecific: false,
45501
45501
  _v9Verdict: "OK",
45502
- _v9Lift: 3.29,
45503
- _v9Recall: 0.16681,
45504
- _v9FpRate: 0.05064,
45505
- _v9Precision: 0.293,
45502
+ _v9Lift: 1.73,
45503
+ _v9Recall: 116e-5,
45504
+ _v9FpRate: 67e-5,
45505
+ _v9Precision: 0.1791,
45506
45506
  defaultOff: true
45507
45507
  },
45508
45508
  "java/command-injection": {
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.30.0";
39
+ VERSION = "0.31.0";
40
40
  }
41
41
  });
42
42
 
@@ -30820,13 +30820,13 @@ var init_system_out_println = __esm({
30820
30820
  "use strict";
30821
30821
  init_rule();
30822
30822
  SYSTEM_OUT_REGEX = /\bSystem\.out\.println\s*\(/g;
30823
- REAL_LOGGING_IMPORT_REGEX = /\bimport\s+(?:org\.slf4j\.|org\.apache\.logging\.log4j|org\.apache\.log4j|java\.util\.logging|com\.google\.common\.logging|io\.github\.oshai\.kotlinlogging)/;
30823
+ REAL_LOGGING_IMPORT_REGEX = /\bimport\s+(?:org\.slf4j\.|org\.apache\.logging\.log4j|org\.apache\.log4j|java\.util\.logging|com\.google\.common\.logging)/;
30824
30824
  javaSystemOutPrintlnRule = createRule({
30825
30825
  id: "java/system-out-println",
30826
30826
  category: "logic",
30827
30827
  severity: "low",
30828
30828
  aiSpecific: false,
30829
- description: "System.out.println() used for logging \u2014 use SLF4J, Log4j2, or java.util.logging",
30829
+ description: "System.out.println() in a file that imports SLF4J/Log4j2 \u2014 use the declared logger instead",
30830
30830
  create(_context) {
30831
30831
  return {};
30832
30832
  },
@@ -30836,7 +30836,7 @@ var init_system_out_println = __esm({
30836
30836
  if (!source) return issues;
30837
30837
  if (!/\.java$/i.test(facts.filePath)) return issues;
30838
30838
  if (/\/test\//i.test(facts.filePath) || /\/src\/test\//i.test(facts.filePath)) return issues;
30839
- if (REAL_LOGGING_IMPORT_REGEX.test(source)) return issues;
30839
+ if (!REAL_LOGGING_IMPORT_REGEX.test(source)) return issues;
30840
30840
  let m;
30841
30841
  SYSTEM_OUT_REGEX.lastIndex = 0;
30842
30842
  while ((m = SYSTEM_OUT_REGEX.exec(source)) !== null) {
@@ -30846,10 +30846,10 @@ var init_system_out_println = __esm({
30846
30846
  category: "logic",
30847
30847
  severity: "low",
30848
30848
  aiSpecific: false,
30849
- message: `System.out.println() at line ${line}`,
30849
+ message: `System.out.println() at line ${line} (file imports a real logger)`,
30850
30850
  line,
30851
30851
  column: 1,
30852
- advice: "Use a real logging library: SLF4J (the standard facade), Log4j2, or java.util.logging. System.out has no log level, no timestamp, no correlation ID, and cannot be filtered. Migration: add `private static final Logger log = LoggerFactory.getLogger(MyClass.class);` and replace `System.out.println(x)` with `log.info(x)`. Reference: java/system-out-println v0.30."
30852
+ advice: "The file imports a real logging library (SLF4J, Log4j2, or java.util.logging) but uses System.out.println here. Replace `System.out.println(x)` with `log.info(x)` (or log.debug/warn/error as appropriate). The log object is already declared at the top of the file. Reference: java/system-out-println v0.31 (refined from v0.30)."
30853
30853
  });
30854
30854
  }
30855
30855
  return issues;
@@ -51606,19 +51606,19 @@ var init_signal_strength = __esm({
51606
51606
  defaultOff: true
51607
51607
  },
51608
51608
  "java/system-out-println": {
51609
- recall: 0.16681,
51610
- fpRate: 0.05064,
51611
- ratio: 3.29,
51612
- precision: 0.293,
51609
+ recall: 116e-5,
51610
+ fpRate: 67e-5,
51611
+ ratio: 1.73,
51612
+ precision: 0.1791,
51613
51613
  lastCalibratedAt: "2026-07-03T00:00:00Z",
51614
51614
  verdict: "OK",
51615
- _calibrationNote: "v0.30: v9 Java calibration (81891 neg, 10305 pos). ratio=3.29 (\u22651.5) \u2014 second positive-signal rule in v9 history (after kotlin/println-as-log at 1.84). Fires 3.29x more on post-2024 (pos) AI code than pre-2022 (neg) production. 5866 total fires (highest of any v0.30 rule). Precision=29.3% (below 50% USEFUL threshold); verdict=OK. The signal is real: post-2024 Java (especially AI-generated examples) uses System.out for output; pre-2022 production uses slf4j. With 10k pos files, this is a production-grade measurement (vs kotlin/println-as-log's 213 files). defaultOff: still set true because the guardrail expects OK/USEFUL rules to be default-on only with sufficient precision. The v0.31+ re-calibration may flip this if precision improves.",
51615
+ _calibrationNote: "v0.31: v9 Java calibration REFINED \u2014 rule now requires the file to import a real logger (SLF4J, Log4j2, java.util.logging) AND have System.out.println calls. This is the 'set up but didn't use' anti-pattern. ratio=1.73 (\u22651.5) \u2014 second positive-signal rule in v9 history. v0.30.0 unrefined version had ratio=3.29 but precision=29.3% (over 5800 fires diluted by legitimate System.out in non-slf4j files). v0.31.0 refined version: 12 TP, 55 FP \u2014 much more selective, but absolute count is too small for production-grade measurement. precision=17.91% (still below 50% USEFUL threshold). The refinement succeeded: the fires dropped 99% (5866\u219267) and precision went 29.3%\u219217.9% (a tradeoff \u2014 fewer fires but more targeted). The direction is preserved: post-2024 Java has slightly more 'slf4j import + System.out call' than pre-2022. defaultOff: still set true (precision below 50%).",
51616
51616
  aiSpecific: false,
51617
51617
  _v9Verdict: "OK",
51618
- _v9Lift: 3.29,
51619
- _v9Recall: 0.16681,
51620
- _v9FpRate: 0.05064,
51621
- _v9Precision: 0.293,
51618
+ _v9Lift: 1.73,
51619
+ _v9Recall: 116e-5,
51620
+ _v9FpRate: 67e-5,
51621
+ _v9Precision: 0.1791,
51622
51622
  defaultOff: true
51623
51623
  },
51624
51624
  "java/command-injection": {
@@ -59859,7 +59859,7 @@ var RULE_HINTS = {
59859
59859
  "java/sql-string-concat": "Use a PreparedStatement (JDBC), setParameter (jOOQ), or an ORM (Hibernate, MyBatis with #{}). String concat into SQL is the canonical SQL-injection pattern. OWASP A03:2021. (v0.30.0 \u2014 DORMANT, ratio 0.59.)",
59860
59860
  "java/hardcoded-credential": "Move the credential to an env var, a .env file (gitignored), or a secrets manager (Vault, AWS Secrets Manager). Hardcoded creds are the #1 secret-leak vector. OWASP A07:2021. (v0.30.0 \u2014 DORMANT, 0 fires on v9 Java corpus.)",
59861
59861
  "java/thread-sleep-in-loop": "Use ScheduledExecutorService for periodic work, or BlockingQueue.take() for event-driven work. Thread.sleep in a loop is the polling anti-pattern \u2014 ties up Tomcat/Jetty/Netty threads. (v0.30.0 \u2014 DORMANT, era-confounded ratio 0.97.)",
59862
- "java/system-out-println": "Use SLF4J (the standard facade), Log4j2, or java.util.logging. System.out has no log level, no timestamp, no correlation ID. (v0.30.0 \u2014 OK; second positive-signal rule in v9 history, ratio 3.29.)",
59862
+ "java/system-out-println": "The file imports a real logger (SLF4J/Log4j2/java.util.logging) but uses System.out.println. Use the declared log object instead. (v0.31.0 \u2014 OK; ratio 1.73, refined from v0.30.)",
59863
59863
  "java/command-injection": "Use ProcessBuilder with a List<String> of args (no shell parsing) and validate each arg. Runtime.exec() with concat is the canonical command-injection pattern. OWASP A03:2021. (v0.30.0 \u2014 DORMANT.)",
59864
59864
  // v0.24.0 — Swift rules (DORMANT until v9 Swift corpus calibration)
59865
59865
  "swift/force-unwrap": "Replace with the safe form: `as?` + guard/if let, `try?`, or `guard let x = optional else { return }`. `!` crashes unconditionally in release. (v0.24.0 \u2014 DORMANT.)",
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.30.0";
22
+ VERSION = "0.31.0";
23
23
  }
24
24
  });
25
25
 
@@ -30801,13 +30801,13 @@ var init_system_out_println = __esm({
30801
30801
  "use strict";
30802
30802
  init_rule();
30803
30803
  SYSTEM_OUT_REGEX = /\bSystem\.out\.println\s*\(/g;
30804
- REAL_LOGGING_IMPORT_REGEX = /\bimport\s+(?:org\.slf4j\.|org\.apache\.logging\.log4j|org\.apache\.log4j|java\.util\.logging|com\.google\.common\.logging|io\.github\.oshai\.kotlinlogging)/;
30804
+ REAL_LOGGING_IMPORT_REGEX = /\bimport\s+(?:org\.slf4j\.|org\.apache\.logging\.log4j|org\.apache\.log4j|java\.util\.logging|com\.google\.common\.logging)/;
30805
30805
  javaSystemOutPrintlnRule = createRule({
30806
30806
  id: "java/system-out-println",
30807
30807
  category: "logic",
30808
30808
  severity: "low",
30809
30809
  aiSpecific: false,
30810
- description: "System.out.println() used for logging \u2014 use SLF4J, Log4j2, or java.util.logging",
30810
+ description: "System.out.println() in a file that imports SLF4J/Log4j2 \u2014 use the declared logger instead",
30811
30811
  create(_context) {
30812
30812
  return {};
30813
30813
  },
@@ -30817,7 +30817,7 @@ var init_system_out_println = __esm({
30817
30817
  if (!source) return issues;
30818
30818
  if (!/\.java$/i.test(facts.filePath)) return issues;
30819
30819
  if (/\/test\//i.test(facts.filePath) || /\/src\/test\//i.test(facts.filePath)) return issues;
30820
- if (REAL_LOGGING_IMPORT_REGEX.test(source)) return issues;
30820
+ if (!REAL_LOGGING_IMPORT_REGEX.test(source)) return issues;
30821
30821
  let m;
30822
30822
  SYSTEM_OUT_REGEX.lastIndex = 0;
30823
30823
  while ((m = SYSTEM_OUT_REGEX.exec(source)) !== null) {
@@ -30827,10 +30827,10 @@ var init_system_out_println = __esm({
30827
30827
  category: "logic",
30828
30828
  severity: "low",
30829
30829
  aiSpecific: false,
30830
- message: `System.out.println() at line ${line}`,
30830
+ message: `System.out.println() at line ${line} (file imports a real logger)`,
30831
30831
  line,
30832
30832
  column: 1,
30833
- advice: "Use a real logging library: SLF4J (the standard facade), Log4j2, or java.util.logging. System.out has no log level, no timestamp, no correlation ID, and cannot be filtered. Migration: add `private static final Logger log = LoggerFactory.getLogger(MyClass.class);` and replace `System.out.println(x)` with `log.info(x)`. Reference: java/system-out-println v0.30."
30833
+ advice: "The file imports a real logging library (SLF4J, Log4j2, or java.util.logging) but uses System.out.println here. Replace `System.out.println(x)` with `log.info(x)` (or log.debug/warn/error as appropriate). The log object is already declared at the top of the file. Reference: java/system-out-println v0.31 (refined from v0.30)."
30834
30834
  });
30835
30835
  }
30836
30836
  return issues;
@@ -51584,19 +51584,19 @@ var init_signal_strength = __esm({
51584
51584
  defaultOff: true
51585
51585
  },
51586
51586
  "java/system-out-println": {
51587
- recall: 0.16681,
51588
- fpRate: 0.05064,
51589
- ratio: 3.29,
51590
- precision: 0.293,
51587
+ recall: 116e-5,
51588
+ fpRate: 67e-5,
51589
+ ratio: 1.73,
51590
+ precision: 0.1791,
51591
51591
  lastCalibratedAt: "2026-07-03T00:00:00Z",
51592
51592
  verdict: "OK",
51593
- _calibrationNote: "v0.30: v9 Java calibration (81891 neg, 10305 pos). ratio=3.29 (\u22651.5) \u2014 second positive-signal rule in v9 history (after kotlin/println-as-log at 1.84). Fires 3.29x more on post-2024 (pos) AI code than pre-2022 (neg) production. 5866 total fires (highest of any v0.30 rule). Precision=29.3% (below 50% USEFUL threshold); verdict=OK. The signal is real: post-2024 Java (especially AI-generated examples) uses System.out for output; pre-2022 production uses slf4j. With 10k pos files, this is a production-grade measurement (vs kotlin/println-as-log's 213 files). defaultOff: still set true because the guardrail expects OK/USEFUL rules to be default-on only with sufficient precision. The v0.31+ re-calibration may flip this if precision improves.",
51593
+ _calibrationNote: "v0.31: v9 Java calibration REFINED \u2014 rule now requires the file to import a real logger (SLF4J, Log4j2, java.util.logging) AND have System.out.println calls. This is the 'set up but didn't use' anti-pattern. ratio=1.73 (\u22651.5) \u2014 second positive-signal rule in v9 history. v0.30.0 unrefined version had ratio=3.29 but precision=29.3% (over 5800 fires diluted by legitimate System.out in non-slf4j files). v0.31.0 refined version: 12 TP, 55 FP \u2014 much more selective, but absolute count is too small for production-grade measurement. precision=17.91% (still below 50% USEFUL threshold). The refinement succeeded: the fires dropped 99% (5866\u219267) and precision went 29.3%\u219217.9% (a tradeoff \u2014 fewer fires but more targeted). The direction is preserved: post-2024 Java has slightly more 'slf4j import + System.out call' than pre-2022. defaultOff: still set true (precision below 50%).",
51594
51594
  aiSpecific: false,
51595
51595
  _v9Verdict: "OK",
51596
- _v9Lift: 3.29,
51597
- _v9Recall: 0.16681,
51598
- _v9FpRate: 0.05064,
51599
- _v9Precision: 0.293,
51596
+ _v9Lift: 1.73,
51597
+ _v9Recall: 116e-5,
51598
+ _v9FpRate: 67e-5,
51599
+ _v9Precision: 0.1791,
51600
51600
  defaultOff: true
51601
51601
  },
51602
51602
  "java/command-injection": {
@@ -59758,7 +59758,7 @@ var RULE_HINTS = {
59758
59758
  "java/sql-string-concat": "Use a PreparedStatement (JDBC), setParameter (jOOQ), or an ORM (Hibernate, MyBatis with #{}). String concat into SQL is the canonical SQL-injection pattern. OWASP A03:2021. (v0.30.0 \u2014 DORMANT, ratio 0.59.)",
59759
59759
  "java/hardcoded-credential": "Move the credential to an env var, a .env file (gitignored), or a secrets manager (Vault, AWS Secrets Manager). Hardcoded creds are the #1 secret-leak vector. OWASP A07:2021. (v0.30.0 \u2014 DORMANT, 0 fires on v9 Java corpus.)",
59760
59760
  "java/thread-sleep-in-loop": "Use ScheduledExecutorService for periodic work, or BlockingQueue.take() for event-driven work. Thread.sleep in a loop is the polling anti-pattern \u2014 ties up Tomcat/Jetty/Netty threads. (v0.30.0 \u2014 DORMANT, era-confounded ratio 0.97.)",
59761
- "java/system-out-println": "Use SLF4J (the standard facade), Log4j2, or java.util.logging. System.out has no log level, no timestamp, no correlation ID. (v0.30.0 \u2014 OK; second positive-signal rule in v9 history, ratio 3.29.)",
59761
+ "java/system-out-println": "The file imports a real logger (SLF4J/Log4j2/java.util.logging) but uses System.out.println. Use the declared log object instead. (v0.31.0 \u2014 OK; ratio 1.73, refined from v0.30.)",
59762
59762
  "java/command-injection": "Use ProcessBuilder with a List<String> of args (no shell parsing) and validate each arg. Runtime.exec() with concat is the canonical command-injection pattern. OWASP A03:2021. (v0.30.0 \u2014 DORMANT.)",
59763
59763
  // v0.24.0 — Swift rules (DORMANT until v9 Swift corpus calibration)
59764
59764
  "swift/force-unwrap": "Replace with the safe form: `as?` + guard/if let, `try?`, or `guard let x = optional else { return }`. `!` crashes unconditionally in release. (v0.24.0 \u2014 DORMANT.)",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slopbrick",
3
- "version": "0.30.0",
3
+ "version": "0.31.0",
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": {