claude-dev-env 1.83.0 → 1.84.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.
Files changed (165) hide show
  1. package/_shared/pr-loop/audit-contract.md +24 -12
  2. package/_shared/pr-loop/scripts/_claude_permissions_common.py +16 -5
  3. package/_shared/pr-loop/scripts/code_rules_gate.py +2 -3
  4. package/_shared/pr-loop/scripts/reviews_disabled.py +2 -0
  5. package/_shared/pr-loop/scripts/tests/test__claude_permissions_common.py +212 -0
  6. package/_shared/pr-loop/scripts/tests/test_agent_config_carveout.py +18 -0
  7. package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +18 -0
  8. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +37 -0
  9. package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +14 -0
  10. package/agents/clean-coder.md +3 -0
  11. package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +1 -1
  12. package/bin/install.mjs +16 -8
  13. package/bin/install.test.mjs +17 -6
  14. package/commands/CLAUDE.md +0 -1
  15. package/docs/CODE_RULES.md +1 -1
  16. package/hooks/blocking/CLAUDE.md +0 -4
  17. package/hooks/blocking/code_rules_constants_config.py +5 -0
  18. package/hooks/blocking/code_rules_docstrings.py +116 -6
  19. package/hooks/blocking/code_rules_enforcer.py +4 -0
  20. package/hooks/blocking/code_rules_magic_values.py +5 -0
  21. package/hooks/blocking/code_rules_naming_collection.py +11 -6
  22. package/hooks/blocking/code_rules_shared.py +34 -0
  23. package/hooks/blocking/duplicate_rmtree_helper_blocker.py +4 -4
  24. package/hooks/blocking/test_code_rules_enforcer_docstring_prose_wall_illustration.py +197 -0
  25. package/hooks/blocking/test_code_rules_enforcer_docstring_runon_sentence.py +27 -0
  26. package/hooks/blocking/test_code_rules_enforcer_split_constants_config.py +33 -0
  27. package/hooks/blocking/test_code_rules_enforcer_split_shared.py +23 -0
  28. package/hooks/blocking/test_code_rules_magic_values.py +54 -0
  29. package/hooks/blocking/test_duplicate_rmtree_helper_blocker.py +0 -6
  30. package/hooks/blocking/test_pr_converge_bugteam_enforcer_state_tolerance.py +184 -0
  31. package/hooks/blocking/test_shared_stdin_adoption.py +5 -30
  32. package/hooks/hooks_constants/CLAUDE.md +0 -3
  33. package/hooks/hooks_constants/blocking_check_limits.py +3 -0
  34. package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -1
  35. package/hooks/hooks_constants/duplicate_rmtree_helper_blocker_constants.py +0 -1
  36. package/hooks/hooks_constants/post_tool_use_dispatcher_constants.py +0 -5
  37. package/hooks/validation/post_tool_use_dispatcher.py +1 -1
  38. package/hooks/validation/test_post_tool_use_dispatcher.py +51 -35
  39. package/hooks/workflow/CLAUDE.md +2 -8
  40. package/package.json +1 -1
  41. package/rules/CLAUDE.md +1 -1
  42. package/rules/plain-illustrative-docstrings.md +35 -1
  43. package/skills/CLAUDE.md +6 -1
  44. package/skills/autoconverge/SKILL.md +38 -57
  45. package/skills/autoconverge/reference/closing-report.md +6 -6
  46. package/skills/autoconverge/reference/convergence.md +17 -15
  47. package/skills/autoconverge/reference/gotchas.md +6 -3
  48. package/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +2 -9
  49. package/skills/autoconverge/workflow/converge.contract.test.mjs +87 -13
  50. package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +1 -1
  51. package/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +16 -9
  52. package/skills/autoconverge/workflow/converge.mjs +70 -73
  53. package/skills/autoconverge/workflow/render_report.py +7 -11
  54. package/skills/bugteam/CLAUDE.md +1 -1
  55. package/skills/bugteam/PROMPTS.md +7 -6
  56. package/skills/bugteam/SKILL.md +25 -72
  57. package/skills/bugteam/reference/CLAUDE.md +1 -3
  58. package/skills/bugteam/reference/README.md +1 -1
  59. package/skills/bugteam/reference/audit-and-teammates.md +1 -1
  60. package/skills/bugteam/reference/obstacles/fix-publish-summary.md +1 -1
  61. package/skills/bugteam/reference/team-setup.md +8 -7
  62. package/skills/bugteam/scripts/CLAUDE.md +0 -6
  63. package/skills/bugteam/scripts/README.md +0 -4
  64. package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +0 -1
  65. package/skills/code/SKILL.md +2 -0
  66. package/skills/copilot-review/CLAUDE.md +1 -1
  67. package/skills/copilot-review/SKILL.md +25 -23
  68. package/skills/findbugs/CLAUDE.md +2 -2
  69. package/skills/findbugs/SKILL.md +22 -83
  70. package/skills/fixbugs/SKILL.md +2 -4
  71. package/skills/log-audit/CLAUDE.md +20 -0
  72. package/skills/log-audit/SKILL.md +68 -0
  73. package/skills/log-audit/reference/CLAUDE.md +9 -0
  74. package/skills/log-audit/reference/charter.md +52 -0
  75. package/skills/log-audit/scripts/CLAUDE.md +27 -0
  76. package/skills/log-audit/scripts/cluster_recurrences.py +261 -0
  77. package/skills/log-audit/scripts/collect_log_window.py +199 -0
  78. package/skills/log-audit/scripts/log_audit_constants/CLAUDE.md +12 -0
  79. package/skills/log-audit/scripts/log_audit_constants/cluster_recurrences_constants.py +23 -0
  80. package/skills/log-audit/scripts/log_audit_constants/collect_log_window_constants.py +24 -0
  81. package/skills/log-audit/scripts/log_audit_constants/mine_copilot_findings_constants.py +49 -0
  82. package/skills/log-audit/scripts/mine_copilot_findings.py +302 -0
  83. package/skills/log-audit/scripts/test_cluster_recurrences.py +160 -0
  84. package/skills/log-audit/scripts/test_collect_log_window.py +111 -0
  85. package/skills/log-audit/scripts/test_mine_copilot_findings.py +126 -0
  86. package/skills/monitor-open-prs/SKILL.md +2 -2
  87. package/skills/post-audit-findings/SKILL.md +84 -0
  88. package/skills/pr-converge/CLAUDE.md +2 -0
  89. package/skills/pr-converge/SKILL.md +72 -59
  90. package/skills/pr-converge/reference/CLAUDE.md +1 -1
  91. package/skills/pr-converge/reference/convergence-gates.md +16 -19
  92. package/skills/pr-converge/reference/examples.md +5 -5
  93. package/skills/pr-converge/reference/fix-protocol.md +16 -43
  94. package/skills/pr-converge/reference/obstacles/fix-publish-summary.md +1 -1
  95. package/skills/pr-converge/reference/per-tick.md +24 -45
  96. package/skills/pr-converge/reference/state-schema.md +15 -0
  97. package/skills/pr-converge/scripts/README.md +3 -5
  98. package/skills/pr-fix-protocol/SKILL.md +70 -0
  99. package/skills/pr-loop-lifecycle/SKILL.md +73 -0
  100. package/skills/{bugteam → pr-loop-lifecycle}/reference/teardown-publish-permissions.md +22 -24
  101. package/skills/pr-scope-resolve/SKILL.md +48 -0
  102. package/skills/qbug/CLAUDE.md +4 -4
  103. package/skills/qbug/SKILL.md +46 -144
  104. package/skills/qbug/test_qbug_skill_audit_schema.py +2 -2
  105. package/skills/qbug/test_qbug_skill_post_fix_audit.py +1 -1
  106. package/skills/reviewer-gates/SKILL.md +96 -0
  107. package/skills/session-log/CLAUDE.md +7 -7
  108. package/skills/session-log/SKILL.md +27 -44
  109. package/skills/test_markdown_link_integrity.py +103 -0
  110. package/commands/doc-gist.md +0 -16
  111. package/hooks/blocking/_md_to_html_blocker_test_support.py +0 -65
  112. package/hooks/blocking/conftest.py +0 -30
  113. package/hooks/blocking/md_path_exemptions.py +0 -224
  114. package/hooks/blocking/md_to_html_blocker.py +0 -155
  115. package/hooks/blocking/test_md_to_html_blocker_exemptions.py +0 -434
  116. package/hooks/blocking/test_md_to_html_blocker_extensions.py +0 -157
  117. package/hooks/blocking/test_md_to_html_blocker_path_resolution.py +0 -336
  118. package/hooks/hooks_constants/doc_gist_auto_publish_constants.py +0 -18
  119. package/hooks/hooks_constants/html_companion_constants.py +0 -20
  120. package/hooks/hooks_constants/md_to_html_blocker_constants.py +0 -76
  121. package/hooks/hooks_constants/test_md_to_html_blocker_constants.py +0 -125
  122. package/hooks/workflow/doc_gist_auto_publish.py +0 -144
  123. package/hooks/workflow/md_to_html_companion.py +0 -358
  124. package/hooks/workflow/test_doc_gist_auto_publish.py +0 -117
  125. package/hooks/workflow/test_md_to_html_companion.py +0 -613
  126. package/skills/bugteam/reference/audit-contract.md +0 -163
  127. package/skills/bugteam/scripts/_bugteam_permissions_common.py +0 -455
  128. package/skills/bugteam/scripts/bugteam_scripts_constants/claude_permissions_common_constants.py +0 -69
  129. package/skills/bugteam/scripts/grant_project_claude_permissions.py +0 -280
  130. package/skills/bugteam/scripts/revoke_project_claude_permissions.py +0 -266
  131. package/skills/bugteam/scripts/test__bugteam_permissions_common.py +0 -160
  132. package/skills/bugteam/scripts/test_agent_config_carveout.py +0 -356
  133. package/skills/bugteam/scripts/test_bugteam_permissions_common.py +0 -140
  134. package/skills/doc-gist/CLAUDE.md +0 -25
  135. package/skills/doc-gist/SKILL.md +0 -97
  136. package/skills/doc-gist/references/CLAUDE.md +0 -9
  137. package/skills/doc-gist/references/examples/01-exploration-code-approaches.html +0 -453
  138. package/skills/doc-gist/references/examples/02-exploration-visual-designs.html +0 -515
  139. package/skills/doc-gist/references/examples/03-code-review-pr.html +0 -638
  140. package/skills/doc-gist/references/examples/04-code-understanding.html +0 -491
  141. package/skills/doc-gist/references/examples/05-design-system.html +0 -629
  142. package/skills/doc-gist/references/examples/06-component-variants.html +0 -605
  143. package/skills/doc-gist/references/examples/07-prototype-animation.html +0 -455
  144. package/skills/doc-gist/references/examples/08-prototype-interaction.html +0 -396
  145. package/skills/doc-gist/references/examples/09-slide-deck.html +0 -592
  146. package/skills/doc-gist/references/examples/10-svg-illustrations.html +0 -492
  147. package/skills/doc-gist/references/examples/11-status-report.html +0 -528
  148. package/skills/doc-gist/references/examples/12-incident-report.html +0 -596
  149. package/skills/doc-gist/references/examples/13-flowchart-diagram.html +0 -395
  150. package/skills/doc-gist/references/examples/14-research-feature-explainer.html +0 -381
  151. package/skills/doc-gist/references/examples/15-research-concept-explainer.html +0 -368
  152. package/skills/doc-gist/references/examples/16-implementation-plan.html +0 -702
  153. package/skills/doc-gist/references/examples/17-pr-writeup.html +0 -595
  154. package/skills/doc-gist/references/examples/18-editor-triage-board.html +0 -573
  155. package/skills/doc-gist/references/examples/19-editor-feature-flags.html +0 -663
  156. package/skills/doc-gist/references/examples/20-editor-prompt-tuner.html +0 -722
  157. package/skills/doc-gist/references/examples/21-decision-signoff.html +0 -546
  158. package/skills/doc-gist/references/examples/CLAUDE.md +0 -25
  159. package/skills/doc-gist/references/examples/README.md +0 -5
  160. package/skills/doc-gist/scripts/CLAUDE.md +0 -27
  161. package/skills/doc-gist/scripts/doc_gist_scripts_constants/CLAUDE.md +0 -10
  162. package/skills/doc-gist/scripts/doc_gist_scripts_constants/gist_upload_constants.py +0 -16
  163. package/skills/doc-gist/scripts/gist_upload.py +0 -177
  164. package/skills/doc-gist/scripts/test_gist_upload.py +0 -51
  165. /package/skills/{doc-gist/scripts/doc_gist_scripts_constants → log-audit/scripts/log_audit_constants}/__init__.py +0 -0
