patchrail 0.1.0__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.
- patchrail/__init__.py +7 -0
- patchrail/__main__.py +7 -0
- patchrail/ci/__init__.py +7 -0
- patchrail/ci/classify.py +888 -0
- patchrail/cli.py +8566 -0
- patchrail/funded_issues/__init__.py +138 -0
- patchrail/funded_issues/algora_board.py +240 -0
- patchrail/funded_issues/blocklist.py +112 -0
- patchrail/funded_issues/discovery.py +4091 -0
- patchrail/funded_issues/importers.py +316 -0
- patchrail/funded_issues/source_noise.py +349 -0
- patchrail/funded_issues/store.py +459 -0
- patchrail/queue/__init__.py +75 -0
- patchrail/queue/server.py +273 -0
- patchrail/queue/status.py +756 -0
- patchrail/queue/store.py +600 -0
- patchrail/reviewer_quick_check.py +650 -0
- patchrail/schemas/__init__.py +1 -0
- patchrail/schemas/application-dossier.v1.schema.json +305 -0
- patchrail/schemas/ci-benchmark.v1.schema.json +174 -0
- patchrail/schemas/ci-fixture-check.v1.schema.json +122 -0
- patchrail/schemas/ci-pilot-metrics.v1.schema.json +164 -0
- patchrail/schemas/ci-pilot-summary.v1.schema.json +146 -0
- patchrail/schemas/ci-result.v1.schema.json +133 -0
- patchrail/schemas/funded-issues-client-report.v1.schema.json +524 -0
- patchrail/schemas/funded-issues-recheck-queue.v1.schema.json +333 -0
- patchrail/schemas/funded-issues-recheck-summary.v1.schema.json +136 -0
- patchrail/schemas/funded-issues-report.v1.schema.json +836 -0
- patchrail/schemas/funded-issues-shortlist.v1.schema.json +953 -0
- patchrail/schemas/funded-issues-store-status.v1.schema.json +96 -0
- patchrail/schemas/funded-issues-store.v1.schema.json +117 -0
- patchrail/schemas/queue-audit-event.v1.schema.json +44 -0
- patchrail/schemas/queue-audit-summary.v1.schema.json +169 -0
- patchrail/schemas/queue-gate-report.v1.schema.json +158 -0
- patchrail/schemas/queue-policy-resolution.v1.schema.json +188 -0
- patchrail/schemas/queue-policy-scan.v1.schema.json +175 -0
- patchrail/schemas/queue-proposal.v1.schema.json +61 -0
- patchrail/schemas/queue-review.v1.schema.json +218 -0
- patchrail/schemas/queue-status.v1.schema.json +179 -0
- patchrail/schemas/queue-work-item.v1.schema.json +64 -0
- patchrail/schemas/reviewer-quick-check-artifacts.v1.schema.json +104 -0
- patchrail/web_metrics.py +649 -0
- patchrail-0.1.0.dist-info/METADATA +279 -0
- patchrail-0.1.0.dist-info/RECORD +47 -0
- patchrail-0.1.0.dist-info/WHEEL +4 -0
- patchrail-0.1.0.dist-info/entry_points.txt +2 -0
- patchrail-0.1.0.dist-info/licenses/LICENSE +202 -0
patchrail/ci/classify.py
ADDED
|
@@ -0,0 +1,888 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
from collections import Counter
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
REDACTION_PATTERNS: list[tuple[str, str, str]] = [
|
|
9
|
+
("github_token", r"\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{20,}\b", "<github-token>"),
|
|
10
|
+
("github_fine_grained_token", r"\bgithub_pat_[A-Za-z0-9_]{20,}\b", "<github-token>"),
|
|
11
|
+
("gitlab_token", r"\bglpat-[A-Za-z0-9_-]{20,}\b", "<gitlab-token>"),
|
|
12
|
+
("api_key", r"\b(?:sk|rk)-[A-Za-z0-9_-]{20,}\b", "<api-key>"),
|
|
13
|
+
("npm_token", r"\bnpm_[A-Za-z0-9]{20,}\b", "<npm-token>"),
|
|
14
|
+
("pypi_token", r"\bpypi-[A-Za-z0-9_.-]{20,}\b", "<pypi-token>"),
|
|
15
|
+
("aws_access_key", r"\b(?:AKIA|ASIA)[A-Z0-9]{16}\b", "<aws-access-key>"),
|
|
16
|
+
("stripe_secret_key", r"\bsk_(?:live|test)_[A-Za-z0-9]{16,}\b", "<stripe-secret-key>"),
|
|
17
|
+
("slack_token", r"\bxox[baprs]-[A-Za-z0-9-]{10,}\b", "<slack-token>"),
|
|
18
|
+
("google_api_key", r"\bAIza[0-9A-Za-z_-]{35}\b", "<google-api-key>"),
|
|
19
|
+
("google_oauth_token", r"\bya29\.[A-Za-z0-9_-]{20,}", "<google-oauth-token>"),
|
|
20
|
+
("huggingface_token", r"\bhf_[A-Za-z0-9]{20,}\b", "<huggingface-token>"),
|
|
21
|
+
(
|
|
22
|
+
"private_key_block",
|
|
23
|
+
r"-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----"
|
|
24
|
+
r"[\s\S]*?-----END (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----",
|
|
25
|
+
"<private-key>",
|
|
26
|
+
),
|
|
27
|
+
("jwt", r"\beyJ[A-Za-z0-9_-]{8,}\.eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b", "<jwt>"),
|
|
28
|
+
("bearer_token", r"\bBearer\s+[A-Za-z0-9._~+/=-]{16,}\b", "Bearer <token>"),
|
|
29
|
+
("sendgrid_api_key", r"\bSG\.[A-Za-z0-9_-]{16,}\.[A-Za-z0-9_-]{16,}\b", "<sendgrid-api-key>"),
|
|
30
|
+
("telegram_bot_token", r"\b\d{8,10}:AA[A-Za-z0-9_-]{30,}\b", "<telegram-bot-token>"),
|
|
31
|
+
(
|
|
32
|
+
"url_credentials",
|
|
33
|
+
r"\b([a-z][a-z0-9+.-]*://)[^\s:/@]+:[^\s/@]+@",
|
|
34
|
+
r"\1<credentials>@",
|
|
35
|
+
),
|
|
36
|
+
(
|
|
37
|
+
"env_secret_assignment",
|
|
38
|
+
r"\b([A-Z0-9_]*(?:TOKEN|SECRET|PASSWORD|KEY))=([^\s'\"]+)",
|
|
39
|
+
r"\1=<redacted>",
|
|
40
|
+
),
|
|
41
|
+
("email", r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b", "<email>"),
|
|
42
|
+
("unix_home_path", r"/home/[^/\s'\":]+", "/home/<user>"),
|
|
43
|
+
("mac_home_path", r"/Users/[^/\s'\":]+", "/Users/<user>"),
|
|
44
|
+
("windows_home_path", r"\b[A-Z]:[\\/]+Users[\\/]+[^\\/\s'\":]+", "C:/Users/<user>"),
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
RULES: list[dict[str, Any]] = [
|
|
49
|
+
{
|
|
50
|
+
"failure_class": "runner_resource_exhaustion",
|
|
51
|
+
"likely_subsystem": "CI runner memory or disk capacity",
|
|
52
|
+
"patterns": [
|
|
53
|
+
r"OOMKilled",
|
|
54
|
+
r"Out of memory",
|
|
55
|
+
r"Cannot allocate memory",
|
|
56
|
+
r"JavaScript heap out of memory",
|
|
57
|
+
r"runtime: out of memory",
|
|
58
|
+
r"signal: killed",
|
|
59
|
+
r"Process completed with exit code 137",
|
|
60
|
+
r"\bexit code 137\b",
|
|
61
|
+
r"No space left on device",
|
|
62
|
+
r"\bENOSPC\b",
|
|
63
|
+
r"disk quota exceeded",
|
|
64
|
+
r"received a shutdown signal",
|
|
65
|
+
r"exceeded memory limit",
|
|
66
|
+
],
|
|
67
|
+
"reproduction_command": (
|
|
68
|
+
"rerun the failing job while watching runner memory and disk "
|
|
69
|
+
"(e.g. /usr/bin/time -v and df -h)"
|
|
70
|
+
),
|
|
71
|
+
"minimal_repair_strategy": (
|
|
72
|
+
"Confirm the runner hit a memory or disk limit rather than a code defect, then lower "
|
|
73
|
+
"peak memory use, free disk space, or raise the runner resource class before rerunning."
|
|
74
|
+
),
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"failure_class": "network_transient_failure",
|
|
78
|
+
"likely_subsystem": "Network connectivity or upstream service availability",
|
|
79
|
+
"patterns": [
|
|
80
|
+
r"Could not resolve host",
|
|
81
|
+
r"Temporary failure in name resolution",
|
|
82
|
+
r"Name or service not known",
|
|
83
|
+
r"getaddrinfo ENOTFOUND",
|
|
84
|
+
r"getaddrinfo EAI_AGAIN",
|
|
85
|
+
r"\bno such host\b",
|
|
86
|
+
r"Connection timed out",
|
|
87
|
+
r"\bETIMEDOUT\b",
|
|
88
|
+
r"\bECONNREFUSED\b",
|
|
89
|
+
r"Connection refused",
|
|
90
|
+
r"\bECONNRESET\b",
|
|
91
|
+
r"Connection reset by peer",
|
|
92
|
+
r"Network is unreachable",
|
|
93
|
+
r"\bENETUNREACH\b",
|
|
94
|
+
r"TLS handshake timeout",
|
|
95
|
+
r"\bESOCKETTIMEDOUT\b",
|
|
96
|
+
r"\bi/o timeout\b",
|
|
97
|
+
r"context deadline exceeded",
|
|
98
|
+
r"\bdial tcp\b",
|
|
99
|
+
r"429 Too Many Requests",
|
|
100
|
+
r"API rate limit exceeded",
|
|
101
|
+
r"503 Service Unavailable",
|
|
102
|
+
r"502 Bad Gateway",
|
|
103
|
+
r"504 Gateway Time-?out",
|
|
104
|
+
r"The remote end hung up unexpectedly",
|
|
105
|
+
r"RPC failed",
|
|
106
|
+
r"fetch-pack: unexpected disconnect",
|
|
107
|
+
r"early EOF",
|
|
108
|
+
r"fatal: unable to access",
|
|
109
|
+
r"Failed to connect to .* port",
|
|
110
|
+
],
|
|
111
|
+
"reproduction_command": (
|
|
112
|
+
"re-run the failing job; if it fails again, probe the endpoint "
|
|
113
|
+
"(e.g. curl -sSf <url> or nslookup <host>) from the runner"
|
|
114
|
+
),
|
|
115
|
+
"minimal_repair_strategy": (
|
|
116
|
+
"Confirm the failure is a transient network or upstream-service outage rather than a "
|
|
117
|
+
"code defect, then retry the job; if it persists, pin a reachable mirror, add a "
|
|
118
|
+
"bounded retry, or wait for the upstream service to recover before changing code."
|
|
119
|
+
),
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"failure_class": "ci_job_timeout",
|
|
123
|
+
"likely_subsystem": "CI job execution time limit or cancellation",
|
|
124
|
+
"patterns": [
|
|
125
|
+
r"has exceeded the maximum execution time of \d+ minutes",
|
|
126
|
+
r"The job running on runner .+ has exceeded",
|
|
127
|
+
r"##\[error\]The operation was canceled",
|
|
128
|
+
r"The operation was canceled",
|
|
129
|
+
r"ERROR: Job failed: execution took longer than",
|
|
130
|
+
r"execution took longer than \S+ seconds",
|
|
131
|
+
r"Too long with no output",
|
|
132
|
+
r"\(exceeded \d+m\d*s?\)",
|
|
133
|
+
r"exceeded the maximum time limit for jobs",
|
|
134
|
+
r"ran longer than the maximum time of \d+ minutes",
|
|
135
|
+
r"\btimeout-minutes\b",
|
|
136
|
+
],
|
|
137
|
+
"reproduction_command": (
|
|
138
|
+
"re-run the job and compare step durations against the configured job/step "
|
|
139
|
+
"time limit (e.g. timeout-minutes)"
|
|
140
|
+
),
|
|
141
|
+
"minimal_repair_strategy": (
|
|
142
|
+
"Confirm the job hit a time limit or was canceled (manual or matrix fail-fast) "
|
|
143
|
+
"rather than a code defect, then cache dependencies, split or parallelize the "
|
|
144
|
+
"slowest steps, or raise the limit deliberately before rerunning."
|
|
145
|
+
),
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"failure_class": "python_dependency_resolution",
|
|
149
|
+
"likely_subsystem": "Python dependency installation",
|
|
150
|
+
"patterns": [
|
|
151
|
+
r"Could not find a version that satisfies the requirement",
|
|
152
|
+
r"No matching distribution found",
|
|
153
|
+
r"Cannot install .*because these package versions have conflicting dependencies",
|
|
154
|
+
r"ResolutionImpossible",
|
|
155
|
+
r"pip._vendor.resolvelib",
|
|
156
|
+
r"python -m pip install",
|
|
157
|
+
r"The conflict is caused by:",
|
|
158
|
+
r"Requires-Python",
|
|
159
|
+
r"requires a different python version",
|
|
160
|
+
r"version solving failed",
|
|
161
|
+
r"SolverProblemError",
|
|
162
|
+
r"Could not find a version that matches",
|
|
163
|
+
r"incompatible versions in the resolved dependencies",
|
|
164
|
+
r"uv pip compile",
|
|
165
|
+
r"No solution found",
|
|
166
|
+
r"requirements are unsatisfiable",
|
|
167
|
+
r"pip-compile",
|
|
168
|
+
r"yanked",
|
|
169
|
+
],
|
|
170
|
+
"reproduction_command": "python -m pip install -r requirements.txt",
|
|
171
|
+
"minimal_repair_strategy": (
|
|
172
|
+
"Pin or relax the conflicting dependency range, then rerun the same install "
|
|
173
|
+
"command and the affected tests."
|
|
174
|
+
),
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"failure_class": "code_coverage_threshold",
|
|
178
|
+
"likely_subsystem": "Test coverage gate",
|
|
179
|
+
"patterns": [
|
|
180
|
+
r"Required test coverage of \d",
|
|
181
|
+
r"Coverage failure: total of",
|
|
182
|
+
r"\bfail[_-]under\b",
|
|
183
|
+
r"coverage threshold",
|
|
184
|
+
r"does not meet (?:the )?(?:global )?threshold",
|
|
185
|
+
r"is below the (?:expected )?minimum coverage",
|
|
186
|
+
r"below the (?:minimum )?coverage threshold",
|
|
187
|
+
r"Coverage for \w+ \(\d+(?:\.\d+)?%\) does not meet",
|
|
188
|
+
r"SimpleCov failed",
|
|
189
|
+
r"project coverage.*(?:target|failed)",
|
|
190
|
+
r"total coverage.*(?:decreased|below)",
|
|
191
|
+
r"\bTotal coverage:",
|
|
192
|
+
r"coverage .*(?:is )?less than",
|
|
193
|
+
],
|
|
194
|
+
"reproduction_command": (
|
|
195
|
+
"re-run the suite with coverage locally "
|
|
196
|
+
"(e.g. pytest --cov, npm test -- --coverage, or go test -cover)"
|
|
197
|
+
),
|
|
198
|
+
"minimal_repair_strategy": (
|
|
199
|
+
"Confirm the tests passed but coverage fell under the configured threshold, then add "
|
|
200
|
+
"focused tests for the uncovered lines named in the coverage summary; only lower the "
|
|
201
|
+
"threshold deliberately when the uncovered code is intentionally excluded."
|
|
202
|
+
),
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
"failure_class": "python_type_check",
|
|
206
|
+
"likely_subsystem": "Python static type checking",
|
|
207
|
+
"patterns": [
|
|
208
|
+
r"\bmypy\b",
|
|
209
|
+
r"\bpyright\b",
|
|
210
|
+
r"Found \d+ errors? in \d+ files?",
|
|
211
|
+
r"error: Incompatible (?:types|return value type|default for argument)",
|
|
212
|
+
r"has incompatible type",
|
|
213
|
+
r"Argument \d+ to .* has incompatible type",
|
|
214
|
+
r"error: .*\[(?:assignment|arg-type|return-value|attr-defined|call-arg|union-attr"
|
|
215
|
+
r"|index|operator|var-annotated|name-defined|misc|override|valid-type|no-any-return"
|
|
216
|
+
r"|type-var|dict-item|list-item|import-untyped|func-returns-value)\]",
|
|
217
|
+
r"error: Need type annotation for",
|
|
218
|
+
r"error: Function is missing a (?:return )?type annotation",
|
|
219
|
+
r"error: Missing (?:return statement|type parameters)",
|
|
220
|
+
r"report(?:GeneralTypeIssues|ArgumentType|AttributeAccessIssue|ReturnType"
|
|
221
|
+
r"|OptionalMemberAccess|CallIssue|AssignmentType|IndexIssue|Redeclaration"
|
|
222
|
+
r"|UndefinedVariable)",
|
|
223
|
+
r"\d+ errors?, \d+ warnings?, \d+ informations?",
|
|
224
|
+
r"is not assignable to (?:parameter|return type|declared type)",
|
|
225
|
+
],
|
|
226
|
+
"reproduction_command": "mypy . || pyright",
|
|
227
|
+
"minimal_repair_strategy": (
|
|
228
|
+
"Confirm the static type checker (mypy or pyright) failed rather than the tests, then "
|
|
229
|
+
"fix the narrowest reported type mismatch, missing annotation, or import drift and "
|
|
230
|
+
"rerun the same type checker before broad CI."
|
|
231
|
+
),
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"failure_class": "python_lint",
|
|
235
|
+
"likely_subsystem": "Python linting or formatting",
|
|
236
|
+
"patterns": [
|
|
237
|
+
r"\bruff\b",
|
|
238
|
+
r"ruff check",
|
|
239
|
+
r"\bflake8\b",
|
|
240
|
+
r"\bpycodestyle\b",
|
|
241
|
+
r"\bpyflakes\b",
|
|
242
|
+
r"\bpylint\b",
|
|
243
|
+
r"\bautopep8\b",
|
|
244
|
+
r"\bisort\b",
|
|
245
|
+
r"imported but unused",
|
|
246
|
+
r"\bF401\b",
|
|
247
|
+
r"\bE501\b",
|
|
248
|
+
r"line too long \(\d+ > \d+",
|
|
249
|
+
r"Your code has been rated at",
|
|
250
|
+
r"\((?:unused-import|line-too-long|missing-(?:module|function|class)-docstring"
|
|
251
|
+
r"|undefined-variable|unused-variable)\)",
|
|
252
|
+
r"\d+ files? would be reformatted",
|
|
253
|
+
r"would reformat \S+\.py",
|
|
254
|
+
r"Imports are incorrectly sorted",
|
|
255
|
+
],
|
|
256
|
+
"reproduction_command": "ruff check . || flake8 .",
|
|
257
|
+
"minimal_repair_strategy": (
|
|
258
|
+
"Confirm a linter or formatter (ruff, flake8, pylint, black, or isort) failed rather "
|
|
259
|
+
"than the tests, then apply the reported fix only in the touched files and rerun the "
|
|
260
|
+
"same linter."
|
|
261
|
+
),
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"failure_class": "python_test_failure",
|
|
265
|
+
"likely_subsystem": "Python tests",
|
|
266
|
+
"patterns": [r"\bpytest\b", r"FAILED .*::", r"AssertionError", r"ModuleNotFoundError"],
|
|
267
|
+
"reproduction_command": "python -m pytest -q",
|
|
268
|
+
"minimal_repair_strategy": (
|
|
269
|
+
"Reproduce the failing test, patch the narrow behavior drift, and rerun the "
|
|
270
|
+
"focused pytest node before broad test runs."
|
|
271
|
+
),
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
"failure_class": "node_dependency_install",
|
|
275
|
+
"likely_subsystem": "Node package installation",
|
|
276
|
+
"patterns": [
|
|
277
|
+
r"npm ERR!",
|
|
278
|
+
r"npm error\b",
|
|
279
|
+
r"ERR_PNPM",
|
|
280
|
+
r"ERR_PNPM_NO_MATCHING_VERSION",
|
|
281
|
+
r"YN\d{4}",
|
|
282
|
+
r"lockfile",
|
|
283
|
+
r"peer dep",
|
|
284
|
+
r"\bERESOLVE\b",
|
|
285
|
+
r"unable to resolve dependency tree",
|
|
286
|
+
r"could not resolve dependency",
|
|
287
|
+
r"Conflicting peer dependency",
|
|
288
|
+
r"Fix the upstream dependency conflict",
|
|
289
|
+
r"npm ci can only install packages when your package\.json and package-lock\.json",
|
|
290
|
+
r"404 Not Found - GET https?://registry\.npmjs\.org",
|
|
291
|
+
r"is not in this registry",
|
|
292
|
+
r"yarn install v\d",
|
|
293
|
+
r"error An unexpected error occurred",
|
|
294
|
+
r"info Visit https://yarnpkg\.com",
|
|
295
|
+
],
|
|
296
|
+
"reproduction_command": "corepack pnpm install --frozen-lockfile || npm ci",
|
|
297
|
+
"minimal_repair_strategy": (
|
|
298
|
+
"Reconcile lockfile and package metadata without upgrading unrelated dependencies."
|
|
299
|
+
),
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
"failure_class": "typescript_typecheck",
|
|
303
|
+
"likely_subsystem": "TypeScript type checking",
|
|
304
|
+
"patterns": [
|
|
305
|
+
r"\bTS\d{4}\b",
|
|
306
|
+
r"\btsc\b",
|
|
307
|
+
r"tsc --noEmit",
|
|
308
|
+
r"vue-tsc --noEmit",
|
|
309
|
+
r"TSError: .* Unable to compile TypeScript",
|
|
310
|
+
r"Type '.*' is not assignable",
|
|
311
|
+
r"Cannot find name",
|
|
312
|
+
r"Property '.*' does not exist on type",
|
|
313
|
+
r"No overload matches this call",
|
|
314
|
+
r"Argument of type '.*' is not assignable to parameter of type",
|
|
315
|
+
r"Object is possibly '(?:null|undefined)'",
|
|
316
|
+
r"is declared but its value is never read",
|
|
317
|
+
r"tsc exited with code [1-9]",
|
|
318
|
+
r"Type checking failed",
|
|
319
|
+
],
|
|
320
|
+
"reproduction_command": "pnpm typecheck || npm run typecheck",
|
|
321
|
+
"minimal_repair_strategy": (
|
|
322
|
+
"Fix the smallest reported type mismatch, import drift, or schema mismatch and "
|
|
323
|
+
"rerun the targeted typecheck."
|
|
324
|
+
),
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
"failure_class": "javascript_lint",
|
|
328
|
+
"likely_subsystem": "JavaScript or TypeScript linting",
|
|
329
|
+
"patterns": [r"\beslint\b", r"\bbiome\b", r"lint failed", r"no-unused-vars", r"prettier"],
|
|
330
|
+
"reproduction_command": "pnpm lint || npm run lint",
|
|
331
|
+
"minimal_repair_strategy": "Apply the reported lint correction only in touched files.",
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
"failure_class": "github_actions_workflow",
|
|
335
|
+
"likely_subsystem": "GitHub Actions workflow wiring",
|
|
336
|
+
"patterns": [
|
|
337
|
+
r"Invalid workflow file",
|
|
338
|
+
r"\.github/workflows",
|
|
339
|
+
r"Unable to resolve action",
|
|
340
|
+
r"Resource not accessible by integration",
|
|
341
|
+
],
|
|
342
|
+
"reproduction_command": "gh workflow view <workflow> --yaml",
|
|
343
|
+
"minimal_repair_strategy": (
|
|
344
|
+
"Inspect workflow syntax, action versions, and permissions, then adjust only the "
|
|
345
|
+
"broken job or permission stanza."
|
|
346
|
+
),
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
"failure_class": "artifact_or_cache_failure",
|
|
350
|
+
"likely_subsystem": "GitHub Actions artifact or cache storage",
|
|
351
|
+
"patterns": [
|
|
352
|
+
r"Failed to CreateArtifact",
|
|
353
|
+
r"Artifact upload failed",
|
|
354
|
+
r"an artifact with this name already exists",
|
|
355
|
+
r"Unable to download artifact",
|
|
356
|
+
r"error occurred while (?:trying to )?download(?:ing)? (?:the )?artifact",
|
|
357
|
+
r"No files were found with the provided path",
|
|
358
|
+
r"Provided artifact name input during validation",
|
|
359
|
+
r"actions/(?:upload|download)-artifact",
|
|
360
|
+
r"Cache service responded with \d+",
|
|
361
|
+
r"Failed to restore:? .*[Cc]ache",
|
|
362
|
+
r"Failed to save:? .*[Cc]ache",
|
|
363
|
+
r"reserveCache failed",
|
|
364
|
+
r"Unable to reserve cache",
|
|
365
|
+
r"getCacheEntry failed",
|
|
366
|
+
r"Cache upload failed",
|
|
367
|
+
],
|
|
368
|
+
"reproduction_command": (
|
|
369
|
+
"re-run the job and inspect the failing actions/upload-artifact, "
|
|
370
|
+
"actions/download-artifact, or actions/cache step (paths, name, key, action version)"
|
|
371
|
+
),
|
|
372
|
+
"minimal_repair_strategy": (
|
|
373
|
+
"Confirm the failure is artifact or cache storage (wrong path, name collision, stale "
|
|
374
|
+
"action version, or a transient storage-service outage) rather than a code defect, "
|
|
375
|
+
"then fix the step's path/name/key inputs or bump the action version and retry — "
|
|
376
|
+
"do not change application code."
|
|
377
|
+
),
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
"failure_class": "release_publish_failure",
|
|
381
|
+
"likely_subsystem": "Package or release publishing",
|
|
382
|
+
"patterns": [
|
|
383
|
+
r"npm publish",
|
|
384
|
+
r"You cannot publish over the previously published versions?",
|
|
385
|
+
r"\bEPUBLISHCONFLICT\b",
|
|
386
|
+
r"\bENEEDAUTH\b",
|
|
387
|
+
r"npm error code E403",
|
|
388
|
+
r"403 Forbidden.*(?:upload|pypi|package)",
|
|
389
|
+
r"(?:upload|pypi|package).*403 Forbidden",
|
|
390
|
+
r"\btwine upload\b",
|
|
391
|
+
r"HTTPError: 400.*File already exists",
|
|
392
|
+
r"File already exists",
|
|
393
|
+
r"This filename has already been used",
|
|
394
|
+
r"cargo publish",
|
|
395
|
+
r"crate version .* is already uploaded",
|
|
396
|
+
r"is already uploaded",
|
|
397
|
+
r"the remote server responded with an error.*already exists",
|
|
398
|
+
r"gh release create",
|
|
399
|
+
r"a release with the same tag .* already exists",
|
|
400
|
+
r"Validation Failed.*already_exists",
|
|
401
|
+
r"already_exists",
|
|
402
|
+
],
|
|
403
|
+
"reproduction_command": (
|
|
404
|
+
"rerun the publish step locally with the same registry credentials "
|
|
405
|
+
"(e.g. npm publish --dry-run, twine upload, cargo publish --dry-run, "
|
|
406
|
+
"or gh release create)"
|
|
407
|
+
),
|
|
408
|
+
"minimal_repair_strategy": (
|
|
409
|
+
"Confirm the failure is a release or package publish conflict (a version/tag already "
|
|
410
|
+
"exists or the publish step lacked auth) rather than a build or test defect, then bump "
|
|
411
|
+
"the version, restore the missing publish credential, or skip the already-published "
|
|
412
|
+
"artifact before rerunning only the publish step."
|
|
413
|
+
),
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
"failure_class": "git_checkout_failure",
|
|
417
|
+
"likely_subsystem": "Git checkout, clone, or submodule fetch",
|
|
418
|
+
"patterns": [
|
|
419
|
+
r"fatal: could not read Username",
|
|
420
|
+
r"fatal: Authentication failed",
|
|
421
|
+
r"Repository not found",
|
|
422
|
+
r"fatal: repository '.*' not found",
|
|
423
|
+
r"fatal: clone of '.*' (?:into submodule path|failed)",
|
|
424
|
+
r"Fetched in submodule path",
|
|
425
|
+
r"Failed to (?:clone|fetch|recurse into) submodule",
|
|
426
|
+
r"git submodule",
|
|
427
|
+
r"git-lfs",
|
|
428
|
+
r"smudge filter lfs failed",
|
|
429
|
+
r"error downloading object",
|
|
430
|
+
r"reference is not a tree",
|
|
431
|
+
r"fatal: reference is not a tree",
|
|
432
|
+
r"error: pathspec '.*' did not match",
|
|
433
|
+
r"fatal: not a git repository",
|
|
434
|
+
r"actions/checkout",
|
|
435
|
+
],
|
|
436
|
+
"reproduction_command": (
|
|
437
|
+
"reproduce the checkout locally with the same ref and credentials "
|
|
438
|
+
"(e.g. git clone --recurse-submodules <repo> && git checkout <ref>)"
|
|
439
|
+
),
|
|
440
|
+
"minimal_repair_strategy": (
|
|
441
|
+
"Confirm the failure is a git checkout, clone, submodule, or LFS fetch problem rather "
|
|
442
|
+
"than a build or test defect, then fix the narrow ref, submodule URL, LFS pointer, or "
|
|
443
|
+
"checkout credential before rerunning only the checkout step."
|
|
444
|
+
),
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
"failure_class": "git_merge_conflict",
|
|
448
|
+
"likely_subsystem": "Git merge or rebase against the base branch",
|
|
449
|
+
"patterns": [
|
|
450
|
+
r"Automatic merge failed; fix conflicts and then commit",
|
|
451
|
+
r"CONFLICT \((?:content|add/add|rename|modify/delete|delete/modify|"
|
|
452
|
+
r"submodule)",
|
|
453
|
+
r"Merge conflict in ",
|
|
454
|
+
r"fix conflicts and then commit the result",
|
|
455
|
+
r"error: Merging is not possible because you have unmerged files",
|
|
456
|
+
r"fatal: You have not concluded your merge \(MERGE_HEAD exists\)",
|
|
457
|
+
r"\byou have unmerged paths\b",
|
|
458
|
+
r"\bUnmerged paths:",
|
|
459
|
+
r"\bneeds merge\b",
|
|
460
|
+
r"Resolve all conflicts manually",
|
|
461
|
+
r"error: could not apply [0-9a-f]+",
|
|
462
|
+
r"Resolve the conflicts before",
|
|
463
|
+
r"hint: after resolving the conflicts",
|
|
464
|
+
],
|
|
465
|
+
"reproduction_command": (
|
|
466
|
+
"merge or rebase the base branch locally to surface the conflict "
|
|
467
|
+
"(e.g. git fetch origin && git merge origin/<base>)"
|
|
468
|
+
),
|
|
469
|
+
"minimal_repair_strategy": (
|
|
470
|
+
"Confirm the failure is a merge or rebase conflict against the base branch rather than "
|
|
471
|
+
"a build or test defect, then resolve the conflicting files, commit the resolution, and "
|
|
472
|
+
"rerun the job on the updated branch."
|
|
473
|
+
),
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
"failure_class": "secrets_or_permissions_failure",
|
|
477
|
+
"likely_subsystem": "CI secrets, tokens, or workflow permissions",
|
|
478
|
+
"patterns": [
|
|
479
|
+
r"Resource not accessible by integration",
|
|
480
|
+
r"Error: Input required and not supplied",
|
|
481
|
+
r"Input required and not supplied",
|
|
482
|
+
r"is not set\b",
|
|
483
|
+
r"secret .* (?:is )?(?:not set|missing|empty|required)",
|
|
484
|
+
r"\$\{\{\s*secrets\.[A-Z0-9_]+\s*\}\}",
|
|
485
|
+
r"context access might be invalid",
|
|
486
|
+
r"Permission to .* denied to github-actions",
|
|
487
|
+
r"remote: Permission to .* denied",
|
|
488
|
+
r"refusing to allow a(?:n)? (?:GitHub App|OAuth App|integration) to create or "
|
|
489
|
+
r"update workflow",
|
|
490
|
+
r"without (?:the )?workflows? permission",
|
|
491
|
+
r"403.*write_packages",
|
|
492
|
+
r"insufficient (?:permission|scope|privileges)",
|
|
493
|
+
r"missing or insufficient permissions",
|
|
494
|
+
r"(?:token|app|integration) lacks the .*(?:permission|scope)",
|
|
495
|
+
r"lacks the .*(?:permission|scope)",
|
|
496
|
+
r"requires the .* permission",
|
|
497
|
+
r"\bpermissions:\b.*\bwrite\b",
|
|
498
|
+
],
|
|
499
|
+
"reproduction_command": (
|
|
500
|
+
"inspect the workflow permissions and required secrets "
|
|
501
|
+
"(e.g. gh secret list and the permissions: block in the workflow)"
|
|
502
|
+
),
|
|
503
|
+
"minimal_repair_strategy": (
|
|
504
|
+
"Confirm the failure is a missing secret, unset input, or insufficient workflow "
|
|
505
|
+
"permission rather than a code defect, then provision the missing secret or widen the "
|
|
506
|
+
"narrow permissions/token scope the failing step needs before rerunning it."
|
|
507
|
+
),
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
"failure_class": "security_scan_failure",
|
|
511
|
+
"likely_subsystem": "Security scanner or dependency audit",
|
|
512
|
+
"patterns": [
|
|
513
|
+
r"\bnpm audit\b",
|
|
514
|
+
r"\bpip-audit\b",
|
|
515
|
+
r"\bcargo audit\b",
|
|
516
|
+
r"\btrivy\b",
|
|
517
|
+
r"\bgosec\b",
|
|
518
|
+
r"\bsnyk\b",
|
|
519
|
+
r"\bsemgrep\b",
|
|
520
|
+
r"\bbandit\b",
|
|
521
|
+
r"CRITICAL: Vulnerability",
|
|
522
|
+
r"Found known vulnerabilities",
|
|
523
|
+
r"Vulnerabilities found",
|
|
524
|
+
r"High severity vulnerability",
|
|
525
|
+
r"\bCVE-\d{4}-\d{4,}\b",
|
|
526
|
+
r"\bGHSA-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}\b",
|
|
527
|
+
r"\bRUSTSEC-\d{4}-\d{4}\b",
|
|
528
|
+
r"Severity:\s+(?:HIGH|CRITICAL)",
|
|
529
|
+
r"Scan failed",
|
|
530
|
+
r"gosec found issues",
|
|
531
|
+
],
|
|
532
|
+
"reproduction_command": "rerun the failing security scan locally",
|
|
533
|
+
"minimal_repair_strategy": (
|
|
534
|
+
"Confirm the vulnerable package or finding, upgrade or patch the narrow affected "
|
|
535
|
+
"dependency/configuration, and rerun the same scanner before broad CI."
|
|
536
|
+
),
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
"failure_class": "dotnet_build_failure",
|
|
540
|
+
"likely_subsystem": ".NET restore, build, or test lifecycle",
|
|
541
|
+
"patterns": [
|
|
542
|
+
r"\bdotnet restore\b",
|
|
543
|
+
r"\bdotnet build\b",
|
|
544
|
+
r"\bdotnet test\b",
|
|
545
|
+
r"\bNU\d{4}\b",
|
|
546
|
+
r"\bCS\d{4}\b",
|
|
547
|
+
r"error NETSDK\d+",
|
|
548
|
+
r"package downgrade",
|
|
549
|
+
r"Version conflict detected",
|
|
550
|
+
r"Unable to resolve",
|
|
551
|
+
r"Xunit\.Sdk",
|
|
552
|
+
r"Failed! - Failed:",
|
|
553
|
+
r"Build FAILED",
|
|
554
|
+
],
|
|
555
|
+
"reproduction_command": "dotnet restore && dotnet test",
|
|
556
|
+
"minimal_repair_strategy": (
|
|
557
|
+
"Reproduce the failing dotnet restore, build, or test command, then fix the narrow "
|
|
558
|
+
"NuGet graph, target framework, compiler, or test assertion drift before rerunning it."
|
|
559
|
+
),
|
|
560
|
+
},
|
|
561
|
+
{
|
|
562
|
+
"failure_class": "java_build_failure",
|
|
563
|
+
"likely_subsystem": "Java build or test lifecycle",
|
|
564
|
+
"patterns": [
|
|
565
|
+
r"\bmvn\b",
|
|
566
|
+
r"\bgradle\b",
|
|
567
|
+
r"COMPILATION ERROR",
|
|
568
|
+
r"Failed to execute goal",
|
|
569
|
+
r"Execution failed for task",
|
|
570
|
+
r"Could not resolve all files",
|
|
571
|
+
r"Could not resolve dependencies",
|
|
572
|
+
r"Could not determine java version",
|
|
573
|
+
r"Unsupported class file major version",
|
|
574
|
+
r"No tests found for given includes",
|
|
575
|
+
r"BUILD FAILED",
|
|
576
|
+
r"cannot find symbol",
|
|
577
|
+
r"package .* does not exist",
|
|
578
|
+
],
|
|
579
|
+
"reproduction_command": "./gradlew test || mvn test",
|
|
580
|
+
"minimal_repair_strategy": (
|
|
581
|
+
"Reproduce the failing Maven or Gradle task, then fix the narrow dependency, "
|
|
582
|
+
"toolchain, compiler, or test-selection drift before rerunning the same task."
|
|
583
|
+
),
|
|
584
|
+
},
|
|
585
|
+
{
|
|
586
|
+
"failure_class": "docker_build_failure",
|
|
587
|
+
"likely_subsystem": "Container image build",
|
|
588
|
+
"patterns": [
|
|
589
|
+
r"\bdocker build\b",
|
|
590
|
+
r"\bdocker buildx build\b",
|
|
591
|
+
r"\bdocker compose\b",
|
|
592
|
+
r"failed to solve",
|
|
593
|
+
r"failed to compute cache key",
|
|
594
|
+
r"no such file or directory",
|
|
595
|
+
r"target stage .* could not be found",
|
|
596
|
+
r"service .* is unhealthy",
|
|
597
|
+
r"manifest .* not found",
|
|
598
|
+
],
|
|
599
|
+
"reproduction_command": "docker build .",
|
|
600
|
+
"minimal_repair_strategy": (
|
|
601
|
+
"Reproduce the failing image build locally, then fix the narrow Dockerfile, "
|
|
602
|
+
"build context, compose healthcheck, or base-image reference drift."
|
|
603
|
+
),
|
|
604
|
+
},
|
|
605
|
+
{
|
|
606
|
+
"failure_class": "cpp_build_failure",
|
|
607
|
+
"likely_subsystem": "C/C++ native build toolchain",
|
|
608
|
+
"patterns": [
|
|
609
|
+
r"CMake Error",
|
|
610
|
+
r"ninja: build stopped",
|
|
611
|
+
r"g?make(?:\[\d+\])?: \*\*\* \[[^\]]*\] Error \d+",
|
|
612
|
+
r"undefined reference to",
|
|
613
|
+
r"collect2: error: ld returned",
|
|
614
|
+
r"error: ld returned \d+ exit status",
|
|
615
|
+
r"fatal error: [^\s:]+\.(?:h|hpp|hxx): No such file or directory",
|
|
616
|
+
r"was not declared in this scope",
|
|
617
|
+
r"use of undeclared identifier",
|
|
618
|
+
r"clang(?:\+\+)?: error:",
|
|
619
|
+
r"\bcc1plus\b",
|
|
620
|
+
r"undefined symbols for architecture",
|
|
621
|
+
],
|
|
622
|
+
"reproduction_command": "cmake --build build || make",
|
|
623
|
+
"minimal_repair_strategy": (
|
|
624
|
+
"Reproduce the failing compile or link target, then fix the narrow drift "
|
|
625
|
+
"(missing header or include path, undeclared symbol, or linker reference) "
|
|
626
|
+
"before rerunning the same target."
|
|
627
|
+
),
|
|
628
|
+
},
|
|
629
|
+
{
|
|
630
|
+
"failure_class": "browser_test_failure",
|
|
631
|
+
"likely_subsystem": "Browser end-to-end tests",
|
|
632
|
+
"patterns": [
|
|
633
|
+
r"\bplaywright test\b",
|
|
634
|
+
r"\bcypress run\b",
|
|
635
|
+
r"browserType\.launch",
|
|
636
|
+
r"Executable doesn't exist",
|
|
637
|
+
r"Timeout \d+ms exceeded",
|
|
638
|
+
r"locator\(",
|
|
639
|
+
r"CypressError",
|
|
640
|
+
r"browser exited unexpectedly",
|
|
641
|
+
],
|
|
642
|
+
"reproduction_command": "npx playwright test || npx cypress run",
|
|
643
|
+
"minimal_repair_strategy": (
|
|
644
|
+
"Reproduce the browser test locally, install missing browsers if needed, "
|
|
645
|
+
"then patch the selector, fixture, or launch configuration causing the failure."
|
|
646
|
+
),
|
|
647
|
+
},
|
|
648
|
+
{
|
|
649
|
+
"failure_class": "rust_test_failure",
|
|
650
|
+
"likely_subsystem": "Rust tests",
|
|
651
|
+
"patterns": [
|
|
652
|
+
r"\bcargo test\b",
|
|
653
|
+
r"error\[E\d{4}\]",
|
|
654
|
+
r"thread '.*' panicked",
|
|
655
|
+
r"test result: FAILED",
|
|
656
|
+
],
|
|
657
|
+
"reproduction_command": "cargo test",
|
|
658
|
+
"minimal_repair_strategy": (
|
|
659
|
+
"Reproduce the failing crate or test target, patch the narrow Rust error, and "
|
|
660
|
+
"rerun cargo test for that crate."
|
|
661
|
+
),
|
|
662
|
+
},
|
|
663
|
+
{
|
|
664
|
+
"failure_class": "ruby_bundle_failure",
|
|
665
|
+
"likely_subsystem": "Ruby dependency installation or test lifecycle",
|
|
666
|
+
"patterns": [
|
|
667
|
+
r"\bbundle install\b",
|
|
668
|
+
r"\bbundle exec\b",
|
|
669
|
+
r"\bbundler\b",
|
|
670
|
+
r"Bundler could not find compatible versions",
|
|
671
|
+
r"Could not find gem",
|
|
672
|
+
r"Gem::Ext::BuildError",
|
|
673
|
+
r"An error occurred while installing",
|
|
674
|
+
r"Your bundle is locked to",
|
|
675
|
+
r"rake aborted!",
|
|
676
|
+
r"rspec .*failures?",
|
|
677
|
+
],
|
|
678
|
+
"reproduction_command": "bundle install && bundle exec rake test",
|
|
679
|
+
"minimal_repair_strategy": (
|
|
680
|
+
"Reproduce the failing Bundler, Rake, or RSpec command, then fix the narrow "
|
|
681
|
+
"Gemfile, lockfile, native extension, or test drift before rerunning it."
|
|
682
|
+
),
|
|
683
|
+
},
|
|
684
|
+
{
|
|
685
|
+
"failure_class": "php_composer_failure",
|
|
686
|
+
"likely_subsystem": "PHP Composer dependency installation or PHPUnit lifecycle",
|
|
687
|
+
"patterns": [
|
|
688
|
+
r"\bcomposer install\b",
|
|
689
|
+
r"\bcomposer update\b",
|
|
690
|
+
r"Your requirements could not be resolved to an installable set of packages",
|
|
691
|
+
r"requires php",
|
|
692
|
+
r"Problem \d+",
|
|
693
|
+
r"lock file is not up to date",
|
|
694
|
+
r"not present in the lock file",
|
|
695
|
+
r"\bvendor/bin/phpunit\b",
|
|
696
|
+
r"\bphpunit\b",
|
|
697
|
+
r"FAILURES!",
|
|
698
|
+
r"Tests: .*Failures?:",
|
|
699
|
+
r"Failed asserting",
|
|
700
|
+
r"Class .* not found",
|
|
701
|
+
],
|
|
702
|
+
"reproduction_command": "composer install && vendor/bin/phpunit",
|
|
703
|
+
"minimal_repair_strategy": (
|
|
704
|
+
"Reproduce the failing Composer or PHPUnit command, then fix the narrow "
|
|
705
|
+
"composer.json, lockfile, PHP platform, autoload, or test drift before rerunning it."
|
|
706
|
+
),
|
|
707
|
+
},
|
|
708
|
+
{
|
|
709
|
+
"failure_class": "go_test_failure",
|
|
710
|
+
"likely_subsystem": "Go tests",
|
|
711
|
+
"patterns": [r"\bgo test\b", r"FAIL\t", r"undefined:", r"panic: test timed out"],
|
|
712
|
+
"reproduction_command": "go test ./...",
|
|
713
|
+
"minimal_repair_strategy": (
|
|
714
|
+
"Run the failing package test and make the smallest compile or runtime fix in "
|
|
715
|
+
"that package."
|
|
716
|
+
),
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
"failure_class": "node_test_failure",
|
|
720
|
+
"likely_subsystem": "Node test runner (jest, vitest, or mocha)",
|
|
721
|
+
"patterns": [
|
|
722
|
+
r"\bjest\b",
|
|
723
|
+
r"\bvitest\b",
|
|
724
|
+
r"\bmocha\b",
|
|
725
|
+
r"\bjasmine\b",
|
|
726
|
+
r"jest --",
|
|
727
|
+
r"vitest run",
|
|
728
|
+
r"npx (?:jest|vitest|mocha)",
|
|
729
|
+
r"npm (?:run )?test",
|
|
730
|
+
r"Tests:\s+\d+ failed",
|
|
731
|
+
r"Test Suites:\s+\d+ failed",
|
|
732
|
+
r"\d+ failing",
|
|
733
|
+
r"\d+ passing",
|
|
734
|
+
r"^\s*FAIL\s+(?:src|test|tests|spec|__tests__)/",
|
|
735
|
+
r"\bFAIL\b .*\.(?:test|spec)\.(?:[jt]sx?)\b",
|
|
736
|
+
r"× .*\.(?:test|spec)\.(?:[jt]sx?)\b",
|
|
737
|
+
r"Expected:.*Received:",
|
|
738
|
+
r"expect\(.*\)\.to(?:Equal|Be|Match|Have)",
|
|
739
|
+
r"AssertionError \[ERR_ASSERTION\]",
|
|
740
|
+
r"toMatchSnapshot",
|
|
741
|
+
r"● .* > ",
|
|
742
|
+
],
|
|
743
|
+
"reproduction_command": "npx jest || npx vitest run || npx mocha",
|
|
744
|
+
"minimal_repair_strategy": (
|
|
745
|
+
"Confirm a Node unit-test runner (jest, vitest, or mocha) failed rather than a "
|
|
746
|
+
"browser end-to-end suite, then reproduce the failing spec, patch the narrow "
|
|
747
|
+
"assertion or behavior drift, and rerun that spec before the full suite."
|
|
748
|
+
),
|
|
749
|
+
},
|
|
750
|
+
{
|
|
751
|
+
"failure_class": "rust_lint",
|
|
752
|
+
"likely_subsystem": "Rust linting (clippy)",
|
|
753
|
+
"patterns": [
|
|
754
|
+
r"\bclippy\b",
|
|
755
|
+
r"cargo clippy",
|
|
756
|
+
r"error\[clippy::",
|
|
757
|
+
r"warning: clippy::",
|
|
758
|
+
r"could not compile due to clippy",
|
|
759
|
+
r"-D warnings",
|
|
760
|
+
r"unneeded `return` statement",
|
|
761
|
+
],
|
|
762
|
+
"reproduction_command": "cargo clippy --all-targets -- -D warnings",
|
|
763
|
+
"minimal_repair_strategy": (
|
|
764
|
+
"Confirm clippy failed rather than the tests, then apply the reported fix only in "
|
|
765
|
+
"the touched files and rerun cargo clippy."
|
|
766
|
+
),
|
|
767
|
+
},
|
|
768
|
+
{
|
|
769
|
+
"failure_class": "go_lint",
|
|
770
|
+
"likely_subsystem": "Go linting (golangci-lint)",
|
|
771
|
+
"patterns": [
|
|
772
|
+
r"\bgolangci-lint\b",
|
|
773
|
+
r"golangci-lint run",
|
|
774
|
+
r"\(gofmt\)",
|
|
775
|
+
r"\(govet\)",
|
|
776
|
+
r"\(staticcheck\)",
|
|
777
|
+
r"\(errcheck\)",
|
|
778
|
+
r"\(ineffassign\)",
|
|
779
|
+
r"\(gosimple\)",
|
|
780
|
+
r"\(revive\)",
|
|
781
|
+
r"\(unused\)\s*$",
|
|
782
|
+
r"^\s*\S+\.go:\d+:\d+: .* \(\w+\)\s*$",
|
|
783
|
+
],
|
|
784
|
+
"reproduction_command": "golangci-lint run ./...",
|
|
785
|
+
"minimal_repair_strategy": (
|
|
786
|
+
"Confirm golangci-lint failed rather than the tests, then apply the reported fix "
|
|
787
|
+
"only in the touched files and rerun golangci-lint."
|
|
788
|
+
),
|
|
789
|
+
},
|
|
790
|
+
{
|
|
791
|
+
"failure_class": "terraform_iac_failure",
|
|
792
|
+
"likely_subsystem": "Terraform/OpenTofu infrastructure-as-code plan, apply, or init",
|
|
793
|
+
"patterns": [
|
|
794
|
+
r"Error acquiring the state lock",
|
|
795
|
+
r"Error: Inconsistent dependency lock file",
|
|
796
|
+
r"Error: Failed to query available provider packages",
|
|
797
|
+
r"Error: Failed to install provider",
|
|
798
|
+
r"Error: Reference to undeclared (?:resource|input variable|local value|module)",
|
|
799
|
+
r"Error: Unsupported (?:argument|block type)",
|
|
800
|
+
r"Error: Invalid (?:value for|reference|resource type)",
|
|
801
|
+
r"Error: Module not installed",
|
|
802
|
+
r"Error: Provider configuration not present",
|
|
803
|
+
r"╷\s*\n\s*│\s*Error:",
|
|
804
|
+
r"\bterraform (?:init|plan|apply|validate|fmt)\b",
|
|
805
|
+
r"\bopentofu\b|\btofu (?:init|plan|apply)\b",
|
|
806
|
+
r"\bterragrunt\b",
|
|
807
|
+
r"Terraform planned the following actions, but then encountered a problem",
|
|
808
|
+
],
|
|
809
|
+
"reproduction_command": (
|
|
810
|
+
"run the failing stage locally against the same workspace "
|
|
811
|
+
"(e.g. terraform init && terraform validate && terraform plan)"
|
|
812
|
+
),
|
|
813
|
+
"minimal_repair_strategy": (
|
|
814
|
+
"Confirm the failure is a Terraform/IaC configuration or state issue rather than a "
|
|
815
|
+
"downstream provider outage, then fix the reported HCL argument, lock file, or provider "
|
|
816
|
+
"constraint (or release a stale state lock) and rerun plan before apply."
|
|
817
|
+
),
|
|
818
|
+
},
|
|
819
|
+
]
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
def _matching_signals(text: str, patterns: list[str]) -> list[str]:
|
|
823
|
+
return [
|
|
824
|
+
pattern
|
|
825
|
+
for pattern in patterns
|
|
826
|
+
if re.search(pattern, text, flags=re.IGNORECASE | re.MULTILINE)
|
|
827
|
+
]
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
def _requirements() -> dict[str, Any]:
|
|
831
|
+
return {
|
|
832
|
+
"billing_required": False,
|
|
833
|
+
"webhook_required_for_local_classification": False,
|
|
834
|
+
"github_app_required_for_local_classification": False,
|
|
835
|
+
"pr_creation_required": "no; write actions remain separate human-approved gates",
|
|
836
|
+
"external_model_required": False,
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
|
|
840
|
+
def redact_ci_log(text: str) -> dict[str, Any]:
|
|
841
|
+
redacted = text
|
|
842
|
+
counts: Counter[str] = Counter()
|
|
843
|
+
for name, pattern, replacement in REDACTION_PATTERNS:
|
|
844
|
+
redacted, count = re.subn(pattern, replacement, redacted, flags=re.IGNORECASE)
|
|
845
|
+
if count:
|
|
846
|
+
counts[name] += count
|
|
847
|
+
return {
|
|
848
|
+
"schema_version": "patchrail.redaction.v1",
|
|
849
|
+
"text": redacted,
|
|
850
|
+
"redactions": dict(sorted(counts.items())),
|
|
851
|
+
"local_only": True,
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
|
|
855
|
+
def classify_ci_log(text: str) -> dict[str, Any]:
|
|
856
|
+
best_rule: dict[str, Any] | None = None
|
|
857
|
+
best_signals: list[str] = []
|
|
858
|
+
for rule in RULES:
|
|
859
|
+
signals = _matching_signals(text, list(rule["patterns"]))
|
|
860
|
+
if len(signals) > len(best_signals):
|
|
861
|
+
best_rule = rule
|
|
862
|
+
best_signals = signals
|
|
863
|
+
|
|
864
|
+
if best_rule is None or not best_signals:
|
|
865
|
+
return {
|
|
866
|
+
"schema_version": "patchrail.ci_result.v1",
|
|
867
|
+
"failure_class": "unknown",
|
|
868
|
+
"likely_subsystem": "unknown",
|
|
869
|
+
"reproduction_command": "inspect CI log and run the failing job locally",
|
|
870
|
+
"minimal_repair_strategy": (
|
|
871
|
+
"Do not auto-repair until the failing subsystem is identified."
|
|
872
|
+
),
|
|
873
|
+
"confidence": 0.15,
|
|
874
|
+
"signals": [],
|
|
875
|
+
"requirements": _requirements(),
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
confidence = min(0.95, 0.35 + 0.18 * len(best_signals))
|
|
879
|
+
return {
|
|
880
|
+
"schema_version": "patchrail.ci_result.v1",
|
|
881
|
+
"failure_class": best_rule["failure_class"],
|
|
882
|
+
"likely_subsystem": best_rule["likely_subsystem"],
|
|
883
|
+
"reproduction_command": best_rule["reproduction_command"],
|
|
884
|
+
"minimal_repair_strategy": best_rule["minimal_repair_strategy"],
|
|
885
|
+
"confidence": round(confidence, 2),
|
|
886
|
+
"signals": best_signals,
|
|
887
|
+
"requirements": _requirements(),
|
|
888
|
+
}
|