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/engine/worker.cjs +143 -22
- package/dist/engine/worker.js +143 -22
- package/dist/index.cjs +148 -27
- package/dist/index.js +148 -27
- package/package.json +1 -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.
|
|
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 -
|
|
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.
|
|
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(
|
|
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(
|
|
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.
|
|
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
|
|
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
|
-
|
|
30884
|
-
|
|
30885
|
-
|
|
30886
|
-
|
|
30887
|
-
|
|
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.
|
|
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 (
|
|
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.
|
|
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,
|
|
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
|
-
|
|
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 (
|
|
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,
|