@@ -27,7 +27,7 @@ description: >-
27
27
 
28
28
  Refusals — first match wins; respond with the quoted line exactly and stop:
29
29
 
30
- - **Disabled via environment.** When `CLAUDE_REVIEWS_DISABLED` (comma-separated, case-insensitive, whitespace-tolerant) contains the token `bugteam`: `/monitor-open-prs is a /bugteam dispatcher and /bugteam is disabled via CLAUDE_REVIEWS_DISABLED.`
30
+ - **Disabled via environment.** When `CLAUDE_REVIEWS_DISABLED` (comma-separated, case-insensitive, whitespace-tolerant) has the token `bugteam`: `/monitor-open-prs is a /bugteam dispatcher and /bugteam is disabled via CLAUDE_REVIEWS_DISABLED.` Gate semantics live in the `reviewer-gates` skill ([../reviewer-gates/SKILL.md](../reviewer-gates/SKILL.md)).
31
31
  - **GitHub API not accessible.** `get_me failed. /monitor-open-prs needs active GitHub MCP credentials.`
32
32
  - **Dirty tree on the caller's repo.** `Uncommitted changes detected. Stash, commit, or revert before /monitor-open-prs.`
33
33
  - **Required subagents missing.** Confirm `code-quality-agent` and `clean-coder` exist. Else: `Required subagent type <name> not installed.`
