slopbrick 0.35.0 → 0.35.1

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.
@@ -37139,6 +37139,67 @@ var javaHardcodedCredentialRule = createRule({
37139
37139
  }
37140
37140
  });
37141
37141
 
37142
+ // src/rules/java/lost-stack-trace.ts
37143
+ var THROW_NEW_REGEX = /throw\s+new\s+(\w+(?:Exception|Error|Throwable))\s*\(([^)]*)\)/g;
37144
+ var CATCH_REGEX = /catch\s*\(\s*(?:final\s+)?[\w<>,\s]+\s+(\w+)\s*\)\s*\{/g;
37145
+ var javaLostStackTraceRule = createRule({
37146
+ id: "java/lost-stack-trace",
37147
+ category: "logic",
37148
+ severity: "medium",
37149
+ aiSpecific: false,
37150
+ description: "catch block throws a new exception without the original cause \u2014 stack trace is lost",
37151
+ create(_context) {
37152
+ return {};
37153
+ },
37154
+ analyze(_context, facts) {
37155
+ const issues = [];
37156
+ const source = facts.v2?._source;
37157
+ if (!source) return issues;
37158
+ if (!/\.java$/i.test(facts.filePath)) return issues;
37159
+ if (/\/test\//i.test(facts.filePath) || /\/src\/test\//i.test(facts.filePath)) return issues;
37160
+ const catchBlocks = [];
37161
+ let cm;
37162
+ CATCH_REGEX.lastIndex = 0;
37163
+ while ((cm = CATCH_REGEX.exec(source)) !== null) {
37164
+ const catchStart = cm.index;
37165
+ const exVar = cm[1];
37166
+ let depth = 1;
37167
+ let i = cm.index + cm[0].length;
37168
+ while (i < source.length && depth > 0) {
37169
+ const ch = source[i];
37170
+ if (ch === "{") depth++;
37171
+ else if (ch === "}") depth--;
37172
+ i++;
37173
+ }
37174
+ catchBlocks.push({ start: catchStart, end: i, exVar });
37175
+ }
37176
+ let m;
37177
+ THROW_NEW_REGEX.lastIndex = 0;
37178
+ while ((m = THROW_NEW_REGEX.exec(source)) !== null) {
37179
+ const throwPos = m.index;
37180
+ const args = m[2].trim();
37181
+ const enclosing = catchBlocks.find(
37182
+ (cb) => cb.start < throwPos && throwPos < cb.end
37183
+ );
37184
+ if (!enclosing) continue;
37185
+ const exVarPattern = new RegExp(`\\b${enclosing.exVar}\\b`);
37186
+ if (exVarPattern.test(args)) continue;
37187
+ const line = source.slice(0, throwPos).split("\n").length;
37188
+ issues.push({
37189
+ ruleId: "java/lost-stack-trace",
37190
+ category: "logic",
37191
+ severity: "medium",
37192
+ aiSpecific: false,
37193
+ message: `throw new ${m[1]}(${args}) \u2014 original exception \`${enclosing.exVar}\` is not included as cause`,
37194
+ line,
37195
+ column: 1,
37196
+ advice: `The catch block declares exception variable \`${enclosing.exVar}\` but the throw statement doesn't include it as a cause. The original stack trace is lost. Fix: \`throw new ${m[1]}("...", ${enclosing.exVar})\` \u2014 the second argument to the exception constructor is the cause, which Java's Throwable framework preserves in the stack trace chain. Reference: java/lost-stack-trace v0.35.1 (Raidar-inspired content-based detection of AI-polished error handling).`
37197
+ });
37198
+ }
37199
+ return issues;
37200
+ }
37201
+ });
37202
+
37142
37203
  // src/rules/java/sql-string-concat.ts
37143
37204
  var SQL_KEYWORD_REGEX = /\b(?:SELECT|INSERT\s+INTO|UPDATE|DELETE\s+FROM|CREATE\s+TABLE|DROP\s+TABLE|ALTER\s+TABLE)\b/i;
37144
37205
  var UNSAFE_REGEX = /\+/;
@@ -43375,6 +43436,7 @@ var builtinRules = [
43375
43436
  goStructTagInconsistencyRule,
43376
43437
  javaCommandInjectionRule,
43377
43438
  javaHardcodedCredentialRule,
43439
+ javaLostStackTraceRule,
43378
43440
  javaSqlStringConcatRule,
43379
43441
  javaSuspiciousImplementationRule,
43380
43442
  javaSystemOutPrintlnRule,
@@ -45782,6 +45844,22 @@ var signal_strength_default = {
45782
45844
  _v9Precision: 0,
45783
45845
  defaultOff: false
45784
45846
  },
45847
+ "java/lost-stack-trace": {
45848
+ recall: 0,
45849
+ fpRate: 0,
45850
+ ratio: 0,
45851
+ precision: 0,
45852
+ lastCalibratedAt: "2026-07-03T00:00:00Z",
45853
+ verdict: "OK",
45854
+ _calibrationNote: "v0.35.1: NEW RULE \u2014 Raidar-inspired content-based detection. The Raidar paper (ICLR 2024) showed that LLMs tend to 'polish' error handling by wrapping exceptions but losing the original cause; the inverse observation is that AI-generated code often has this pattern. This rule detects catch blocks that throw a new exception WITHOUT including the original exception as a cause \u2014 the original stack trace is lost. The rule is a real engineering defect detector (not AI fingerprint), so it is defaultOff=false (ON by default) and verdict=OK. v9 calibration is pending. The expected impact: low recall (most production code preserves the original exception) but very high precision (when it fires, it's a real bug \u2014 debugging without the stack trace is impossible).",
45855
+ aiSpecific: false,
45856
+ _v9Verdict: "OK",
45857
+ _v9Lift: 0,
45858
+ _v9Recall: 0,
45859
+ _v9FpRate: 0,
45860
+ _v9Precision: 0,
45861
+ defaultOff: false
45862
+ },
45785
45863
  "swift/force-unwrap": {
45786
45864
  recall: 0.10211,
45787
45865
  fpRate: 0.21462,
@@ -37110,6 +37110,67 @@ var javaHardcodedCredentialRule = createRule({
37110
37110
  }
37111
37111
  });
37112
37112
 
37113
+ // src/rules/java/lost-stack-trace.ts
37114
+ var THROW_NEW_REGEX = /throw\s+new\s+(\w+(?:Exception|Error|Throwable))\s*\(([^)]*)\)/g;
37115
+ var CATCH_REGEX = /catch\s*\(\s*(?:final\s+)?[\w<>,\s]+\s+(\w+)\s*\)\s*\{/g;
37116
+ var javaLostStackTraceRule = createRule({
37117
+ id: "java/lost-stack-trace",
37118
+ category: "logic",
37119
+ severity: "medium",
37120
+ aiSpecific: false,
37121
+ description: "catch block throws a new exception without the original cause \u2014 stack trace is lost",
37122
+ create(_context) {
37123
+ return {};
37124
+ },
37125
+ analyze(_context, facts) {
37126
+ const issues = [];
37127
+ const source = facts.v2?._source;
37128
+ if (!source) return issues;
37129
+ if (!/\.java$/i.test(facts.filePath)) return issues;
37130
+ if (/\/test\//i.test(facts.filePath) || /\/src\/test\//i.test(facts.filePath)) return issues;
37131
+ const catchBlocks = [];
37132
+ let cm;
37133
+ CATCH_REGEX.lastIndex = 0;
37134
+ while ((cm = CATCH_REGEX.exec(source)) !== null) {
37135
+ const catchStart = cm.index;
37136
+ const exVar = cm[1];
37137
+ let depth = 1;
37138
+ let i = cm.index + cm[0].length;
37139
+ while (i < source.length && depth > 0) {
37140
+ const ch = source[i];
37141
+ if (ch === "{") depth++;
37142
+ else if (ch === "}") depth--;
37143
+ i++;
37144
+ }
37145
+ catchBlocks.push({ start: catchStart, end: i, exVar });
37146
+ }
37147
+ let m;
37148
+ THROW_NEW_REGEX.lastIndex = 0;
37149
+ while ((m = THROW_NEW_REGEX.exec(source)) !== null) {
37150
+ const throwPos = m.index;
37151
+ const args = m[2].trim();
37152
+ const enclosing = catchBlocks.find(
37153
+ (cb) => cb.start < throwPos && throwPos < cb.end
37154
+ );
37155
+ if (!enclosing) continue;
37156
+ const exVarPattern = new RegExp(`\\b${enclosing.exVar}\\b`);
37157
+ if (exVarPattern.test(args)) continue;
37158
+ const line = source.slice(0, throwPos).split("\n").length;
37159
+ issues.push({
37160
+ ruleId: "java/lost-stack-trace",
37161
+ category: "logic",
37162
+ severity: "medium",
37163
+ aiSpecific: false,
37164
+ message: `throw new ${m[1]}(${args}) \u2014 original exception \`${enclosing.exVar}\` is not included as cause`,
37165
+ line,
37166
+ column: 1,
37167
+ advice: `The catch block declares exception variable \`${enclosing.exVar}\` but the throw statement doesn't include it as a cause. The original stack trace is lost. Fix: \`throw new ${m[1]}("...", ${enclosing.exVar})\` \u2014 the second argument to the exception constructor is the cause, which Java's Throwable framework preserves in the stack trace chain. Reference: java/lost-stack-trace v0.35.1 (Raidar-inspired content-based detection of AI-polished error handling).`
37168
+ });
37169
+ }
37170
+ return issues;
37171
+ }
37172
+ });
37173
+
37113
37174
  // src/rules/java/sql-string-concat.ts
37114
37175
  var SQL_KEYWORD_REGEX = /\b(?:SELECT|INSERT\s+INTO|UPDATE|DELETE\s+FROM|CREATE\s+TABLE|DROP\s+TABLE|ALTER\s+TABLE)\b/i;
37115
37176
  var UNSAFE_REGEX = /\+/;
@@ -43346,6 +43407,7 @@ var builtinRules = [
43346
43407
  goStructTagInconsistencyRule,
43347
43408
  javaCommandInjectionRule,
43348
43409
  javaHardcodedCredentialRule,
43410
+ javaLostStackTraceRule,
43349
43411
  javaSqlStringConcatRule,
43350
43412
  javaSuspiciousImplementationRule,
43351
43413
  javaSystemOutPrintlnRule,
@@ -45753,6 +45815,22 @@ var signal_strength_default = {
45753
45815
  _v9Precision: 0,
45754
45816
  defaultOff: false
45755
45817
  },
45818
+ "java/lost-stack-trace": {
45819
+ recall: 0,
45820
+ fpRate: 0,
45821
+ ratio: 0,
45822
+ precision: 0,
45823
+ lastCalibratedAt: "2026-07-03T00:00:00Z",
45824
+ verdict: "OK",
45825
+ _calibrationNote: "v0.35.1: NEW RULE \u2014 Raidar-inspired content-based detection. The Raidar paper (ICLR 2024) showed that LLMs tend to 'polish' error handling by wrapping exceptions but losing the original cause; the inverse observation is that AI-generated code often has this pattern. This rule detects catch blocks that throw a new exception WITHOUT including the original exception as a cause \u2014 the original stack trace is lost. The rule is a real engineering defect detector (not AI fingerprint), so it is defaultOff=false (ON by default) and verdict=OK. v9 calibration is pending. The expected impact: low recall (most production code preserves the original exception) but very high precision (when it fires, it's a real bug \u2014 debugging without the stack trace is impossible).",
45826
+ aiSpecific: false,
45827
+ _v9Verdict: "OK",
45828
+ _v9Lift: 0,
45829
+ _v9Recall: 0,
45830
+ _v9FpRate: 0,
45831
+ _v9Precision: 0,
45832
+ defaultOff: false
45833
+ },
45756
45834
  "swift/force-unwrap": {
45757
45835
  recall: 0.10211,
45758
45836
  fpRate: 0.21462,
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.35.0";
39
+ VERSION = "0.35.1";
40
40
  }
41
41
  });
42
42
 
@@ -30797,6 +30797,74 @@ var init_hardcoded_credential = __esm({
30797
30797
  }
30798
30798
  });
30799
30799
 
30800
+ // src/rules/java/lost-stack-trace.ts
30801
+ var THROW_NEW_REGEX, CATCH_REGEX, javaLostStackTraceRule;
30802
+ var init_lost_stack_trace = __esm({
30803
+ "src/rules/java/lost-stack-trace.ts"() {
30804
+ "use strict";
30805
+ init_rule();
30806
+ THROW_NEW_REGEX = /throw\s+new\s+(\w+(?:Exception|Error|Throwable))\s*\(([^)]*)\)/g;
30807
+ CATCH_REGEX = /catch\s*\(\s*(?:final\s+)?[\w<>,\s]+\s+(\w+)\s*\)\s*\{/g;
30808
+ javaLostStackTraceRule = createRule({
30809
+ id: "java/lost-stack-trace",
30810
+ category: "logic",
30811
+ severity: "medium",
30812
+ aiSpecific: false,
30813
+ description: "catch block throws a new exception without the original cause \u2014 stack trace is lost",
30814
+ create(_context) {
30815
+ return {};
30816
+ },
30817
+ analyze(_context, facts) {
30818
+ const issues = [];
30819
+ const source = facts.v2?._source;
30820
+ if (!source) return issues;
30821
+ if (!/\.java$/i.test(facts.filePath)) return issues;
30822
+ if (/\/test\//i.test(facts.filePath) || /\/src\/test\//i.test(facts.filePath)) return issues;
30823
+ const catchBlocks = [];
30824
+ let cm;
30825
+ CATCH_REGEX.lastIndex = 0;
30826
+ while ((cm = CATCH_REGEX.exec(source)) !== null) {
30827
+ const catchStart = cm.index;
30828
+ const exVar = cm[1];
30829
+ let depth = 1;
30830
+ let i = cm.index + cm[0].length;
30831
+ while (i < source.length && depth > 0) {
30832
+ const ch = source[i];
30833
+ if (ch === "{") depth++;
30834
+ else if (ch === "}") depth--;
30835
+ i++;
30836
+ }
30837
+ catchBlocks.push({ start: catchStart, end: i, exVar });
30838
+ }
30839
+ let m;
30840
+ THROW_NEW_REGEX.lastIndex = 0;
30841
+ while ((m = THROW_NEW_REGEX.exec(source)) !== null) {
30842
+ const throwPos = m.index;
30843
+ const args = m[2].trim();
30844
+ const enclosing = catchBlocks.find(
30845
+ (cb) => cb.start < throwPos && throwPos < cb.end
30846
+ );
30847
+ if (!enclosing) continue;
30848
+ const exVarPattern = new RegExp(`\\b${enclosing.exVar}\\b`);
30849
+ if (exVarPattern.test(args)) continue;
30850
+ const line = source.slice(0, throwPos).split("\n").length;
30851
+ issues.push({
30852
+ ruleId: "java/lost-stack-trace",
30853
+ category: "logic",
30854
+ severity: "medium",
30855
+ aiSpecific: false,
30856
+ message: `throw new ${m[1]}(${args}) \u2014 original exception \`${enclosing.exVar}\` is not included as cause`,
30857
+ line,
30858
+ column: 1,
30859
+ advice: `The catch block declares exception variable \`${enclosing.exVar}\` but the throw statement doesn't include it as a cause. The original stack trace is lost. Fix: \`throw new ${m[1]}("...", ${enclosing.exVar})\` \u2014 the second argument to the exception constructor is the cause, which Java's Throwable framework preserves in the stack trace chain. Reference: java/lost-stack-trace v0.35.1 (Raidar-inspired content-based detection of AI-polished error handling).`
30860
+ });
30861
+ }
30862
+ return issues;
30863
+ }
30864
+ });
30865
+ }
30866
+ });
30867
+
30800
30868
  // src/rules/java/sql-string-concat.ts
30801
30869
  var SQL_KEYWORD_REGEX, UNSAFE_REGEX, SAFE_REGEX, javaSqlStringConcatRule;
30802
30870
  var init_sql_string_concat = __esm({
@@ -47025,6 +47093,7 @@ var init_builtins = __esm({
47025
47093
  init_struct_tag_inconsistency();
47026
47094
  init_command_injection();
47027
47095
  init_hardcoded_credential();
47096
+ init_lost_stack_trace();
47028
47097
  init_sql_string_concat();
47029
47098
  init_suspicious_implementation();
47030
47099
  init_system_out_println();
@@ -47165,6 +47234,7 @@ var init_builtins = __esm({
47165
47234
  goStructTagInconsistencyRule,
47166
47235
  javaCommandInjectionRule,
47167
47236
  javaHardcodedCredentialRule,
47237
+ javaLostStackTraceRule,
47168
47238
  javaSqlStringConcatRule,
47169
47239
  javaSuspiciousImplementationRule,
47170
47240
  javaSystemOutPrintlnRule,
@@ -51877,6 +51947,22 @@ var init_signal_strength = __esm({
51877
51947
  _v9Precision: 0,
51878
51948
  defaultOff: false
51879
51949
  },
51950
+ "java/lost-stack-trace": {
51951
+ recall: 0,
51952
+ fpRate: 0,
51953
+ ratio: 0,
51954
+ precision: 0,
51955
+ lastCalibratedAt: "2026-07-03T00:00:00Z",
51956
+ verdict: "OK",
51957
+ _calibrationNote: "v0.35.1: NEW RULE \u2014 Raidar-inspired content-based detection. The Raidar paper (ICLR 2024) showed that LLMs tend to 'polish' error handling by wrapping exceptions but losing the original cause; the inverse observation is that AI-generated code often has this pattern. This rule detects catch blocks that throw a new exception WITHOUT including the original exception as a cause \u2014 the original stack trace is lost. The rule is a real engineering defect detector (not AI fingerprint), so it is defaultOff=false (ON by default) and verdict=OK. v9 calibration is pending. The expected impact: low recall (most production code preserves the original exception) but very high precision (when it fires, it's a real bug \u2014 debugging without the stack trace is impossible).",
51958
+ aiSpecific: false,
51959
+ _v9Verdict: "OK",
51960
+ _v9Lift: 0,
51961
+ _v9Recall: 0,
51962
+ _v9FpRate: 0,
51963
+ _v9Precision: 0,
51964
+ defaultOff: false
51965
+ },
51880
51966
  "swift/force-unwrap": {
51881
51967
  recall: 0.10211,
51882
51968
  fpRate: 0.21462,
@@ -60145,6 +60231,8 @@ var RULE_HINTS = {
60145
60231
  "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.)",
60146
60232
  // v0.35.0 — content-based detection (CoCoNUTS-inspired)
60147
60233
  "java/suspicious-implementation": "Function name claims validate/encrypt/hash/sanitize but body is empty, returns null/true, or returns the input. This is a content mismatch \u2014 the function's claimed behavior doesn't match its actual behavior. OWASP A04:2021.",
60234
+ // v0.35.1 — Raidar-inspired content-based detection
60235
+ "java/lost-stack-trace": 'catch block throws a new exception without the original cause \u2014 stack trace is lost. Pass the original exception as the second arg to the new exception\'s constructor: `throw new XxxException("msg", e)`.',
60148
60236
  // v0.24.0 — Swift rules (DORMANT until v9 Swift corpus calibration)
60149
60237
  "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.)",
60150
60238
  "swift/print-debug": "Replace with `Logger(subsystem:..., category:...).info(...)` (os.log). `print` writes to stdout with no level and no redaction. (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.35.0";
22
+ VERSION = "0.35.1";
23
23
  }
24
24
  });
25
25
 
@@ -30778,6 +30778,74 @@ var init_hardcoded_credential = __esm({
30778
30778
  }
30779
30779
  });
30780
30780
 
30781
+ // src/rules/java/lost-stack-trace.ts
30782
+ var THROW_NEW_REGEX, CATCH_REGEX, javaLostStackTraceRule;
30783
+ var init_lost_stack_trace = __esm({
30784
+ "src/rules/java/lost-stack-trace.ts"() {
30785
+ "use strict";
30786
+ init_rule();
30787
+ THROW_NEW_REGEX = /throw\s+new\s+(\w+(?:Exception|Error|Throwable))\s*\(([^)]*)\)/g;
30788
+ CATCH_REGEX = /catch\s*\(\s*(?:final\s+)?[\w<>,\s]+\s+(\w+)\s*\)\s*\{/g;
30789
+ javaLostStackTraceRule = createRule({
30790
+ id: "java/lost-stack-trace",
30791
+ category: "logic",
30792
+ severity: "medium",
30793
+ aiSpecific: false,
30794
+ description: "catch block throws a new exception without the original cause \u2014 stack trace is lost",
30795
+ create(_context) {
30796
+ return {};
30797
+ },
30798
+ analyze(_context, facts) {
30799
+ const issues = [];
30800
+ const source = facts.v2?._source;
30801
+ if (!source) return issues;
30802
+ if (!/\.java$/i.test(facts.filePath)) return issues;
30803
+ if (/\/test\//i.test(facts.filePath) || /\/src\/test\//i.test(facts.filePath)) return issues;
30804
+ const catchBlocks = [];
30805
+ let cm;
30806
+ CATCH_REGEX.lastIndex = 0;
30807
+ while ((cm = CATCH_REGEX.exec(source)) !== null) {
30808
+ const catchStart = cm.index;
30809
+ const exVar = cm[1];
30810
+ let depth = 1;
30811
+ let i = cm.index + cm[0].length;
30812
+ while (i < source.length && depth > 0) {
30813
+ const ch = source[i];
30814
+ if (ch === "{") depth++;
30815
+ else if (ch === "}") depth--;
30816
+ i++;
30817
+ }
30818
+ catchBlocks.push({ start: catchStart, end: i, exVar });
30819
+ }
30820
+ let m;
30821
+ THROW_NEW_REGEX.lastIndex = 0;
30822
+ while ((m = THROW_NEW_REGEX.exec(source)) !== null) {
30823
+ const throwPos = m.index;
30824
+ const args = m[2].trim();
30825
+ const enclosing = catchBlocks.find(
30826
+ (cb) => cb.start < throwPos && throwPos < cb.end
30827
+ );
30828
+ if (!enclosing) continue;
30829
+ const exVarPattern = new RegExp(`\\b${enclosing.exVar}\\b`);
30830
+ if (exVarPattern.test(args)) continue;
30831
+ const line = source.slice(0, throwPos).split("\n").length;
30832
+ issues.push({
30833
+ ruleId: "java/lost-stack-trace",
30834
+ category: "logic",
30835
+ severity: "medium",
30836
+ aiSpecific: false,
30837
+ message: `throw new ${m[1]}(${args}) \u2014 original exception \`${enclosing.exVar}\` is not included as cause`,
30838
+ line,
30839
+ column: 1,
30840
+ advice: `The catch block declares exception variable \`${enclosing.exVar}\` but the throw statement doesn't include it as a cause. The original stack trace is lost. Fix: \`throw new ${m[1]}("...", ${enclosing.exVar})\` \u2014 the second argument to the exception constructor is the cause, which Java's Throwable framework preserves in the stack trace chain. Reference: java/lost-stack-trace v0.35.1 (Raidar-inspired content-based detection of AI-polished error handling).`
30841
+ });
30842
+ }
30843
+ return issues;
30844
+ }
30845
+ });
30846
+ }
30847
+ });
30848
+
30781
30849
  // src/rules/java/sql-string-concat.ts
30782
30850
  var SQL_KEYWORD_REGEX, UNSAFE_REGEX, SAFE_REGEX, javaSqlStringConcatRule;
30783
30851
  var init_sql_string_concat = __esm({
@@ -47006,6 +47074,7 @@ var init_builtins = __esm({
47006
47074
  init_struct_tag_inconsistency();
47007
47075
  init_command_injection();
47008
47076
  init_hardcoded_credential();
47077
+ init_lost_stack_trace();
47009
47078
  init_sql_string_concat();
47010
47079
  init_suspicious_implementation();
47011
47080
  init_system_out_println();
@@ -47146,6 +47215,7 @@ var init_builtins = __esm({
47146
47215
  goStructTagInconsistencyRule,
47147
47216
  javaCommandInjectionRule,
47148
47217
  javaHardcodedCredentialRule,
47218
+ javaLostStackTraceRule,
47149
47219
  javaSqlStringConcatRule,
47150
47220
  javaSuspiciousImplementationRule,
47151
47221
  javaSystemOutPrintlnRule,
@@ -51855,6 +51925,22 @@ var init_signal_strength = __esm({
51855
51925
  _v9Precision: 0,
51856
51926
  defaultOff: false
51857
51927
  },
51928
+ "java/lost-stack-trace": {
51929
+ recall: 0,
51930
+ fpRate: 0,
51931
+ ratio: 0,
51932
+ precision: 0,
51933
+ lastCalibratedAt: "2026-07-03T00:00:00Z",
51934
+ verdict: "OK",
51935
+ _calibrationNote: "v0.35.1: NEW RULE \u2014 Raidar-inspired content-based detection. The Raidar paper (ICLR 2024) showed that LLMs tend to 'polish' error handling by wrapping exceptions but losing the original cause; the inverse observation is that AI-generated code often has this pattern. This rule detects catch blocks that throw a new exception WITHOUT including the original exception as a cause \u2014 the original stack trace is lost. The rule is a real engineering defect detector (not AI fingerprint), so it is defaultOff=false (ON by default) and verdict=OK. v9 calibration is pending. The expected impact: low recall (most production code preserves the original exception) but very high precision (when it fires, it's a real bug \u2014 debugging without the stack trace is impossible).",
51936
+ aiSpecific: false,
51937
+ _v9Verdict: "OK",
51938
+ _v9Lift: 0,
51939
+ _v9Recall: 0,
51940
+ _v9FpRate: 0,
51941
+ _v9Precision: 0,
51942
+ defaultOff: false
51943
+ },
51858
51944
  "swift/force-unwrap": {
51859
51945
  recall: 0.10211,
51860
51946
  fpRate: 0.21462,
@@ -60044,6 +60130,8 @@ var RULE_HINTS = {
60044
60130
  "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.)",
60045
60131
  // v0.35.0 — content-based detection (CoCoNUTS-inspired)
60046
60132
  "java/suspicious-implementation": "Function name claims validate/encrypt/hash/sanitize but body is empty, returns null/true, or returns the input. This is a content mismatch \u2014 the function's claimed behavior doesn't match its actual behavior. OWASP A04:2021.",
60133
+ // v0.35.1 — Raidar-inspired content-based detection
60134
+ "java/lost-stack-trace": 'catch block throws a new exception without the original cause \u2014 stack trace is lost. Pass the original exception as the second arg to the new exception\'s constructor: `throw new XxxException("msg", e)`.',
60047
60135
  // v0.24.0 — Swift rules (DORMANT until v9 Swift corpus calibration)
60048
60136
  "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.)",
60049
60137
  "swift/print-debug": "Replace with `Logger(subsystem:..., category:...).info(...)` (os.log). `print` writes to stdout with no level and no redaction. (v0.24.0 \u2014 DORMANT.)",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slopbrick",
3
- "version": "0.35.0",
3
+ "version": "0.35.1",
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": {