@rigour-labs/core 4.3.0 → 4.3.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.
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Side-Effect Analysis Rules
3
+ *
4
+ * Pattern definitions for detecting unbounded side effects that cause
5
+ * real-world consequences: process spawns, resource exhaustion, circular
6
+ * triggers, missing circuit breakers.
7
+ *
8
+ * Each rule has:
9
+ * - regex patterns per language
10
+ * - a check function that verifies context (surrounding lines)
11
+ * - severity and description
12
+ *
13
+ * @since v4.3.0
14
+ */
15
+ export type SideEffectLang = 'js' | 'ts' | 'py' | 'go' | 'rs' | 'cs' | 'java' | 'rb';
16
+ export interface SideEffectViolation {
17
+ rule: string;
18
+ severity: 'critical' | 'high' | 'medium' | 'low';
19
+ file: string;
20
+ line: number;
21
+ match: string;
22
+ description: string;
23
+ hint: string;
24
+ }
25
+ export declare const LANG_MAP: Record<string, SideEffectLang>;
26
+ export declare const FILE_GLOBS: string[];
27
+ export declare const TIMER_CREATE_PATTERNS: Record<string, RegExp[]>;
28
+ export declare const TIMER_CLEANUP_PATTERNS: Record<string, RegExp[]>;
29
+ export declare const PROCESS_SPAWN_PATTERNS: Record<string, RegExp[]>;
30
+ export declare const PROCESS_EXIT_PATTERNS: Record<string, RegExp[]>;
31
+ export declare const UNBOUNDED_LOOP_PATTERNS: Record<string, RegExp[]>;
32
+ export declare const IO_PATTERNS: Record<string, RegExp[]>;
33
+ export declare const RETRY_PATTERNS: Record<string, RegExp[]>;
34
+ export declare const MAX_RETRY_INDICATORS: RegExp[];
35
+ export declare const WATCHER_PATTERNS: Record<string, RegExp[]>;
36
+ export declare const WRITE_PATTERNS: Record<string, RegExp[]>;
37
+ export declare const RESOURCE_OPEN_PATTERNS: Record<string, RegExp[]>;
38
+ export declare const RESOURCE_CLOSE_PATTERNS: Record<string, RegExp[]>;
39
+ export declare const AUTO_RESTART_PATTERNS: Record<string, RegExp[]>;
@@ -0,0 +1,302 @@
1
+ /**
2
+ * Side-Effect Analysis Rules
3
+ *
4
+ * Pattern definitions for detecting unbounded side effects that cause
5
+ * real-world consequences: process spawns, resource exhaustion, circular
6
+ * triggers, missing circuit breakers.
7
+ *
8
+ * Each rule has:
9
+ * - regex patterns per language
10
+ * - a check function that verifies context (surrounding lines)
11
+ * - severity and description
12
+ *
13
+ * @since v4.3.0
14
+ */
15
+ // ── Language detection ──
16
+ export const LANG_MAP = {
17
+ '.ts': 'ts', '.tsx': 'ts', '.mts': 'ts',
18
+ '.js': 'js', '.jsx': 'js', '.mjs': 'js', '.cjs': 'js',
19
+ '.py': 'py',
20
+ '.go': 'go',
21
+ '.rs': 'rs',
22
+ '.cs': 'cs',
23
+ '.java': 'java',
24
+ '.rb': 'rb',
25
+ };
26
+ export const FILE_GLOBS = [
27
+ '**/*.{ts,tsx,mts,js,jsx,mjs,cjs}',
28
+ '**/*.py',
29
+ '**/*.go',
30
+ '**/*.rs',
31
+ '**/*.cs',
32
+ '**/*.java',
33
+ '**/*.rb',
34
+ ];
35
+ // ── Timer patterns (setInterval/setTimeout without cleanup) ──
36
+ export const TIMER_CREATE_PATTERNS = {
37
+ js: [
38
+ /\bsetInterval\s*\(/,
39
+ /\bsetTimeout\s*\(/,
40
+ ],
41
+ ts: [
42
+ /\bsetInterval\s*\(/,
43
+ /\bsetTimeout\s*\(/,
44
+ ],
45
+ py: [
46
+ /\bscheduler\.enter\s*\(/,
47
+ /\bTimer\s*\(/,
48
+ /\bschedule\.every\b/,
49
+ ],
50
+ go: [
51
+ /\btime\.NewTicker\s*\(/,
52
+ /\btime\.Tick\s*\(/,
53
+ ],
54
+ java: [
55
+ /\bScheduledExecutorService\b/,
56
+ /\bTimer\(\)\.schedule\b/,
57
+ /\bTimer\(\)\.scheduleAtFixedRate\b/,
58
+ ],
59
+ rs: [],
60
+ cs: [
61
+ /\bnew\s+Timer\s*\(/,
62
+ /\bSetInterval\s*\(/,
63
+ ],
64
+ rb: [],
65
+ };
66
+ export const TIMER_CLEANUP_PATTERNS = {
67
+ js: [/\bclearInterval\s*\(/, /\bclearTimeout\s*\(/],
68
+ ts: [/\bclearInterval\s*\(/, /\bclearTimeout\s*\(/],
69
+ py: [/\.cancel\s*\(/],
70
+ go: [/\.Stop\s*\(/],
71
+ java: [/\.shutdown\s*\(/, /\.cancel\s*\(/],
72
+ rs: [],
73
+ cs: [/\.Dispose\s*\(/, /\.Stop\s*\(/],
74
+ rb: [],
75
+ };
76
+ // ── Process spawn patterns ──
77
+ export const PROCESS_SPAWN_PATTERNS = {
78
+ js: [
79
+ /\bchild_process\.\w+\s*\(/,
80
+ /\bspawn\s*\(/,
81
+ /\bexec\s*\(/,
82
+ /\bexecFile\s*\(/,
83
+ /\bfork\s*\(/,
84
+ /\bexeca\s*\(/,
85
+ ],
86
+ ts: [
87
+ /\bchild_process\.\w+\s*\(/,
88
+ /\bspawn\s*\(/,
89
+ /\bexec\s*\(/,
90
+ /\bexecFile\s*\(/,
91
+ /\bfork\s*\(/,
92
+ /\bexeca\s*\(/,
93
+ ],
94
+ py: [
95
+ /\bsubprocess\.\w+\s*\(/,
96
+ /\bPopen\s*\(/,
97
+ /\bos\.system\s*\(/,
98
+ /\bos\.exec\w*\s*\(/,
99
+ /\bos\.spawn\w*\s*\(/,
100
+ ],
101
+ go: [
102
+ /\bexec\.Command\s*\(/,
103
+ /\bos\/exec\b/,
104
+ /\bcmd\.Start\s*\(/,
105
+ /\bcmd\.Run\s*\(/,
106
+ ],
107
+ java: [
108
+ /\bProcessBuilder\b/,
109
+ /\bRuntime\.getRuntime\(\)\.exec\s*\(/,
110
+ ],
111
+ rs: [
112
+ /\bCommand::new\s*\(/,
113
+ /\bstd::process::Command\b/,
114
+ ],
115
+ cs: [
116
+ /\bProcess\.Start\s*\(/,
117
+ /\bnew\s+ProcessStartInfo\b/,
118
+ ],
119
+ rb: [
120
+ /\bsystem\s*\(/,
121
+ /\bspawn\s*\(/,
122
+ /\b`[^`]+`/,
123
+ /\bIO\.popen\s*\(/,
124
+ ],
125
+ };
126
+ export const PROCESS_EXIT_PATTERNS = {
127
+ js: [/\.on\s*\(\s*['"](?:exit|close)['"]/, /\.kill\s*\(/, /\.disconnect\s*\(/],
128
+ ts: [/\.on\s*\(\s*['"](?:exit|close)['"]/, /\.kill\s*\(/, /\.disconnect\s*\(/],
129
+ py: [/\.wait\s*\(/, /\.terminate\s*\(/, /\.kill\s*\(/, /\.communicate\s*\(/],
130
+ go: [/\.Wait\s*\(/, /cmd\.Process\.Kill\s*\(/],
131
+ java: [/\.waitFor\s*\(/, /\.destroy\s*\(/, /\.destroyForcibly\s*\(/],
132
+ rs: [/\.wait\s*\(/, /\.kill\s*\(/],
133
+ cs: [/\.WaitForExit\s*\(/, /\.Kill\s*\(/, /\.Close\s*\(/],
134
+ rb: [/Process\.wait\b/, /Process\.kill\b/],
135
+ };
136
+ // ── Unbounded loop patterns ──
137
+ export const UNBOUNDED_LOOP_PATTERNS = {
138
+ js: [/\bwhile\s*\(\s*true\s*\)/, /\bwhile\s*\(\s*1\s*\)/, /\bfor\s*\(\s*;\s*;\s*\)/],
139
+ ts: [/\bwhile\s*\(\s*true\s*\)/, /\bwhile\s*\(\s*1\s*\)/, /\bfor\s*\(\s*;\s*;\s*\)/],
140
+ py: [/\bwhile\s+True\s*:/, /\bwhile\s+1\s*:/],
141
+ go: [/\bfor\s*\{/, /\bfor\s+\{/], // bare `for {` in Go = infinite loop
142
+ java: [/\bwhile\s*\(\s*true\s*\)/, /\bfor\s*\(\s*;\s*;\s*\)/],
143
+ rs: [/\bloop\s*\{/],
144
+ cs: [/\bwhile\s*\(\s*true\s*\)/, /\bfor\s*\(\s*;\s*;\s*\)/],
145
+ rb: [/\bloop\s+do\b/, /\bwhile\s+true\b/],
146
+ };
147
+ // I/O operations inside loops that indicate resource impact
148
+ export const IO_PATTERNS = {
149
+ js: [
150
+ /\bfs\.\w+/, /\bfetch\s*\(/, /\baxios\.\w+/, /\bhttp\.\w+/,
151
+ /\.write\s*\(/, /\.send\s*\(/, /\bchild_process\./,
152
+ /\bconsole\.\w+/, /\bprocess\.stdout/,
153
+ ],
154
+ ts: [
155
+ /\bfs\.\w+/, /\bfetch\s*\(/, /\baxios\.\w+/, /\bhttp\.\w+/,
156
+ /\.write\s*\(/, /\.send\s*\(/, /\bchild_process\./,
157
+ ],
158
+ py: [
159
+ /\bopen\s*\(/, /\brequests\.\w+/, /\burllib\.\w+/,
160
+ /\bsubprocess\./, /\bos\.\w+/, /\bsocket\.\w+/,
161
+ /\.write\s*\(/, /\bprint\s*\(/,
162
+ ],
163
+ go: [
164
+ /\bos\.\w+/, /\bnet\.\w+/, /\bhttp\.\w+/,
165
+ /\bio\.\w+/, /\bfmt\.Fprint/, /\bioutil\.\w+/,
166
+ /\bexec\.Command/,
167
+ ],
168
+ java: [
169
+ /\bnew\s+File\w*\(/, /\bHttpClient\b/, /\bSocket\b/,
170
+ /\.write\s*\(/, /\bRuntime\.getRuntime\(\)/,
171
+ ],
172
+ rs: [
173
+ /\bstd::fs::/, /\bstd::net::/, /\bstd::process::/,
174
+ /\.write\s*\(/, /\btokio::\w+/,
175
+ ],
176
+ cs: [
177
+ /\bFile\.\w+/, /\bHttpClient\b/, /\bProcess\.Start/,
178
+ /\.Write\s*\(/, /\bSocket\b/,
179
+ ],
180
+ rb: [
181
+ /\bFile\.\w+/, /\bNet::HTTP\b/, /\bIO\.\w+/,
182
+ /\.write\s*\(/, /\bsystem\s*\(/,
183
+ ],
184
+ };
185
+ // ── Retry without limit patterns ──
186
+ export const RETRY_PATTERNS = {
187
+ js: [/\bcatch\s*\([^)]*\)\s*\{/, /\.catch\s*\(/],
188
+ ts: [/\bcatch\s*\([^)]*\)\s*\{/, /\.catch\s*\(/],
189
+ py: [/\bexcept\s+\w+/, /\bexcept\s*:/],
190
+ go: [/\bif\s+err\s*!=\s*nil\b/],
191
+ java: [/\bcatch\s*\(\w+\s+\w+\)/, /\bcatch\s*\(\s*Exception\b/],
192
+ rs: [/\.unwrap_or_else\s*\(/, /\bif\s+let\s+Err\b/],
193
+ cs: [/\bcatch\s*\(\w+\b/, /\bcatch\s*\{/],
194
+ rb: [/\brescue\b/],
195
+ };
196
+ export const MAX_RETRY_INDICATORS = [
197
+ /max.?retries?/i,
198
+ /retry.?count/i,
199
+ /retry.?limit/i,
200
+ /attempt/i,
201
+ /retries?\s*[<>=!]+\s*\d+/,
202
+ /count\s*[<>=!]+\s*\d+/,
203
+ /MAX_/,
204
+ /backoff/i,
205
+ /circuit.?breaker/i,
206
+ ];
207
+ // ── File watcher patterns (circular trigger detection) ──
208
+ export const WATCHER_PATTERNS = {
209
+ js: [
210
+ /\bfs\.watch\s*\(/, /\bfs\.watchFile\s*\(/,
211
+ /\bchokidar\.watch\s*\(/, /\bnodemon\b/,
212
+ /\bnew\s+FSWatcher\b/,
213
+ ],
214
+ ts: [
215
+ /\bfs\.watch\s*\(/, /\bfs\.watchFile\s*\(/,
216
+ /\bchokidar\.watch\s*\(/,
217
+ /\bnew\s+FSWatcher\b/,
218
+ ],
219
+ py: [
220
+ /\bwatchdog\b/, /\bObserver\s*\(/,
221
+ /\binotify\b/, /\bwatchfiles\b/,
222
+ ],
223
+ go: [
224
+ /\bfsnotify\.\w+/, /\bNewWatcher\s*\(/,
225
+ ],
226
+ java: [
227
+ /\bWatchService\b/, /\bWatchKey\b/,
228
+ ],
229
+ rs: [
230
+ /\bnotify::/, /\bRecommendedWatcher\b/,
231
+ ],
232
+ cs: [
233
+ /\bFileSystemWatcher\b/, /\bnew\s+FileSystemWatcher\b/,
234
+ ],
235
+ rb: [
236
+ /\bListen\.\w+/, /\brb-inotify\b/,
237
+ ],
238
+ };
239
+ export const WRITE_PATTERNS = {
240
+ js: [/\bfs\.writeFile/, /\bfs\.appendFile/, /\bfs\.createWriteStream/, /\.write\s*\(/],
241
+ ts: [/\bfs\.writeFile/, /\bfs\.appendFile/, /\bfs\.createWriteStream/, /\.write\s*\(/],
242
+ py: [/\bopen\s*\([^)]*['"][wa]['"]/, /\.write\s*\(/, /\bshutil\.\w+/],
243
+ go: [/\bos\.WriteFile/, /\bos\.Create/, /\bio\.WriteString/, /\.Write\s*\(/],
244
+ java: [/\bFileWriter\b/, /\bBufferedWriter\b/, /\.write\s*\(/],
245
+ rs: [/\bfs::write/, /\bFile::create/, /\.write_all\s*\(/],
246
+ cs: [/\bFile\.Write/, /\bStreamWriter\b/, /\.Write\s*\(/],
247
+ rb: [/\bFile\.write/, /\bFile\.open\s*\([^)]*['"]w['"]/, /\.write\s*\(/],
248
+ };
249
+ // ── Resource lifecycle patterns (open without close) ──
250
+ export const RESOURCE_OPEN_PATTERNS = {
251
+ js: [/\bfs\.open\s*\(/, /\bfs\.createReadStream\s*\(/, /\bfs\.createWriteStream\s*\(/],
252
+ ts: [/\bfs\.open\s*\(/, /\bfs\.createReadStream\s*\(/, /\bfs\.createWriteStream\s*\(/],
253
+ py: [/\bopen\s*\(/],
254
+ go: [/\bos\.Open\s*\(/, /\bos\.Create\s*\(/, /\bos\.OpenFile\s*\(/],
255
+ java: [/\bnew\s+FileInputStream\b/, /\bnew\s+FileOutputStream\b/, /\bnew\s+BufferedReader\b/],
256
+ rs: [/\bFile::open\s*\(/, /\bFile::create\s*\(/],
257
+ cs: [/\bFile\.Open\s*\(/, /\bnew\s+FileStream\b/, /\bnew\s+StreamReader\b/],
258
+ rb: [/\bFile\.open\s*\(/],
259
+ };
260
+ export const RESOURCE_CLOSE_PATTERNS = {
261
+ js: [/\.close\s*\(/, /\.destroy\s*\(/, /\.end\s*\(/],
262
+ ts: [/\.close\s*\(/, /\.destroy\s*\(/, /\.end\s*\(/],
263
+ py: [/\.close\s*\(/, /\bwith\s+open\b/], // `with` auto-closes
264
+ go: [/\.Close\s*\(/, /\bdefer\b/], // defer auto-closes
265
+ java: [/\.close\s*\(/, /\btry\s*\(/], // try-with-resources
266
+ rs: [/\bdrop\s*\(/, /\}$/], // Rust auto-drops
267
+ cs: [/\.Close\s*\(/, /\.Dispose\s*\(/, /\busing\s*\(/], // using auto-disposes
268
+ rb: [/\.close\b/, /\bFile\.open\s*\([^)]*\)\s*do\b/], // block form auto-closes
269
+ };
270
+ // ── Auto-restart / self-respawn patterns ──
271
+ export const AUTO_RESTART_PATTERNS = {
272
+ js: [
273
+ /process\.on\s*\(\s*['"](?:exit|uncaughtException|SIGTERM)['"]\s*,\s*(?:function|\(|=>).*(?:spawn|exec|fork)/,
274
+ /process\.on\s*\(\s*['"]exit['"]/,
275
+ ],
276
+ ts: [
277
+ /process\.on\s*\(\s*['"](?:exit|uncaughtException|SIGTERM)['"]\s*,\s*(?:function|\(|=>).*(?:spawn|exec|fork)/,
278
+ /process\.on\s*\(\s*['"]exit['"]/,
279
+ ],
280
+ py: [
281
+ /\batexit\.register\s*\(/,
282
+ /\bsignal\.signal\s*\(\s*signal\.SIG\w+\s*,/,
283
+ ],
284
+ go: [
285
+ /\bsignal\.Notify\s*\(/,
286
+ /\bos\.Exit\s*\(/,
287
+ ],
288
+ java: [
289
+ /\bRuntime\.getRuntime\(\)\.addShutdownHook\b/,
290
+ ],
291
+ rs: [
292
+ /\bctrlc::set_handler\b/,
293
+ /\bsignal::ctrl_c\b/,
294
+ ],
295
+ cs: [
296
+ /\bAppDomain\.CurrentDomain\.ProcessExit\b/,
297
+ ],
298
+ rb: [
299
+ /\bat_exit\b/,
300
+ /\btrap\s*\(/,
301
+ ],
302
+ };
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export * from './templates/index.js';
6
6
  export * from './types/fix-packet.js';
7
7
  export { Gate, GateContext } from './gates/base.js';
8
8
  export { RetryLoopBreakerGate } from './gates/retry-loop-breaker.js';
9
+ export { SideEffectAnalysisGate } from './gates/side-effect-analysis.js';
9
10
  export * from './utils/logger.js';
10
11
  export * from './services/score-history.js';
11
12
  export * from './hooks/index.js';
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ export * from './templates/index.js';
6
6
  export * from './types/fix-packet.js';
7
7
  export { Gate } from './gates/base.js';
8
8
  export { RetryLoopBreakerGate } from './gates/retry-loop-breaker.js';
9
+ export { SideEffectAnalysisGate } from './gates/side-effect-analysis.js';
9
10
  export * from './utils/logger.js';
10
11
  export * from './services/score-history.js';
11
12
  export * from './hooks/index.js';
@@ -187,6 +187,18 @@ export const UNIVERSAL_CONFIG = {
187
187
  ignore_patterns: [],
188
188
  audit_log: true,
189
189
  },
190
+ side_effect_analysis: {
191
+ enabled: true,
192
+ check_unbounded_timers: true,
193
+ check_unbounded_loops: true,
194
+ check_process_lifecycle: true,
195
+ check_recursive_depth: true,
196
+ check_resource_lifecycle: true,
197
+ check_retry_without_limit: true,
198
+ check_circular_triggers: true,
199
+ check_auto_restart: true,
200
+ ignore_patterns: [],
201
+ },
190
202
  deep: {
191
203
  enabled: false,
192
204
  pro: false,
@@ -452,6 +452,40 @@ export declare const GatesSchema: z.ZodObject<{
452
452
  custom_patterns?: string[] | undefined;
453
453
  audit_log?: boolean | undefined;
454
454
  }>>>;
455
+ side_effect_analysis: z.ZodDefault<z.ZodOptional<z.ZodObject<{
456
+ enabled: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
457
+ check_unbounded_timers: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
458
+ check_unbounded_loops: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
459
+ check_process_lifecycle: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
460
+ check_recursive_depth: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
461
+ check_resource_lifecycle: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
462
+ check_retry_without_limit: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
463
+ check_circular_triggers: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
464
+ check_auto_restart: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
465
+ ignore_patterns: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
466
+ }, "strip", z.ZodTypeAny, {
467
+ enabled: boolean;
468
+ ignore_patterns: string[];
469
+ check_unbounded_timers: boolean;
470
+ check_unbounded_loops: boolean;
471
+ check_process_lifecycle: boolean;
472
+ check_recursive_depth: boolean;
473
+ check_resource_lifecycle: boolean;
474
+ check_retry_without_limit: boolean;
475
+ check_circular_triggers: boolean;
476
+ check_auto_restart: boolean;
477
+ }, {
478
+ enabled?: boolean | undefined;
479
+ ignore_patterns?: string[] | undefined;
480
+ check_unbounded_timers?: boolean | undefined;
481
+ check_unbounded_loops?: boolean | undefined;
482
+ check_process_lifecycle?: boolean | undefined;
483
+ check_recursive_depth?: boolean | undefined;
484
+ check_resource_lifecycle?: boolean | undefined;
485
+ check_retry_without_limit?: boolean | undefined;
486
+ check_circular_triggers?: boolean | undefined;
487
+ check_auto_restart?: boolean | undefined;
488
+ }>>>;
455
489
  deep: z.ZodDefault<z.ZodOptional<z.ZodObject<{
456
490
  enabled: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
457
491
  pro: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -725,6 +759,18 @@ export declare const GatesSchema: z.ZodObject<{
725
759
  custom_patterns: string[];
726
760
  audit_log: boolean;
727
761
  };
762
+ side_effect_analysis: {
763
+ enabled: boolean;
764
+ ignore_patterns: string[];
765
+ check_unbounded_timers: boolean;
766
+ check_unbounded_loops: boolean;
767
+ check_process_lifecycle: boolean;
768
+ check_recursive_depth: boolean;
769
+ check_resource_lifecycle: boolean;
770
+ check_retry_without_limit: boolean;
771
+ check_circular_triggers: boolean;
772
+ check_auto_restart: boolean;
773
+ };
728
774
  }, {
729
775
  deep?: {
730
776
  enabled?: boolean | undefined;
@@ -913,6 +959,18 @@ export declare const GatesSchema: z.ZodObject<{
913
959
  custom_patterns?: string[] | undefined;
914
960
  audit_log?: boolean | undefined;
915
961
  } | undefined;
962
+ side_effect_analysis?: {
963
+ enabled?: boolean | undefined;
964
+ ignore_patterns?: string[] | undefined;
965
+ check_unbounded_timers?: boolean | undefined;
966
+ check_unbounded_loops?: boolean | undefined;
967
+ check_process_lifecycle?: boolean | undefined;
968
+ check_recursive_depth?: boolean | undefined;
969
+ check_resource_lifecycle?: boolean | undefined;
970
+ check_retry_without_limit?: boolean | undefined;
971
+ check_circular_triggers?: boolean | undefined;
972
+ check_auto_restart?: boolean | undefined;
973
+ } | undefined;
916
974
  }>;
917
975
  export declare const CommandsSchema: z.ZodObject<{
918
976
  format: z.ZodOptional<z.ZodString>;
@@ -1426,6 +1484,40 @@ export declare const ConfigSchema: z.ZodObject<{
1426
1484
  custom_patterns?: string[] | undefined;
1427
1485
  audit_log?: boolean | undefined;
1428
1486
  }>>>;
1487
+ side_effect_analysis: z.ZodDefault<z.ZodOptional<z.ZodObject<{
1488
+ enabled: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1489
+ check_unbounded_timers: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1490
+ check_unbounded_loops: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1491
+ check_process_lifecycle: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1492
+ check_recursive_depth: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1493
+ check_resource_lifecycle: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1494
+ check_retry_without_limit: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1495
+ check_circular_triggers: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1496
+ check_auto_restart: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1497
+ ignore_patterns: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString, "many">>>;
1498
+ }, "strip", z.ZodTypeAny, {
1499
+ enabled: boolean;
1500
+ ignore_patterns: string[];
1501
+ check_unbounded_timers: boolean;
1502
+ check_unbounded_loops: boolean;
1503
+ check_process_lifecycle: boolean;
1504
+ check_recursive_depth: boolean;
1505
+ check_resource_lifecycle: boolean;
1506
+ check_retry_without_limit: boolean;
1507
+ check_circular_triggers: boolean;
1508
+ check_auto_restart: boolean;
1509
+ }, {
1510
+ enabled?: boolean | undefined;
1511
+ ignore_patterns?: string[] | undefined;
1512
+ check_unbounded_timers?: boolean | undefined;
1513
+ check_unbounded_loops?: boolean | undefined;
1514
+ check_process_lifecycle?: boolean | undefined;
1515
+ check_recursive_depth?: boolean | undefined;
1516
+ check_resource_lifecycle?: boolean | undefined;
1517
+ check_retry_without_limit?: boolean | undefined;
1518
+ check_circular_triggers?: boolean | undefined;
1519
+ check_auto_restart?: boolean | undefined;
1520
+ }>>>;
1429
1521
  deep: z.ZodDefault<z.ZodOptional<z.ZodObject<{
1430
1522
  enabled: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
1431
1523
  pro: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -1699,6 +1791,18 @@ export declare const ConfigSchema: z.ZodObject<{
1699
1791
  custom_patterns: string[];
1700
1792
  audit_log: boolean;
1701
1793
  };
1794
+ side_effect_analysis: {
1795
+ enabled: boolean;
1796
+ ignore_patterns: string[];
1797
+ check_unbounded_timers: boolean;
1798
+ check_unbounded_loops: boolean;
1799
+ check_process_lifecycle: boolean;
1800
+ check_recursive_depth: boolean;
1801
+ check_resource_lifecycle: boolean;
1802
+ check_retry_without_limit: boolean;
1803
+ check_circular_triggers: boolean;
1804
+ check_auto_restart: boolean;
1805
+ };
1702
1806
  }, {
1703
1807
  deep?: {
1704
1808
  enabled?: boolean | undefined;
@@ -1887,6 +1991,18 @@ export declare const ConfigSchema: z.ZodObject<{
1887
1991
  custom_patterns?: string[] | undefined;
1888
1992
  audit_log?: boolean | undefined;
1889
1993
  } | undefined;
1994
+ side_effect_analysis?: {
1995
+ enabled?: boolean | undefined;
1996
+ ignore_patterns?: string[] | undefined;
1997
+ check_unbounded_timers?: boolean | undefined;
1998
+ check_unbounded_loops?: boolean | undefined;
1999
+ check_process_lifecycle?: boolean | undefined;
2000
+ check_recursive_depth?: boolean | undefined;
2001
+ check_resource_lifecycle?: boolean | undefined;
2002
+ check_retry_without_limit?: boolean | undefined;
2003
+ check_circular_triggers?: boolean | undefined;
2004
+ check_auto_restart?: boolean | undefined;
2005
+ } | undefined;
1890
2006
  }>>>;
1891
2007
  hooks: z.ZodDefault<z.ZodOptional<z.ZodObject<{
1892
2008
  enabled: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
@@ -2117,6 +2233,18 @@ export declare const ConfigSchema: z.ZodObject<{
2117
2233
  custom_patterns: string[];
2118
2234
  audit_log: boolean;
2119
2235
  };
2236
+ side_effect_analysis: {
2237
+ enabled: boolean;
2238
+ ignore_patterns: string[];
2239
+ check_unbounded_timers: boolean;
2240
+ check_unbounded_loops: boolean;
2241
+ check_process_lifecycle: boolean;
2242
+ check_recursive_depth: boolean;
2243
+ check_resource_lifecycle: boolean;
2244
+ check_retry_without_limit: boolean;
2245
+ check_circular_triggers: boolean;
2246
+ check_auto_restart: boolean;
2247
+ };
2120
2248
  };
2121
2249
  hooks: {
2122
2250
  enabled: boolean;
@@ -2331,6 +2459,18 @@ export declare const ConfigSchema: z.ZodObject<{
2331
2459
  custom_patterns?: string[] | undefined;
2332
2460
  audit_log?: boolean | undefined;
2333
2461
  } | undefined;
2462
+ side_effect_analysis?: {
2463
+ enabled?: boolean | undefined;
2464
+ ignore_patterns?: string[] | undefined;
2465
+ check_unbounded_timers?: boolean | undefined;
2466
+ check_unbounded_loops?: boolean | undefined;
2467
+ check_process_lifecycle?: boolean | undefined;
2468
+ check_recursive_depth?: boolean | undefined;
2469
+ check_resource_lifecycle?: boolean | undefined;
2470
+ check_retry_without_limit?: boolean | undefined;
2471
+ check_circular_triggers?: boolean | undefined;
2472
+ check_auto_restart?: boolean | undefined;
2473
+ } | undefined;
2334
2474
  } | undefined;
2335
2475
  hooks?: {
2336
2476
  enabled?: boolean | undefined;
@@ -225,6 +225,19 @@ export const GatesSchema = z.object({
225
225
  ignore_patterns: z.array(z.string()).optional().default([]),
226
226
  audit_log: z.boolean().optional().default(true),
227
227
  }).optional().default({}),
228
+ // v4.3+ Side-Effect Safety Analysis
229
+ side_effect_analysis: z.object({
230
+ enabled: z.boolean().optional().default(true),
231
+ check_unbounded_timers: z.boolean().optional().default(true),
232
+ check_unbounded_loops: z.boolean().optional().default(true),
233
+ check_process_lifecycle: z.boolean().optional().default(true),
234
+ check_recursive_depth: z.boolean().optional().default(true),
235
+ check_resource_lifecycle: z.boolean().optional().default(true),
236
+ check_retry_without_limit: z.boolean().optional().default(true),
237
+ check_circular_triggers: z.boolean().optional().default(true),
238
+ check_auto_restart: z.boolean().optional().default(true),
239
+ ignore_patterns: z.array(z.string()).optional().default([]),
240
+ }).optional().default({}),
228
241
  // v4.0+ Deep Analysis (LLM-powered)
229
242
  deep: z.object({
230
243
  enabled: z.boolean().optional().default(false),
@@ -265,6 +278,7 @@ export const HooksSchema = z.object({
265
278
  'deprecated-apis',
266
279
  'promise-safety',
267
280
  'security-patterns',
281
+ 'side-effect-analysis',
268
282
  'file-size',
269
283
  ]),
270
284
  timeout_ms: z.number().optional().default(5000),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rigour-labs/core",
3
- "version": "4.3.0",
3
+ "version": "4.3.1",
4
4
  "description": "Deterministic quality gate engine for AI-generated code. AST analysis, drift detection, and Fix Packet generation across TypeScript, JavaScript, Python, Go, Ruby, and C#.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://rigour.run",
@@ -59,11 +59,11 @@
59
59
  "@xenova/transformers": "^2.17.2",
60
60
  "better-sqlite3": "^11.0.0",
61
61
  "openai": "^4.104.0",
62
- "@rigour-labs/brain-linux-arm64": "4.3.0",
63
- "@rigour-labs/brain-linux-x64": "4.3.0",
64
- "@rigour-labs/brain-darwin-x64": "4.3.0",
65
- "@rigour-labs/brain-win-x64": "4.3.0",
66
- "@rigour-labs/brain-darwin-arm64": "4.3.0"
62
+ "@rigour-labs/brain-darwin-arm64": "4.3.1",
63
+ "@rigour-labs/brain-darwin-x64": "4.3.1",
64
+ "@rigour-labs/brain-linux-arm64": "4.3.1",
65
+ "@rigour-labs/brain-win-x64": "4.3.1",
66
+ "@rigour-labs/brain-linux-x64": "4.3.1"
67
67
  },
68
68
  "devDependencies": {
69
69
  "@types/better-sqlite3": "^7.6.12",