@@ -41,7 +41,7 @@ Call `scripts/discover_open_prs.discover_open_prs(all_owners=["jl-cmd", "JonEcho
41
41
  For each discovered PR:
42
42
 
43
43
  1. Resolve the PR's repo checkout (existing worktree or fresh `git clone`).
44
- 2. From that checkout, invoke `/bugteam --bugbot-retrigger <pr_number>`. When `CLAUDE_REVIEWS_DISABLED` (comma-separated, case-insensitive, whitespace-tolerant) contains the token `bugbot`, omit `--bugbot-retrigger` from the dispatched command so the bugbot leg sits out the run.
44
+ 2. From that checkout, invoke `/bugteam --bugbot-retrigger <pr_number>`. When `python "$HOME/.claude/_shared/pr-loop/scripts/reviews_disabled.py" --reviewer bugbot` exits 0 (bugbot disabled), omit `--bugbot-retrigger` from the dispatched command so the bugbot leg sits out the run.
45
45
  3. The `--bugbot-retrigger` flag tells bugteam to post `bugbot run` as an issue comment after every successful FIX push so Cursor's bugbot re-evaluates the new commit.
46
46
  4. Bugteam runs its own 20-loop audit/fix cycle per PR; this skill waits for each bugteam invocation to return before dispatching the next (or fanning out — see below).
47
47
 
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: post-audit-findings
3
+ description: >-
4
+ Publishes an audit pass as one GitHub PR review via the shared
5
+ post_audit_thread.py: maps audit findings to the {path, line, side,
6
+ severity, description, fix_summary} JSON shape (splitting failure_mode at
7
+ the literal `Fix:` heading), partitions anchored vs unanchored findings so
8
+ one bad anchor cannot reject the whole POST, handles the self-PR reviewer
9
+ toggle via BUGTEAM_REVIEWER_ACCOUNT, and harvests finding comment ids and
10
+ PRRT thread node ids for the fix loop. Invoked by audit skills (bugteam,
11
+ qbug, findbugs) after each audit pass, CLEAN or DIRTY; not for ad-hoc PR
12
+ comments or review replies.
13
+ ---
14
+
15
+ # Post Audit Findings
16
+
17
+ **Core principle:** every audit pass — CLEAN or DIRTY — lands on the PR as exactly one review, so the unresolved-thread gate sees the pass and each finding becomes its own resolvable thread.
18
+
19
+ ## How callers invoke this
20
+
21
+ - **Skill-capable contexts** (a lead session with the `Skill` tool): `Skill({skill: "post-audit-findings", args: "--skill <caller> --owner <O> --repo <R> --pr-number <N> --commit <head_sha> --state <CLEAN|DIRTY> --findings-json <path>"})`.
22
+ - **Fallback** (a subagent or teammate without the `Skill` tool): the caller's spawn prompt says "Read `~/.claude/skills/post-audit-findings/SKILL.md` and apply it with the parameters below."
23
+
24
+ `--skill <caller>` is required — the posted review names the audit skill that produced it. Capture `<head_sha>` once, at the start of the posting step, via `git rev-parse HEAD` in the worktree the diff was scoped against.
25
+
26
+ ## Findings-JSON mapping
27
+
28
+ The findings file's root is a list of objects shaped `{path, line, side, severity, description, fix_summary}`. Map each audit finding:
29
+
30
+ - Finding `file` → `path`.
31
+ - The `failure_mode` field carries both the failure narrative AND the `Fix:` / `Validation:` text (per [`agents/code-quality-agent.md`](../../agents/code-quality-agent.md), "The `failure_mode` field is the audit-to-fix handoff"). Split it at the literal `Fix:` heading: the prefix becomes `description`; the suffix starting at `Fix:` (including the trailing `Validation:` clause) becomes `fix_summary`. When a finding omits the `Fix:` heading, write the full `failure_mode` text to BOTH fields so the script's `INLINE_COMMENT_BODY_TEMPLATE` still renders coherently.
32
+ - Set `side="RIGHT"` for every entry.
33
+ - On CLEAN, the file holds an empty array (`[]`).
34
+
35
+ ## Anchored vs unanchored partition
36
+
37
+ Before serializing, partition findings into **anchored** (the line appears in the diff at `--commit`) and **unanchored** (it does not). Only anchored findings go into the JSON — the GitHub reviews API rejects the ENTIRE POST when any inline comment targets a line outside the diff, so a single unanchored entry breaks the whole review. Surface unanchored findings in the caller's user-facing report instead.
38
+
39
+ Zero anchored findings → `--state CLEAN`; one or more → `--state DIRTY`.
40
+
41
+ ## Posting
42
+
43
+ ```bash
44
+ python "$HOME/.claude/_shared/pr-loop/scripts/post_audit_thread.py" \
45
+ --skill <caller> \
46
+ --owner <owner> \
47
+ --repo <repo> \
48
+ --pr-number <N> \
49
+ --commit <head_sha> \
50
+ --state <CLEAN|DIRTY> \
51
+ --findings-json <path>
52
+ ```
53
+
54
+ The script POSTs one review to `/repos/{owner}/{repo}/pulls/{N}/reviews`: `event=APPROVE` on CLEAN (GitHub stores it as `state=APPROVED`; empty `comments[]`; body documents "no findings"), `event=REQUEST_CHANGES` on DIRTY (one inline anchored comment per finding; each becomes its own resolvable thread).
55
+
56
+ **Self-PR auto-toggle.** GitHub rejects both `APPROVE` and `REQUEST_CHANGES` with HTTP 422 when the authenticated identity matches the PR author. `post_audit_thread.py` detects this via `gh api user` + `gh api repos/<o>/<r>/pulls/<n>` and auto-resolves an alternate gh account's token for the reviews POST — the active `gh auth` account is not mutated; only the bearer token on the request changes, so no swap-back step exists.
57
+
58
+ Configuration:
59
+
60
+ - `GH_TOKEN` / `GITHUB_TOKEN` env vars take precedence over the toggle — set one to pin a reviewer identity by token.
61
+ - `BUGTEAM_REVIEWER_ACCOUNT` names which authenticated alternate to prefer (for example `BUGTEAM_REVIEWER_ACCOUNT=jl-cmd`). The env var name is shared across every skill that invokes `post_audit_thread.py`. When unset, the script falls back to the first alternate account `gh auth status` reports.
62
+ - The named alternate must be logged in (`gh auth login -h github.com -u <login>`) before the audit runs; on self-PR with no usable alternate the script exits 1 with a message pointing at `gh auth login`.
63
+
64
+ **Exit codes:** `0` — success; the new review's `html_url` prints to stdout (surface it in the caller's report). `1` — user input error. `2` — retry exhaustion (1s / 4s / 16s backoff across four attempts): a hard blocker. On exit 2 the caller halts the loop (`error: post_audit_thread retry exhausted`) or tells the user the review post failed and the unresolved-thread gate will not see this pass — never a silent retry.
65
+
66
+ ## Harvest ids for the fix loop
67
+
68
+ After a DIRTY post, fetch the new review's threads once and record, per finding: the finding comment's URL, its numeric comment id (the reply anchor), and its thread node id (`PRRT_…`, the `resolve_thread` handle):
69
+
70
+ ```
71
+ pull_request_read(method="get_review_comments", ...) → match comments to the new review id
72
+ ```
73
+
74
+ Hand the id triple to the fix step — `pr-fix-protocol` consumes it for the reply-and-resolve unit. Harvesting at post time saves the fix executor a second fetch and pins the mapping before any thread state changes.
75
+
76
+ ## Gotchas
77
+
78
+ - **One unanchored comment voids the whole review.** The partition is not an optimization; skipping it makes every DIRTY post a coin flip.
79
+ - **CLEAN still posts.** A pass that finds nothing and posts nothing is invisible to the unresolved-thread gate and to anyone auditing the loop's history.
80
+ - **Exit 2 is a stop, not a retry.** The script already retried with backoff; a caller looping on top of it hammers the API to no effect.
81
+
82
+ ## Folder map
83
+
84
+ - `SKILL.md` — this file. The posting script and its body template constants live in `_shared/pr-loop/scripts/` (`post_audit_thread.py`, `pr_loop_shared_constants/post_audit_thread_constants.py`); the review-payload reference is `_shared/pr-loop/gh-payloads.md`.
@@ -27,3 +27,5 @@ Drives a draft PR to convergence by looping Cursor Bugbot, a code-review pass, a
27
27
  - The pre-flight gate requires `EnterWorktree` before any file read or API call, and confirms `ScheduleWakeup` is in the tool list.
28
28
  - All findings and PR reports state verified facts only — no hedging language.
29
29
  - The GitHub MCP (`pull_request_read`, `pull_request_review_write`) is the primary path for PR inspection; `gh api` is the fallback.
30
+ - Three step-scoped agents (`fix_executor`, `thread_sweep`, `copilot_watch`) persist across ticks via the `persistent_agents` map in loop state; each tick resumes them with `SendMessage` and spawns a fresh named agent when a stored id is dead.
31
+ - The tick delegates shared mechanics to five sibling sub-skills: `reviewer-gates` (opt-out, Copilot quota, Bugbot trigger), `pr-scope-resolve` (target resolution), `pr-fix-protocol` (fix sequence + unresolved-thread sweep), `post-audit-findings` (audit posting), and `pr-loop-lifecycle` (run open/close).
@@ -45,23 +45,15 @@ the session worktree before teardown. See
45
45
 
46
46
  ## Copilot quota pre-check (start of run)
47
47
 
48
- On the first tick, before Step 4, run the Copilot quota pre-check once:
49
- `python "$HOME/.claude/_shared/pr-loop/scripts/copilot_quota.py"`. It reads the
50
- account's remaining Copilot premium-request quota via `gh api
51
- copilot_internal/user` and prints one line log that line. Exit 0 means Copilot
52
- has quota, so leave `copilot_down` false. Any non-zero exit means skip Copilot
53
- for the whole run the account is out of quota, the quota API or account access
54
- is down, or no account is set so set `copilot_down = true` in
55
- `pr-converge-state.json`. The account comes from the `COPILOT_QUOTA_ACCOUNT`
56
- environment variable or a git-ignored `.env` file, and the no-account line names
57
- the exact `.env` path and key to set.
58
-
59
- Run the pre-check once, not per tick. Every tick reads `copilot_down` from
60
- state. When `copilot_down` is true, skip the Copilot gate outright — no fetch,
61
- no request, no poll, no agent — and export `CLAUDE_REVIEWS_DISABLED="copilot"`
62
- in that tick's shell before the convergence check, so `check_convergence.py`
63
- bypasses the Copilot review gate and the pending-requested-reviews gate and the
64
- run still marks ready on the remaining signals.
48
+ On the first tick, apply the `reviewer-gates` skill's Copilot quota gate
49
+ (`../reviewer-gates/SKILL.md` § Gate 2) — once per run, never per tick. The
50
+ flag lives in `pr-converge-state.json` as `copilot_down`, and every tick reads
51
+ it. While `copilot_down` is true, the tick skips all Copilot work no fetch,
52
+ no request, no poll, no agent and exports
53
+ `CLAUDE_REVIEWS_DISABLED="copilot"` in that tick's shell before
54
+ `check_convergence.py`, so the check bypasses the Copilot review gate and the
55
+ pending-requested-reviews gate and the run still marks ready on the remaining
56
+ signals.
65
57
 
66
58
  ## Budget-aware tick boundaries
67
59
 
@@ -94,7 +86,39 @@ so the next tick resumes with accurate state.
94
86
  Fields: `phase`, `tick_count`, `bugbot_clean_at`, `code_review_clean_at`,
95
87
  `bugteam_clean_at`, `copilot_clean_at`, `current_head`,
96
88
  `bugbot_acknowledged_at`, `bugbot_down`, `copilot_down`,
97
- `bugteam_skill_invoked_at_head`, `bugteam_skill_invoked_at_tick`.
89
+ `bugteam_skill_invoked_at_head`, `bugteam_skill_invoked_at_tick`,
90
+ `agents_session_id`, `persistent_agents`.
91
+
92
+ ## Persistent per-step agents
93
+
94
+ Three step-scoped agents persist across ticks so their context carries
95
+ forward: `fix_executor`, `thread_sweep`, and `copilot_watch`, recorded in
96
+ the `persistent_agents` map
97
+ ([`reference/state-schema.md`](reference/state-schema.md)).
98
+
99
+ - **Resume:** read `persistent_agents.<key>`. When an entry exists,
100
+ `SendMessage` to the stored `agent_id` with a tick payload that restates
101
+ the PR scope, `current_head`, the PR worktree path, this tick's findings
102
+ or threads, and the report-back contract. Bump `last_used_tick`, then
103
+ await completion.
104
+ - **First spawn:** `Agent(subagent_type: "clean-coder", name:
105
+ "prc-fix-<PR#>")` — the `name` makes the agent a persistent teammate
106
+ that idles awaiting messages. Record `{agent_id, created_tick,
107
+ last_used_tick}` under the step key. Keep the spawn prompt fix-shaped,
108
+ never audit-shaped: the `pr_converge_bugteam_enforcer` hook blocks
109
+ audit-shaped clean-coder spawns during the BUGTEAM phase.
110
+ - **Stale or dead id:** on a `SendMessage` failure, or no acknowledgment
111
+ within one bounded wait, drop the map entry, spawn a fresh named agent,
112
+ record it, and continue the tick. Never abort a tick on a stale id;
113
+ never retry the same dead id.
114
+ - **Fresh every round (never persisted):** the Step 5 `/code-review --fix`
115
+ pass and the Step 6 bugteam audit (unbiased eyes each round; the
116
+ enforcer needs the formal Skill call), and every `code-verifier` — a
117
+ named code-verifier never fires `SubagentStop`, so no verdict mints (see
118
+ the named-`code-verifier` entry in the Gotchas list below).
119
+ - **Shutdown:** at loop end (convergence or a stop condition), send each
120
+ persistent agent a shutdown request and clear `persistent_agents` before
121
+ the `pr-loop-lifecycle` Close.
98
122
 
99
123
  ## Gotchas
100
124
 
@@ -159,13 +183,9 @@ script invocations, decision criteria. Every "return to Step N" means the next
159
183
  tick starts fresh from that step.
160
184
 
161
185
  **Hard gate: do not advance from any step while ANY unresolved review
162
- thread exists on the PR.** The thread-count filter is purely
163
- `is_resolved == false` author, commit anchor, and `is_outdated` are
164
- all irrelevant. After every fix, reply to each finding comment and
165
- resolve the thread via `pull_request_review_write(method="resolve_thread")`.
166
- For each unresolved thread, verify the concern against current HEAD;
167
- either fix-and-resolve, or reply-with-note-and-resolve when the concern
168
- no longer applies.
186
+ thread exists on the PR.** The sweep semantics and per-thread handling live
187
+ in the `pr-fix-protocol` skill's unresolved-thread sweep
188
+ (`../pr-fix-protocol/SKILL.md`).
169
189
 
170
190
  **Full-PR-diff rule: every CODE-REVIEW round (Step 5) and every BUGTEAM
171
191
  round (Step 6) covers the FULL `origin/main...HEAD` diff — every file
@@ -176,11 +196,13 @@ against a partial diff is not a valid clean. Re-run the round against the
176
196
  full diff before recording `code_review_clean_at` or treating the bugteam
177
197
  round as converged. This rule holds every tick, every loop, every PR.
178
198
 
179
- - [ ] **Step 0: Grant project permissions**
180
- `python "$HOME/.claude/skills/bugteam/scripts/grant_project_claude_permissions.py"`
199
+ - [ ] **Step 0: Open the run**
200
+ Apply the `pr-loop-lifecycle` skill's Open section
201
+ (`../pr-loop-lifecycle/SKILL.md`): permission grant + worktree preflight.
181
202
 
182
203
  - [ ] **Step 1: Resolve PR scope + PR worktree**
183
- Capture owner, repo, number, head SHA, branch. Resolve the **PR
204
+ Apply the `pr-scope-resolve` skill (`../pr-scope-resolve/SKILL.md`)
205
+ with caller `pr-converge`. Resolve the **PR
184
206
  worktree** — the local checkout every local step this tick targets:
185
207
  the `EnterWorktree` checkout when the PR shares the session's repo,
186
208
  else a checkout of the PR's repo that the working directory routes
@@ -205,6 +227,8 @@ round as converged. This rule holds every tick, every loop, every PR.
205
227
  See: [`reference/per-tick.md` § Step 2 BUGBOT + Step 3](reference/per-tick.md)
206
228
 
207
229
  - [ ] **Opt-out gate (runs first, every BUGBOT entry).**
230
+ Gate semantics live in the `reviewer-gates` skill
231
+ (`../reviewer-gates/SKILL.md` § Gate 1).
208
232
  `python "$HOME/.claude/_shared/pr-loop/scripts/reviews_disabled.py" --reviewer bugbot`
209
233
  - [ ] Exit 0 (`CLAUDE_REVIEWS_DISABLED` lists `bugbot`) → set `bugbot_down = true`, `phase = CODE_REVIEW`, advance to Step 5 (bypass). Cursor Bugbot is skipped for the entire run.
210
234
  - [ ] Exit 1 → continue below.
@@ -212,9 +236,7 @@ round as converged. This rule holds every tick, every loop, every PR.
212
236
  Fetch bugbot reviews + inline comments on `current_head`.
213
237
 
214
238
  - [ ] **dirty** (findings on `current_head`) →
215
- - [ ] Fix each finding (spawn `clean-coder`)
216
- - [ ] Reply to each finding comment via `python ~/.claude/skills/pr-converge/scripts/post_fix_reply.py`
217
- - [ ] Resolve each addressed thread via `pull_request_review_write(method="resolve_thread")`
239
+ - [ ] Apply the `pr-fix-protocol` skill (`../pr-fix-protocol/SKILL.md`) to this tick's findings
218
240
  - [ ] Push → return to Step 4
219
241
  - [ ] **clean** (no findings on `current_head`) →
220
242
  - [ ] Count ALL unresolved threads on PR (`is_resolved == false`) → zero? advance; >0? fix + resolve first
@@ -222,14 +244,12 @@ round as converged. This rule holds every tick, every loop, every PR.
222
244
  - [ ] `phase = CODE_REVIEW`
223
245
  - [ ] Advance to Step 5
224
246
  - [ ] **no review yet / commit_id mismatch** →
225
- - [ ] Run `python ~/.claude/skills/pr-converge/scripts/check_bugbot_ci.py --owner <O> --repo <R> --check-clean --sha <current_head>`
226
- - [ ] Exit 0 (bugbot CI completed with success/neutral conclusion and no review = silent pass) `bugbot_clean_at = current_head` → `phase = CODE_REVIEW` → advance to Step 5
227
- - [ ] Exit 1 (not a silent pass) or Exit 2 (gh CLI error — silent pass not confirmable) → Run `python ~/.claude/skills/pr-converge/scripts/check_bugbot_ci.py --owner <O> --repo <R> --check-active --sha <current_head>`
228
- - [ ] Exit 0 (already queued)schedule 360s wakeupreturn to Step 4 next tick
229
- - [ ] Exit 1 post exactly `bugbot run` via `add_issue_comment` (no `@cursor[bot]` mention, no other text), wait 8s
230
- - [ ] Run `python ~/.claude/skills/pr-converge/scripts/check_bugbot_ci.py --owner <O> --repo <R> --sha <current_head>`
231
- - [ ] Exit non-zero → `bugbot_down = true` → `phase = CODE_REVIEW` → advance to Step 5 (bypass)
232
- - [ ] Exit 0 → record `bugbot_acknowledged_at`, schedule 360s wakeup → return to Step 4
247
+ Apply the `reviewer-gates` skill's Bugbot flow
248
+ (`../reviewer-gates/SKILL.md` § Gate 3) against `current_head`,
249
+ then map its outcomes:
250
+ - [ ] Silent pass `bugbot_clean_at = current_head` `phase = CODE_REVIEW`advance to Step 5
251
+ - [ ] Already queued, or trigger acknowledged schedule 360s wakeup return to Step 4 next tick
252
+ - [ ] Bugbot down → `bugbot_down = true` `phase = CODE_REVIEW` → advance to Step 5 (bypass)
233
253
  - [ ] **Step 5: CODE-REVIEW — run, fix, reset, advance**
234
254
  See: [`reference/per-tick.md` § Step 2 CODE_REVIEW](reference/per-tick.md)
235
255
 
@@ -264,13 +284,13 @@ round as converged. This rule holds every tick, every loop, every PR.
264
284
  - [ ] Re-trigger bugbot (Step 4 "no review yet" checklist)
265
285
  - [ ] `phase = BUGBOT` → schedule 360s wakeup → return to Step 4
266
286
  - [ ] **clean** (no changes applied) →
267
- - [ ] Count ALL unresolved threads on PR (`is_resolved == false`) → zero? advance; >0? fix + resolve first
287
+ - [ ] Zero unresolved threads per the `pr-fix-protocol` sweep (`../pr-fix-protocol/SKILL.md`) → advance; else fix + resolve first (same skill)
268
288
  - [ ] `code_review_clean_at = current_head`
269
289
  - [ ] `phase = BUGTEAM` → advance to Step 6
270
290
 
271
291
  - [ ] **Step 6: BUGTEAM — run, decide, fix, reply, resolve**
272
292
  See: [`reference/per-tick.md` § Step 2 BUGTEAM](reference/per-tick.md);
273
- [`../../bugteam/SKILL.md`](../../bugteam/SKILL.md)
293
+ [`../bugteam/SKILL.md`](../bugteam/SKILL.md)
274
294
 
275
295
  Pre-condition: `code_review_clean_at == current_head`.
276
296
 
@@ -300,9 +320,7 @@ round as converged. This rule holds every tick, every loop, every PR.
300
320
  - [ ] **converged + `bugbot_clean_at ≠ current_head`** →
301
321
  `phase = BUGBOT` → schedule 360s wakeup → return to Step 4
302
322
  - [ ] **findings without committed fixes** →
303
- - [ ] Fix each finding (spawn `clean-coder`)
304
- - [ ] Reply to each finding comment via `python ~/.claude/skills/pr-converge/scripts/post_fix_reply.py`
305
- - [ ] Resolve each addressed thread via `pull_request_review_write(method="resolve_thread")`
323
+ - [ ] Apply the `pr-fix-protocol` skill (`../pr-fix-protocol/SKILL.md`) to the findings
306
324
  - [ ] Push → `phase = BUGBOT` → return to Step 4
307
325
 
308
326
  - [ ] **Step 7: Convergence gates**
@@ -317,15 +335,13 @@ round as converged. This rule holds every tick, every loop, every PR.
317
335
  pull_request_read(method="get_review_comments")
318
336
  → filter threads where is_resolved == false
319
337
  ```
