claude-dev-env 2.0.2 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +1 -1
- package/hooks/blocking/CLAUDE.md +1 -0
- package/hooks/blocking/code_rules_shared.py +126 -47
- package/hooks/blocking/config/CLAUDE.md +2 -0
- package/hooks/blocking/config/verified_commit_context_constants.py +21 -0
- package/hooks/blocking/config/verified_commit_gate_output_constants.py +14 -0
- package/hooks/blocking/conftest.py +36 -30
- package/hooks/blocking/convergence_gate_blocker.py +76 -8
- package/hooks/blocking/plain_language_blocker.py +8 -0
- package/hooks/blocking/state_description_blocker.py +4 -1
- package/hooks/blocking/test_code_rules_shared.py +120 -20
- package/hooks/blocking/test_convergence_gate_blocker.py +146 -0
- package/hooks/blocking/test_plain_language_blocker.py +15 -0
- package/hooks/blocking/test_state_description_blocker.py +15 -0
- package/hooks/blocking/test_verified_commit_config_bootstrap.py +18 -0
- package/hooks/blocking/test_verified_commit_gate_additional_context.py +134 -0
- package/hooks/blocking/tests/test_verified_commit_gate.py +41 -0
- package/hooks/blocking/verified_commit_config_bootstrap.py +22 -10
- package/hooks/blocking/verified_commit_gate.py +113 -568
- package/hooks/blocking/verified_commit_gate_parts/CLAUDE.md +28 -0
- package/hooks/blocking/verified_commit_gate_parts/__init__.py +1 -0
- package/hooks/blocking/verified_commit_gate_parts/command_tokenization.py +174 -0
- package/hooks/blocking/verified_commit_gate_parts/deny_payload.py +53 -0
- package/hooks/blocking/verified_commit_gate_parts/deny_reason.py +80 -0
- package/hooks/blocking/verified_commit_gate_parts/directory_resolution.py +170 -0
- package/hooks/blocking/verified_commit_gate_parts/gated_invocations.py +205 -0
- package/hooks/blocking/verified_commit_gate_parts/tests/conftest.py +10 -0
- package/hooks/blocking/verified_commit_gate_parts/tests/test_command_tokenization.py +94 -0
- package/hooks/blocking/verified_commit_gate_parts/tests/test_deny_payload.py +17 -0
- package/hooks/blocking/verified_commit_gate_parts/tests/test_deny_reason.py +38 -0
- package/hooks/blocking/verified_commit_gate_parts/tests/test_directory_resolution.py +71 -0
- package/hooks/blocking/verified_commit_gate_parts/tests/test_gated_invocations.py +61 -0
- package/hooks/hooks_constants/CLAUDE.md +4 -1
- package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -0
- package/hooks/hooks_constants/convergence_gate_blocker_constants.py +36 -0
- package/hooks/hooks_constants/harness_scratchpad_constants.py +10 -9
- package/hooks/hooks_constants/mypy_integration_constants.py +16 -0
- package/hooks/validators/mypy_integration.py +145 -24
- package/hooks/validators/python_antipattern_checks.py +16 -0
- package/hooks/validators/run_all_validators.py +9 -3
- package/hooks/validators/test_mypy_integration.py +154 -0
- package/hooks/validators/test_python_antipattern_checks.py +112 -1
- package/hooks/validators/test_run_all_validators_pretooluse.py +16 -0
- package/package.json +1 -1
- package/rules/CLAUDE.md +1 -0
- package/rules/verified-commit-gate-skip.md +28 -0
- package/skills/_shared/pr-loop/CLAUDE.md +18 -13
- package/skills/_shared/pr-loop/portable-driver.md +150 -0
- package/skills/_shared/pr-loop/scripts/CLAUDE.md +3 -0
- package/skills/_shared/pr-loop/scripts/build_converge_task_list.py +310 -0
- package/skills/_shared/pr-loop/scripts/portable_converge_driver.py +1637 -0
- package/skills/_shared/pr-loop/scripts/select_converge_pacer.py +215 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +3 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/converge_task_list_constants.py +56 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/pacer_constants.py +47 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/portable_driver_constants.py +181 -0
- package/skills/_shared/pr-loop/scripts/test_build_converge_task_list.py +140 -0
- package/skills/_shared/pr-loop/scripts/test_portable_converge_driver.py +1119 -0
- package/skills/_shared/pr-loop/scripts/test_select_converge_pacer.py +207 -0
- package/skills/auditing-claude-config/CLAUDE.md +2 -1
- package/skills/auditing-claude-config/SKILL.md +114 -176
- package/skills/auditing-claude-config/reference/probe-hook.md +74 -0
- package/skills/autoconverge/CLAUDE.md +6 -3
- package/skills/autoconverge/SKILL.md +421 -346
- package/skills/autoconverge/reference/CLAUDE.md +1 -0
- package/skills/autoconverge/reference/convergence.md +5 -5
- package/skills/autoconverge/reference/copilot-findings.md +51 -0
- package/skills/autoconverge/reference/multi-pr.md +33 -2
- package/skills/autoconverge/reference/stop-conditions.md +9 -6
- package/skills/autoconverge/test_portable_pacer_gate.py +54 -0
- package/skills/closeout/SKILL.md +7 -9
- package/skills/copilot-finding-triage/SKILL.md +21 -11
- package/skills/copilot-review/CLAUDE.md +3 -2
- package/skills/copilot-review/SKILL.md +119 -155
- package/skills/copilot-review/templates/subagent-prompt.md +49 -0
- package/skills/fresh-branch/CLAUDE.md +6 -9
- package/skills/fresh-branch/SKILL.md +84 -33
- package/skills/fresh-branch/scripts/create_fresh_branch.py +445 -0
- package/skills/fresh-branch/scripts/fresh_branch_scripts_constants/__init__.py +1 -0
- package/skills/fresh-branch/scripts/fresh_branch_scripts_constants/fresh_branch_cli_constants.py +74 -0
- package/skills/fresh-branch/scripts/test_create_fresh_branch.py +670 -0
- package/skills/pr-converge/CLAUDE.md +4 -3
- package/skills/pr-converge/SKILL.md +469 -422
- package/skills/pr-converge/reference/CLAUDE.md +1 -0
- package/skills/pr-converge/reference/multi-pr-orchestration.md +5 -1
- package/skills/pr-converge/reference/per-tick.md +51 -24
- package/skills/pr-converge/reference/progress-checklist.md +168 -0
- package/skills/pr-converge/test_portable_pacer_gate.py +67 -0
- package/skills/pr-converge/test_step5_host_branch.py +8 -6
- package/skills/pr-converge/workflows/schedule-wakeup-loop.md +5 -3
- package/skills/pr-loop-cloud-transport/SKILL.md +1 -1
- package/skills/privacy-hygiene/SKILL.md +68 -115
- package/skills/privacy-hygiene/reference/sweep-procedure.md +62 -0
- package/skills/session-log/CLAUDE.md +2 -1
- package/skills/session-log/SKILL.md +4 -26
- package/skills/session-log/templates/frontmatter.md +40 -0
- package/skills/skill-builder/CLAUDE.md +8 -7
- package/skills/skill-builder/SKILL.md +26 -11
- package/skills/skill-builder/references/CLAUDE.md +3 -1
- package/skills/skill-builder/references/delegation-map.md +21 -12
- package/skills/skill-builder/references/description-field.md +9 -11
- package/skills/skill-builder/references/deterministic-elements.md +218 -0
- package/skills/skill-builder/references/self-audit-checklist.md +62 -45
- package/skills/skill-builder/references/skill-modularity.md +8 -9
- package/skills/skill-builder/templates/CLAUDE.md +2 -2
- package/skills/skill-builder/templates/gap-analysis.md +15 -0
- package/skills/skill-builder/workflows/CLAUDE.md +5 -5
- package/skills/skill-builder/workflows/improve-skill.md +18 -9
- package/skills/skill-builder/workflows/new-skill.md +23 -15
- package/skills/skill-builder/workflows/polish-skill.md +28 -21
|
@@ -1,422 +1,469 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: pr-converge
|
|
3
|
-
description: >-
|
|
4
|
-
Loops Cursor Bugbot, a code review, a bug audit, and Copilot on the current
|
|
5
|
-
PR, applying TDD fixes until all are clean on one HEAD. Use when the user says
|
|
6
|
-
'/pr-converge', 'drive PR to convergence', 'loop bugbot and bugteam', 'babysit
|
|
7
|
-
bugbot and bugteam', 'until both are clean', or 'converge this PR'.
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
# PR Converge
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
`
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
`
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
##
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
- **
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
- [ ] **Step
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
`
|
|
298
|
-
|
|
299
|
-
`
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
- [ ]
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
[
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
`
|
|
331
|
-
|
|
332
|
-
- [ ] **
|
|
333
|
-
→
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
- [ ] **
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
- [ ] **
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
`
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
-
|
|
375
|
-
`
|
|
376
|
-
|
|
377
|
-
- [ ] **
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
1
|
+
---
|
|
2
|
+
name: pr-converge
|
|
3
|
+
description: >-
|
|
4
|
+
Loops Cursor Bugbot, a code review, a bug audit, and Copilot on the current
|
|
5
|
+
PR, applying TDD fixes until all are clean on one HEAD. Use when the user says
|
|
6
|
+
'/pr-converge', 'drive PR to convergence', 'loop bugbot and bugteam', 'babysit
|
|
7
|
+
bugbot and bugteam', 'until both are clean', or 'converge this PR'.
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# PR Converge
|
|
11
|
+
|
|
12
|
+
A code-review ↔ bugteam ↔ Bugbot ↔ Copilot loop on a draft PR: the internal
|
|
13
|
+
code-review and bugteam passes drive the code to clean first, then Cursor
|
|
14
|
+
Bugbot and Copilot run as terminal confirmation gates, until all are clean on
|
|
15
|
+
the same `HEAD` and mergeable. On `pacer=schedule_wakeup`, one tick runs per
|
|
16
|
+
invocation and the next tick is scheduled. On `pacer=portable`, ticks run
|
|
17
|
+
continuously in-session (see
|
|
18
|
+
[`../_shared/pr-loop/portable-driver.md`](../_shared/pr-loop/portable-driver.md)).
|
|
19
|
+
|
|
20
|
+
## Transport check (before any GitHub step)
|
|
21
|
+
|
|
22
|
+
Run `command -v gh`; when it succeeds, run `gh auth status`; once the PR
|
|
23
|
+
scope is resolved, run `gh api repos/<owner>/<repo> --jq .permissions.push`
|
|
24
|
+
and take `true` as the pass. When any check fails, run the
|
|
25
|
+
`pr-loop-cloud-transport` skill first and route every `gh` operation in this
|
|
26
|
+
skill through its substitution matrix.
|
|
27
|
+
|
|
28
|
+
## Pre-flight
|
|
29
|
+
|
|
30
|
+
### Task list (step 1)
|
|
31
|
+
|
|
32
|
+
After down/opt-out flags are known, build the work list with
|
|
33
|
+
`build_converge_task_list.py` only (same script as autoconverge). Register every
|
|
34
|
+
task; **final task** is always `all_runnable_reviews_clean_same_head`. Complete
|
|
35
|
+
that final task only when every runnable review is CLEAN on the same HEAD.
|
|
36
|
+
On `pacer=portable`, `open-run` returns the same list.
|
|
37
|
+
|
|
38
|
+
### Pacer selection
|
|
39
|
+
|
|
40
|
+
Scan the tool list for `ScheduleWakeup`. Record whether it is present, then
|
|
41
|
+
select the pacer:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
python "$HOME/.claude/skills/_shared/pr-loop/scripts/select_converge_pacer.py" \
|
|
45
|
+
--skill pr-converge \
|
|
46
|
+
--has-workflow <0|1> \
|
|
47
|
+
--has-schedule-wakeup <0|1>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- `pacer=schedule_wakeup` — native tick pacing via `ScheduleWakeup` (see
|
|
51
|
+
[`workflows/schedule-wakeup-loop.md`](workflows/schedule-wakeup-loop.md)).
|
|
52
|
+
- `pacer=portable` — continuous in-session driver on
|
|
53
|
+
[`../_shared/pr-loop/portable-driver.md`](../_shared/pr-loop/portable-driver.md).
|
|
54
|
+
**Do not abort** because `ScheduleWakeup` is missing.
|
|
55
|
+
|
|
56
|
+
### Worktree isolation
|
|
57
|
+
|
|
58
|
+
When the tool list includes `EnterWorktree`, call it with no arguments before
|
|
59
|
+
any API call, file read, or edit. Agent-view sessions start in the shared
|
|
60
|
+
checkout; Bash (`gh`, `git`) does not auto-isolate. Do not proceed until the
|
|
61
|
+
working directory contains `.claude/worktrees/`. If `EnterWorktree` fails,
|
|
62
|
+
report the failure and stop.
|
|
63
|
+
|
|
64
|
+
When `EnterWorktree` is absent, isolate with git worktree machinery per
|
|
65
|
+
[`../_shared/pr-loop/portable-driver.md`](../_shared/pr-loop/portable-driver.md)
|
|
66
|
+
§ Isolation and worktree, then run strict
|
|
67
|
+
`preflight_worktree.py` for the PR's owner/repo. Fail closed only when the
|
|
68
|
+
checkout is not the PR's repo on the PR head ref.
|
|
69
|
+
|
|
70
|
+
`EnterWorktree` (or the portable worktree path) isolates the session repo.
|
|
71
|
+
When the PR lives in a different repo, Step 1.5 routes the working directory
|
|
72
|
+
into a **PR worktree** of that repo on its head branch (routine, never a
|
|
73
|
+
pause). See [`reference/per-tick.md` § Step 1.5](reference/per-tick.md).
|
|
74
|
+
|
|
75
|
+
## Resume from a prior run
|
|
76
|
+
|
|
77
|
+
Before Step 0, check
|
|
78
|
+
`~/.claude/runtime/pr-loop/bugteam-pr-<PR number>/handoff.json`. When
|
|
79
|
+
`$CLAUDE_JOB_DIR/pr-converge-state.json` is absent but that handoff exists, seed
|
|
80
|
+
`phase`, `tick_count`, and the clean-at SHAs from the run's `state-copy.json`, so
|
|
81
|
+
a fresh session continues where the last one stopped rather than restarting at
|
|
82
|
+
CODE_REVIEW.
|
|
83
|
+
|
|
84
|
+
## Copilot quota pre-check (start of run)
|
|
85
|
+
|
|
86
|
+
On the first tick, apply the `reviewer-gates` skill's Copilot quota gate
|
|
87
|
+
(`../reviewer-gates/SKILL.md` § Gate 2) — once per run, never per tick. The
|
|
88
|
+
flag lives in `pr-converge-state.json` as `copilot_down`, and every tick reads
|
|
89
|
+
it. While `copilot_down` is true, the tick skips all Copilot work — no fetch,
|
|
90
|
+
no request, no poll, no agent — and exports
|
|
91
|
+
`CLAUDE_REVIEWS_DISABLED="copilot"` in that tick's shell before
|
|
92
|
+
`check_convergence.py`, so the check bypasses the Copilot review gate and the
|
|
93
|
+
pending-requested-reviews gate and the run still marks ready on the remaining
|
|
94
|
+
signals.
|
|
95
|
+
|
|
96
|
+
## Copilot findings — tier, verify, then route
|
|
97
|
+
|
|
98
|
+
Tier, verify, and route each Copilot finding via
|
|
99
|
+
[`copilot-finding-triage`](../copilot-finding-triage/SKILL.md) (self-healing
|
|
100
|
+
auto-fix; code-concern verify then confirmed / refuted / inconclusive).
|
|
101
|
+
|
|
102
|
+
**pr-converge phase routing after triage:**
|
|
103
|
+
|
|
104
|
+
- Self-healing and **confirmed** findings join the fix tick on `current_head`;
|
|
105
|
+
after push, reset clean-at SHAs, set `phase = CODE_REVIEW`, return to Step 5.
|
|
106
|
+
- **Refuted** findings resolve clean on the thread; no phase change.
|
|
107
|
+
- One or more **inconclusive** findings: do not mark ready. Page via the
|
|
108
|
+
triage skill's ntfy step, then hold by pacer:
|
|
109
|
+
- **`pacer=schedule_wakeup`** — triage user gate (`ScheduleWakeup` /
|
|
110
|
+
`send_later` 45-minute hold across ticks; persist the deadline so each tick
|
|
111
|
+
reads it on entry).
|
|
112
|
+
- **`pacer=portable`** — in-session deadline poll or handoff per
|
|
113
|
+
[`../_shared/pr-loop/portable-driver.md`](../_shared/pr-loop/portable-driver.md);
|
|
114
|
+
never `ScheduleWakeup` or `send_later`.
|
|
115
|
+
Act on the user's direction inside the window; on timeout, teardown and report
|
|
116
|
+
the findings un-reviewed.
|
|
117
|
+
- Enter `COPILOT_WAIT` only from gate (d) after requesting a Copilot review
|
|
118
|
+
(Step 7 → 7a). Stay on `COPILOT_WAIT` until a review surfaces at
|
|
119
|
+
`current_head`, `copilot_wait_count >= 3` hard-blocks, or `copilot_down`
|
|
120
|
+
skips the Copilot path entirely.
|
|
121
|
+
|
|
122
|
+
## Budget-aware tick boundaries
|
|
123
|
+
|
|
124
|
+
Before starting any tick, estimate whether the remaining session/usage
|
|
125
|
+
budget covers one full clean tick (worst case: a BUGBOT fetch + a
|
|
126
|
+
full-diff CODE_REVIEW + a fix commit + replies). If it does not, do not
|
|
127
|
+
start the tick. Stop at the current tick boundary: write updated state to
|
|
128
|
+
`$CLAUDE_JOB_DIR/pr-converge-state.json`, write the durable handoff (see
|
|
129
|
+
[State persistence](#state-persistence)), then report the exact resume
|
|
130
|
+
command (`/pr-converge <PR URL>`) and the persisted `phase`/`tick_count`.
|
|
131
|
+
A tick cut off mid-flight poisons the resume state — clean SHAs recorded
|
|
132
|
+
against work that never landed — so an unstarted tick is always cheaper
|
|
133
|
+
than a half-finished one.
|
|
134
|
+
|
|
135
|
+
## Findings discipline
|
|
136
|
+
|
|
137
|
+
Every finding, reply, and report states verified facts only — no hedging
|
|
138
|
+
language (`likely`, `probably`, `should`, `appears to`). Verify each
|
|
139
|
+
claim against the code on `current_head` before stating it; the
|
|
140
|
+
anti-hallucination Stop hook rejects hedged output, forcing a rework
|
|
141
|
+
pass. A claim that cannot be verified is reported as unverified, not
|
|
142
|
+
softened.
|
|
143
|
+
|
|
144
|
+
## State persistence
|
|
145
|
+
|
|
146
|
+
Single-PR mode persists loop state to `$CLAUDE_JOB_DIR/pr-converge-state.json`.
|
|
147
|
+
On tick entry, read this file if it exists to restore phase, tick_count, and
|
|
148
|
+
clean-at SHAs. On tick exit, write updated state before the next pacer step
|
|
149
|
+
(`ScheduleWakeup` when `pacer=schedule_wakeup`; continuous continue or
|
|
150
|
+
in-session poll when `pacer=portable`) so the next tick resumes with accurate
|
|
151
|
+
state.
|
|
152
|
+
|
|
153
|
+
After the state write and before the next pacer step, write the durable handoff
|
|
154
|
+
so a fresh session in a new job can resume this run:
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
python "$HOME/.claude/skills/_shared/pr-loop/scripts/write_handoff.py" \
|
|
158
|
+
--pr-number <N> --head-ref <branch> --phase <phase> \
|
|
159
|
+
--resume-command "/pr-converge <PR URL>" \
|
|
160
|
+
--state-file "$CLAUDE_JOB_DIR/pr-converge-state.json" \
|
|
161
|
+
--completed-steps "<clean phases this run>"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
It writes `handoff.json`, `HANDOFF.md`, and `state-copy.json` under
|
|
165
|
+
`~/.claude/runtime/pr-loop/<run-name>/`. The job-dir state stays the source of
|
|
166
|
+
truth for a resumed tick; the handoff copy is the pointer a fresh session reads
|
|
167
|
+
when `$CLAUDE_JOB_DIR` is gone.
|
|
168
|
+
|
|
169
|
+
Fields: `phase`, `tick_count`, `bugbot_clean_at`, `code_review_clean_at`,
|
|
170
|
+
`bugteam_clean_at`, `copilot_clean_at`, `merge_state_status`, `current_head`,
|
|
171
|
+
`bugbot_acknowledged_at`, `bugbot_down`, `copilot_down`,
|
|
172
|
+
`bugteam_skill_invoked_at_head`, `bugteam_skill_invoked_at_tick`,
|
|
173
|
+
`agents_session_id`, `persistent_agents`.
|
|
174
|
+
|
|
175
|
+
## Persistent per-step agents
|
|
176
|
+
|
|
177
|
+
Three step-scoped agents persist across ticks so their context carries
|
|
178
|
+
forward: `fix_executor`, `thread_sweep`, and `copilot_watch`, recorded in
|
|
179
|
+
the `persistent_agents` map
|
|
180
|
+
([`reference/state-schema.md`](reference/state-schema.md)).
|
|
181
|
+
|
|
182
|
+
- **Resume:** read `persistent_agents.<key>`. When an entry exists,
|
|
183
|
+
`SendMessage` to the stored `agent_id` with a tick payload that restates
|
|
184
|
+
the PR scope, `current_head`, the PR worktree path, this tick's findings
|
|
185
|
+
or threads, and the report-back contract. Bump `last_used_tick`, then
|
|
186
|
+
await completion.
|
|
187
|
+
- **First spawn:** `Agent(subagent_type: "clean-coder", name:
|
|
188
|
+
"prc-fix-<PR#>")` — the `name` makes the agent a persistent teammate
|
|
189
|
+
that idles awaiting messages. Record `{agent_id, created_tick,
|
|
190
|
+
last_used_tick}` under the step key. Keep the spawn prompt fix-shaped,
|
|
191
|
+
never audit-shaped: the `pr_converge_bugteam_enforcer` hook blocks
|
|
192
|
+
audit-shaped clean-coder spawns during the BUGTEAM phase.
|
|
193
|
+
- **Stale or dead id:** on a `SendMessage` failure, or no acknowledgment
|
|
194
|
+
within one bounded wait, drop the map entry, spawn a fresh named agent,
|
|
195
|
+
record it, and continue the tick. Never abort a tick on a stale id;
|
|
196
|
+
never retry the same dead id.
|
|
197
|
+
- **Fresh every round (never persisted):** the Step 5 host-aware
|
|
198
|
+
`invoke_code_review.py` / `/code-review high --fix` pass and the Step 6
|
|
199
|
+
bugteam audit (unbiased eyes each round; the enforcer needs the formal
|
|
200
|
+
Skill call), and every `code-verifier` — a named code-verifier never fires
|
|
201
|
+
`SubagentStop`, so no verdict mints (see the named-`code-verifier` entry
|
|
202
|
+
in the Gotchas list below).
|
|
203
|
+
- **Shutdown:** at loop end (convergence or a stop condition), send each
|
|
204
|
+
persistent agent a shutdown request and clear `persistent_agents` before
|
|
205
|
+
the `pr-loop-lifecycle` Close.
|
|
206
|
+
|
|
207
|
+
## Gotchas
|
|
208
|
+
|
|
209
|
+
Highest-signal content. Append a bullet each time a tick fails in a new
|
|
210
|
+
way — these are the hard-won lessons that keep the loop honest. Once this
|
|
211
|
+
grows to 5 or more items, suggest spinning up a subagent to investigate, fix,
|
|
212
|
+
post a fresh PR in a fresh branch based on origin main to the user.
|
|
213
|
+
|
|
214
|
+
- **`ScheduleWakeup` not in subagent tool registries** — background
|
|
215
|
+
`general-purpose` tick cannot schedule re-entry; only the parent session
|
|
216
|
+
with `ScheduleWakeup` (or the portable continuous driver on the parent)
|
|
217
|
+
may pace the next tick.
|
|
218
|
+
- **Portable host has no durable wake outside the session** — when
|
|
219
|
+
`pacer=portable`, budget and context bound how many ticks complete; write
|
|
220
|
+
handoff at a tick boundary and resume with `/pr-converge <PR URL>`.
|
|
221
|
+
- **`state.json` without §Concurrency lock loses merges** when teammates
|
|
222
|
+
finish in same wall-clock window.
|
|
223
|
+
- **`tick_count` must not double-increment** — conversation state line
|
|
224
|
+
only when **no** `state.json`; with `state.json`, only the
|
|
225
|
+
orchestrator bump increments.
|
|
226
|
+
- **Bugbot trigger and detection** — CI check-run based. Full flow at
|
|
227
|
+
[`per-tick.md` Step 3](reference/per-tick.md); see also
|
|
228
|
+
`~/.claude/skills/pr-converge/scripts/check_bugbot_ci.py --help`.
|
|
229
|
+
- **Bot login fields differ by endpoint** — `get_reviews` returns
|
|
230
|
+
`.user.login` (object), but `get_review_comments` returns `.author`
|
|
231
|
+
(string, not an object). Always check the correct fields and use
|
|
232
|
+
case-insensitive substring matching on login values, never strict
|
|
233
|
+
equality.
|
|
234
|
+
- **`isOutdated` has dual scope** — GitHub marks a thread `isOutdated=true`
|
|
235
|
+
when the line it anchors to has changed since the comment was posted. The
|
|
236
|
+
machine gate (`check_convergence.py` / [convergence-gates.md](reference/convergence-gates.md)
|
|
237
|
+
gate (e)) excludes `isOutdated == true` bot threads from the fail count —
|
|
238
|
+
only non-outdated unresolved bot threads fail the gate. The agent-side
|
|
239
|
+
unresolved-thread sweep in the shared fix protocol
|
|
240
|
+
([`../../_shared/pr-loop/fix-protocol.md`](../../_shared/pr-loop/fix-protocol.md)
|
|
241
|
+
step 12; skill deltas in [`reference/fix-protocol.md`](reference/fix-protocol.md))
|
|
242
|
+
still verifies outdated unresolved threads against HEAD before resolve when
|
|
243
|
+
the protocol requires it (the original concern can still apply when the fix
|
|
244
|
+
moved rather than landed).
|
|
245
|
+
- **Tilde paths fail on Windows Git Bash** — `~/.claude/skills/...`
|
|
246
|
+
resolves to the wrong home directory in Bash-tool contexts. Use
|
|
247
|
+
`$HOME/.claude/skills/...` in shell invocations or `Path.home() /
|
|
248
|
+
".claude/skills/..."` in Python scripts. Script invocations through
|
|
249
|
+
Bash that reference `~` produce "file not found" errors
|
|
250
|
+
indistinguishable from actual script failures.
|
|
251
|
+
- **PowerShell cmdlets fail in Bash tool** — `.ps1` scripts and
|
|
252
|
+
`pwsh` calls run through the PowerShell tool, not Bash. Bash on
|
|
253
|
+
Windows is Git Bash which cannot execute PowerShell cmdlets. Route all
|
|
254
|
+
PowerShell work through the PowerShell tool or `pwsh -NoProfile -File`.
|
|
255
|
+
- **Cross-repo PR: route cwd into the PR worktree before Step 5 review** —
|
|
256
|
+
`invoke_code_review.py` and `/code-review high --fix` audit the repo of the
|
|
257
|
+
cwd (the helper's `--cwd`). When the session is rooted in a different repo
|
|
258
|
+
than the PR, `EnterWorktree` cannot re-root (it is scoped to the session's
|
|
259
|
+
repo); resolve the PR worktree and `cd` into it per
|
|
260
|
+
[Step 1.5](reference/per-tick.md). Skipping this reviews and edits the
|
|
261
|
+
wrong repo. The route is routine and automatic — never a material fork
|
|
262
|
+
to pause on.
|
|
263
|
+
- **A named/teammate `code-verifier` never mints a verdict** — In a background-job session, an `Agent`-tool `code-verifier` spawned with a `name` (or otherwise as a persistent teammate) goes idle/"available" awaiting messages rather than terminating, so its `SubagentStop` never fires. `verifier_verdict_minter.py` mints the verdict only on `SubagentStop`, so no verdict file is written and `verified_commit_gate` blocks the `git commit`/`git push` with "no passing verification verdict" even though the verifier emitted `all_pass`. A `shutdown_request` is ignored and `TaskStop` cannot resolve the teammate's id. Spawn the code-verifier as a one-shot agent with NO `name` (a plain async `Agent` call) so it runs to completion and fires `SubagentStop`, minting the verdict bound to the live surface. Keep the work tree frozen between verification and the commit so the minted surface hash still matches.
|
|
264
|
+
|
|
265
|
+
## Progress checklist
|
|
266
|
+
|
|
267
|
+
State variables (`phase`, `bugbot_clean_at`, `code_review_clean_at`,
|
|
268
|
+
`bugteam_clean_at`, `copilot_clean_at`, `merge_state_status`, counters) are
|
|
269
|
+
defined in [`reference/state-schema.md`](reference/state-schema.md). Ground rules
|
|
270
|
+
in [`reference/ground-rules.md`](reference/ground-rules.md).
|
|
271
|
+
|
|
272
|
+
Each step references its spoke file for full procedural detail — MCP calls,
|
|
273
|
+
script invocations, decision criteria. Every "return to Step N" means the next
|
|
274
|
+
tick starts fresh from that step.
|
|
275
|
+
|
|
276
|
+
**Hard gate: do not advance from any step while ANY unresolved review
|
|
277
|
+
thread exists on the PR.** Sweep semantics and per-thread handling live in
|
|
278
|
+
the shared fix protocol
|
|
279
|
+
([`../../_shared/pr-loop/fix-protocol.md`](../../_shared/pr-loop/fix-protocol.md)
|
|
280
|
+
step 12; skill deltas in [`reference/fix-protocol.md`](reference/fix-protocol.md)).
|
|
281
|
+
|
|
282
|
+
**Full-PR-diff rule: every CODE-REVIEW round (Step 5) and every BUGTEAM
|
|
283
|
+
round (Step 6) covers the FULL `origin/main...HEAD` diff — every file
|
|
284
|
+
the PR touches.** A round that scopes to a subset — only the last commit,
|
|
285
|
+
only files touched since the prior clean SHA, only bugbot-flagged paths,
|
|
286
|
+
or any other delta cut — does not satisfy the gate, and a "clean" verdict
|
|
287
|
+
against a partial diff is not a valid clean. Re-run the round against the
|
|
288
|
+
full diff before recording `code_review_clean_at` or treating the bugteam
|
|
289
|
+
round as converged. This rule holds every tick, every loop, every PR.
|
|
290
|
+
|
|
291
|
+
- [ ] **Step 0: Open the run**
|
|
292
|
+
Apply the `pr-loop-lifecycle` skill's Open section
|
|
293
|
+
(`../pr-loop-lifecycle/SKILL.md`): permission grant + worktree preflight.
|
|
294
|
+
|
|
295
|
+
- [ ] **Step 1: Resolve PR scope + PR worktree**
|
|
296
|
+
Apply Step 1.5 scope resolution in
|
|
297
|
+
[`reference/per-tick.md`](reference/per-tick.md). Resolve the **PR
|
|
298
|
+
worktree** — the local checkout every local step this tick targets:
|
|
299
|
+
the `EnterWorktree` checkout when the PR shares the session's repo,
|
|
300
|
+
else a checkout of the PR's repo that the working directory routes
|
|
301
|
+
into via `cd`. Cross-repo routing is automatic, not a fork.
|
|
302
|
+
See: [`reference/per-tick.md` § Step 1](reference/per-tick.md)
|
|
303
|
+
and [§ Step 1.5](reference/per-tick.md)
|
|
304
|
+
|
|
305
|
+
- [ ] **Step 2: Initialize loop state**
|
|
306
|
+
`phase = CODE_REVIEW`; all counters at zero; `run_name` resolved.
|
|
307
|
+
|
|
308
|
+
- [ ] **Step 3: Mergeability check**
|
|
309
|
+
See: [`reference/convergence-gates.md` § (c)](reference/convergence-gates.md)
|
|
310
|
+
|
|
311
|
+
```
|
|
312
|
+
pull_request_read(method="get") → .mergeable_state, .mergeable
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
- [ ] mergeable → advance to Step 4
|
|
316
|
+
- [ ] not mergeable → rebase → force-push → return to Step 1
|
|
317
|
+
|
|
318
|
+
- [ ] **Step 4: BUGBOT — terminal Bugbot confirmation gate**
|
|
319
|
+
Step 6 routes here after BUGTEAM converges. Bugbot confirms code the
|
|
320
|
+
internal passes already drove to clean.
|
|
321
|
+
See: [`reference/per-tick.md` § BUGBOT terminal gate + Step 3](reference/per-tick.md);
|
|
322
|
+
availability and trigger via `reviewer-gates`
|
|
323
|
+
(`../reviewer-gates/SKILL.md` § Gate 1 / Gate 3).
|
|
324
|
+
|
|
325
|
+
- [ ] **disabled / down** → `bugbot_down = true` → Step 7
|
|
326
|
+
- [ ] **dirty on `current_head`** → apply shared fix protocol
|
|
327
|
+
([`../../_shared/pr-loop/fix-protocol.md`](../../_shared/pr-loop/fix-protocol.md);
|
|
328
|
+
skill deltas in [`reference/fix-protocol.md`](reference/fix-protocol.md))
|
|
329
|
+
→ push → reset push-invalidated markers → `phase = CODE_REVIEW` → Step 5
|
|
330
|
+
- [ ] **clean on `current_head`** → zero unresolved threads (else fix + resolve first)
|
|
331
|
+
→ `bugbot_clean_at = current_head` → Step 7
|
|
332
|
+
- [ ] **no review / commit_id mismatch** → `reviewer-gates` Bugbot flow (Gate 3):
|
|
333
|
+
silent pass → stamp + Step 7; queued/triggered → ScheduleWakeup 360s or portable in-session poll → Step 4;
|
|
334
|
+
down → `bugbot_down = true` → Step 7
|
|
335
|
+
|
|
336
|
+
- [ ] **Step 5: CODE-REVIEW — static sweep, review, fix, advance**
|
|
337
|
+
Entry phase every tick; re-entered after any fix push.
|
|
338
|
+
See: [`reference/per-tick.md` § CODE_REVIEW entry](reference/per-tick.md).
|
|
339
|
+
Pre-condition: cwd is the Step 1.5 PR worktree on `current_head`.
|
|
340
|
+
Scope: FULL `origin/main...HEAD` diff every tick (no path args, no delta cut).
|
|
341
|
+
Review always runs at effort high on model opus through
|
|
342
|
+
`invoke_code_review.py`. Mode decision inputs: host profile + session
|
|
343
|
+
model. Call:
|
|
344
|
+
`python "$HOME/.claude/scripts/invoke_code_review.py" --cwd <PR-worktree>
|
|
345
|
+
--session-model <alias>`. Chain mode uses that cwd and empty stdin; the
|
|
346
|
+
chain process never commits and never pushes. JSON stdout carries
|
|
347
|
+
`mode` (`in_session` | `chain`), `served_command`, `returncode`, and
|
|
348
|
+
`dirty_tree`. Config/host errors still emit that JSON with non-zero
|
|
349
|
+
`returncode` (no traceback-only failure).
|
|
350
|
+
|
|
351
|
+
- [ ] **Static sweep fails** → apply shared fix protocol → push → reset markers
|
|
352
|
+
→ stay CODE_REVIEW → Step 5
|
|
353
|
+
- [ ] **`mode == in_session`** (Claude host, session model opus) → run
|
|
354
|
+
`/code-review high --fix` in-session (no path args)
|
|
355
|
+
- [ ] **`mode == chain`** (any other host or non-opus session) → helper
|
|
356
|
+
already ran the headless review; read `returncode`,
|
|
357
|
+
`served_command`, and `dirty_tree` from JSON
|
|
358
|
+
- [ ] **failed review** (`returncode != 0`, or chain with null
|
|
359
|
+
`served_command`) → do not set `code_review_clean_at` → stay
|
|
360
|
+
CODE_REVIEW → Step 5
|
|
361
|
+
- [ ] **fixes applied** (`dirty_tree` true / working tree dirty) →
|
|
362
|
+
commit + push via shared fix protocol → reset markers → stay
|
|
363
|
+
CODE_REVIEW → Step 5
|
|
364
|
+
- [ ] **clean** (successful serve: `returncode == 0`, chain
|
|
365
|
+
`served_command` non-null when chain, and `dirty_tree` false) →
|
|
366
|
+
zero unresolved threads (else fix + resolve) →
|
|
367
|
+
`code_review_clean_at = current_head` → `phase = BUGTEAM` → Step 6
|
|
368
|
+
|
|
369
|
+
- [ ] **Step 6: BUGTEAM — run, decide, fix, reply, resolve**
|
|
370
|
+
See: [`reference/per-tick.md` § Step 2 BUGTEAM](reference/per-tick.md);
|
|
371
|
+
[`../bugteam/SKILL.md`](../bugteam/SKILL.md).
|
|
372
|
+
Pre-condition: `code_review_clean_at == current_head`.
|
|
373
|
+
Mandatory: `Skill({skill: "bugteam", args: "<PR URL>"})` this tick
|
|
374
|
+
(enforcer-blocked otherwise; `qbug` is not a substitute). Scope: FULL
|
|
375
|
+
`origin/main...HEAD` diff. Re-resolve HEAD after bugteam.
|
|
376
|
+
|
|
377
|
+
- [ ] **bugteam pushed** → verify threads replied + resolved → reset markers
|
|
378
|
+
→ `phase = CODE_REVIEW` → ScheduleWakeup 360s or portable in-session poll → Step 5
|
|
379
|
+
- [ ] **converged, no push** → zero unresolved threads →
|
|
380
|
+
`bugteam_clean_at = current_head` → `phase = BUGBOT` → Step 4
|
|
381
|
+
- [ ] **findings without committed fixes** → apply shared fix protocol → push →
|
|
382
|
+
reset markers → `phase = CODE_REVIEW` → Step 5
|
|
383
|
+
|
|
384
|
+
- [ ] **Step 7: Convergence gates**
|
|
385
|
+
Full procedure: [`reference/convergence-gates.md`](reference/convergence-gates.md).
|
|
386
|
+
|
|
387
|
+
Pre-condition: Step 6 converged AND (`bugbot_clean_at == current_head` OR
|
|
388
|
+
`bugbot_down`). The terminal Bugbot gate (Step 4) sets that state just
|
|
389
|
+
before these gates run. Count unresolved threads before each gate.
|
|
390
|
+
Every gate records evidence; gate (f) cites evidence from (a)–(e).
|
|
391
|
+
|
|
392
|
+
- [ ] **(a) Copilot findings** — fetch Copilot on `current_head`; dirty → fix + return to Step 5; clean → stamp `copilot_clean_at`; absent → continue; when `copilot_down`, skip
|
|
393
|
+
- [ ] **(b) Claude reviewer** — fetch Claude on `current_head`; dirty → fix + return to Step 5; clean or absent → continue
|
|
394
|
+
- [ ] **(c) Mergeability** — `mergeable_state == "clean"` and `mergeable == true`; dirty → rebase + return to Step 1; blocked/behind/unknown/unstable → hard blocker
|
|
395
|
+
- [ ] **(d) Post-convergence Copilot request** — request Copilot when not pending and not `copilot_down`; enter `COPILOT_WAIT` (Step 7a); when `copilot_down`, skip to (e)
|
|
396
|
+
- [ ] **(e) Thread-resolution** — zero unresolved threads across the PR; else sweep + fix/resolve
|
|
397
|
+
- [ ] **(f) Mark ready** — run `check_convergence.py`; exit 0 → `update_pull_request(draft=false)` → Step 8; exit 1 → fix path; exit 2 → retry/stop
|
|
398
|
+
|
|
399
|
+
- [ ] **Step 7a: COPILOT_WAIT — fetch Copilot, decide**
|
|
400
|
+
See: [`reference/per-tick.md` § Step 2 COPILOT_WAIT](reference/per-tick.md).
|
|
401
|
+
Skipped entirely when `copilot_down` (gate (d) never enters this phase).
|
|
402
|
+
|
|
403
|
+
- [ ] **clean** → `copilot_clean_at = current_head` → Step 7 (re-validate (b), (c), (e), (f))
|
|
404
|
+
- [ ] **dirty** → apply shared fix protocol
|
|
405
|
+
([`../../_shared/pr-loop/fix-protocol.md`](../../_shared/pr-loop/fix-protocol.md);
|
|
406
|
+
skill deltas in [`reference/fix-protocol.md`](reference/fix-protocol.md))
|
|
407
|
+
→ push → reset markers → `phase = CODE_REVIEW` → Step 5
|
|
408
|
+
- [ ] **no review yet** → increment `copilot_wait_count` → ≥ 3 hard-blocks;
|
|
409
|
+
else ScheduleWakeup 360s or portable in-session poll → Step 7a next tick
|
|
410
|
+
|
|
411
|
+
- [ ] **Step 8: Clean working tree**
|
|
412
|
+
`pr-loop-lifecycle` Close (`../pr-loop-lifecycle/SKILL.md`).
|
|
413
|
+
See: [`pr-loop-lifecycle/reference/teardown-publish-permissions.md` § Clean working tree](../pr-loop-lifecycle/reference/teardown-publish-permissions.md)
|
|
414
|
+
|
|
415
|
+
- [ ] **Step 9: Rewrite PR description**
|
|
416
|
+
`pr-loop-lifecycle` Close.
|
|
417
|
+
See: [`pr-loop-lifecycle/reference/teardown-publish-permissions.md` § Publish the final PR description](../pr-loop-lifecycle/reference/teardown-publish-permissions.md)
|
|
418
|
+
|
|
419
|
+
- [ ] **Step 10: Revoke project permissions (always)**
|
|
420
|
+
`pr-loop-lifecycle` Close (`../pr-loop-lifecycle/SKILL.md` § Close).
|
|
421
|
+
|
|
422
|
+
- [ ] **Step 11: Print final report**
|
|
423
|
+
Print this block verbatim — no paraphrase, no extra commentary:
|
|
424
|
+
```
|
|
425
|
+
/pr-converge exit: converged
|
|
426
|
+
Loops: <N>
|
|
427
|
+
Final commit: <SHA>
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
## Edge cases
|
|
431
|
+
|
|
432
|
+
| Situation | Read |
|
|
433
|
+
|---|---|
|
|
434
|
+
| Multi-PR session (`state.json` exists) | [`reference/multi-pr-orchestration.md`](reference/multi-pr-orchestration.md) |
|
|
435
|
+
| Hard blocker or user stops loop | [`reference/stop-conditions.md`](reference/stop-conditions.md) |
|
|
436
|
+
| Tick is ambiguous against the steps above | [`reference/examples.md`](reference/examples.md) |
|
|
437
|
+
|
|
438
|
+
## Depends on / invokes
|
|
439
|
+
|
|
440
|
+
| Skill / path | Role |
|
|
441
|
+
|---|---|
|
|
442
|
+
| `pr-loop-lifecycle` | Open (permission grant + worktree preflight) and Close (cleanup, PR description, revoke) |
|
|
443
|
+
| `reviewer-gates` | Copilot quota gate, Bugbot availability, Bugbot trigger flow |
|
|
444
|
+
| `copilot-finding-triage` | Tier, verify, and route each Copilot finding |
|
|
445
|
+
| `bugteam` | Full-diff bug audit in Step 6 (Skill invocation mandatory) |
|
|
446
|
+
| `pr-loop-cloud-transport` | When `gh` is unavailable or unauthenticated |
|
|
447
|
+
| [`../_shared/pr-loop/portable-driver.md`](../_shared/pr-loop/portable-driver.md) | Continuous in-session pacer when `ScheduleWakeup` is absent |
|
|
448
|
+
| [`../../_shared/pr-loop/fix-protocol.md`](../../_shared/pr-loop/fix-protocol.md) | Shared 13-step fix sequence (TDD, commit, push, reply, resolve) |
|
|
449
|
+
| [`reference/fix-protocol.md`](reference/fix-protocol.md) | pr-converge deltas on the shared fix protocol |
|
|
450
|
+
|
|
451
|
+
## Package file index
|
|
452
|
+
|
|
453
|
+
| Path | Purpose |
|
|
454
|
+
|---|---|
|
|
455
|
+
| `SKILL.md` | Hub: pre-flight, state, progress checklist, gotchas |
|
|
456
|
+
| `CLAUDE.md` | Package map for agents working in this skill |
|
|
457
|
+
| `pr_converge_skill_constants/` | Importable constants for skill scripts |
|
|
458
|
+
| `reference/per-tick.md` | Full per-tick procedure (phases, cwd routing, pacing) |
|
|
459
|
+
| `reference/convergence-gates.md` | Six gates before mark-ready |
|
|
460
|
+
| `reference/fix-protocol.md` | pr-converge fix-protocol deltas |
|
|
461
|
+
| `reference/ground-rules.md` | Non-negotiable loop constraints |
|
|
462
|
+
| `reference/state-schema.md` | `pr-converge-state.json` fields |
|
|
463
|
+
| `reference/stop-conditions.md` | Hard stops without convergence |
|
|
464
|
+
| `reference/multi-pr-orchestration.md` | Multi-PR session orchestration |
|
|
465
|
+
| `reference/examples.md` | Worked tick sequences |
|
|
466
|
+
| `reference/obstacles/` | Per-obstacle fix runbooks |
|
|
467
|
+
| `scripts/` | Convergence helpers, Copilot fetch, fix-reply poster, tests |
|
|
468
|
+
| `workflows/schedule-wakeup-loop.md` | ScheduleWakeup pacing (`pacer=schedule_wakeup`) |
|
|
469
|
+
| [`../_shared/pr-loop/portable-driver.md`](../_shared/pr-loop/portable-driver.md) | Portable continuous pacer (`pacer=portable`) |
|