crackerjack 0.31.9__py3-none-any.whl → 0.31.12__py3-none-any.whl
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.
Potentially problematic release.
This version of crackerjack might be problematic. Click here for more details.
- crackerjack/CLAUDE.md +288 -705
- crackerjack/__main__.py +22 -8
- crackerjack/agents/__init__.py +0 -3
- crackerjack/agents/architect_agent.py +0 -43
- crackerjack/agents/base.py +1 -9
- crackerjack/agents/coordinator.py +2 -148
- crackerjack/agents/documentation_agent.py +109 -81
- crackerjack/agents/dry_agent.py +122 -97
- crackerjack/agents/formatting_agent.py +3 -16
- crackerjack/agents/import_optimization_agent.py +1174 -130
- crackerjack/agents/performance_agent.py +956 -188
- crackerjack/agents/performance_helpers.py +229 -0
- crackerjack/agents/proactive_agent.py +1 -48
- crackerjack/agents/refactoring_agent.py +516 -246
- crackerjack/agents/refactoring_helpers.py +282 -0
- crackerjack/agents/security_agent.py +393 -90
- crackerjack/agents/test_creation_agent.py +1776 -120
- crackerjack/agents/test_specialist_agent.py +59 -15
- crackerjack/agents/tracker.py +0 -102
- crackerjack/api.py +145 -37
- crackerjack/cli/handlers.py +48 -30
- crackerjack/cli/interactive.py +11 -11
- crackerjack/cli/options.py +66 -4
- crackerjack/code_cleaner.py +808 -148
- crackerjack/config/global_lock_config.py +110 -0
- crackerjack/config/hooks.py +43 -64
- crackerjack/core/async_workflow_orchestrator.py +247 -97
- crackerjack/core/autofix_coordinator.py +192 -109
- crackerjack/core/enhanced_container.py +46 -63
- crackerjack/core/file_lifecycle.py +549 -0
- crackerjack/core/performance.py +9 -8
- crackerjack/core/performance_monitor.py +395 -0
- crackerjack/core/phase_coordinator.py +282 -95
- crackerjack/core/proactive_workflow.py +9 -58
- crackerjack/core/resource_manager.py +501 -0
- crackerjack/core/service_watchdog.py +490 -0
- crackerjack/core/session_coordinator.py +4 -8
- crackerjack/core/timeout_manager.py +504 -0
- crackerjack/core/websocket_lifecycle.py +475 -0
- crackerjack/core/workflow_orchestrator.py +355 -204
- crackerjack/dynamic_config.py +47 -6
- crackerjack/errors.py +3 -4
- crackerjack/executors/async_hook_executor.py +63 -13
- crackerjack/executors/cached_hook_executor.py +14 -14
- crackerjack/executors/hook_executor.py +100 -37
- crackerjack/executors/hook_lock_manager.py +856 -0
- crackerjack/executors/individual_hook_executor.py +120 -86
- crackerjack/intelligence/__init__.py +0 -7
- crackerjack/intelligence/adaptive_learning.py +13 -86
- crackerjack/intelligence/agent_orchestrator.py +15 -78
- crackerjack/intelligence/agent_registry.py +12 -59
- crackerjack/intelligence/agent_selector.py +31 -92
- crackerjack/intelligence/integration.py +1 -41
- crackerjack/interactive.py +9 -9
- crackerjack/managers/async_hook_manager.py +25 -8
- crackerjack/managers/hook_manager.py +9 -9
- crackerjack/managers/publish_manager.py +57 -59
- crackerjack/managers/test_command_builder.py +6 -36
- crackerjack/managers/test_executor.py +9 -61
- crackerjack/managers/test_manager.py +52 -62
- crackerjack/managers/test_manager_backup.py +77 -127
- crackerjack/managers/test_progress.py +4 -23
- crackerjack/mcp/cache.py +5 -12
- crackerjack/mcp/client_runner.py +10 -10
- crackerjack/mcp/context.py +64 -6
- crackerjack/mcp/dashboard.py +14 -11
- crackerjack/mcp/enhanced_progress_monitor.py +55 -55
- crackerjack/mcp/file_monitor.py +72 -42
- crackerjack/mcp/progress_components.py +103 -84
- crackerjack/mcp/progress_monitor.py +122 -49
- crackerjack/mcp/rate_limiter.py +12 -12
- crackerjack/mcp/server_core.py +16 -22
- crackerjack/mcp/service_watchdog.py +26 -26
- crackerjack/mcp/state.py +15 -0
- crackerjack/mcp/tools/core_tools.py +95 -39
- crackerjack/mcp/tools/error_analyzer.py +6 -32
- crackerjack/mcp/tools/execution_tools.py +1 -56
- crackerjack/mcp/tools/execution_tools_backup.py +35 -131
- crackerjack/mcp/tools/intelligence_tool_registry.py +0 -36
- crackerjack/mcp/tools/intelligence_tools.py +2 -55
- crackerjack/mcp/tools/monitoring_tools.py +308 -145
- crackerjack/mcp/tools/proactive_tools.py +12 -42
- crackerjack/mcp/tools/progress_tools.py +23 -15
- crackerjack/mcp/tools/utility_tools.py +3 -40
- crackerjack/mcp/tools/workflow_executor.py +40 -60
- crackerjack/mcp/websocket/app.py +0 -3
- crackerjack/mcp/websocket/endpoints.py +206 -268
- crackerjack/mcp/websocket/jobs.py +213 -66
- crackerjack/mcp/websocket/server.py +84 -6
- crackerjack/mcp/websocket/websocket_handler.py +137 -29
- crackerjack/models/config_adapter.py +3 -16
- crackerjack/models/protocols.py +162 -3
- crackerjack/models/resource_protocols.py +454 -0
- crackerjack/models/task.py +3 -3
- crackerjack/monitoring/__init__.py +0 -0
- crackerjack/monitoring/ai_agent_watchdog.py +25 -71
- crackerjack/monitoring/regression_prevention.py +28 -87
- crackerjack/orchestration/advanced_orchestrator.py +44 -78
- crackerjack/orchestration/coverage_improvement.py +10 -60
- crackerjack/orchestration/execution_strategies.py +16 -16
- crackerjack/orchestration/test_progress_streamer.py +61 -53
- crackerjack/plugins/base.py +1 -1
- crackerjack/plugins/managers.py +22 -20
- crackerjack/py313.py +65 -21
- crackerjack/services/backup_service.py +467 -0
- crackerjack/services/bounded_status_operations.py +627 -0
- crackerjack/services/cache.py +7 -9
- crackerjack/services/config.py +35 -52
- crackerjack/services/config_integrity.py +5 -16
- crackerjack/services/config_merge.py +542 -0
- crackerjack/services/contextual_ai_assistant.py +17 -19
- crackerjack/services/coverage_ratchet.py +51 -76
- crackerjack/services/debug.py +25 -39
- crackerjack/services/dependency_monitor.py +52 -50
- crackerjack/services/enhanced_filesystem.py +14 -11
- crackerjack/services/file_hasher.py +1 -1
- crackerjack/services/filesystem.py +1 -12
- crackerjack/services/git.py +78 -44
- crackerjack/services/health_metrics.py +31 -27
- crackerjack/services/initialization.py +281 -433
- crackerjack/services/input_validator.py +760 -0
- crackerjack/services/log_manager.py +16 -16
- crackerjack/services/logging.py +7 -6
- crackerjack/services/metrics.py +43 -43
- crackerjack/services/pattern_cache.py +2 -31
- crackerjack/services/pattern_detector.py +26 -63
- crackerjack/services/performance_benchmarks.py +20 -45
- crackerjack/services/regex_patterns.py +2887 -0
- crackerjack/services/regex_utils.py +537 -0
- crackerjack/services/secure_path_utils.py +683 -0
- crackerjack/services/secure_status_formatter.py +534 -0
- crackerjack/services/secure_subprocess.py +605 -0
- crackerjack/services/security.py +47 -10
- crackerjack/services/security_logger.py +492 -0
- crackerjack/services/server_manager.py +109 -50
- crackerjack/services/smart_scheduling.py +8 -25
- crackerjack/services/status_authentication.py +603 -0
- crackerjack/services/status_security_manager.py +442 -0
- crackerjack/services/thread_safe_status_collector.py +546 -0
- crackerjack/services/tool_version_service.py +1 -23
- crackerjack/services/unified_config.py +36 -58
- crackerjack/services/validation_rate_limiter.py +269 -0
- crackerjack/services/version_checker.py +9 -40
- crackerjack/services/websocket_resource_limiter.py +572 -0
- crackerjack/slash_commands/__init__.py +52 -2
- crackerjack/tools/__init__.py +0 -0
- crackerjack/tools/validate_input_validator_patterns.py +262 -0
- crackerjack/tools/validate_regex_patterns.py +198 -0
- {crackerjack-0.31.9.dist-info → crackerjack-0.31.12.dist-info}/METADATA +197 -12
- crackerjack-0.31.12.dist-info/RECORD +178 -0
- crackerjack/cli/facade.py +0 -104
- crackerjack-0.31.9.dist-info/RECORD +0 -149
- {crackerjack-0.31.9.dist-info → crackerjack-0.31.12.dist-info}/WHEEL +0 -0
- {crackerjack-0.31.9.dist-info → crackerjack-0.31.12.dist-info}/entry_points.txt +0 -0
- {crackerjack-0.31.9.dist-info → crackerjack-0.31.12.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Regression Prevention System
|
|
3
|
-
|
|
4
|
-
Prevents known failures from reoccurring in the AI agent pipeline.
|
|
5
|
-
Creates a comprehensive safety net against surprise failures.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
1
|
import hashlib
|
|
9
2
|
import json
|
|
10
3
|
import typing as t
|
|
@@ -13,21 +6,20 @@ from datetime import datetime, timedelta
|
|
|
13
6
|
from pathlib import Path
|
|
14
7
|
from typing import Any
|
|
15
8
|
|
|
16
|
-
from crackerjack.agents.base import FixResult, Issue, IssueType
|
|
17
9
|
from rich.console import Console
|
|
18
10
|
from rich.panel import Panel
|
|
19
11
|
from rich.table import Table
|
|
20
12
|
|
|
13
|
+
from crackerjack.agents.base import FixResult, Issue, IssueType
|
|
14
|
+
|
|
21
15
|
|
|
22
16
|
@dataclass
|
|
23
17
|
class RegressionPattern:
|
|
24
|
-
"""Known failure pattern to prevent regression."""
|
|
25
|
-
|
|
26
18
|
pattern_id: str
|
|
27
19
|
name: str
|
|
28
20
|
description: str
|
|
29
|
-
issue_signature: str
|
|
30
|
-
failure_indicators: list[str]
|
|
21
|
+
issue_signature: str
|
|
22
|
+
failure_indicators: list[str]
|
|
31
23
|
fix_applied_date: datetime
|
|
32
24
|
agent_name: str
|
|
33
25
|
issue_type: IssueType
|
|
@@ -37,34 +29,26 @@ class RegressionPattern:
|
|
|
37
29
|
|
|
38
30
|
@dataclass
|
|
39
31
|
class RegressionAlert:
|
|
40
|
-
"""Alert for detected regression."""
|
|
41
|
-
|
|
42
32
|
pattern_id: str
|
|
43
33
|
pattern_name: str
|
|
44
34
|
detected_at: datetime
|
|
45
35
|
issue_id: str
|
|
46
36
|
agent_name: str
|
|
47
37
|
failure_evidence: list[str]
|
|
48
|
-
severity: str
|
|
38
|
+
severity: str
|
|
49
39
|
|
|
50
40
|
|
|
51
41
|
class RegressionPreventionSystem:
|
|
52
|
-
"""System to prevent known failure patterns from recurring."""
|
|
53
|
-
|
|
54
42
|
def __init__(self, console: Console | None = None):
|
|
55
43
|
self.console = console or Console()
|
|
56
44
|
self.known_patterns: dict[str, RegressionPattern] = {}
|
|
57
45
|
self.regression_alerts: list[RegressionAlert] = []
|
|
58
46
|
self.prevention_active = True
|
|
59
47
|
|
|
60
|
-
# Load known patterns
|
|
61
48
|
self._initialize_known_patterns()
|
|
62
49
|
self._load_patterns_from_file()
|
|
63
50
|
|
|
64
51
|
def _initialize_known_patterns(self):
|
|
65
|
-
"""Initialize patterns for known critical failures."""
|
|
66
|
-
|
|
67
|
-
# Pattern 1: detect_agent_needs complexity failure
|
|
68
52
|
self.register_regression_pattern(
|
|
69
53
|
pattern_id="detect_agent_needs_complexity_22",
|
|
70
54
|
name="detect_agent_needs Complexity Failure",
|
|
@@ -72,7 +56,7 @@ class RegressionPreventionSystem:
|
|
|
72
56
|
issue_signature=self._generate_issue_signature(
|
|
73
57
|
issue_type=IssueType.COMPLEXITY,
|
|
74
58
|
message="Function detect_agent_needs has complexity 22",
|
|
75
|
-
file_path="crackerjack/mcp/tools/execution_tools.py",
|
|
59
|
+
file_path="crackerjack / mcp / tools / execution_tools.py",
|
|
76
60
|
),
|
|
77
61
|
failure_indicators=[
|
|
78
62
|
"Could not automatically reduce complexity",
|
|
@@ -88,7 +72,7 @@ class RegressionPreventionSystem:
|
|
|
88
72
|
"issue": {
|
|
89
73
|
"type": "COMPLEXITY",
|
|
90
74
|
"message": "Function detect_agent_needs has complexity 22 (exceeds limit of 15)",
|
|
91
|
-
"file_path": "/Users/les/Projects/crackerjack/crackerjack/mcp/tools/execution_tools.py",
|
|
75
|
+
"file_path": "/ Users / les / Projects / crackerjack / crackerjack / mcp / tools / execution_tools.py",
|
|
92
76
|
},
|
|
93
77
|
"expected_success": True,
|
|
94
78
|
"expected_confidence": 0.8,
|
|
@@ -96,7 +80,6 @@ class RegressionPreventionSystem:
|
|
|
96
80
|
],
|
|
97
81
|
)
|
|
98
82
|
|
|
99
|
-
# Pattern 2: Agent coordination infinite loops
|
|
100
83
|
self.register_regression_pattern(
|
|
101
84
|
pattern_id="agent_coordination_infinite_loop",
|
|
102
85
|
name="Agent Coordination Infinite Loop",
|
|
@@ -119,7 +102,6 @@ class RegressionPreventionSystem:
|
|
|
119
102
|
],
|
|
120
103
|
)
|
|
121
104
|
|
|
122
|
-
# Pattern 3: RefactoringAgent returning no changes
|
|
123
105
|
self.register_regression_pattern(
|
|
124
106
|
pattern_id="refactoring_agent_no_changes",
|
|
125
107
|
name="RefactoringAgent No Changes Applied",
|
|
@@ -140,7 +122,6 @@ class RegressionPreventionSystem:
|
|
|
140
122
|
],
|
|
141
123
|
)
|
|
142
124
|
|
|
143
|
-
# Pattern 4: Import optimization failures
|
|
144
125
|
self.register_regression_pattern(
|
|
145
126
|
pattern_id="import_optimization_no_effect",
|
|
146
127
|
name="Import Optimization No Effect",
|
|
@@ -156,7 +137,6 @@ class RegressionPreventionSystem:
|
|
|
156
137
|
issue_type=IssueType.IMPORT_ERROR,
|
|
157
138
|
)
|
|
158
139
|
|
|
159
|
-
# Pattern 5: Test agent failures
|
|
160
140
|
self.register_regression_pattern(
|
|
161
141
|
pattern_id="test_agent_instantiation_failure",
|
|
162
142
|
name="Test Agent Instantiation Failure",
|
|
@@ -183,7 +163,6 @@ class RegressionPreventionSystem:
|
|
|
183
163
|
issue_type: IssueType,
|
|
184
164
|
test_cases: list[dict[str, Any]] | None = None,
|
|
185
165
|
):
|
|
186
|
-
"""Register a new regression pattern."""
|
|
187
166
|
pattern = RegressionPattern(
|
|
188
167
|
pattern_id=pattern_id,
|
|
189
168
|
name=name,
|
|
@@ -206,14 +185,12 @@ class RegressionPreventionSystem:
|
|
|
206
185
|
file_path: str = "",
|
|
207
186
|
line_number: int = 0,
|
|
208
187
|
) -> str:
|
|
209
|
-
|
|
210
|
-
content = f"{issue_type.value}:{message}:{file_path}:{line_number}"
|
|
188
|
+
content = f"{issue_type.value}: {message}: {file_path}: {line_number}"
|
|
211
189
|
return hashlib.md5(content.encode(), usedforsecurity=False).hexdigest()[:12]
|
|
212
190
|
|
|
213
191
|
async def check_for_regression(
|
|
214
192
|
self, agent_name: str, issue: Issue, result: FixResult
|
|
215
193
|
) -> RegressionAlert | None:
|
|
216
|
-
"""Check if this represents a known regression pattern."""
|
|
217
194
|
if not self.prevention_active:
|
|
218
195
|
return None
|
|
219
196
|
|
|
@@ -224,7 +201,6 @@ class RegressionPreventionSystem:
|
|
|
224
201
|
line_number=issue.line_number or 0,
|
|
225
202
|
)
|
|
226
203
|
|
|
227
|
-
# Check against known patterns
|
|
228
204
|
for pattern_id, pattern in self.known_patterns.items():
|
|
229
205
|
if not pattern.prevention_enabled:
|
|
230
206
|
continue
|
|
@@ -252,16 +228,13 @@ class RegressionPreventionSystem:
|
|
|
252
228
|
issue: Issue,
|
|
253
229
|
result: FixResult,
|
|
254
230
|
) -> list[str] | None:
|
|
255
|
-
"""Check if a pattern matches the current issue."""
|
|
256
231
|
is_regression = False
|
|
257
232
|
evidence = []
|
|
258
233
|
|
|
259
|
-
# Check signature match
|
|
260
234
|
if pattern.issue_signature == issue_signature:
|
|
261
235
|
is_regression = True
|
|
262
236
|
evidence.append(f"Exact issue signature match: {issue_signature}")
|
|
263
237
|
|
|
264
|
-
# Check failure indicators
|
|
265
238
|
failure_text = self._build_failure_text(result, issue)
|
|
266
239
|
matched_indicators = self._find_matching_indicators(
|
|
267
240
|
pattern.failure_indicators, failure_text
|
|
@@ -271,7 +244,6 @@ class RegressionPreventionSystem:
|
|
|
271
244
|
is_regression = True
|
|
272
245
|
evidence.extend([f"Matched indicator: {ind}" for ind in matched_indicators])
|
|
273
246
|
|
|
274
|
-
# Agent-specific checks
|
|
275
247
|
if self._check_agent_specific_failure(pattern, agent_name, issue, result):
|
|
276
248
|
is_regression = True
|
|
277
249
|
evidence.append(
|
|
@@ -281,7 +253,6 @@ class RegressionPreventionSystem:
|
|
|
281
253
|
return evidence if is_regression else None
|
|
282
254
|
|
|
283
255
|
def _build_failure_text(self, result: FixResult, issue: Issue) -> str:
|
|
284
|
-
"""Build concatenated text for failure indicator matching."""
|
|
285
256
|
return " ".join(
|
|
286
257
|
[
|
|
287
258
|
" ".join(result.remaining_issues),
|
|
@@ -295,7 +266,6 @@ class RegressionPreventionSystem:
|
|
|
295
266
|
def _find_matching_indicators(
|
|
296
267
|
self, indicators: list[str], failure_text: str
|
|
297
268
|
) -> list[str]:
|
|
298
|
-
"""Find indicators that match in the failure text."""
|
|
299
269
|
return [
|
|
300
270
|
indicator
|
|
301
271
|
for indicator in indicators
|
|
@@ -309,7 +279,6 @@ class RegressionPreventionSystem:
|
|
|
309
279
|
issue: Issue,
|
|
310
280
|
result: FixResult,
|
|
311
281
|
) -> bool:
|
|
312
|
-
"""Check if this is an agent-specific failure pattern."""
|
|
313
282
|
return (
|
|
314
283
|
pattern.agent_name == agent_name
|
|
315
284
|
and pattern.issue_type == issue.type
|
|
@@ -325,7 +294,6 @@ class RegressionPreventionSystem:
|
|
|
325
294
|
issue: Issue,
|
|
326
295
|
evidence: list[str],
|
|
327
296
|
) -> RegressionAlert:
|
|
328
|
-
"""Create a regression alert with appropriate severity."""
|
|
329
297
|
severity = self._determine_alert_severity(pattern_id)
|
|
330
298
|
|
|
331
299
|
return RegressionAlert(
|
|
@@ -339,7 +307,6 @@ class RegressionPreventionSystem:
|
|
|
339
307
|
)
|
|
340
308
|
|
|
341
309
|
def _determine_alert_severity(self, pattern_id: str) -> str:
|
|
342
|
-
"""Determine alert severity based on pattern type."""
|
|
343
310
|
if "detect_agent_needs" in pattern_id:
|
|
344
311
|
return "critical"
|
|
345
312
|
elif "infinite_loop" in pattern_id:
|
|
@@ -347,7 +314,6 @@ class RegressionPreventionSystem:
|
|
|
347
314
|
return "error"
|
|
348
315
|
|
|
349
316
|
async def _handle_regression_alert(self, alert: RegressionAlert):
|
|
350
|
-
"""Handle a detected regression alert."""
|
|
351
317
|
color = {"warning": "yellow", "error": "red", "critical": "bold red"}.get(
|
|
352
318
|
alert.severity, "white"
|
|
353
319
|
)
|
|
@@ -357,32 +323,29 @@ class RegressionPreventionSystem:
|
|
|
357
323
|
self.console.print(f"\n{icon} [bold {color}]REGRESSION DETECTED[/bold {color}]")
|
|
358
324
|
self.console.print(
|
|
359
325
|
Panel(
|
|
360
|
-
f"[bold]Pattern:[/bold] {alert.pattern_name}\n"
|
|
361
|
-
f"[bold]Agent:[/bold] {alert.agent_name}\n"
|
|
362
|
-
f"[bold]Issue ID:[/bold] {alert.issue_id}\n"
|
|
363
|
-
f"[bold]Evidence:[/bold]\n"
|
|
364
|
-
+ "\n".join(f"
|
|
326
|
+
f"[bold]Pattern: [/bold] {alert.pattern_name}\n"
|
|
327
|
+
f"[bold]Agent: [/bold] {alert.agent_name}\n"
|
|
328
|
+
f"[bold]Issue ID: [/bold] {alert.issue_id}\n"
|
|
329
|
+
f"[bold]Evidence: [/bold]\n"
|
|
330
|
+
+ "\n".join(f" • {e}" for e in alert.failure_evidence),
|
|
365
331
|
title=f"{alert.severity.upper()} Regression Alert",
|
|
366
332
|
border_style=color,
|
|
367
333
|
)
|
|
368
334
|
)
|
|
369
335
|
|
|
370
|
-
# Immediate actions based on severity
|
|
371
336
|
if alert.severity == "critical":
|
|
372
337
|
self.console.print(
|
|
373
|
-
"[bold red]🚨 CRITICAL REGRESSION
|
|
338
|
+
"[bold red]🚨 CRITICAL REGRESSION-IMMEDIATE ACTION REQUIRED[/bold red]"
|
|
374
339
|
)
|
|
375
|
-
self.console.print("Recommended actions:")
|
|
376
|
-
self.console.print("
|
|
377
|
-
self.console.print("
|
|
378
|
-
self.console.print("
|
|
379
|
-
self.console.print("
|
|
340
|
+
self.console.print("Recommended actions: ")
|
|
341
|
+
self.console.print(" 1. Stop current AI agent execution")
|
|
342
|
+
self.console.print(" 2. Run regression tests immediately")
|
|
343
|
+
self.console.print(" 3. Check recent agent code changes")
|
|
344
|
+
self.console.print(" 4. Verify fix implementation")
|
|
380
345
|
|
|
381
|
-
# Log to file for persistent tracking
|
|
382
346
|
self._log_critical_regression(alert)
|
|
383
347
|
|
|
384
348
|
def _log_critical_regression(self, alert: RegressionAlert):
|
|
385
|
-
"""Log critical regression for persistent tracking."""
|
|
386
349
|
log_file = Path(".crackerjack") / "critical_regressions.log"
|
|
387
350
|
log_file.parent.mkdir(exist_ok=True)
|
|
388
351
|
|
|
@@ -399,7 +362,6 @@ class RegressionPreventionSystem:
|
|
|
399
362
|
f.write(json.dumps(log_entry) + "\n")
|
|
400
363
|
|
|
401
364
|
def run_regression_tests(self) -> dict[str, t.Any]:
|
|
402
|
-
"""Run all regression test cases."""
|
|
403
365
|
self.console.print("🧪 [bold]Running Regression Prevention Tests[/bold]")
|
|
404
366
|
|
|
405
367
|
results: dict[str, t.Any] = {
|
|
@@ -410,7 +372,6 @@ class RegressionPreventionSystem:
|
|
|
410
372
|
"failures": [],
|
|
411
373
|
}
|
|
412
374
|
|
|
413
|
-
# Type hints for clarity
|
|
414
375
|
patterns_tested: int = 0
|
|
415
376
|
tests_passed: int = 0
|
|
416
377
|
tests_failed: int = 0
|
|
@@ -425,13 +386,11 @@ class RegressionPreventionSystem:
|
|
|
425
386
|
|
|
426
387
|
for i, test_case in enumerate(pattern.test_cases):
|
|
427
388
|
try:
|
|
428
|
-
# This would need integration with actual agent testing
|
|
429
|
-
# For now, simulate test execution
|
|
430
389
|
test_passed = self._simulate_regression_test(test_case, pattern)
|
|
431
390
|
|
|
432
391
|
if test_passed:
|
|
433
392
|
tests_passed += 1
|
|
434
|
-
self.console.print(f"
|
|
393
|
+
self.console.print(f" ✅ Test case {i + 1} passed")
|
|
435
394
|
else:
|
|
436
395
|
tests_failed += 1
|
|
437
396
|
failures.append(
|
|
@@ -443,25 +402,23 @@ class RegressionPreventionSystem:
|
|
|
443
402
|
),
|
|
444
403
|
}
|
|
445
404
|
)
|
|
446
|
-
self.console.print(f"
|
|
405
|
+
self.console.print(f" ❌ Test case {i + 1} failed")
|
|
447
406
|
|
|
448
407
|
except Exception as e:
|
|
449
408
|
tests_failed += 1
|
|
450
409
|
failures.append(
|
|
451
410
|
{"pattern_id": pattern_id, "test_case": i + 1, "error": str(e)}
|
|
452
411
|
)
|
|
453
|
-
self.console.print(f"
|
|
412
|
+
self.console.print(f" ❌ Test case {i + 1} error: {e}")
|
|
454
413
|
|
|
455
|
-
# Update results with final counts
|
|
456
414
|
results["patterns_tested"] = patterns_tested
|
|
457
415
|
results["tests_passed"] = tests_passed
|
|
458
416
|
results["tests_failed"] = tests_failed
|
|
459
417
|
results["failures"] = failures
|
|
460
418
|
|
|
461
|
-
# Report results
|
|
462
419
|
if tests_failed > 0:
|
|
463
420
|
self.console.print(
|
|
464
|
-
f"🚨 [bold red]{tests_failed} regression tests failed![/bold red]"
|
|
421
|
+
f"🚨 [bold red]{tests_failed} regression tests failed ![/bold red]"
|
|
465
422
|
)
|
|
466
423
|
else:
|
|
467
424
|
self.console.print(
|
|
@@ -473,27 +430,19 @@ class RegressionPreventionSystem:
|
|
|
473
430
|
def _simulate_regression_test(
|
|
474
431
|
self, test_case: dict[str, Any], pattern: RegressionPattern
|
|
475
432
|
) -> bool:
|
|
476
|
-
"""Simulate running a regression test case."""
|
|
477
|
-
# This is a placeholder - in practice would run actual agent tests
|
|
478
|
-
|
|
479
|
-
# Simulate test based on test case requirements
|
|
480
433
|
if "expected_success" in test_case:
|
|
481
|
-
# Simulate that our fixes work
|
|
482
434
|
if pattern.pattern_id == "detect_agent_needs_complexity_22":
|
|
483
|
-
return True
|
|
435
|
+
return True
|
|
484
436
|
|
|
485
437
|
if "max_iterations" in test_case:
|
|
486
|
-
# Simulate that coordination doesn't loop infinitely
|
|
487
438
|
return True
|
|
488
439
|
|
|
489
440
|
if "should_modify_files" in test_case:
|
|
490
|
-
# Simulate that agents apply changes
|
|
491
441
|
return True
|
|
492
442
|
|
|
493
|
-
return True
|
|
443
|
+
return True
|
|
494
444
|
|
|
495
445
|
def create_prevention_dashboard(self) -> Table:
|
|
496
|
-
"""Create regression prevention dashboard."""
|
|
497
446
|
table = Table(
|
|
498
447
|
title="Regression Prevention Dashboard",
|
|
499
448
|
header_style="bold magenta",
|
|
@@ -507,7 +456,6 @@ class RegressionPreventionSystem:
|
|
|
507
456
|
table.add_column("Test Cases", justify="center", width=10)
|
|
508
457
|
|
|
509
458
|
for pattern in self.known_patterns.values():
|
|
510
|
-
# Find recent alerts for this pattern
|
|
511
459
|
recent_alerts = [
|
|
512
460
|
a
|
|
513
461
|
for a in self.regression_alerts
|
|
@@ -534,9 +482,9 @@ class RegressionPreventionSystem:
|
|
|
534
482
|
latest = max(recent_alerts, key=lambda a: a.detected_at)
|
|
535
483
|
delta = datetime.now() - latest.detected_at
|
|
536
484
|
if delta.seconds < 3600:
|
|
537
|
-
last_alert = f"{delta.seconds
|
|
485
|
+
last_alert = f"{delta.seconds / 60}m ago"
|
|
538
486
|
else:
|
|
539
|
-
last_alert = f"{delta.seconds
|
|
487
|
+
last_alert = f"{delta.seconds / 3600}h ago"
|
|
540
488
|
|
|
541
489
|
table.add_row(
|
|
542
490
|
pattern.name[:24] + ("..." if len(pattern.name) > 24 else ""),
|
|
@@ -550,12 +498,10 @@ class RegressionPreventionSystem:
|
|
|
550
498
|
return table
|
|
551
499
|
|
|
552
500
|
def get_recent_regressions(self, hours: int = 24) -> list[RegressionAlert]:
|
|
553
|
-
"""Get regression alerts from recent hours."""
|
|
554
501
|
cutoff = datetime.now() - timedelta(hours=hours)
|
|
555
502
|
return [alert for alert in self.regression_alerts if alert.detected_at > cutoff]
|
|
556
503
|
|
|
557
504
|
def _save_patterns_to_file(self):
|
|
558
|
-
"""Save patterns to persistent storage."""
|
|
559
505
|
patterns_file = Path(".crackerjack") / "regression_patterns.json"
|
|
560
506
|
patterns_file.parent.mkdir(exist_ok=True)
|
|
561
507
|
|
|
@@ -581,7 +527,6 @@ class RegressionPreventionSystem:
|
|
|
581
527
|
json.dump(data, f, indent=2)
|
|
582
528
|
|
|
583
529
|
def _load_patterns_from_file(self):
|
|
584
|
-
"""Load additional patterns from file."""
|
|
585
530
|
patterns_file = Path(".crackerjack") / "regression_patterns.json"
|
|
586
531
|
if not patterns_file.exists():
|
|
587
532
|
return
|
|
@@ -591,7 +536,7 @@ class RegressionPreventionSystem:
|
|
|
591
536
|
data = json.load(f)
|
|
592
537
|
|
|
593
538
|
for pid, pdata in data.get("patterns", {}).items():
|
|
594
|
-
if pid not in self.known_patterns:
|
|
539
|
+
if pid not in self.known_patterns:
|
|
595
540
|
pattern = RegressionPattern(
|
|
596
541
|
pattern_id=pid,
|
|
597
542
|
name=pdata["name"],
|
|
@@ -612,17 +557,14 @@ class RegressionPreventionSystem:
|
|
|
612
557
|
self.console.print(f"⚠️ Warning: Could not load patterns from file: {e}")
|
|
613
558
|
|
|
614
559
|
|
|
615
|
-
# Integration function for easy use
|
|
616
560
|
async def monitor_for_regressions(
|
|
617
561
|
agent_name: str, issue: Issue, result: FixResult
|
|
618
562
|
) -> RegressionAlert | None:
|
|
619
|
-
"""Quick function to check for regressions during agent execution."""
|
|
620
563
|
prevention_system = RegressionPreventionSystem()
|
|
621
564
|
return await prevention_system.check_for_regression(agent_name, issue, result)
|
|
622
565
|
|
|
623
566
|
|
|
624
567
|
if __name__ == "__main__":
|
|
625
|
-
# Demo the regression prevention system
|
|
626
568
|
console = Console()
|
|
627
569
|
system = RegressionPreventionSystem(console)
|
|
628
570
|
|
|
@@ -631,7 +573,6 @@ if __name__ == "__main__":
|
|
|
631
573
|
f"\n📊 Monitoring {len(system.known_patterns)} known regression patterns"
|
|
632
574
|
)
|
|
633
575
|
|
|
634
|
-
# Run regression tests
|
|
635
576
|
results = system.run_regression_tests()
|
|
636
577
|
console.print(f"\n✅ Regression testing complete: {results}")
|
|
637
578
|
|