320
- - [ ] Any unresolved? → For each: verify concern against current HEAD;
321
- if still applies → Fix (spawn `clean-coder`) → reply → resolve;
322
- if no longer applies → reply-with-note → resolve. Push if any code changed → return to Step 4
338
+ - [ ] Any unresolved? → apply the `pr-fix-protocol` skill's unresolved-thread sweep (`../pr-fix-protocol/SKILL.md`). Push if any code changed → return to Step 4
323
339
  - [ ] When `copilot_down == true` (start-of-run quota pre-check), skip the Copilot fetch below — no request, no poll, no agent — and continue to gate (b); the Copilot gate is bypassed for the whole run.
324
340
  - [ ] Fetch Copilot review on `current_head` (top-level review state — uses get_reviews, identifies by reviewer):
325
341
  ```
326
342
  python ~/.claude/skills/pr-converge/scripts/fetch_copilot_reviews.py --owner <O> --repo <R> --pr-number <N>
327
343
  ```
328
- - [ ] dirty → Fix (spawn `clean-coder`) replyresolve threads → push → return to Step 4
344
+ - [ ] dirty → apply the `pr-fix-protocol` skill (`../pr-fix-protocol/SKILL.md`) → push → return to Step 4
329
345
  - [ ] clean (no findings) → `copilot_clean_at = current_head` → gate (b)
330
346
  - [ ] no review yet → gate (b)
331
347
 
@@ -357,10 +373,7 @@ round as converged. This rule holds every tick, every loop, every PR.
357
373
  → count threads where is_resolved == false
358
374
  ```
359
375
  - [ ] zero unresolved → gate (e)
360
- - [ ] unresolved → For each: verify against HEAD;
361
- still applies → Fix (spawn `clean-coder`) → reply → resolve;
362
- no longer applies → reply-with-note → resolve.
363
- Push if code changed → return to Step 4
376
+ - [ ] unresolved → apply the `pr-fix-protocol` skill's unresolved-thread sweep (`../pr-fix-protocol/SKILL.md`). Push if code changed → return to Step 4
364
377
 
365
378
  **(e) Mark ready**
366
379
  - [ ] When `copilot_down == true`, export `CLAUDE_REVIEWS_DISABLED="copilot"` in this tick's shell before the check below, so it bypasses the Copilot review gate and the pending-requested-reviews gate.
@@ -384,22 +397,22 @@ round as converged. This rule holds every tick, every loop, every PR.
384
397
  - [ ] **clean (no findings)** →
385
398
  `copilot_clean_at = current_head` → return to Step 7 (re-validate gates b, d, e)
386
399
  - [ ] **dirty (findings present)** →
387
- - [ ] Fix each finding (spawn `clean-coder`)
388
- - [ ] Reply to each finding comment via `python ~/.claude/skills/pr-converge/scripts/post_fix_reply.py`
389
- - [ ] Resolve each addressed thread via `pull_request_review_write(method="resolve_thread")`
400
+ - [ ] Apply the `pr-fix-protocol` skill (`../pr-fix-protocol/SKILL.md`) to the findings
390
401
  - [ ] Push → `phase = BUGBOT` → return to Step 4
391
402
  - [ ] **no review yet** →
392
403
  increment `copilot_wait_count` → ≥ 3 = hard blocker → stop
393
404
  schedule 360s wakeup → return to Step 7a next tick
394
405
 
395
406
  - [ ] **Step 8: Clean working tree**
396
- See: [`bugteam/reference/teardown-publish-permissions.md` § Step 4](../../bugteam/reference/teardown-publish-permissions.md)
407
+ `pr-loop-lifecycle` Close (`../pr-loop-lifecycle/SKILL.md`).
408
+ See: [`pr-loop-lifecycle/reference/teardown-publish-permissions.md` § Clean working tree](../pr-loop-lifecycle/reference/teardown-publish-permissions.md)
397
409
 
398
410
  - [ ] **Step 9: Rewrite PR description**
399
- See: [`bugteam/reference/teardown-publish-permissions.md` § Step 4.5](../../bugteam/reference/teardown-publish-permissions.md)
411
+ `pr-loop-lifecycle` Close.
412
+ See: [`pr-loop-lifecycle/reference/teardown-publish-permissions.md` § Publish the final PR description](../pr-loop-lifecycle/reference/teardown-publish-permissions.md)
400
413
 
401
- - [ ] **Step 10: Revoke project permissions**
402
- `python "$HOME/.claude/skills/bugteam/scripts/revoke_project_claude_permissions.py"`
414
+ - [ ] **Step 10: Revoke project permissions (always)**
415
+ `pr-loop-lifecycle` Close (`../pr-loop-lifecycle/SKILL.md` § Close).
403
416
 
404
417
  - [ ] **Step 11: Print final report**
405
418
  Print this block verbatim — no paraphrase, no extra commentary:
@@ -8,7 +8,7 @@ Reference documents for the `pr-converge` skill. These files define the per-tick
8
8
  |---|---|
9
9
  | `per-tick.md` | Step-by-step procedure for one tick (resolve HEAD, run BUGBOT, CODE_REVIEW, BUGTEAM, COPILOT_WAIT phases, schedule next wakeup) |
10
10
  | `convergence-gates.md` | Six gates that must all pass before the PR is marked ready for review |
11
- | `fix-protocol.md` | How to apply fixes: TDD first, one commit per fix round, reply to each finding inline |
11
+ | `fix-protocol.md` | pr-converge deltas on the `pr-fix-protocol` skill: multi-PR teammate obligations and the same-tick bugbot re-trigger rule |
12
12
  | `ground-rules.md` | Non-negotiable constraints for the convergence loop |
13
13
  | `stop-conditions.md` | Conditions that end the loop without convergence (cap reached, stuck, user stop) |
14
14
  | `state-schema.md` | Fields in `pr-converge-state.json` and their meanings |
@@ -35,22 +35,21 @@ Decide (four branches; match first whose predicate holds):
35
35
 
36
36
  - **`classification == "dirty"` with non-empty inline comments matching
37
37
  `pull_request_review_id`:** Fix protocol input (same shape as bugbot
38
- dirty). Spawn Agent (subagent_type: clean-coder) to implement → push → reply inline on each thread via
39
- `python ~/.claude/skills/pr-converge/scripts/post_fix_reply.py` → Step 3 in same tick (see
40
- [Single-PR fix workflow](fix-protocol.md#single-pr-fix-workflow) for
41
- full contract).
38
+ dirty). Apply the `pr-fix-protocol` skill
39
+ (`../../pr-fix-protocol/SKILL.md`) → Step 3 in same tick.
42
40
  Reset `bugbot_clean_at = null` AND `copilot_clean_at = null`, `phase =
43
41
  BUGBOT`, schedule next wakeup, return. Full back-to-back-clean cycle
44
42
  plus all six gates must hold again on new HEAD.
45
43
  - **`classification == "dirty"` with empty inline comments matching
46
44
  `pull_request_review_id`:** Copilot posted findings only in review body
47
45
  (`CHANGES_REQUESTED` or `COMMENTED` with non-empty body, no inline
48
- threads). Parse body for actionable findings. Spawn Agent (subagent_type: clean-coder) to implement → push → post
49
- top-level review reply via `python ~/.claude/skills/pr-converge/scripts/post_fix_reply.py` citing new HEAD SHA → Step 3 in same tick.
50
- Reset
46
+ threads). Parse body for actionable findings. Apply the
47
+ `pr-fix-protocol` skill (`../../pr-fix-protocol/SKILL.md`), whose reply
48
+ step for body-only findings posts a top-level review reply citing the
49
+ new HEAD SHA → Step 3 in same tick. Reset
51
50
  `bugbot_clean_at = null` AND
52
51
  `copilot_clean_at = null`, `phase = BUGBOT`, Step 3 on new HEAD,
53
- schedule next wakeup, return. Convergence requires full
52
+ schedule next wakeup, return. Convergence needs full
54
53
  back-to-back-clean on new HEAD.
55
54
  - **`classification == "clean"` (state `APPROVED`):** Set
56
55
  `copilot_clean_at = current_head`. Record evidence: "Copilot APPROVED at <SHA>".
@@ -77,14 +76,15 @@ Decide (four branches; match first whose predicate holds):
77
76
 
78
77
  - **`classification == "dirty"` with non-empty inline comments matching
79
78
  `pull_request_review_id`:** Treat identically to gate (a) dirty+inline
80
- path — spawn Agent (subagent_type: clean-coder) to fix → push → reply inline on each thread. Reset
79
+ path — apply the `pr-fix-protocol` skill
80
+ (`../../pr-fix-protocol/SKILL.md`). Reset
81
81
  `bugbot_clean_at = null` AND `copilot_clean_at = null`, `phase = BUGBOT`,
82
82
  schedule next wakeup, return.
83
83
  - **`classification == "dirty"` with empty inline comments matching
84
84
  `pull_request_review_id`:** Claude posted findings only in review body
85
85
  (`CHANGES_REQUESTED` or `COMMENTED` with non-empty body, no inline
86
- threads). Treat identically to gate (a) dirty+body path — spawn Agent
87
- (subagent_type: clean-coder) to implement → push → post top-level review reply via `python ~/.claude/skills/pr-converge/scripts/post_fix_reply.py`. Reset
86
+ threads). Treat identically to gate (a) dirty+body path — apply the
87
+ `pr-fix-protocol` skill (`../../pr-fix-protocol/SKILL.md`). Reset
88
88
  `bugbot_clean_at = null` AND `copilot_clean_at = null`, `phase = BUGBOT`,
89
89
  schedule next wakeup, return.
90
90
  - **`classification == "clean"` (state `APPROVED`):** Record evidence:
@@ -176,19 +176,16 @@ pull_request_read(owner=OWNER, repo=REPO, pullNumber=NUMBER, method="get_review_
176
176
  → count
177
177
  ```
178
178
 
179
- When you address an unresolved thread, you still need its author and
180
- anchor commit so you can decide how to fix it — but the gate doesn't
181
- filter on those fields.
179
+ This count is the `pr-fix-protocol` unresolved-thread sweep
180
+ (`../../pr-fix-protocol/SKILL.md`).
182
181
 
183
182
  Decide:
184
183
 
185
184
  - **Zero unresolved threads:** Record evidence:
186
185
  "0 unresolved threads across PR at <SHA>". Continue to gate (f).
187
- - **One or more unresolved threads:** Do **not** mark ready. For each
188
- unresolved thread, verify the concern against current HEAD. If still
189
- applies, apply Fix protocol (test fix pushreply → resolve). If
190
- no longer applies (e.g. code already changed), reply-with-note
191
- explaining why and resolve. Push if any code changed → reset
186
+ - **One or more unresolved threads:** Do **not** mark ready. Apply the
187
+ `pr-fix-protocol` skill's unresolved-thread sweep
188
+ (`../../pr-fix-protocol/SKILL.md`). Push if any code changedreset
192
189
  `bugbot_clean_at = null` AND `copilot_clean_at = null`,
193
190
  `phase = BUGBOT`, schedule next wakeup, return. If only resolutions
194
191
  (no code changes), re-check this gate without resetting.
@@ -54,9 +54,8 @@ sufficient. Runs `convergence-gates.md` gates in order:
54
54
  Next tick: re-run gate (a) fetch → Copilot `APPROVED` at `current_head`
55
55
  → set `copilot_clean_at = current_head`, record evidence: "Copilot
56
56
  APPROVED at <SHA>", set `phase = BUGTEAM`, re-validate gates (b) and (c).
57
- Gate (e): `pull_request_read(method="get_review_comments")` count
58
- threads where `is_resolved == false` (no author/commit/outdated
59
- filter) → zero across PR → record evidence.
57
+ Gate (e): the `pr-fix-protocol` unresolved-thread sweep
58
+ (`../../pr-fix-protocol/SKILL.md`) zero across PR record evidence.
60
59
  Gate (f): all six gates pass → `update_pull_request(pullNumber=NUMBER,
61
60
  owner=OWNER, repo=REPO, draft=false)`.
62
61
  Reports "PR #N converged: bugbot CLEAN at <SHA>, bugteam CLEAN at <SHA>,
@@ -100,8 +99,9 @@ Copilot review `state: APPROVED` at `current_head`. Claude: [re-runs
100
99
  gate (a) fetch → APPROVED → sets `copilot_clean_at = current_head`,
101
100
  records evidence: "Copilot APPROVED at <SHA>", sets `phase = BUGTEAM`;
102
101
  re-validates gates (b) Claude absent and (c) mergeability clean,
103
- records evidence for both; gate (e) zero unresolved threads passes
104
- trivially, record evidence: "0 unresolved threads across PR at <SHA>";
102
+ records evidence for both; gate (e) the `pr-fix-protocol`
103
+ unresolved-thread sweep — passes trivially, record evidence:
104
+ "0 unresolved threads across PR at <SHA>";
105
105
  runs `update_pull_request(pullNumber=NUMBER,
106
106
  owner=OWNER, repo=REPO, draft=false)`; reports "PR #N converged: bugbot CLEAN
107
107
  at <SHA>, bugteam CLEAN at <SHA>, mergeable_state clean, copilot CLEAN at
@@ -1,10 +1,15 @@
1
1
  # Fix protocol
2
2
 
3
- Single-PR (no `state.json`): production edits run in main session via
4
- `Agent` (`subagent_type: "clean-coder"`). Multi-PR (`state.json`):
5
- clean-coder teammate; orchestrator never edits inline. Hook handling
3
+ The full fix protocol executor choice, the shared 13-step sequence,
4
+ reply transport, thread resolution, the unresolved-thread sweep, and
5
+ post-push resets lives in the `pr-fix-protocol` skill
6
+ (`../../pr-fix-protocol/SKILL.md`), which follows the shared step
7
+ sequence in `../../../_shared/pr-loop/fix-protocol.md`. Hook handling
6
8
  per [ground-rules.md](ground-rules.md).
7
9
 
10
+ This file holds only the pr-converge deltas: the multi-PR teammate
11
+ obligations and the same-tick re-trigger rule.
12
+
8
13
  **Multi-PR (`state.json`) teammate obligations** (plus TDD, commit, push):
9
14
 
10
15
  - Replies inline on each addressed finding via
@@ -21,44 +26,12 @@ per [ground-rules.md](ground-rules.md).
21
26
  Orchestrator does not reply inline, trigger bugbot, or read repo source
22
27
  files during fix phase in multi-PR mode.
23
28
 
24
- ### Single-PR fix workflow
25
-
26
- **Single-PR (no `state.json`) — same gates, main session executor:**
27
-
28
- Run every command below in the PR worktree (the working directory routed in
29
- [per-tick.md § Step 1.5](per-tick.md)). The `git add`, `git commit`, and
30
- `git push` act on the repo of the current working directory, so a cross-repo
31
- PR's fix lands in the PR's repo only when the cwd is its worktree. A spawned
32
- `clean-coder` does not inherit the lead's working directory — name the PR
33
- worktree path in its prompt and direct it to edit, stage, and commit there,
34
- matching the worktree-path handoff bugteam embeds in its fix worker's spawn
35
- prompt.
36
-
37
- - Read each referenced file:line.
38
- - Write failing test first when finding has behavior to test. Pure doc /
39
- comment / naming nits with no behavior → straight to fix.
40
- - **Implement** via `Agent` (`subagent_type: "clean-coder"`).
41
- Full-stop if `Agent` is unavailable.
42
- - Stage affected files and create one new commit on existing branch:
43
- ```bash
44
- git add <files> && git commit -m "fix(review): <brief summary>"
45
- ```
46
- **Pre-commit gate:** honor hooks; full-stop on bypass.
47
- - Push the new commit:
48
- ```bash
49
- git push origin <BRANCH>
50
- ```
51
- **Pre-push gate:** honor hooks; full-stop on bypass. Capture new HEAD
52
- only after both gates pass; set `current_head`, `bugbot_clean_at = null`.
53
- - Reply inline on each addressed comment thread using `python scripts/post_fix_reply.py`:
29
+ ### Same-tick re-trigger rule
54
30
 
55
- ```
56
- python scripts/post_fix_reply.py --owner <O> --repo <R> --pr-number <N> --in-reply-to <COMMENT_ID> --body "Fixed in <SHA> — <what changed>"
57
- ```
58
- - **After pushing a fix, always run Step 3 (`bugbot run`) in the same
59
- tick** regardless of phase. New commit **resets full convergence cycle**:
60
- prior bugbot clean and prior bugteam clean on older SHA do **not**
61
- count toward convergence on new `HEAD`. Must re-obtain bugbot CLEAN on
62
- `current_head`, then bugteam CLEAN on same `HEAD` with no
63
- intervening push. Re-triggering in same tick saves a wakeup cycle vs
64
- deferring Step 3.
31
+ **After pushing a fix, always run Step 3 (`bugbot run`) in the same
32
+ tick** regardless of phase. A new commit **resets the full convergence
33
+ cycle**: a bugbot clean and a bugteam clean on an older SHA do **not**
34
+ count toward convergence on the new `HEAD`. Re-obtain bugbot CLEAN on
35
+ `current_head`, then bugteam CLEAN on the same `HEAD` with no
36
+ intervening push. Re-triggering in the same tick saves a wakeup cycle
37
+ vs deferring Step 3.
@@ -1,6 +1,6 @@
1
1
  # Publish fix summary
2
2
 
3
- Publish fix summary HTML via /doc-gist with commit SHA and per-fix descriptions
3
+ Publish fix summary HTML via the Artifact tool with commit SHA and per-fix descriptions
4
4
 
5
5
  ## Self-population
6
6